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

Cache object: 8490912dc7152871c151159b2aea5a5f


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