diff options
| author | Melchior FRANZ <mfranz@aon.at> | 2010-12-21 20:04:33 -0500 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-12-21 23:48:21 -0500 |
| commit | 73bc7d315f56e260071bdb5f15e25b53bddc1402 (patch) | |
| tree | 20e676a2eb44f2b5eba6bee581a74ccca6a60cde /drivers/usb/misc | |
| parent | c466cd2bb9cee2e576fc9663b828f51e322d7b4b (diff) | |
USB: add support for Dream Cheeky DL100B Webmail Notifier (1d34:0004)
So far the USBLED driver only supports Delcom's "USB Visual Signal
Indicator" (http://www.delcomproducts.com/products_USBLMP.asp). The
driver generates virtual files "red", "green", and "blue" under the
device's /sys/ directory, where color values can be read from and
written to.
This patch adds support for Dream Cheeky's "DL100B Webmail Notifier"
(http://www.dreamcheeky.com/webmail-notifier -- available from several
shops, such as http://www.conrad.at/ce/de/product/777048/USB-WEBMAIL).
This device isn't as pretty as Delcom's, but it's *far* cheaper, and
its 3 LEDs can be set in 32 brightness steps each. The grey envelope
contour can easily be removed, leaving a rather neutral white box (with
a few small holes), which is useful for generic signalling purposes.
Of course, the small circuit board can easily be put into a prettier
case.
The DL100B device pretends to be a HID, but the HID descriptor shows
that it's not overly useful as such (see below). The patch therefore
removes the "HID-ness" (hid-core.c, hid-ids.h), and adds the necessary
commands to usbled.c. The protocol info comes from the developer's
manual that Dream Cheeky kindly provided (815DeveloperManual.pdf).
HID descriptor:
0: 05 01 Usage Page 'Generic Desktop Controls'
2: 09 10 Usage 'Reserved'
4: a1 01 Collection 'Application (mouse, keyboard)'
6: 05 00 Usage Page 'Undefined'
8: 19 10 Usage Minimum = 16
10: 29 11 Usage Maximum = 17
12: 15 00 Logical Minimum = 0
14: 25 0f Logical Maximum = 15
16: 75 08 Report Size = 8
18: 95 08 Report Count = 8
20: 91 02 Output data *var abs lin pref-state null-pos non-vol bit-field
22: 19 10 Usage Minimum = 16
24: 29 11 Usage Maximum = 17
26: 15 00 Logical Minimum = 0
28: 25 0f Logical Maximum = 15
30: 75 08 Report Size = 8
32: 95 08 Report Count = 8
34: 81 00 Input data array abs lin pref-state null-pos non-vol bit-field
36: c0 End Collection
Signed-off-by: Melchior FRANZ <mfranz@aon.at>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/misc')
| -rw-r--r-- | drivers/usb/misc/usbled.c | 118 |
1 files changed, 90 insertions, 28 deletions
diff --git a/drivers/usb/misc/usbled.c b/drivers/usb/misc/usbled.c index c96f51de1696..1732d9bc097e 100644 --- a/drivers/usb/misc/usbled.c +++ b/drivers/usb/misc/usbled.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * USB LED driver - 1.1 | 2 | * USB LED driver |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2004 Greg Kroah-Hartman (greg@kroah.com) | 4 | * Copyright (C) 2004 Greg Kroah-Hartman (greg@kroah.com) |
| 5 | * | 5 | * |
| @@ -20,12 +20,17 @@ | |||
| 20 | #define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com" | 20 | #define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com" |
| 21 | #define DRIVER_DESC "USB LED Driver" | 21 | #define DRIVER_DESC "USB LED Driver" |
| 22 | 22 | ||
| 23 | #define VENDOR_ID 0x0fc5 | 23 | enum led_type { |
| 24 | #define PRODUCT_ID 0x1223 | 24 | DELCOM_VISUAL_SIGNAL_INDICATOR, |
| 25 | DREAM_CHEEKY_WEBMAIL_NOTIFIER, | ||
| 26 | }; | ||
| 25 | 27 | ||
| 26 | /* table of devices that work with this driver */ | 28 | /* table of devices that work with this driver */ |
| 27 | static const struct usb_device_id id_table[] = { | 29 | static const struct usb_device_id id_table[] = { |
| 28 | { USB_DEVICE(VENDOR_ID, PRODUCT_ID) }, | 30 | { USB_DEVICE(0x0fc5, 0x1223), |
| 31 | .driver_info = DELCOM_VISUAL_SIGNAL_INDICATOR }, | ||
| 32 | { USB_DEVICE(0x1d34, 0x0004), | ||
| 33 | .driver_info = DREAM_CHEEKY_WEBMAIL_NOTIFIER }, | ||
| 29 | { }, | 34 | { }, |
| 30 | }; | 35 | }; |
| 31 | MODULE_DEVICE_TABLE (usb, id_table); | 36 | MODULE_DEVICE_TABLE (usb, id_table); |
| @@ -35,15 +40,12 @@ struct usb_led { | |||
| 35 | unsigned char blue; | 40 | unsigned char blue; |
| 36 | unsigned char red; | 41 | unsigned char red; |
| 37 | unsigned char green; | 42 | unsigned char green; |
| 43 | enum led_type type; | ||
| 38 | }; | 44 | }; |
| 39 | 45 | ||
| 40 | #define BLUE 0x04 | ||
| 41 | #define RED 0x02 | ||
| 42 | #define GREEN 0x01 | ||
| 43 | static void change_color(struct usb_led *led) | 46 | static void change_color(struct usb_led *led) |
| 44 | { | 47 | { |
| 45 | int retval; | 48 | int retval; |
| 46 | unsigned char color = 0x07; | ||
| 47 | unsigned char *buffer; | 49 | unsigned char *buffer; |
| 48 | 50 | ||
| 49 | buffer = kmalloc(8, GFP_KERNEL); | 51 | buffer = kmalloc(8, GFP_KERNEL); |
| @@ -52,25 +54,59 @@ static void change_color(struct usb_led *led) | |||
| 52 | return; | 54 | return; |
| 53 | } | 55 | } |
| 54 | 56 | ||
| 55 | if (led->blue) | 57 | switch (led->type) { |
| 56 | color &= ~(BLUE); | 58 | case DELCOM_VISUAL_SIGNAL_INDICATOR: { |
| 57 | if (led->red) | 59 | unsigned char color = 0x07; |
| 58 | color &= ~(RED); | 60 | |
| 59 | if (led->green) | 61 | if (led->blue) |
| 60 | color &= ~(GREEN); | 62 | color &= ~0x04; |
| 61 | dev_dbg(&led->udev->dev, | 63 | if (led->red) |
| 62 | "blue = %d, red = %d, green = %d, color = %.2x\n", | 64 | color &= ~0x02; |
| 63 | led->blue, led->red, led->green, color); | 65 | if (led->green) |
| 64 | 66 | color &= ~0x01; | |
| 65 | retval = usb_control_msg(led->udev, | 67 | dev_dbg(&led->udev->dev, |
| 66 | usb_sndctrlpipe(led->udev, 0), | 68 | "blue = %d, red = %d, green = %d, color = %.2x\n", |
| 67 | 0x12, | 69 | led->blue, led->red, led->green, color); |
| 68 | 0xc8, | 70 | |
| 69 | (0x02 * 0x100) + 0x0a, | 71 | retval = usb_control_msg(led->udev, |
| 70 | (0x00 * 0x100) + color, | 72 | usb_sndctrlpipe(led->udev, 0), |
| 71 | buffer, | 73 | 0x12, |
| 72 | 8, | 74 | 0xc8, |
| 73 | 2000); | 75 | (0x02 * 0x100) + 0x0a, |
| 76 | (0x00 * 0x100) + color, | ||
| 77 | buffer, | ||
| 78 | 8, | ||
| 79 | 2000); | ||
| 80 | break; | ||
| 81 | } | ||
| 82 | |||
| 83 | case DREAM_CHEEKY_WEBMAIL_NOTIFIER: | ||
| 84 | dev_dbg(&led->udev->dev, | ||
| 85 | "red = %d, green = %d, blue = %d\n", | ||
| 86 | led->red, led->green, led->blue); | ||
| 87 | |||
| 88 | buffer[0] = led->red; | ||
| 89 | buffer[1] = led->green; | ||
| 90 | buffer[2] = led->blue; | ||
| 91 | buffer[3] = buffer[4] = buffer[5] = 0; | ||
| 92 | buffer[6] = 0x1a; | ||
| 93 | buffer[7] = 0x05; | ||
| 94 | |||
| 95 | retval = usb_control_msg(led->udev, | ||
| 96 | usb_sndctrlpipe(led->udev, 0), | ||
| 97 | 0x09, | ||
| 98 | 0x21, | ||
| 99 | 0x200, | ||
| 100 | 0, | ||
| 101 | buffer, | ||
| 102 | 8, | ||
| 103 | 2000); | ||
| 104 | break; | ||
| 105 | |||
| 106 | default: | ||
| 107 | dev_err(&led->udev->dev, "unknown device type %d\n", led->type); | ||
| 108 | } | ||
| 109 | |||
| 74 | if (retval) | 110 | if (retval) |
| 75 | dev_dbg(&led->udev->dev, "retval = %d\n", retval); | 111 | dev_dbg(&led->udev->dev, "retval = %d\n", retval); |
| 76 | kfree(buffer); | 112 | kfree(buffer); |
| @@ -107,11 +143,12 @@ static int led_probe(struct usb_interface *interface, const struct usb_device_id | |||
| 107 | 143 | ||
| 108 | dev = kzalloc(sizeof(struct usb_led), GFP_KERNEL); | 144 | dev = kzalloc(sizeof(struct usb_led), GFP_KERNEL); |
| 109 | if (dev == NULL) { | 145 | if (dev == NULL) { |
| 110 | dev_err(&interface->dev, "Out of memory\n"); | 146 | dev_err(&interface->dev, "out of memory\n"); |
| 111 | goto error_mem; | 147 | goto error_mem; |
| 112 | } | 148 | } |
| 113 | 149 | ||
| 114 | dev->udev = usb_get_dev(udev); | 150 | dev->udev = usb_get_dev(udev); |
| 151 | dev->type = id->driver_info; | ||
| 115 | 152 | ||
| 116 | usb_set_intfdata (interface, dev); | 153 | usb_set_intfdata (interface, dev); |
| 117 | 154 | ||
| @@ -125,6 +162,31 @@ static int led_probe(struct usb_interface *interface, const struct usb_device_id | |||
| 125 | if (retval) | 162 | if (retval) |
| 126 | goto error; | 163 | goto error; |
| 127 | 164 | ||
| 165 | if (dev->type == DREAM_CHEEKY_WEBMAIL_NOTIFIER) { | ||
| 166 | unsigned char *enable; | ||
| 167 | |||
| 168 | enable = kmemdup("\x1f\x02\0\x5f\0\0\x1a\x03", 8, GFP_KERNEL); | ||
| 169 | if (!enable) { | ||
| 170 | dev_err(&interface->dev, "out of memory\n"); | ||
| 171 | retval = -ENOMEM; | ||
| 172 | goto error; | ||
| 173 | } | ||
| 174 | |||
| 175 | retval = usb_control_msg(udev, | ||
| 176 | usb_sndctrlpipe(udev, 0), | ||
| 177 | 0x09, | ||
| 178 | 0x21, | ||
| 179 | 0x200, | ||
| 180 | 0, | ||
| 181 | enable, | ||
| 182 | 8, | ||
| 183 | 2000); | ||
| 184 | |||
| 185 | kfree(enable); | ||
| 186 | if (retval != 8) | ||
| 187 | goto error; | ||
| 188 | } | ||
| 189 | |||
| 128 | dev_info(&interface->dev, "USB LED device now attached\n"); | 190 | dev_info(&interface->dev, "USB LED device now attached\n"); |
| 129 | return 0; | 191 | return 0; |
| 130 | 192 | ||
