diff options
Diffstat (limited to 'drivers/media/IR/imon.c')
-rw-r--r-- | drivers/media/IR/imon.c | 264 |
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 | */ | ||
1716 | static 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 | |||
1771 | static 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 | |||
1704 | static struct input_dev *imon_init_rdev(struct imon_context *ictx) | 1821 | static 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 | */ | ||
2111 | static 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 | |||
2161 | static 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 | |||
2212 | static void imon_init_display(struct imon_context *ictx, | 2239 | static 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); |