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

Cache object: e02194b1a45bd3864419b41ec3ceac57


[ 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.