1 /* 2 * Copyright (c) 1999 Cameron Grant <gandalf@vilnya.demon.co.uk> 3 * (C) 1997 Luigi Rizzo (luigi@iet.unipi.it) 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 * $FreeBSD$ 28 */ 29 30 #include <dev/sound/pcm/sound.h> 31 #include <sys/sysctl.h> 32 33 static dev_t status_dev = 0; 34 static int status_isopen = 0; 35 static int status_init(char *buf, int size); 36 static int status_read(struct uio *buf); 37 38 static d_open_t sndopen; 39 static d_close_t sndclose; 40 static d_ioctl_t sndioctl; 41 static d_read_t sndread; 42 static d_write_t sndwrite; 43 static d_mmap_t sndmmap; 44 static d_poll_t sndpoll; 45 46 #define CDEV_MAJOR 30 47 static struct cdevsw snd_cdevsw = { 48 /* open */ sndopen, 49 /* close */ sndclose, 50 /* read */ sndread, 51 /* write */ sndwrite, 52 /* ioctl */ sndioctl, 53 /* poll */ sndpoll, 54 /* mmap */ sndmmap, 55 /* strategy */ nostrategy, 56 /* name */ "snd", 57 /* maj */ CDEV_MAJOR, 58 /* dump */ nodump, 59 /* psize */ nopsize, 60 /* flags */ 0, 61 /* bmaj */ -1 62 }; 63 64 /* 65 PROPOSAL: 66 each unit needs: 67 status, mixer, dsp, dspW, audio, sequencer, midi-in, seq2, sndproc = 9 devices 68 dspW and audio are deprecated. 69 dsp needs min 64 channels, will give it 256 70 71 minor = (unit << 20) + (dev << 16) + channel 72 currently minor = (channel << 16) + (unit << 4) + dev 73 74 nomenclature: 75 /dev/pcmX/dsp.(0..255) 76 /dev/pcmX/dspW 77 /dev/pcmX/audio 78 /dev/pcmX/status 79 /dev/pcmX/mixer 80 [etc.] 81 */ 82 83 #define PCMMINOR(x) (minor(x)) 84 #define PCMCHAN(x) ((PCMMINOR(x) & 0x00ff0000) >> 16) 85 #define PCMUNIT(x) ((PCMMINOR(x) & 0x000000f0) >> 4) 86 #define PCMDEV(x) (PCMMINOR(x) & 0x0000000f) 87 #define PCMMKMINOR(u, d, c) ((((c) & 0xff) << 16) | (((u) & 0x0f) << 4) | ((d) & 0x0f)) 88 89 static devclass_t pcm_devclass; 90 int snd_unit; 91 TUNABLE_INT_DECL("hw.sndunit", 0, snd_unit); 92 93 static void 94 pcm_makelinks(void *dummy) 95 { 96 int unit; 97 dev_t pdev; 98 static dev_t dsp = 0, dspW = 0, audio = 0, mixer = 0; 99 100 if (pcm_devclass == NULL || devfs_present == 0) 101 return; 102 if (dsp) { 103 destroy_dev(dsp); 104 dsp = 0; 105 } 106 if (dspW) { 107 destroy_dev(dspW); 108 dspW = 0; 109 } 110 if (audio) { 111 destroy_dev(audio); 112 audio = 0; 113 } 114 if (mixer) { 115 destroy_dev(mixer); 116 mixer = 0; 117 } 118 119 unit = snd_unit; 120 if (unit < 0 || unit > devclass_get_maxunit(pcm_devclass)) 121 return; 122 if (devclass_get_softc(pcm_devclass, unit) == NULL) 123 return; 124 125 pdev = makedev(CDEV_MAJOR, PCMMKMINOR(unit, SND_DEV_DSP, 0)); 126 dsp = make_dev_alias(pdev, "dsp"); 127 pdev = makedev(CDEV_MAJOR, PCMMKMINOR(unit, SND_DEV_DSP16, 0)); 128 dspW = make_dev_alias(pdev, "dspW"); 129 pdev = makedev(CDEV_MAJOR, PCMMKMINOR(unit, SND_DEV_AUDIO, 0)); 130 audio = make_dev_alias(pdev, "audio"); 131 pdev = makedev(CDEV_MAJOR, PCMMKMINOR(unit, SND_DEV_CTL, 0)); 132 mixer = make_dev_alias(pdev, "mixer"); 133 } 134 135 static int 136 sysctl_hw_sndunit(SYSCTL_HANDLER_ARGS) 137 { 138 int error, unit; 139 140 unit = snd_unit; 141 error = sysctl_handle_int(oidp, &unit, sizeof(unit), req); 142 if (error == 0 && req->newptr != NULL) { 143 snd_unit = unit; 144 pcm_makelinks(NULL); 145 } 146 return (error); 147 } 148 SYSCTL_PROC(_hw, OID_AUTO, sndunit, CTLTYPE_INT | CTLFLAG_RW, 149 0, sizeof(int), sysctl_hw_sndunit, "I", ""); 150 151 int 152 pcm_addchan(device_t dev, int dir, pcm_channel *templ, void *devinfo) 153 { 154 int unit = device_get_unit(dev), idx; 155 snddev_info *d = device_get_softc(dev); 156 pcm_channel *chns, *ch; 157 char *dirs; 158 159 dirs = ((dir == PCMDIR_PLAY)? "play" : "record"); 160 chns = ((dir == PCMDIR_PLAY)? d->play : d->rec); 161 idx = ((dir == PCMDIR_PLAY)? d->playcount++ : d->reccount++); 162 163 if (chns == NULL) { 164 device_printf(dev, "bad channel add (%s:%d)\n", dirs, idx); 165 return 1; 166 } 167 ch = &chns[idx]; 168 *ch = *templ; 169 ch->parent = d; 170 if (chn_init(ch, devinfo, dir)) { 171 device_printf(dev, "chn_init() for (%s:%d) failed\n", dirs, idx); 172 return 1; 173 } 174 make_dev(&snd_cdevsw, PCMMKMINOR(unit, SND_DEV_DSP, d->chancount), 175 UID_ROOT, GID_WHEEL, 0666, "dsp%d.%d", unit, d->chancount); 176 make_dev(&snd_cdevsw, PCMMKMINOR(unit, SND_DEV_DSP16, d->chancount), 177 UID_ROOT, GID_WHEEL, 0666, "dspW%d.%d", unit, d->chancount); 178 make_dev(&snd_cdevsw, PCMMKMINOR(unit, SND_DEV_AUDIO, d->chancount), 179 UID_ROOT, GID_WHEEL, 0666, "audio%d.%d", unit, d->chancount); 180 /* XXX SND_DEV_NORESET? */ 181 d->chancount++; 182 if (d->chancount == d->maxchans) 183 pcm_makelinks(NULL); 184 return 0; 185 } 186 187 static int 188 pcm_killchan(device_t dev, int dir) 189 { 190 int unit = device_get_unit(dev), idx; 191 snddev_info *d = device_get_softc(dev); 192 pcm_channel *chns, *ch; 193 char *dirs; 194 dev_t pdev; 195 196 dirs = ((dir == PCMDIR_PLAY)? "play" : "record"); 197 chns = ((dir == PCMDIR_PLAY)? d->play : d->rec); 198 idx = ((dir == PCMDIR_PLAY)? --d->playcount : --d->reccount); 199 200 if (chns == NULL || idx < 0) { 201 device_printf(dev, "bad channel kill (%s:%d)\n", dirs, idx); 202 return 1; 203 } 204 ch = &chns[idx]; 205 if (chn_kill(ch)) { 206 device_printf(dev, "chn_kill() for (%s:%d) failed\n", dirs, idx); 207 return 1; 208 } 209 d->chancount--; 210 pdev = makedev(CDEV_MAJOR, PCMMKMINOR(unit, SND_DEV_DSP, d->chancount)); 211 destroy_dev(pdev); 212 pdev = makedev(CDEV_MAJOR, PCMMKMINOR(unit, SND_DEV_DSP16, d->chancount)); 213 destroy_dev(pdev); 214 pdev = makedev(CDEV_MAJOR, PCMMKMINOR(unit, SND_DEV_AUDIO, d->chancount)); 215 destroy_dev(pdev); 216 return 0; 217 } 218 219 int 220 pcm_setstatus(device_t dev, char *str) 221 { 222 snddev_info *d = device_get_softc(dev); 223 strncpy(d->status, str, SND_STATUSLEN); 224 return 0; 225 } 226 227 u_int32_t 228 pcm_getflags(device_t dev) 229 { 230 snddev_info *d = device_get_softc(dev); 231 return d->flags; 232 } 233 234 void 235 pcm_setflags(device_t dev, u_int32_t val) 236 { 237 snddev_info *d = device_get_softc(dev); 238 d->flags = val; 239 } 240 241 void * 242 pcm_getdevinfo(device_t dev) 243 { 244 snddev_info *d = device_get_softc(dev); 245 return d->devinfo; 246 } 247 248 void 249 pcm_setswap(device_t dev, pcm_swap_t *swap) 250 { 251 snddev_info *d = device_get_softc(dev); 252 d->swap = swap; 253 } 254 255 /* This is the generic init routine */ 256 int 257 pcm_register(device_t dev, void *devinfo, int numplay, int numrec) 258 { 259 int sz, unit = device_get_unit(dev); 260 snddev_info *d = device_get_softc(dev); 261 262 if (!pcm_devclass) { 263 pcm_devclass = device_get_devclass(dev); 264 status_dev = make_dev(&snd_cdevsw, PCMMKMINOR(0, SND_DEV_STATUS, 0), 265 UID_ROOT, GID_WHEEL, 0444, "sndstat"); 266 } 267 make_dev(&snd_cdevsw, PCMMKMINOR(unit, SND_DEV_CTL, 0), 268 UID_ROOT, GID_WHEEL, 0666, "mixer%d", unit); 269 d->dev = dev; 270 d->devinfo = devinfo; 271 d->chancount = d->playcount = d->reccount = 0; 272 d->maxchans = numplay + numrec; 273 sz = (numplay + numrec) * sizeof(pcm_channel *); 274 275 if (sz > 0) { 276 d->aplay = (pcm_channel **)malloc(sz, M_DEVBUF, M_NOWAIT); 277 if (!d->aplay) goto no; 278 bzero(d->aplay, sz); 279 280 d->arec = (pcm_channel **)malloc(sz, M_DEVBUF, M_NOWAIT); 281 if (!d->arec) goto no; 282 bzero(d->arec, sz); 283 284 sz = (numplay + numrec) * sizeof(int); 285 d->ref = (int *)malloc(sz, M_DEVBUF, M_NOWAIT); 286 if (!d->ref) goto no; 287 bzero(d->ref, sz); 288 } 289 290 if (numplay > 0) { 291 d->play = (pcm_channel *)malloc(numplay * sizeof(pcm_channel), 292 M_DEVBUF, M_NOWAIT); 293 if (!d->play) goto no; 294 bzero(d->play, numplay * sizeof(pcm_channel)); 295 } else 296 d->play = NULL; 297 298 if (numrec > 0) { 299 d->rec = (pcm_channel *)malloc(numrec * sizeof(pcm_channel), 300 M_DEVBUF, M_NOWAIT); 301 if (!d->rec) goto no; 302 bzero(d->rec, numrec * sizeof(pcm_channel)); 303 } else 304 d->rec = NULL; 305 306 if (numplay == 0 || numrec == 0) 307 d->flags |= SD_F_SIMPLEX; 308 309 fkchan_setup(&d->fakechan); 310 chn_init(&d->fakechan, NULL, 0); 311 d->magic = MAGIC(unit); /* debugging... */ 312 d->swap = NULL; 313 314 return 0; 315 no: 316 if (d->aplay) free(d->aplay, M_DEVBUF); 317 if (d->play) free(d->play, M_DEVBUF); 318 if (d->arec) free(d->arec, M_DEVBUF); 319 if (d->rec) free(d->rec, M_DEVBUF); 320 if (d->ref) free(d->ref, M_DEVBUF); 321 return ENXIO; 322 } 323 324 int 325 pcm_unregister(device_t dev) 326 { 327 int r, i, unit = device_get_unit(dev); 328 snddev_info *d = device_get_softc(dev); 329 dev_t pdev; 330 331 r = 0; 332 for (i = 0; i < d->chancount; i++) 333 if (d->ref[i]) r = EBUSY; 334 if (r) { 335 device_printf(dev, "unregister: channel busy"); 336 return r; 337 } 338 if (mixer_isbusy(d)) { 339 device_printf(dev, "unregister: mixer busy"); 340 return EBUSY; 341 } 342 343 pdev = makedev(CDEV_MAJOR, PCMMKMINOR(unit, SND_DEV_CTL, 0)); 344 destroy_dev(pdev); 345 mixer_uninit(dev); 346 347 while (d->playcount > 0) 348 pcm_killchan(dev, PCMDIR_PLAY); 349 while (d->reccount > 0) 350 pcm_killchan(dev, PCMDIR_REC); 351 d->magic = 0; 352 353 if (d->aplay) free(d->aplay, M_DEVBUF); 354 if (d->play) free(d->play, M_DEVBUF); 355 if (d->arec) free(d->arec, M_DEVBUF); 356 if (d->rec) free(d->rec, M_DEVBUF); 357 if (d->ref) free(d->ref, M_DEVBUF); 358 359 pcm_makelinks(NULL); 360 return 0; 361 } 362 363 /* 364 * a small utility function which, given a device number, returns 365 * a pointer to the associated snddev_info struct, and sets the unit 366 * number. 367 */ 368 static snddev_info * 369 get_snddev_info(dev_t i_dev, int *unit, int *dev, int *chan) 370 { 371 snddev_info *sc; 372 int u, d, c; 373 374 u = PCMUNIT(i_dev); 375 d = PCMDEV(i_dev); 376 c = PCMCHAN(i_dev); 377 if (u > devclass_get_maxunit(pcm_devclass)) u = -1; 378 if (unit) *unit = u; 379 if (dev) *dev = d; 380 if (chan) *chan = c; 381 if (u < 0) return NULL; 382 383 sc = devclass_get_softc(pcm_devclass, u); 384 if (sc == NULL || sc->magic == 0) return NULL; 385 386 switch(d) { 387 case SND_DEV_CTL: /* /dev/mixer handled by pcm */ 388 case SND_DEV_STATUS: /* /dev/sndstat handled by pcm */ 389 case SND_DEV_DSP: 390 case SND_DEV_DSP16: 391 case SND_DEV_AUDIO: 392 return sc; 393 394 case SND_DEV_SEQ: /* XXX when enabled... */ 395 case SND_DEV_SEQ2: 396 case SND_DEV_MIDIN: 397 case SND_DEV_SNDPROC: /* /dev/sndproc handled by pcm */ 398 default: 399 printf("unsupported subdevice %d\n", d); 400 return NULL; 401 } 402 } 403 404 static int 405 sndopen(dev_t i_dev, int flags, int mode, struct proc *p) 406 { 407 int dev, unit, chan; 408 snddev_info *d = get_snddev_info(i_dev, &unit, &dev, &chan); 409 410 DEB(printf("open snd%d subdev %d flags 0x%08x mode 0x%08x\n", 411 unit, dev, flags, mode)); 412 413 switch(dev) { 414 case SND_DEV_STATUS: 415 if (status_isopen) return EBUSY; 416 status_isopen = 1; 417 return 0; 418 419 case SND_DEV_CTL: 420 return d? mixer_busy(d, 1) : ENXIO; 421 422 case SND_DEV_AUDIO: 423 case SND_DEV_DSP: 424 case SND_DEV_DSP16: 425 case SND_DEV_NORESET: 426 return d? dsp_open(d, chan, flags, dev) : ENXIO; 427 428 default: 429 return ENXIO; 430 } 431 } 432 433 static int 434 sndclose(dev_t i_dev, int flags, int mode, struct proc *p) 435 { 436 int dev, unit, chan; 437 snddev_info *d = get_snddev_info(i_dev, &unit, &dev, &chan); 438 439 DEB(printf("close snd%d subdev %d\n", unit, dev)); 440 441 switch(dev) { /* only those for which close makes sense */ 442 case SND_DEV_STATUS: 443 if (!status_isopen) return EBADF; 444 status_isopen = 0; 445 return 0; 446 447 case SND_DEV_CTL: 448 return d? mixer_busy(d, 0) : ENXIO; 449 450 case SND_DEV_AUDIO: 451 case SND_DEV_DSP: 452 case SND_DEV_DSP16: 453 return d? dsp_close(d, chan, dev) : ENXIO; 454 455 default: 456 return ENXIO; 457 } 458 } 459 460 static int 461 sndread(dev_t i_dev, struct uio *buf, int flag) 462 { 463 int dev, unit, chan; 464 snddev_info *d = get_snddev_info(i_dev, &unit, &dev, &chan); 465 DEB(printf("read snd%d subdev %d flag 0x%08x\n", unit, dev, flag)); 466 467 switch(dev) { 468 case SND_DEV_STATUS: 469 return status_isopen? status_read(buf) : EBADF; 470 471 case SND_DEV_AUDIO: 472 case SND_DEV_DSP: 473 case SND_DEV_DSP16: 474 return d? dsp_read(d, chan, buf, flag) : EBADF; 475 476 default: 477 return ENXIO; 478 } 479 } 480 481 static int 482 sndwrite(dev_t i_dev, struct uio *buf, int flag) 483 { 484 int dev, unit, chan; 485 snddev_info *d = get_snddev_info(i_dev, &unit, &dev, &chan); 486 487 DEB(printf("write snd%d subdev %d flag 0x%08x\n", unit, dev & 0xf, flag)); 488 489 switch(dev) { /* only writeable devices */ 490 case SND_DEV_DSP: 491 case SND_DEV_DSP16: 492 case SND_DEV_AUDIO: 493 return d? dsp_write(d, chan, buf, flag) : EBADF; 494 495 default: 496 return EPERM; /* for non-writeable devices ; */ 497 } 498 } 499 500 static int 501 sndioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct proc * p) 502 { 503 int dev, chan; 504 snddev_info *d = get_snddev_info(i_dev, NULL, &dev, &chan); 505 506 if (d == NULL) return ENXIO; 507 508 switch(dev) { 509 case SND_DEV_CTL: 510 return mixer_ioctl(d, cmd, arg); 511 512 case SND_DEV_AUDIO: 513 case SND_DEV_DSP: 514 case SND_DEV_DSP16: 515 if (IOCGROUP(cmd) == 'M') 516 return mixer_ioctl(d, cmd, arg); 517 else 518 return dsp_ioctl(d, chan, cmd, arg); 519 520 default: 521 return ENXIO; 522 } 523 } 524 525 static int 526 sndpoll(dev_t i_dev, int events, struct proc *p) 527 { 528 int dev, chan; 529 snddev_info *d = get_snddev_info(i_dev, NULL, &dev, &chan); 530 531 DEB(printf("sndpoll d 0x%p dev 0x%04x events 0x%08x\n", d, dev, events)); 532 533 if (d == NULL) return ENXIO; 534 535 switch(dev) { 536 case SND_DEV_AUDIO: 537 case SND_DEV_DSP: 538 case SND_DEV_DSP16: 539 return dsp_poll(d, chan, events, p); 540 541 default: 542 return (events & 543 (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM)) | POLLHUP; 544 } 545 } 546 547 /* 548 * The mmap interface allows access to the play and read buffer, 549 * plus the device descriptor. 550 * The various blocks are accessible at the following offsets: 551 * 552 * 0x00000000 ( 0 ) : write buffer ; 553 * 0x01000000 (16 MB) : read buffer ; 554 * 0x02000000 (32 MB) : device descriptor (dangerous!) 555 * 556 * WARNING: the mmap routines assume memory areas are aligned. This 557 * is true (probably) for the dma buffers, but likely false for the 558 * device descriptor. As a consequence, we do not know where it is 559 * located in the requested area. 560 */ 561 static int 562 sndmmap(dev_t i_dev, vm_offset_t offset, int nprot) 563 { 564 int unit, dev, chan; 565 snddev_info *d = get_snddev_info(i_dev, &unit, &dev, &chan); 566 567 DEB(printf("sndmmap d 0x%p dev 0x%04x ofs 0x%08x nprot 0x%08x\n", 568 d, dev, offset, nprot)); 569 570 if (d == NULL || nprot & PROT_EXEC) return -1; /* forbidden */ 571 572 switch(dev) { 573 case SND_DEV_AUDIO: 574 case SND_DEV_DSP: 575 case SND_DEV_DSP16: 576 return dsp_mmap(d, chan, offset, nprot); 577 578 default: 579 return -1; 580 } 581 } 582 583 static int 584 status_init(char *buf, int size) 585 { 586 int i; 587 device_t dev; 588 snddev_info *d; 589 590 snprintf(buf, size, "FreeBSD Audio Driver (newpcm) %s %s\n" 591 "Installed devices:\n", __DATE__, __TIME__); 592 593 for (i = 0; i <= devclass_get_maxunit(pcm_devclass); i++) { 594 d = devclass_get_softc(pcm_devclass, i); 595 if (!d) continue; 596 dev = devclass_get_device(pcm_devclass, i); 597 if (1) { 598 snprintf(buf + strlen(buf), size - strlen(buf), 599 "pcm%d: <%s> %s", 600 i, device_get_desc(dev), d->status); 601 if (d->chancount > 0) 602 snprintf(buf + strlen(buf), size - strlen(buf), 603 " (%dp/%dr channels%s)\n", 604 d->playcount, d->reccount, 605 (!(d->flags & SD_F_SIMPLEX))? " duplex" : ""); 606 else 607 snprintf(buf + strlen(buf), size - strlen(buf), 608 " (mixer only)\n"); 609 } 610 } 611 return strlen(buf); 612 } 613 614 static int 615 status_read(struct uio *buf) 616 { 617 static char status_buf[4096]; 618 static int bufptr = 0, buflen = 0; 619 int l; 620 621 if (status_isopen == 1) { 622 status_isopen++; 623 bufptr = 0; 624 buflen = status_init(status_buf, sizeof status_buf); 625 } 626 627 l = min(buf->uio_resid, buflen - bufptr); 628 bufptr += l; 629 return (l > 0)? uiomove(status_buf + bufptr - l, l, buf) : 0; 630 } 631 632 static int 633 sndpcm_modevent(module_t mod, int type, void *data) 634 { 635 636 switch (type) { 637 case MOD_LOAD: 638 break; 639 case MOD_UNLOAD: 640 if (status_isopen) 641 return EBUSY; 642 if (status_dev) 643 destroy_dev(status_dev); 644 status_dev = 0; 645 break; 646 default: 647 break; 648 } 649 return 0; 650 } 651 652 static moduledata_t sndpcm_mod = { 653 "snd_pcm", 654 sndpcm_modevent, 655 NULL 656 }; 657 DECLARE_MODULE(snd_pcm, sndpcm_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); 658 MODULE_VERSION(snd_pcm, PCM_MODVER); 659