diff options
Diffstat (limited to 'drivers/usb/misc/usbled.c')
| -rw-r--r-- | drivers/usb/misc/usbled.c | 198 | 
1 files changed, 141 insertions, 57 deletions
diff --git a/drivers/usb/misc/usbled.c b/drivers/usb/misc/usbled.c index 63da2c3c838..bdef0d6eb91 100644 --- a/drivers/usb/misc/usbled.c +++ b/drivers/usb/misc/usbled.c @@ -1,5 +1,5 @@  /* - * USB LED driver - 1.1 + * USB LED driver   *   * Copyright (C) 2004 Greg Kroah-Hartman (greg@kroah.com)   * @@ -11,7 +11,6 @@  #include <linux/kernel.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/module.h>  #include <linux/usb.h> @@ -20,31 +19,57 @@  #define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com"  #define DRIVER_DESC "USB LED Driver" -#define VENDOR_ID	0x0fc5 -#define PRODUCT_ID	0x1223 +enum led_type { +	DELCOM_VISUAL_SIGNAL_INDICATOR, +	DREAM_CHEEKY_WEBMAIL_NOTIFIER, +	RISO_KAGAKU_LED +}; + +/* the Webmail LED made by RISO KAGAKU CORP. decodes a color index +   internally, we want to keep the red+green+blue sysfs api, so we decode +   from 1-bit RGB to the riso kagaku color index according to this table... */ + +static unsigned const char riso_kagaku_tbl[] = { +/* R+2G+4B -> riso kagaku color index */ +	[0] = 0, /* black   */ +	[1] = 2, /* red     */ +	[2] = 1, /* green   */ +	[3] = 5, /* yellow  */ +	[4] = 3, /* blue    */ +	[5] = 6, /* magenta */ +	[6] = 4, /* cyan    */ +	[7] = 7  /* white   */ +}; + +#define RISO_KAGAKU_IX(r,g,b) riso_kagaku_tbl[((r)?1:0)+((g)?2:0)+((b)?4:0)]  /* table of devices that work with this driver */  static const struct usb_device_id id_table[] = { -	{ USB_DEVICE(VENDOR_ID, PRODUCT_ID) }, +	{ USB_DEVICE(0x0fc5, 0x1223), +			.driver_info = DELCOM_VISUAL_SIGNAL_INDICATOR }, +	{ USB_DEVICE(0x1d34, 0x0004), +			.driver_info = DREAM_CHEEKY_WEBMAIL_NOTIFIER }, +	{ USB_DEVICE(0x1d34, 0x000a), +			.driver_info = DREAM_CHEEKY_WEBMAIL_NOTIFIER }, +	{ USB_DEVICE(0x1294, 0x1320), +			.driver_info = RISO_KAGAKU_LED },  	{ },  }; -MODULE_DEVICE_TABLE (usb, id_table); +MODULE_DEVICE_TABLE(usb, id_table);  struct usb_led { -	struct usb_device *	udev; +	struct usb_device	*udev;  	unsigned char		blue;  	unsigned char		red;  	unsigned char		green; +	enum led_type		type;  }; -#define BLUE	0x04 -#define RED	0x02 -#define GREEN	0x01  static void change_color(struct usb_led *led)  { -	int retval; -	unsigned char color = 0x07; +	int retval = 0;  	unsigned char *buffer; +	int actlength;  	buffer = kmalloc(8, GFP_KERNEL);  	if (!buffer) { @@ -52,39 +77,87 @@ static void change_color(struct usb_led *led)  		return;  	} -	if (led->blue) -		color &= ~(BLUE); -	if (led->red) -		color &= ~(RED); -	if (led->green) -		color &= ~(GREEN); -	dev_dbg(&led->udev->dev, -		"blue = %d, red = %d, green = %d, color = %.2x\n", -		led->blue, led->red, led->green, color); - -	retval = usb_control_msg(led->udev, -				usb_sndctrlpipe(led->udev, 0), -				0x12, -				0xc8, -				(0x02 * 0x100) + 0x0a, -				(0x00 * 0x100) + color, -				buffer,	 -				8, -				2000); +	switch (led->type) { +	case DELCOM_VISUAL_SIGNAL_INDICATOR: { +		unsigned char color = 0x07; + +		if (led->blue) +			color &= ~0x04; +		if (led->red) +			color &= ~0x02; +		if (led->green) +			color &= ~0x01; +		dev_dbg(&led->udev->dev, +			"blue = %d, red = %d, green = %d, color = %.2x\n", +			led->blue, led->red, led->green, color); + +		retval = usb_control_msg(led->udev, +					usb_sndctrlpipe(led->udev, 0), +					0x12, +					0xc8, +					(0x02 * 0x100) + 0x0a, +					(0x00 * 0x100) + color, +					buffer, +					8, +					2000); +		break; +	} + +	case DREAM_CHEEKY_WEBMAIL_NOTIFIER: +		dev_dbg(&led->udev->dev, +			"red = %d, green = %d, blue = %d\n", +			led->red, led->green, led->blue); + +		buffer[0] = led->red; +		buffer[1] = led->green; +		buffer[2] = led->blue; +		buffer[3] = buffer[4] = buffer[5] = 0; +		buffer[6] = 0x1a; +		buffer[7] = 0x05; + +		retval = usb_control_msg(led->udev, +					usb_sndctrlpipe(led->udev, 0), +					0x09, +					0x21, +					0x200, +					0, +					buffer, +					8, +					2000); +		break; + +	case RISO_KAGAKU_LED: +		buffer[0] = RISO_KAGAKU_IX(led->red, led->green, led->blue); +		buffer[1] = 0; +		buffer[2] = 0; +		buffer[3] = 0; +		buffer[4] = 0; + +		retval = usb_interrupt_msg(led->udev, +			usb_sndctrlpipe(led->udev, 2), +			buffer, 5, &actlength, 1000 /*ms timeout*/); +		break; + +	default: +		dev_err(&led->udev->dev, "unknown device type %d\n", led->type); +	} +  	if (retval)  		dev_dbg(&led->udev->dev, "retval = %d\n", retval);  	kfree(buffer);  }  #define show_set(value)	\ -static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf)		\ +static ssize_t show_##value(struct device *dev, struct device_attribute *attr,\ +			    char *buf)					\  {									\  	struct usb_interface *intf = to_usb_interface(dev);		\  	struct usb_led *led = usb_get_intfdata(intf);			\  									\  	return sprintf(buf, "%d\n", led->value);			\  }									\ -static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)	\ +static ssize_t set_##value(struct device *dev, struct device_attribute *attr,\ +			   const char *buf, size_t count)		\  {									\  	struct usb_interface *intf = to_usb_interface(dev);		\  	struct usb_led *led = usb_get_intfdata(intf);			\ @@ -94,12 +167,13 @@ static ssize_t set_##value(struct device *dev, struct device_attribute *attr, co  	change_color(led);						\  	return count;							\  }									\ -static DEVICE_ATTR(value, S_IWUGO | S_IRUGO, show_##value, set_##value); +static DEVICE_ATTR(value, S_IRUGO | S_IWUSR, show_##value, set_##value);  show_set(blue);  show_set(red);  show_set(green); -static int led_probe(struct usb_interface *interface, const struct usb_device_id *id) +static int led_probe(struct usb_interface *interface, +		     const struct usb_device_id *id)  {  	struct usb_device *udev = interface_to_usbdev(interface);  	struct usb_led *dev = NULL; @@ -107,13 +181,14 @@ static int led_probe(struct usb_interface *interface, const struct usb_device_id  	dev = kzalloc(sizeof(struct usb_led), GFP_KERNEL);  	if (dev == NULL) { -		dev_err(&interface->dev, "Out of memory\n"); +		dev_err(&interface->dev, "out of memory\n");  		goto error_mem;  	}  	dev->udev = usb_get_dev(udev); +	dev->type = id->driver_info; -	usb_set_intfdata (interface, dev); +	usb_set_intfdata(interface, dev);  	retval = device_create_file(&interface->dev, &dev_attr_blue);  	if (retval) @@ -125,6 +200,31 @@ static int led_probe(struct usb_interface *interface, const struct usb_device_id  	if (retval)  		goto error; +	if (dev->type == DREAM_CHEEKY_WEBMAIL_NOTIFIER) { +		unsigned char *enable; + +		enable = kmemdup("\x1f\x02\0\x5f\0\0\x1a\x03", 8, GFP_KERNEL); +		if (!enable) { +			dev_err(&interface->dev, "out of memory\n"); +			retval = -ENOMEM; +			goto error; +		} + +		retval = usb_control_msg(udev, +					usb_sndctrlpipe(udev, 0), +					0x09, +					0x21, +					0x200, +					0, +					enable, +					8, +					2000); + +		kfree(enable); +		if (retval != 8) +			goto error; +	} +  	dev_info(&interface->dev, "USB LED device now attached\n");  	return 0; @@ -132,7 +232,7 @@ error:  	device_remove_file(&interface->dev, &dev_attr_blue);  	device_remove_file(&interface->dev, &dev_attr_red);  	device_remove_file(&interface->dev, &dev_attr_green); -	usb_set_intfdata (interface, NULL); +	usb_set_intfdata(interface, NULL);  	usb_put_dev(dev->udev);  	kfree(dev);  error_mem: @@ -143,14 +243,14 @@ static void led_disconnect(struct usb_interface *interface)  {  	struct usb_led *dev; -	dev = usb_get_intfdata (interface); +	dev = usb_get_intfdata(interface);  	device_remove_file(&interface->dev, &dev_attr_blue);  	device_remove_file(&interface->dev, &dev_attr_red);  	device_remove_file(&interface->dev, &dev_attr_green);  	/* first remove the files, then set the pointer to NULL */ -	usb_set_intfdata (interface, NULL); +	usb_set_intfdata(interface, NULL);  	usb_put_dev(dev->udev); @@ -166,23 +266,7 @@ static struct usb_driver led_driver = {  	.id_table =	id_table,  }; -static int __init usb_led_init(void) -{ -	int retval = 0; - -	retval = usb_register(&led_driver); -	if (retval) -		err("usb_register failed. Error number %d", retval); -	return retval; -} - -static void __exit usb_led_exit(void) -{ -	usb_deregister(&led_driver); -} - -module_init (usb_led_init); -module_exit (usb_led_exit); +module_usb_driver(led_driver);  MODULE_AUTHOR(DRIVER_AUTHOR);  MODULE_DESCRIPTION(DRIVER_DESC);  | 
