3 GPIO-controlled USB LED Driver
4 Copyright (C) 2010-2011 Fedor Kozhevnikov
6 Licensed under GNU GPL v2.
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>
23 #ifndef CONFIG_PROC_FS
24 #error PROC_FS must be configured!
27 #define DEV_BUS_ID_SIZE 32
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
)
43 if (reverse
) brightness
= !brightness
;
44 gpio_led_ctl(brightness
? 1 : 0);
48 static DEFINE_RWLOCK(usbdev_lock
);
49 static LIST_HEAD(usbdev_list
);
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...) \
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)) { \
67 read_unlock_bh(&usbdev_lock); \
71 static void del_usbdev(struct led_usbdev
*dev
)
73 led_classdev_unregister(&dev
->usb_led
);
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
;
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
,
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
,
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) {
135 static void remove_usbdev(const char *name
)
137 struct led_usbdev
*dev
;
139 dev
= LIST_FIND(&usbdev_list
,
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;
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
);
174 static int gpio_pin_write(struct file
*file
, const char *buffer
, unsigned long length
, void *data
)
179 if ((length
> 0) && (length
< 11)) {
180 memcpy(s
, buffer
, length
);
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
);
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
)))
207 usbled_dir
= proc_mkdir("leds-usb", NULL
);
210 usbled_dir
->owner
= THIS_MODULE
;
212 p
= create_proc_entry("add", 0200, usbled_dir
);
214 p
->owner
= THIS_MODULE
;
215 p
->write_proc
= add_device_write
;
218 p
= create_proc_entry("remove", 0200, usbled_dir
);
220 p
->owner
= THIS_MODULE
;
221 p
->write_proc
= remove_device_write
;
224 p
= create_proc_entry("gpio_pin", 0200, usbled_dir
);
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)
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
);
252 MODULE_LICENSE("GPL");