hc
2024-01-03 2f7c68cb55ecb7331f2381deb497c27155f32faf
kernel/drivers/media/rc/imon.c
....@@ -1,3 +1,4 @@
1
+// SPDX-License-Identifier: GPL-2.0-or-later
12 /*
23 * imon.c: input and display driver for SoundGraph iMON IR/VFD/LCD
34 *
....@@ -10,16 +11,6 @@
1011 * which the support for them wouldn't be nearly as good. Thanks
1112 * also to the numerous 0xffdc device owners that tested auto-config
1213 * support for me and provided debug dumps from their devices.
13
- *
14
- * imon is free software; you can redistribute it and/or modify
15
- * it under the terms of the GNU General Public License as published by
16
- * the Free Software Foundation; either version 2 of the License, or
17
- * (at your option) any later version.
18
- *
19
- * This program is distributed in the hope that it will be useful,
20
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
21
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22
- * GNU General Public License for more details.
2314 */
2415
2516 #define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
....@@ -92,6 +83,7 @@
9283 __u16 flags;
9384 #define IMON_NO_FLAGS 0
9485 #define IMON_NEED_20MS_PKT_DELAY 1
86
+#define IMON_SUPPRESS_REPEATED_KEYS 2
9587 struct imon_panel_key_table key_table[];
9688 };
9789
....@@ -158,8 +150,27 @@
158150 struct timer_list ttimer; /* touch screen timer */
159151 int touch_x; /* x coordinate on touchscreen */
160152 int touch_y; /* y coordinate on touchscreen */
161
- struct imon_usb_dev_descr *dev_descr; /* device description with key
162
- table for front panels */
153
+ const struct imon_usb_dev_descr *dev_descr;
154
+ /* device description with key */
155
+ /* table for front panels */
156
+ /*
157
+ * Fields for deferring free_imon_context().
158
+ *
159
+ * Since reference to "struct imon_context" is stored into
160
+ * "struct file"->private_data, we need to remember
161
+ * how many file descriptors might access this "struct imon_context".
162
+ */
163
+ refcount_t users;
164
+ /*
165
+ * Use a flag for telling display_open()/vfd_write()/lcd_write() that
166
+ * imon_disconnect() was already called.
167
+ */
168
+ bool disconnected;
169
+ /*
170
+ * We need to wait for RCU grace period in order to allow
171
+ * display_open() to safely check ->disconnected and increment ->users.
172
+ */
173
+ struct rcu_head rcu;
163174 };
164175
165176 #define TOUCH_TIMEOUT (HZ/30)
....@@ -167,18 +178,18 @@
167178 /* vfd character device file operations */
168179 static const struct file_operations vfd_fops = {
169180 .owner = THIS_MODULE,
170
- .open = &display_open,
171
- .write = &vfd_write,
172
- .release = &display_close,
181
+ .open = display_open,
182
+ .write = vfd_write,
183
+ .release = display_close,
173184 .llseek = noop_llseek,
174185 };
175186
176187 /* lcd character device file operations */
177188 static const struct file_operations lcd_fops = {
178189 .owner = THIS_MODULE,
179
- .open = &display_open,
180
- .write = &lcd_write,
181
- .release = &display_close,
190
+ .open = display_open,
191
+ .write = lcd_write,
192
+ .release = display_close,
182193 .llseek = noop_llseek,
183194 };
184195
....@@ -324,6 +335,32 @@
324335 }
325336 };
326337
338
+/* imon ultrabay front panel key table */
339
+static const struct imon_usb_dev_descr ultrabay_table = {
340
+ .flags = IMON_SUPPRESS_REPEATED_KEYS,
341
+ .key_table = {
342
+ { 0x0000000f0000ffeell, KEY_MEDIA }, /* Go */
343
+ { 0x000000000100ffeell, KEY_UP },
344
+ { 0x000000000001ffeell, KEY_DOWN },
345
+ { 0x000000160000ffeell, KEY_ENTER },
346
+ { 0x0000001f0000ffeell, KEY_AUDIO }, /* Music */
347
+ { 0x000000200000ffeell, KEY_VIDEO }, /* Movie */
348
+ { 0x000000210000ffeell, KEY_CAMERA }, /* Photo */
349
+ { 0x000000270000ffeell, KEY_DVD }, /* DVD */
350
+ { 0x000000230000ffeell, KEY_TV }, /* TV */
351
+ { 0x000000050000ffeell, KEY_PREVIOUS }, /* Previous */
352
+ { 0x000000070000ffeell, KEY_REWIND },
353
+ { 0x000000040000ffeell, KEY_STOP },
354
+ { 0x000000020000ffeell, KEY_PLAYPAUSE },
355
+ { 0x000000080000ffeell, KEY_FASTFORWARD },
356
+ { 0x000000060000ffeell, KEY_NEXT }, /* Next */
357
+ { 0x000100000000ffeell, KEY_VOLUMEUP },
358
+ { 0x010000000000ffeell, KEY_VOLUMEDOWN },
359
+ { 0x000000010000ffeell, KEY_MUTE },
360
+ { 0, KEY_RESERVED },
361
+ }
362
+};
363
+
327364 /*
328365 * USB Device ID for iMON USB Control Boards
329366 *
....@@ -420,9 +457,6 @@
420457 .id_table = imon_usb_id_table,
421458 };
422459
423
-/* to prevent races between open() and disconnect(), probing, etc */
424
-static DEFINE_MUTEX(driver_lock);
425
-
426460 /* Module bookkeeping bits */
427461 MODULE_AUTHOR(MOD_AUTHOR);
428462 MODULE_DESCRIPTION(MOD_DESC);
....@@ -462,9 +496,11 @@
462496 struct device *dev = ictx->dev;
463497
464498 usb_free_urb(ictx->tx_urb);
499
+ WARN_ON(ictx->dev_present_intf0);
465500 usb_free_urb(ictx->rx_urb_intf0);
501
+ WARN_ON(ictx->dev_present_intf1);
466502 usb_free_urb(ictx->rx_urb_intf1);
467
- kfree(ictx);
503
+ kfree_rcu(ictx, rcu);
468504
469505 dev_dbg(dev, "%s: iMON context freed\n", __func__);
470506 }
....@@ -480,9 +516,6 @@
480516 int subminor;
481517 int retval = 0;
482518
483
- /* prevent races with disconnect */
484
- mutex_lock(&driver_lock);
485
-
486519 subminor = iminor(inode);
487520 interface = usb_find_interface(&imon_driver, subminor);
488521 if (!interface) {
....@@ -490,13 +523,16 @@
490523 retval = -ENODEV;
491524 goto exit;
492525 }
493
- ictx = usb_get_intfdata(interface);
494526
495
- if (!ictx) {
527
+ rcu_read_lock();
528
+ ictx = usb_get_intfdata(interface);
529
+ if (!ictx || ictx->disconnected || !refcount_inc_not_zero(&ictx->users)) {
530
+ rcu_read_unlock();
496531 pr_err("no context found for minor %d\n", subminor);
497532 retval = -ENODEV;
498533 goto exit;
499534 }
535
+ rcu_read_unlock();
500536
501537 mutex_lock(&ictx->lock);
502538
....@@ -514,8 +550,10 @@
514550
515551 mutex_unlock(&ictx->lock);
516552
553
+ if (retval && refcount_dec_and_test(&ictx->users))
554
+ free_imon_context(ictx);
555
+
517556 exit:
518
- mutex_unlock(&driver_lock);
519557 return retval;
520558 }
521559
....@@ -525,15 +563,8 @@
525563 */
526564 static int display_close(struct inode *inode, struct file *file)
527565 {
528
- struct imon_context *ictx = NULL;
566
+ struct imon_context *ictx = file->private_data;
529567 int retval = 0;
530
-
531
- ictx = file->private_data;
532
-
533
- if (!ictx) {
534
- pr_err("no context for device\n");
535
- return -ENODEV;
536
- }
537568
538569 mutex_lock(&ictx->lock);
539570
....@@ -549,6 +580,8 @@
549580 }
550581
551582 mutex_unlock(&ictx->lock);
583
+ if (refcount_dec_and_test(&ictx->users))
584
+ free_imon_context(ictx);
552585 return retval;
553586 }
554587
....@@ -613,15 +646,14 @@
613646 pr_err_ratelimited("error submitting urb(%d)\n", retval);
614647 } else {
615648 /* Wait for transmission to complete (or abort) */
616
- mutex_unlock(&ictx->lock);
617649 retval = wait_for_completion_interruptible(
618650 &ictx->tx.finished);
619651 if (retval) {
620652 usb_kill_urb(ictx->tx_urb);
621653 pr_err_ratelimited("task interrupted\n");
622654 }
623
- mutex_lock(&ictx->lock);
624655
656
+ ictx->tx.busy = false;
625657 retval = ictx->tx.status;
626658 if (retval)
627659 pr_err_ratelimited("packet tx failed (%d)\n", retval);
....@@ -772,11 +804,11 @@
772804
773805 mutex_lock(&ictx->lock);
774806 if (ictx->rf_isassociating)
775
- strcpy(buf, "associating\n");
807
+ strscpy(buf, "associating\n", PAGE_SIZE);
776808 else
777
- strcpy(buf, "closed\n");
809
+ strscpy(buf, "closed\n", PAGE_SIZE);
778810
779
- dev_info(d, "Visit http://www.lirc.org/html/imon-24g.html for instructions on how to associate your iMON 2.4G DT/LT remote\n");
811
+ dev_info(d, "Visit https://www.lirc.org/html/imon-24g.html for instructions on how to associate your iMON 2.4G DT/LT remote\n");
780812 mutex_unlock(&ictx->lock);
781813 return strlen(buf);
782814 }
....@@ -918,17 +950,15 @@
918950 int offset;
919951 int seq;
920952 int retval = 0;
921
- struct imon_context *ictx;
953
+ struct imon_context *ictx = file->private_data;
922954 static const unsigned char vfd_packet6[] = {
923955 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF };
924956
925
- ictx = file->private_data;
926
- if (!ictx) {
927
- pr_err_ratelimited("no context for device\n");
957
+ if (ictx->disconnected)
928958 return -ENODEV;
929
- }
930959
931
- mutex_lock(&ictx->lock);
960
+ if (mutex_lock_interruptible(&ictx->lock))
961
+ return -ERESTARTSYS;
932962
933963 if (!ictx->dev_present_intf0) {
934964 pr_err_ratelimited("no iMON device present\n");
....@@ -1002,13 +1032,10 @@
10021032 size_t n_bytes, loff_t *pos)
10031033 {
10041034 int retval = 0;
1005
- struct imon_context *ictx;
1035
+ struct imon_context *ictx = file->private_data;
10061036
1007
- ictx = file->private_data;
1008
- if (!ictx) {
1009
- pr_err_ratelimited("no context for device\n");
1037
+ if (ictx->disconnected)
10101038 return -ENODEV;
1011
- }
10121039
10131040 mutex_lock(&ictx->lock);
10141041
....@@ -1273,9 +1300,11 @@
12731300
12741301 static u32 imon_panel_key_lookup(struct imon_context *ictx, u64 code)
12751302 {
1276
- int i;
1303
+ const struct imon_panel_key_table *key_table;
12771304 u32 keycode = KEY_RESERVED;
1278
- struct imon_panel_key_table *key_table = ictx->dev_descr->key_table;
1305
+ int i;
1306
+
1307
+ key_table = ictx->dev_descr->key_table;
12791308
12801309 for (i = 0; key_table[i].hw_code != 0; i++) {
12811310 if (key_table[i].hw_code == (code | 0xffee)) {
....@@ -1559,7 +1588,6 @@
15591588 u32 kc;
15601589 u64 scancode;
15611590 int press_type = 0;
1562
- long msec;
15631591 ktime_t t;
15641592 static ktime_t prev_time;
15651593 u8 ktype;
....@@ -1661,14 +1689,16 @@
16611689 spin_lock_irqsave(&ictx->kc_lock, flags);
16621690
16631691 t = ktime_get();
1664
- /* KEY_MUTE repeats from knob need to be suppressed */
1665
- if (ictx->kc == KEY_MUTE && ictx->kc == ictx->last_keycode) {
1666
- msec = ktime_ms_delta(t, prev_time);
1667
- if (msec < ictx->idev->rep[REP_DELAY]) {
1692
+ /* KEY repeats from knob and panel that need to be suppressed */
1693
+ if (ictx->kc == KEY_MUTE ||
1694
+ ictx->dev_descr->flags & IMON_SUPPRESS_REPEATED_KEYS) {
1695
+ if (ictx->kc == ictx->last_keycode &&
1696
+ ktime_ms_delta(t, prev_time) < ictx->idev->rep[REP_DELAY]) {
16681697 spin_unlock_irqrestore(&ictx->kc_lock, flags);
16691698 return;
16701699 }
16711700 }
1701
+
16721702 prev_time = t;
16731703 kc = ictx->kc;
16741704
....@@ -1856,6 +1886,14 @@
18561886 dev_info(ictx->dev, "0xffdc iMON Inside, iMON IR");
18571887 ictx->display_supported = false;
18581888 break;
1889
+ /* Soundgraph iMON UltraBay */
1890
+ case 0x98:
1891
+ dev_info(ictx->dev, "0xffdc iMON UltraBay, LCD + IR");
1892
+ detected_display_type = IMON_DISPLAY_TYPE_LCD;
1893
+ allowed_protos = RC_PROTO_BIT_IMON | RC_PROTO_BIT_RC6_MCE;
1894
+ ictx->dev_descr = &ultrabay_table;
1895
+ break;
1896
+
18591897 default:
18601898 dev_info(ictx->dev, "Unknown 0xffdc device, defaulting to VFD and iMON IR");
18611899 detected_display_type = IMON_DISPLAY_TYPE_VFD;
....@@ -1987,9 +2025,11 @@
19872025
19882026 static struct input_dev *imon_init_idev(struct imon_context *ictx)
19892027 {
1990
- struct imon_panel_key_table *key_table = ictx->dev_descr->key_table;
2028
+ const struct imon_panel_key_table *key_table;
19912029 struct input_dev *idev;
19922030 int ret, i;
2031
+
2032
+ key_table = ictx->dev_descr->key_table;
19932033
19942034 idev = input_allocate_device();
19952035 if (!idev)
....@@ -2373,7 +2413,6 @@
23732413 int ifnum, sysfs_err;
23742414 int ret = 0;
23752415 struct imon_context *ictx = NULL;
2376
- struct imon_context *first_if_ctx = NULL;
23772416 u16 vendor, product;
23782417
23792418 usbdev = usb_get_dev(interface_to_usbdev(interface));
....@@ -2385,16 +2424,11 @@
23852424 dev_dbg(dev, "%s: found iMON device (%04x:%04x, intf%d)\n",
23862425 __func__, vendor, product, ifnum);
23872426
2388
- /* prevent races probing devices w/multiple interfaces */
2389
- mutex_lock(&driver_lock);
2390
-
23912427 first_if = usb_ifnum_to_if(usbdev, 0);
23922428 if (!first_if) {
23932429 ret = -ENODEV;
23942430 goto fail;
23952431 }
2396
-
2397
- first_if_ctx = usb_get_intfdata(first_if);
23982432
23992433 if (ifnum == 0) {
24002434 ictx = imon_init_intf0(interface, id);
....@@ -2403,9 +2437,11 @@
24032437 ret = -ENODEV;
24042438 goto fail;
24052439 }
2440
+ refcount_set(&ictx->users, 1);
24062441
24072442 } else {
24082443 /* this is the secondary interface on the device */
2444
+ struct imon_context *first_if_ctx = usb_get_intfdata(first_if);
24092445
24102446 /* fail early if first intf failed to register */
24112447 if (!first_if_ctx) {
....@@ -2419,14 +2455,13 @@
24192455 ret = -ENODEV;
24202456 goto fail;
24212457 }
2458
+ refcount_inc(&ictx->users);
24222459
24232460 }
24242461
24252462 usb_set_intfdata(interface, ictx);
24262463
24272464 if (ifnum == 0) {
2428
- mutex_lock(&ictx->lock);
2429
-
24302465 if (product == 0xffdc && ictx->rf_device) {
24312466 sysfs_err = sysfs_create_group(&interface->dev.kobj,
24322467 &imon_rf_attr_group);
....@@ -2437,21 +2472,17 @@
24372472
24382473 if (ictx->display_supported)
24392474 imon_init_display(ictx, interface);
2440
-
2441
- mutex_unlock(&ictx->lock);
24422475 }
24432476
24442477 dev_info(dev, "iMON device (%04x:%04x, intf%d) on usb<%d:%d> initialized\n",
24452478 vendor, product, ifnum,
24462479 usbdev->bus->busnum, usbdev->devnum);
24472480
2448
- mutex_unlock(&driver_lock);
24492481 usb_put_dev(usbdev);
24502482
24512483 return 0;
24522484
24532485 fail:
2454
- mutex_unlock(&driver_lock);
24552486 usb_put_dev(usbdev);
24562487 dev_err(dev, "unable to register, err %d\n", ret);
24572488
....@@ -2467,10 +2498,8 @@
24672498 struct device *dev;
24682499 int ifnum;
24692500
2470
- /* prevent races with multi-interface device probing and display_open */
2471
- mutex_lock(&driver_lock);
2472
-
24732501 ictx = usb_get_intfdata(interface);
2502
+ ictx->disconnected = true;
24742503 dev = ictx->dev;
24752504 ifnum = interface->cur_altsetting->desc.bInterfaceNumber;
24762505
....@@ -2511,10 +2540,8 @@
25112540 }
25122541 }
25132542
2514
- if (!ictx->dev_present_intf0 && !ictx->dev_present_intf1)
2543
+ if (refcount_dec_and_test(&ictx->users))
25152544 free_imon_context(ictx);
2516
-
2517
- mutex_unlock(&driver_lock);
25182545
25192546 dev_dbg(dev, "%s: iMON device (intf%d) disconnected\n",
25202547 __func__, ifnum);