aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media')
-rw-r--r--drivers/media/IR/imon.c264
1 files changed, 138 insertions, 126 deletions
diff --git a/drivers/media/IR/imon.c b/drivers/media/IR/imon.c
index 4b73b8eaf7dc..7a971764ba44 100644
--- a/drivers/media/IR/imon.c
+++ b/drivers/media/IR/imon.c
@@ -292,6 +292,9 @@ static const struct {
292 { 0x000100000000ffeell, KEY_VOLUMEUP }, 292 { 0x000100000000ffeell, KEY_VOLUMEUP },
293 { 0x010000000000ffeell, KEY_VOLUMEDOWN }, 293 { 0x010000000000ffeell, KEY_VOLUMEDOWN },
294 { 0x000000000100ffeell, KEY_MUTE }, 294 { 0x000000000100ffeell, KEY_MUTE },
295 /* 0xffdc iMON MCE VFD */
296 { 0x00010000ffffffeell, KEY_VOLUMEUP },
297 { 0x01000000ffffffeell, KEY_VOLUMEDOWN },
295 /* iMON Knob values */ 298 /* iMON Knob values */
296 { 0x000100ffffffffeell, KEY_VOLUMEUP }, 299 { 0x000100ffffffffeell, KEY_VOLUMEUP },
297 { 0x010000ffffffffeell, KEY_VOLUMEDOWN }, 300 { 0x010000ffffffffeell, KEY_VOLUMEDOWN },
@@ -1701,11 +1704,128 @@ static void usb_rx_callback_intf1(struct urb *urb)
1701 usb_submit_urb(ictx->rx_urb_intf1, GFP_ATOMIC); 1704 usb_submit_urb(ictx->rx_urb_intf1, GFP_ATOMIC);
1702} 1705}
1703 1706
1707/*
1708 * The 0x15c2:0xffdc device ID was used for umpteen different imon
1709 * devices, and all of them constantly spew interrupts, even when there
1710 * is no actual data to report. However, byte 6 of this buffer looks like
1711 * its unique across device variants, so we're trying to key off that to
1712 * figure out which display type (if any) and what IR protocol the device
1713 * actually supports. These devices have their IR protocol hard-coded into
1714 * their firmware, they can't be changed on the fly like the newer hardware.
1715 */
1716static void imon_get_ffdc_type(struct imon_context *ictx)
1717{
1718 u8 ffdc_cfg_byte = ictx->usb_rx_buf[6];
1719 u8 detected_display_type = IMON_DISPLAY_TYPE_NONE;
1720 u64 allowed_protos = IR_TYPE_OTHER;
1721
1722 switch (ffdc_cfg_byte) {
1723 /* iMON Knob, no display, iMON IR + vol knob */
1724 case 0x21:
1725 dev_info(ictx->dev, "0xffdc iMON Knob, iMON IR");
1726 ictx->display_supported = false;
1727 break;
1728 /* iMON 2.4G LT (usb stick), no display, iMON RF */
1729 case 0x4e:
1730 dev_info(ictx->dev, "0xffdc iMON 2.4G LT, iMON RF");
1731 ictx->display_supported = false;
1732 ictx->rf_device = true;
1733 break;
1734 /* iMON VFD, no IR (does have vol knob tho) */
1735 case 0x35:
1736 dev_info(ictx->dev, "0xffdc iMON VFD + knob, no IR");
1737 detected_display_type = IMON_DISPLAY_TYPE_VFD;
1738 break;
1739 /* iMON VFD, iMON IR */
1740 case 0x24:
1741 case 0x85:
1742 dev_info(ictx->dev, "0xffdc iMON VFD, iMON IR");
1743 detected_display_type = IMON_DISPLAY_TYPE_VFD;
1744 break;
1745 /* iMON VFD, MCE IR */
1746 case 0x9e:
1747 dev_info(ictx->dev, "0xffdc iMON VFD, MCE IR");
1748 detected_display_type = IMON_DISPLAY_TYPE_VFD;
1749 allowed_protos = IR_TYPE_RC6;
1750 break;
1751 /* iMON LCD, MCE IR */
1752 case 0x9f:
1753 dev_info(ictx->dev, "0xffdc iMON LCD, MCE IR");
1754 detected_display_type = IMON_DISPLAY_TYPE_LCD;
1755 allowed_protos = IR_TYPE_RC6;
1756 break;
1757 default:
1758 dev_info(ictx->dev, "Unknown 0xffdc device, "
1759 "defaulting to VFD and iMON IR");
1760 detected_display_type = IMON_DISPLAY_TYPE_VFD;
1761 break;
1762 }
1763
1764 printk(KERN_CONT " (id 0x%02x)\n", ffdc_cfg_byte);
1765
1766 ictx->display_type = detected_display_type;
1767 ictx->props->allowed_protos = allowed_protos;
1768 ictx->ir_type = allowed_protos;
1769}
1770
1771static void imon_set_display_type(struct imon_context *ictx)
1772{
1773 u8 configured_display_type = IMON_DISPLAY_TYPE_VFD;
1774
1775 /*
1776 * Try to auto-detect the type of display if the user hasn't set
1777 * it by hand via the display_type modparam. Default is VFD.
1778 */
1779
1780 if (display_type == IMON_DISPLAY_TYPE_AUTO) {
1781 switch (ictx->product) {
1782 case 0xffdc:
1783 /* set in imon_get_ffdc_type() */
1784 configured_display_type = ictx->display_type;
1785 break;
1786 case 0x0034:
1787 case 0x0035:
1788 configured_display_type = IMON_DISPLAY_TYPE_VGA;
1789 break;
1790 case 0x0038:
1791 case 0x0039:
1792 case 0x0045:
1793 configured_display_type = IMON_DISPLAY_TYPE_LCD;
1794 break;
1795 case 0x003c:
1796 case 0x0041:
1797 case 0x0042:
1798 case 0x0043:
1799 configured_display_type = IMON_DISPLAY_TYPE_NONE;
1800 ictx->display_supported = false;
1801 break;
1802 case 0x0036:
1803 case 0x0044:
1804 default:
1805 configured_display_type = IMON_DISPLAY_TYPE_VFD;
1806 break;
1807 }
1808 } else {
1809 configured_display_type = display_type;
1810 if (display_type == IMON_DISPLAY_TYPE_NONE)
1811 ictx->display_supported = false;
1812 else
1813 ictx->display_supported = true;
1814 dev_info(ictx->dev, "%s: overriding display type to %d via "
1815 "modparam\n", __func__, display_type);
1816 }
1817
1818 ictx->display_type = configured_display_type;
1819}
1820
1704static struct input_dev *imon_init_rdev(struct imon_context *ictx) 1821static struct input_dev *imon_init_rdev(struct imon_context *ictx)
1705{ 1822{
1706 struct input_dev *rdev; 1823 struct input_dev *rdev;
1707 struct ir_dev_props *props; 1824 struct ir_dev_props *props;
1708 int ret; 1825 int ret;
1826 char *ir_codes = NULL;
1827 const unsigned char fp_packet[] = { 0x40, 0x00, 0x00, 0x00,
1828 0x00, 0x00, 0x00, 0x88 };
1709 1829
1710 rdev = input_allocate_device(); 1830 rdev = input_allocate_device();
1711 props = kzalloc(sizeof(*props), GFP_KERNEL); 1831 props = kzalloc(sizeof(*props), GFP_KERNEL);
@@ -1733,7 +1853,24 @@ static struct input_dev *imon_init_rdev(struct imon_context *ictx)
1733 props->change_protocol = imon_ir_change_protocol; 1853 props->change_protocol = imon_ir_change_protocol;
1734 ictx->props = props; 1854 ictx->props = props;
1735 1855
1736 ret = ir_input_register(rdev, RC_MAP_IMON_PAD, props, MOD_NAME); 1856 /* Enable front-panel buttons and/or knobs */
1857 memcpy(ictx->usb_tx_buf, &fp_packet, sizeof(fp_packet));
1858 ret = send_packet(ictx);
1859 /* Not fatal, but warn about it */
1860 if (ret)
1861 dev_info(ictx->dev, "panel buttons/knobs setup failed\n");
1862
1863 if (ictx->product == 0xffdc)
1864 imon_get_ffdc_type(ictx);
1865
1866 imon_set_display_type(ictx);
1867
1868 if (ictx->ir_type == IR_TYPE_RC6)
1869 ir_codes = RC_MAP_IMON_MCE;
1870 else
1871 ir_codes = RC_MAP_IMON_PAD;
1872
1873 ret = ir_input_register(rdev, ir_codes, props, MOD_NAME);
1737 if (ret < 0) { 1874 if (ret < 0) {
1738 dev_err(ictx->dev, "remote input dev register failed\n"); 1875 dev_err(ictx->dev, "remote input dev register failed\n");
1739 goto out; 1876 goto out;
@@ -2099,116 +2236,6 @@ rx_urb_alloc_failed:
2099 return NULL; 2236 return NULL;
2100} 2237}
2101 2238
2102/*
2103 * The 0x15c2:0xffdc device ID was used for umpteen different imon
2104 * devices, and all of them constantly spew interrupts, even when there
2105 * is no actual data to report. However, byte 6 of this buffer looks like
2106 * its unique across device variants, so we're trying to key off that to
2107 * figure out which display type (if any) and what IR protocol the device
2108 * actually supports. These devices have their IR protocol hard-coded into
2109 * their firmware, they can't be changed on the fly like the newer hardware.
2110 */
2111static void imon_get_ffdc_type(struct imon_context *ictx)
2112{
2113 u8 ffdc_cfg_byte = ictx->usb_rx_buf[6];
2114 u8 detected_display_type = IMON_DISPLAY_TYPE_NONE;
2115 u64 allowed_protos = IR_TYPE_OTHER;
2116
2117 switch (ffdc_cfg_byte) {
2118 /* iMON Knob, no display, iMON IR + vol knob */
2119 case 0x21:
2120 dev_info(ictx->dev, "0xffdc iMON Knob, iMON IR");
2121 ictx->display_supported = false;
2122 break;
2123 /* iMON 2.4G LT (usb stick), no display, iMON RF */
2124 case 0x4e:
2125 dev_info(ictx->dev, "0xffdc iMON 2.4G LT, iMON RF");
2126 ictx->display_supported = false;
2127 ictx->rf_device = true;
2128 break;
2129 /* iMON VFD, no IR (does have vol knob tho) */
2130 case 0x35:
2131 dev_info(ictx->dev, "0xffdc iMON VFD + knob, no IR");
2132 detected_display_type = IMON_DISPLAY_TYPE_VFD;
2133 break;
2134 /* iMON VFD, iMON IR */
2135 case 0x24:
2136 case 0x85:
2137 dev_info(ictx->dev, "0xffdc iMON VFD, iMON IR");
2138 detected_display_type = IMON_DISPLAY_TYPE_VFD;
2139 break;
2140 /* iMON LCD, MCE IR */
2141 case 0x9e:
2142 case 0x9f:
2143 dev_info(ictx->dev, "0xffdc iMON LCD, MCE IR");
2144 detected_display_type = IMON_DISPLAY_TYPE_LCD;
2145 allowed_protos = IR_TYPE_RC6;
2146 break;
2147 default:
2148 dev_info(ictx->dev, "Unknown 0xffdc device, "
2149 "defaulting to VFD and iMON IR");
2150 detected_display_type = IMON_DISPLAY_TYPE_VFD;
2151 break;
2152 }
2153
2154 printk(KERN_CONT " (id 0x%02x)\n", ffdc_cfg_byte);
2155
2156 ictx->display_type = detected_display_type;
2157 ictx->props->allowed_protos = allowed_protos;
2158 ictx->ir_type = allowed_protos;
2159}
2160
2161static void imon_set_display_type(struct imon_context *ictx,
2162 struct usb_interface *intf)
2163{
2164 u8 configured_display_type = IMON_DISPLAY_TYPE_VFD;
2165
2166 /*
2167 * Try to auto-detect the type of display if the user hasn't set
2168 * it by hand via the display_type modparam. Default is VFD.
2169 */
2170
2171 if (display_type == IMON_DISPLAY_TYPE_AUTO) {
2172 switch (ictx->product) {
2173 case 0xffdc:
2174 /* set in imon_get_ffdc_type() */
2175 configured_display_type = ictx->display_type;
2176 break;
2177 case 0x0034:
2178 case 0x0035:
2179 configured_display_type = IMON_DISPLAY_TYPE_VGA;
2180 break;
2181 case 0x0038:
2182 case 0x0039:
2183 case 0x0045:
2184 configured_display_type = IMON_DISPLAY_TYPE_LCD;
2185 break;
2186 case 0x003c:
2187 case 0x0041:
2188 case 0x0042:
2189 case 0x0043:
2190 configured_display_type = IMON_DISPLAY_TYPE_NONE;
2191 ictx->display_supported = false;
2192 break;
2193 case 0x0036:
2194 case 0x0044:
2195 default:
2196 configured_display_type = IMON_DISPLAY_TYPE_VFD;
2197 break;
2198 }
2199 } else {
2200 configured_display_type = display_type;
2201 if (display_type == IMON_DISPLAY_TYPE_NONE)
2202 ictx->display_supported = false;
2203 else
2204 ictx->display_supported = true;
2205 dev_info(ictx->dev, "%s: overriding display type to %d via "
2206 "modparam\n", __func__, display_type);
2207 }
2208
2209 ictx->display_type = configured_display_type;
2210}
2211
2212static void imon_init_display(struct imon_context *ictx, 2239static void imon_init_display(struct imon_context *ictx,
2213 struct usb_interface *intf) 2240 struct usb_interface *intf)
2214{ 2241{
@@ -2249,8 +2276,6 @@ static int __devinit imon_probe(struct usb_interface *interface,
2249 struct imon_context *ictx = NULL; 2276 struct imon_context *ictx = NULL;
2250 struct imon_context *first_if_ctx = NULL; 2277 struct imon_context *first_if_ctx = NULL;
2251 u16 vendor, product; 2278 u16 vendor, product;
2252 const unsigned char fp_packet[] = { 0x40, 0x00, 0x00, 0x00,
2253 0x00, 0x00, 0x00, 0x88 };
2254 2279
2255 code_length = BUF_CHUNK_SIZE * 8; 2280 code_length = BUF_CHUNK_SIZE * 8;
2256 2281
@@ -2291,19 +2316,6 @@ static int __devinit imon_probe(struct usb_interface *interface,
2291 usb_set_intfdata(interface, ictx); 2316 usb_set_intfdata(interface, ictx);
2292 2317
2293 if (ifnum == 0) { 2318 if (ifnum == 0) {
2294 /* Enable front-panel buttons and/or knobs */
2295 memcpy(ictx->usb_tx_buf, &fp_packet, sizeof(fp_packet));
2296 ret = send_packet(ictx);
2297 /* Not fatal, but warn about it */
2298 if (ret)
2299 dev_info(dev, "failed to enable panel buttons "
2300 "and/or knobs\n");
2301
2302 if (product == 0xffdc)
2303 imon_get_ffdc_type(ictx);
2304
2305 imon_set_display_type(ictx, interface);
2306
2307 if (product == 0xffdc && ictx->rf_device) { 2319 if (product == 0xffdc && ictx->rf_device) {
2308 sysfs_err = sysfs_create_group(&interface->dev.kobj, 2320 sysfs_err = sysfs_create_group(&interface->dev.kobj,
2309 &imon_rf_attribute_group); 2321 &imon_rf_attribute_group);