allow coexistance of N build and AC build.
[tomato.git] / release / src-rt-6.x / linux / linux-2.6 / drivers / leds / leds-usb.c
blob6093b6cb1d7c8b0c41666962b228408b91f7cf5a
1 /*
3 GPIO-controlled USB LED Driver
4 Copyright (C) 2010-2011 Fedor Kozhevnikov
6 Licensed under GNU GPL v2.
8 */
10 #include <linux/module.h>
11 #include <linux/types.h>
12 #include <linux/kernel.h>
13 #include <linux/device.h>
14 #include <linux/sysdev.h>
15 #include <linux/ctype.h>
16 #include <linux/proc_fs.h>
17 #include "leds.h"
19 #include <typedefs.h>
20 #include <bcmutils.h>
21 #include <siutils.h>
23 #ifndef CONFIG_PROC_FS
24 #error PROC_FS must be configured!
25 #endif
27 #define DEV_BUS_ID_SIZE 32
29 static si_t *sih;
30 static unsigned int gpio_pin = 255;
31 static unsigned int reverse = 0;
33 static void gpio_led_ctl(int on_off)
35 si_gpioreserve(sih, 1 << gpio_pin, GPIO_APP_PRIORITY);
36 si_gpioouten(sih, 1 << gpio_pin, 1 << gpio_pin, GPIO_APP_PRIORITY);
37 si_gpioout(sih, 1 << gpio_pin, on_off << gpio_pin, GPIO_APP_PRIORITY);
40 static void usb_led_set(struct led_classdev *led_cdev, enum led_brightness brightness)
42 if (gpio_pin < 16) {
43 if (reverse) brightness = !brightness;
44 gpio_led_ctl(brightness ? 1 : 0);
48 static DEFINE_RWLOCK(usbdev_lock);
49 static LIST_HEAD(usbdev_list);
51 struct led_usbdev {
52 struct list_head list;
53 struct led_classdev usb_led;
54 char dev_name[DEV_BUS_ID_SIZE];
57 #define LIST_FIND(head, cmpfn, type, args...) \
58 ({ \
59 const struct list_head *__i, *__j = NULL; \
61 read_lock_bh(&usbdev_lock); \
62 list_for_each(__i, (head)) \
63 if (cmpfn((const type)__i , ## args)) { \
64 __j = __i; \
65 break; \
66 } \
67 read_unlock_bh(&usbdev_lock); \
68 (type)__j; \
71 static void del_usbdev(struct led_usbdev *dev)
73 led_classdev_unregister(&dev->usb_led);
74 list_del(&dev->list);
75 kfree(dev);
78 static void usbdev_flush(void)
80 struct list_head *cur_item, *tmp_item;
82 write_lock_bh(&usbdev_lock);
83 list_for_each_safe(cur_item, tmp_item, &usbdev_list) {
84 struct led_usbdev *dev = (void *)cur_item;
85 del_usbdev(dev);
87 write_unlock_bh(&usbdev_lock);
90 static inline int usbdev_matched(const struct led_usbdev *i, const char *name)
92 return strcmp(name, i->dev_name) == 0;
95 extern ssize_t usbdev_trig_set_name(struct led_classdev *led_cdev,
96 const char *buf,
97 size_t size);
99 static int add_usbdev(const char *name)
101 struct led_usbdev *dev;
103 /* Check if the device already exists */
104 dev = LIST_FIND(&usbdev_list,
105 usbdev_matched,
106 struct led_usbdev *,
107 name);
109 if (dev == NULL) {
110 /* create new device */
111 dev = (struct led_usbdev *)kzalloc(sizeof(struct led_usbdev), GFP_ATOMIC);
112 if (dev == NULL) return -1;
114 INIT_LIST_HEAD(&dev->list);
115 memcpy(dev->dev_name, name, strlen(name));
116 dev->usb_led.name = dev->dev_name;
117 dev->usb_led.brightness_set = usb_led_set;
118 dev->usb_led.default_trigger = "usbdev";
120 /* add to global table and register */
121 write_lock_bh(&usbdev_lock);
122 list_add(&dev->list, &usbdev_list);
123 write_unlock_bh(&usbdev_lock);
125 if (led_classdev_register(NULL, &dev->usb_led) ||
126 usbdev_trig_set_name(&dev->usb_led, name, strlen(name)) < 0) {
127 del_usbdev(dev);
128 return -1;
132 return 0;
135 static void remove_usbdev(const char *name)
137 struct led_usbdev *dev;
139 dev = LIST_FIND(&usbdev_list,
140 usbdev_matched,
141 struct led_usbdev *,
142 name);
144 if (dev) del_usbdev(dev);
147 static struct proc_dir_entry *usbled_dir = NULL;
149 static int add_device_write(struct file *file, const char *buffer, unsigned long length, void *data)
151 char dev_name[DEV_BUS_ID_SIZE];
153 if ((length > 0) && (length < DEV_BUS_ID_SIZE)) {
154 memcpy(dev_name, buffer, length);
155 dev_name[length] = 0;
156 return (add_usbdev(dev_name) == 0) ? length : 0;
158 return 0;
161 static int remove_device_write(struct file *file, const char *buffer, unsigned long length, void *data)
163 char dev_name[DEV_BUS_ID_SIZE];
165 if ((length > 0) && (length < DEV_BUS_ID_SIZE)) {
166 memcpy(dev_name, buffer, length);
167 dev_name[length] = 0;
168 remove_usbdev(dev_name);
169 return length;
171 return 0;
174 static int gpio_pin_write(struct file *file, const char *buffer, unsigned long length, void *data)
176 char s[11];
177 int value;
179 if ((length > 0) && (length < 11)) {
180 memcpy(s, buffer, length);
181 s[length] = 0;
183 value = simple_strtol(s, NULL, 0);
184 write_lock(&usbdev_lock);
185 reverse = (value >= 0);
186 gpio_pin = reverse ? value : (value == -99 ? 0 : -value);
187 write_unlock(&usbdev_lock);
189 return length;
191 return 0;
194 static int gpio_pin_read(char *page, char **start, off_t off, int count, int *eof, void *data)
196 int pin = reverse ? gpio_pin : (gpio_pin ? -gpio_pin : -99);
197 return sprintf(page, "%d\n", pin);
200 static int __init init(void)
202 struct proc_dir_entry *p;
204 if (!(sih = si_kattach(SI_OSH)))
205 return -ENODEV;
207 usbled_dir = proc_mkdir("leds-usb", NULL);
209 if (usbled_dir) {
210 usbled_dir->owner = THIS_MODULE;
212 p = create_proc_entry("add", 0200, usbled_dir);
213 if (p) {
214 p->owner = THIS_MODULE;
215 p->write_proc = add_device_write;
218 p = create_proc_entry("remove", 0200, usbled_dir);
219 if (p) {
220 p->owner = THIS_MODULE;
221 p->write_proc = remove_device_write;
224 p = create_proc_entry("gpio_pin", 0200, usbled_dir);
225 if (p) {
226 p->owner = THIS_MODULE;
227 p->write_proc = gpio_pin_write;
228 p->read_proc = gpio_pin_read;
232 return (usbled_dir == NULL);
235 static void __exit fini(void)
237 usbdev_flush();
239 if (usbled_dir) {
240 remove_proc_entry("gpio_pin", usbled_dir);
241 remove_proc_entry("remove", usbled_dir);
242 remove_proc_entry("add", usbled_dir);
244 remove_proc_entry("leds-usb", NULL);
245 usbled_dir = NULL;
249 module_init(init);
250 module_exit(fini);
252 MODULE_LICENSE("GPL");