1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25 /* 26 * Sun audio(7I) and mixer(7I) personality. 27 * 28 * There are some "undocumented" details of how legacy Sun audio 29 * interfaces work. The following "rules" were derived from reading the 30 * legacy Sun mixer code, and to the best of our knowledge are not 31 * documented elsewhere. 32 * 33 * - We create a "fake" audio device, which behaves like a classic 34 * exclusive audio device, for each PID, as determined during open(2). 35 * 36 * - Different processes don't interfere with each other. Even though 37 * they are running concurrently, they each think they have exclusive 38 * control over the audio device. 39 * 40 * - Read and write directions operate independent of each other. That 41 * is, a device open for reading won't intefere with a future open for 42 * writing, and vice versa. This is true even within the same process. 43 * 44 * - Because the virtualization is by PID, strange behavior may occur 45 * if a process tries to open an audio device at the same time it 46 * has already received a file descriptor from another process (such 47 * through inheritence via fork()). 48 * 49 * - The "fake" audio device has no control over physical settings. 50 * It sees only the software attenuation-based volumes for play and 51 * record, and has no support for alternate input or output ports or 52 * access to the monitoring features of the hardware. 53 * 54 * - Explicit notificaton signals (SIGPOLL) are only ever sent up the 55 * audioctl node -- never up a regular audio node. (The stream head 56 * may still issue SIGPOLL based on readability/writability of 57 * course.) 58 * 59 * - Corollary: processes that want asynch. notifications will open 60 * /dev/audioctl as well as /dev/audio. 61 * 62 * - We don't support the MIXER mode at all. 63 * 64 * - By corollary, a process is only allowed to open /dev/audio once 65 * (in each direction.) 66 * 67 * - Attempts to open /dev/audio in duplex mode (O_RDWR) fail (EBUSY) 68 * if the device cannot support duplex operation. 69 * 70 * - Attempts to open a device with FREAD set fail if the device is not 71 * capable of recording. (Likewise for FWRITE and playback.) 72 * 73 * - No data transfer is permitted for audioctl nodes. (No actual 74 * record or play.) 75 * 76 * - Sun audio does not support any formats other than linear and 77 * ULAW/ALAW. I.e. it will never support AC3 or other "opaque" 78 * streams which require special handling. 79 * 80 * - Sun audio only supports stereo or monophonic data streams. 81 */ 82 83 #include <sys/types.h> 84 #include <sys/open.h> 85 #include <sys/errno.h> 86 #include <sys/audio.h> 87 #include <sys/mixer.h> 88 #include <sys/file.h> 89 #include <sys/stropts.h> 90 #include <sys/strsun.h> 91 #include <sys/sysmacros.h> 92 #include <sys/list.h> 93 #include <sys/note.h> 94 #include <sys/stat.h> 95 #include <sys/ddi.h> 96 #include <sys/sunddi.h> 97 #include "audio_client.h" 98 99 typedef struct daclient daclient_t; 100 typedef struct dadev dadev_t; 101 typedef struct daproc daproc_t; 102 103 /* common structure shared between both audioctl and audio nodes */ 104 struct daclient { 105 daproc_t *dc_proc; 106 dadev_t *dc_dev; 107 audio_client_t *dc_client; 108 queue_t *dc_wq; 109 unsigned dc_eof; 110 list_t dc_eofcnt; 111 kmutex_t dc_lock; 112 mblk_t *dc_draining; 113 }; 114 115 struct eofcnt { 116 list_node_t linkage; 117 uint64_t tail; 118 }; 119 120 struct dadev { 121 audio_dev_t *d_dev; 122 123 list_t d_procs; 124 kmutex_t d_mx; 125 kcondvar_t d_cv; 126 }; 127 128 struct daproc { 129 pid_t p_id; 130 struct audio_info p_info; 131 int p_refcnt; 132 int p_oflag; 133 list_node_t p_linkage; 134 dadev_t *p_dev; 135 audio_client_t *p_writer; 136 audio_client_t *p_reader; 137 }; 138 139 int devaudio_proc_hold(audio_client_t *, int); 140 void devaudio_proc_release(audio_client_t *); 141 static void devaudio_proc_update(daproc_t *); 142 143 144 static int 145 devaudio_compose_format(audio_prinfo_t *prinfo) 146 { 147 switch (prinfo->precision) { 148 case 8: 149 switch (prinfo->encoding) { 150 case AUDIO_ENCODING_ULAW: 151 return (AUDIO_FORMAT_ULAW); 152 case AUDIO_ENCODING_ALAW: 153 return (AUDIO_FORMAT_ALAW); 154 case AUDIO_ENCODING_LINEAR8: 155 return (AUDIO_FORMAT_U8); 156 case AUDIO_ENCODING_LINEAR: 157 return (AUDIO_FORMAT_S8); 158 } 159 break; 160 case 16: 161 if (prinfo->encoding == AUDIO_ENCODING_LINEAR) 162 return (AUDIO_FORMAT_S16_NE); 163 break; 164 case 32: 165 if (prinfo->encoding == AUDIO_ENCODING_LINEAR) 166 return (AUDIO_FORMAT_S32_NE); 167 break; 168 } 169 return (AUDIO_FORMAT_NONE); 170 171 } 172 173 static void 174 devaudio_decompose_format(audio_prinfo_t *prinfo, int afmt) 175 { 176 int e, p; 177 178 /* 179 * N.B.: Even though some of the formats below can't be set by 180 * this personality, reporting them (using the closest match) 181 * allows this personality to roughly approximate settings for 182 * other streams. It would be incredibly poor form for any 183 * personality to modify the format settings for a different 184 * personality, so we don't worry about that case. 185 */ 186 187 switch (afmt) { 188 case AUDIO_FORMAT_ULAW: 189 e = AUDIO_ENCODING_ULAW; 190 p = 8; 191 break; 192 193 case AUDIO_FORMAT_ALAW: 194 e = AUDIO_ENCODING_ALAW; 195 p = 8; 196 break; 197 198 case AUDIO_FORMAT_U8: 199 e = AUDIO_ENCODING_LINEAR8; 200 p = 8; 201 break; 202 203 case AUDIO_FORMAT_S8: 204 e = AUDIO_ENCODING_LINEAR; 205 p = 8; 206 break; 207 208 case AUDIO_FORMAT_S16_NE: 209 case AUDIO_FORMAT_S16_OE: 210 case AUDIO_FORMAT_U16_NE: 211 case AUDIO_FORMAT_U16_OE: 212 e = AUDIO_ENCODING_LINEAR; 213 p = 16; 214 break; 215 216 case AUDIO_FORMAT_S24_NE: 217 case AUDIO_FORMAT_S24_OE: 218 case AUDIO_FORMAT_S24_PACKED: 219 e = AUDIO_ENCODING_LINEAR; 220 p = 24; 221 break; 222 223 case AUDIO_FORMAT_S32_NE: 224 case AUDIO_FORMAT_S32_OE: 225 e = AUDIO_ENCODING_LINEAR; 226 p = 32; 227 break; 228 229 default: 230 /* all other formats (e.g. AC3) are uninterpreted */ 231 e = AUDIO_ENCODING_NONE; 232 p = 32; 233 break; 234 } 235 236 prinfo->encoding = e; 237 prinfo->precision = p; 238 } 239 240 static daproc_t * 241 devaudio_proc_alloc(audio_client_t *c) 242 { 243 audio_info_t *info; 244 audio_prinfo_t *prinfo; 245 uint32_t caps; 246 daproc_t *proc; 247 248 if ((proc = kmem_zalloc(sizeof (*proc), KM_NOSLEEP)) == NULL) { 249 return (NULL); 250 } 251 info = &proc->p_info; 252 253 /* 254 * audio(7I) says: Upon the initial open() of the audio 255 * device, the driver resets the data format of the device to 256 * the default state of 8-bit, 8Khz, mono u-Law data. 257 */ 258 prinfo = &info->play; 259 prinfo->channels = 1; 260 prinfo->sample_rate = 8000; 261 prinfo->encoding = AUDIO_ENCODING_ULAW; 262 prinfo->precision = 8; 263 prinfo->gain = AUDIO_MAX_GAIN; 264 prinfo->balance = AUDIO_MID_BALANCE; 265 prinfo->buffer_size = 8192; 266 prinfo->pause = B_FALSE; 267 prinfo->waiting = B_FALSE; 268 prinfo->open = B_FALSE; 269 prinfo->active = B_FALSE; 270 prinfo->samples = 0; 271 prinfo->eof = 0; 272 prinfo->error = 0; 273 prinfo->minordev = 0; 274 prinfo->port = AUDIO_SPEAKER; 275 prinfo->avail_ports = AUDIO_SPEAKER; 276 prinfo->mod_ports = AUDIO_NONE; 277 prinfo->_xxx = 0; 278 279 prinfo = &info->record; 280 prinfo->channels = 1; 281 prinfo->sample_rate = 8000; 282 prinfo->encoding = AUDIO_ENCODING_ULAW; 283 prinfo->precision = 8; 284 prinfo->gain = AUDIO_MAX_GAIN; 285 prinfo->balance = AUDIO_MID_BALANCE; 286 prinfo->buffer_size = 8192; 287 prinfo->waiting = B_FALSE; 288 prinfo->open = B_FALSE; 289 prinfo->active = B_FALSE; 290 prinfo->samples = 0; 291 prinfo->eof = 0; 292 prinfo->error = 0; 293 prinfo->minordev = 0; 294 prinfo->port = AUDIO_MICROPHONE; 295 prinfo->avail_ports = AUDIO_MICROPHONE; 296 prinfo->mod_ports = AUDIO_MICROPHONE; 297 298 info->output_muted = B_FALSE; 299 /* pretend we don't have a software mixer - we don't support the API */ 300 info->hw_features = 0; 301 info->sw_features = 0; 302 info->sw_features_enabled = 0; 303 304 caps = auclnt_get_dev_capab(auclnt_get_dev(c)); 305 if (caps & AUDIO_CLIENT_CAP_PLAY) 306 info->hw_features |= AUDIO_HWFEATURE_PLAY; 307 if (caps & AUDIO_CLIENT_CAP_RECORD) 308 info->hw_features |= AUDIO_HWFEATURE_RECORD; 309 if (caps & AUDIO_CLIENT_CAP_DUPLEX) 310 info->hw_features |= AUDIO_HWFEATURE_DUPLEX; 311 312 return (proc); 313 } 314 315 static void 316 devaudio_proc_free(daproc_t *proc) 317 { 318 kmem_free(proc, sizeof (*proc)); 319 } 320 321 int 322 devaudio_proc_hold(audio_client_t *c, int oflag) 323 { 324 pid_t pid; 325 daproc_t *proc; 326 dadev_t *dev; 327 daclient_t *dc; 328 list_t *l; 329 audio_dev_t *adev; 330 int rv; 331 332 adev = auclnt_get_dev(c); 333 334 /* first allocate and initialize the daclient private data */ 335 if ((dc = kmem_zalloc(sizeof (*dc), KM_NOSLEEP)) == NULL) { 336 return (ENOMEM); 337 } 338 339 mutex_init(&dc->dc_lock, NULL, MUTEX_DRIVER, NULL); 340 list_create(&dc->dc_eofcnt, sizeof (struct eofcnt), 341 offsetof(struct eofcnt, linkage)); 342 auclnt_set_private(c, dc); 343 344 dev = auclnt_get_dev_minor_data(adev, AUDIO_MINOR_DEVAUDIO); 345 l = &dev->d_procs; 346 pid = auclnt_get_pid(c); 347 348 /* set a couple of common fields */ 349 dc->dc_client = c; 350 dc->dc_dev = dev; 351 352 mutex_enter(&dev->d_mx); 353 for (proc = list_head(l); proc != NULL; proc = list_next(l, proc)) { 354 if (proc->p_id == pid) { 355 proc->p_refcnt++; 356 break; 357 } 358 } 359 if (proc == NULL) { 360 if ((proc = devaudio_proc_alloc(c)) == NULL) { 361 rv = ENOMEM; 362 goto failed; 363 } 364 proc->p_refcnt = 1; 365 proc->p_id = pid; 366 proc->p_dev = dev; 367 list_insert_tail(l, proc); 368 } 369 370 while (proc->p_oflag & oflag) { 371 372 if (oflag & (FNDELAY|FNONBLOCK)) { 373 rv = EBUSY; 374 goto failed; 375 } 376 if (oflag & FWRITE) 377 proc->p_info.play.waiting++; 378 if (oflag & FREAD) 379 proc->p_info.record.waiting++; 380 if (cv_wait_sig(&dev->d_cv, &dev->d_mx) == 0) { 381 /* interrupted! */ 382 if (oflag & FWRITE) 383 proc->p_info.play.waiting--; 384 if (oflag & FREAD) 385 proc->p_info.record.waiting--; 386 rv = EINTR; 387 goto failed; 388 } 389 if (oflag & FWRITE) 390 proc->p_info.play.waiting--; 391 if (oflag & FREAD) 392 proc->p_info.record.waiting--; 393 } 394 395 if (oflag & FWRITE) { 396 audio_prinfo_t *play = &proc->p_info.play; 397 audio_stream_t *sp = auclnt_output_stream(c); 398 399 if (((rv = auclnt_set_rate(sp, 8000)) != 0) || 400 ((rv = auclnt_set_format(sp, AUDIO_FORMAT_ULAW)) != 0) || 401 ((rv = auclnt_set_channels(sp, 1)) != 0)) { 402 goto failed; 403 } 404 405 auclnt_set_samples(sp, 0); 406 auclnt_set_errors(sp, 0); 407 play->eof = 0; 408 play->buffer_size = 8192; 409 410 auclnt_set_gain(sp, ((play->gain * 100) / AUDIO_MAX_GAIN)); 411 auclnt_set_muted(sp, proc->p_info.output_muted); 412 play->open = B_TRUE; 413 proc->p_writer = c; 414 proc->p_oflag |= FWRITE; 415 } 416 417 if (oflag & FREAD) { 418 audio_prinfo_t *rec = &proc->p_info.record; 419 audio_stream_t *sp = auclnt_input_stream(c); 420 421 if (((rv = auclnt_set_rate(sp, 8000)) != 0) || 422 ((rv = auclnt_set_format(sp, AUDIO_FORMAT_ULAW)) != 0) || 423 ((rv = auclnt_set_channels(sp, 1)) != 0)) { 424 goto failed; 425 } 426 427 auclnt_set_samples(sp, 0); 428 auclnt_set_errors(sp, 0); 429 rec->eof = 0; 430 rec->buffer_size = 8192; 431 432 auclnt_set_gain(sp, ((rec->gain * 100) / AUDIO_MAX_GAIN)); 433 rec->open = B_TRUE; 434 proc->p_reader = c; 435 proc->p_oflag |= FREAD; 436 } 437 438 439 dc->dc_wq = auclnt_get_wq(c); 440 441 /* we update the s_proc last to avoid a race */ 442 dc->dc_proc = proc; 443 444 devaudio_proc_update(proc); 445 446 mutex_exit(&dev->d_mx); 447 448 return (0); 449 450 failed: 451 mutex_exit(&dev->d_mx); 452 devaudio_proc_release(c); 453 return (rv); 454 455 } 456 457 static void 458 devaudio_clear_eof(audio_client_t *c) 459 { 460 struct eofcnt *eof; 461 daclient_t *dc; 462 463 dc = auclnt_get_private(c); 464 mutex_enter(&dc->dc_lock); 465 while ((eof = list_remove_head(&dc->dc_eofcnt)) != NULL) { 466 kmem_free(eof, sizeof (*eof)); 467 } 468 mutex_exit(&dc->dc_lock); 469 } 470 471 void 472 devaudio_proc_release(audio_client_t *c) 473 { 474 daproc_t *proc; 475 dadev_t *dev; 476 mblk_t *mp; 477 daclient_t *dc; 478 479 dc = auclnt_get_private(c); 480 proc = dc->dc_proc; 481 dev = dc->dc_dev; 482 dc->dc_proc = NULL; 483 484 mutex_enter(&dev->d_mx); 485 486 if (proc != NULL) { 487 proc->p_refcnt--; 488 ASSERT(proc->p_refcnt >= 0); 489 490 if (c == proc->p_writer) { 491 proc->p_oflag &= ~FWRITE; 492 proc->p_writer = NULL; 493 } 494 if (c == proc->p_reader) { 495 proc->p_oflag &= ~FREAD; 496 proc->p_reader = NULL; 497 } 498 cv_broadcast(&dev->d_cv); 499 500 if (proc->p_refcnt == 0) { 501 list_remove(&dev->d_procs, proc); 502 devaudio_proc_free(proc); 503 } 504 dc->dc_proc = NULL; 505 } 506 507 mutex_exit(&dev->d_mx); 508 509 devaudio_clear_eof(c); 510 511 while ((mp = dc->dc_draining) != NULL) { 512 dc->dc_draining = mp->b_next; 513 mp->b_next = NULL; 514 freemsg(mp); 515 } 516 517 mutex_destroy(&dc->dc_lock); 518 list_destroy(&dc->dc_eofcnt); 519 kmem_free(dc, sizeof (*dc)); 520 } 521 522 static void 523 devaudio_input(audio_client_t *c) 524 { 525 audio_stream_t *sp = auclnt_input_stream(c); 526 daclient_t *dc = auclnt_get_private(c); 527 unsigned framesz = auclnt_get_framesz(sp); 528 queue_t *rq = auclnt_get_rq(c); 529 mblk_t *mp; 530 unsigned nbytes = dc->dc_proc->p_info.record.buffer_size; 531 unsigned count = nbytes / framesz; 532 533 /* 534 * Potentially send a message upstream with the record data. 535 * We collect this up in chunks of the buffer size requested 536 * by the client. 537 */ 538 539 while (auclnt_get_count(sp) >= count) { 540 541 if ((!canput(rq)) || 542 ((mp = allocb(nbytes, BPRI_MED)) == NULL)) { 543 /* 544 * This will apply back pressure to the 545 * buffer. We haven't yet lost any data, we 546 * just can't send it up. The point at which 547 * we have an unrecoverable overrun is in the 548 * buffer, not in the streams queue. So, no 549 * need to do anything right now. 550 * 551 * Note that since recording is enabled, we 552 * expect that the callback routine will be 553 * called repeatedly & regularly, so we don't 554 * have to worry about leaving data orphaned 555 * in the queue. 556 */ 557 break; 558 } 559 560 (void) auclnt_consume_data(sp, (caddr_t)mp->b_wptr, count); 561 mp->b_wptr += nbytes; 562 (void) putq(rq, mp); 563 } 564 } 565 566 static void 567 devaudio_proc_update(daproc_t *proc) 568 { 569 audio_info_t *info; 570 audio_stream_t *sp; 571 audio_client_t *c; 572 573 info = &proc->p_info; 574 575 ASSERT(mutex_owned(&proc->p_dev->d_mx)); 576 577 if ((c = proc->p_writer) != NULL) { 578 sp = auclnt_output_stream(c); 579 580 info->play.sample_rate = auclnt_get_rate(sp); 581 info->play.channels = auclnt_get_channels(sp); 582 devaudio_decompose_format(&info->play, auclnt_get_format(sp)); 583 584 info->play.gain = 585 (auclnt_get_gain(sp) * AUDIO_MAX_GAIN) / 100; 586 info->play.pause = auclnt_is_paused(sp); 587 info->play.active = auclnt_is_running(sp); 588 info->play.samples = auclnt_get_samples(sp); 589 info->play.error = auclnt_get_errors(sp) ? B_TRUE : B_FALSE; 590 info->output_muted = auclnt_get_muted(sp); 591 } else { 592 info->play.encoding = AUDIO_ENCODING_NONE; 593 info->play.precision = 0; 594 info->play.sample_rate = 0; 595 info->play.pause = B_FALSE; 596 info->play.active = B_FALSE; 597 info->play.error = B_FALSE; 598 info->play.samples = 0; 599 } 600 601 if ((c = proc->p_reader) != NULL) { 602 sp = auclnt_input_stream(c); 603 604 info->record.sample_rate = auclnt_get_rate(sp); 605 info->record.channels = auclnt_get_channels(sp); 606 devaudio_decompose_format(&info->record, auclnt_get_format(sp)); 607 608 info->record.gain = 609 (auclnt_get_gain(sp) * AUDIO_MAX_GAIN) / 100; 610 info->record.pause = auclnt_is_paused(sp); 611 info->record.active = auclnt_is_running(sp); 612 info->record.samples = auclnt_get_samples(sp); 613 info->record.error = auclnt_get_errors(sp) ? B_TRUE : B_FALSE; 614 } else { 615 info->record.encoding = AUDIO_ENCODING_NONE; 616 info->record.precision = 0; 617 info->record.sample_rate = 0; 618 info->record.pause = B_FALSE; 619 info->record.active = B_FALSE; 620 info->record.error = B_FALSE; 621 info->record.samples = 0; 622 } 623 } 624 625 static void 626 devaudio_ioc_getinfo(queue_t *wq, audio_client_t *c, mblk_t *mp) 627 { 628 daclient_t *dc = auclnt_get_private(c); 629 daproc_t *proc = dc->dc_proc; 630 mblk_t *bcont; 631 632 if ((bcont = allocb(sizeof (audio_info_t), BPRI_MED)) == NULL) { 633 miocnak(wq, mp, 0, ENOMEM); 634 return; 635 } 636 637 mutex_enter(&dc->dc_dev->d_mx); 638 devaudio_proc_update(proc); 639 bcopy(&proc->p_info, bcont->b_wptr, sizeof (audio_info_t)); 640 mutex_exit(&dc->dc_dev->d_mx); 641 642 bcont->b_wptr += sizeof (audio_info_t); 643 644 mcopyout(mp, NULL, sizeof (audio_info_t), NULL, bcont); 645 qreply(wq, mp); 646 } 647 648 #define CHANGED(new, old, field) \ 649 ((new->field != ((uint32_t)~0)) && (new->field != old->field)) 650 #define CHANGED8(new, old, field) \ 651 ((new->field != ((uint8_t)~0)) && (new->field != old->field)) 652 653 static void 654 devaudio_ioc_setinfo(queue_t *wq, audio_client_t *c, mblk_t *mp) 655 { 656 daclient_t *dc; 657 daproc_t *proc; 658 audio_info_t *oinfo; 659 audio_info_t *ninfo; 660 audio_prinfo_t *npr; 661 audio_prinfo_t *opr; 662 663 int pfmt = AUDIO_FORMAT_NONE; 664 int rfmt = AUDIO_FORMAT_NONE; 665 666 boolean_t reader; 667 boolean_t writer; 668 boolean_t isctl; 669 audio_stream_t *sp; 670 int rv; 671 caddr_t uaddr; 672 mblk_t *bcont; 673 674 struct copyresp *csp; 675 676 if (DB_TYPE(mp) == M_IOCTL) { 677 /* the special value "1" indicates that this is a copyin */ 678 uaddr = *(caddr_t *)(void *)mp->b_cont->b_rptr; 679 680 mcopyin(mp, uaddr, sizeof (audio_info_t), NULL); 681 qreply(wq, mp); 682 return; 683 } 684 685 ASSERT(DB_TYPE(mp) == M_IOCDATA); 686 if (((bcont = mp->b_cont) == NULL) || 687 (MBLKL(mp->b_cont) != sizeof (audio_info_t))) { 688 miocnak(wq, mp, 0, EINVAL); 689 return; 690 } 691 692 mp->b_cont = NULL; 693 csp = (void *)mp->b_rptr; 694 uaddr = (void *)csp->cp_private; 695 dc = auclnt_get_private(c); 696 ninfo = (void *)bcont->b_rptr; 697 698 mutex_enter(&dc->dc_dev->d_mx); 699 700 proc = dc->dc_proc; 701 oinfo = &proc->p_info; 702 703 if (auclnt_get_minor_type(c) == AUDIO_MINOR_DEVAUDIOCTL) { 704 /* control node can do both read and write fields */ 705 isctl = B_TRUE; 706 reader = B_TRUE; 707 writer = B_TRUE; 708 } else { 709 isctl = B_FALSE; 710 writer = (c == proc->p_writer); 711 reader = (c == proc->p_reader); 712 } 713 714 /* 715 * Start by validating settings. 716 */ 717 npr = &ninfo->play; 718 opr = &oinfo->play; 719 720 if (writer && CHANGED(npr, opr, sample_rate)) { 721 if ((isctl) || 722 (npr->sample_rate < 5500) || (npr->sample_rate > 48000)) { 723 rv = EINVAL; 724 goto err; 725 } 726 } 727 if (writer && CHANGED(npr, opr, channels)) { 728 if ((isctl) || (npr->channels < 1) || (npr->channels > 2)) { 729 rv = EINVAL; 730 goto err; 731 } 732 } 733 if (writer && 734 (CHANGED(npr, opr, encoding) || CHANGED(npr, opr, precision))) { 735 if (npr->encoding == (uint32_t)~0) 736 npr->encoding = opr->encoding; 737 if (npr->precision == (uint32_t)~0) 738 npr->precision = opr->precision; 739 pfmt = devaudio_compose_format(npr); 740 if ((isctl) || (pfmt == AUDIO_FORMAT_NONE)) { 741 rv = EINVAL; 742 goto err; 743 } 744 } 745 746 /* play fields that anyone can modify */ 747 if (CHANGED(npr, opr, gain)) { 748 if (npr->gain > AUDIO_MAX_GAIN) { 749 rv = EINVAL; 750 goto err; 751 } 752 } 753 754 755 npr = &ninfo->record; 756 opr = &oinfo->record; 757 758 if (reader && CHANGED(npr, opr, sample_rate)) { 759 if ((isctl) || 760 (npr->sample_rate < 5500) || (npr->sample_rate > 48000)) { 761 rv = EINVAL; 762 goto err; 763 } 764 } 765 if (reader && CHANGED(npr, opr, channels)) { 766 if ((isctl) || (npr->channels < 1) || (npr->channels > 2)) { 767 rv = EINVAL; 768 goto err; 769 } 770 } 771 if (reader && 772 (CHANGED(npr, opr, encoding) || CHANGED(npr, opr, precision))) { 773 if (npr->encoding == (uint32_t)~0) 774 npr->encoding = opr->encoding; 775 if (npr->precision == (uint32_t)~0) 776 npr->precision = opr->precision; 777 rfmt = devaudio_compose_format(npr); 778 if ((isctl) || (rfmt == AUDIO_FORMAT_NONE)) { 779 rv = EINVAL; 780 goto err; 781 } 782 } 783 if (reader && CHANGED(npr, opr, buffer_size)) { 784 if (isctl) { 785 rv = EINVAL; 786 goto err; 787 } 788 /* make sure we can support 16-bit stereo samples */ 789 if ((npr->buffer_size % 4) != 0) { 790 npr->buffer_size = (npr->buffer_size + 3) & ~3; 791 } 792 /* limit the maximum buffer size somewhat */ 793 if (npr->buffer_size > 16384) { 794 npr->buffer_size = 16384; 795 } 796 } 797 798 /* record fields that anyone can modify */ 799 if (CHANGED(npr, opr, gain)) { 800 if (npr->gain > AUDIO_MAX_GAIN) { 801 rv = EINVAL; 802 goto err; 803 } 804 } 805 806 /* 807 * Now apply the changes. 808 */ 809 if (proc->p_writer != NULL) { 810 sp = auclnt_output_stream(proc->p_writer); 811 npr = &ninfo->play; 812 opr = &oinfo->play; 813 814 if (CHANGED(npr, opr, sample_rate)) { 815 if ((rv = auclnt_set_rate(sp, npr->sample_rate)) != 0) 816 goto err; 817 } 818 if (CHANGED(npr, opr, channels)) { 819 if ((rv = auclnt_set_channels(sp, npr->channels)) != 0) 820 goto err; 821 } 822 if (pfmt != AUDIO_FORMAT_NONE) { 823 if ((rv = auclnt_set_format(sp, pfmt)) != 0) 824 goto err; 825 } 826 if (CHANGED(npr, opr, samples)) { 827 auclnt_set_samples(sp, npr->samples); 828 } 829 if (CHANGED(npr, opr, eof)) { 830 /* 831 * This ugly special case code is required to 832 * prevent problems with realaudio. 833 */ 834 if (npr->eof == 0) { 835 devaudio_clear_eof(proc->p_writer); 836 } 837 opr->eof = npr->eof; 838 } 839 if (CHANGED8(npr, opr, pause)) { 840 if (npr->pause) { 841 auclnt_set_paused(sp); 842 } else { 843 auclnt_clear_paused(sp); 844 845 /* qenable to start up the playback */ 846 qenable(auclnt_get_wq(proc->p_writer)); 847 } 848 } 849 if (CHANGED8(npr, opr, waiting) && (npr->waiting)) { 850 opr->waiting = npr->waiting; 851 } 852 if (CHANGED8(npr, opr, error)) { 853 auclnt_set_errors(sp, npr->error); 854 } 855 if (CHANGED(npr, opr, gain)) { 856 auclnt_set_gain(sp, (npr->gain * 100) / AUDIO_MAX_GAIN); 857 } 858 if (CHANGED8(ninfo, oinfo, output_muted)) { 859 auclnt_set_muted(sp, ninfo->output_muted); 860 } 861 if (CHANGED(npr, opr, buffer_size)) { 862 /* 863 * No checks on the buffer size are performed 864 * for play side. The value of the buffer size 865 * is meaningless for play side anyway. 866 */ 867 opr->buffer_size = npr->buffer_size; 868 } 869 } else { 870 /* these values are preserved even if /dev/audio not open */ 871 if (CHANGED(npr, opr, gain)) { 872 opr->gain = npr->gain; 873 } 874 if (CHANGED8(ninfo, oinfo, output_muted)) { 875 oinfo->output_muted = ninfo->output_muted; 876 } 877 } 878 879 if (proc->p_reader != NULL) { 880 sp = auclnt_input_stream(proc->p_reader); 881 npr = &ninfo->record; 882 opr = &oinfo->record; 883 884 if (CHANGED(npr, opr, sample_rate)) { 885 if ((rv = auclnt_set_rate(sp, npr->sample_rate)) != 0) 886 goto err; 887 } 888 if (CHANGED(npr, opr, channels)) { 889 if ((rv = auclnt_set_channels(sp, npr->channels)) != 0) 890 goto err; 891 } 892 if (rfmt != AUDIO_FORMAT_NONE) { 893 if ((rv = auclnt_set_format(sp, rfmt)) != 0) 894 goto err; 895 } 896 if (CHANGED(npr, opr, samples)) { 897 auclnt_set_samples(sp, npr->samples); 898 } 899 if (CHANGED(npr, opr, eof)) { 900 opr->eof = npr->eof; 901 } 902 if (CHANGED8(npr, opr, pause)) { 903 if (npr->pause) { 904 auclnt_set_paused(sp); 905 } else { 906 auclnt_clear_paused(sp); 907 auclnt_start(sp); 908 } 909 } 910 if (CHANGED8(npr, opr, waiting) && (npr->waiting)) { 911 opr->waiting = npr->waiting; 912 } 913 if (CHANGED8(npr, opr, error)) { 914 auclnt_set_errors(sp, npr->error); 915 } 916 if (CHANGED(npr, opr, buffer_size)) { 917 opr->buffer_size = npr->buffer_size; 918 } 919 if (CHANGED(npr, opr, gain)) { 920 auclnt_set_gain(sp, (npr->gain * 100) / AUDIO_MAX_GAIN); 921 } 922 } else { 923 /* these values are preserved even if /dev/audio not open */ 924 if (CHANGED(npr, opr, gain)) { 925 opr->gain = npr->gain; 926 } 927 } 928 929 devaudio_proc_update(dc->dc_proc); 930 bcopy(&dc->dc_proc->p_info, ninfo, sizeof (*ninfo)); 931 932 mutex_exit(&dc->dc_dev->d_mx); 933 mcopyout(mp, NULL, sizeof (audio_info_t), uaddr, bcont); 934 qreply(wq, mp); 935 return; 936 937 err: 938 mutex_exit(&dc->dc_dev->d_mx); 939 miocnak(wq, mp, 0, rv); 940 } 941 942 static void 943 devaudio_ioc_getdev(queue_t *wq, audio_client_t *c, mblk_t *mp) 944 { 945 audio_dev_t *d = auclnt_get_dev(c); 946 mblk_t *bcont; 947 audio_device_t *a; 948 949 if ((bcont = allocb(sizeof (*a), BPRI_MED)) == NULL) { 950 miocnak(wq, mp, 0, ENOMEM); 951 return; 952 } 953 954 a = (void *)bcont->b_wptr; 955 (void) snprintf(a->name, sizeof (a->name), 956 "SUNW,%s", auclnt_get_dev_name(d)); 957 (void) strlcpy(a->config, 958 auclnt_get_dev_description(d), sizeof (a->config)); 959 (void) strlcpy(a->version, 960 auclnt_get_dev_version(d), sizeof (a->version)); 961 bcont->b_wptr += sizeof (*a); 962 963 mcopyout(mp, NULL, sizeof (*a), NULL, bcont); 964 qreply(wq, mp); 965 } 966 967 static int 968 devaudio_sigpoll(audio_client_t *c, void *arg) 969 { 970 pid_t pid = (pid_t)(uintptr_t)arg; 971 972 if (auclnt_get_minor_type(c) == AUDIO_MINOR_DEVAUDIOCTL) { 973 /* we only need to notify peers in our own process */ 974 if (auclnt_get_pid(c) == pid) { 975 (void) putctl1(auclnt_get_rq(c), M_PCSIG, SIGPOLL); 976 } 977 } 978 return (AUDIO_WALK_CONTINUE); 979 } 980 981 static void 982 devaudio_drain(audio_client_t *c) 983 { 984 daclient_t *dc = auclnt_get_private(c); 985 mblk_t *mplist, *mp; 986 987 mutex_enter(&dc->dc_lock); 988 mplist = dc->dc_draining; 989 dc->dc_draining = NULL; 990 mutex_exit(&dc->dc_lock); 991 992 while ((mp = mplist) != NULL) { 993 mplist = mp->b_next; 994 mp->b_next = NULL; 995 mioc2ack(mp, NULL, 0, 0); 996 (void) putq(auclnt_get_rq(c), mp); 997 } 998 } 999 1000 static void 1001 devaudio_output(audio_client_t *c) 1002 { 1003 daclient_t *dc = auclnt_get_private(c); 1004 daproc_t *proc = dc->dc_proc; 1005 uint64_t tail; 1006 struct eofcnt *eof; 1007 int eofs = 0; 1008 1009 tail = auclnt_get_tail(auclnt_output_stream(c)); 1010 1011 /* get more data! (do this early) */ 1012 qenable(auclnt_get_wq(c)); 1013 1014 mutex_enter(&dc->dc_lock); 1015 while (((eof = list_head(&dc->dc_eofcnt)) != NULL) && 1016 (eof->tail <= tail)) { 1017 list_remove(&dc->dc_eofcnt, eof); 1018 kmem_free(eof, sizeof (*eof)); 1019 eofs++; 1020 } 1021 proc->p_info.play.eof += eofs; 1022 mutex_exit(&dc->dc_lock); 1023 1024 if (eofs) { 1025 auclnt_dev_walk_clients(auclnt_get_dev(c), 1026 devaudio_sigpoll, (void *)(uintptr_t)auclnt_get_pid(c)); 1027 } 1028 } 1029 1030 static void * 1031 devaudio_init(audio_dev_t *adev) 1032 { 1033 dadev_t *dev; 1034 unsigned cap; 1035 1036 cap = auclnt_get_dev_capab(adev); 1037 /* if not a play or record device, don't bother initializing it */ 1038 if ((cap & (AUDIO_CLIENT_CAP_PLAY | AUDIO_CLIENT_CAP_RECORD)) == 0) { 1039 return (NULL); 1040 } 1041 1042 dev = kmem_zalloc(sizeof (*dev), KM_SLEEP); 1043 dev->d_dev = adev; 1044 mutex_init(&dev->d_mx, NULL, MUTEX_DRIVER, NULL); 1045 cv_init(&dev->d_cv, NULL, CV_DRIVER, NULL); 1046 list_create(&dev->d_procs, sizeof (struct daproc), 1047 offsetof(struct daproc, p_linkage)); 1048 1049 return (dev); 1050 } 1051 1052 static void 1053 devaudio_fini(void *arg) 1054 { 1055 dadev_t *dev = arg; 1056 1057 if (dev != NULL) { 1058 1059 mutex_destroy(&dev->d_mx); 1060 cv_destroy(&dev->d_cv); 1061 list_destroy(&dev->d_procs); 1062 kmem_free(dev, sizeof (*dev)); 1063 } 1064 } 1065 1066 static int 1067 devaudio_open(audio_client_t *c, int oflag) 1068 { 1069 int rv; 1070 1071 if ((rv = auclnt_open(c, oflag)) != 0) { 1072 return (rv); 1073 } 1074 1075 if ((rv = devaudio_proc_hold(c, oflag)) != 0) { 1076 auclnt_close(c); 1077 return (rv); 1078 } 1079 1080 /* start up the input */ 1081 if (oflag & FREAD) { 1082 auclnt_start(auclnt_input_stream(c)); 1083 } 1084 1085 return (0); 1086 } 1087 1088 static int 1089 devaudioctl_open(audio_client_t *c, int oflag) 1090 { 1091 int rv; 1092 1093 _NOTE(ARGUNUSED(oflag)); 1094 1095 oflag &= ~(FWRITE | FREAD); 1096 1097 if ((rv = auclnt_open(c, 0)) != 0) { 1098 return (rv); 1099 } 1100 1101 if ((rv = devaudio_proc_hold(c, oflag)) != 0) { 1102 auclnt_close(c); 1103 return (rv); 1104 } 1105 1106 return (0); 1107 } 1108 1109 static void 1110 devaudio_close(audio_client_t *c) 1111 { 1112 auclnt_stop(auclnt_output_stream(c)); 1113 auclnt_stop(auclnt_input_stream(c)); 1114 1115 auclnt_close(c); 1116 devaudio_proc_release(c); 1117 } 1118 1119 static void 1120 devaudioctl_close(audio_client_t *c) 1121 { 1122 auclnt_close(c); 1123 devaudio_proc_release(c); 1124 } 1125 1126 static void 1127 devaudio_miocdata(audio_client_t *c, mblk_t *mp) 1128 { 1129 struct copyresp *csp; 1130 queue_t *wq; 1131 1132 csp = (void *)mp->b_rptr; 1133 wq = auclnt_get_wq(c); 1134 1135 /* 1136 * If a transfer error occurred, the framework already 1137 * MIOCNAK'd it. 1138 */ 1139 if (csp->cp_rval != 0) { 1140 freemsg(mp); 1141 return; 1142 } 1143 1144 /* 1145 * If no state, then this is a response to M_COPYOUT, and we 1146 * are done. (Audio ioctls just copyout a single structure at 1147 * completion of work.) 1148 */ 1149 if (csp->cp_private == NULL) { 1150 miocack(wq, mp, 0, 0); 1151 return; 1152 } 1153 1154 /* now, call the handler ioctl */ 1155 switch (csp->cp_cmd) { 1156 case AUDIO_SETINFO: 1157 devaudio_ioc_setinfo(wq, c, mp); 1158 break; 1159 default: 1160 miocnak(wq, mp, 0, EINVAL); 1161 break; 1162 } 1163 } 1164 1165 static void 1166 devaudio_mioctl(audio_client_t *c, mblk_t *mp) 1167 { 1168 struct iocblk *iocp = (void *)mp->b_rptr; 1169 queue_t *wq = auclnt_get_wq(c); 1170 1171 /* BSD legacy here: we only support transparent ioctls */ 1172 if (iocp->ioc_count != TRANSPARENT) { 1173 miocnak(wq, mp, 0, EINVAL); 1174 return; 1175 } 1176 1177 switch (iocp->ioc_cmd) { 1178 case AUDIO_GETINFO: 1179 devaudio_ioc_getinfo(wq, c, mp); 1180 break; 1181 1182 case AUDIO_SETINFO: 1183 devaudio_ioc_setinfo(wq, c, mp); 1184 break; 1185 1186 case AUDIO_GETDEV: 1187 devaudio_ioc_getdev(wq, c, mp); 1188 break; 1189 1190 case AUDIO_DIAG_LOOPBACK: 1191 /* we don't support this one */ 1192 miocnak(wq, mp, 0, ENOTTY); 1193 break; 1194 1195 case AUDIO_MIXERCTL_GET_MODE: 1196 case AUDIO_MIXERCTL_SET_MODE: 1197 case AUDIO_MIXERCTL_GET_CHINFO: 1198 case AUDIO_MIXERCTL_SET_CHINFO: 1199 case AUDIO_MIXERCTL_GETINFO: 1200 case AUDIO_MIXERCTL_SETINFO: 1201 case AUDIO_GET_NUM_CHS: 1202 case AUDIO_GET_CH_NUMBER: 1203 case AUDIO_GET_CH_TYPE: 1204 case AUDIO_MIXER_SINGLE_OPEN: 1205 case AUDIO_MIXER_MULTIPLE_OPEN: 1206 case AUDIO_MIXER_GET_SAMPLE_RATES: 1207 default: 1208 miocnak(wq, mp, 0, EINVAL); 1209 break; 1210 } 1211 } 1212 1213 static void 1214 devaudioctl_wput(audio_client_t *c, mblk_t *mp) 1215 { 1216 queue_t *wq = auclnt_get_wq(c); 1217 1218 switch (DB_TYPE(mp)) { 1219 case M_IOCTL: 1220 /* Drain ioctl needs to be handled on the service queue */ 1221 devaudio_mioctl(c, mp); 1222 break; 1223 1224 case M_IOCDATA: 1225 devaudio_miocdata(c, mp); 1226 break; 1227 1228 case M_FLUSH: 1229 /* 1230 * We don't flush the engine. The reason is that 1231 * other streams might be using the engine. This is 1232 * fundamentally no different from the case where the 1233 * engine hardware has data buffered in an 1234 * inaccessible FIFO. 1235 * 1236 * Clients that want to ensure no more data is coming 1237 * should stop the stream before flushing. 1238 */ 1239 if (*mp->b_rptr & FLUSHW) { 1240 *mp->b_rptr &= ~FLUSHW; 1241 } 1242 if (*mp->b_rptr & FLUSHR) { 1243 qreply(wq, mp); 1244 } else { 1245 freemsg(mp); 1246 } 1247 break; 1248 1249 case M_DATA: 1250 /* 1251 * No audio data on control nodes! 1252 */ 1253 1254 default: 1255 freemsg(mp); 1256 break; 1257 } 1258 } 1259 1260 static void 1261 devaudio_wput(audio_client_t *c, mblk_t *mp) 1262 { 1263 queue_t *wq = auclnt_get_wq(c); 1264 1265 switch (DB_TYPE(mp)) { 1266 case M_IOCTL: 1267 /* Drain ioctl needs to be handled on the service queue */ 1268 if (*(int *)(void *)mp->b_rptr == AUDIO_DRAIN) { 1269 (void) putq(wq, mp); 1270 } else { 1271 devaudio_mioctl(c, mp); 1272 } 1273 break; 1274 1275 case M_IOCDATA: 1276 devaudio_miocdata(c, mp); 1277 break; 1278 1279 case M_FLUSH: 1280 /* 1281 * We don't flush the engine. The reason is that 1282 * other streams might be using the engine. This is 1283 * fundamentally no different from the case where the 1284 * engine hardware has data buffered in an 1285 * inaccessible FIFO. 1286 * 1287 * Clients that want to ensure no more data is coming 1288 * should stop the stream before flushing. 1289 */ 1290 if (*mp->b_rptr & FLUSHW) { 1291 flushq(wq, FLUSHALL); 1292 auclnt_flush(auclnt_output_stream(c)); 1293 *mp->b_rptr &= ~FLUSHW; 1294 } 1295 if (*mp->b_rptr & FLUSHR) { 1296 flushq(RD(wq), FLUSHALL); 1297 auclnt_flush(auclnt_input_stream(c)); 1298 qreply(wq, mp); 1299 } else { 1300 freemsg(mp); 1301 } 1302 break; 1303 1304 case M_DATA: 1305 /* 1306 * Defer processing to the queue. This keeps the data 1307 * ordered, and allows the wsrv routine to gather 1308 * multiple mblks at once. 1309 */ 1310 if (mp->b_cont != NULL) { 1311 1312 /* 1313 * If we need to pullup, do it here to 1314 * simplify the rest of the processing later. 1315 * This should rarely (if ever) be necessary. 1316 */ 1317 mblk_t *nmp; 1318 1319 if ((nmp = msgpullup(mp, -1)) == NULL) { 1320 freemsg(mp); 1321 } else { 1322 freemsg(mp); 1323 (void) putq(wq, nmp); 1324 } 1325 } else { 1326 (void) putq(wq, mp); 1327 } 1328 break; 1329 1330 default: 1331 freemsg(mp); 1332 break; 1333 } 1334 } 1335 1336 static void 1337 devaudio_rsrv(audio_client_t *c) 1338 { 1339 queue_t *rq = auclnt_get_rq(c); 1340 mblk_t *mp; 1341 1342 while ((mp = getq(rq)) != NULL) { 1343 1344 if ((queclass(mp) != QPCTL) && (!canputnext(rq))) { 1345 /* 1346 * Put it back in the queue so we can apply 1347 * backpressure properly. 1348 */ 1349 (void) putbq(rq, mp); 1350 return; 1351 } 1352 putnext(rq, mp); 1353 } 1354 } 1355 1356 static void 1357 devaudio_wsrv(audio_client_t *c) 1358 { 1359 queue_t *wq = auclnt_get_wq(c); 1360 daclient_t *dc = auclnt_get_private(c); 1361 audio_stream_t *sp; 1362 mblk_t *mp; 1363 unsigned framesz; 1364 1365 sp = auclnt_output_stream(c); 1366 1367 framesz = auclnt_get_framesz(sp); 1368 1369 while ((mp = getq(wq)) != NULL) { 1370 1371 unsigned count; 1372 1373 /* got a message */ 1374 1375 /* if its a drain ioctl, we need to process it here */ 1376 if (DB_TYPE(mp) == M_IOCTL) { 1377 ASSERT((*(int *)(void *)mp->b_rptr) == AUDIO_DRAIN); 1378 mutex_enter(&dc->dc_lock); 1379 mp->b_next = dc->dc_draining; 1380 dc->dc_draining = mp; 1381 mutex_exit(&dc->dc_lock); 1382 1383 if (auclnt_start_drain(c) != 0) { 1384 devaudio_drain(c); 1385 } 1386 continue; 1387 } 1388 1389 ASSERT(DB_TYPE(mp) == M_DATA); 1390 1391 /* 1392 * Empty mblk require special handling, since they 1393 * indicate EOF. We treat them separate from the main 1394 * processing loop. 1395 */ 1396 if (MBLKL(mp) == 0) { 1397 struct eofcnt *eof; 1398 1399 eof = kmem_zalloc(sizeof (*eof), KM_NOSLEEP); 1400 if (eof != NULL) { 1401 eof->tail = auclnt_get_head(sp); 1402 mutex_enter(&dc->dc_lock); 1403 list_insert_tail(&dc->dc_eofcnt, eof); 1404 mutex_exit(&dc->dc_lock); 1405 } 1406 freemsg(mp); 1407 continue; 1408 } 1409 1410 count = auclnt_produce_data(sp, (caddr_t)mp->b_rptr, 1411 MBLKL(mp) / framesz); 1412 1413 mp->b_rptr += count * framesz; 1414 1415 if (MBLKL(mp) >= framesz) { 1416 (void) putbq(wq, mp); 1417 break; 1418 } else { 1419 freemsg(mp); 1420 } 1421 } 1422 1423 /* if the stream isn't running yet, start it up */ 1424 if (!auclnt_is_paused(sp)) 1425 auclnt_start(sp); 1426 } 1427 1428 static struct audio_client_ops devaudio_ops = { 1429 "sound,audio", 1430 devaudio_init, 1431 devaudio_fini, 1432 devaudio_open, 1433 devaudio_close, 1434 NULL, /* read */ 1435 NULL, /* write */ 1436 NULL, /* ioctl */ 1437 NULL, /* chpoll */ 1438 NULL, /* mmap */ 1439 devaudio_input, 1440 devaudio_output, 1441 devaudio_drain, 1442 devaudio_wput, 1443 devaudio_wsrv, 1444 devaudio_rsrv 1445 }; 1446 1447 static struct audio_client_ops devaudioctl_ops = { 1448 "sound,audioctl", 1449 NULL, /* dev_init */ 1450 NULL, /* dev_fini */ 1451 devaudioctl_open, 1452 devaudioctl_close, 1453 NULL, /* read */ 1454 NULL, /* write */ 1455 NULL, /* ioctl */ 1456 NULL, /* chpoll */ 1457 NULL, /* mmap */ 1458 NULL, /* output */ 1459 NULL, /* input */ 1460 NULL, /* drain */ 1461 devaudioctl_wput, 1462 NULL, 1463 devaudio_rsrv 1464 }; 1465 1466 void 1467 auimpl_sun_init(void) 1468 { 1469 auclnt_register_ops(AUDIO_MINOR_DEVAUDIO, &devaudio_ops); 1470 auclnt_register_ops(AUDIO_MINOR_DEVAUDIOCTL, &devaudioctl_ops); 1471 } 1472