File:  [DragonFly] / src / sys / dev / sound / pcm / dsp.c
Revision 1.7: download - view: text, annotated - select for diffs
Fri May 21 01:14:27 2004 UTC (10 years, 6 months ago) by dillon
Branches: MAIN
CVS tags: HEAD, DragonFly_Stable, DragonFly_Snap29Sep2004, DragonFly_Snap13Sep2004, DragonFly_RELEASE_1_2_Slip, DragonFly_RELEASE_1_2, DragonFly_1_0_REL, DragonFly_1_0_RC1, DragonFly_1_0A_REL
Pass the proper mask/match arguments to cdevsw_add() so the various sound
device minor numbers do not override each other's major numbers / cdevsw
structures.

Reported-by: Emiel Kollof <coolvibe@hackerheaven.org> and others

    1: /*
    2:  * Copyright (c) 1999 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/dsp.c,v 1.15.2.13 2002/08/30 13:53:03 orion Exp $
   27:  * $DragonFly: src/sys/dev/sound/pcm/dsp.c,v 1.7 2004/05/21 01:14:27 dillon Exp $
   28:  */
   29: 
   30: #include <sys/param.h>
   31: #include <sys/queue.h>
   32: 
   33: #include <dev/sound/pcm/sound.h>
   34: 
   35: SND_DECLARE_FILE("$DragonFly: src/sys/dev/sound/pcm/dsp.c,v 1.7 2004/05/21 01:14:27 dillon Exp $");
   36: 
   37: #define OLDPCM_IOCTL
   38: 
   39: static d_open_t dsp_open;
   40: static d_close_t dsp_close;
   41: static d_read_t dsp_read;
   42: static d_write_t dsp_write;
   43: static d_ioctl_t dsp_ioctl;
   44: static d_poll_t dsp_poll;
   45: static d_mmap_t dsp_mmap;
   46: 
   47: static struct cdevsw dsp_cdevsw = {
   48: 	/* name */	"dsp",
   49: 	/* maj */	SND_CDEV_MAJOR,
   50: 	/* flags */	0,
   51: 	/* port */	NULL,
   52: 	/* clone */	NULL,
   53: 
   54: 	/* open */	dsp_open,
   55: 	/* close */	dsp_close,
   56: 	/* read */	dsp_read,
   57: 	/* write */	dsp_write,
   58: 	/* ioctl */	dsp_ioctl,
   59: 	/* poll */	dsp_poll,
   60: 	/* mmap */	dsp_mmap,
   61: 	/* strategy */	nostrategy,
   62: 	/* dump */	nodump,
   63: 	/* psize */	nopsize
   64: };
   65: 
   66: #ifdef USING_DEVFS
   67: static eventhandler_tag dsp_ehtag;
   68: #endif
   69: 
   70: static struct snddev_info *
   71: dsp_get_info(dev_t dev)
   72: {
   73: 	struct snddev_info *d;
   74: 	int unit;
   75: 
   76: 	unit = PCMUNIT(dev);
   77: 	if (unit >= devclass_get_maxunit(pcm_devclass))
   78: 		return NULL;
   79: 	d = devclass_get_softc(pcm_devclass, unit);
   80: 
   81: 	return d;
   82: }
   83: 
   84: static u_int32_t
   85: dsp_get_flags(dev_t dev)
   86: {
   87: 	device_t bdev;
   88: 	int unit;
   89: 
   90: 	unit = PCMUNIT(dev);
   91: 	if (unit >= devclass_get_maxunit(pcm_devclass))
   92: 		return 0xffffffff;
   93: 	bdev = devclass_get_device(pcm_devclass, unit);
   94: 
   95: 	return pcm_getflags(bdev);
   96: }
   97: 
   98: static void
   99: dsp_set_flags(dev_t dev, u_int32_t flags)
  100: {
  101: 	device_t bdev;
  102: 	int unit;
  103: 
  104: 	unit = PCMUNIT(dev);
  105: 	if (unit >= devclass_get_maxunit(pcm_devclass))
  106: 		return;
  107: 	bdev = devclass_get_device(pcm_devclass, unit);
  108: 
  109: 	pcm_setflags(bdev, flags);
  110: }
  111: 
  112: /*
  113:  * return the channels channels associated with an open device instance.
  114:  * set the priority if the device is simplex and one direction (only) is
  115:  * specified.
  116:  * lock channels specified.
  117:  */
  118: static int
  119: getchns(dev_t dev, struct pcm_channel **rdch, struct pcm_channel **wrch, u_int32_t prio)
  120: {
  121: 	struct snddev_info *d;
  122: 	u_int32_t flags;
  123: 
  124: 	flags = dsp_get_flags(dev);
  125: 	d = dsp_get_info(dev);
  126: 	pcm_lock(d);
  127: 	pcm_inprog(d, 1);
  128: 	KASSERT((flags & SD_F_PRIO_SET) != SD_F_PRIO_SET, \
  129: 		("getchns: read and write both prioritised"));
  130: 
  131: 	if ((flags & SD_F_PRIO_SET) == 0 && (prio != (SD_F_PRIO_RD | SD_F_PRIO_WR))) {
  132: 		flags |= prio & (SD_F_PRIO_RD | SD_F_PRIO_WR);
  133: 		dsp_set_flags(dev, flags);
  134: 	}
  135: 
  136: 	*rdch = dev->si_drv1;
  137: 	*wrch = dev->si_drv2;
  138: 	if ((flags & SD_F_SIMPLEX) && (flags & SD_F_PRIO_SET)) {
  139: 		if (prio) {
  140: 			if (*rdch && flags & SD_F_PRIO_WR) {
  141: 				dev->si_drv1 = NULL;
  142: 				*rdch = pcm_getfakechan(d);
  143: 			} else if (*wrch && flags & SD_F_PRIO_RD) {
  144: 				dev->si_drv2 = NULL;
  145: 				*wrch = pcm_getfakechan(d);
  146: 			}
  147: 		}
  148: 
  149: 		pcm_getfakechan(d)->flags |= CHN_F_BUSY;
  150: 	}
  151: 	pcm_unlock(d);
  152: 
  153: 	if (*rdch && *rdch != pcm_getfakechan(d) && (prio & SD_F_PRIO_RD))
  154: 		CHN_LOCK(*rdch);
  155: 	if (*wrch && *wrch != pcm_getfakechan(d) && (prio & SD_F_PRIO_WR))
  156: 		CHN_LOCK(*wrch);
  157: 
  158: 	return 0;
  159: }
  160: 
  161: /* unlock specified channels */
  162: static void
  163: relchns(dev_t dev, struct pcm_channel *rdch, struct pcm_channel *wrch, u_int32_t prio)
  164: {
  165: 	struct snddev_info *d;
  166: 
  167: 	d = dsp_get_info(dev);
  168: 	if (wrch && wrch != pcm_getfakechan(d) && (prio & SD_F_PRIO_WR))
  169: 		CHN_UNLOCK(wrch);
  170: 	if (rdch && rdch != pcm_getfakechan(d) && (prio & SD_F_PRIO_RD))
  171: 		CHN_UNLOCK(rdch);
  172: 	pcm_lock(d);
  173: 	pcm_inprog(d, -1);
  174: 	pcm_unlock(d);
  175: }
  176: 
  177: static int
  178: dsp_open(dev_t i_dev, int flags, int mode, struct thread *td)
  179: {
  180: 	struct pcm_channel *rdch, *wrch;
  181: 	struct snddev_info *d;
  182: 	intrmask_t s;
  183: 	u_int32_t fmt;
  184: 	int devtype;
  185: 	struct proc *p = td->td_proc;
  186: 
  187: 	KKASSERT(p != NULL);
  188: 
  189: 	s = spltty();
  190: 	d = dsp_get_info(i_dev);
  191: 	devtype = PCMDEV(i_dev);
  192: 
  193: 	/* decide default format */
  194: 	switch (devtype) {
  195: 	case SND_DEV_DSP16:
  196: 		fmt = AFMT_S16_LE;
  197: 		break;
  198: 
  199: 	case SND_DEV_DSP:
  200: 		fmt = AFMT_U8;
  201: 		break;
  202: 
  203: 	case SND_DEV_AUDIO:
  204: 		fmt = AFMT_MU_LAW;
  205: 		break;
  206: 
  207: 	case SND_DEV_NORESET:
  208: 		fmt = 0;
  209: 		break;
  210: 
  211: 	case SND_DEV_DSPREC:
  212: 		fmt = AFMT_U8;
  213: 		if (mode & FWRITE) {
  214: 			splx(s);
  215: 			return EINVAL;
  216: 		}
  217: 		break;
  218: 
  219: 	default:
  220: 		panic("impossible devtype %d", devtype);
  221: 	}
  222: 
  223: 	/* lock snddev so nobody else can monkey with it */
  224: 	pcm_lock(d);
  225: 
  226: 	rdch = i_dev->si_drv1;
  227: 	wrch = i_dev->si_drv2;
  228: 
  229: 	if ((dsp_get_flags(i_dev) & SD_F_SIMPLEX) && (rdch || wrch)) {
  230: 		/* simplex device, already open, exit */
  231: 		pcm_unlock(d);
  232: 		splx(s);
  233: 		return EBUSY;
  234: 	}
  235: 
  236: 	if (((flags & FREAD) && rdch) || ((flags & FWRITE) && wrch)) {
  237: 		/* device already open in one or both directions */
  238: 		pcm_unlock(d);
  239: 		splx(s);
  240: 		return EBUSY;
  241: 	}
  242: 
  243: 	/*  if we get here, the open request is valid */
  244: 	if (flags & FREAD) {
  245: 		/* open for read */
  246: 		if (devtype == SND_DEV_DSPREC)
  247: 			rdch = pcm_chnalloc(d, PCMDIR_REC, p->p_pid, PCMCHAN(i_dev));
  248: 		else
  249: 			rdch = pcm_chnalloc(d, PCMDIR_REC, p->p_pid, -1);
  250: 		if (!rdch) {
  251: 			/* no channel available, exit */
  252: 			pcm_unlock(d);
  253: 			splx(s);
  254: 			return EBUSY;
  255: 		}
  256: 		/* got a channel, already locked for us */
  257: 	}
  258: 
  259: 	if (flags & FWRITE) {
  260: 		/* open for write */
  261: 		wrch = pcm_chnalloc(d, PCMDIR_PLAY, p->p_pid, -1);
  262: 		if (!wrch) {
  263: 			/* no channel available */
  264: 			if (rdch && (flags & FREAD)) {
  265: 				/* just opened a read channel, release it */
  266: 				pcm_chnrelease(rdch);
  267: 			}
  268: 				/* exit */
  269: 			pcm_unlock(d);
  270: 			splx(s);
  271: 			return EBUSY;
  272: 		}
  273: 		/* got a channel, already locked for us */
  274: 	}
  275: 
  276: 	i_dev->si_drv1 = rdch;
  277: 	i_dev->si_drv2 = wrch;
  278: 	pcm_unlock(d);
  279: 	/* finished with snddev, new channels still locked */
  280: 
  281: 	/* bump refcounts, reset and unlock any channels that we just opened */
  282: 	if (flags & FREAD) {
  283: 		if (chn_reset(rdch, fmt)) {
  284: 			pcm_lock(d);
  285: 			pcm_chnrelease(rdch);
  286: 			if (wrch && (flags & FWRITE))
  287: 				pcm_chnrelease(wrch);
  288: 			pcm_unlock(d);
  289: 			splx(s);
  290: 			return ENODEV;
  291: 		}
  292: 		if (flags & O_NONBLOCK)
  293: 			rdch->flags |= CHN_F_NBIO;
  294: 		pcm_chnref(rdch, 1);
  295: 	 	CHN_UNLOCK(rdch);
  296: 	}
  297: 	if (flags & FWRITE) {
  298: 		if (chn_reset(wrch, fmt)) {
  299: 			pcm_lock(d);
  300: 			pcm_chnrelease(wrch);
  301: 			if (flags & FREAD) {
  302: 				CHN_LOCK(rdch);
  303: 				pcm_chnref(rdch, -1);
  304: 				pcm_chnrelease(rdch);
  305: 				CHN_UNLOCK(rdch);
  306: 			}
  307: 			pcm_unlock(d);
  308: 			splx(s);
  309: 			return ENODEV;
  310: 		}
  311: 		if (flags & O_NONBLOCK)
  312: 			wrch->flags |= CHN_F_NBIO;
  313: 		pcm_chnref(wrch, 1);
  314: 	 	CHN_UNLOCK(wrch);
  315: 	}
  316: 	splx(s);
  317: 	return 0;
  318: }
  319: 
  320: static int
  321: dsp_close(dev_t i_dev, int flags, int mode, struct thread *td)
  322: {
  323: 	struct pcm_channel *rdch, *wrch;
  324: 	struct snddev_info *d;
  325: 	intrmask_t s;
  326: 	int exit;
  327: 
  328: 	s = spltty();
  329: 	d = dsp_get_info(i_dev);
  330: 	pcm_lock(d);
  331: 	rdch = i_dev->si_drv1;
  332: 	wrch = i_dev->si_drv2;
  333: 
  334: 	exit = 0;
  335: 
  336: 	/* decrement refcount for each channel, exit if nonzero */
  337: 	if (rdch) {
  338: 		CHN_LOCK(rdch);
  339: 		if (pcm_chnref(rdch, -1) > 0) {
  340: 			CHN_UNLOCK(rdch);
  341: 			exit = 1;
  342: 		}
  343: 	}
  344: 	if (wrch) {
  345: 		CHN_LOCK(wrch);
  346: 		if (pcm_chnref(wrch, -1) > 0) {
  347: 			CHN_UNLOCK(wrch);
  348: 			exit = 1;
  349: 		}
  350: 	}
  351: 	if (exit) {
  352: 		pcm_unlock(d);
  353: 		splx(s);
  354: 		return 0;
  355: 	}
  356: 
  357: 	/* both refcounts are zero, abort and release */
  358: 
  359: 	if (pcm_getfakechan(d))
  360: 		pcm_getfakechan(d)->flags = 0;
  361: 
  362: 	i_dev->si_drv1 = NULL;
  363: 	i_dev->si_drv2 = NULL;
  364: 
  365: 	dsp_set_flags(i_dev, dsp_get_flags(i_dev) & ~SD_F_TRANSIENT);
  366: 	pcm_unlock(d);
  367: 
  368: 	if (rdch) {
  369: 		chn_abort(rdch); /* won't sleep */
  370: 		rdch->flags &= ~(CHN_F_RUNNING | CHN_F_MAPPED | CHN_F_DEAD);
  371: 		chn_reset(rdch, 0);
  372: 		pcm_chnrelease(rdch);
  373: 	}
  374: 	if (wrch) {
  375: 		chn_flush(wrch); /* may sleep */
  376: 		wrch->flags &= ~(CHN_F_RUNNING | CHN_F_MAPPED | CHN_F_DEAD);
  377: 		chn_reset(wrch, 0);
  378: 		pcm_chnrelease(wrch);
  379: 	}
  380: 
  381: 	splx(s);
  382: 	return 0;
  383: }
  384: 
  385: static int
  386: dsp_read(dev_t i_dev, struct uio *buf, int flag)
  387: {
  388: 	struct pcm_channel *rdch, *wrch;
  389: 	intrmask_t s;
  390: 	int ret;
  391: 
  392: 	s = spltty();
  393: 	getchns(i_dev, &rdch, &wrch, SD_F_PRIO_RD);
  394: 
  395: 	KASSERT(rdch, ("dsp_read: nonexistant channel"));
  396: 	KASSERT(rdch->flags & CHN_F_BUSY, ("dsp_read: nonbusy channel"));
  397: 
  398: 	if (rdch->flags & (CHN_F_MAPPED | CHN_F_DEAD)) {
  399: 		relchns(i_dev, rdch, wrch, SD_F_PRIO_RD);
  400: 		splx(s);
  401: 		return EINVAL;
  402: 	}
  403: 	if (!(rdch->flags & CHN_F_RUNNING))
  404: 		rdch->flags |= CHN_F_RUNNING;
  405: 	ret = chn_read(rdch, buf);
  406: 	relchns(i_dev, rdch, wrch, SD_F_PRIO_RD);
  407: 
  408: 	splx(s);
  409: 	return ret;
  410: }
  411: 
  412: static int
  413: dsp_write(dev_t i_dev, struct uio *buf, int flag)
  414: {
  415: 	struct pcm_channel *rdch, *wrch;
  416: 	intrmask_t s;
  417: 	int ret;
  418: 
  419: 	s = spltty();
  420: 	getchns(i_dev, &rdch, &wrch, SD_F_PRIO_WR);
  421: 
  422: 	KASSERT(wrch, ("dsp_write: nonexistant channel"));
  423: 	KASSERT(wrch->flags & CHN_F_BUSY, ("dsp_write: nonbusy channel"));
  424: 
  425: 	if (wrch->flags & (CHN_F_MAPPED | CHN_F_DEAD)) {
  426: 		relchns(i_dev, rdch, wrch, SD_F_PRIO_WR);
  427: 		splx(s);
  428: 		return EINVAL;
  429: 	}
  430: 	if (!(wrch->flags & CHN_F_RUNNING))
  431: 		wrch->flags |= CHN_F_RUNNING;
  432: 	ret = chn_write(wrch, buf);
  433: 	relchns(i_dev, rdch, wrch, SD_F_PRIO_WR);
  434: 
  435: 	splx(s);
  436: 	return ret;
  437: }
  438: 
  439: static int
  440: dsp_ioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct thread *td)
  441: {
  442:     	struct pcm_channel *wrch, *rdch;
  443: 	struct snddev_info *d;
  444: 	intrmask_t s;
  445: 	int kill;
  446:     	int ret = 0, *arg_i = (int *)arg, tmp;
  447: 
  448: 	/*
  449: 	 * this is an evil hack to allow broken apps to perform mixer ioctls
  450: 	 * on dsp devices.
  451: 	 */
  452: 
  453: 	if (IOCGROUP(cmd) == 'M') {
  454: 		dev_t pdev;
  455: 
  456: 		pdev = make_adhoc_dev(&dsp_cdevsw, 
  457: 				PCMMKMINOR(PCMUNIT(i_dev), SND_DEV_CTL, 0));
  458: 		return mixer_ioctl(pdev, cmd, arg, mode, td);
  459: 	}
  460: 
  461:     	s = spltty();
  462: 	d = dsp_get_info(i_dev);
  463: 	getchns(i_dev, &rdch, &wrch, 0);
  464: 
  465: 	kill = 0;
  466: 	if (wrch && (wrch->flags & CHN_F_DEAD))
  467: 		kill |= 1;
  468: 	if (rdch && (rdch->flags & CHN_F_DEAD))
  469: 		kill |= 2;
  470: 	if (kill == 3) {
  471: 		relchns(i_dev, rdch, wrch, 0);
  472: 		splx(s);
  473: 		return EINVAL;
  474: 	}
  475: 	if (kill & 1)
  476: 		wrch = NULL;
  477: 	if (kill & 2)
  478: 		rdch = NULL;
  479: 
  480:     	switch(cmd) {
  481: #ifdef OLDPCM_IOCTL
  482:     	/*
  483:      	 * we start with the new ioctl interface.
  484:      	 */
  485:     	case AIONWRITE:	/* how many bytes can write ? */
  486: /*
  487: 		if (wrch && wrch->bufhard.dl)
  488: 			while (chn_wrfeed(wrch) == 0);
  489: */
  490: 		*arg_i = wrch? sndbuf_getfree(wrch->bufsoft) : 0;
  491: 		break;
  492: 
  493:     	case AIOSSIZE:     /* set the current blocksize */
  494: 		{
  495: 	    		struct snd_size *p = (struct snd_size *)arg;
  496: 
  497: 			p->play_size = 0;
  498: 			p->rec_size = 0;
  499: 	    		if (wrch) {
  500: 				CHN_LOCK(wrch);
  501: 				chn_setblocksize(wrch, 2, p->play_size);
  502: 				p->play_size = sndbuf_getblksz(wrch->bufsoft);
  503: 				CHN_UNLOCK(wrch);
  504: 			}
  505: 	    		if (rdch) {
  506: 				CHN_LOCK(rdch);
  507: 				chn_setblocksize(rdch, 2, p->rec_size);
  508: 				p->rec_size = sndbuf_getblksz(rdch->bufsoft);
  509: 				CHN_UNLOCK(rdch);
  510: 			}
  511: 		}
  512: 		break;
  513:     	case AIOGSIZE:	/* get the current blocksize */
  514: 		{
  515: 	    		struct snd_size *p = (struct snd_size *)arg;
  516: 
  517: 	    		if (wrch)
  518: 				p->play_size = sndbuf_getblksz(wrch->bufsoft);
  519: 	    		if (rdch)
  520: 				p->rec_size = sndbuf_getblksz(rdch->bufsoft);
  521: 		}
  522: 		break;
  523: 
  524:     	case AIOSFMT:
  525: 		{
  526: 	    		snd_chan_param *p = (snd_chan_param *)arg;
  527: 
  528: 	    		if (wrch) {
  529: 				CHN_LOCK(wrch);
  530: 				chn_setformat(wrch, p->play_format);
  531: 				chn_setspeed(wrch, p->play_rate);
  532: 				CHN_UNLOCK(wrch);
  533: 	    		}
  534: 	    		if (rdch) {
  535: 				CHN_LOCK(rdch);
  536: 				chn_setformat(rdch, p->rec_format);
  537: 				chn_setspeed(rdch, p->rec_rate);
  538: 				CHN_UNLOCK(rdch);
  539: 	    		}
  540: 		}
  541: 		/* FALLTHROUGH */
  542: 
  543:     	case AIOGFMT:
  544: 		{
  545: 	    		snd_chan_param *p = (snd_chan_param *)arg;
  546: 
  547: 	    		p->play_rate = wrch? wrch->speed : 0;
  548: 	    		p->rec_rate = rdch? rdch->speed : 0;
  549: 	    		p->play_format = wrch? wrch->format : 0;
  550: 	    		p->rec_format = rdch? rdch->format : 0;
  551: 		}
  552: 		break;
  553: 
  554:     	case AIOGCAP:     /* get capabilities */
  555: 		{
  556: 	    		snd_capabilities *p = (snd_capabilities *)arg;
  557: 			struct pcmchan_caps *pcaps = NULL, *rcaps = NULL;
  558: 			dev_t pdev;
  559: 
  560: 			if (rdch) {
  561: 				CHN_LOCK(rdch);
  562: 				rcaps = chn_getcaps(rdch);
  563: 			}
  564: 			if (wrch) {
  565: 				CHN_LOCK(wrch);
  566: 				pcaps = chn_getcaps(wrch);
  567: 			}
  568: 	    		p->rate_min = max(rcaps? rcaps->minspeed : 0,
  569: 	                      		  pcaps? pcaps->minspeed : 0);
  570: 	    		p->rate_max = min(rcaps? rcaps->maxspeed : 1000000,
  571: 	                      		  pcaps? pcaps->maxspeed : 1000000);
  572: 	    		p->bufsize = min(rdch? sndbuf_getsize(rdch->bufsoft) : 1000000,
  573: 	                     		 wrch? sndbuf_getsize(wrch->bufsoft) : 1000000);
  574: 			/* XXX bad on sb16 */
  575: 	    		p->formats = (rdch? chn_getformats(rdch) : 0xffffffff) &
  576: 			 	     (wrch? chn_getformats(wrch) : 0xffffffff);
  577: 			if (rdch && wrch)
  578: 				p->formats |= (dsp_get_flags(i_dev) & SD_F_SIMPLEX)? 0 : AFMT_FULLDUPLEX;
  579: 			pdev = make_adhoc_dev(&dsp_cdevsw, PCMMKMINOR(PCMUNIT(i_dev), SND_DEV_CTL, 0));
  580: 	    		p->mixers = 1; /* default: one mixer */
  581: 	    		p->inputs = pdev->si_drv1? mix_getdevs(pdev->si_drv1) : 0;
  582: 	    		p->left = p->right = 100;
  583: 			if (wrch)
  584: 				CHN_UNLOCK(wrch);
  585: 			if (rdch)
  586: 				CHN_UNLOCK(rdch);
  587: 		}
  588: 		break;
  589: 
  590:     	case AIOSTOP:
  591: 		if (*arg_i == AIOSYNC_PLAY && wrch)
  592: 			*arg_i = chn_abort(wrch);
  593: 		else if (*arg_i == AIOSYNC_CAPTURE && rdch)
  594: 			*arg_i = chn_abort(rdch);
  595: 		else {
  596: 	   	 	printf("AIOSTOP: bad channel 0x%x\n", *arg_i);
  597: 	    		*arg_i = 0;
  598: 		}
  599: 		break;
  600: 
  601:     	case AIOSYNC:
  602: 		printf("AIOSYNC chan 0x%03lx pos %lu unimplemented\n",
  603: 	    		((snd_sync_parm *)arg)->chan, ((snd_sync_parm *)arg)->pos);
  604: 		break;
  605: #endif
  606: 	/*
  607: 	 * here follow the standard ioctls (filio.h etc.)
  608: 	 */
  609:     	case FIONREAD: /* get # bytes to read */
  610: /*		if (rdch && rdch->bufhard.dl)
  611: 			while (chn_rdfeed(rdch) == 0);
  612: */		*arg_i = rdch? sndbuf_getready(rdch->bufsoft) : 0;
  613: 		break;
  614: 
  615:     	case FIOASYNC: /*set/clear async i/o */
  616: 		DEB( printf("FIOASYNC\n") ; )
  617: 		break;
  618: 
  619:     	case SNDCTL_DSP_NONBLOCK:
  620:     	case FIONBIO: /* set/clear non-blocking i/o */
  621: 		if (rdch)
  622: 			rdch->flags &= ~CHN_F_NBIO;
  623: 		if (wrch)
  624: 			wrch->flags &= ~CHN_F_NBIO;
  625: 		if (*arg_i) {
  626: 		    	if (rdch)
  627: 				rdch->flags |= CHN_F_NBIO;
  628: 		    	if (wrch)
  629: 				wrch->flags |= CHN_F_NBIO;
  630: 		}
  631: 		break;
  632: 
  633:     	/*
  634: 	 * Finally, here is the linux-compatible ioctl interface
  635: 	 */
  636: #define THE_REAL_SNDCTL_DSP_GETBLKSIZE _IOWR('P', 4, int)
  637:     	case THE_REAL_SNDCTL_DSP_GETBLKSIZE:
  638:     	case SNDCTL_DSP_GETBLKSIZE:
  639: 		if (wrch)
  640: 			*arg_i = sndbuf_getblksz(wrch->bufsoft);
  641: 		else if (rdch)
  642: 			*arg_i = sndbuf_getblksz(rdch->bufsoft);
  643: 		else
  644: 			*arg_i = 0;
  645: 		break ;
  646: 
  647:     	case SNDCTL_DSP_SETBLKSIZE:
  648: 		RANGE(*arg_i, 16, 65536);
  649: 		if (wrch) {
  650: 			CHN_LOCK(wrch);
  651: 			chn_setblocksize(wrch, 2, *arg_i);
  652: 			CHN_UNLOCK(wrch);
  653: 		}
  654: 		if (rdch) {
  655: 			CHN_LOCK(rdch);
  656: 			chn_setblocksize(rdch, 2, *arg_i);
  657: 			CHN_UNLOCK(rdch);
  658: 		}
  659: 		break;
  660: 
  661:     	case SNDCTL_DSP_RESET:
  662: 		DEB(printf("dsp reset\n"));
  663: 		if (wrch)
  664: 			chn_abort(wrch);
  665: 		if (rdch)
  666: 			chn_abort(rdch);
  667: 		break;
  668: 
  669:     	case SNDCTL_DSP_SYNC:
  670: 		DEB(printf("dsp sync\n"));
  671: 		/* chn_sync may sleep */
  672: 		if (wrch) {
  673: 			CHN_LOCK(wrch);
  674: 			chn_sync(wrch, sndbuf_getsize(wrch->bufsoft) - 4);
  675: 			CHN_UNLOCK(wrch);
  676: 		}
  677: 		break;
  678: 
  679:     	case SNDCTL_DSP_SPEED:
  680: 		/* chn_setspeed may sleep */
  681: 		tmp = 0;
  682: 		if (wrch) {
  683: 			CHN_LOCK(wrch);
  684: 			ret = chn_setspeed(wrch, *arg_i);
  685: 			tmp = wrch->speed;
  686: 			CHN_UNLOCK(wrch);
  687: 		}
  688: 		if (rdch && ret == 0) {
  689: 			CHN_LOCK(rdch);
  690: 			ret = chn_setspeed(rdch, *arg_i);
  691: 			if (tmp == 0)
  692: 				tmp = rdch->speed;
  693: 			CHN_UNLOCK(rdch);
  694: 		}
  695: 		*arg_i = tmp;
  696: 		break;
  697: 
  698:     	case SOUND_PCM_READ_RATE:
  699: 		*arg_i = wrch? wrch->speed : rdch->speed;
  700: 		break;
  701: 
  702:     	case SNDCTL_DSP_STEREO:
  703: 		tmp = -1;
  704: 		*arg_i = (*arg_i)? AFMT_STEREO : 0;
  705: 		if (wrch) {
  706: 			CHN_LOCK(wrch);
  707: 			ret = chn_setformat(wrch, (wrch->format & ~AFMT_STEREO) | *arg_i);
  708: 			tmp = (wrch->format & AFMT_STEREO)? 1 : 0;
  709: 			CHN_UNLOCK(wrch);
  710: 		}
  711: 		if (rdch && ret == 0) {
  712: 			CHN_LOCK(rdch);
  713: 			ret = chn_setformat(rdch, (rdch->format & ~AFMT_STEREO) | *arg_i);
  714: 			if (tmp == -1)
  715: 				tmp = (rdch->format & AFMT_STEREO)? 1 : 0;
  716: 			CHN_UNLOCK(rdch);
  717: 		}
  718: 		*arg_i = tmp;
  719: 		break;
  720: 
  721:     	case SOUND_PCM_WRITE_CHANNELS:
  722: /*	case SNDCTL_DSP_CHANNELS: ( == SOUND_PCM_WRITE_CHANNELS) */
  723: 		if (*arg_i != 0) {
  724: 			tmp = 0;
  725: 			*arg_i = (*arg_i != 1)? AFMT_STEREO : 0;
  726: 	  		if (wrch) {
  727: 				CHN_LOCK(wrch);
  728: 				ret = chn_setformat(wrch, (wrch->format & ~AFMT_STEREO) | *arg_i);
  729: 				tmp = (wrch->format & AFMT_STEREO)? 2 : 1;
  730: 				CHN_UNLOCK(wrch);
  731: 			}
  732: 			if (rdch && ret == 0) {
  733: 				CHN_LOCK(rdch);
  734: 				ret = chn_setformat(rdch, (rdch->format & ~AFMT_STEREO) | *arg_i);
  735: 				if (tmp == 0)
  736: 					tmp = (rdch->format & AFMT_STEREO)? 2 : 1;
  737: 				CHN_UNLOCK(rdch);
  738: 			}
  739: 			*arg_i = tmp;
  740: 		} else {
  741: 			*arg_i = ((wrch? wrch->format : rdch->format) & AFMT_STEREO)? 2 : 1;
  742: 		}
  743: 		break;
  744: 
  745:     	case SOUND_PCM_READ_CHANNELS:
  746: 		*arg_i = ((wrch? wrch->format : rdch->format) & AFMT_STEREO)? 2 : 1;
  747: 		break;
  748: 
  749:     	case SNDCTL_DSP_GETFMTS:	/* returns a mask of supported fmts */
  750: 		*arg_i = wrch? chn_getformats(wrch) : chn_getformats(rdch);
  751: 		break ;
  752: 
  753:     	case SNDCTL_DSP_SETFMT:	/* sets _one_ format */
  754: 		/* XXX locking */
  755: 		if ((*arg_i != AFMT_QUERY)) {
  756: 			tmp = 0;
  757: 			if (wrch) {
  758: 				CHN_LOCK(wrch);
  759: 				ret = chn_setformat(wrch, (*arg_i) | (wrch->format & AFMT_STEREO));
  760: 				tmp = wrch->format & ~AFMT_STEREO;
  761: 				CHN_UNLOCK(wrch);
  762: 			}
  763: 			if (rdch && ret == 0) {
  764: 				CHN_LOCK(rdch);
  765: 				ret = chn_setformat(rdch, (*arg_i) | (rdch->format & AFMT_STEREO));
  766: 				if (tmp == 0)
  767: 					tmp = rdch->format & ~AFMT_STEREO;
  768: 				CHN_UNLOCK(rdch);
  769: 			}
  770: 			*arg_i = tmp;
  771: 		} else
  772: 			*arg_i = (wrch? wrch->format : rdch->format) & ~AFMT_STEREO;
  773: 		break;
  774: 
  775:     	case SNDCTL_DSP_SETFRAGMENT:
  776: 		/* XXX locking */
  777: 		DEB(printf("SNDCTL_DSP_SETFRAGMENT 0x%08x\n", *(int *)arg));
  778: 		{
  779: 			u_int32_t fragln = (*arg_i) & 0x0000ffff;
  780: 			u_int32_t maxfrags = ((*arg_i) & 0xffff0000) >> 16;
  781: 			u_int32_t fragsz;
  782: 
  783: 			RANGE(fragln, 4, 16);
  784: 			fragsz = 1 << fragln;
  785: 
  786: 			if (maxfrags == 0)
  787: 				maxfrags = CHN_2NDBUFMAXSIZE / fragsz;
  788: 			if (maxfrags < 2) {
  789: 				ret = EINVAL;
  790: 				break;
  791: 			}
  792: 			if (maxfrags * fragsz > CHN_2NDBUFMAXSIZE)
  793: 				maxfrags = CHN_2NDBUFMAXSIZE / fragsz;
  794: 
  795: 			DEB(printf("SNDCTL_DSP_SETFRAGMENT %d frags, %d sz\n", maxfrags, fragsz));
  796: 		    	if (rdch) {
  797: 				CHN_LOCK(rdch);
  798: 				ret = chn_setblocksize(rdch, maxfrags, fragsz);
  799: 				maxfrags = sndbuf_getblkcnt(rdch->bufsoft);
  800: 				fragsz = sndbuf_getblksz(rdch->bufsoft);
  801: 				CHN_UNLOCK(rdch);
  802: 			}
  803: 		    	if (wrch && ret == 0) {
  804: 				CHN_LOCK(wrch);
  805: 				ret = chn_setblocksize(wrch, maxfrags, fragsz);
  806:  				maxfrags = sndbuf_getblkcnt(wrch->bufsoft);
  807: 				fragsz = sndbuf_getblksz(wrch->bufsoft);
  808: 				CHN_UNLOCK(wrch);
  809: 			}
  810: 
  811: 			fragln = 0;
  812: 			while (fragsz > 1) {
  813: 				fragln++;
  814: 				fragsz >>= 1;
  815: 			}
  816: 	    		*arg_i = (maxfrags << 16) | fragln;
  817: 		}
  818: 		break;
  819: 
  820:     	case SNDCTL_DSP_GETISPACE:
  821: 		/* return the size of data available in the input queue */
  822: 		{
  823: 	    		audio_buf_info *a = (audio_buf_info *)arg;
  824: 	    		if (rdch) {
  825: 	        		struct snd_dbuf *bs = rdch->bufsoft;
  826: 
  827: 				CHN_LOCK(rdch);
  828: 				a->bytes = sndbuf_getready(bs);
  829: 	        		a->fragments = a->bytes / sndbuf_getblksz(bs);
  830: 	        		a->fragstotal = sndbuf_getblkcnt(bs);
  831: 	        		a->fragsize = sndbuf_getblksz(bs);
  832: 				CHN_UNLOCK(rdch);
  833: 	    		}
  834: 		}
  835: 		break;
  836: 
  837:     	case SNDCTL_DSP_GETOSPACE:
  838: 		/* return space available in the output queue */
  839: 		{
  840: 	    		audio_buf_info *a = (audio_buf_info *)arg;
  841: 	    		if (wrch) {
  842: 	        		struct snd_dbuf *bs = wrch->bufsoft;
  843: 
  844: 				CHN_LOCK(wrch);
  845: 				chn_wrupdate(wrch);
  846: 				a->bytes = sndbuf_getfree(bs);
  847: 	        		a->fragments = a->bytes / sndbuf_getblksz(bs);
  848: 	        		a->fragstotal = sndbuf_getblkcnt(bs);
  849: 	        		a->fragsize = sndbuf_getblksz(bs);
  850: 				CHN_UNLOCK(wrch);
  851: 	    		}
  852: 		}
  853: 		break;
  854: 
  855:     	case SNDCTL_DSP_GETIPTR:
  856: 		{
  857: 	    		count_info *a = (count_info *)arg;
  858: 	    		if (rdch) {
  859: 	        		struct snd_dbuf *bs = rdch->bufsoft;
  860: 
  861: 				CHN_LOCK(rdch);
  862: 				chn_rdupdate(rdch);
  863: 	        		a->bytes = sndbuf_gettotal(bs);
  864: 	        		a->blocks = sndbuf_getblocks(bs) - rdch->blocks;
  865: 	        		a->ptr = sndbuf_getreadyptr(bs);
  866: 				rdch->blocks = sndbuf_getblocks(bs);
  867: 				CHN_UNLOCK(rdch);
  868: 	    		} else
  869: 				ret = EINVAL;
  870: 		}
  871: 		break;
  872: 
  873:     	case SNDCTL_DSP_GETOPTR:
  874: 		{
  875: 	    		count_info *a = (count_info *)arg;
  876: 	    		if (wrch) {
  877: 	        		struct snd_dbuf *bs = wrch->bufsoft;
  878: 
  879: 				CHN_LOCK(wrch);
  880: 				chn_wrupdate(wrch);
  881: 	        		a->bytes = sndbuf_gettotal(bs);
  882: 	        		a->blocks = sndbuf_getblocks(bs) - wrch->blocks;
  883: 	        		a->ptr = sndbuf_getreadyptr(bs);
  884: 				wrch->blocks = sndbuf_getblocks(bs);
  885: 				CHN_UNLOCK(wrch);
  886: 	    		} else
  887: 				ret = EINVAL;
  888: 		}
  889: 		break;
  890: 
  891:     	case SNDCTL_DSP_GETCAPS:
  892: 		*arg_i = DSP_CAP_REALTIME | DSP_CAP_MMAP | DSP_CAP_TRIGGER;
  893: 		if (rdch && wrch && !(dsp_get_flags(i_dev) & SD_F_SIMPLEX))
  894: 			*arg_i |= DSP_CAP_DUPLEX;
  895: 		break;
  896: 
  897:     	case SOUND_PCM_READ_BITS:
  898:         	*arg_i = ((wrch? wrch->format : rdch->format) & AFMT_16BIT)? 16 : 8;
  899: 		break;
  900: 
  901:     	case SNDCTL_DSP_SETTRIGGER:
  902: 		if (rdch) {
  903: 			CHN_LOCK(rdch);
  904: 			rdch->flags &= ~(CHN_F_TRIGGERED | CHN_F_NOTRIGGER);
  905: 		    	if (*arg_i & PCM_ENABLE_INPUT)
  906: 				chn_start(rdch, 1);
  907: 			else
  908: 				rdch->flags |= CHN_F_NOTRIGGER;
  909: 			CHN_UNLOCK(rdch);
  910: 		}
  911: 		if (wrch) {
  912: 			CHN_LOCK(wrch);
  913: 			wrch->flags &= ~(CHN_F_TRIGGERED | CHN_F_NOTRIGGER);
  914: 		    	if (*arg_i & PCM_ENABLE_OUTPUT)
  915: 				chn_start(wrch, 1);
  916: 			else
  917: 				wrch->flags |= CHN_F_NOTRIGGER;
  918: 		 	CHN_UNLOCK(wrch);
  919: 		}
  920: 		break;
  921: 
  922:     	case SNDCTL_DSP_GETTRIGGER:
  923: 		*arg_i = 0;
  924: 		if (wrch && wrch->flags & CHN_F_TRIGGERED)
  925: 			*arg_i |= PCM_ENABLE_OUTPUT;
  926: 		if (rdch && rdch->flags & CHN_F_TRIGGERED)
  927: 			*arg_i |= PCM_ENABLE_INPUT;
  928: 		break;
  929: 
  930: 	case SNDCTL_DSP_GETODELAY:
  931: 		if (wrch) {
  932: 			struct snd_dbuf *b = wrch->bufhard;
  933: 	        	struct snd_dbuf *bs = wrch->bufsoft;
  934: 
  935: 			CHN_LOCK(wrch);
  936: 			chn_wrupdate(wrch);
  937: 			*arg_i = sndbuf_getready(b) + sndbuf_getready(bs);
  938: 			CHN_UNLOCK(wrch);
  939: 		} else
  940: 			ret = EINVAL;
  941: 		break;
  942: 
  943:     	case SNDCTL_DSP_POST:
  944: 		if (wrch) {
  945: 			CHN_LOCK(wrch);
  946: 			wrch->flags &= ~CHN_F_NOTRIGGER;
  947: 			chn_start(wrch, 1);
  948: 			CHN_UNLOCK(wrch);
  949: 		}
  950: 		break;
  951: 
  952:     	case SNDCTL_DSP_MAPINBUF:
  953:     	case SNDCTL_DSP_MAPOUTBUF:
  954:     	case SNDCTL_DSP_SETSYNCRO:
  955: 		/* undocumented */
  956: 
  957:     	case SNDCTL_DSP_SUBDIVIDE:
  958:     	case SOUND_PCM_WRITE_FILTER:
  959:     	case SOUND_PCM_READ_FILTER:
  960: 		/* dunno what these do, don't sound important */
  961:     	default:
  962: 		DEB(printf("default ioctl fn 0x%08lx fail\n", cmd));
  963: 		ret = EINVAL;
  964: 		break;
  965:     	}
  966: 	relchns(i_dev, rdch, wrch, 0);
  967: 	splx(s);
  968:     	return ret;
  969: }
  970: 
  971: static int
  972: dsp_poll(dev_t i_dev, int events, struct thread *td)
  973: {
  974: 	struct pcm_channel *wrch = NULL, *rdch = NULL;
  975: 	intrmask_t s;
  976: 	int ret, e;
  977: 
  978: 	s = spltty();
  979: 	ret = 0;
  980: 	getchns(i_dev, &rdch, &wrch, SD_F_PRIO_RD | SD_F_PRIO_WR);
  981: 
  982: 	if (wrch) {
  983: 		e = (events & (POLLOUT | POLLWRNORM));
  984: 		if (e)
  985: 			ret |= chn_poll(wrch, e, td->td_proc);
  986: 	}
  987: 	if (rdch) {
  988: 		e = (events & (POLLIN | POLLRDNORM));
  989: 		if (e)
  990: 			ret |= chn_poll(rdch, e, td->td_proc);
  991: 	}
  992: 	relchns(i_dev, rdch, wrch, SD_F_PRIO_RD | SD_F_PRIO_WR);
  993: 
  994: 	splx(s);
  995: 	return ret;
  996: }
  997: 
  998: static int
  999: dsp_mmap(dev_t i_dev, vm_offset_t offset, int nprot)
 1000: {
 1001: 	struct pcm_channel *wrch = NULL, *rdch = NULL, *c;
 1002: 	intrmask_t s;
 1003: 	int ret;
 1004: 
 1005: 	if (nprot & PROT_EXEC)
 1006: 		return -1;
 1007: 
 1008: 	s = spltty();
 1009: 	getchns(i_dev, &rdch, &wrch, SD_F_PRIO_RD | SD_F_PRIO_WR);
 1010: #if 0
 1011: 	/*
 1012: 	 * XXX the linux api uses the nprot to select read/write buffer
 1013: 	 * our vm system doesn't allow this, so force write buffer
 1014: 	 */
 1015: 
 1016: 	if (wrch && (nprot & PROT_WRITE)) {
 1017: 		c = wrch;
 1018: 	} else if (rdch && (nprot & PROT_READ)) {
 1019: 		c = rdch;
 1020: 	} else {
 1021: 		splx(s);
 1022: 		return -1;
 1023: 	}
 1024: #else
 1025: 	c = wrch;
 1026: #endif
 1027: 
 1028: 	if (c == NULL) {
 1029: 		relchns(i_dev, rdch, wrch, SD_F_PRIO_RD | SD_F_PRIO_WR);
 1030: 		splx(s);
 1031: 		return -1;
 1032: 	}
 1033: 
 1034: 	if (offset >= sndbuf_getsize(c->bufsoft)) {
 1035: 		relchns(i_dev, rdch, wrch, SD_F_PRIO_RD | SD_F_PRIO_WR);
 1036: 		splx(s);
 1037: 		return -1;
 1038: 	}
 1039: 
 1040: 	if (!(c->flags & CHN_F_MAPPED))
 1041: 		c->flags |= CHN_F_MAPPED;
 1042: 
 1043: 	ret = atop(vtophys(sndbuf_getbufofs(c->bufsoft, offset)));
 1044: 	relchns(i_dev, rdch, wrch, SD_F_PRIO_RD | SD_F_PRIO_WR);
 1045: 
 1046: 	splx(s);
 1047: 	return ret;
 1048: }
 1049: 
 1050: int
 1051: dsp_register(int unit, int channel)
 1052: {
 1053: 	cdevsw_add(&dsp_cdevsw, 
 1054: 		PCMMKMINOR(-1, -1, 0), PCMMKMINOR(unit, SND_DEV_DSP, 0));
 1055: 	cdevsw_add(&dsp_cdevsw, 
 1056: 		PCMMKMINOR(-1, -1, 0), PCMMKMINOR(unit, SND_DEV_DSP16, 0));
 1057: 	cdevsw_add(&dsp_cdevsw, 
 1058: 		PCMMKMINOR(-1, -1, 0), PCMMKMINOR(unit, SND_DEV_AUDIO, 0));
 1059: 	cdevsw_add(&dsp_cdevsw, 
 1060: 		PCMMKMINOR(-1, -1, 0), PCMMKMINOR(unit, SND_DEV_NORESET, 0));
 1061: 	make_dev(&dsp_cdevsw, PCMMKMINOR(unit, SND_DEV_DSP, channel),
 1062: 		 UID_ROOT, GID_WHEEL, 0666, "dsp%d.%d", unit, channel);
 1063: 	make_dev(&dsp_cdevsw, PCMMKMINOR(unit, SND_DEV_DSP16, channel),
 1064: 		 UID_ROOT, GID_WHEEL, 0666, "dspW%d.%d", unit, channel);
 1065: 	make_dev(&dsp_cdevsw, PCMMKMINOR(unit, SND_DEV_AUDIO, channel),
 1066: 		 UID_ROOT, GID_WHEEL, 0666, "audio%d.%d", unit, channel);
 1067: 
 1068: 	return 0;
 1069: }
 1070: 
 1071: int
 1072: dsp_registerrec(int unit, int channel)
 1073: {
 1074: 	cdevsw_add(&dsp_cdevsw, 
 1075: 		PCMMKMINOR(-1, -1, 0), PCMMKMINOR(unit, SND_DEV_DSPREC, 0));
 1076: 	make_dev(&dsp_cdevsw, PCMMKMINOR(unit, SND_DEV_DSPREC, channel),
 1077: 		 UID_ROOT, GID_WHEEL, 0666, "dspr%d.%d", unit, channel);
 1078: 
 1079: 	return 0;
 1080: }
 1081: 
 1082: int
 1083: dsp_unregister(int unit, int channel)
 1084: {
 1085: 	cdevsw_remove(&dsp_cdevsw, 
 1086: 		PCMMKMINOR(-1, -1, 0), PCMMKMINOR(unit, SND_DEV_DSP, 0));
 1087: 	cdevsw_remove(&dsp_cdevsw, 
 1088: 		PCMMKMINOR(-1, -1, 0), PCMMKMINOR(unit, SND_DEV_DSP16, 0));
 1089: 	cdevsw_remove(&dsp_cdevsw, 
 1090: 		PCMMKMINOR(-1, -1, 0), PCMMKMINOR(unit, SND_DEV_AUDIO, 0));
 1091: 	cdevsw_remove(&dsp_cdevsw, 
 1092: 		PCMMKMINOR(-1, -1, 0), PCMMKMINOR(unit, SND_DEV_NORESET, 0));
 1093: 	return 0;
 1094: }
 1095: 
 1096: int
 1097: dsp_unregisterrec(int unit, int channel)
 1098: {
 1099: 	cdevsw_remove(&dsp_cdevsw, 
 1100: 		PCMMKMINOR(-1, -1, 0), PCMMKMINOR(unit, SND_DEV_DSPREC, 0));
 1101: 	return 0;
 1102: }
 1103: 
 1104: #ifdef USING_DEVFS
 1105: static void
 1106: dsp_clone(void *arg, char *name, int namelen, dev_t *dev)
 1107: {
 1108: 	dev_t pdev;
 1109: 	int i, cont, unit, devtype;
 1110: 	int devtypes[3] = {SND_DEV_DSP, SND_DEV_DSP16, SND_DEV_AUDIO};
 1111: 	char *devnames[3] = {"dsp", "dspW", "audio"};
 1112: 
 1113: 	if (*dev != NODEV)
 1114: 		return;
 1115: 	if (pcm_devclass == NULL)
 1116: 		return;
 1117: 
 1118: 	devtype = 0;
 1119: 	unit = -1;
 1120: 	for (i = 0; (i < 3) && (unit == -1); i++) {
 1121: 		devtype = devtypes[i];
 1122: 		if (strcmp(name, devnames[i]) == 0) {
 1123: 			unit = snd_unit;
 1124: 		} else {
 1125: 			if (dev_stdclone(name, NULL, devnames[i], &unit) != 1)
 1126: 				unit = -1;
 1127: 		}
 1128: 	}
 1129: 	if (unit == -1 || unit >= devclass_get_maxunit(pcm_devclass))
 1130: 		return;
 1131: 
 1132: 	cont = 1;
 1133: 	for (i = 0; cont; i++) {
 1134: 		pdev = make_adhoc_dev(&dsp_cdevsw, PCMMKMINOR(unit, devtype, i));
 1135: 		if (pdev->si_flags & SI_NAMED) {
 1136: 			if ((pdev->si_drv1 == NULL) && (pdev->si_drv2 == NULL)) {
 1137: 				*dev = pdev;
 1138: 				return;
 1139: 			}
 1140: 		} else {
 1141: 			cont = 0;
 1142: 		}
 1143: 	}
 1144: }
 1145: 
 1146: static void
 1147: dsp_sysinit(void *p)
 1148: {
 1149: 	dsp_ehtag = EVENTHANDLER_REGISTER(dev_clone, dsp_clone, 0, 1000);
 1150: }
 1151: 
 1152: static void
 1153: dsp_sysuninit(void *p)
 1154: {
 1155: 	if (dsp_ehtag != NULL)
 1156: 		EVENTHANDLER_DEREGISTER(dev_clone, dsp_ehtag);
 1157: }
 1158: 
 1159: SYSINIT(dsp_sysinit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, dsp_sysinit, NULL);
 1160: SYSUNINIT(dsp_sysuninit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, dsp_sysuninit, NULL);
 1161: #endif
 1162: 
 1163: