aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/IR/imon.c
diff options
context:
space:
mode:
authorJarod Wilson <jarod@redhat.com>2010-09-14 23:28:41 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2010-10-20 23:06:08 -0400
commit04292fc0031a28d298dfa03c4cd9ce6abef9b4e0 (patch)
tree10f19dab2a991dcb0eb04d7435ce5799d9b0cea2 /drivers/media/IR/imon.c
parent693508df9824ecc2bf308a35b58159aa2fecf91f (diff)
V4L/DVB: IR/imon: set up mce-only devices w/mce keytable
Currently, they get set up with the pad keytable, which they can't actually use at all. Also add another variant of volume scancodes from another 0xffdc device, and properly set up the 0x9e 0xffdc device as an iMON VFD w/MCE proto IR. Based on data and a prior patch from Anders Eriksson on the lirc list. Signed-off-by: Jarod Wilson <jarod@redhat.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/IR/imon.c')
-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 4b73b8eaf7d..7a971764ba4 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);