|
@@ -46,7 +46,7 @@
|
|
|
#define MOD_AUTHOR "Jarod Wilson <jarod@wilsonet.com>"
|
|
|
#define MOD_DESC "Driver for SoundGraph iMON MultiMedia IR/Display"
|
|
|
#define MOD_NAME "imon"
|
|
|
-#define MOD_VERSION "0.9.2"
|
|
|
+#define MOD_VERSION "0.9.3"
|
|
|
|
|
|
#define DISPLAY_MINOR_BASE 144
|
|
|
#define DEVICE_NAME "lcd%d"
|
|
@@ -460,8 +460,9 @@ static int display_close(struct inode *inode, struct file *file)
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Sends a packet to the device -- this function must be called
|
|
|
- * with ictx->lock held.
|
|
|
+ * Sends a packet to the device -- this function must be called with
|
|
|
+ * ictx->lock held, or its unlock/lock sequence while waiting for tx
|
|
|
+ * to complete can/will lead to a deadlock.
|
|
|
*/
|
|
|
static int send_packet(struct imon_context *ictx)
|
|
|
{
|
|
@@ -991,12 +992,21 @@ static void imon_touch_display_timeout(unsigned long data)
|
|
|
* the iMON remotes, and those used by the Windows MCE remotes (which is
|
|
|
* really just RC-6), but only one or the other at a time, as the signals
|
|
|
* are decoded onboard the receiver.
|
|
|
+ *
|
|
|
+ * This function gets called two different ways, one way is from
|
|
|
+ * rc_register_device, for initial protocol selection/setup, and the other is
|
|
|
+ * via a userspace-initiated protocol change request, either by direct sysfs
|
|
|
+ * prodding or by something like ir-keytable. In the rc_register_device case,
|
|
|
+ * the imon context lock is already held, but when initiated from userspace,
|
|
|
+ * 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)
|
|
|
{
|
|
|
int retval;
|
|
|
struct imon_context *ictx = rc->priv;
|
|
|
struct device *dev = ictx->dev;
|
|
|
+ bool unlock = false;
|
|
|
unsigned char ir_proto_packet[] = {
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86 };
|
|
|
|
|
@@ -1029,6 +1039,11 @@ static int imon_ir_change_protocol(struct rc_dev *rc, u64 rc_type)
|
|
|
|
|
|
memcpy(ictx->usb_tx_buf, &ir_proto_packet, sizeof(ir_proto_packet));
|
|
|
|
|
|
+ if (!mutex_is_locked(&ictx->lock)) {
|
|
|
+ unlock = true;
|
|
|
+ mutex_lock(&ictx->lock);
|
|
|
+ }
|
|
|
+
|
|
|
retval = send_packet(ictx);
|
|
|
if (retval)
|
|
|
goto out;
|
|
@@ -1037,6 +1052,9 @@ static int imon_ir_change_protocol(struct rc_dev *rc, u64 rc_type)
|
|
|
ictx->pad_mouse = false;
|
|
|
|
|
|
out:
|
|
|
+ if (unlock)
|
|
|
+ mutex_unlock(&ictx->lock);
|
|
|
+
|
|
|
return retval;
|
|
|
}
|
|
|
|
|
@@ -2134,6 +2152,7 @@ static struct imon_context *imon_init_intf0(struct usb_interface *intf)
|
|
|
goto rdev_setup_failed;
|
|
|
}
|
|
|
|
|
|
+ mutex_unlock(&ictx->lock);
|
|
|
return ictx;
|
|
|
|
|
|
rdev_setup_failed:
|
|
@@ -2205,6 +2224,7 @@ static struct imon_context *imon_init_intf1(struct usb_interface *intf,
|
|
|
goto urb_submit_failed;
|
|
|
}
|
|
|
|
|
|
+ mutex_unlock(&ictx->lock);
|
|
|
return ictx;
|
|
|
|
|
|
urb_submit_failed:
|
|
@@ -2299,6 +2319,8 @@ static int __devinit imon_probe(struct usb_interface *interface,
|
|
|
usb_set_intfdata(interface, ictx);
|
|
|
|
|
|
if (ifnum == 0) {
|
|
|
+ mutex_lock(&ictx->lock);
|
|
|
+
|
|
|
if (product == 0xffdc && ictx->rf_device) {
|
|
|
sysfs_err = sysfs_create_group(&interface->dev.kobj,
|
|
|
&imon_rf_attr_group);
|
|
@@ -2309,13 +2331,14 @@ static int __devinit imon_probe(struct usb_interface *interface,
|
|
|
|
|
|
if (ictx->display_supported)
|
|
|
imon_init_display(ictx, interface);
|
|
|
+
|
|
|
+ mutex_unlock(&ictx->lock);
|
|
|
}
|
|
|
|
|
|
dev_info(dev, "iMON device (%04x:%04x, intf%d) on "
|
|
|
"usb<%d:%d> initialized\n", vendor, product, ifnum,
|
|
|
usbdev->bus->busnum, usbdev->devnum);
|
|
|
|
|
|
- mutex_unlock(&ictx->lock);
|
|
|
mutex_unlock(&driver_lock);
|
|
|
|
|
|
return 0;
|