2 * ----------------------------------------------------------------------------
3 * "THE BEER-WARE LICENSE" (Revision 42):
4 * <phk@FreeBSD.org> wrote this file. As long as you retain this notice you
5 * can do whatever you want with this stuff. If we meet some day, and you think
6 * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
7 * ----------------------------------------------------------------------------
9 * $FreeBSD: head/sys/dev/led/led.c 247008 2013-02-19 19:25:50Z mav $
12 #include <sys/param.h>
14 #include <sys/kernel.h>
15 #include <sys/systm.h>
16 #include <sys/limits.h>
17 #include <sys/malloc.h>
18 #include <sys/ctype.h>
20 #include <sys/queue.h>
21 #include <dev/misc/led/led.h>
23 #include <sys/device.h>
26 LIST_ENTRY(ledsc
) list
;
39 static struct unrhdr
*led_unit
;
40 static struct lock led_lock
;
41 static struct lock led_lock2
;
42 static LIST_HEAD(, ledsc
) led_list
= LIST_HEAD_INITIALIZER(led_list
);
43 static struct callout led_ch
;
44 static int blinkers
= 0;
46 static MALLOC_DEFINE(M_LED
, "LED", "LED driver");
53 lockmgr(&led_lock
, LK_EXCLUSIVE
);
54 LIST_FOREACH(sc
, &led_list
, list
) {
61 if (*sc
->ptr
== '.') {
65 } else if (*sc
->ptr
== 'U' || *sc
->ptr
== 'u') {
66 if (sc
->last_second
== time_second
)
68 sc
->last_second
= time_second
;
69 sc
->func(sc
->private, *sc
->ptr
== 'U');
70 } else if (*sc
->ptr
>= 'a' && *sc
->ptr
<= 'j') {
71 sc
->func(sc
->private, 0);
72 sc
->count
= (*sc
->ptr
& 0xf) - 1;
73 } else if (*sc
->ptr
>= 'A' && *sc
->ptr
<= 'J') {
74 sc
->func(sc
->private, 1);
75 sc
->count
= (*sc
->ptr
& 0xf) - 1;
82 callout_reset(&led_ch
, hz
/ 10, led_timeout
, p
);
83 lockmgr(&led_lock
, LK_RELEASE
);
87 led_state(struct ledsc
*sc
, struct sbuf
**sb
, int state
)
89 struct sbuf
*sb2
= NULL
;
94 sc
->str
= sbuf_data(*sb
);
95 if (sc
->ptr
== NULL
) {
97 callout_reset(&led_ch
, hz
/ 10, led_timeout
, NULL
);
105 sc
->func(sc
->private, state
);
113 led_parse(const char *s
, struct sbuf
**sb
, int *state
)
118 * Handle "on" and "off" immediately so people can flash really
119 * fast from userland if they want to
121 if (*s
== '0' || *s
== '1') {
127 *sb
= sbuf_new_auto();
132 * Flash, default is 100msec/100msec.
133 * 'f2' sets 200msec/200msec etc.
136 if (s
[1] >= '1' && s
[1] <= '9')
140 sbuf_printf(*sb
, "%c%c", 'A' + i
, 'a' + i
);
143 * Digits, flashes out numbers.
144 * 'd12' becomes -__________-_-______________________________
160 * String, roll your own.
161 * 'a-j' gives "off" for n/10 sec.
162 * 'A-J' gives "on" for n/10 sec.
163 * no delay before repeat
164 * 'sAaAbBa' becomes _-_--__-
168 if ((*s
>= 'a' && *s
<= 'j') ||
169 (*s
>= 'A' && *s
<= 'J') ||
170 *s
== 'U' || *s
<= 'u' ||
172 sbuf_bcat(*sb
, s
, 1);
181 * 1sec pause between repeats
182 * '... --- ...' -> _-_-_-___---_---_---___-_-_-__________
201 error
= sbuf_finish(*sb
);
202 if (error
!= 0 || sbuf_len(*sb
) == 0) {
210 led_open(struct dev_open_args
*ap
)
216 led_close(struct dev_close_args
*ap
)
222 led_write(struct dev_write_args
*ap
)
224 struct uio
*uio
= ap
->a_uio
;
225 cdev_t dev
= ap
->a_head
.a_dev
;
228 struct sbuf
*sb
= NULL
;
229 int error
, state
= 0;
231 if (uio
->uio_resid
> 512)
233 s
= kmalloc(uio
->uio_resid
+ 1, M_DEVBUF
, M_WAITOK
);
234 s
[uio
->uio_resid
] = '\0';
235 error
= uiomove(s
, uio
->uio_resid
, uio
);
240 error
= led_parse(s
, &sb
, &state
);
244 lockmgr(&led_lock
, LK_EXCLUSIVE
);
247 error
= led_state(sc
, &sb
, state
);
248 lockmgr(&led_lock
, LK_RELEASE
);
255 led_set(char const *name
, char const *cmd
)
258 struct sbuf
*sb
= NULL
;
259 int error
, state
= 0;
261 error
= led_parse(cmd
, &sb
, &state
);
264 lockmgr(&led_lock
, LK_EXCLUSIVE
);
265 LIST_FOREACH(sc
, &led_list
, list
) {
266 if (strcmp(sc
->name
, name
) == 0)
270 error
= led_state(sc
, &sb
, state
);
273 lockmgr(&led_lock
, LK_RELEASE
);
279 static struct dev_ops led_ops
= {
280 { "LED", 0, D_MPSAFE
},
282 .d_close
= led_close
,
283 .d_write
= led_write
,
287 led_create(led_t
*func
, void *priv
, char const *name
)
290 return (led_create_state(func
, priv
, name
, 0));
293 led_create_state(led_t
*func
, void *priv
, char const *name
, int state
)
297 sc
= kmalloc(sizeof *sc
, M_LED
, M_WAITOK
| M_ZERO
);
299 lockmgr(&led_lock2
, LK_EXCLUSIVE
);
300 sc
->name
= kstrdup(name
, M_LED
);
301 sc
->unit
= alloc_unr(led_unit
);
304 sc
->dev
= make_dev(&led_ops
, sc
->unit
,
305 UID_ROOT
, GID_WHEEL
, 0600, "led/%s", name
);
306 lockmgr(&led_lock2
, LK_RELEASE
);
308 lockmgr(&led_lock
, LK_EXCLUSIVE
);
309 sc
->dev
->si_drv1
= sc
;
310 LIST_INSERT_HEAD(&led_list
, sc
, list
);
311 sc
->func(sc
->private, state
!= 0);
312 lockmgr(&led_lock
, LK_RELEASE
);
318 led_destroy(struct cdev
*dev
)
322 lockmgr(&led_lock
, LK_EXCLUSIVE
);
327 LIST_REMOVE(sc
, list
);
328 if (LIST_EMPTY(&led_list
))
329 callout_stop(&led_ch
);
330 lockmgr(&led_lock
, LK_RELEASE
);
332 lockmgr(&led_lock2
, LK_EXCLUSIVE
);
333 free_unr(led_unit
, sc
->unit
);
335 if (sc
->spec
!= NULL
)
336 sbuf_delete(sc
->spec
);
337 kfree(sc
->name
, M_LED
);
339 lockmgr(&led_lock2
, LK_RELEASE
);
343 led_drvinit(void *unused
)
346 led_unit
= new_unrhdr(0, INT_MAX
, NULL
);
347 lockinit(&led_lock
, "LED lock", 0, LK_CANRECURSE
);
348 lockinit(&led_lock2
, "LED lock2", 0, LK_CANRECURSE
);
349 callout_init_mp(&led_ch
);
352 SYSINIT(leddev
, SI_SUB_DRIVERS
, SI_ORDER_MIDDLE
, led_drvinit
, NULL
);