0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/kernel.h>
0011 #include <linux/errno.h>
0012 #include <linux/init.h>
0013 #include <linux/module.h>
0014 #include <linux/slab.h>
0015 #include <linux/usb.h>
0016 #include <linux/backlight.h>
0017 #include <linux/timer.h>
0018 #include <linux/workqueue.h>
0019 #include <linux/atomic.h>
0020
0021 #define APPLE_VENDOR_ID 0x05AC
0022
0023 #define USB_REQ_GET_REPORT 0x01
0024 #define USB_REQ_SET_REPORT 0x09
0025
0026 #define ACD_USB_TIMEOUT 250
0027
0028 #define ACD_USB_EDID 0x0302
0029 #define ACD_USB_BRIGHTNESS 0x0310
0030
0031 #define ACD_BTN_NONE 0
0032 #define ACD_BTN_BRIGHT_UP 3
0033 #define ACD_BTN_BRIGHT_DOWN 4
0034
0035 #define ACD_URB_BUFFER_LEN 2
0036 #define ACD_MSG_BUFFER_LEN 2
0037
0038 #define APPLEDISPLAY_DEVICE(prod) \
0039 .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \
0040 USB_DEVICE_ID_MATCH_INT_CLASS | \
0041 USB_DEVICE_ID_MATCH_INT_PROTOCOL, \
0042 .idVendor = APPLE_VENDOR_ID, \
0043 .idProduct = (prod), \
0044 .bInterfaceClass = USB_CLASS_HID, \
0045 .bInterfaceProtocol = 0x00
0046
0047
0048 static const struct usb_device_id appledisplay_table[] = {
0049 { APPLEDISPLAY_DEVICE(0x9218) },
0050 { APPLEDISPLAY_DEVICE(0x9219) },
0051 { APPLEDISPLAY_DEVICE(0x921c) },
0052 { APPLEDISPLAY_DEVICE(0x921d) },
0053 { APPLEDISPLAY_DEVICE(0x9222) },
0054 { APPLEDISPLAY_DEVICE(0x9226) },
0055 { APPLEDISPLAY_DEVICE(0x9236) },
0056
0057
0058 { }
0059 };
0060 MODULE_DEVICE_TABLE(usb, appledisplay_table);
0061
0062
0063 struct appledisplay {
0064 struct usb_device *udev;
0065 struct urb *urb;
0066 struct backlight_device *bd;
0067 u8 *urbdata;
0068 u8 *msgdata;
0069
0070 struct delayed_work work;
0071 int button_pressed;
0072 struct mutex sysfslock;
0073 };
0074
0075 static atomic_t count_displays = ATOMIC_INIT(0);
0076
0077 static void appledisplay_complete(struct urb *urb)
0078 {
0079 struct appledisplay *pdata = urb->context;
0080 struct device *dev = &pdata->udev->dev;
0081 int status = urb->status;
0082 int retval;
0083
0084 switch (status) {
0085 case 0:
0086
0087 break;
0088 case -EOVERFLOW:
0089 dev_err(dev,
0090 "OVERFLOW with data length %d, actual length is %d\n",
0091 ACD_URB_BUFFER_LEN, pdata->urb->actual_length);
0092 fallthrough;
0093 case -ECONNRESET:
0094 case -ENOENT:
0095 case -ESHUTDOWN:
0096
0097 dev_dbg(dev, "%s - urb shuttingdown with status: %d\n",
0098 __func__, status);
0099 return;
0100 default:
0101 dev_dbg(dev, "%s - nonzero urb status received: %d\n",
0102 __func__, status);
0103 goto exit;
0104 }
0105
0106 switch(pdata->urbdata[1]) {
0107 case ACD_BTN_BRIGHT_UP:
0108 case ACD_BTN_BRIGHT_DOWN:
0109 pdata->button_pressed = 1;
0110 schedule_delayed_work(&pdata->work, 0);
0111 break;
0112 case ACD_BTN_NONE:
0113 default:
0114 pdata->button_pressed = 0;
0115 break;
0116 }
0117
0118 exit:
0119 retval = usb_submit_urb(pdata->urb, GFP_ATOMIC);
0120 if (retval) {
0121 dev_err(dev, "%s - usb_submit_urb failed with result %d\n",
0122 __func__, retval);
0123 }
0124 }
0125
0126 static int appledisplay_bl_update_status(struct backlight_device *bd)
0127 {
0128 struct appledisplay *pdata = bl_get_data(bd);
0129 int retval;
0130
0131 mutex_lock(&pdata->sysfslock);
0132 pdata->msgdata[0] = 0x10;
0133 pdata->msgdata[1] = bd->props.brightness;
0134
0135 retval = usb_control_msg(
0136 pdata->udev,
0137 usb_sndctrlpipe(pdata->udev, 0),
0138 USB_REQ_SET_REPORT,
0139 USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
0140 ACD_USB_BRIGHTNESS,
0141 0,
0142 pdata->msgdata, 2,
0143 ACD_USB_TIMEOUT);
0144 mutex_unlock(&pdata->sysfslock);
0145
0146 if (retval < 0)
0147 return retval;
0148 else
0149 return 0;
0150 }
0151
0152 static int appledisplay_bl_get_brightness(struct backlight_device *bd)
0153 {
0154 struct appledisplay *pdata = bl_get_data(bd);
0155 int retval, brightness;
0156
0157 mutex_lock(&pdata->sysfslock);
0158 retval = usb_control_msg(
0159 pdata->udev,
0160 usb_rcvctrlpipe(pdata->udev, 0),
0161 USB_REQ_GET_REPORT,
0162 USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
0163 ACD_USB_BRIGHTNESS,
0164 0,
0165 pdata->msgdata, 2,
0166 ACD_USB_TIMEOUT);
0167 if (retval < 2) {
0168 if (retval >= 0)
0169 retval = -EMSGSIZE;
0170 } else {
0171 brightness = pdata->msgdata[1];
0172 }
0173 mutex_unlock(&pdata->sysfslock);
0174
0175 if (retval < 0)
0176 return retval;
0177 else
0178 return brightness;
0179 }
0180
0181 static const struct backlight_ops appledisplay_bl_data = {
0182 .get_brightness = appledisplay_bl_get_brightness,
0183 .update_status = appledisplay_bl_update_status,
0184 };
0185
0186 static void appledisplay_work(struct work_struct *work)
0187 {
0188 struct appledisplay *pdata =
0189 container_of(work, struct appledisplay, work.work);
0190 int retval;
0191
0192 retval = appledisplay_bl_get_brightness(pdata->bd);
0193 if (retval >= 0)
0194 pdata->bd->props.brightness = retval;
0195
0196
0197 if (pdata->button_pressed)
0198 schedule_delayed_work(&pdata->work, HZ / 8);
0199 }
0200
0201 static int appledisplay_probe(struct usb_interface *iface,
0202 const struct usb_device_id *id)
0203 {
0204 struct backlight_properties props;
0205 struct appledisplay *pdata;
0206 struct usb_device *udev = interface_to_usbdev(iface);
0207 struct usb_endpoint_descriptor *endpoint;
0208 int int_in_endpointAddr = 0;
0209 int retval, brightness;
0210 char bl_name[20];
0211
0212
0213
0214 retval = usb_find_int_in_endpoint(iface->cur_altsetting, &endpoint);
0215 if (retval) {
0216 dev_err(&iface->dev, "Could not find int-in endpoint\n");
0217 return retval;
0218 }
0219
0220 int_in_endpointAddr = endpoint->bEndpointAddress;
0221
0222
0223 pdata = kzalloc(sizeof(struct appledisplay), GFP_KERNEL);
0224 if (!pdata) {
0225 retval = -ENOMEM;
0226 goto error;
0227 }
0228
0229 pdata->udev = udev;
0230
0231 INIT_DELAYED_WORK(&pdata->work, appledisplay_work);
0232 mutex_init(&pdata->sysfslock);
0233
0234
0235 pdata->msgdata = kmalloc(ACD_MSG_BUFFER_LEN, GFP_KERNEL);
0236 if (!pdata->msgdata) {
0237 retval = -ENOMEM;
0238 goto error;
0239 }
0240
0241
0242 pdata->urb = usb_alloc_urb(0, GFP_KERNEL);
0243 if (!pdata->urb) {
0244 retval = -ENOMEM;
0245 goto error;
0246 }
0247
0248
0249 pdata->urbdata = usb_alloc_coherent(pdata->udev, ACD_URB_BUFFER_LEN,
0250 GFP_KERNEL, &pdata->urb->transfer_dma);
0251 if (!pdata->urbdata) {
0252 retval = -ENOMEM;
0253 dev_err(&iface->dev, "Allocating URB buffer failed\n");
0254 goto error;
0255 }
0256
0257
0258 usb_fill_int_urb(pdata->urb, udev,
0259 usb_rcvintpipe(udev, int_in_endpointAddr),
0260 pdata->urbdata, ACD_URB_BUFFER_LEN, appledisplay_complete,
0261 pdata, 1);
0262 pdata->urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
0263 if (usb_submit_urb(pdata->urb, GFP_KERNEL)) {
0264 retval = -EIO;
0265 dev_err(&iface->dev, "Submitting URB failed\n");
0266 goto error;
0267 }
0268
0269
0270 snprintf(bl_name, sizeof(bl_name), "appledisplay%d",
0271 atomic_inc_return(&count_displays) - 1);
0272 memset(&props, 0, sizeof(struct backlight_properties));
0273 props.type = BACKLIGHT_RAW;
0274 props.max_brightness = 0xff;
0275 pdata->bd = backlight_device_register(bl_name, NULL, pdata,
0276 &appledisplay_bl_data, &props);
0277 if (IS_ERR(pdata->bd)) {
0278 dev_err(&iface->dev, "Backlight registration failed\n");
0279 retval = PTR_ERR(pdata->bd);
0280 goto error;
0281 }
0282
0283
0284 brightness = appledisplay_bl_get_brightness(pdata->bd);
0285
0286 if (brightness < 0) {
0287 retval = brightness;
0288 dev_err(&iface->dev,
0289 "Error while getting initial brightness: %d\n", retval);
0290 goto error;
0291 }
0292
0293
0294 pdata->bd->props.brightness = brightness;
0295
0296
0297 usb_set_intfdata(iface, pdata);
0298
0299 printk(KERN_INFO "appledisplay: Apple Cinema Display connected\n");
0300
0301 return 0;
0302
0303 error:
0304 if (pdata) {
0305 if (pdata->urb) {
0306 usb_kill_urb(pdata->urb);
0307 cancel_delayed_work_sync(&pdata->work);
0308 usb_free_coherent(pdata->udev, ACD_URB_BUFFER_LEN,
0309 pdata->urbdata, pdata->urb->transfer_dma);
0310 usb_free_urb(pdata->urb);
0311 }
0312 if (!IS_ERR(pdata->bd))
0313 backlight_device_unregister(pdata->bd);
0314 kfree(pdata->msgdata);
0315 }
0316 usb_set_intfdata(iface, NULL);
0317 kfree(pdata);
0318 return retval;
0319 }
0320
0321 static void appledisplay_disconnect(struct usb_interface *iface)
0322 {
0323 struct appledisplay *pdata = usb_get_intfdata(iface);
0324
0325 if (pdata) {
0326 usb_kill_urb(pdata->urb);
0327 cancel_delayed_work_sync(&pdata->work);
0328 backlight_device_unregister(pdata->bd);
0329 usb_free_coherent(pdata->udev, ACD_URB_BUFFER_LEN,
0330 pdata->urbdata, pdata->urb->transfer_dma);
0331 usb_free_urb(pdata->urb);
0332 kfree(pdata->msgdata);
0333 kfree(pdata);
0334 }
0335
0336 printk(KERN_INFO "appledisplay: Apple Cinema Display disconnected\n");
0337 }
0338
0339 static struct usb_driver appledisplay_driver = {
0340 .name = "appledisplay",
0341 .probe = appledisplay_probe,
0342 .disconnect = appledisplay_disconnect,
0343 .id_table = appledisplay_table,
0344 };
0345 module_usb_driver(appledisplay_driver);
0346
0347 MODULE_AUTHOR("Michael Hanselmann");
0348 MODULE_DESCRIPTION("Apple Cinema Display driver");
0349 MODULE_LICENSE("GPL");