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>
24 #include <sys/module.h>
27 LIST_ENTRY(ledsc
) list
;
40 static struct unrhdr
*led_unit
;
41 static struct lock led_lock
;
42 static struct lock led_lock2
;
43 static LIST_HEAD(, ledsc
) led_list
= LIST_HEAD_INITIALIZER(led_list
);
44 static struct callout led_ch
;
45 static int blinkers
= 0;
47 static MALLOC_DEFINE(M_LED
, "LED", "LED driver");
54 lockmgr(&led_lock
, LK_EXCLUSIVE
);
55 LIST_FOREACH(sc
, &led_list
, list
) {
62 if (*sc
->ptr
== '.') {
66 } else if (*sc
->ptr
== 'U' || *sc
->ptr
== 'u') {
67 if (sc
->last_second
== time_second
)
69 sc
->last_second
= time_second
;
70 sc
->func(sc
->private, *sc
->ptr
== 'U');
71 } else if (*sc
->ptr
>= 'a' && *sc
->ptr
<= 'j') {
72 sc
->func(sc
->private, 0);
73 sc
->count
= (*sc
->ptr
& 0xf) - 1;
74 } else if (*sc
->ptr
>= 'A' && *sc
->ptr
<= 'J') {
75 sc
->func(sc
->private, 1);
76 sc
->count
= (*sc
->ptr
& 0xf) - 1;
83 callout_reset(&led_ch
, hz
/ 10, led_timeout
, p
);
84 lockmgr(&led_lock
, LK_RELEASE
);
88 led_state(struct ledsc
*sc
, struct sbuf
**sb
, int state
)
90 struct sbuf
*sb2
= NULL
;
95 sc
->str
= sbuf_data(*sb
);
96 if (sc
->ptr
== NULL
) {
98 callout_reset(&led_ch
, hz
/ 10, led_timeout
, NULL
);
106 sc
->func(sc
->private, state
);
114 led_parse(const char *s
, struct sbuf
**sb
, int *state
)
119 * Handle "on" and "off" immediately so people can flash really
120 * fast from userland if they want to
122 if (*s
== '0' || *s
== '1') {
128 *sb
= sbuf_new_auto();
133 * Flash, default is 100msec/100msec.
134 * 'f2' sets 200msec/200msec etc.
137 if (s
[1] >= '1' && s
[1] <= '9')
141 sbuf_printf(*sb
, "%c%c", 'A' + i
, 'a' + i
);
144 * Digits, flashes out numbers.
145 * 'd12' becomes -__________-_-______________________________
161 * String, roll your own.
162 * 'a-j' gives "off" for n/10 sec.
163 * 'A-J' gives "on" for n/10 sec.
164 * no delay before repeat
165 * 'sAaAbBa' becomes _-_--__-
169 if ((*s
>= 'a' && *s
<= 'j') ||
170 (*s
>= 'A' && *s
<= 'J') ||
171 *s
== 'U' || *s
<= 'u' ||
173 sbuf_bcat(*sb
, s
, 1);
182 * 1sec pause between repeats
183 * '... --- ...' -> _-_-_-___---_---_---___-_-_-__________
202 error
= sbuf_finish(*sb
);
203 if (error
!= 0 || sbuf_len(*sb
) == 0) {
211 led_open(struct dev_open_args
*ap
)
217 led_close(struct dev_close_args
*ap
)
223 led_write(struct dev_write_args
*ap
)
225 struct uio
*uio
= ap
->a_uio
;
226 cdev_t dev
= ap
->a_head
.a_dev
;
229 struct sbuf
*sb
= NULL
;
230 int error
, state
= 0;
232 if (uio
->uio_resid
> 512)
234 s
= kmalloc(uio
->uio_resid
+ 1, M_DEVBUF
, M_WAITOK
);
235 s
[uio
->uio_resid
] = '\0';
236 error
= uiomove(s
, uio
->uio_resid
, uio
);
241 error
= led_parse(s
, &sb
, &state
);
245 lockmgr(&led_lock
, LK_EXCLUSIVE
);
248 error
= led_state(sc
, &sb
, state
);
249 lockmgr(&led_lock
, LK_RELEASE
);
256 led_set(char const *name
, char const *cmd
)
259 struct sbuf
*sb
= NULL
;
260 int error
, state
= 0;
262 error
= led_parse(cmd
, &sb
, &state
);
265 lockmgr(&led_lock
, LK_EXCLUSIVE
);
266 LIST_FOREACH(sc
, &led_list
, list
) {
267 if (strcmp(sc
->name
, name
) == 0)
271 error
= led_state(sc
, &sb
, state
);
274 lockmgr(&led_lock
, LK_RELEASE
);
280 static struct dev_ops led_ops
= {
281 { "LED", 0, D_MPSAFE
},
283 .d_close
= led_close
,
284 .d_write
= led_write
,
288 led_create(led_t
*func
, void *priv
, char const *name
)
291 return (led_create_state(func
, priv
, name
, 0));
294 led_create_state(led_t
*func
, void *priv
, char const *name
, int state
)
298 sc
= kmalloc(sizeof *sc
, M_LED
, M_WAITOK
| M_ZERO
);
300 lockmgr(&led_lock2
, LK_EXCLUSIVE
);
301 sc
->name
= kstrdup(name
, M_LED
);
302 sc
->unit
= alloc_unr(led_unit
);
305 sc
->dev
= make_dev(&led_ops
, sc
->unit
,
306 UID_ROOT
, GID_WHEEL
, 0600, "led/%s", name
);
307 lockmgr(&led_lock2
, LK_RELEASE
);
309 lockmgr(&led_lock
, LK_EXCLUSIVE
);
310 sc
->dev
->si_drv1
= sc
;
311 LIST_INSERT_HEAD(&led_list
, sc
, list
);
312 sc
->func(sc
->private, state
!= 0);
313 lockmgr(&led_lock
, LK_RELEASE
);
319 led_destroy(struct cdev
*dev
)
323 lockmgr(&led_lock
, LK_EXCLUSIVE
);
328 LIST_REMOVE(sc
, list
);
329 if (LIST_EMPTY(&led_list
))
330 callout_stop(&led_ch
);
331 lockmgr(&led_lock
, LK_RELEASE
);
333 lockmgr(&led_lock2
, LK_EXCLUSIVE
);
334 free_unr(led_unit
, sc
->unit
);
336 if (sc
->spec
!= NULL
)
337 sbuf_delete(sc
->spec
);
338 kfree(sc
->name
, M_LED
);
340 lockmgr(&led_lock2
, LK_RELEASE
);
347 led_unit
= new_unrhdr(0, INT_MAX
, NULL
);
348 lockinit(&led_lock
, "LED lock", 0, LK_CANRECURSE
);
349 lockinit(&led_lock2
, "LED lock2", 0, LK_CANRECURSE
);
350 callout_init_mp(&led_ch
);
359 lockmgr(&led_lock
, LK_EXCLUSIVE
);
360 /* A minimal sanity check, before unloading. */
361 if (!LIST_EMPTY(&led_list
))
363 lockmgr(&led_lock
, LK_RELEASE
);
365 callout_cancel(&led_ch
);
366 delete_unrhdr(led_unit
);
367 lockuninit(&led_lock
);
368 lockuninit(&led_lock2
);
374 led_modevent(module_t mod
, int type
, void *unused
)
380 error
= led_drvinit();
383 error
= led_drvexit();
392 static moduledata_t led_mod
= {
397 DECLARE_MODULE(led
, led_mod
, SI_SUB_DRIVERS
, SI_ORDER_MIDDLE
);
398 MODULE_VERSION(led
, 1);