linux/drivers/usb/misc/usbled.c
<<
>>
Prefs
   1/*
   2 * USB LED driver - 1.1
   3 *
   4 * Copyright (C) 2004 Greg Kroah-Hartman (greg@kroah.com)
   5 *
   6 *      This program is free software; you can redistribute it and/or
   7 *      modify it under the terms of the GNU General Public License as
   8 *      published by the Free Software Foundation, version 2.
   9 *
  10 */
  11
  12#include <linux/kernel.h>
  13#include <linux/errno.h>
  14#include <linux/init.h>
  15#include <linux/slab.h>
  16#include <linux/module.h>
  17#include <linux/usb.h>
  18
  19
  20#define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com"
  21#define DRIVER_DESC "USB LED Driver"
  22
  23#define VENDOR_ID       0x0fc5
  24#define PRODUCT_ID      0x1223
  25
  26/* table of devices that work with this driver */
  27static struct usb_device_id id_table [] = {
  28        { USB_DEVICE(VENDOR_ID, PRODUCT_ID) },
  29        { },
  30};
  31MODULE_DEVICE_TABLE (usb, id_table);
  32
  33struct usb_led {
  34        struct usb_device *     udev;
  35        unsigned char           blue;
  36        unsigned char           red;
  37        unsigned char           green;
  38};
  39
  40#define BLUE    0x04
  41#define RED     0x02
  42#define GREEN   0x01
  43static void change_color(struct usb_led *led)
  44{
  45        int retval;
  46        unsigned char color = 0x07;
  47        unsigned char *buffer;
  48
  49        buffer = kmalloc(8, GFP_KERNEL);
  50        if (!buffer) {
  51                dev_err(&led->udev->dev, "out of memory\n");
  52                return;
  53        }
  54
  55        if (led->blue)
  56                color &= ~(BLUE);
  57        if (led->red)
  58                color &= ~(RED);
  59        if (led->green)
  60                color &= ~(GREEN);
  61        dev_dbg(&led->udev->dev,
  62                "blue = %d, red = %d, green = %d, color = %.2x\n",
  63                led->blue, led->red, led->green, color);
  64
  65        retval = usb_control_msg(led->udev,
  66                                usb_sndctrlpipe(led->udev, 0),
  67                                0x12,
  68                                0xc8,
  69                                (0x02 * 0x100) + 0x0a,
  70                                (0x00 * 0x100) + color,
  71                                buffer, 
  72                                8,
  73                                2000);
  74        if (retval)
  75                dev_dbg(&led->udev->dev, "retval = %d\n", retval);
  76        kfree(buffer);
  77}
  78
  79#define show_set(value) \
  80static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf)               \
  81{                                                                       \
  82        struct usb_interface *intf = to_usb_interface(dev);             \
  83        struct usb_led *led = usb_get_intfdata(intf);                   \
  84                                                                        \
  85        return sprintf(buf, "%d\n", led->value);                        \
  86}                                                                       \
  87static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)    \
  88{                                                                       \
  89        struct usb_interface *intf = to_usb_interface(dev);             \
  90        struct usb_led *led = usb_get_intfdata(intf);                   \
  91        int temp = simple_strtoul(buf, NULL, 10);                       \
  92                                                                        \
  93        led->value = temp;                                              \
  94        change_color(led);                                              \
  95        return count;                                                   \
  96}                                                                       \
  97static DEVICE_ATTR(value, S_IWUGO | S_IRUGO, show_##value, set_##value);
  98show_set(blue);
  99show_set(red);
 100show_set(green);
 101
 102static int led_probe(struct usb_interface *interface, const struct usb_device_id *id)
 103{
 104        struct usb_device *udev = interface_to_usbdev(interface);
 105        struct usb_led *dev = NULL;
 106        int retval = -ENOMEM;
 107
 108        dev = kzalloc(sizeof(struct usb_led), GFP_KERNEL);
 109        if (dev == NULL) {
 110                dev_err(&interface->dev, "Out of memory\n");
 111                goto error_mem;
 112        }
 113
 114        dev->udev = usb_get_dev(udev);
 115
 116        usb_set_intfdata (interface, dev);
 117
 118        retval = device_create_file(&interface->dev, &dev_attr_blue);
 119        if (retval)
 120                goto error;
 121        retval = device_create_file(&interface->dev, &dev_attr_red);
 122        if (retval)
 123                goto error;
 124        retval = device_create_file(&interface->dev, &dev_attr_green);
 125        if (retval)
 126                goto error;
 127
 128        dev_info(&interface->dev, "USB LED device now attached\n");
 129        return 0;
 130
 131error:
 132        device_remove_file(&interface->dev, &dev_attr_blue);
 133        device_remove_file(&interface->dev, &dev_attr_red);
 134        device_remove_file(&interface->dev, &dev_attr_green);
 135        usb_set_intfdata (interface, NULL);
 136        usb_put_dev(dev->udev);
 137        kfree(dev);
 138error_mem:
 139        return retval;
 140}
 141
 142static void led_disconnect(struct usb_interface *interface)
 143{
 144        struct usb_led *dev;
 145
 146        dev = usb_get_intfdata (interface);
 147
 148        device_remove_file(&interface->dev, &dev_attr_blue);
 149        device_remove_file(&interface->dev, &dev_attr_red);
 150        device_remove_file(&interface->dev, &dev_attr_green);
 151
 152        /* first remove the files, then set the pointer to NULL */
 153        usb_set_intfdata (interface, NULL);
 154
 155        usb_put_dev(dev->udev);
 156
 157        kfree(dev);
 158
 159        dev_info(&interface->dev, "USB LED now disconnected\n");
 160}
 161
 162static struct usb_driver led_driver = {
 163        .name =         "usbled",
 164        .probe =        led_probe,
 165        .disconnect =   led_disconnect,
 166        .id_table =     id_table,
 167};
 168
 169static int __init usb_led_init(void)
 170{
 171        int retval = 0;
 172
 173        retval = usb_register(&led_driver);
 174        if (retval)
 175                err("usb_register failed. Error number %d", retval);
 176        return retval;
 177}
 178
 179static void __exit usb_led_exit(void)
 180{
 181        usb_deregister(&led_driver);
 182}
 183
 184module_init (usb_led_init);
 185module_exit (usb_led_exit);
 186
 187MODULE_AUTHOR(DRIVER_AUTHOR);
 188MODULE_DESCRIPTION(DRIVER_DESC);
 189MODULE_LICENSE("GPL");
 190