1987e5972SCameron Grant /* 2987e5972SCameron Grant * Copyright (c) 1999 Cameron Grant <gandalf@vilnya.demon.co.uk> 3987e5972SCameron Grant * (C) 1997 Luigi Rizzo (luigi@iet.unipi.it) 4987e5972SCameron Grant * All rights reserved. 5987e5972SCameron Grant * 6987e5972SCameron Grant * Redistribution and use in source and binary forms, with or without 7987e5972SCameron Grant * modification, are permitted provided that the following conditions 8987e5972SCameron Grant * are met: 9987e5972SCameron Grant * 1. Redistributions of source code must retain the above copyright 10987e5972SCameron Grant * notice, this list of conditions and the following disclaimer. 11987e5972SCameron Grant * 2. Redistributions in binary form must reproduce the above copyright 12987e5972SCameron Grant * notice, this list of conditions and the following disclaimer in the 13987e5972SCameron Grant * documentation and/or other materials provided with the distribution. 14987e5972SCameron Grant * 15987e5972SCameron Grant * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16987e5972SCameron Grant * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17987e5972SCameron Grant * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18987e5972SCameron Grant * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19987e5972SCameron Grant * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20987e5972SCameron Grant * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21987e5972SCameron Grant * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22987e5972SCameron Grant * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23987e5972SCameron Grant * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24987e5972SCameron Grant * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25987e5972SCameron Grant * SUCH DAMAGE. 26987e5972SCameron Grant * 2753c5a968SPeter Wemm * $FreeBSD$ 28987e5972SCameron Grant */ 29987e5972SCameron Grant 30ef9308b1SCameron Grant #include <dev/sound/pcm/sound.h> 31987e5972SCameron Grant 32987e5972SCameron Grant static int status_isopen = 0; 33987e5972SCameron Grant static int status_init(char *buf, int size); 34987e5972SCameron Grant static int status_read(struct uio *buf); 35987e5972SCameron Grant 36987e5972SCameron Grant static d_open_t sndopen; 37987e5972SCameron Grant static d_close_t sndclose; 38987e5972SCameron Grant static d_ioctl_t sndioctl; 39987e5972SCameron Grant static d_read_t sndread; 40987e5972SCameron Grant static d_write_t sndwrite; 41987e5972SCameron Grant static d_mmap_t sndmmap; 42987e5972SCameron Grant static d_poll_t sndpoll; 43987e5972SCameron Grant 44987e5972SCameron Grant #define CDEV_MAJOR 30 45987e5972SCameron Grant static struct cdevsw snd_cdevsw = { 46987e5972SCameron Grant /* open */ sndopen, 47987e5972SCameron Grant /* close */ sndclose, 48987e5972SCameron Grant /* read */ sndread, 49987e5972SCameron Grant /* write */ sndwrite, 50987e5972SCameron Grant /* ioctl */ sndioctl, 51987e5972SCameron Grant /* poll */ sndpoll, 52987e5972SCameron Grant /* mmap */ sndmmap, 53987e5972SCameron Grant /* strategy */ nostrategy, 54987e5972SCameron Grant /* name */ "snd", 55987e5972SCameron Grant /* maj */ CDEV_MAJOR, 56987e5972SCameron Grant /* dump */ nodump, 57987e5972SCameron Grant /* psize */ nopsize, 58987e5972SCameron Grant /* flags */ 0, 59987e5972SCameron Grant /* bmaj */ -1 60987e5972SCameron Grant }; 61987e5972SCameron Grant 62dd186369SCameron Grant /* 63dd186369SCameron Grant PROPOSAL: 64987e5972SCameron Grant each unit needs: 65987e5972SCameron Grant status, mixer, dsp, dspW, audio, sequencer, midi-in, seq2, sndproc = 9 devices 66987e5972SCameron Grant dspW and audio are deprecated. 67987e5972SCameron Grant dsp needs min 64 channels, will give it 256 68987e5972SCameron Grant 69dd186369SCameron Grant minor = (unit << 20) + (dev << 16) + channel 70dd186369SCameron Grant currently minor = (channel << 16) + (unit << 4) + dev 71987e5972SCameron Grant 72987e5972SCameron Grant nomenclature: 73987e5972SCameron Grant /dev/pcmX/dsp.(0..255) 74987e5972SCameron Grant /dev/pcmX/dspW 75987e5972SCameron Grant /dev/pcmX/audio 76987e5972SCameron Grant /dev/pcmX/status 77987e5972SCameron Grant /dev/pcmX/mixer 78987e5972SCameron Grant [etc.] 79987e5972SCameron Grant */ 80987e5972SCameron Grant 81987e5972SCameron Grant #define PCMMINOR(x) (minor(x)) 82a618cffeSCameron Grant #define PCMCHAN(x) ((PCMMINOR(x) & 0x00ff0000) >> 16) 83987e5972SCameron Grant #define PCMUNIT(x) ((PCMMINOR(x) & 0x000000f0) >> 4) 84987e5972SCameron Grant #define PCMDEV(x) (PCMMINOR(x) & 0x0000000f) 85dd186369SCameron Grant #define PCMMKMINOR(u, d, c) ((((c) & 0xff) << 16) | (((u) & 0x0f) << 4) | ((d) & 0x0f)) 86987e5972SCameron Grant 87987e5972SCameron Grant static devclass_t pcm_devclass; 88987e5972SCameron Grant 89987e5972SCameron Grant static snddev_info * 90987e5972SCameron Grant gsd(int unit) 91987e5972SCameron Grant { 92987e5972SCameron Grant return devclass_get_softc(pcm_devclass, unit); 93987e5972SCameron Grant } 94987e5972SCameron Grant 95987e5972SCameron Grant int 96987e5972SCameron Grant pcm_addchan(device_t dev, int dir, pcm_channel *templ, void *devinfo) 97987e5972SCameron Grant { 987207eca6SCameron Grant int unit = device_get_unit(dev); 99987e5972SCameron Grant snddev_info *d = device_get_softc(dev); 100987e5972SCameron Grant pcm_channel *ch; 101987e5972SCameron Grant 1029c326820SCameron Grant if (((dir == PCMDIR_PLAY)? d->play : d->rec) == NULL) { 1039c326820SCameron Grant device_printf(dev, "bad channel add (%s)\n", 1049c326820SCameron Grant (dir == PCMDIR_PLAY)? "play" : "record"); 1059c326820SCameron Grant return 1; 1069c326820SCameron Grant } 107bbb5bf3dSCameron Grant ch = (dir == PCMDIR_PLAY)? &d->play[d->playcount] : &d->rec[d->reccount]; 108987e5972SCameron Grant *ch = *templ; 109e4d5b250SCameron Grant ch->parent = d; 110bbb5bf3dSCameron Grant if (chn_init(ch, devinfo, dir)) { 111bbb5bf3dSCameron Grant device_printf(dev, "chn_init() for %s:%d failed\n", 112bbb5bf3dSCameron Grant (dir == PCMDIR_PLAY)? "play" : "record", 113bbb5bf3dSCameron Grant (dir == PCMDIR_PLAY)? d->playcount : d->reccount); 114bbb5bf3dSCameron Grant return 1; 115bbb5bf3dSCameron Grant } 116bbb5bf3dSCameron Grant if (dir == PCMDIR_PLAY) d->playcount++; else d->reccount++; 1177207eca6SCameron Grant make_dev(&snd_cdevsw, PCMMKMINOR(unit, SND_DEV_DSP, d->chancount), 1187207eca6SCameron Grant UID_ROOT, GID_WHEEL, 0666, "dsp%d.%d", unit, d->chancount); 1197207eca6SCameron Grant make_dev(&snd_cdevsw, PCMMKMINOR(unit, SND_DEV_AUDIO, d->chancount), 1207207eca6SCameron Grant UID_ROOT, GID_WHEEL, 0666, "audio%d.%d", unit, d->chancount); 1217207eca6SCameron Grant make_dev(&snd_cdevsw, PCMMKMINOR(unit, SND_DEV_DSP16, d->chancount), 1227207eca6SCameron Grant UID_ROOT, GID_WHEEL, 0666, "dspW%d.%d", unit, d->chancount); 1237207eca6SCameron Grant /* XXX SND_DEV_NORESET? */ 124987e5972SCameron Grant d->chancount++; 125987e5972SCameron Grant return 0; 126987e5972SCameron Grant } 127987e5972SCameron Grant 128987e5972SCameron Grant int 129987e5972SCameron Grant pcm_setstatus(device_t dev, char *str) 130987e5972SCameron Grant { 131987e5972SCameron Grant snddev_info *d = device_get_softc(dev); 132987e5972SCameron Grant strncpy(d->status, str, SND_STATUSLEN); 133987e5972SCameron Grant return 0; 134987e5972SCameron Grant } 135987e5972SCameron Grant 136987e5972SCameron Grant u_int32_t 137987e5972SCameron Grant pcm_getflags(device_t dev) 138987e5972SCameron Grant { 139987e5972SCameron Grant snddev_info *d = device_get_softc(dev); 140987e5972SCameron Grant return d->flags; 141987e5972SCameron Grant } 142987e5972SCameron Grant 143987e5972SCameron Grant void 144987e5972SCameron Grant pcm_setflags(device_t dev, u_int32_t val) 145987e5972SCameron Grant { 146987e5972SCameron Grant snddev_info *d = device_get_softc(dev); 147987e5972SCameron Grant d->flags = val; 148987e5972SCameron Grant } 149987e5972SCameron Grant 15039004e69SCameron Grant void * 15139004e69SCameron Grant pcm_getdevinfo(device_t dev) 15239004e69SCameron Grant { 15339004e69SCameron Grant snddev_info *d = device_get_softc(dev); 15439004e69SCameron Grant return d->devinfo; 15539004e69SCameron Grant } 15639004e69SCameron Grant 1570927bf43SCameron Grant void 1580927bf43SCameron Grant pcm_setswap(device_t dev, pcm_swap_t *swap) 1590927bf43SCameron Grant { 1600927bf43SCameron Grant snddev_info *d = device_get_softc(dev); 1610927bf43SCameron Grant d->swap = swap; 1620927bf43SCameron Grant } 163987e5972SCameron Grant /* This is the generic init routine */ 164987e5972SCameron Grant int 165987e5972SCameron Grant pcm_register(device_t dev, void *devinfo, int numplay, int numrec) 166987e5972SCameron Grant { 167987e5972SCameron Grant int sz, unit = device_get_unit(dev); 168987e5972SCameron Grant snddev_info *d = device_get_softc(dev); 169987e5972SCameron Grant 170987e5972SCameron Grant if (!pcm_devclass) { 171987e5972SCameron Grant pcm_devclass = device_get_devclass(dev); 1727207eca6SCameron Grant make_dev(&snd_cdevsw, PCMMKMINOR(0, SND_DEV_STATUS, 0), 173083279e4SSeigo Tanimura UID_ROOT, GID_WHEEL, 0444, "sndstat"); 174083279e4SSeigo Tanimura } 1757207eca6SCameron Grant make_dev(&snd_cdevsw, PCMMKMINOR(unit, SND_DEV_CTL, 0), 17611346231SSeigo Tanimura UID_ROOT, GID_WHEEL, 0666, "mixer%d", unit); 177833f7023SCameron Grant 178e4d5b250SCameron Grant d->dev = dev; 179987e5972SCameron Grant d->devinfo = devinfo; 180987e5972SCameron Grant d->chancount = d->playcount = d->reccount = 0; 181987e5972SCameron Grant sz = (numplay + numrec) * sizeof(pcm_channel *); 182833f7023SCameron Grant 183833f7023SCameron Grant if (sz > 0) { 184987e5972SCameron Grant d->aplay = (pcm_channel **)malloc(sz, M_DEVBUF, M_NOWAIT); 185987e5972SCameron Grant if (!d->aplay) goto no; 186833f7023SCameron Grant bzero(d->aplay, sz); 187833f7023SCameron Grant 188987e5972SCameron Grant d->arec = (pcm_channel **)malloc(sz, M_DEVBUF, M_NOWAIT); 189987e5972SCameron Grant if (!d->arec) goto no; 190987e5972SCameron Grant bzero(d->arec, sz); 191bd18f334SCameron Grant 192bd18f334SCameron Grant sz = (numplay + numrec) * sizeof(int); 193bd18f334SCameron Grant d->ref = (int *)malloc(sz, M_DEVBUF, M_NOWAIT); 194bd18f334SCameron Grant if (!d->ref) goto no; 195bd18f334SCameron Grant bzero(d->ref, sz); 196833f7023SCameron Grant } 197987e5972SCameron Grant 198833f7023SCameron Grant if (numplay > 0) { 199987e5972SCameron Grant d->play = (pcm_channel *)malloc(numplay * sizeof(pcm_channel), 200987e5972SCameron Grant M_DEVBUF, M_NOWAIT); 201987e5972SCameron Grant if (!d->play) goto no; 202833f7023SCameron Grant bzero(d->play, numplay * sizeof(pcm_channel)); 2039c326820SCameron Grant } else 2049c326820SCameron Grant d->play = NULL; 205833f7023SCameron Grant 206833f7023SCameron Grant if (numrec > 0) { 207987e5972SCameron Grant d->rec = (pcm_channel *)malloc(numrec * sizeof(pcm_channel), 208987e5972SCameron Grant M_DEVBUF, M_NOWAIT); 209987e5972SCameron Grant if (!d->rec) goto no; 210987e5972SCameron Grant bzero(d->rec, numrec * sizeof(pcm_channel)); 2119c326820SCameron Grant } else 2129c326820SCameron Grant d->rec = NULL; 213987e5972SCameron Grant 21417dbf677SCameron Grant if (numplay == 0 || numrec == 0) 21517dbf677SCameron Grant d->flags |= SD_F_SIMPLEX; 21617dbf677SCameron Grant 217987e5972SCameron Grant fkchan_setup(&d->fakechan); 218987e5972SCameron Grant chn_init(&d->fakechan, NULL, 0); 219987e5972SCameron Grant d->magic = MAGIC(unit); /* debugging... */ 2200927bf43SCameron Grant d->swap = NULL; 221987e5972SCameron Grant 222987e5972SCameron Grant return 0; 223987e5972SCameron Grant no: 224987e5972SCameron Grant if (d->aplay) free(d->aplay, M_DEVBUF); 225987e5972SCameron Grant if (d->play) free(d->play, M_DEVBUF); 226987e5972SCameron Grant if (d->arec) free(d->arec, M_DEVBUF); 227987e5972SCameron Grant if (d->rec) free(d->rec, M_DEVBUF); 228987e5972SCameron Grant return ENXIO; 229987e5972SCameron Grant } 230987e5972SCameron Grant 231987e5972SCameron Grant /* 232987e5972SCameron Grant * a small utility function which, given a device number, returns 233987e5972SCameron Grant * a pointer to the associated snddev_info struct, and sets the unit 234987e5972SCameron Grant * number. 235987e5972SCameron Grant */ 236987e5972SCameron Grant static snddev_info * 237987e5972SCameron Grant get_snddev_info(dev_t i_dev, int *unit, int *dev, int *chan) 238987e5972SCameron Grant { 239987e5972SCameron Grant int u, d, c; 240987e5972SCameron Grant 241987e5972SCameron Grant u = PCMUNIT(i_dev); 242987e5972SCameron Grant d = PCMDEV(i_dev); 243987e5972SCameron Grant c = PCMCHAN(i_dev); 244987e5972SCameron Grant if (u > devclass_get_maxunit(pcm_devclass)) u = -1; 245987e5972SCameron Grant if (unit) *unit = u; 246987e5972SCameron Grant if (dev) *dev = d; 247987e5972SCameron Grant if (chan) *chan = c; 248987e5972SCameron Grant if (u < 0) return NULL; 249987e5972SCameron Grant 250987e5972SCameron Grant switch(d) { 251987e5972SCameron Grant case SND_DEV_CTL: /* /dev/mixer handled by pcm */ 252987e5972SCameron Grant case SND_DEV_STATUS: /* /dev/sndstat handled by pcm */ 253987e5972SCameron Grant case SND_DEV_DSP: 254987e5972SCameron Grant case SND_DEV_DSP16: 255987e5972SCameron Grant case SND_DEV_AUDIO: 256987e5972SCameron Grant return gsd(u); 257987e5972SCameron Grant 258987e5972SCameron Grant case SND_DEV_SEQ: /* XXX when enabled... */ 259987e5972SCameron Grant case SND_DEV_SEQ2: 260987e5972SCameron Grant case SND_DEV_MIDIN: 261987e5972SCameron Grant case SND_DEV_SNDPROC: /* /dev/sndproc handled by pcm */ 262987e5972SCameron Grant default: 263987e5972SCameron Grant printf("unsupported subdevice %d\n", d); 264987e5972SCameron Grant return NULL; 265987e5972SCameron Grant } 266987e5972SCameron Grant } 267987e5972SCameron Grant 268987e5972SCameron Grant static int 269987e5972SCameron Grant sndopen(dev_t i_dev, int flags, int mode, struct proc *p) 270987e5972SCameron Grant { 271987e5972SCameron Grant int dev, unit, chan; 272987e5972SCameron Grant snddev_info *d = get_snddev_info(i_dev, &unit, &dev, &chan); 273987e5972SCameron Grant 274987e5972SCameron Grant DEB(printf("open snd%d subdev %d flags 0x%08x mode 0x%08x\n", 275987e5972SCameron Grant unit, dev, flags, mode)); 276987e5972SCameron Grant 277987e5972SCameron Grant switch(dev) { 278987e5972SCameron Grant case SND_DEV_STATUS: 279987e5972SCameron Grant if (status_isopen) return EBUSY; 280987e5972SCameron Grant status_isopen = 1; 281987e5972SCameron Grant return 0; 282987e5972SCameron Grant 283987e5972SCameron Grant case SND_DEV_CTL: 284987e5972SCameron Grant return d? 0 : ENXIO; 285987e5972SCameron Grant 286987e5972SCameron Grant case SND_DEV_AUDIO: 287987e5972SCameron Grant case SND_DEV_DSP: 288987e5972SCameron Grant case SND_DEV_DSP16: 2895b78a734SCameron Grant case SND_DEV_NORESET: 290987e5972SCameron Grant return d? dsp_open(d, chan, flags, dev) : ENXIO; 291987e5972SCameron Grant 292987e5972SCameron Grant default: 293987e5972SCameron Grant return ENXIO; 294987e5972SCameron Grant } 295987e5972SCameron Grant } 296987e5972SCameron Grant 297987e5972SCameron Grant static int 298987e5972SCameron Grant sndclose(dev_t i_dev, int flags, int mode, struct proc *p) 299987e5972SCameron Grant { 300987e5972SCameron Grant int dev, unit, chan; 301987e5972SCameron Grant snddev_info *d = get_snddev_info(i_dev, &unit, &dev, &chan); 302987e5972SCameron Grant 303987e5972SCameron Grant DEB(printf("close snd%d subdev %d\n", unit, dev)); 304987e5972SCameron Grant 305987e5972SCameron Grant switch(dev) { /* only those for which close makes sense */ 306987e5972SCameron Grant case SND_DEV_STATUS: 307987e5972SCameron Grant if (!status_isopen) return EBADF; 308987e5972SCameron Grant status_isopen = 0; 309987e5972SCameron Grant return 0; 310987e5972SCameron Grant 311987e5972SCameron Grant case SND_DEV_CTL: 312987e5972SCameron Grant return d? 0 : ENXIO; 313987e5972SCameron Grant 314987e5972SCameron Grant case SND_DEV_AUDIO: 315987e5972SCameron Grant case SND_DEV_DSP: 316987e5972SCameron Grant case SND_DEV_DSP16: 317987e5972SCameron Grant return d? dsp_close(d, chan, dev) : ENXIO; 318987e5972SCameron Grant 319987e5972SCameron Grant default: 320987e5972SCameron Grant return ENXIO; 321987e5972SCameron Grant } 322987e5972SCameron Grant } 323987e5972SCameron Grant 324987e5972SCameron Grant static int 325987e5972SCameron Grant sndread(dev_t i_dev, struct uio *buf, int flag) 326987e5972SCameron Grant { 327987e5972SCameron Grant int dev, unit, chan; 328987e5972SCameron Grant snddev_info *d = get_snddev_info(i_dev, &unit, &dev, &chan); 329987e5972SCameron Grant DEB(printf("read snd%d subdev %d flag 0x%08x\n", unit, dev, flag)); 330987e5972SCameron Grant 331987e5972SCameron Grant switch(dev) { 332987e5972SCameron Grant case SND_DEV_STATUS: 333987e5972SCameron Grant return status_isopen? status_read(buf) : EBADF; 334987e5972SCameron Grant 335987e5972SCameron Grant case SND_DEV_AUDIO: 336987e5972SCameron Grant case SND_DEV_DSP: 337987e5972SCameron Grant case SND_DEV_DSP16: 338987e5972SCameron Grant return d? dsp_read(d, chan, buf, flag) : EBADF; 339987e5972SCameron Grant 340987e5972SCameron Grant default: 341987e5972SCameron Grant return ENXIO; 342987e5972SCameron Grant } 343987e5972SCameron Grant } 344987e5972SCameron Grant 345987e5972SCameron Grant static int 346987e5972SCameron Grant sndwrite(dev_t i_dev, struct uio *buf, int flag) 347987e5972SCameron Grant { 348987e5972SCameron Grant int dev, unit, chan; 349987e5972SCameron Grant snddev_info *d = get_snddev_info(i_dev, &unit, &dev, &chan); 350987e5972SCameron Grant 351987e5972SCameron Grant DEB(printf("write snd%d subdev %d flag 0x%08x\n", unit, dev & 0xf, flag)); 352987e5972SCameron Grant 353987e5972SCameron Grant switch(dev) { /* only writeable devices */ 354987e5972SCameron Grant case SND_DEV_DSP: 355987e5972SCameron Grant case SND_DEV_DSP16: 356987e5972SCameron Grant case SND_DEV_AUDIO: 357987e5972SCameron Grant return d? dsp_write(d, chan, buf, flag) : EBADF; 358987e5972SCameron Grant 359987e5972SCameron Grant default: 360987e5972SCameron Grant return EPERM; /* for non-writeable devices ; */ 361987e5972SCameron Grant } 362987e5972SCameron Grant } 363987e5972SCameron Grant 364987e5972SCameron Grant static int 365987e5972SCameron Grant sndioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct proc * p) 366987e5972SCameron Grant { 367987e5972SCameron Grant int dev, chan; 368987e5972SCameron Grant snddev_info *d = get_snddev_info(i_dev, NULL, &dev, &chan); 369987e5972SCameron Grant 370987e5972SCameron Grant if (d == NULL) return ENXIO; 371987e5972SCameron Grant 372987e5972SCameron Grant switch(dev) { 373987e5972SCameron Grant case SND_DEV_CTL: 374987e5972SCameron Grant return mixer_ioctl(d, cmd, arg); 375987e5972SCameron Grant 376987e5972SCameron Grant case SND_DEV_AUDIO: 377987e5972SCameron Grant case SND_DEV_DSP: 378987e5972SCameron Grant case SND_DEV_DSP16: 3791ad869dbSCameron Grant if (IOCGROUP(cmd) == 'M') 3801ad869dbSCameron Grant return mixer_ioctl(d, cmd, arg); 3811ad869dbSCameron Grant else 382987e5972SCameron Grant return dsp_ioctl(d, chan, cmd, arg); 383987e5972SCameron Grant 384987e5972SCameron Grant default: 385987e5972SCameron Grant return ENXIO; 386987e5972SCameron Grant } 387987e5972SCameron Grant } 388987e5972SCameron Grant 389987e5972SCameron Grant static int 390987e5972SCameron Grant sndpoll(dev_t i_dev, int events, struct proc *p) 391987e5972SCameron Grant { 392987e5972SCameron Grant int dev, chan; 393987e5972SCameron Grant snddev_info *d = get_snddev_info(i_dev, NULL, &dev, &chan); 394987e5972SCameron Grant 3950e25481fSCameron Grant DEB(printf("sndpoll d 0x%p dev 0x%04x events 0x%08x\n", d, dev, events)); 396987e5972SCameron Grant 397987e5972SCameron Grant if (d == NULL) return ENXIO; 398987e5972SCameron Grant 399987e5972SCameron Grant switch(dev) { 400987e5972SCameron Grant case SND_DEV_AUDIO: 401987e5972SCameron Grant case SND_DEV_DSP: 402987e5972SCameron Grant case SND_DEV_DSP16: 403987e5972SCameron Grant return dsp_poll(d, chan, events, p); 404987e5972SCameron Grant 405987e5972SCameron Grant default: 406987e5972SCameron Grant return (events & 407987e5972SCameron Grant (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM)) | POLLHUP; 408987e5972SCameron Grant } 409987e5972SCameron Grant } 410987e5972SCameron Grant 411987e5972SCameron Grant /* 412987e5972SCameron Grant * The mmap interface allows access to the play and read buffer, 413987e5972SCameron Grant * plus the device descriptor. 414987e5972SCameron Grant * The various blocks are accessible at the following offsets: 415987e5972SCameron Grant * 416987e5972SCameron Grant * 0x00000000 ( 0 ) : write buffer ; 417987e5972SCameron Grant * 0x01000000 (16 MB) : read buffer ; 418987e5972SCameron Grant * 0x02000000 (32 MB) : device descriptor (dangerous!) 419987e5972SCameron Grant * 420987e5972SCameron Grant * WARNING: the mmap routines assume memory areas are aligned. This 421987e5972SCameron Grant * is true (probably) for the dma buffers, but likely false for the 422987e5972SCameron Grant * device descriptor. As a consequence, we do not know where it is 423987e5972SCameron Grant * located in the requested area. 424987e5972SCameron Grant */ 425987e5972SCameron Grant static int 426987e5972SCameron Grant sndmmap(dev_t i_dev, vm_offset_t offset, int nprot) 427987e5972SCameron Grant { 428987e5972SCameron Grant int unit, dev, chan; 429987e5972SCameron Grant snddev_info *d = get_snddev_info(i_dev, &unit, &dev, &chan); 430987e5972SCameron Grant 431987e5972SCameron Grant DEB(printf("sndmmap d 0x%p dev 0x%04x ofs 0x%08x nprot 0x%08x\n", 432987e5972SCameron Grant d, dev, offset, nprot)); 433987e5972SCameron Grant 434987e5972SCameron Grant if (d == NULL || nprot & PROT_EXEC) return -1; /* forbidden */ 435987e5972SCameron Grant 436987e5972SCameron Grant switch(dev) { 437987e5972SCameron Grant case SND_DEV_AUDIO: 438987e5972SCameron Grant case SND_DEV_DSP: 439987e5972SCameron Grant case SND_DEV_DSP16: 440987e5972SCameron Grant return dsp_mmap(d, chan, offset, nprot); 441987e5972SCameron Grant 442987e5972SCameron Grant default: 443987e5972SCameron Grant return -1; 444987e5972SCameron Grant } 445987e5972SCameron Grant } 446987e5972SCameron Grant 447987e5972SCameron Grant static int 448987e5972SCameron Grant status_init(char *buf, int size) 449987e5972SCameron Grant { 450987e5972SCameron Grant int i; 451987e5972SCameron Grant device_t dev; 452987e5972SCameron Grant snddev_info *d; 453987e5972SCameron Grant 454987e5972SCameron Grant snprintf(buf, size, "FreeBSD Audio Driver (newpcm) %s %s\n" 455987e5972SCameron Grant "Installed devices:\n", __DATE__, __TIME__); 456987e5972SCameron Grant 457987e5972SCameron Grant for (i = 0; i <= devclass_get_maxunit(pcm_devclass); i++) { 458987e5972SCameron Grant d = gsd(i); 459987e5972SCameron Grant if (!d) continue; 460987e5972SCameron Grant dev = devclass_get_device(pcm_devclass, i); 461bf8ca271SCameron Grant if (1) { 462bf8ca271SCameron Grant snprintf(buf + strlen(buf), size - strlen(buf), 463bf8ca271SCameron Grant "pcm%d: <%s> %s", 464bf8ca271SCameron Grant i, device_get_desc(dev), d->status); 465bf8ca271SCameron Grant if (d->chancount > 0) 466bf8ca271SCameron Grant snprintf(buf + strlen(buf), size - strlen(buf), 467bf8ca271SCameron Grant " (%dp/%dr channels%s)\n", 468987e5972SCameron Grant d->playcount, d->reccount, 469987e5972SCameron Grant (!(d->flags & SD_F_SIMPLEX))? " duplex" : ""); 470bf8ca271SCameron Grant else 471bf8ca271SCameron Grant snprintf(buf + strlen(buf), size - strlen(buf), 4729bc50208SCameron Grant " (mixer only)\n"); 473bf8ca271SCameron Grant } 474987e5972SCameron Grant } 475987e5972SCameron Grant return strlen(buf); 476987e5972SCameron Grant } 477987e5972SCameron Grant 478987e5972SCameron Grant static int 479987e5972SCameron Grant status_read(struct uio *buf) 480987e5972SCameron Grant { 481987e5972SCameron Grant static char status_buf[4096]; 482987e5972SCameron Grant static int bufptr = 0, buflen = 0; 483987e5972SCameron Grant int l; 484987e5972SCameron Grant 485987e5972SCameron Grant if (status_isopen == 1) { 486987e5972SCameron Grant status_isopen++; 487987e5972SCameron Grant bufptr = 0; 488987e5972SCameron Grant buflen = status_init(status_buf, sizeof status_buf); 489987e5972SCameron Grant } 490987e5972SCameron Grant 491987e5972SCameron Grant l = min(buf->uio_resid, buflen - bufptr); 492987e5972SCameron Grant bufptr += l; 493987e5972SCameron Grant return (l > 0)? uiomove(status_buf + bufptr - l, l, buf) : 0; 494987e5972SCameron Grant } 495