--- zzzz-none-000/linux-3.10.107/drivers/media/rc/imon.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/drivers/media/rc/imon.c 2021-02-04 17:41:59.000000000 +0000 @@ -78,15 +78,27 @@ static int display_close(struct inode *inode, struct file *file); /* VFD write operation */ -static ssize_t vfd_write(struct file *file, const char *buf, +static ssize_t vfd_write(struct file *file, const char __user *buf, size_t n_bytes, loff_t *pos); /* LCD file_operations override function prototypes */ -static ssize_t lcd_write(struct file *file, const char *buf, +static ssize_t lcd_write(struct file *file, const char __user *buf, size_t n_bytes, loff_t *pos); /*** G L O B A L S ***/ +struct imon_panel_key_table { + u64 hw_code; + u32 keycode; +}; + +struct imon_usb_dev_descr { + __u16 flags; +#define IMON_NO_FLAGS 0 +#define IMON_NEED_20MS_PKT_DELAY 1 + struct imon_panel_key_table key_table[]; +}; + struct imon_context { struct device *dev; /* Newer devices have two interfaces */ @@ -150,6 +162,8 @@ struct timer_list ttimer; /* touch screen timer */ int touch_x; /* x coordinate on touchscreen */ int touch_y; /* y coordinate on touchscreen */ + struct imon_usb_dev_descr *dev_descr; /* device description with key + table for front panels */ }; #define TOUCH_TIMEOUT (HZ/30) @@ -186,8 +200,132 @@ IMON_KEY_PANEL = 2, }; -enum { - IMON_NEED_20MS_PKT_DELAY = 1 +static struct usb_class_driver imon_vfd_class = { + .name = DEVICE_NAME, + .fops = &vfd_fops, + .minor_base = DISPLAY_MINOR_BASE, +}; + +static struct usb_class_driver imon_lcd_class = { + .name = DEVICE_NAME, + .fops = &lcd_fops, + .minor_base = DISPLAY_MINOR_BASE, +}; + +/* imon receiver front panel/knob key table */ +static const struct imon_usb_dev_descr imon_default_table = { + .flags = IMON_NO_FLAGS, + .key_table = { + { 0x000000000f00ffeell, KEY_MEDIA }, /* Go */ + { 0x000000001200ffeell, KEY_UP }, + { 0x000000001300ffeell, KEY_DOWN }, + { 0x000000001400ffeell, KEY_LEFT }, + { 0x000000001500ffeell, KEY_RIGHT }, + { 0x000000001600ffeell, KEY_ENTER }, + { 0x000000001700ffeell, KEY_ESC }, + { 0x000000001f00ffeell, KEY_AUDIO }, + { 0x000000002000ffeell, KEY_VIDEO }, + { 0x000000002100ffeell, KEY_CAMERA }, + { 0x000000002700ffeell, KEY_DVD }, + { 0x000000002300ffeell, KEY_TV }, + { 0x000000002b00ffeell, KEY_EXIT }, + { 0x000000002c00ffeell, KEY_SELECT }, + { 0x000000002d00ffeell, KEY_MENU }, + { 0x000000000500ffeell, KEY_PREVIOUS }, + { 0x000000000700ffeell, KEY_REWIND }, + { 0x000000000400ffeell, KEY_STOP }, + { 0x000000003c00ffeell, KEY_PLAYPAUSE }, + { 0x000000000800ffeell, KEY_FASTFORWARD }, + { 0x000000000600ffeell, KEY_NEXT }, + { 0x000000010000ffeell, KEY_RIGHT }, + { 0x000001000000ffeell, KEY_LEFT }, + { 0x000000003d00ffeell, KEY_SELECT }, + { 0x000100000000ffeell, KEY_VOLUMEUP }, + { 0x010000000000ffeell, KEY_VOLUMEDOWN }, + { 0x000000000100ffeell, KEY_MUTE }, + /* 0xffdc iMON MCE VFD */ + { 0x00010000ffffffeell, KEY_VOLUMEUP }, + { 0x01000000ffffffeell, KEY_VOLUMEDOWN }, + { 0x00000001ffffffeell, KEY_MUTE }, + { 0x0000000fffffffeell, KEY_MEDIA }, + { 0x00000012ffffffeell, KEY_UP }, + { 0x00000013ffffffeell, KEY_DOWN }, + { 0x00000014ffffffeell, KEY_LEFT }, + { 0x00000015ffffffeell, KEY_RIGHT }, + { 0x00000016ffffffeell, KEY_ENTER }, + { 0x00000017ffffffeell, KEY_ESC }, + /* iMON Knob values */ + { 0x000100ffffffffeell, KEY_VOLUMEUP }, + { 0x010000ffffffffeell, KEY_VOLUMEDOWN }, + { 0x000008ffffffffeell, KEY_MUTE }, + { 0, KEY_RESERVED }, + } +}; + +static const struct imon_usb_dev_descr imon_OEM_VFD = { + .flags = IMON_NEED_20MS_PKT_DELAY, + .key_table = { + { 0x000000000f00ffeell, KEY_MEDIA }, /* Go */ + { 0x000000001200ffeell, KEY_UP }, + { 0x000000001300ffeell, KEY_DOWN }, + { 0x000000001400ffeell, KEY_LEFT }, + { 0x000000001500ffeell, KEY_RIGHT }, + { 0x000000001600ffeell, KEY_ENTER }, + { 0x000000001700ffeell, KEY_ESC }, + { 0x000000001f00ffeell, KEY_AUDIO }, + { 0x000000002b00ffeell, KEY_EXIT }, + { 0x000000002c00ffeell, KEY_SELECT }, + { 0x000000002d00ffeell, KEY_MENU }, + { 0x000000000500ffeell, KEY_PREVIOUS }, + { 0x000000000700ffeell, KEY_REWIND }, + { 0x000000000400ffeell, KEY_STOP }, + { 0x000000003c00ffeell, KEY_PLAYPAUSE }, + { 0x000000000800ffeell, KEY_FASTFORWARD }, + { 0x000000000600ffeell, KEY_NEXT }, + { 0x000000010000ffeell, KEY_RIGHT }, + { 0x000001000000ffeell, KEY_LEFT }, + { 0x000000003d00ffeell, KEY_SELECT }, + { 0x000100000000ffeell, KEY_VOLUMEUP }, + { 0x010000000000ffeell, KEY_VOLUMEDOWN }, + { 0x000000000100ffeell, KEY_MUTE }, + /* 0xffdc iMON MCE VFD */ + { 0x00010000ffffffeell, KEY_VOLUMEUP }, + { 0x01000000ffffffeell, KEY_VOLUMEDOWN }, + { 0x00000001ffffffeell, KEY_MUTE }, + { 0x0000000fffffffeell, KEY_MEDIA }, + { 0x00000012ffffffeell, KEY_UP }, + { 0x00000013ffffffeell, KEY_DOWN }, + { 0x00000014ffffffeell, KEY_LEFT }, + { 0x00000015ffffffeell, KEY_RIGHT }, + { 0x00000016ffffffeell, KEY_ENTER }, + { 0x00000017ffffffeell, KEY_ESC }, + /* iMON Knob values */ + { 0x000100ffffffffeell, KEY_VOLUMEUP }, + { 0x010000ffffffffeell, KEY_VOLUMEDOWN }, + { 0x000008ffffffffeell, KEY_MUTE }, + { 0, KEY_RESERVED }, + } +}; + +/* imon receiver front panel/knob key table for DH102*/ +static const struct imon_usb_dev_descr imon_DH102 = { + .flags = IMON_NO_FLAGS, + .key_table = { + { 0x000100000000ffeell, KEY_VOLUMEUP }, + { 0x010000000000ffeell, KEY_VOLUMEDOWN }, + { 0x000000010000ffeell, KEY_MUTE }, + { 0x0000000f0000ffeell, KEY_MEDIA }, + { 0x000000120000ffeell, KEY_UP }, + { 0x000000130000ffeell, KEY_DOWN }, + { 0x000000140000ffeell, KEY_LEFT }, + { 0x000000150000ffeell, KEY_RIGHT }, + { 0x000000160000ffeell, KEY_ENTER }, + { 0x000000170000ffeell, KEY_ESC }, + { 0x0000002b0000ffeell, KEY_EXIT }, + { 0x0000002c0000ffeell, KEY_SELECT }, + { 0x0000002d0000ffeell, KEY_MENU }, + { 0, KEY_RESERVED } + } }; /* @@ -208,7 +346,8 @@ * SoundGraph iMON PAD (IR & LCD) * SoundGraph iMON Knob (IR only) */ - { USB_DEVICE(0x15c2, 0xffdc) }, + { USB_DEVICE(0x15c2, 0xffdc), + .driver_info = (unsigned long)&imon_default_table }, /* * Newer devices, all driven by the latest iMON Windows driver, full @@ -216,43 +355,62 @@ * Need user input to fill in details on unknown devices. */ /* SoundGraph iMON OEM Touch LCD (IR & 7" VGA LCD) */ - { USB_DEVICE(0x15c2, 0x0034) }, + { USB_DEVICE(0x15c2, 0x0034), + .driver_info = (unsigned long)&imon_DH102 }, /* SoundGraph iMON OEM Touch LCD (IR & 4.3" VGA LCD) */ - { USB_DEVICE(0x15c2, 0x0035) }, + { USB_DEVICE(0x15c2, 0x0035), + .driver_info = (unsigned long)&imon_default_table}, /* SoundGraph iMON OEM VFD (IR & VFD) */ - { USB_DEVICE(0x15c2, 0x0036), .driver_info = IMON_NEED_20MS_PKT_DELAY }, + { USB_DEVICE(0x15c2, 0x0036), + .driver_info = (unsigned long)&imon_OEM_VFD }, /* device specifics unknown */ - { USB_DEVICE(0x15c2, 0x0037) }, + { USB_DEVICE(0x15c2, 0x0037), + .driver_info = (unsigned long)&imon_default_table}, /* SoundGraph iMON OEM LCD (IR & LCD) */ - { USB_DEVICE(0x15c2, 0x0038) }, + { USB_DEVICE(0x15c2, 0x0038), + .driver_info = (unsigned long)&imon_default_table}, /* SoundGraph iMON UltraBay (IR & LCD) */ - { USB_DEVICE(0x15c2, 0x0039) }, + { USB_DEVICE(0x15c2, 0x0039), + .driver_info = (unsigned long)&imon_default_table}, /* device specifics unknown */ - { USB_DEVICE(0x15c2, 0x003a) }, + { USB_DEVICE(0x15c2, 0x003a), + .driver_info = (unsigned long)&imon_default_table}, /* device specifics unknown */ - { USB_DEVICE(0x15c2, 0x003b) }, + { USB_DEVICE(0x15c2, 0x003b), + .driver_info = (unsigned long)&imon_default_table}, /* SoundGraph iMON OEM Inside (IR only) */ - { USB_DEVICE(0x15c2, 0x003c) }, + { USB_DEVICE(0x15c2, 0x003c), + .driver_info = (unsigned long)&imon_default_table}, /* device specifics unknown */ - { USB_DEVICE(0x15c2, 0x003d) }, + { USB_DEVICE(0x15c2, 0x003d), + .driver_info = (unsigned long)&imon_default_table}, /* device specifics unknown */ - { USB_DEVICE(0x15c2, 0x003e) }, + { USB_DEVICE(0x15c2, 0x003e), + .driver_info = (unsigned long)&imon_default_table}, /* device specifics unknown */ - { USB_DEVICE(0x15c2, 0x003f) }, + { USB_DEVICE(0x15c2, 0x003f), + .driver_info = (unsigned long)&imon_default_table}, /* device specifics unknown */ - { USB_DEVICE(0x15c2, 0x0040) }, + { USB_DEVICE(0x15c2, 0x0040), + .driver_info = (unsigned long)&imon_default_table}, /* SoundGraph iMON MINI (IR only) */ - { USB_DEVICE(0x15c2, 0x0041) }, + { USB_DEVICE(0x15c2, 0x0041), + .driver_info = (unsigned long)&imon_default_table}, /* Antec Veris Multimedia Station EZ External (IR only) */ - { USB_DEVICE(0x15c2, 0x0042) }, + { USB_DEVICE(0x15c2, 0x0042), + .driver_info = (unsigned long)&imon_default_table}, /* Antec Veris Multimedia Station Basic Internal (IR only) */ - { USB_DEVICE(0x15c2, 0x0043) }, + { USB_DEVICE(0x15c2, 0x0043), + .driver_info = (unsigned long)&imon_default_table}, /* Antec Veris Multimedia Station Elite (IR & VFD) */ - { USB_DEVICE(0x15c2, 0x0044) }, + { USB_DEVICE(0x15c2, 0x0044), + .driver_info = (unsigned long)&imon_default_table}, /* Antec Veris Multimedia Station Premiere (IR & LCD) */ - { USB_DEVICE(0x15c2, 0x0045) }, + { USB_DEVICE(0x15c2, 0x0045), + .driver_info = (unsigned long)&imon_default_table}, /* device specifics unknown */ - { USB_DEVICE(0x15c2, 0x0046) }, + { USB_DEVICE(0x15c2, 0x0046), + .driver_info = (unsigned long)&imon_default_table}, {} }; @@ -266,67 +424,6 @@ .id_table = imon_usb_id_table, }; -static struct usb_class_driver imon_vfd_class = { - .name = DEVICE_NAME, - .fops = &vfd_fops, - .minor_base = DISPLAY_MINOR_BASE, -}; - -static struct usb_class_driver imon_lcd_class = { - .name = DEVICE_NAME, - .fops = &lcd_fops, - .minor_base = DISPLAY_MINOR_BASE, -}; - -/* imon receiver front panel/knob key table */ -static const struct { - u64 hw_code; - u32 keycode; -} imon_panel_key_table[] = { - { 0x000000000f00ffeell, KEY_MEDIA }, /* Go */ - { 0x000000001200ffeell, KEY_UP }, - { 0x000000001300ffeell, KEY_DOWN }, - { 0x000000001400ffeell, KEY_LEFT }, - { 0x000000001500ffeell, KEY_RIGHT }, - { 0x000000001600ffeell, KEY_ENTER }, - { 0x000000001700ffeell, KEY_ESC }, - { 0x000000001f00ffeell, KEY_AUDIO }, - { 0x000000002000ffeell, KEY_VIDEO }, - { 0x000000002100ffeell, KEY_CAMERA }, - { 0x000000002700ffeell, KEY_DVD }, - { 0x000000002300ffeell, KEY_TV }, - { 0x000000002b00ffeell, KEY_EXIT }, - { 0x000000002c00ffeell, KEY_SELECT }, - { 0x000000002d00ffeell, KEY_MENU }, - { 0x000000000500ffeell, KEY_PREVIOUS }, - { 0x000000000700ffeell, KEY_REWIND }, - { 0x000000000400ffeell, KEY_STOP }, - { 0x000000003c00ffeell, KEY_PLAYPAUSE }, - { 0x000000000800ffeell, KEY_FASTFORWARD }, - { 0x000000000600ffeell, KEY_NEXT }, - { 0x000000010000ffeell, KEY_RIGHT }, - { 0x000001000000ffeell, KEY_LEFT }, - { 0x000000003d00ffeell, KEY_SELECT }, - { 0x000100000000ffeell, KEY_VOLUMEUP }, - { 0x010000000000ffeell, KEY_VOLUMEDOWN }, - { 0x000000000100ffeell, KEY_MUTE }, - /* 0xffdc iMON MCE VFD */ - { 0x00010000ffffffeell, KEY_VOLUMEUP }, - { 0x01000000ffffffeell, KEY_VOLUMEDOWN }, - { 0x00000001ffffffeell, KEY_MUTE }, - { 0x0000000fffffffeell, KEY_MEDIA }, - { 0x00000012ffffffeell, KEY_UP }, - { 0x00000013ffffffeell, KEY_DOWN }, - { 0x00000014ffffffeell, KEY_LEFT }, - { 0x00000015ffffffeell, KEY_RIGHT }, - { 0x00000016ffffffeell, KEY_ENTER }, - { 0x00000017ffffffeell, KEY_ESC }, - /* iMON Knob values */ - { 0x000100ffffffffeell, KEY_VOLUMEUP }, - { 0x010000ffffffffeell, KEY_VOLUMEDOWN }, - { 0x000008ffffffffeell, KEY_MUTE }, -}; - /* to prevent races between open() and disconnect(), probing, etc */ static DEFINE_MUTEX(driver_lock); @@ -825,7 +922,7 @@ * than 32 bytes are provided spaces will be appended to * generate a full screen. */ -static ssize_t vfd_write(struct file *file, const char *buf, +static ssize_t vfd_write(struct file *file, const char __user *buf, size_t n_bytes, loff_t *pos) { int i; @@ -912,7 +1009,7 @@ * display whatever diacritics you need, and so on), but it's also * a lot more complicated than most LCDs... */ -static ssize_t lcd_write(struct file *file, const char *buf, +static ssize_t lcd_write(struct file *file, const char __user *buf, size_t n_bytes, loff_t *pos) { int retval = 0; @@ -1017,7 +1114,7 @@ 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_type & rc->allowed_protocols)) dev_warn(dev, "Looks like you're trying to use an IR protocol " "this device does not support\n"); @@ -1210,18 +1307,19 @@ return keycode; } -static u32 imon_panel_key_lookup(u64 code) +static u32 imon_panel_key_lookup(struct imon_context *ictx, u64 code) { int i; u32 keycode = KEY_RESERVED; + struct imon_panel_key_table *key_table = ictx->dev_descr->key_table; - for (i = 0; i < ARRAY_SIZE(imon_panel_key_table); i++) { - if (imon_panel_key_table[i].hw_code == (code | 0xffee)) { - keycode = imon_panel_key_table[i].keycode; + for (i = 0; key_table[i].hw_code != 0; i++) { + if (key_table[i].hw_code == (code | 0xffee)) { + keycode = key_table[i].keycode; break; } } - + ictx->release_code = false; return keycode; } @@ -1340,7 +1438,7 @@ } buf[2] = dir & 0xFF; buf[3] = (dir >> 8) & 0xFF; - scancode = be32_to_cpu(*((u32 *)buf)); + scancode = be32_to_cpu(*((__be32 *)buf)); } } else { /* @@ -1370,7 +1468,7 @@ * 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. */ @@ -1404,7 +1502,7 @@ } buf[2] = dir & 0xFF; buf[3] = (dir >> 8) & 0xFF; - scancode = be32_to_cpu(*((u32 *)buf)); + scancode = be32_to_cpu(*((__be32 *)buf)); } else { /* * Hack alert: instead of using keycodes, we have @@ -1509,11 +1607,12 @@ /* Figure out what key was pressed */ if (len == 8 && buf[7] == 0xee) { - scancode = be64_to_cpu(*((u64 *)buf)); + scancode = be64_to_cpu(*((__be64 *)buf)); ktype = IMON_KEY_PANEL; - kc = imon_panel_key_lookup(scancode); + kc = imon_panel_key_lookup(ictx, scancode); + ictx->release_code = false; } else { - scancode = be32_to_cpu(*((u32 *)buf)); + scancode = be32_to_cpu(*((__be32 *)buf)); if (ictx->rc_type == RC_BIT_RC6_MCE) { ktype = IMON_KEY_IMON; if (buf[0] == 0x80) @@ -1579,7 +1678,11 @@ if (press_type == 0) rc_keyup(ictx->rdev); else { - rc_keydown(ictx->rdev, ictx->rc_scancode, ictx->rc_toggle); + if (ictx->rc_type == RC_BIT_RC6_MCE || + ictx->rc_type == RC_BIT_OTHER) + rc_keydown(ictx->rdev, + ictx->rc_type == RC_BIT_RC6_MCE ? RC_TYPE_RC6_MCE : RC_TYPE_OTHER, + ictx->rc_scancode, ictx->rc_toggle); spin_lock_irqsave(&ictx->kc_lock, flags); ictx->last_keycode = ictx->kc; spin_unlock_irqrestore(&ictx->kc_lock, flags); @@ -1867,7 +1970,7 @@ rdev->priv = ictx; rdev->driver_type = RC_DRIVER_SCANCODE; - rdev->allowed_protos = RC_BIT_OTHER | RC_BIT_RC6_MCE; /* iMON PAD or MCE */ + rdev->allowed_protocols = RC_BIT_OTHER | RC_BIT_RC6_MCE; /* iMON PAD or MCE */ rdev->change_protocol = imon_ir_change_protocol; rdev->driver_name = MOD_NAME; @@ -1880,7 +1983,7 @@ if (ictx->product == 0xffdc) { imon_get_ffdc_type(ictx); - rdev->allowed_protos = ictx->rc_type; + rdev->allowed_protocols = ictx->rc_type; } imon_set_display_type(ictx); @@ -1905,14 +2008,13 @@ static struct input_dev *imon_init_idev(struct imon_context *ictx) { + struct imon_panel_key_table *key_table = ictx->dev_descr->key_table; struct input_dev *idev; 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)", @@ -1932,8 +2034,8 @@ BIT_MASK(REL_WHEEL); /* panel and/or knob code support */ - for (i = 0; i < ARRAY_SIZE(imon_panel_key_table); i++) { - u32 kc = imon_panel_key_table[i].keycode; + for (i = 0; key_table[i].hw_code != 0; i++) { + u32 kc = key_table[i].keycode; __set_bit(kc, idev->keybit); } @@ -1960,10 +2062,8 @@ 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)", @@ -2024,7 +2124,7 @@ for (i = 0; i < num_endpts && !(ir_ep_found && display_ep_found); ++i) { ep = &iface_desc->endpoint[i].desc; ep_dir = ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK; - ep_type = ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; + ep_type = usb_endpoint_type(ep); if (!ir_ep_found && ep_dir == USB_DIR_IN && ep_type == USB_ENDPOINT_XFER_INT) { @@ -2136,9 +2236,11 @@ ictx->vendor = le16_to_cpu(ictx->usbdev_intf0->descriptor.idVendor); ictx->product = le16_to_cpu(ictx->usbdev_intf0->descriptor.idProduct); + /* save drive info for later accessing the panel/knob key table */ + ictx->dev_descr = (struct imon_usb_dev_descr *)id->driver_info; /* 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; + ictx->send_packet_delay = ictx->dev_descr->flags & + IMON_NEED_20MS_PKT_DELAY ? 20 : 5; ret = -ENODEV; iface_desc = intf->cur_altsetting; @@ -2182,6 +2284,7 @@ usb_kill_urb(ictx->rx_urb_intf0); urb_submit_failed: find_endpoint_failed: + usb_put_dev(ictx->usbdev_intf0); mutex_unlock(&ictx->lock); usb_free_urb(tx_urb); tx_urb_alloc_failed: @@ -2254,6 +2357,7 @@ input_unregister_device(ictx->touch); touch_setup_failed: find_endpoint_failed: + usb_put_dev(ictx->usbdev_intf1); mutex_unlock(&ictx->lock); usb_free_urb(rx_urb); rx_urb_alloc_failed: @@ -2367,11 +2471,13 @@ usbdev->bus->busnum, usbdev->devnum); mutex_unlock(&driver_lock); + usb_put_dev(usbdev); return 0; fail: mutex_unlock(&driver_lock); + usb_put_dev(usbdev); dev_err(dev, "unable to register, err %d\n", ret); return ret; @@ -2411,6 +2517,7 @@ if (ifnum == 0) { ictx->dev_present_intf0 = false; usb_kill_urb(ictx->rx_urb_intf0); + usb_put_dev(ictx->usbdev_intf0); input_unregister_device(ictx->idev); rc_unregister_device(ictx->rdev); if (ictx->display_supported) { @@ -2422,6 +2529,7 @@ } else { ictx->dev_present_intf1 = false; usb_kill_urb(ictx->rx_urb_intf1); + usb_put_dev(ictx->usbdev_intf1); if (ictx->display_type == IMON_DISPLAY_TYPE_VGA) { input_unregister_device(ictx->touch); del_timer_sync(&ictx->ttimer);