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/sound/pcm/sndstat.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  * Copyright (c) 2005-2009 Ariff Abdullah <ariff@FreeBSD.org>
    3  * Copyright (c) 2001 Cameron Grant <cg@FreeBSD.org>
    4  * All rights reserved.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25  * SUCH DAMAGE.
   26  */
   27 
   28 #ifdef HAVE_KERNEL_OPTION_HEADERS
   29 #include "opt_snd.h"
   30 #endif
   31 
   32 #include <dev/sound/pcm/sound.h>
   33 #include <dev/sound/pcm/pcm.h>
   34 #include <dev/sound/version.h>
   35 #include <sys/sx.h>
   36 
   37 SND_DECLARE_FILE("$FreeBSD: releng/10.0/sys/dev/sound/pcm/sndstat.c 248381 2013-03-16 17:57:00Z joel $");
   38 
   39 #define SS_TYPE_MODULE          0
   40 #define SS_TYPE_FIRST           1
   41 #define SS_TYPE_PCM             1
   42 #define SS_TYPE_MIDI            2
   43 #define SS_TYPE_SEQUENCER       3
   44 #define SS_TYPE_LAST            3
   45 
   46 static d_open_t sndstat_open;
   47 static d_close_t sndstat_close;
   48 static d_read_t sndstat_read;
   49 
   50 static struct cdevsw sndstat_cdevsw = {
   51         .d_version =    D_VERSION,
   52         .d_open =       sndstat_open,
   53         .d_close =      sndstat_close,
   54         .d_read =       sndstat_read,
   55         .d_name =       "sndstat",
   56         .d_flags =      D_TRACKCLOSE,
   57 };
   58 
   59 struct sndstat_entry {
   60         SLIST_ENTRY(sndstat_entry) link;
   61         device_t dev;
   62         char *str;
   63         sndstat_handler handler;
   64         int type, unit;
   65 };
   66 
   67 static struct sx sndstat_lock;
   68 static struct sbuf sndstat_sbuf;
   69 static struct cdev *sndstat_dev = NULL;
   70 static int sndstat_bufptr = -1;
   71 static int sndstat_maxunit = -1;
   72 static int sndstat_files = 0;
   73 
   74 #define SNDSTAT_PID(x)          ((pid_t)((intptr_t)((x)->si_drv1)))
   75 #define SNDSTAT_PID_SET(x, y)   (x)->si_drv1 = (void *)((intptr_t)(y))
   76 #define SNDSTAT_FLUSH()         do {                                    \
   77         if (sndstat_bufptr != -1) {                                     \
   78                 sbuf_delete(&sndstat_sbuf);                             \
   79                 sndstat_bufptr = -1;                                    \
   80         }                                                               \
   81 } while (0)
   82 
   83 static SLIST_HEAD(, sndstat_entry) sndstat_devlist = SLIST_HEAD_INITIALIZER(sndstat_devlist);
   84 
   85 int snd_verbose = 0;
   86 TUNABLE_INT("hw.snd.verbose", &snd_verbose);
   87 
   88 #ifdef SND_DEBUG
   89 static int
   90 sysctl_hw_snd_sndstat_pid(SYSCTL_HANDLER_ARGS)
   91 {
   92         int err, val;
   93 
   94         if (sndstat_dev == NULL)
   95                 return (EINVAL);
   96 
   97         sx_xlock(&sndstat_lock);
   98         val = (int)SNDSTAT_PID(sndstat_dev);
   99         err = sysctl_handle_int(oidp, &val, 0, req);
  100         if (err == 0 && req->newptr != NULL && val == 0) {
  101                 SNDSTAT_FLUSH();
  102                 SNDSTAT_PID_SET(sndstat_dev, 0);
  103         }
  104         sx_unlock(&sndstat_lock);
  105         return (err);
  106 }
  107 SYSCTL_PROC(_hw_snd, OID_AUTO, sndstat_pid, CTLTYPE_INT | CTLFLAG_RW,
  108     0, sizeof(int), sysctl_hw_snd_sndstat_pid, "I", "sndstat busy pid");
  109 #endif
  110 
  111 static int sndstat_prepare(struct sbuf *s);
  112 
  113 static int
  114 sysctl_hw_sndverbose(SYSCTL_HANDLER_ARGS)
  115 {
  116         int error, verbose;
  117 
  118         verbose = snd_verbose;
  119         error = sysctl_handle_int(oidp, &verbose, 0, req);
  120         if (error == 0 && req->newptr != NULL) {
  121                 if (verbose < 0 || verbose > 4)
  122                         error = EINVAL;
  123                 else
  124                         snd_verbose = verbose;
  125         }
  126         return error;
  127 }
  128 SYSCTL_PROC(_hw_snd, OID_AUTO, verbose, CTLTYPE_INT | CTLFLAG_RW,
  129             0, sizeof(int), sysctl_hw_sndverbose, "I", "verbosity level");
  130 
  131 static int
  132 sndstat_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
  133 {
  134         if (sndstat_dev == NULL || i_dev != sndstat_dev)
  135                 return EBADF;
  136 
  137         sx_xlock(&sndstat_lock);
  138         if (SNDSTAT_PID(i_dev) != 0) {
  139                 sx_unlock(&sndstat_lock);
  140                 return EBUSY;
  141         }
  142         SNDSTAT_PID_SET(i_dev, td->td_proc->p_pid);
  143         if (sbuf_new(&sndstat_sbuf, NULL, 4096, SBUF_AUTOEXTEND) == NULL) {
  144                 SNDSTAT_PID_SET(i_dev, 0);
  145                 sx_unlock(&sndstat_lock);
  146                 return ENXIO;
  147         }
  148         sndstat_bufptr = 0;
  149         sx_unlock(&sndstat_lock);
  150         return 0;
  151 }
  152 
  153 static int
  154 sndstat_close(struct cdev *i_dev, int flags, int mode, struct thread *td)
  155 {
  156         if (sndstat_dev == NULL || i_dev != sndstat_dev)
  157                 return EBADF;
  158 
  159         sx_xlock(&sndstat_lock);
  160         if (SNDSTAT_PID(i_dev) == 0) {
  161                 sx_unlock(&sndstat_lock);
  162                 return EBADF;
  163         }
  164 
  165         SNDSTAT_FLUSH();
  166         SNDSTAT_PID_SET(i_dev, 0);
  167 
  168         sx_unlock(&sndstat_lock);
  169 
  170         return 0;
  171 }
  172 
  173 static int
  174 sndstat_read(struct cdev *i_dev, struct uio *buf, int flag)
  175 {
  176         int l, err;
  177 
  178         if (sndstat_dev == NULL || i_dev != sndstat_dev)
  179                 return EBADF;
  180 
  181         sx_xlock(&sndstat_lock);
  182         if (SNDSTAT_PID(i_dev) != buf->uio_td->td_proc->p_pid ||
  183             sndstat_bufptr == -1) {
  184                 sx_unlock(&sndstat_lock);
  185                 return EBADF;
  186         }
  187 
  188         if (sndstat_bufptr == 0) {
  189                 err = (sndstat_prepare(&sndstat_sbuf) > 0) ? 0 : ENOMEM;
  190                 if (err) {
  191                         SNDSTAT_FLUSH();
  192                         sx_unlock(&sndstat_lock);
  193                         return err;
  194                 }
  195         }
  196 
  197         l = min(buf->uio_resid, sbuf_len(&sndstat_sbuf) - sndstat_bufptr);
  198         err = (l > 0)? uiomove(sbuf_data(&sndstat_sbuf) + sndstat_bufptr, l, buf) : 0;
  199         sndstat_bufptr += l;
  200         sx_unlock(&sndstat_lock);
  201 
  202         return err;
  203 }
  204 
  205 /************************************************************************/
  206 
  207 static struct sndstat_entry *
  208 sndstat_find(int type, int unit)
  209 {
  210         struct sndstat_entry *ent;
  211 
  212         SLIST_FOREACH(ent, &sndstat_devlist, link) {
  213                 if (ent->type == type && ent->unit == unit)
  214                         return ent;
  215         }
  216 
  217         return NULL;
  218 }
  219 
  220 int
  221 sndstat_acquire(struct thread *td)
  222 {
  223         if (sndstat_dev == NULL)
  224                 return EBADF;
  225 
  226         sx_xlock(&sndstat_lock);
  227         if (SNDSTAT_PID(sndstat_dev) != 0) {
  228                 sx_unlock(&sndstat_lock);
  229                 return EBUSY;
  230         }
  231         SNDSTAT_PID_SET(sndstat_dev, td->td_proc->p_pid);
  232         sx_unlock(&sndstat_lock);
  233         return 0;
  234 }
  235 
  236 int
  237 sndstat_release(struct thread *td)
  238 {
  239         if (sndstat_dev == NULL)
  240                 return EBADF;
  241 
  242         sx_xlock(&sndstat_lock);
  243         if (SNDSTAT_PID(sndstat_dev) != td->td_proc->p_pid) {
  244                 sx_unlock(&sndstat_lock);
  245                 return EBADF;
  246         }
  247         SNDSTAT_PID_SET(sndstat_dev, 0);
  248         sx_unlock(&sndstat_lock);
  249         return 0;
  250 }
  251 
  252 int
  253 sndstat_register(device_t dev, char *str, sndstat_handler handler)
  254 {
  255         struct sndstat_entry *ent;
  256         const char *devtype;
  257         int type, unit;
  258 
  259         if (dev) {
  260                 unit = device_get_unit(dev);
  261                 devtype = device_get_name(dev);
  262                 if (!strcmp(devtype, "pcm"))
  263                         type = SS_TYPE_PCM;
  264                 else if (!strcmp(devtype, "midi"))
  265                         type = SS_TYPE_MIDI;
  266                 else if (!strcmp(devtype, "sequencer"))
  267                         type = SS_TYPE_SEQUENCER;
  268                 else
  269                         return EINVAL;
  270         } else {
  271                 type = SS_TYPE_MODULE;
  272                 unit = -1;
  273         }
  274 
  275         ent = malloc(sizeof *ent, M_DEVBUF, M_WAITOK | M_ZERO);
  276         ent->dev = dev;
  277         ent->str = str;
  278         ent->type = type;
  279         ent->unit = unit;
  280         ent->handler = handler;
  281 
  282         sx_xlock(&sndstat_lock);
  283         SLIST_INSERT_HEAD(&sndstat_devlist, ent, link);
  284         if (type == SS_TYPE_MODULE)
  285                 sndstat_files++;
  286         sndstat_maxunit = (unit > sndstat_maxunit)? unit : sndstat_maxunit;
  287         sx_unlock(&sndstat_lock);
  288 
  289         return 0;
  290 }
  291 
  292 int
  293 sndstat_registerfile(char *str)
  294 {
  295         return sndstat_register(NULL, str, NULL);
  296 }
  297 
  298 int
  299 sndstat_unregister(device_t dev)
  300 {
  301         struct sndstat_entry *ent;
  302 
  303         sx_xlock(&sndstat_lock);
  304         SLIST_FOREACH(ent, &sndstat_devlist, link) {
  305                 if (ent->dev == dev) {
  306                         SLIST_REMOVE(&sndstat_devlist, ent, sndstat_entry, link);
  307                         sx_unlock(&sndstat_lock);
  308                         free(ent, M_DEVBUF);
  309 
  310                         return 0;
  311                 }
  312         }
  313         sx_unlock(&sndstat_lock);
  314 
  315         return ENXIO;
  316 }
  317 
  318 int
  319 sndstat_unregisterfile(char *str)
  320 {
  321         struct sndstat_entry *ent;
  322 
  323         sx_xlock(&sndstat_lock);
  324         SLIST_FOREACH(ent, &sndstat_devlist, link) {
  325                 if (ent->dev == NULL && ent->str == str) {
  326                         SLIST_REMOVE(&sndstat_devlist, ent, sndstat_entry, link);
  327                         sndstat_files--;
  328                         sx_unlock(&sndstat_lock);
  329                         free(ent, M_DEVBUF);
  330 
  331                         return 0;
  332                 }
  333         }
  334         sx_unlock(&sndstat_lock);
  335 
  336         return ENXIO;
  337 }
  338 
  339 /************************************************************************/
  340 
  341 static int
  342 sndstat_prepare(struct sbuf *s)
  343 {
  344         struct sndstat_entry *ent;
  345         struct snddev_info *d;
  346         int i, j;
  347 
  348         if (snd_verbose > 0) {
  349                 sbuf_printf(s, "FreeBSD Audio Driver (%ubit %d/%s)\n",
  350                     (u_int)sizeof(intpcm32_t) << 3, SND_DRV_VERSION,
  351                     MACHINE_ARCH);
  352         }
  353 
  354         if (SLIST_EMPTY(&sndstat_devlist)) {
  355                 sbuf_printf(s, "No devices installed.\n");
  356                 sbuf_finish(s);
  357                 return sbuf_len(s);
  358         }
  359 
  360         sbuf_printf(s, "Installed devices:\n");
  361 
  362         for (i = 0; i <= sndstat_maxunit; i++) {
  363                 for (j = SS_TYPE_FIRST; j <= SS_TYPE_LAST; j++) {
  364                         ent = sndstat_find(j, i);
  365                         if (!ent)
  366                                 continue;
  367                         d = device_get_softc(ent->dev);
  368                         if (!PCM_REGISTERED(d))
  369                                 continue;
  370                         /* XXX Need Giant magic entry ??? */
  371                         PCM_ACQUIRE_QUICK(d);
  372                         sbuf_printf(s, "%s:", device_get_nameunit(ent->dev));
  373                         sbuf_printf(s, " <%s>", device_get_desc(ent->dev));
  374                         if (snd_verbose > 0)
  375                                 sbuf_printf(s, " %s", ent->str);
  376                         if (ent->handler)
  377                                 ent->handler(s, ent->dev, snd_verbose);
  378                         sbuf_printf(s, "\n");
  379                         PCM_RELEASE_QUICK(d);
  380                 }
  381         }
  382 
  383         if (snd_verbose >= 3 && sndstat_files > 0) {
  384                 sbuf_printf(s, "\nFile Versions:\n");
  385 
  386                 SLIST_FOREACH(ent, &sndstat_devlist, link) {
  387                         if (ent->dev == NULL && ent->str != NULL)
  388                                 sbuf_printf(s, "%s\n", ent->str);
  389                 }
  390         }
  391 
  392         sbuf_finish(s);
  393         return sbuf_len(s);
  394 }
  395 
  396 static int
  397 sndstat_init(void)
  398 {
  399         if (sndstat_dev != NULL)
  400                 return EINVAL;
  401         sx_init(&sndstat_lock, "sndstat lock");
  402         sndstat_dev = make_dev(&sndstat_cdevsw, SND_DEV_STATUS,
  403             UID_ROOT, GID_WHEEL, 0444, "sndstat");
  404         return 0;
  405 }
  406 
  407 static int
  408 sndstat_uninit(void)
  409 {
  410         if (sndstat_dev == NULL)
  411                 return EINVAL;
  412 
  413         sx_xlock(&sndstat_lock);
  414         if (SNDSTAT_PID(sndstat_dev) != curthread->td_proc->p_pid) {
  415                 sx_unlock(&sndstat_lock);
  416                 return EBUSY;
  417         }
  418 
  419         /* XXXPHO: use destroy_dev_sched() */
  420         destroy_dev(sndstat_dev);
  421         sndstat_dev = NULL;
  422 
  423         SNDSTAT_FLUSH();
  424 
  425         sx_unlock(&sndstat_lock);
  426         sx_destroy(&sndstat_lock);
  427         return 0;
  428 }
  429 
  430 static void
  431 sndstat_sysinit(void *p)
  432 {
  433         sndstat_init();
  434 }
  435 
  436 static void
  437 sndstat_sysuninit(void *p)
  438 {
  439         int error;
  440 
  441         error = sndstat_uninit();
  442         KASSERT(error == 0, ("%s: error = %d", __func__, error));
  443 }
  444 
  445 SYSINIT(sndstat_sysinit, SI_SUB_DRIVERS, SI_ORDER_FIRST, sndstat_sysinit, NULL);
  446 SYSUNINIT(sndstat_sysuninit, SI_SUB_DRIVERS, SI_ORDER_FIRST, sndstat_sysuninit, NULL);

Cache object: b524759fda1c2556f7ec1950496d477f


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