File:  [DragonFly] / src / sys / dev / sound / pcm / sndstat.c
Revision 1.5: download - view: text, annotated - select for diffs
Thu May 13 23:49:21 2004 UTC (10 years, 6 months ago) by dillon
Branches: MAIN
CVS tags: HEAD
device switch 1/many: Remove d_autoq, add d_clone (where d_autoq was).

d_autoq was used to allow the device port dispatch to mix old-style synchronous
calls with new style messaging calls within a particular device.  It was never
used for that purpose.

d_clone will be more fully implemented as work continues.  We are going to
install d_port in the dev_t (struct specinfo) structure itself and d_clone
will be needed to allow devices to 'revector' the port on a minor-number
by minor-number basis, in particular allowing minor numbers to be directly
dispatched to distinct threads.  This is something we will be needing later
on.

    1: /*
    2:  * Copyright (c) 2001 Cameron Grant <gandalf@vilnya.demon.co.uk>
    3:  * All rights reserved.
    4:  *
    5:  * Redistribution and use in source and binary forms, with or without
    6:  * modification, are permitted provided that the following conditions
    7:  * are met:
    8:  * 1. Redistributions of source code must retain the above copyright
    9:  *    notice, this list of conditions and the following disclaimer.
   10:  * 2. Redistributions in binary form must reproduce the above copyright
   11:  *    notice, this list of conditions and the following disclaimer in the
   12:  *    documentation and/or other materials provided with the distribution.
   13:  *
   14:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24:  * SUCH DAMAGE.
   25:  *
   26:  * $FreeBSD: src/sys/dev/sound/pcm/sndstat.c,v 1.4.2.2 2002/04/22 15:49:36 cg Exp $
   27:  * $DragonFly: src/sys/dev/sound/pcm/sndstat.c,v 1.5 2004/05/13 23:49:21 dillon Exp $
   28:  */
   29: 
   30: #include <dev/sound/pcm/sound.h>
   31: #include <dev/sound/pcm/vchan.h>
   32: 
   33: SND_DECLARE_FILE("$DragonFly: src/sys/dev/sound/pcm/sndstat.c,v 1.5 2004/05/13 23:49:21 dillon Exp $");
   34: 
   35: #define	SS_TYPE_MODULE		0
   36: #define	SS_TYPE_FIRST		1
   37: #define	SS_TYPE_PCM		1
   38: #define	SS_TYPE_MIDI		2
   39: #define	SS_TYPE_SEQUENCER	3
   40: #define	SS_TYPE_LAST		3
   41: 
   42: static d_open_t sndstat_open;
   43: static d_close_t sndstat_close;
   44: static d_read_t sndstat_read;
   45: 
   46: static struct cdevsw sndstat_cdevsw = {
   47: 	/* name */	"sndstat",
   48: 	/* maj */	SND_CDEV_MAJOR,
   49: 	/* flags */	0,
   50: 	/* port */	NULL,
   51: 	/* clone */	NULL,
   52: 
   53: 	/* open */	sndstat_open,
   54: 	/* close */	sndstat_close,
   55: 	/* read */	sndstat_read,
   56: 	/* write */	nowrite,
   57: 	/* ioctl */	noioctl,
   58: 	/* poll */	nopoll,
   59: 	/* mmap */	nommap,
   60: 	/* strategy */	nostrategy,
   61: 	/* dump */	nodump,
   62: 	/* psize */	nopsize
   63: };
   64: 
   65: struct sndstat_entry {
   66: 	SLIST_ENTRY(sndstat_entry) link;
   67: 	device_t dev;
   68: 	char *str;
   69: 	sndstat_handler handler;
   70: 	int type, unit;
   71: };
   72: 
   73: static struct sbuf sndstat_sbuf;
   74: static dev_t sndstat_dev = 0;
   75: static int sndstat_isopen = 0;
   76: static int sndstat_bufptr;
   77: static int sndstat_maxunit = -1;
   78: static int sndstat_files = 0;
   79: 
   80: static SLIST_HEAD(, sndstat_entry) sndstat_devlist = SLIST_HEAD_INITIALIZER(none);
   81: 
   82: static int sndstat_verbose = 1;
   83: #ifdef	USING_MUTEX
   84: TUNABLE_INT("hw.snd.verbose", &sndstat_verbose);
   85: #else
   86: TUNABLE_INT_DECL("hw.snd.verbose", 1, sndstat_verbose);
   87: #endif
   88: 
   89: static int sndstat_prepare(struct sbuf *s);
   90: 
   91: static int
   92: sysctl_hw_sndverbose(SYSCTL_HANDLER_ARGS)
   93: {
   94: 	intrmask_t s;
   95: 	int error, verbose;
   96: 
   97: 	verbose = sndstat_verbose;
   98: 	error = sysctl_handle_int(oidp, &verbose, sizeof(verbose), req);
   99: 	if (error == 0 && req->newptr != NULL) {
  100: 		s = spltty();
  101: 		if (verbose < 0 || verbose > 3)
  102: 			error = EINVAL;
  103: 		else
  104: 			sndstat_verbose = verbose;
  105: 		splx(s);
  106: 	}
  107: 	return error;
  108: }
  109: SYSCTL_PROC(_hw_snd, OID_AUTO, verbose, CTLTYPE_INT | CTLFLAG_RW,
  110:             0, sizeof(int), sysctl_hw_sndverbose, "I", "");
  111: 
  112: static int
  113: sndstat_open(dev_t i_dev, int flags, int mode, struct thread *td)
  114: {
  115: 	intrmask_t s;
  116: 	int err;
  117: 
  118: 	s = spltty();
  119: 	if (sndstat_isopen) {
  120: 		splx(s);
  121: 		return EBUSY;
  122: 	}
  123: 	if (sbuf_new(&sndstat_sbuf, NULL, 4096, 0) == NULL) {
  124: 		splx(s);
  125: 		return ENXIO;
  126: 	}
  127: 	sndstat_bufptr = 0;
  128: 	err = (sndstat_prepare(&sndstat_sbuf) > 0)? 0 : ENOMEM;
  129: 	if (!err)
  130: 		sndstat_isopen = 1;
  131: 
  132: 	splx(s);
  133: 	return err;
  134: }
  135: 
  136: static int
  137: sndstat_close(dev_t i_dev, int flags, int mode, struct thread *td)
  138: {
  139: 	intrmask_t s;
  140: 
  141: 	s = spltty();
  142: 	if (!sndstat_isopen) {
  143: 		splx(s);
  144: 		return EBADF;
  145: 	}
  146: 	sbuf_delete(&sndstat_sbuf);
  147: 	sndstat_isopen = 0;
  148: 
  149: 	splx(s);
  150: 	return 0;
  151: }
  152: 
  153: static int
  154: sndstat_read(dev_t i_dev, struct uio *buf, int flag)
  155: {
  156: 	intrmask_t s;
  157: 	int l, err;
  158: 
  159: 	s = spltty();
  160: 	if (!sndstat_isopen) {
  161: 		splx(s);
  162: 		return EBADF;
  163: 	}
  164:     	l = min(buf->uio_resid, sbuf_len(&sndstat_sbuf) - sndstat_bufptr);
  165: 	err = (l > 0)? uiomove(sbuf_data(&sndstat_sbuf) + sndstat_bufptr, l, buf) : 0;
  166: 	sndstat_bufptr += l;
  167: 
  168: 	splx(s);
  169: 	return err;
  170: }
  171: 
  172: /************************************************************************/
  173: 
  174: static struct sndstat_entry *
  175: sndstat_find(int type, int unit)
  176: {
  177: 	struct sndstat_entry *ent;
  178: 
  179: 	SLIST_FOREACH(ent, &sndstat_devlist, link) {
  180: 		if (ent->type == type && ent->unit == unit)
  181: 			return ent;
  182: 	}
  183: 
  184: 	return NULL;
  185: }
  186: 
  187: int
  188: sndstat_register(device_t dev, char *str, sndstat_handler handler)
  189: {
  190: 	intrmask_t s;
  191: 	struct sndstat_entry *ent;
  192: 	const char *devtype;
  193: 	int type, unit;
  194: 
  195: 	if (dev) {
  196: 		unit = device_get_unit(dev);
  197: 		devtype = device_get_name(dev);
  198: 		if (!strcmp(devtype, "pcm"))
  199: 			type = SS_TYPE_PCM;
  200: 		else if (!strcmp(devtype, "midi"))
  201: 			type = SS_TYPE_MIDI;
  202: 		else if (!strcmp(devtype, "sequencer"))
  203: 			type = SS_TYPE_SEQUENCER;
  204: 		else
  205: 			return EINVAL;
  206: 	} else {
  207: 		type = SS_TYPE_MODULE;
  208: 		unit = -1;
  209: 	}
  210: 
  211: 	ent = malloc(sizeof *ent, M_DEVBUF, M_ZERO | M_WAITOK);
  212: 	if (!ent)
  213: 		return ENOSPC;
  214: 
  215: 	ent->dev = dev;
  216: 	ent->str = str;
  217: 	ent->type = type;
  218: 	ent->unit = unit;
  219: 	ent->handler = handler;
  220: 
  221: 	s = spltty();
  222: 	SLIST_INSERT_HEAD(&sndstat_devlist, ent, link);
  223: 	if (type == SS_TYPE_MODULE)
  224: 		sndstat_files++;
  225: 	sndstat_maxunit = (unit > sndstat_maxunit)? unit : sndstat_maxunit;
  226: 	splx(s);
  227: 
  228: 	return 0;
  229: }
  230: 
  231: int
  232: sndstat_registerfile(char *str)
  233: {
  234: 	return sndstat_register(NULL, str, NULL);
  235: }
  236: 
  237: int
  238: sndstat_unregister(device_t dev)
  239: {
  240: 	intrmask_t s;
  241: 	struct sndstat_entry *ent;
  242: 
  243: 	s = spltty();
  244: 	SLIST_FOREACH(ent, &sndstat_devlist, link) {
  245: 		if (ent->dev == dev) {
  246: 			SLIST_REMOVE(&sndstat_devlist, ent, sndstat_entry, link);
  247: 			free(ent, M_DEVBUF);
  248: 			splx(s);
  249: 
  250: 			return 0;
  251: 		}
  252: 	}
  253: 	splx(s);
  254: 
  255: 	return ENXIO;
  256: }
  257: 
  258: int
  259: sndstat_unregisterfile(char *str)
  260: {
  261: 	intrmask_t s;
  262: 	struct sndstat_entry *ent;
  263: 
  264: 	s = spltty();
  265: 	SLIST_FOREACH(ent, &sndstat_devlist, link) {
  266: 		if (ent->dev == NULL && ent->str == str) {
  267: 			SLIST_REMOVE(&sndstat_devlist, ent, sndstat_entry, link);
  268: 			free(ent, M_DEVBUF);
  269: 			sndstat_files--;
  270: 			splx(s);
  271: 
  272: 			return 0;
  273: 		}
  274: 	}
  275: 	splx(s);
  276: 
  277: 	return ENXIO;
  278: }
  279: 
  280: /************************************************************************/
  281: 
  282: static int
  283: sndstat_prepare(struct sbuf *s)
  284: {
  285: 	struct sndstat_entry *ent;
  286:     	int i, j;
  287: 
  288: 	sbuf_printf(s, "FreeBSD Audio Driver (newpcm)\n");
  289: 	if (SLIST_EMPTY(&sndstat_devlist)) {
  290: 		sbuf_printf(s, "No devices installed.\n");
  291: 		sbuf_finish(s);
  292:     		return sbuf_len(s);
  293: 	}
  294: 
  295: 	sbuf_printf(s, "Installed devices:\n");
  296: 
  297:     	for (i = 0; i <= sndstat_maxunit; i++) {
  298: 		for (j = SS_TYPE_FIRST; j <= SS_TYPE_LAST; j++) {
  299: 			ent = sndstat_find(j, i);
  300: 			if (!ent)
  301: 				continue;
  302: 			sbuf_printf(s, "%s:", device_get_nameunit(ent->dev));
  303: 			sbuf_printf(s, " <%s>", device_get_desc(ent->dev));
  304: 			sbuf_printf(s, " %s", ent->str);
  305: 			if (ent->handler)
  306: 				ent->handler(s, ent->dev, sndstat_verbose);
  307: 			else
  308: 				sbuf_printf(s, " [no handler]");
  309: 			sbuf_printf(s, "\n");
  310: 		}
  311:     	}
  312: 
  313: 	if (sndstat_verbose >= 3 && sndstat_files > 0) {
  314: 		sbuf_printf(s, "\nFile Versions:\n");
  315: 
  316: 		SLIST_FOREACH(ent, &sndstat_devlist, link) {
  317: 			if (ent->dev == NULL && ent->str != NULL)
  318: 				sbuf_printf(s, "%s\n", ent->str);
  319: 		}
  320: 	}
  321: 
  322: 	sbuf_finish(s);
  323:     	return sbuf_len(s);
  324: }
  325: 
  326: static int
  327: sndstat_init(void)
  328: {
  329: 	sndstat_dev = make_dev(&sndstat_cdevsw, SND_DEV_STATUS, UID_ROOT, GID_WHEEL, 0444, "sndstat");
  330: 
  331: 	return (sndstat_dev != 0)? 0 : ENXIO;
  332: }
  333: 
  334: static int
  335: sndstat_uninit(void)
  336: {
  337: 	intrmask_t s;
  338: 
  339: 	s = spltty();
  340: 	if (sndstat_isopen) {
  341: 		splx(s);
  342: 		return EBUSY;
  343: 	}
  344: 
  345: 	if (sndstat_dev)
  346: 		destroy_dev(sndstat_dev);
  347: 	sndstat_dev = 0;
  348: 
  349: 	splx(s);
  350: 	return 0;
  351: }
  352: 
  353: int
  354: sndstat_busy(void)
  355: {
  356: 	return (sndstat_isopen);
  357: }
  358: 
  359: static void
  360: sndstat_sysinit(void *p)
  361: {
  362: 	sndstat_init();
  363: }
  364: 
  365: static void
  366: sndstat_sysuninit(void *p)
  367: {
  368: 	sndstat_uninit();
  369: }
  370: 
  371: SYSINIT(sndstat_sysinit, SI_SUB_DRIVERS, SI_ORDER_FIRST, sndstat_sysinit, NULL);
  372: SYSUNINIT(sndstat_sysuninit, SI_SUB_DRIVERS, SI_ORDER_FIRST, sndstat_sysuninit, NULL);
  373: 
  374: