diff options
Diffstat (limited to 'drivers/media/rc/imon.c')
| -rw-r--r-- | drivers/media/rc/imon.c | 111 |
1 files changed, 56 insertions, 55 deletions
diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index 5dd0386604f..6f24e77b148 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -112,6 +112,7 @@ struct imon_context { bool tx_control; unsigned char usb_rx_buf[8]; unsigned char usb_tx_buf[8]; + unsigned int send_packet_delay; struct tx_t { unsigned char data_buf[35]; /* user data buffer */ @@ -185,6 +186,10 @@ enum { IMON_KEY_PANEL = 2, }; +enum { + IMON_NEED_20MS_PKT_DELAY = 1 +}; + /* * USB Device ID for iMON USB Control Boards * @@ -215,7 +220,7 @@ static struct usb_device_id imon_usb_id_table[] = { /* SoundGraph iMON OEM Touch LCD (IR & 4.3" VGA LCD) */ { USB_DEVICE(0x15c2, 0x0035) }, /* SoundGraph iMON OEM VFD (IR & VFD) */ - { USB_DEVICE(0x15c2, 0x0036) }, + { USB_DEVICE(0x15c2, 0x0036), .driver_info = IMON_NEED_20MS_PKT_DELAY }, /* device specifics unknown */ { USB_DEVICE(0x15c2, 0x0037) }, /* SoundGraph iMON OEM LCD (IR & LCD) */ @@ -255,7 +260,7 @@ static struct usb_device_id imon_usb_id_table[] = { static struct usb_driver imon_driver = { .name = MOD_NAME, .probe = imon_probe, - .disconnect = __devexit_p(imon_disconnect), + .disconnect = imon_disconnect, .suspend = imon_suspend, .resume = imon_resume, .id_table = imon_usb_id_table, @@ -523,8 +528,10 @@ static int send_packet(struct imon_context *ictx) mutex_unlock(&ictx->lock); retval = wait_for_completion_interruptible( &ictx->tx.finished); - if (retval) + if (retval) { + usb_kill_urb(ictx->tx_urb); pr_err_ratelimited("task interrupted\n"); + } mutex_lock(&ictx->lock); retval = ictx->tx.status; @@ -535,12 +542,12 @@ static int send_packet(struct imon_context *ictx) kfree(control_req); /* - * Induce a mandatory 5ms delay before returning, as otherwise, + * Induce a mandatory delay before returning, as otherwise, * send_packet can get called so rapidly as to overwhelm the device, * particularly on faster systems and/or those with quirky usb. */ - timeout = msecs_to_jiffies(5); - set_current_state(TASK_UNINTERRUPTIBLE); + timeout = msecs_to_jiffies(ictx->send_packet_delay); + set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(timeout); return retval; @@ -1001,7 +1008,7 @@ static void imon_touch_display_timeout(unsigned long data) * it is not, so we must acquire it prior to calling send_packet, which * requires that the lock is held. */ -static int imon_ir_change_protocol(struct rc_dev *rc, u64 rc_type) +static int imon_ir_change_protocol(struct rc_dev *rc, u64 *rc_type) { int retval; struct imon_context *ictx = rc->priv; @@ -1010,31 +1017,27 @@ static int imon_ir_change_protocol(struct rc_dev *rc, u64 rc_type) unsigned char ir_proto_packet[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86 }; - if (rc_type && !(rc_type & rc->allowed_protos)) + if (*rc_type && !rc_protocols_allowed(rc, *rc_type)) dev_warn(dev, "Looks like you're trying to use an IR protocol " "this device does not support\n"); - switch (rc_type) { - case RC_TYPE_RC6: + if (*rc_type & RC_BIT_RC6_MCE) { dev_dbg(dev, "Configuring IR receiver for MCE protocol\n"); ir_proto_packet[0] = 0x01; - break; - case RC_TYPE_UNKNOWN: - case RC_TYPE_OTHER: + *rc_type = RC_BIT_RC6_MCE; + } else if (*rc_type & RC_BIT_OTHER) { dev_dbg(dev, "Configuring IR receiver for iMON protocol\n"); if (!pad_stabilize) dev_dbg(dev, "PAD stabilize functionality disabled\n"); /* ir_proto_packet[0] = 0x00; // already the default */ - rc_type = RC_TYPE_OTHER; - break; - default: + *rc_type = RC_BIT_OTHER; + } else { dev_warn(dev, "Unsupported IR protocol specified, overriding " "to iMON IR protocol\n"); if (!pad_stabilize) dev_dbg(dev, "PAD stabilize functionality disabled\n"); /* ir_proto_packet[0] = 0x00; // already the default */ - rc_type = RC_TYPE_OTHER; - break; + *rc_type = RC_BIT_OTHER; } memcpy(ictx->usb_tx_buf, &ir_proto_packet, sizeof(ir_proto_packet)); @@ -1048,7 +1051,7 @@ static int imon_ir_change_protocol(struct rc_dev *rc, u64 rc_type) if (retval) goto out; - ictx->rc_type = rc_type; + ictx->rc_type = *rc_type; ictx->pad_mouse = false; out: @@ -1225,7 +1228,7 @@ static u32 imon_panel_key_lookup(u64 code) static bool imon_mouse_event(struct imon_context *ictx, unsigned char *buf, int len) { - char rel_x = 0x00, rel_y = 0x00; + signed char rel_x = 0x00, rel_y = 0x00; u8 right_shift = 1; bool mouse_input = true; int dir = 0; @@ -1301,7 +1304,7 @@ static void imon_touch_event(struct imon_context *ictx, unsigned char *buf) static void imon_pad_to_keys(struct imon_context *ictx, unsigned char *buf) { int dir = 0; - char rel_x = 0x00, rel_y = 0x00; + signed char rel_x = 0x00, rel_y = 0x00; u16 timeout, threshold; u32 scancode = KEY_RESERVED; unsigned long flags; @@ -1323,7 +1326,7 @@ static void imon_pad_to_keys(struct imon_context *ictx, unsigned char *buf) rel_x = buf[2]; rel_y = buf[3]; - if (ictx->rc_type == RC_TYPE_OTHER && pad_stabilize) { + if (ictx->rc_type == RC_BIT_OTHER && pad_stabilize) { if ((buf[1] == 0) && ((rel_x != 0) || (rel_y != 0))) { dir = stabilize((int)rel_x, (int)rel_y, timeout, threshold); @@ -1367,7 +1370,7 @@ static void imon_pad_to_keys(struct imon_context *ictx, unsigned char *buf) * 0x68nnnnB7 to 0x6AnnnnB7, the left mouse button generates * 0x688301b7 and the right one 0x688481b7. All other keys generate * 0x2nnnnnnn. Position coordinate is encoded in buf[1] and buf[2] with - * reversed endianess. Extract direction from buffer, rotate endianess, + * reversed endianness. Extract direction from buffer, rotate endianness, * adjust sign and feed the values into stabilize(). The resulting codes * will be 0x01008000, 0x01007F00, which match the newer devices. */ @@ -1390,7 +1393,7 @@ static void imon_pad_to_keys(struct imon_context *ictx, unsigned char *buf) buf[0] = 0x01; buf[1] = buf[4] = buf[5] = buf[6] = buf[7] = 0; - if (ictx->rc_type == RC_TYPE_OTHER && pad_stabilize) { + if (ictx->rc_type == RC_BIT_OTHER && pad_stabilize) { dir = stabilize((int)rel_x, (int)rel_y, timeout, threshold); if (!dir) { @@ -1511,7 +1514,7 @@ static void imon_incoming_packet(struct imon_context *ictx, kc = imon_panel_key_lookup(scancode); } else { scancode = be32_to_cpu(*((u32 *)buf)); - if (ictx->rc_type == RC_TYPE_RC6) { + if (ictx->rc_type == RC_BIT_RC6_MCE) { ktype = IMON_KEY_IMON; if (buf[0] == 0x80) ktype = IMON_KEY_MCE; @@ -1572,11 +1575,6 @@ static void imon_incoming_packet(struct imon_context *ictx, if (press_type < 0) goto not_input_data; - spin_lock_irqsave(&ictx->kc_lock, flags); - if (ictx->kc == KEY_UNKNOWN) - goto unknown_key; - spin_unlock_irqrestore(&ictx->kc_lock, flags); - if (ktype != IMON_KEY_PANEL) { if (press_type == 0) rc_keyup(ictx->rdev); @@ -1619,12 +1617,6 @@ static void imon_incoming_packet(struct imon_context *ictx, return; -unknown_key: - spin_unlock_irqrestore(&ictx->kc_lock, flags); - dev_info(dev, "%s: unknown keypress, code 0x%llx\n", __func__, - (long long)scancode); - return; - not_input_data: if (len != 8) { dev_warn(dev, "imon %s: invalid incoming packet " @@ -1744,7 +1736,7 @@ static void imon_get_ffdc_type(struct imon_context *ictx) { u8 ffdc_cfg_byte = ictx->usb_rx_buf[6]; u8 detected_display_type = IMON_DISPLAY_TYPE_NONE; - u64 allowed_protos = RC_TYPE_OTHER; + u64 allowed_protos = RC_BIT_OTHER; switch (ffdc_cfg_byte) { /* iMON Knob, no display, iMON IR + vol knob */ @@ -1775,13 +1767,13 @@ static void imon_get_ffdc_type(struct imon_context *ictx) case 0x9e: dev_info(ictx->dev, "0xffdc iMON VFD, MCE IR"); detected_display_type = IMON_DISPLAY_TYPE_VFD; - allowed_protos = RC_TYPE_RC6; + allowed_protos = RC_BIT_RC6_MCE; break; /* iMON LCD, MCE IR */ case 0x9f: dev_info(ictx->dev, "0xffdc iMON LCD, MCE IR"); detected_display_type = IMON_DISPLAY_TYPE_LCD; - allowed_protos = RC_TYPE_RC6; + allowed_protos = RC_BIT_RC6_MCE; break; default: dev_info(ictx->dev, "Unknown 0xffdc device, " @@ -1789,7 +1781,7 @@ static void imon_get_ffdc_type(struct imon_context *ictx) detected_display_type = IMON_DISPLAY_TYPE_VFD; /* We don't know which one it is, allow user to set the * RC6 one from userspace if OTHER wasn't correct. */ - allowed_protos |= RC_TYPE_RC6; + allowed_protos |= RC_BIT_RC6_MCE; break; } @@ -1875,7 +1867,8 @@ static struct rc_dev *imon_init_rdev(struct imon_context *ictx) rdev->priv = ictx; rdev->driver_type = RC_DRIVER_SCANCODE; - rdev->allowed_protos = RC_TYPE_OTHER | RC_TYPE_RC6; /* iMON PAD or MCE */ + /* iMON PAD or MCE */ + rc_set_allowed_protocols(rdev, RC_BIT_OTHER | RC_BIT_RC6_MCE); rdev->change_protocol = imon_ir_change_protocol; rdev->driver_name = MOD_NAME; @@ -1888,12 +1881,12 @@ static struct rc_dev *imon_init_rdev(struct imon_context *ictx) if (ictx->product == 0xffdc) { imon_get_ffdc_type(ictx); - rdev->allowed_protos = ictx->rc_type; + rc_set_allowed_protocols(rdev, ictx->rc_type); } imon_set_display_type(ictx); - if (ictx->rc_type == RC_TYPE_RC6) + if (ictx->rc_type == RC_BIT_RC6_MCE) rdev->map_name = RC_MAP_IMON_MCE; else rdev->map_name = RC_MAP_IMON_PAD; @@ -1917,10 +1910,8 @@ static struct input_dev *imon_init_idev(struct imon_context *ictx) int ret, i; idev = input_allocate_device(); - if (!idev) { - dev_err(ictx->dev, "input dev allocation failed\n"); + if (!idev) goto out; - } snprintf(ictx->name_idev, sizeof(ictx->name_idev), "iMON Panel, Knob and Mouse(%04x:%04x)", @@ -1968,10 +1959,8 @@ static struct input_dev *imon_init_touch(struct imon_context *ictx) int ret; touch = input_allocate_device(); - if (!touch) { - dev_err(ictx->dev, "touchscreen input dev allocation failed\n"); + if (!touch) goto touch_alloc_failed; - } snprintf(ictx->name_touch, sizeof(ictx->name_touch), "iMON USB Touchscreen (%04x:%04x)", @@ -2103,7 +2092,8 @@ static bool imon_find_endpoints(struct imon_context *ictx, } -static struct imon_context *imon_init_intf0(struct usb_interface *intf) +static struct imon_context *imon_init_intf0(struct usb_interface *intf, + const struct usb_device_id *id) { struct imon_context *ictx; struct urb *rx_urb; @@ -2143,6 +2133,10 @@ static struct imon_context *imon_init_intf0(struct usb_interface *intf) ictx->vendor = le16_to_cpu(ictx->usbdev_intf0->descriptor.idVendor); ictx->product = le16_to_cpu(ictx->usbdev_intf0->descriptor.idProduct); + /* default send_packet delay is 5ms but some devices need more */ + ictx->send_packet_delay = id->driver_info & IMON_NEED_20MS_PKT_DELAY ? + 20 : 5; + ret = -ENODEV; iface_desc = intf->cur_altsetting; if (!imon_find_endpoints(ictx, iface_desc)) { @@ -2292,8 +2286,8 @@ static void imon_init_display(struct imon_context *ictx, /** * Callback function for USB core API: Probe */ -static int __devinit imon_probe(struct usb_interface *interface, - const struct usb_device_id *id) +static int imon_probe(struct usb_interface *interface, + const struct usb_device_id *id) { struct usb_device *usbdev = NULL; struct usb_host_interface *iface_desc = NULL; @@ -2321,7 +2315,7 @@ static int __devinit imon_probe(struct usb_interface *interface, first_if_ctx = usb_get_intfdata(first_if); if (ifnum == 0) { - ictx = imon_init_intf0(interface); + ictx = imon_init_intf0(interface, id); if (!ictx) { pr_err("failed to initialize context!\n"); ret = -ENODEV; @@ -2329,7 +2323,14 @@ static int __devinit imon_probe(struct usb_interface *interface, } } else { - /* this is the secondary interface on the device */ + /* this is the secondary interface on the device */ + + /* fail early if first intf failed to register */ + if (!first_if_ctx) { + ret = -ENODEV; + goto fail; + } + ictx = imon_init_intf1(interface, first_if_ctx); if (!ictx) { pr_err("failed to attach to context!\n"); @@ -2376,7 +2377,7 @@ fail: /** * Callback function for USB core API: disconnect */ -static void __devexit imon_disconnect(struct usb_interface *interface) +static void imon_disconnect(struct usb_interface *interface) { struct imon_context *ictx; struct device *dev; |
