The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/led/led.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    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  * ----------------------------------------------------------------------------
    8  *
    9  */
   10 
   11 #include <sys/cdefs.h>
   12 __FBSDID("$FreeBSD: releng/6.4/sys/dev/led/led.c 143238 2005-03-07 11:05:47Z phk $");
   13 
   14 #include <sys/param.h>
   15 #include <sys/conf.h>
   16 #include <sys/kernel.h>
   17 #include <sys/systm.h>
   18 #include <sys/malloc.h>
   19 #include <sys/ctype.h>
   20 #include <sys/sbuf.h>
   21 #include <sys/queue.h>
   22 #include <dev/led/led.h>
   23 #include <sys/uio.h>
   24 #include <sys/sx.h>
   25 
   26 struct ledsc {
   27         LIST_ENTRY(ledsc)       list;
   28         void                    *private;
   29         int                     unit;
   30         led_t                   *func;
   31         struct cdev *dev;
   32         struct sbuf             *spec;
   33         char                    *str;
   34         char                    *ptr;
   35         int                     count;
   36         time_t                  last_second;
   37 };
   38 
   39 static struct unrhdr *led_unit;
   40 static struct mtx led_mtx;
   41 static struct sx led_sx;
   42 static LIST_HEAD(, ledsc) led_list = LIST_HEAD_INITIALIZER(&led_list);
   43 static struct callout led_ch;
   44 
   45 static MALLOC_DEFINE(M_LED, "LED", "LED driver");
   46 
   47 static void
   48 led_timeout(void *p)
   49 {
   50         struct ledsc    *sc;
   51 
   52         mtx_lock(&led_mtx);
   53         LIST_FOREACH(sc, &led_list, list) {
   54                 if (sc->ptr == NULL)
   55                         continue;
   56                 if (sc->count > 0) {
   57                         sc->count--;
   58                         continue;
   59                 }
   60                 if (*sc->ptr == '.') {
   61                         sc->ptr = NULL;
   62                         continue;
   63                 } else if (*sc->ptr == 'U' || *sc->ptr == 'u') {
   64                         if (sc->last_second == time_second)
   65                                 continue;
   66                         sc->last_second = time_second;
   67                         sc->func(sc->private, *sc->ptr == 'U');
   68                 } else if (*sc->ptr >= 'a' && *sc->ptr <= 'j') {
   69                         sc->func(sc->private, 0);
   70                         sc->count = (*sc->ptr & 0xf) - 1;
   71                 } else if (*sc->ptr >= 'A' && *sc->ptr <= 'J') {
   72                         sc->func(sc->private, 1);
   73                         sc->count = (*sc->ptr & 0xf) - 1;
   74                 }
   75                 sc->ptr++;
   76                 if (*sc->ptr == '\0')
   77                         sc->ptr = sc->str;
   78         }
   79         mtx_unlock(&led_mtx);
   80         callout_reset(&led_ch, hz / 10, led_timeout, p);
   81         return;
   82 }
   83 
   84 static int
   85 led_state(struct cdev *dev, struct sbuf *sb, int state)
   86 {
   87         struct sbuf *sb2 = NULL;
   88         struct ledsc *sc;
   89 
   90         mtx_lock(&led_mtx);
   91         sc = dev->si_drv1;
   92         if (sc != NULL) {
   93                 sb2 = sc->spec;
   94                 sc->spec = sb;
   95                 if (sb != NULL) {
   96                         sc->str = sbuf_data(sb);
   97                         sc->ptr = sc->str;
   98                 } else {
   99                         sc->str = NULL;
  100                         sc->ptr = NULL;
  101                         sc->func(sc->private, state);
  102                 }
  103                 sc->count = 0;
  104         }
  105         mtx_unlock(&led_mtx);
  106         if (sb2 != NULL)
  107                 sbuf_delete(sb2);
  108         if (sc == NULL)
  109                 return (ENXIO);
  110         return(0);
  111 }
  112 
  113 static int
  114 led_write(struct cdev *dev, struct uio *uio, int ioflag)
  115 {
  116         int error;
  117         char *s, *s2;
  118         struct sbuf *sb = NULL;
  119         int i;
  120 
  121         if (dev->si_drv1 == NULL)
  122                 return (ENXIO);
  123 
  124         if (uio->uio_resid > 512)
  125                 return (EINVAL);
  126         s2 = s = malloc(uio->uio_resid + 1, M_DEVBUF, M_WAITOK);
  127         s[uio->uio_resid] = '\0';
  128         error = uiomove(s, uio->uio_resid, uio);
  129         if (error) {
  130                 free(s2, M_DEVBUF);
  131                 return (error);
  132         }
  133 
  134         /*
  135          * Handle "on" and "off" immediately so people can flash really
  136          * fast from userland if they want to
  137          */
  138         if (*s == '' || *s == '1') {
  139                 error = led_state(dev, NULL, *s & 1);
  140                 free(s2, M_DEVBUF);
  141                 return(error);
  142         }
  143 
  144         sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND);
  145         if (sb == NULL) {
  146                 free(s2, M_DEVBUF);
  147                 return (ENOMEM);
  148         }
  149                 
  150         switch(s[0]) {
  151                 /*
  152                  * Flash, default is 100msec/100msec.
  153                  * 'f2' sets 200msec/200msec etc.
  154                  */
  155                 case 'f':
  156                         if (s[1] >= '1' && s[1] <= '9')
  157                                 i = s[1] - '1';
  158                         else
  159                                 i = 0;
  160                         sbuf_printf(sb, "%c%c", 'A' + i, 'a' + i);
  161                         break;
  162                 /*
  163                  * Digits, flashes out numbers.
  164                  * 'd12' becomes -__________-_-______________________________
  165                  */
  166                 case 'd':
  167                         for(s++; *s; s++) {
  168                                 if (!isdigit(*s))
  169                                         continue;
  170                                 i = *s - '';
  171                                 if (i == 0)
  172                                         i = 10;
  173                                 for (; i > 1; i--) 
  174                                         sbuf_cat(sb, "Aa");
  175                                 sbuf_cat(sb, "Aj");
  176                         }
  177                         sbuf_cat(sb, "jj");
  178                         break;
  179                 /*
  180                  * String, roll your own.
  181                  * 'a-j' gives "off" for n/10 sec.
  182                  * 'A-J' gives "on" for n/10 sec.
  183                  * no delay before repeat
  184                  * 'sAaAbBa' becomes _-_--__-
  185                  */
  186                 case 's':
  187                         for(s++; *s; s++) {
  188                                 if ((*s >= 'a' && *s <= 'j') ||
  189                                     (*s >= 'A' && *s <= 'J') ||
  190                                     *s == 'U' || *s <= 'u' ||
  191                                         *s == '.')
  192                                         sbuf_bcat(sb, s, 1);
  193                         }
  194                         break;
  195                 /*
  196                  * Morse.
  197                  * '.' becomes _-
  198                  * '-' becomes _---
  199                  * ' ' becomes __
  200                  * '\n' becomes ____
  201                  * 1sec pause between repeats
  202                  * '... --- ...' -> _-_-_-___---_---_---___-_-_-__________
  203                  */
  204                 case 'm':
  205                         for(s++; *s; s++) {
  206                                 if (*s == '.')
  207                                         sbuf_cat(sb, "aA");
  208                                 else if (*s == '-')
  209                                         sbuf_cat(sb, "aC");
  210                                 else if (*s == ' ')
  211                                         sbuf_cat(sb, "b");
  212                                 else if (*s == '\n')
  213                                         sbuf_cat(sb, "d");
  214                         }
  215                         sbuf_cat(sb, "j");
  216                         break;
  217                 default:
  218                         sbuf_delete(sb);
  219                         free(s2, M_DEVBUF);
  220                         return (EINVAL);
  221         }
  222         sbuf_finish(sb);
  223         free(s2, M_DEVBUF);
  224         if (sbuf_overflowed(sb)) {
  225                 sbuf_delete(sb);
  226                 return (ENOMEM);
  227         }
  228         if (sbuf_len(sb) == 0) {
  229                 sbuf_delete(sb);
  230                 return (0);
  231         }
  232 
  233         return (led_state(dev, sb, 0));
  234 }
  235 
  236 static struct cdevsw led_cdevsw = {
  237         .d_version =    D_VERSION,
  238         .d_write =      led_write,
  239         .d_name =       "LED",
  240 };
  241 
  242 struct cdev *
  243 led_create(led_t *func, void *priv, char const *name)
  244 {
  245         struct ledsc    *sc;
  246 
  247         sc = malloc(sizeof *sc, M_LED, M_WAITOK | M_ZERO);
  248 
  249         sx_xlock(&led_sx);
  250         sc->unit = alloc_unr(led_unit);
  251         sc->private = priv;
  252         sc->func = func;
  253         sc->dev = make_dev(&led_cdevsw, unit2minor(sc->unit),
  254             UID_ROOT, GID_WHEEL, 0600, "led/%s", name);
  255         sx_xunlock(&led_sx);
  256 
  257         mtx_lock(&led_mtx);
  258         sc->dev->si_drv1 = sc;
  259         if (LIST_EMPTY(&led_list))
  260                 callout_reset(&led_ch, hz / 10, led_timeout, NULL);
  261         LIST_INSERT_HEAD(&led_list, sc, list);
  262         sc->func(sc->private, 0);
  263         mtx_unlock(&led_mtx);
  264 
  265         return (sc->dev);
  266 }
  267 
  268 void
  269 led_destroy(struct cdev *dev)
  270 {
  271         struct ledsc *sc;
  272 
  273         mtx_lock(&led_mtx);
  274         sc = dev->si_drv1;
  275         dev->si_drv1 = NULL;
  276 
  277         LIST_REMOVE(sc, list);
  278         if (LIST_EMPTY(&led_list))
  279                 callout_stop(&led_ch);
  280         mtx_unlock(&led_mtx);
  281 
  282         sx_xlock(&led_sx);
  283         free_unr(led_unit, sc->unit);
  284         destroy_dev(dev);
  285         if (sc->spec != NULL)
  286                 sbuf_delete(sc->spec);
  287         free(sc, M_LED);
  288         sx_xunlock(&led_sx);
  289 }
  290 
  291 static void
  292 led_drvinit(void *unused)
  293 {
  294 
  295         led_unit = new_unrhdr(0, minor2unit(MAXMINOR), NULL);
  296         mtx_init(&led_mtx, "LED mtx", NULL, MTX_DEF);
  297         sx_init(&led_sx, "LED sx");
  298         callout_init(&led_ch, CALLOUT_MPSAFE);
  299 }
  300 
  301 SYSINIT(leddev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, led_drvinit, NULL);

Cache object: 776eedca8eabd6a4911453964db42c61


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.