summaryrefslogtreecommitdiff
path: root/drivers/usb/misc/appledisplay.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/misc/appledisplay.c')
-rw-r--r--drivers/usb/misc/appledisplay.c118
1 files changed, 46 insertions, 72 deletions
diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c
index ba6a5d6e618e..62b5a30edc42 100644
--- a/drivers/usb/misc/appledisplay.c
+++ b/drivers/usb/misc/appledisplay.c
@@ -1,23 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* Apple Cinema Display driver
*
* Copyright (C) 2006 Michael Hanselmann (linux-kernel@hansmi.ch)
*
* Thanks to Caskey L. Dickson for his work with acdctl.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <linux/kernel.h>
@@ -63,6 +50,8 @@ static const struct usb_device_id appledisplay_table[] = {
{ APPLEDISPLAY_DEVICE(0x9219) },
{ APPLEDISPLAY_DEVICE(0x921c) },
{ APPLEDISPLAY_DEVICE(0x921d) },
+ { APPLEDISPLAY_DEVICE(0x9222) },
+ { APPLEDISPLAY_DEVICE(0x9226) },
{ APPLEDISPLAY_DEVICE(0x9236) },
/* Terminating entry */
@@ -80,17 +69,15 @@ 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);
-static struct workqueue_struct *wq;
static void appledisplay_complete(struct urb *urb)
{
struct appledisplay *pdata = urb->context;
struct device *dev = &pdata->udev->dev;
- unsigned long flags;
int status = urb->status;
int retval;
@@ -102,6 +89,7 @@ static void appledisplay_complete(struct urb *urb)
dev_err(dev,
"OVERFLOW with data length %d, actual length is %d\n",
ACD_URB_BUFFER_LEN, pdata->urb->actual_length);
+ fallthrough;
case -ECONNRESET:
case -ENOENT:
case -ESHUTDOWN:
@@ -110,18 +98,21 @@ static void appledisplay_complete(struct urb *urb)
__func__, status);
return;
default:
- dev_dbg(dev, "%s - nonzero urb status received: %d/n",
+ dev_dbg(dev, "%s - nonzero urb status received: %d\n",
__func__, status);
goto exit;
}
- spin_lock_irqsave(&pdata->lock, flags);
-
switch(pdata->urbdata[1]) {
case ACD_BTN_BRIGHT_UP:
case ACD_BTN_BRIGHT_DOWN:
pdata->button_pressed = 1;
- queue_delayed_work(wq, &pdata->work, 0);
+ /*
+ * there is a window during which no device
+ * is registered
+ */
+ if (pdata->bd )
+ schedule_delayed_work(&pdata->work, 0);
break;
case ACD_BTN_NONE:
default:
@@ -129,8 +120,6 @@ static void appledisplay_complete(struct urb *urb)
break;
}
- spin_unlock_irqrestore(&pdata->lock, flags);
-
exit:
retval = usb_submit_urb(pdata->urb, GFP_ATOMIC);
if (retval) {
@@ -144,6 +133,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 +146,20 @@ static int appledisplay_bl_update_status(struct backlight_device *bd)
0,
pdata->msgdata, 2,
ACD_USB_TIMEOUT);
+ mutex_unlock(&pdata->sysfslock);
- return retval;
+ if (retval < 0)
+ return retval;
+ else
+ return 0;
}
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 +169,18 @@ static int appledisplay_bl_get_brightness(struct backlight_device *bd)
0,
pdata->msgdata, 2,
ACD_USB_TIMEOUT);
+ if (retval < 2) {
+ if (retval >= 0)
+ retval = -EMSGSIZE;
+ } else {
+ 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 = {
@@ -205,49 +207,40 @@ static int appledisplay_probe(struct usb_interface *iface,
const struct usb_device_id *id)
{
struct backlight_properties props;
+ struct backlight_device *backlight;
struct appledisplay *pdata;
struct usb_device *udev = interface_to_usbdev(iface);
- struct usb_host_interface *iface_desc;
struct usb_endpoint_descriptor *endpoint;
int int_in_endpointAddr = 0;
- int i, retval = -ENOMEM, brightness;
+ int retval, brightness;
char bl_name[20];
/* set up the endpoint information */
/* use only the first interrupt-in endpoint */
- iface_desc = iface->cur_altsetting;
- for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
- endpoint = &iface_desc->endpoint[i].desc;
- if (!int_in_endpointAddr && usb_endpoint_is_int_in(endpoint)) {
- /* we found an interrupt in endpoint */
- int_in_endpointAddr = endpoint->bEndpointAddress;
- break;
- }
- }
- if (!int_in_endpointAddr) {
+ retval = usb_find_int_in_endpoint(iface->cur_altsetting, &endpoint);
+ if (retval) {
dev_err(&iface->dev, "Could not find int-in endpoint\n");
- return -EIO;
+ return retval;
}
+ int_in_endpointAddr = endpoint->bEndpointAddress;
+
/* allocate memory for our device state and initialize it */
pdata = kzalloc(sizeof(struct appledisplay), GFP_KERNEL);
if (!pdata) {
retval = -ENOMEM;
- dev_err(&iface->dev, "Out of memory\n");
goto error;
}
pdata->udev = udev;
- 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);
if (!pdata->msgdata) {
retval = -ENOMEM;
- dev_err(&iface->dev,
- "Allocating buffer for control messages failed\n");
goto error;
}
@@ -255,7 +248,6 @@ static int appledisplay_probe(struct usb_interface *iface,
pdata->urb = usb_alloc_urb(0, GFP_KERNEL);
if (!pdata->urb) {
retval = -ENOMEM;
- dev_err(&iface->dev, "Allocating URB failed\n");
goto error;
}
@@ -273,6 +265,7 @@ static int appledisplay_probe(struct usb_interface *iface,
usb_rcvintpipe(udev, int_in_endpointAddr),
pdata->urbdata, ACD_URB_BUFFER_LEN, appledisplay_complete,
pdata, 1);
+ pdata->urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
if (usb_submit_urb(pdata->urb, GFP_KERNEL)) {
retval = -EIO;
dev_err(&iface->dev, "Submitting URB failed\n");
@@ -285,13 +278,14 @@ static int appledisplay_probe(struct usb_interface *iface,
memset(&props, 0, sizeof(struct backlight_properties));
props.type = BACKLIGHT_RAW;
props.max_brightness = 0xff;
- pdata->bd = backlight_device_register(bl_name, NULL, pdata,
+ backlight = backlight_device_register(bl_name, NULL, pdata,
&appledisplay_bl_data, &props);
- if (IS_ERR(pdata->bd)) {
+ if (IS_ERR(backlight)) {
dev_err(&iface->dev, "Backlight registration failed\n");
- retval = PTR_ERR(pdata->bd);
+ retval = PTR_ERR(backlight);
goto error;
}
+ pdata->bd = backlight;
/* Try to get brightness */
brightness = appledisplay_bl_get_brightness(pdata->bd);
@@ -317,12 +311,12 @@ error:
if (pdata) {
if (pdata->urb) {
usb_kill_urb(pdata->urb);
- if (pdata->urbdata)
- usb_free_coherent(pdata->udev, ACD_URB_BUFFER_LEN,
+ cancel_delayed_work_sync(&pdata->work);
+ usb_free_coherent(pdata->udev, ACD_URB_BUFFER_LEN,
pdata->urbdata, pdata->urb->transfer_dma);
usb_free_urb(pdata->urb);
}
- if (pdata->bd && !IS_ERR(pdata->bd))
+ if (!IS_ERR(pdata->bd))
backlight_device_unregister(pdata->bd);
kfree(pdata->msgdata);
}
@@ -337,7 +331,7 @@ static void appledisplay_disconnect(struct usb_interface *iface)
if (pdata) {
usb_kill_urb(pdata->urb);
- cancel_delayed_work(&pdata->work);
+ cancel_delayed_work_sync(&pdata->work);
backlight_device_unregister(pdata->bd);
usb_free_coherent(pdata->udev, ACD_URB_BUFFER_LEN,
pdata->urbdata, pdata->urb->transfer_dma);
@@ -355,28 +349,8 @@ static struct usb_driver appledisplay_driver = {
.disconnect = appledisplay_disconnect,
.id_table = appledisplay_table,
};
-
-static int __init appledisplay_init(void)
-{
- wq = create_singlethread_workqueue("appledisplay");
- if (!wq) {
- printk(KERN_ERR "appledisplay: Could not create work queue\n");
- return -ENOMEM;
- }
-
- return usb_register(&appledisplay_driver);
-}
-
-static void __exit appledisplay_exit(void)
-{
- flush_workqueue(wq);
- destroy_workqueue(wq);
- usb_deregister(&appledisplay_driver);
-}
+module_usb_driver(appledisplay_driver);
MODULE_AUTHOR("Michael Hanselmann");
MODULE_DESCRIPTION("Apple Cinema Display driver");
MODULE_LICENSE("GPL");
-
-module_init(appledisplay_init);
-module_exit(appledisplay_exit);