sound.c revision 61144
150724Scg/*
250724Scg * Copyright (c) 1999 Cameron Grant <gandalf@vilnya.demon.co.uk>
350724Scg * (C) 1997 Luigi Rizzo (luigi@iet.unipi.it)
450724Scg * All rights reserved.
550724Scg *
650724Scg * Redistribution and use in source and binary forms, with or without
750724Scg * modification, are permitted provided that the following conditions
850724Scg * are met:
950724Scg * 1. Redistributions of source code must retain the above copyright
1050724Scg *    notice, this list of conditions and the following disclaimer.
1150724Scg * 2. Redistributions in binary form must reproduce the above copyright
1250724Scg *    notice, this list of conditions and the following disclaimer in the
1350724Scg *    documentation and/or other materials provided with the distribution.
1450724Scg *
1550724Scg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1650724Scg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1750724Scg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1850724Scg * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1950724Scg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2050724Scg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2150724Scg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2250724Scg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2350724Scg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2450724Scg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2550724Scg * SUCH DAMAGE.
2650724Scg *
2750733Speter * $FreeBSD: head/sys/dev/sound/pcm/sound.c 61144 2000-06-01 01:32:30Z cg $
2850724Scg */
2950724Scg
3053465Scg#include <dev/sound/pcm/sound.h>
3150724Scg
3250724Scgstatic int 	status_isopen = 0;
3350724Scgstatic int 	status_init(char *buf, int size);
3450724Scgstatic int 	status_read(struct uio *buf);
3550724Scg
3650724Scgstatic d_open_t sndopen;
3750724Scgstatic d_close_t sndclose;
3850724Scgstatic d_ioctl_t sndioctl;
3950724Scgstatic d_read_t sndread;
4050724Scgstatic d_write_t sndwrite;
4150724Scgstatic d_mmap_t sndmmap;
4250724Scgstatic d_poll_t sndpoll;
4350724Scg
4450724Scg#define CDEV_MAJOR 30
4550724Scgstatic struct cdevsw snd_cdevsw = {
4650724Scg	/* open */	sndopen,
4750724Scg	/* close */	sndclose,
4850724Scg	/* read */	sndread,
4950724Scg	/* write */	sndwrite,
5050724Scg	/* ioctl */	sndioctl,
5150724Scg	/* poll */	sndpoll,
5250724Scg	/* mmap */	sndmmap,
5350724Scg	/* strategy */	nostrategy,
5450724Scg	/* name */	"snd",
5550724Scg	/* maj */	CDEV_MAJOR,
5650724Scg	/* dump */	nodump,
5750724Scg	/* psize */	nopsize,
5850724Scg	/* flags */	0,
5950724Scg	/* bmaj */	-1
6050724Scg};
6150724Scg
6259660Scg/*
6359660ScgPROPOSAL:
6450724Scgeach unit needs:
6550724Scgstatus, mixer, dsp, dspW, audio, sequencer, midi-in, seq2, sndproc = 9 devices
6650724ScgdspW and audio are deprecated.
6750724Scgdsp needs min 64 channels, will give it 256
6850724Scg
6959660Scgminor = (unit << 20) + (dev << 16) + channel
7059660Scgcurrently minor = (channel << 16) + (unit << 4) + dev
7150724Scg
7250724Scgnomenclature:
7350724Scg	/dev/pcmX/dsp.(0..255)
7450724Scg	/dev/pcmX/dspW
7550724Scg	/dev/pcmX/audio
7650724Scg	/dev/pcmX/status
7750724Scg	/dev/pcmX/mixer
7850724Scg	[etc.]
7950724Scg*/
8050724Scg
8150724Scg#define PCMMINOR(x) (minor(x))
8259665Scg#define PCMCHAN(x) ((PCMMINOR(x) & 0x00ff0000) >> 16)
8350724Scg#define PCMUNIT(x) ((PCMMINOR(x) & 0x000000f0) >> 4)
8450724Scg#define PCMDEV(x)   (PCMMINOR(x) & 0x0000000f)
8559660Scg#define PCMMKMINOR(u, d, c) ((((c) & 0xff) << 16) | (((u) & 0x0f) << 4) | ((d) & 0x0f))
8650724Scg
8750724Scgstatic devclass_t pcm_devclass;
8850724Scg
8950724Scgstatic snddev_info *
9050724Scggsd(int unit)
9150724Scg{
9250724Scg	return devclass_get_softc(pcm_devclass, unit);
9350724Scg}
9450724Scg
9550724Scgint
9650724Scgpcm_addchan(device_t dev, int dir, pcm_channel *templ, void *devinfo)
9750724Scg{
9854826Scg    	int unit = device_get_unit(dev);
9950724Scg    	snddev_info *d = device_get_softc(dev);
10050724Scg	pcm_channel *ch;
10150724Scg
10255483Scg	ch = (dir == PCMDIR_PLAY)? &d->play[d->playcount] : &d->rec[d->reccount];
10350724Scg	*ch = *templ;
10455483Scg	if (chn_init(ch, devinfo, dir)) {
10555483Scg		device_printf(dev, "chn_init() for %s:%d failed\n",
10655483Scg		              (dir == PCMDIR_PLAY)? "play" : "record",
10755483Scg			      (dir == PCMDIR_PLAY)? d->playcount : d->reccount);
10855483Scg		return 1;
10955483Scg	}
11055483Scg	if (dir == PCMDIR_PLAY) d->playcount++; else d->reccount++;
11154826Scg	make_dev(&snd_cdevsw, PCMMKMINOR(unit, SND_DEV_DSP, d->chancount),
11254826Scg		 UID_ROOT, GID_WHEEL, 0666, "dsp%d.%d", unit, d->chancount);
11354826Scg	make_dev(&snd_cdevsw, PCMMKMINOR(unit, SND_DEV_AUDIO, d->chancount),
11454826Scg		 UID_ROOT, GID_WHEEL, 0666, "audio%d.%d", unit, d->chancount);
11554826Scg	make_dev(&snd_cdevsw, PCMMKMINOR(unit, SND_DEV_DSP16, d->chancount),
11654826Scg		 UID_ROOT, GID_WHEEL, 0666, "dspW%d.%d", unit, d->chancount);
11754826Scg	/* XXX SND_DEV_NORESET? */
11850724Scg	d->chancount++;
11950724Scg	return 0;
12050724Scg}
12150724Scg
12250724Scgint
12350724Scgpcm_setstatus(device_t dev, char *str)
12450724Scg{
12550724Scg    	snddev_info *d = device_get_softc(dev);
12650724Scg	strncpy(d->status, str, SND_STATUSLEN);
12750724Scg	return 0;
12850724Scg}
12950724Scg
13050724Scgu_int32_t
13150724Scgpcm_getflags(device_t dev)
13250724Scg{
13350724Scg    	snddev_info *d = device_get_softc(dev);
13450724Scg	return d->flags;
13550724Scg}
13650724Scg
13750724Scgvoid
13850724Scgpcm_setflags(device_t dev, u_int32_t val)
13950724Scg{
14050724Scg    	snddev_info *d = device_get_softc(dev);
14150724Scg	d->flags = val;
14250724Scg}
14350724Scg
14458384Scgvoid *
14558384Scgpcm_getdevinfo(device_t dev)
14658384Scg{
14758384Scg    	snddev_info *d = device_get_softc(dev);
14858384Scg	return d->devinfo;
14958384Scg}
15058384Scg
15154460Scgvoid
15254460Scgpcm_setswap(device_t dev, pcm_swap_t *swap)
15354460Scg{
15454460Scg    	snddev_info *d = device_get_softc(dev);
15554460Scg	d->swap = swap;
15654460Scg}
15750724Scg/* This is the generic init routine */
15850724Scgint
15950724Scgpcm_register(device_t dev, void *devinfo, int numplay, int numrec)
16050724Scg{
16150724Scg    	int sz, unit = device_get_unit(dev);
16250724Scg    	snddev_info *d = device_get_softc(dev);
16350724Scg
16450724Scg    	if (!pcm_devclass) {
16550724Scg    		pcm_devclass = device_get_devclass(dev);
16654826Scg		make_dev(&snd_cdevsw, PCMMKMINOR(0, SND_DEV_STATUS, 0),
16752755Stanimura			 UID_ROOT, GID_WHEEL, 0444, "sndstat");
16852823Stanimura	}
16954826Scg	make_dev(&snd_cdevsw, PCMMKMINOR(unit, SND_DEV_CTL, 0),
17052823Stanimura		 UID_ROOT, GID_WHEEL, 0666, "mixer%d", unit);
17155494Scg
17250724Scg	d->devinfo = devinfo;
17350724Scg	d->chancount = d->playcount = d->reccount = 0;
17450724Scg    	sz = (numplay + numrec) * sizeof(pcm_channel *);
17550724Scg
17655494Scg	if (sz > 0) {
17755494Scg		d->aplay = (pcm_channel **)malloc(sz, M_DEVBUF, M_NOWAIT);
17855494Scg    		if (!d->aplay) goto no;
17955494Scg    		bzero(d->aplay, sz);
18050724Scg
18155494Scg    		d->arec = (pcm_channel **)malloc(sz, M_DEVBUF, M_NOWAIT);
18255494Scg    		if (!d->arec) goto no;
18355494Scg    		bzero(d->arec, sz);
18459021Scg
18559021Scg    		sz = (numplay + numrec) * sizeof(int);
18659021Scg		d->ref = (int *)malloc(sz, M_DEVBUF, M_NOWAIT);
18759021Scg    		if (!d->ref) goto no;
18859021Scg    		bzero(d->ref, sz);
18955494Scg	}
19055494Scg
19155494Scg	if (numplay > 0) {
19255494Scg    		d->play = (pcm_channel *)malloc(numplay * sizeof(pcm_channel),
19355494Scg						M_DEVBUF, M_NOWAIT);
19455494Scg    		if (!d->play) goto no;
19555494Scg    		bzero(d->play, numplay * sizeof(pcm_channel));
19655494Scg	}
19755494Scg
19855494Scg	if (numrec > 0) {
19955494Scg	  	d->rec = (pcm_channel *)malloc(numrec * sizeof(pcm_channel),
20055494Scg				       	M_DEVBUF, M_NOWAIT);
20155494Scg    		if (!d->rec) goto no;
20255494Scg    		bzero(d->rec, numrec * sizeof(pcm_channel));
20355494Scg	}
20455494Scg
20561144Scg	if (numplay == 0 || numrec == 0)
20661144Scg		d->flags |= SD_F_SIMPLEX;
20761144Scg
20850724Scg	fkchan_setup(&d->fakechan);
20950724Scg	chn_init(&d->fakechan, NULL, 0);
21050724Scg	d->magic = MAGIC(unit); /* debugging... */
21154460Scg	d->swap = NULL;
21250724Scg
21350724Scg    	return 0;
21450724Scgno:
21550724Scg	if (d->aplay) free(d->aplay, M_DEVBUF);
21650724Scg	if (d->play) free(d->play, M_DEVBUF);
21750724Scg	if (d->arec) free(d->arec, M_DEVBUF);
21850724Scg	if (d->rec) free(d->rec, M_DEVBUF);
21950724Scg	return ENXIO;
22050724Scg}
22150724Scg
22250724Scg/*
22350724Scg * a small utility function which, given a device number, returns
22450724Scg * a pointer to the associated snddev_info struct, and sets the unit
22550724Scg * number.
22650724Scg */
22750724Scgstatic snddev_info *
22850724Scgget_snddev_info(dev_t i_dev, int *unit, int *dev, int *chan)
22950724Scg{
23050724Scg    	int u, d, c;
23150724Scg
23250724Scg    	u = PCMUNIT(i_dev);
23350724Scg    	d = PCMDEV(i_dev);
23450724Scg    	c = PCMCHAN(i_dev);
23550724Scg    	if (u > devclass_get_maxunit(pcm_devclass)) u = -1;
23650724Scg    	if (unit) *unit = u;
23750724Scg    	if (dev) *dev = d;
23850724Scg    	if (chan) *chan = c;
23950724Scg    	if (u < 0) return NULL;
24050724Scg
24150724Scg    	switch(d) {
24250724Scg    	case SND_DEV_CTL:	/* /dev/mixer handled by pcm */
24350724Scg    	case SND_DEV_STATUS: /* /dev/sndstat handled by pcm */
24450724Scg    	case SND_DEV_DSP:
24550724Scg    	case SND_DEV_DSP16:
24650724Scg    	case SND_DEV_AUDIO:
24750724Scg		return gsd(u);
24850724Scg
24950724Scg    	case SND_DEV_SEQ: /* XXX when enabled... */
25050724Scg    	case SND_DEV_SEQ2:
25150724Scg    	case SND_DEV_MIDIN:
25250724Scg    	case SND_DEV_SNDPROC:	/* /dev/sndproc handled by pcm */
25350724Scg    	default:
25450724Scg		printf("unsupported subdevice %d\n", d);
25550724Scg		return NULL;
25650724Scg    	}
25750724Scg}
25850724Scg
25950724Scgstatic int
26050724Scgsndopen(dev_t i_dev, int flags, int mode, struct proc *p)
26150724Scg{
26250724Scg    	int dev, unit, chan;
26350724Scg    	snddev_info *d = get_snddev_info(i_dev, &unit, &dev, &chan);
26450724Scg
26550724Scg    	DEB(printf("open snd%d subdev %d flags 0x%08x mode 0x%08x\n",
26650724Scg		unit, dev, flags, mode));
26750724Scg
26850724Scg    	switch(dev) {
26950724Scg    	case SND_DEV_STATUS:
27050724Scg		if (status_isopen) return EBUSY;
27150724Scg		status_isopen = 1;
27250724Scg		return 0;
27350724Scg
27450724Scg    	case SND_DEV_CTL:
27550724Scg		return d? 0 : ENXIO;
27650724Scg
27750724Scg    	case SND_DEV_AUDIO:
27850724Scg    	case SND_DEV_DSP:
27950724Scg    	case SND_DEV_DSP16:
28051769Scg	case SND_DEV_NORESET:
28150724Scg		return d? dsp_open(d, chan, flags, dev) : ENXIO;
28250724Scg
28350724Scg    	default:
28450724Scg    		return ENXIO;
28550724Scg    	}
28650724Scg}
28750724Scg
28850724Scgstatic int
28950724Scgsndclose(dev_t i_dev, int flags, int mode, struct proc *p)
29050724Scg{
29150724Scg    	int dev, unit, chan;
29250724Scg    	snddev_info *d = get_snddev_info(i_dev, &unit, &dev, &chan);
29350724Scg
29450724Scg    	DEB(printf("close snd%d subdev %d\n", unit, dev));
29550724Scg
29650724Scg    	switch(dev) { /* only those for which close makes sense */
29750724Scg    	case SND_DEV_STATUS:
29850724Scg		if (!status_isopen) return EBADF;
29950724Scg		status_isopen = 0;
30050724Scg		return 0;
30150724Scg
30250724Scg    	case SND_DEV_CTL:
30350724Scg		return d? 0 : ENXIO;
30450724Scg
30550724Scg    	case SND_DEV_AUDIO:
30650724Scg    	case SND_DEV_DSP:
30750724Scg    	case SND_DEV_DSP16:
30850724Scg		return d? dsp_close(d, chan, dev) : ENXIO;
30950724Scg
31050724Scg    	default:
31150724Scg		return ENXIO;
31250724Scg    	}
31350724Scg}
31450724Scg
31550724Scgstatic int
31650724Scgsndread(dev_t i_dev, struct uio *buf, int flag)
31750724Scg{
31850724Scg    	int dev, unit, chan;
31950724Scg    	snddev_info *d = get_snddev_info(i_dev, &unit, &dev, &chan);
32050724Scg    	DEB(printf("read snd%d subdev %d flag 0x%08x\n", unit, dev, flag));
32150724Scg
32250724Scg    	switch(dev) {
32350724Scg    	case SND_DEV_STATUS:
32450724Scg		return status_isopen? status_read(buf) : EBADF;
32550724Scg
32650724Scg    	case SND_DEV_AUDIO:
32750724Scg    	case SND_DEV_DSP:
32850724Scg    	case SND_DEV_DSP16:
32950724Scg        	return d? dsp_read(d, chan, buf, flag) : EBADF;
33050724Scg
33150724Scg    	default:
33250724Scg    		return ENXIO;
33350724Scg    	}
33450724Scg}
33550724Scg
33650724Scgstatic int
33750724Scgsndwrite(dev_t i_dev, struct uio *buf, int flag)
33850724Scg{
33950724Scg    	int dev, unit, chan;
34050724Scg    	snddev_info *d = get_snddev_info(i_dev, &unit, &dev, &chan);
34150724Scg
34250724Scg    	DEB(printf("write snd%d subdev %d flag 0x%08x\n", unit, dev & 0xf, flag));
34350724Scg
34450724Scg    	switch(dev) {	/* only writeable devices */
34550724Scg    	case SND_DEV_DSP:
34650724Scg    	case SND_DEV_DSP16:
34750724Scg    	case SND_DEV_AUDIO:
34850724Scg		return d? dsp_write(d, chan, buf, flag) : EBADF;
34950724Scg
35050724Scg    	default:
35150724Scg		return EPERM; /* for non-writeable devices ; */
35250724Scg    	}
35350724Scg}
35450724Scg
35550724Scgstatic int
35650724Scgsndioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct proc * p)
35750724Scg{
35850724Scg    	int dev, chan;
35950724Scg    	snddev_info *d = get_snddev_info(i_dev, NULL, &dev, &chan);
36050724Scg
36150724Scg    	if (d == NULL) return ENXIO;
36250724Scg
36350724Scg    	switch(dev) {
36450724Scg    	case SND_DEV_CTL:
36550724Scg		return mixer_ioctl(d, cmd, arg);
36650724Scg
36750724Scg    	case SND_DEV_AUDIO:
36850724Scg    	case SND_DEV_DSP:
36950724Scg    	case SND_DEV_DSP16:
37054857Scg		if (IOCGROUP(cmd) == 'M')
37154857Scg			return mixer_ioctl(d, cmd, arg);
37254857Scg		else
37354857Scg			return dsp_ioctl(d, chan, cmd, arg);
37450724Scg
37550724Scg    	default:
37650724Scg    		return ENXIO;
37750724Scg    	}
37850724Scg}
37950724Scg
38050724Scgstatic int
38150724Scgsndpoll(dev_t i_dev, int events, struct proc *p)
38250724Scg{
38350724Scg    	int dev, chan;
38450724Scg    	snddev_info *d = get_snddev_info(i_dev, NULL, &dev, &chan);
38550724Scg
38654155Scg	DEB(printf("sndpoll d 0x%p dev 0x%04x events 0x%08x\n", d, dev, events));
38750724Scg
38850724Scg    	if (d == NULL) return ENXIO;
38950724Scg
39050724Scg    	switch(dev) {
39150724Scg    	case SND_DEV_AUDIO:
39250724Scg    	case SND_DEV_DSP:
39350724Scg    	case SND_DEV_DSP16:
39450724Scg		return dsp_poll(d, chan, events, p);
39550724Scg
39650724Scg    	default:
39750724Scg    		return (events &
39850724Scg       		       (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM)) | POLLHUP;
39950724Scg    	}
40050724Scg}
40150724Scg
40250724Scg/*
40350724Scg * The mmap interface allows access to the play and read buffer,
40450724Scg * plus the device descriptor.
40550724Scg * The various blocks are accessible at the following offsets:
40650724Scg *
40750724Scg * 0x00000000 ( 0   ) : write buffer ;
40850724Scg * 0x01000000 (16 MB) : read buffer ;
40950724Scg * 0x02000000 (32 MB) : device descriptor (dangerous!)
41050724Scg *
41150724Scg * WARNING: the mmap routines assume memory areas are aligned. This
41250724Scg * is true (probably) for the dma buffers, but likely false for the
41350724Scg * device descriptor. As a consequence, we do not know where it is
41450724Scg * located in the requested area.
41550724Scg */
41650724Scgstatic int
41750724Scgsndmmap(dev_t i_dev, vm_offset_t offset, int nprot)
41850724Scg{
41950724Scg    	int unit, dev, chan;
42050724Scg    	snddev_info *d = get_snddev_info(i_dev, &unit, &dev, &chan);
42150724Scg
42250724Scg    	DEB(printf("sndmmap d 0x%p dev 0x%04x ofs 0x%08x nprot 0x%08x\n",
42350724Scg		   d, dev, offset, nprot));
42450724Scg
42550724Scg    	if (d == NULL || nprot & PROT_EXEC)	return -1; /* forbidden */
42650724Scg
42750724Scg    	switch(dev) {
42850724Scg    	case SND_DEV_AUDIO:
42950724Scg    	case SND_DEV_DSP:
43050724Scg    	case SND_DEV_DSP16:
43150724Scg		return dsp_mmap(d, chan, offset, nprot);
43250724Scg
43350724Scg    	default:
43450724Scg    		return -1;
43550724Scg    	}
43650724Scg}
43750724Scg
43850724Scgstatic int
43950724Scgstatus_init(char *buf, int size)
44050724Scg{
44150724Scg    	int             i;
44250724Scg    	device_t	    dev;
44350724Scg    	snddev_info     *d;
44450724Scg
44550724Scg    	snprintf(buf, size, "FreeBSD Audio Driver (newpcm) %s %s\n"
44650724Scg		 "Installed devices:\n", __DATE__, __TIME__);
44750724Scg
44850724Scg    	for (i = 0; i <= devclass_get_maxunit(pcm_devclass); i++) {
44950724Scg		d = gsd(i);
45050724Scg		if (!d) continue;
45150724Scg		dev = devclass_get_device(pcm_devclass, i);
45255638Scg        	if (1) {
45355638Scg			snprintf(buf + strlen(buf), size - strlen(buf),
45455638Scg		            	"pcm%d: <%s> %s",
45555638Scg		            	i, device_get_desc(dev), d->status);
45655638Scg			if (d->chancount > 0)
45755638Scg				snprintf(buf + strlen(buf), size - strlen(buf),
45855638Scg				" (%dp/%dr channels%s)\n",
45955638Scg			    	d->playcount, d->reccount,
46050724Scg			    	(!(d->flags & SD_F_SIMPLEX))? " duplex" : "");
46155638Scg			else
46255638Scg				snprintf(buf + strlen(buf), size - strlen(buf),
46356110Scg				" (mixer only)\n");
46455638Scg		}
46550724Scg    	}
46650724Scg    	return strlen(buf);
46750724Scg}
46850724Scg
46950724Scgstatic int
47050724Scgstatus_read(struct uio *buf)
47150724Scg{
47250724Scg    	static char	status_buf[4096];
47350724Scg    	static int 	bufptr = 0, buflen = 0;
47450724Scg    	int l;
47550724Scg
47650724Scg    	if (status_isopen == 1) {
47750724Scg		status_isopen++;
47850724Scg		bufptr = 0;
47950724Scg		buflen = status_init(status_buf, sizeof status_buf);
48050724Scg    	}
48150724Scg
48250724Scg    	l = min(buf->uio_resid, buflen - bufptr);
48350724Scg    	bufptr += l;
48450724Scg    	return (l > 0)? uiomove(status_buf + bufptr - l, l, buf) : 0;
48550724Scg}
486