summaryrefslogtreecommitdiff
path: root/drivers/usb
diff options
context:
space:
mode:
authorOliver Neukum <oneukum@suse.de>2014-05-19 13:53:55 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-05-27 16:03:57 -0700
commit552e1f2679b7b766b8b8de3dc6d83d9cd28f28b2 (patch)
tree1e696b32dccada97e0aa1431daf1f8c8a23a0d75 /drivers/usb
parentd846b7650db3fcca7901b6e23f6416c3601a3dfe (diff)
USB: appledisplay: fix race between reading and writing from the device
The workqueue handler may call appledisplay_bl_get_brightness() while user space calls appledisplay_bl_update_status(). As they share a buffer that must not happen. Use a mutex for mutual exclusion. Signed-off-by: Oliver Neukum <oneukum@suse.de> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/misc/appledisplay.c13
1 files changed, 10 insertions, 3 deletions
diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c
index f37c78d1bdf4..b3d245ef46ef 100644
--- a/drivers/usb/misc/appledisplay.c
+++ b/drivers/usb/misc/appledisplay.c
@@ -81,6 +81,7 @@ struct appledisplay {
struct delayed_work work;
int button_pressed;
spinlock_t lock;
+ struct mutex sysfslock; /* concurrent read and write */
};
static atomic_t count_displays = ATOMIC_INIT(0);
@@ -144,6 +145,7 @@ static int appledisplay_bl_update_status(struct backlight_device *bd)
struct appledisplay *pdata = bl_get_data(bd);
int retval;
+ mutex_lock(&pdata->sysfslock);
pdata->msgdata[0] = 0x10;
pdata->msgdata[1] = bd->props.brightness;
@@ -156,15 +158,17 @@ static int appledisplay_bl_update_status(struct backlight_device *bd)
0,
pdata->msgdata, 2,
ACD_USB_TIMEOUT);
-
+ mutex_unlock(&pdata->sysfslock);
+
return retval;
}
static int appledisplay_bl_get_brightness(struct backlight_device *bd)
{
struct appledisplay *pdata = bl_get_data(bd);
- int retval;
+ int retval, brightness;
+ mutex_lock(&pdata->sysfslock);
retval = usb_control_msg(
pdata->udev,
usb_rcvctrlpipe(pdata->udev, 0),
@@ -174,11 +178,13 @@ static int appledisplay_bl_get_brightness(struct backlight_device *bd)
0,
pdata->msgdata, 2,
ACD_USB_TIMEOUT);
+ brightness = pdata->msgdata[1];
+ mutex_unlock(&pdata->sysfslock);
if (retval < 0)
return retval;
else
- return pdata->msgdata[1];
+ return brightness;
}
static const struct backlight_ops appledisplay_bl_data = {
@@ -241,6 +247,7 @@ static int appledisplay_probe(struct usb_interface *iface,
spin_lock_init(&pdata->lock);
INIT_DELAYED_WORK(&pdata->work, appledisplay_work);
+ mutex_init(&pdata->sysfslock);
/* Allocate buffer for control messages */
pdata->msgdata = kmalloc(ACD_MSG_BUFFER_LEN, GFP_KERNEL);