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/8.2/sys/dev/sound/pcm/sndstat.c 203184 2010-01-30 12:11:21Z antoine $");
   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 };
   57 
   58 struct sndstat_entry {
   59         SLIST_ENTRY(sndstat_entry) link;
   60         device_t dev;
   61         char *str;
   62         sndstat_handler handler;
   63         int type, unit;
   64 };
   65 
   66 static struct mtx sndstat_lock;
   67 static struct sbuf sndstat_sbuf;
   68 static struct cdev *sndstat_dev = NULL;
   69 static int sndstat_bufptr = -1;
   70 static int sndstat_maxunit = -1;
   71 static int sndstat_files = 0;
   72 
   73 #define SNDSTAT_PID(x)          ((pid_t)((intptr_t)((x)->si_drv1)))
   74 #define SNDSTAT_PID_SET(x, y)   (x)->si_drv1 = (void *)((intptr_t)(y))
   75 #define SNDSTAT_FLUSH()         do {                                    \
   76         if (sndstat_bufptr != -1) {                                     \
   77                 sbuf_delete(&sndstat_sbuf);                             \
   78                 sndstat_bufptr = -1;                                    \
   79         }                                                               \
   80 } while (0)
   81 
   82 static SLIST_HEAD(, sndstat_entry) sndstat_devlist = SLIST_HEAD_INITIALIZER(sndstat_devlist);
   83 
   84 int snd_verbose = 0;
   85 TUNABLE_INT("hw.snd.verbose", &snd_verbose);
   86 
   87 #ifdef SND_DEBUG
   88 static int
   89 sysctl_hw_snd_sndstat_pid(SYSCTL_HANDLER_ARGS)
   90 {
   91         int err, val;
   92 
   93         if (sndstat_dev == NULL)
   94                 return (EINVAL);
   95 
   96         mtx_lock(&sndstat_lock);
   97         val = (int)SNDSTAT_PID(sndstat_dev);
   98         mtx_unlock(&sndstat_lock);
   99         err = sysctl_handle_int(oidp, &val, 0, req);
  100         if (err == 0 && req->newptr != NULL && val == 0) {
  101                 mtx_lock(&sndstat_lock);
  102                 SNDSTAT_FLUSH();
  103                 SNDSTAT_PID_SET(sndstat_dev, 0);
  104                 mtx_unlock(&sndstat_lock);
  105         }
  106         return (err);
  107 }
  108 SYSCTL_PROC(_hw_snd, OID_AUTO, sndstat_pid, CTLTYPE_INT | CTLFLAG_RW,
  109     0, sizeof(int), sysctl_hw_snd_sndstat_pid, "I", "sndstat busy pid");
  110 #endif
  111 
  112 static int sndstat_prepare(struct sbuf *s);
  113 
  114 static int
  115 sysctl_hw_sndverbose(SYSCTL_HANDLER_ARGS)
  116 {
  117         int error, verbose;
  118 
  119         verbose = snd_verbose;
  120         error = sysctl_handle_int(oidp, &verbose, 0, req);
  121         if (error == 0 && req->newptr != NULL) {
  122                 mtx_lock(&sndstat_lock);
  123                 if (verbose < 0 || verbose > 4)
  124                         error = EINVAL;
  125                 else
  126                         snd_verbose = verbose;
  127                 mtx_unlock(&sndstat_lock);
  128         }
  129         return error;
  130 }
  131 SYSCTL_PROC(_hw_snd, OID_AUTO, verbose, CTLTYPE_INT | CTLFLAG_RW,
  132             0, sizeof(int), sysctl_hw_sndverbose, "I", "verbosity level");
  133 
  134 static int
  135 sndstat_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
  136 {
  137         if (sndstat_dev == NULL || i_dev != sndstat_dev)
  138                 return EBADF;
  139 
  140         mtx_lock(&sndstat_lock);
  141         if (SNDSTAT_PID(i_dev) != 0) {
  142                 mtx_unlock(&sndstat_lock);
  143                 return EBUSY;
  144         }
  145         SNDSTAT_PID_SET(i_dev, td->td_proc->p_pid);
  146         mtx_unlock(&sndstat_lock);
  147         if (sbuf_new(&sndstat_sbuf, NULL, 4096, SBUF_AUTOEXTEND) == NULL) {
  148                 mtx_lock(&sndstat_lock);
  149                 SNDSTAT_PID_SET(i_dev, 0);
  150                 mtx_unlock(&sndstat_lock);
  151                 return ENXIO;
  152         }
  153         sndstat_bufptr = 0;
  154         return 0;
  155 }
  156 
  157 static int
  158 sndstat_close(struct cdev *i_dev, int flags, int mode, struct thread *td)
  159 {
  160         if (sndstat_dev == NULL || i_dev != sndstat_dev)
  161                 return EBADF;
  162 
  163         mtx_lock(&sndstat_lock);
  164         if (SNDSTAT_PID(i_dev) == 0) {
  165                 mtx_unlock(&sndstat_lock);
  166                 return EBADF;
  167         }
  168 
  169         SNDSTAT_FLUSH();
  170         SNDSTAT_PID_SET(i_dev, 0);
  171 
  172         mtx_unlock(&sndstat_lock);
  173 
  174         return 0;
  175 }
  176 
  177 static int
  178 sndstat_read(struct cdev *i_dev, struct uio *buf, int flag)
  179 {
  180         int l, err;
  181 
  182         if (sndstat_dev == NULL || i_dev != sndstat_dev)
  183                 return EBADF;
  184 
  185         mtx_lock(&sndstat_lock);
  186         if (SNDSTAT_PID(i_dev) != buf->uio_td->td_proc->p_pid ||
  187             sndstat_bufptr == -1) {
  188                 mtx_unlock(&sndstat_lock);
  189                 return EBADF;
  190         }
  191         mtx_unlock(&sndstat_lock);
  192 
  193         if (sndstat_bufptr == 0) {
  194                 err = (sndstat_prepare(&sndstat_sbuf) > 0) ? 0 : ENOMEM;
  195                 if (err) {
  196                         mtx_lock(&sndstat_lock);
  197                         SNDSTAT_FLUSH();
  198                         mtx_unlock(&sndstat_lock);
  199                         return err;
  200                 }
  201         }
  202 
  203         l = min(buf->uio_resid, sbuf_len(&sndstat_sbuf) - sndstat_bufptr);
  204         err = (l > 0)? uiomove(sbuf_data(&sndstat_sbuf) + sndstat_bufptr, l, buf) : 0;
  205         sndstat_bufptr += l;
  206 
  207         return err;
  208 }
  209 
  210 /************************************************************************/
  211 
  212 static struct sndstat_entry *
  213 sndstat_find(int type, int unit)
  214 {
  215         struct sndstat_entry *ent;
  216 
  217         SLIST_FOREACH(ent, &sndstat_devlist, link) {
  218                 if (ent->type == type && ent->unit == unit)
  219                         return ent;
  220         }
  221 
  222         return NULL;
  223 }
  224 
  225 int
  226 sndstat_acquire(struct thread *td)
  227 {
  228         if (sndstat_dev == NULL)
  229                 return EBADF;
  230 
  231         mtx_lock(&sndstat_lock);
  232         if (SNDSTAT_PID(sndstat_dev) != 0) {
  233                 mtx_unlock(&sndstat_lock);
  234                 return EBUSY;
  235         }
  236         SNDSTAT_PID_SET(sndstat_dev, td->td_proc->p_pid);
  237         mtx_unlock(&sndstat_lock);
  238         return 0;
  239 }
  240 
  241 int
  242 sndstat_release(struct thread *td)
  243 {
  244         if (sndstat_dev == NULL)
  245                 return EBADF;
  246 
  247         mtx_lock(&sndstat_lock);
  248         if (SNDSTAT_PID(sndstat_dev) != td->td_proc->p_pid) {
  249                 mtx_unlock(&sndstat_lock);
  250                 return EBADF;
  251         }
  252         SNDSTAT_PID_SET(sndstat_dev, 0);
  253         mtx_unlock(&sndstat_lock);
  254         return 0;
  255 }
  256 
  257 int
  258 sndstat_register(device_t dev, char *str, sndstat_handler handler)
  259 {
  260         struct sndstat_entry *ent;
  261         const char *devtype;
  262         int type, unit;
  263 
  264         if (dev) {
  265                 unit = device_get_unit(dev);
  266                 devtype = device_get_name(dev);
  267                 if (!strcmp(devtype, "pcm"))
  268                         type = SS_TYPE_PCM;
  269                 else if (!strcmp(devtype, "midi"))
  270                         type = SS_TYPE_MIDI;
  271                 else if (!strcmp(devtype, "sequencer"))
  272                         type = SS_TYPE_SEQUENCER;
  273                 else
  274                         return EINVAL;
  275         } else {
  276                 type = SS_TYPE_MODULE;
  277                 unit = -1;
  278         }
  279 
  280         ent = malloc(sizeof *ent, M_DEVBUF, M_WAITOK | M_ZERO);
  281         ent->dev = dev;
  282         ent->str = str;
  283         ent->type = type;
  284         ent->unit = unit;
  285         ent->handler = handler;
  286 
  287         mtx_lock(&sndstat_lock);
  288         SLIST_INSERT_HEAD(&sndstat_devlist, ent, link);
  289         if (type == SS_TYPE_MODULE)
  290                 sndstat_files++;
  291         sndstat_maxunit = (unit > sndstat_maxunit)? unit : sndstat_maxunit;
  292         mtx_unlock(&sndstat_lock);
  293 
  294         return 0;
  295 }
  296 
  297 int
  298 sndstat_registerfile(char *str)
  299 {
  300         return sndstat_register(NULL, str, NULL);
  301 }
  302 
  303 int
  304 sndstat_unregister(device_t dev)
  305 {
  306         struct sndstat_entry *ent;
  307 
  308         mtx_lock(&sndstat_lock);
  309         SLIST_FOREACH(ent, &sndstat_devlist, link) {
  310                 if (ent->dev == dev) {
  311                         SLIST_REMOVE(&sndstat_devlist, ent, sndstat_entry, link);
  312                         mtx_unlock(&sndstat_lock);
  313                         free(ent, M_DEVBUF);
  314 
  315                         return 0;
  316                 }
  317         }
  318         mtx_unlock(&sndstat_lock);
  319 
  320         return ENXIO;
  321 }
  322 
  323 int
  324 sndstat_unregisterfile(char *str)
  325 {
  326         struct sndstat_entry *ent;
  327 
  328         mtx_lock(&sndstat_lock);
  329         SLIST_FOREACH(ent, &sndstat_devlist, link) {
  330                 if (ent->dev == NULL && ent->str == str) {
  331                         SLIST_REMOVE(&sndstat_devlist, ent, sndstat_entry, link);
  332                         sndstat_files--;
  333                         mtx_unlock(&sndstat_lock);
  334                         free(ent, M_DEVBUF);
  335 
  336                         return 0;
  337                 }
  338         }
  339         mtx_unlock(&sndstat_lock);
  340 
  341         return ENXIO;
  342 }
  343 
  344 /************************************************************************/
  345 
  346 static int
  347 sndstat_prepare(struct sbuf *s)
  348 {
  349         struct sndstat_entry *ent;
  350         struct snddev_info *d;
  351         int i, j;
  352 
  353         sbuf_printf(s, "FreeBSD Audio Driver (newpcm: %ubit %d/%s)\n",
  354             (u_int)sizeof(intpcm32_t) << 3, SND_DRV_VERSION, MACHINE_ARCH);
  355         if (SLIST_EMPTY(&sndstat_devlist)) {
  356                 sbuf_printf(s, "No devices installed.\n");
  357                 sbuf_finish(s);
  358                 return sbuf_len(s);
  359         }
  360 
  361         sbuf_printf(s, "Installed devices:\n");
  362 
  363         for (i = 0; i <= sndstat_maxunit; i++) {
  364                 for (j = SS_TYPE_FIRST; j <= SS_TYPE_LAST; j++) {
  365                         ent = sndstat_find(j, i);
  366                         if (!ent)
  367                                 continue;
  368                         d = device_get_softc(ent->dev);
  369                         if (!PCM_REGISTERED(d))
  370                                 continue;
  371                         /* XXX Need Giant magic entry ??? */
  372                         PCM_ACQUIRE_QUICK(d);
  373                         sbuf_printf(s, "%s:", device_get_nameunit(ent->dev));
  374                         sbuf_printf(s, " <%s>", device_get_desc(ent->dev));
  375                         if (snd_verbose > 0)
  376                                 sbuf_printf(s, " %s", ent->str);
  377                         if (ent->handler)
  378                                 ent->handler(s, ent->dev, snd_verbose);
  379                         sbuf_printf(s, "\n");
  380                         PCM_RELEASE_QUICK(d);
  381                 }
  382         }
  383 
  384         if (snd_verbose >= 3 && sndstat_files > 0) {
  385                 sbuf_printf(s, "\nFile Versions:\n");
  386 
  387                 SLIST_FOREACH(ent, &sndstat_devlist, link) {
  388                         if (ent->dev == NULL && ent->str != NULL)
  389                                 sbuf_printf(s, "%s\n", ent->str);
  390                 }
  391         }
  392 
  393         sbuf_finish(s);
  394         return sbuf_len(s);
  395 }
  396 
  397 static int
  398 sndstat_init(void)
  399 {
  400         if (sndstat_dev != NULL)
  401                 return EINVAL;
  402         mtx_init(&sndstat_lock, "sndstat", "sndstat lock", MTX_DEF);
  403         sndstat_dev = make_dev(&sndstat_cdevsw, SND_DEV_STATUS,
  404             UID_ROOT, GID_WHEEL, 0444, "sndstat");
  405         return 0;
  406 }
  407 
  408 static int
  409 sndstat_uninit(void)
  410 {
  411         if (sndstat_dev == NULL)
  412                 return EINVAL;
  413 
  414         mtx_lock(&sndstat_lock);
  415         if (SNDSTAT_PID(sndstat_dev) != curthread->td_proc->p_pid) {
  416                 mtx_unlock(&sndstat_lock);
  417                 return EBUSY;
  418         }
  419 
  420         SNDSTAT_FLUSH();
  421 
  422         mtx_unlock(&sndstat_lock);
  423 
  424         destroy_dev(sndstat_dev);
  425         sndstat_dev = NULL;
  426 
  427         mtx_destroy(&sndstat_lock);
  428         return 0;
  429 }
  430 
  431 static void
  432 sndstat_sysinit(void *p)
  433 {
  434         sndstat_init();
  435 }
  436 
  437 static void
  438 sndstat_sysuninit(void *p)
  439 {
  440         int error;
  441 
  442         error = sndstat_uninit();
  443         KASSERT(error == 0, ("%s: error = %d", __func__, error));
  444 }
  445 
  446 SYSINIT(sndstat_sysinit, SI_SUB_DRIVERS, SI_ORDER_FIRST, sndstat_sysinit, NULL);
  447 SYSUNINIT(sndstat_sysuninit, SI_SUB_DRIVERS, SI_ORDER_FIRST, sndstat_sysuninit, NULL);

Cache object: 10695ce82778b380c01d48e222113d70


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