Blame view
drivers/usb/misc/isight_firmware.c
3.29 KB
62d104d0d
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
/* * Driver for loading USB isight firmware * * Copyright (C) 2008 Matthew Garrett <mjg@redhat.com> * * 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, version 2. * * The USB isight cameras in recent Apples are roughly compatible with the USB * video class specification, and can be driven by uvcvideo. However, they * need firmware to be loaded beforehand. After firmware loading, the device * detaches from the USB bus and reattaches with a new device ID. It can then * be claimed by the uvc driver. * * The firmware is non-free and must be extracted by the user. Tools to do this * are available at http://bersace03.free.fr/ift/ * * The isight firmware loading was reverse engineered by Johannes Berg * <johannes@sipsolutions.de>, and this driver is based on code by Ronald * Bultje <rbultje@ronald.bitfreak.net> */ #include <linux/usb.h> #include <linux/firmware.h> #include <linux/errno.h> #include <linux/module.h> |
5a0e3ad6a
|
28 |
#include <linux/slab.h> |
62d104d0d
|
29 |
|
33b9e1624
|
30 |
static const struct usb_device_id id_table[] = { |
62d104d0d
|
31 32 33 34 35 36 37 38 39 40 41 42 |
{USB_DEVICE(0x05ac, 0x8300)}, {}, }; MODULE_DEVICE_TABLE(usb, id_table); static int isight_firmware_load(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_device *dev = interface_to_usbdev(intf); int llen, len, req, ret = 0; const struct firmware *firmware; |
62b588487
|
43 |
unsigned char *buf = kmalloc(50, GFP_KERNEL); |
62d104d0d
|
44 |
unsigned char data[4]; |
ed5a2825f
|
45 |
const u8 *ptr; |
62b588487
|
46 47 48 |
if (!buf) return -ENOMEM; |
62d104d0d
|
49 50 51 52 |
if (request_firmware(&firmware, "isight.fw", &dev->dev) != 0) { printk(KERN_ERR "Unable to load isight firmware "); |
ff1a4a7b1
|
53 54 |
ret = -ENODEV; goto out; |
62d104d0d
|
55 56 57 |
} ptr = firmware->data; |
59bf5cf94
|
58 |
buf[0] = 0x01; |
62d104d0d
|
59 |
if (usb_control_msg |
59bf5cf94
|
60 |
(dev, usb_sndctrlpipe(dev, 0), 0xa0, 0x40, 0xe600, 0, buf, 1, |
62d104d0d
|
61 62 63 64 65 66 67 |
300) != 1) { printk(KERN_ERR "Failed to initialise isight firmware loader "); ret = -ENODEV; goto out; } |
62b588487
|
68 |
while (ptr+4 <= firmware->data+firmware->size) { |
62d104d0d
|
69 70 71 72 73 74 75 76 77 78 79 |
memcpy(data, ptr, 4); len = (data[0] << 8 | data[1]); req = (data[2] << 8 | data[3]); ptr += 4; if (len == 0x8001) break; /* success */ else if (len == 0) continue; for (; len > 0; req += 50) { |
62b588487
|
80 |
llen = min(len, 50); |
62d104d0d
|
81 |
len -= llen; |
62b588487
|
82 83 84 85 86 87 |
if (ptr+llen > firmware->data+firmware->size) { printk(KERN_ERR "Malformed isight firmware"); ret = -ENODEV; goto out; } |
62d104d0d
|
88 89 90 91 92 93 94 95 96 97 |
memcpy(buf, ptr, llen); ptr += llen; if (usb_control_msg (dev, usb_sndctrlpipe(dev, 0), 0xa0, 0x40, req, 0, buf, llen, 300) != llen) { printk(KERN_ERR "Failed to load isight firmware "); |
62d104d0d
|
98 99 100 |
ret = -ENODEV; goto out; } |
62d104d0d
|
101 102 |
} } |
62b588487
|
103 |
|
59bf5cf94
|
104 |
buf[0] = 0x00; |
62d104d0d
|
105 |
if (usb_control_msg |
59bf5cf94
|
106 |
(dev, usb_sndctrlpipe(dev, 0), 0xa0, 0x40, 0xe600, 0, buf, 1, |
62d104d0d
|
107 108 109 110 111 |
300) != 1) { printk(KERN_ERR "isight firmware loading completion failed "); ret = -ENODEV; } |
62b588487
|
112 |
|
62d104d0d
|
113 |
out: |
62b588487
|
114 |
kfree(buf); |
62d104d0d
|
115 116 117 |
release_firmware(firmware); return ret; } |
4e0961d53
|
118 |
MODULE_FIRMWARE("isight.fw"); |
62d104d0d
|
119 120 121 122 123 124 125 126 127 128 |
static void isight_firmware_disconnect(struct usb_interface *intf) { } static struct usb_driver isight_firmware_driver = { .name = "isight_firmware", .probe = isight_firmware_load, .disconnect = isight_firmware_disconnect, .id_table = id_table, }; |
65db43054
|
129 |
module_usb_driver(isight_firmware_driver); |
62d104d0d
|
130 131 132 |
MODULE_LICENSE("GPL"); MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>"); |