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