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 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <sys/types.h> 27 #include <sys/open.h> 28 #include <sys/errno.h> 29 #include <sys/ddi.h> 30 #include <sys/sunddi.h> 31 #include <sys/audio/audio_oss.h> 32 #include <sys/file.h> 33 #include <sys/note.h> 34 #include <sys/sysmacros.h> 35 #include <sys/list.h> 36 #include "audio_client.h" 37 38 #define OSS_FMT AFMT_S16_LE 39 #define OSS_RATE 48000 40 #define OSS_CHANNELS 2 41 42 typedef struct ossclient ossclient_t; 43 typedef struct ossdev ossdev_t; 44 45 static const struct { 46 int oss; 47 int fmt; 48 } oss_formats[] = { 49 { AFMT_MU_LAW, AUDIO_FORMAT_ULAW }, 50 { AFMT_A_LAW, AUDIO_FORMAT_ALAW }, 51 { AFMT_U8, AUDIO_FORMAT_U8 }, 52 { AFMT_S8, AUDIO_FORMAT_S8 }, 53 { AFMT_S16_BE, AUDIO_FORMAT_S16_BE }, 54 { AFMT_S16_LE, AUDIO_FORMAT_S16_LE }, 55 { AFMT_U16_BE, AUDIO_FORMAT_U16_BE }, 56 { AFMT_U16_LE, AUDIO_FORMAT_U16_LE }, 57 { AFMT_S24_BE, AUDIO_FORMAT_S24_BE }, 58 { AFMT_S24_LE, AUDIO_FORMAT_S24_LE }, 59 { AFMT_S32_BE, AUDIO_FORMAT_S32_BE }, 60 { AFMT_S32_LE, AUDIO_FORMAT_S32_LE }, 61 { AFMT_S24_PACKED, AUDIO_FORMAT_S24_PACKED }, 62 { AFMT_AC3, AUDIO_FORMAT_AC3 }, 63 { AFMT_QUERY, AUDIO_FORMAT_NONE } 64 }; 65 66 /* common structure shared between both mixer and dsp nodes */ 67 struct ossclient { 68 ossdev_t *o_ossdev; 69 audio_client_t *o_client; 70 /* sndstat */ 71 kmutex_t o_ss_lock; 72 char *o_ss_buf; 73 size_t o_ss_len; 74 size_t o_ss_sz; 75 size_t o_ss_off; 76 }; 77 78 struct ossdev { 79 audio_dev_t *d_dev; 80 81 uint_t d_modify_cnt; /* flag apps of ctrl changes */ 82 uint_t d_nctrl; /* num actual controls */ 83 uint_t d_nalloc; /* num allocated controls */ 84 audio_ctrl_t **d_ctrls; /* array of control handles */ 85 oss_mixext *d_exts; /* array of mixer descs */ 86 87 int d_play_grp; 88 int d_rec_grp; 89 int d_mon_grp; 90 int d_misc_grp; 91 92 kmutex_t d_mx; 93 kcondvar_t d_cv; 94 }; 95 96 static int 97 oss_cnt_controls(audio_ctrl_t *ctrl, void *arg) 98 { 99 int *pint = (int *)arg; 100 int cnt; 101 audio_ctrl_desc_t desc; 102 103 cnt = *pint; 104 cnt++; 105 *pint = cnt; 106 107 if (auclnt_control_describe(ctrl, &desc) != 0) 108 return (AUDIO_WALK_CONTINUE); 109 110 if (desc.acd_flags & AUDIO_CTRL_FLAG_MULTI) { 111 for (uint64_t mask = desc.acd_maxvalue; mask; mask >>= 1) { 112 if (mask & 1) { 113 cnt++; 114 } 115 } 116 *pint = cnt; 117 } 118 119 return (AUDIO_WALK_CONTINUE); 120 } 121 122 /* 123 * Add one entry to the OSS user control table to internal control 124 * helper table. 125 * 126 * This is used with auimpl_walk_controls. The table must be pre- 127 * allocated before it is walk'd. This includes the root and 128 * extended control markers! 129 */ 130 static int 131 oss_add_control(audio_ctrl_t *ctrl, void *arg) 132 { 133 ossdev_t *odev = arg; 134 audio_ctrl_desc_t desc; 135 oss_mixext *ext; 136 int bit; 137 uint64_t mask; 138 const char *name; 139 int parent; 140 int flags; 141 unsigned scope; 142 143 if (auclnt_control_describe(ctrl, &desc)) 144 return (AUDIO_WALK_CONTINUE); 145 146 parent = 0; 147 148 /* 149 * Add appropriate group if not already done so. 150 */ 151 if (desc.acd_flags & AUDIO_CTRL_FLAG_PLAY) { 152 if (!odev->d_play_grp) { 153 ext = &odev->d_exts[odev->d_nctrl]; 154 ext->ctrl = odev->d_nctrl; 155 ext->control_no = -1; 156 ext->type = MIXT_GROUP; 157 ext->desc = MIXEXT_SCOPE_OUTPUT; 158 ext->timestamp = gethrtime(); 159 (void) snprintf(ext->id, sizeof (ext->id), "PLAYBACK"); 160 odev->d_play_grp = odev->d_nctrl; 161 odev->d_nctrl++; 162 } 163 scope = MIXEXT_SCOPE_OUTPUT; 164 parent = odev->d_play_grp; 165 } else if (desc.acd_flags & AUDIO_CTRL_FLAG_REC) { 166 if (!odev->d_rec_grp) { 167 ext = &odev->d_exts[odev->d_nctrl]; 168 ext->ctrl = odev->d_nctrl; 169 ext->control_no = -1; 170 ext->type = MIXT_GROUP; 171 ext->desc = MIXEXT_SCOPE_INPUT; 172 ext->timestamp = gethrtime(); 173 (void) snprintf(ext->id, sizeof (ext->id), "RECORD"); 174 odev->d_rec_grp = odev->d_nctrl; 175 odev->d_nctrl++; 176 } 177 scope = MIXEXT_SCOPE_INPUT; 178 parent = odev->d_rec_grp; 179 } else if (desc.acd_flags & AUDIO_CTRL_FLAG_MONITOR) { 180 if (!odev->d_mon_grp) { 181 ext = &odev->d_exts[odev->d_nctrl]; 182 ext->ctrl = odev->d_nctrl; 183 ext->control_no = -1; 184 ext->type = MIXT_GROUP; 185 ext->desc = MIXEXT_SCOPE_MONITOR; 186 ext->timestamp = gethrtime(); 187 (void) snprintf(ext->id, sizeof (ext->id), "MONITOR"); 188 odev->d_mon_grp = odev->d_nctrl; 189 odev->d_nctrl++; 190 } 191 scope = MIXEXT_SCOPE_MONITOR; 192 parent = odev->d_mon_grp; 193 } else { 194 if (!odev->d_misc_grp) { 195 ext = &odev->d_exts[odev->d_nctrl]; 196 ext->ctrl = odev->d_nctrl; 197 ext->control_no = -1; 198 ext->type = MIXT_GROUP; 199 ext->desc = MIXEXT_SCOPE_OTHER; 200 ext->timestamp = gethrtime(); 201 (void) snprintf(ext->id, sizeof (ext->id), "MISC"); 202 odev->d_misc_grp = odev->d_nctrl; 203 odev->d_nctrl++; 204 } 205 scope = MIXEXT_SCOPE_OTHER; 206 parent = odev->d_misc_grp; 207 } 208 209 name = desc.acd_name ? desc.acd_name : ""; 210 211 if (desc.acd_flags & AUDIO_CTRL_FLAG_MULTI) { 212 ext = &odev->d_exts[odev->d_nctrl]; 213 ext->ctrl = odev->d_nctrl; 214 ext->control_no = -1; 215 ext->type = MIXT_GROUP; 216 ext->timestamp = gethrtime(); 217 ext->parent = parent; 218 ext->desc = scope; 219 (void) snprintf(ext->id, sizeof (ext->id), "%s", name); 220 (void) snprintf(ext->extname, sizeof (ext->extname), 221 "%s", name); 222 parent = odev->d_nctrl++; 223 } 224 225 /* Next available open entry */ 226 ext = &odev->d_exts[odev->d_nctrl]; 227 228 /* Record the underlying control handle */ 229 odev->d_ctrls[odev->d_nctrl] = ctrl; 230 231 /* 232 * Now setup the oss entry 233 */ 234 235 ext->ctrl = odev->d_nctrl; 236 ext->control_no = -1; 237 ext->maxvalue = (int)desc.acd_maxvalue; 238 ext->minvalue = (int)desc.acd_minvalue; 239 ext->timestamp = gethrtime(); 240 ext->parent = parent; 241 ext->desc = scope; 242 /* all controls should be pollable for now */ 243 flags = MIXF_POLL; 244 245 /* 246 * The following flags are intended to help out applications 247 * which need to figure out where to place certain controls. 248 * A few further words of guidance: 249 * 250 * Apps that just want a single master volume control should 251 * adjust the control(s) that are labelled with MIXF_PCMVOL if 252 * present. They can fall back to adjusting all MAINVOL 253 * levels instead, if no PCMVOL is present. 254 * 255 * Controls that are one type on a certain device might be a 256 * different type on another device. For example, 257 * audiopci/ak4531 can adjust input gains for individual 258 * levels, but lacks a master record gain. AC'97, on the 259 * other hand, has individual monitor gains for inputs, but 260 * only a single master recording gain. 261 */ 262 if (desc.acd_flags & AUDIO_CTRL_FLAG_READABLE) 263 flags |= MIXF_READABLE; 264 if (desc.acd_flags & AUDIO_CTRL_FLAG_WRITEABLE) 265 flags |= MIXF_WRITEABLE; 266 if (desc.acd_flags & AUDIO_CTRL_FLAG_CENTIBEL) 267 flags |= MIXF_CENTIBEL; 268 if (desc.acd_flags & AUDIO_CTRL_FLAG_DECIBEL) 269 flags |= MIXF_DECIBEL; 270 if (desc.acd_flags & AUDIO_CTRL_FLAG_MAINVOL) 271 flags |= MIXF_MAINVOL; 272 if (desc.acd_flags & AUDIO_CTRL_FLAG_PCMVOL) 273 flags |= MIXF_PCMVOL; 274 if (desc.acd_flags & AUDIO_CTRL_FLAG_RECVOL) 275 flags |= MIXF_RECVOL; 276 if (desc.acd_flags & AUDIO_CTRL_FLAG_MONVOL) 277 flags |= MIXF_MONVOL; 278 ext->flags = flags; 279 280 (void) snprintf(ext->id, sizeof (ext->id), "%s", name); 281 282 /* 283 * For now just use the same extname as the real name. 284 */ 285 (void) snprintf(ext->extname, sizeof (ext->extname), name); 286 287 /* 288 * Now we deal with various control types. 289 */ 290 switch (desc.acd_type) { 291 case AUDIO_CTRL_TYPE_BOOLEAN: 292 ext->type = MIXT_ONOFF; 293 ext->enumbit = -1; 294 break; 295 case AUDIO_CTRL_TYPE_STEREO: 296 ext->type = MIXT_STEREOSLIDER; 297 break; 298 case AUDIO_CTRL_TYPE_MONO: 299 ext->type = MIXT_MONOSLIDER; 300 break; 301 case AUDIO_CTRL_TYPE_ENUM: 302 303 if (desc.acd_flags & AUDIO_CTRL_FLAG_MULTI) { 304 /* 305 * We turn AUDIO_CTRL_FLAG_MULTI into a group 306 * of checkboxes, since OSS can't represent it 307 * natively. 308 */ 309 mask = desc.acd_maxvalue; 310 bit = 0; 311 while (mask) { 312 if (mask & 1) { 313 ext = &odev->d_exts[odev->d_nctrl]; 314 (void) snprintf(ext->extname, 315 sizeof (ext->extname), "%s.%s", 316 name, desc.acd_enum[bit]); 317 (void) snprintf(ext->id, 318 sizeof (ext->id), "%s", 319 desc.acd_enum[bit]); 320 ext->ctrl = odev->d_nctrl; 321 ext->control_no = -1; 322 ext->parent = parent; 323 ext->timestamp = gethrtime(); 324 ext->type = MIXT_ONOFF; 325 ext->minvalue = 0; 326 ext->maxvalue = 1; 327 ext->enumbit = bit; 328 ext->flags = flags; 329 odev->d_ctrls[odev->d_nctrl] = ctrl; 330 odev->d_nctrl++; 331 } 332 bit++; 333 mask >>= 1; 334 } 335 return (AUDIO_WALK_CONTINUE); 336 } else { 337 /* 338 * NB: This is sufficient only for controls 339 * with a single value. It cannot express the 340 * richer bitmask capabilities. 341 */ 342 ext->type = MIXT_ENUM; 343 ext->minvalue = 0; 344 345 /* 346 * For an enumaration, we need to figure out 347 * which values are present, and set the 348 * appropriate mask and max value. 349 */ 350 bzero(ext->enum_present, sizeof (ext->enum_present)); 351 mask = desc.acd_maxvalue; 352 bit = 0; 353 while (mask) { 354 if (mask & 1) { 355 ext->enum_present[bit / 8] |= 356 (1 << (bit % 8)); 357 } 358 mask >>= 1; 359 bit++; 360 } 361 ext->maxvalue = bit; 362 } 363 break; 364 365 case AUDIO_CTRL_TYPE_METER: 366 default: 367 /* Its an unknown or unsupported (for now) control, skip */ 368 return (AUDIO_WALK_CONTINUE); 369 } 370 371 odev->d_nctrl++; 372 373 return (AUDIO_WALK_CONTINUE); 374 } 375 376 /* 377 * Free up an OSS user land control to internal control, 378 * helper table. 379 */ 380 static void 381 oss_free_controls(ossdev_t *odev) 382 { 383 kmem_free(odev->d_ctrls, sizeof (audio_ctrl_t *) * odev->d_nalloc); 384 kmem_free(odev->d_exts, sizeof (oss_mixext) * odev->d_nalloc); 385 odev->d_nctrl = 0; 386 odev->d_nalloc = 0; 387 } 388 389 /* 390 * Allocate and fill in an OSS user land controls to internal controls 391 * helper table. This is done on one audio_dev device. 392 */ 393 static void 394 oss_alloc_controls(ossdev_t *odev) 395 { 396 audio_dev_t *d = odev->d_dev; 397 int nctrl = 0; 398 oss_mixext *ext; 399 oss_mixext_root *root_data; 400 401 /* Find out who many entries we need */ 402 auclnt_walk_controls(d, oss_cnt_controls, &nctrl); 403 nctrl++; /* Needs space for the device root node */ 404 nctrl++; /* Needs space for the device ext marker */ 405 nctrl++; /* Needs space for the play group */ 406 nctrl++; /* Needs space for the record group */ 407 nctrl++; /* Needs space for the monitor group */ 408 nctrl++; /* Needs space for the tone group */ 409 nctrl++; /* Needs space for the 3D group */ 410 nctrl++; /* Needs space for the misc group */ 411 412 /* Allocate the OSS to boomer helper table */ 413 odev->d_nalloc = nctrl; 414 odev->d_ctrls = kmem_zalloc(sizeof (audio_ctrl_t *) * nctrl, KM_SLEEP); 415 odev->d_exts = kmem_zalloc(sizeof (oss_mixext) * nctrl, KM_SLEEP); 416 417 /* 418 * Setup special case outputs to output OSS routes helper tables 419 */ 420 421 /* 422 * Root node is first, that way all others parent is this one 423 */ 424 ext = &odev->d_exts[odev->d_nctrl]; 425 ext->ctrl = 0; 426 ext->parent = -1; 427 ext->type = MIXT_DEVROOT; 428 ext->timestamp = gethrtime(); 429 (void) snprintf(ext->id, sizeof (ext->id), "DEVROOT"); 430 /* 431 * Root data... nobody should be using this though. 432 */ 433 root_data = (oss_mixext_root *)&ext->data; 434 (void) snprintf(root_data->name, sizeof (root_data->name), "%s", 435 auclnt_get_dev_name(d)); 436 (void) snprintf(root_data->id, sizeof (root_data->id), "%s", 437 auclnt_get_dev_name(d)); 438 439 odev->d_nctrl++; 440 441 /* 442 * Insert an extra marker -- needed to keep layout apps hapy. 443 * This prevents some apps from assuming we are in "LEGACY" mode. 444 */ 445 ext = &odev->d_exts[odev->d_nctrl]; 446 ext->ctrl = odev->d_nctrl; 447 ext->control_no = -1; 448 ext->type = MIXT_MARKER; 449 ext->timestamp = gethrtime(); 450 ext->parent = 0; 451 odev->d_nctrl++; 452 453 /* Fill in the complete table now */ 454 auclnt_walk_controls(d, oss_add_control, odev); 455 456 /* Update the update_counter reference counter for groups */ 457 for (nctrl = 0; nctrl < odev->d_nctrl; nctrl++) { 458 int i; 459 460 ext = &odev->d_exts[nctrl]; 461 i = ext->parent; 462 while ((i >= 0) && (i < odev->d_nctrl)) { 463 464 ext = &odev->d_exts[i]; 465 ASSERT(ext->parent < i); 466 ASSERT((ext->type == MIXT_GROUP) || 467 (ext->type == MIXT_DEVROOT)); 468 ext->update_counter++; 469 i = ext->parent; 470 } 471 } 472 473 ASSERT(odev->d_nctrl <= odev->d_nalloc); 474 } 475 476 static int 477 oss_open(audio_client_t *c, int oflag) 478 { 479 int rv; 480 ossdev_t *odev; 481 ossclient_t *sc; 482 audio_stream_t *isp, *osp; 483 484 isp = auclnt_input_stream(c); 485 osp = auclnt_output_stream(c); 486 487 /* note that OSS always uses nonblocking open() semantics */ 488 if ((rv = auclnt_open(c, AUDIO_FORMAT_PCM, oflag | FNDELAY)) != 0) { 489 return (rv); 490 } 491 492 if ((sc = kmem_zalloc(sizeof (*sc), KM_NOSLEEP)) == NULL) { 493 auclnt_close(c); 494 return (ENOMEM); 495 } 496 auclnt_set_private(c, sc); 497 498 odev = auclnt_get_minor_data(c, AUDIO_MINOR_DSP); 499 500 /* set a couple of common fields */ 501 sc->o_client = c; 502 sc->o_ossdev = odev; 503 504 /* set all default parameters */ 505 if (oflag & FWRITE) { 506 if (((rv = auclnt_set_format(osp, OSS_FMT)) != 0) || 507 ((rv = auclnt_set_rate(osp, OSS_RATE)) != 0) || 508 ((rv = auclnt_set_channels(osp, OSS_CHANNELS)) != 0)) { 509 goto failed; 510 } 511 /* default to 5 fragments to provide reasonable latency */ 512 auclnt_set_latency(osp, 5, 0); 513 } 514 515 if (oflag & FREAD) { 516 if (((rv = auclnt_set_format(isp, OSS_FMT)) != 0) || 517 ((rv = auclnt_set_rate(isp, OSS_RATE)) != 0) || 518 ((rv = auclnt_set_channels(isp, OSS_CHANNELS)) != 0)) { 519 goto failed; 520 } 521 /* default to 5 fragments to provide reasonable latency */ 522 auclnt_set_latency(isp, 5, 0); 523 } 524 525 return (0); 526 527 failed: 528 auclnt_close(c); 529 return (rv); 530 } 531 532 static void 533 oss_close(audio_client_t *c) 534 { 535 ossclient_t *sc; 536 537 sc = auclnt_get_private(c); 538 539 if (ddi_can_receive_sig() || (ddi_get_pid() == 0)) { 540 (void) auclnt_drain(c); 541 } 542 543 kmem_free(sc, sizeof (*sc)); 544 545 auclnt_close(c); 546 } 547 548 /* 549 * This is used to generate an array of names for an enumeration 550 */ 551 static ushort_t 552 oss_set_enum(oss_mixer_enuminfo *ei, ushort_t nxt, const char *name) 553 { 554 uint32_t n; 555 556 /* Get current entry to fill in */ 557 n = ei->nvalues; 558 (void) snprintf(&ei->strings[nxt], ((sizeof (ei->strings) - nxt) - 1), 559 "%s", name); 560 ei->strindex[n] = nxt; 561 562 /* Adjust everything for next entry */ 563 nxt += strnlen(name, ((sizeof (ei->strings) - nxt) - 1)); 564 ei->strings[nxt++] = '\0'; 565 566 ei->nvalues++; 567 return (nxt); 568 } 569 570 /* 571 * The following two functions are used to count the number of devices 572 * in under the boomer framework. 573 * 574 * We actually report the highest "index", and then if an audio device 575 * is not found, we report a bogus removed device for it in the actual 576 * ioctls. This goofiness is required to make the OSS API happy. 577 */ 578 int 579 oss_dev_walker(audio_dev_t *d, void *arg) 580 { 581 int *pcnt = arg; 582 int cnt; 583 int index; 584 585 cnt = *pcnt; 586 index = auclnt_get_dev_index(d); 587 if ((index + 1) > cnt) { 588 cnt = index + 1; 589 *pcnt = cnt; 590 } 591 592 return (AUDIO_WALK_CONTINUE); 593 } 594 595 static int 596 oss_cnt_devs(void) 597 { 598 int cnt = 0; 599 600 auclnt_walk_devs(oss_dev_walker, &cnt); 601 return (cnt); 602 } 603 604 static int 605 sndctl_dsp_speed(audio_client_t *c, int *ratep) 606 { 607 int rv; 608 int rate; 609 int oflag; 610 611 rate = *ratep; 612 613 oflag = auclnt_get_oflag(c); 614 if (oflag & FREAD) { 615 if ((rv = auclnt_set_rate(auclnt_input_stream(c), rate)) != 0) 616 return (rv); 617 } 618 619 if (oflag & FWRITE) { 620 if ((rv = auclnt_set_rate(auclnt_output_stream(c), rate)) != 0) 621 return (rv); 622 } 623 624 return (0); 625 } 626 627 static int 628 sndctl_dsp_setfmt(audio_client_t *c, int *fmtp) 629 { 630 int rv; 631 int fmt; 632 int i; 633 int oflag; 634 635 oflag = auclnt_get_oflag(c); 636 637 if (*fmtp != AFMT_QUERY) { 638 /* convert from OSS */ 639 for (i = 0; oss_formats[i].fmt != AUDIO_FORMAT_NONE; i++) { 640 if (oss_formats[i].oss == *fmtp) { 641 fmt = oss_formats[i].fmt; 642 break; 643 } 644 } 645 if (fmt == AUDIO_FORMAT_NONE) { 646 /* if format not known, return ENOTSUP */ 647 return (ENOTSUP); 648 } 649 650 if (oflag & FWRITE) { 651 rv = auclnt_set_format(auclnt_output_stream(c), fmt); 652 if (rv != 0) 653 return (rv); 654 } 655 656 if (oflag & FREAD) { 657 rv = auclnt_set_format(auclnt_input_stream(c), fmt); 658 if (rv != 0) 659 return (rv); 660 } 661 } 662 663 if (oflag & FWRITE) { 664 fmt = auclnt_get_format(auclnt_output_stream(c)); 665 } else if (oflag & FREAD) { 666 fmt = auclnt_get_format(auclnt_input_stream(c)); 667 } 668 669 /* convert back to OSS */ 670 *(int *)fmtp = AFMT_QUERY; 671 for (i = 0; oss_formats[i].fmt != AUDIO_FORMAT_NONE; i++) { 672 if (oss_formats[i].fmt == fmt) { 673 *(int *)fmtp = oss_formats[i].oss; 674 } 675 } 676 677 return (0); 678 } 679 680 static int 681 sndctl_dsp_getfmts(audio_client_t *c, int *fmtsp) 682 { 683 _NOTE(ARGUNUSED(c)); 684 685 /* 686 * For now, we support all the standard ones. Later we might 687 * add in conditional support for AC3. 688 */ 689 *fmtsp = (AFMT_MU_LAW | AFMT_A_LAW | 690 AFMT_U8 | AFMT_S8 | 691 AFMT_S16_LE |AFMT_S16_BE | 692 AFMT_S24_LE | AFMT_S24_BE | 693 AFMT_S32_LE | AFMT_S32_BE | 694 AFMT_S24_PACKED); 695 696 return (0); 697 } 698 699 static int 700 sndctl_dsp_channels(audio_client_t *c, int *chanp) 701 { 702 int rv; 703 int nchan; 704 int oflag; 705 706 oflag = auclnt_get_oflag(c); 707 708 nchan = *chanp; 709 if (nchan != 0) { 710 if (oflag & FWRITE) { 711 rv = auclnt_set_channels(auclnt_output_stream(c), 712 nchan); 713 if (rv != 0) 714 return (rv); 715 } 716 717 if (oflag & FREAD) { 718 rv = auclnt_set_channels(auclnt_input_stream(c), nchan); 719 if (rv != 0) 720 return (rv); 721 } 722 } 723 724 if (oflag & FWRITE) { 725 nchan = auclnt_get_channels(auclnt_output_stream(c)); 726 } else if (oflag & FREAD) { 727 nchan = auclnt_get_channels(auclnt_input_stream(c)); 728 } 729 *chanp = nchan; 730 return (0); 731 } 732 733 static int 734 sndctl_dsp_stereo(audio_client_t *c, int *onoff) 735 { 736 int nchan; 737 738 switch (*onoff) { 739 case 0: 740 nchan = 1; 741 break; 742 case 1: 743 nchan = 2; 744 break; 745 default: 746 return (EINVAL); 747 } 748 749 return (sndctl_dsp_channels(c, &nchan)); 750 } 751 752 static int 753 sndctl_dsp_post(audio_client_t *c) 754 { 755 if (auclnt_get_oflag(c) & FWRITE) { 756 audio_stream_t *sp = auclnt_output_stream(c); 757 auclnt_flush(sp); 758 auclnt_clear_paused(sp); 759 } 760 return (0); 761 } 762 763 static int 764 sndctl_dsp_getcaps(audio_client_t *c, int *capsp) 765 { 766 int ncaps; 767 int osscaps = 0; 768 769 ncaps = auclnt_get_dev_capab(auclnt_get_dev(c)); 770 771 if (ncaps & AUDIO_CLIENT_CAP_PLAY) 772 osscaps |= PCM_CAP_OUTPUT; 773 if (ncaps & AUDIO_CLIENT_CAP_RECORD) 774 osscaps |= PCM_CAP_INPUT; 775 if (ncaps & AUDIO_CLIENT_CAP_DUPLEX) 776 osscaps |= PCM_CAP_DUPLEX; 777 778 *capsp = osscaps; 779 return (0); 780 } 781 782 static int 783 sndctl_dsp_gettrigger(audio_client_t *c, int *trigp) 784 { 785 int triggers = 0; 786 int oflag; 787 788 oflag = auclnt_get_oflag(c); 789 790 if (oflag & FWRITE) { 791 if (!auclnt_is_paused(auclnt_output_stream(c))) { 792 triggers |= PCM_ENABLE_OUTPUT; 793 } 794 } 795 796 if (oflag & FREAD) { 797 if (!auclnt_is_paused(auclnt_input_stream(c))) { 798 triggers |= PCM_ENABLE_INPUT; 799 } 800 } 801 *trigp = triggers; 802 803 return (0); 804 } 805 806 static int 807 sndctl_dsp_settrigger(audio_client_t *c, int *trigp) 808 { 809 int triggers; 810 int oflag; 811 audio_stream_t *sp; 812 813 oflag = auclnt_get_oflag(c); 814 triggers = *trigp; 815 816 if ((oflag & FWRITE) && (triggers & PCM_ENABLE_OUTPUT)) { 817 sp = auclnt_output_stream(c); 818 auclnt_clear_paused(sp); 819 auclnt_start(sp); 820 } 821 822 if ((oflag & FREAD) && (triggers & PCM_ENABLE_INPUT)) { 823 sp = auclnt_input_stream(c); 824 auclnt_clear_paused(sp); 825 auclnt_start(sp); 826 } 827 828 return (0); 829 } 830 831 struct oss_legacy_volume { 832 pid_t pid; 833 uint8_t ogain; 834 uint8_t igain; 835 }; 836 837 static int 838 oss_legacy_volume_walker(audio_client_t *c, void *arg) 839 { 840 struct oss_legacy_volume *olv = arg; 841 842 if (auclnt_get_pid(c) == olv->pid) { 843 if (olv->ogain <= 100) { 844 auclnt_set_gain(auclnt_output_stream(c), olv->ogain); 845 } 846 if (olv->igain <= 100) { 847 auclnt_set_gain(auclnt_input_stream(c), olv->igain); 848 } 849 } 850 return (AUDIO_WALK_CONTINUE); 851 } 852 853 static void 854 oss_set_legacy_volume(audio_client_t *c, uint8_t ogain, uint8_t igain) 855 { 856 struct oss_legacy_volume olv; 857 858 olv.pid = auclnt_get_pid(c); 859 olv.ogain = ogain; 860 olv.igain = igain; 861 auclnt_dev_walk_clients(auclnt_get_dev(c), 862 oss_legacy_volume_walker, &olv); 863 } 864 865 static int 866 sndctl_dsp_getplayvol(audio_client_t *c, int *volp) 867 { 868 int vol; 869 870 /* convert monophonic soft value to OSS stereo value */ 871 vol = auclnt_get_gain(auclnt_output_stream(c)); 872 *volp = vol | (vol << 8); 873 return (0); 874 } 875 876 static int 877 sndctl_dsp_setplayvol(audio_client_t *c, int *volp) 878 { 879 uint8_t vol; 880 881 vol = *volp & 0xff; 882 if (vol > 100) { 883 return (EINVAL); 884 } 885 886 auclnt_set_gain(auclnt_output_stream(c), vol); 887 *volp = (vol | (vol << 8)); 888 889 return (0); 890 } 891 892 static int 893 sndctl_dsp_getrecvol(audio_client_t *c, int *volp) 894 { 895 int vol; 896 897 vol = auclnt_get_gain(auclnt_input_stream(c)); 898 *volp = (vol | (vol << 8)); 899 return (0); 900 } 901 902 static int 903 sndctl_dsp_setrecvol(audio_client_t *c, int *volp) 904 { 905 uint8_t vol; 906 907 vol = *volp & 0xff; 908 if (vol > 100) { 909 return (EINVAL); 910 } 911 912 auclnt_set_gain(auclnt_input_stream(c), vol); 913 *volp = (vol | (vol << 8)); 914 915 return (0); 916 } 917 918 static int 919 sound_mixer_write_ogain(audio_client_t *c, int *volp) 920 { 921 uint8_t vol; 922 923 vol = *volp & 0xff; 924 if (vol > 100) { 925 return (EINVAL); 926 } 927 oss_set_legacy_volume(c, vol, 255); 928 *volp = (vol | (vol << 8)); 929 return (0); 930 } 931 932 static int 933 sound_mixer_write_igain(audio_client_t *c, int *volp) 934 { 935 uint8_t vol; 936 937 vol = *volp & 0xff; 938 if (vol > 100) { 939 return (EINVAL); 940 } 941 oss_set_legacy_volume(c, 255, vol); 942 *volp = (vol | (vol << 8)); 943 return (0); 944 } 945 946 static int 947 sndctl_dsp_readctl(audio_client_t *c, oss_digital_control *ctl) 948 { 949 /* SPDIF: need to add support with spdif */ 950 _NOTE(ARGUNUSED(c)); 951 _NOTE(ARGUNUSED(ctl)); 952 return (ENOTSUP); 953 } 954 955 static int 956 sndctl_dsp_writectl(audio_client_t *c, oss_digital_control *ctl) 957 { 958 /* SPDIF: need to add support with spdif */ 959 _NOTE(ARGUNUSED(c)); 960 _NOTE(ARGUNUSED(ctl)); 961 return (ENOTSUP); 962 } 963 964 static int 965 sndctl_dsp_cookedmode(audio_client_t *c, int *rvp) 966 { 967 _NOTE(ARGUNUSED(c)); 968 969 /* We are *always* in cooked mode -- at least until we have AC3. */ 970 if (*rvp == 0) { 971 return (ENOTSUP); 972 } else { 973 return (0); 974 } 975 } 976 977 static int 978 sndctl_dsp_silence(audio_client_t *c) 979 { 980 if (auclnt_get_oflag(c) & FWRITE) { 981 audio_stream_t *sp = auclnt_output_stream(c); 982 auclnt_set_paused(sp); 983 auclnt_flush(sp); 984 } 985 return (0); 986 } 987 988 static int 989 sndctl_dsp_skip(audio_client_t *c) 990 { 991 if (auclnt_get_oflag(c) & FWRITE) { 992 audio_stream_t *sp = auclnt_output_stream(c); 993 auclnt_set_paused(sp); 994 auclnt_flush(sp); 995 auclnt_clear_paused(sp); 996 } 997 return (0); 998 } 999 1000 static int 1001 sndctl_dsp_halt_input(audio_client_t *c) 1002 { 1003 if (auclnt_get_oflag(c) & FREAD) { 1004 audio_stream_t *sp = auclnt_input_stream(c); 1005 auclnt_set_paused(sp); 1006 auclnt_flush(sp); 1007 } 1008 return (0); 1009 } 1010 1011 static int 1012 sndctl_dsp_halt_output(audio_client_t *c) 1013 { 1014 if (auclnt_get_oflag(c) & FWRITE) { 1015 audio_stream_t *sp = auclnt_output_stream(c); 1016 auclnt_set_paused(sp); 1017 auclnt_flush(sp); 1018 } 1019 return (0); 1020 } 1021 1022 static int 1023 sndctl_dsp_halt(audio_client_t *c) 1024 { 1025 (void) sndctl_dsp_halt_input(c); 1026 (void) sndctl_dsp_halt_output(c); 1027 return (0); 1028 } 1029 1030 static int 1031 sndctl_dsp_sync(audio_client_t *c) 1032 { 1033 return (auclnt_drain(c)); 1034 } 1035 1036 static int 1037 sndctl_dsp_setfragment(audio_client_t *c, int *fragp) 1038 { 1039 int bufsz; 1040 int nfrags; 1041 int fragsz; 1042 1043 nfrags = (*fragp) >> 16; 1044 if ((nfrags >= 0x7fffU) || (nfrags < 2)) { 1045 /* use infinite setting... no change */ 1046 return (0); 1047 } 1048 1049 fragsz = (*fragp) & 0xffff; 1050 if (fragsz > 16) { 1051 /* basically too big, so, no change */ 1052 return (0); 1053 } 1054 bufsz = (1U << fragsz) * nfrags; 1055 1056 /* 1057 * Now we have our desired buffer size, but we have to 1058 * make sure we have a whole number of fragments >= 2, and 1059 * less than the maximum. 1060 */ 1061 bufsz = ((*fragp) >> 16) * (1U << (*fragp)); 1062 if (bufsz >= 65536) { 1063 return (0); 1064 } 1065 1066 /* 1067 * We set the latency hints in terms of bytes, not fragments. 1068 */ 1069 auclnt_set_latency(auclnt_output_stream(c), 0, bufsz); 1070 auclnt_set_latency(auclnt_input_stream(c), 0, bufsz); 1071 1072 /* 1073 * According to the OSS API documentation, the values provided 1074 * are nothing more than a "hint" and not to be relied upon 1075 * anyway. And we aren't obligated to report the actual 1076 * values back! 1077 */ 1078 return (0); 1079 } 1080 1081 static int 1082 sndctl_dsp_policy(audio_client_t *c, int *policy) 1083 { 1084 int hint = *policy; 1085 if ((hint >= 2) && (hint <= 10)) { 1086 auclnt_set_latency(auclnt_input_stream(c), hint, 0); 1087 auclnt_set_latency(auclnt_output_stream(c), hint, 0); 1088 } 1089 return (0); 1090 } 1091 1092 /* 1093 * A word about recsrc, and playtgt ioctls: We don't allow ordinary DSP 1094 * applications to change port configurations, because these could have a 1095 * bad effect for other applications. Instead, these settings have to 1096 * be changed using the master mixer panel. In order to make applications 1097 * happy, we just present a single "default" source/target. 1098 */ 1099 static int 1100 sndctl_dsp_get_recsrc_names(audio_client_t *c, oss_mixer_enuminfo *ei) 1101 { 1102 _NOTE(ARGUNUSED(c)); 1103 1104 ei->nvalues = 1; 1105 (void) snprintf(ei->strings, sizeof (ei->strings), "default"); 1106 ei->strindex[0] = 0; 1107 1108 return (0); 1109 } 1110 1111 static int 1112 sndctl_dsp_get_recsrc(audio_client_t *c, int *srcp) 1113 { 1114 _NOTE(ARGUNUSED(c)); 1115 *srcp = 0; 1116 return (0); 1117 } 1118 1119 static int 1120 sndctl_dsp_set_recsrc(audio_client_t *c, int *srcp) 1121 { 1122 _NOTE(ARGUNUSED(c)); 1123 *srcp = 0; 1124 return (0); 1125 } 1126 1127 static int 1128 sndctl_dsp_get_playtgt_names(audio_client_t *c, oss_mixer_enuminfo *ei) 1129 { 1130 _NOTE(ARGUNUSED(c)); 1131 1132 ei->nvalues = 1; 1133 (void) snprintf(ei->strings, sizeof (ei->strings), "default"); 1134 ei->strindex[0] = 0; 1135 1136 return (0); 1137 } 1138 1139 static int 1140 sndctl_dsp_get_playtgt(audio_client_t *c, int *tgtp) 1141 { 1142 _NOTE(ARGUNUSED(c)); 1143 *tgtp = 0; 1144 return (0); 1145 } 1146 1147 static int 1148 sndctl_dsp_set_playtgt(audio_client_t *c, int *tgtp) 1149 { 1150 _NOTE(ARGUNUSED(c)); 1151 *tgtp = 0; 1152 return (0); 1153 } 1154 1155 static int 1156 sndctl_sysinfo(oss_sysinfo *si) 1157 { 1158 bzero(si, sizeof (*si)); 1159 (void) snprintf(si->product, sizeof (si->product), "SunOS Audio"); 1160 (void) snprintf(si->version, sizeof (si->version), "4.0"); 1161 si->versionnum = OSS_VERSION; 1162 si->numcards = oss_cnt_devs(); 1163 si->nummixers = si->numcards - 1; 1164 si->numaudios = si->numcards - 1; 1165 si->numaudioengines = si->numaudios; 1166 (void) snprintf(si->license, sizeof (si->license), "CDDL"); 1167 return (0); 1168 } 1169 1170 static int 1171 sndctl_cardinfo(audio_client_t *c, oss_card_info *ci) 1172 { 1173 audio_dev_t *d; 1174 void *iter; 1175 const char *info; 1176 int n; 1177 boolean_t release; 1178 1179 if ((n = ci->card) == -1) { 1180 release = B_FALSE; 1181 d = auclnt_get_dev(c); 1182 n = auclnt_get_dev_index(d); 1183 } else { 1184 release = B_TRUE; 1185 d = auclnt_hold_dev_by_index(n); 1186 } 1187 1188 bzero(ci, sizeof (*ci)); 1189 ci->card = n; 1190 1191 if (d == NULL) { 1192 /* 1193 * If device removed (e.g. for DR), then 1194 * report a bogus removed entry. 1195 */ 1196 (void) snprintf(ci->shortname, sizeof (ci->shortname), 1197 "<removed>"); 1198 (void) snprintf(ci->longname, sizeof (ci->longname), 1199 "<removed>"); 1200 return (0); 1201 } 1202 1203 (void) snprintf(ci->shortname, sizeof (ci->shortname), 1204 "%s", auclnt_get_dev_name(d)); 1205 (void) snprintf(ci->longname, sizeof (ci->longname), 1206 "%s (%s)", auclnt_get_dev_description(d), 1207 auclnt_get_dev_version(d)); 1208 1209 iter = NULL; 1210 while ((info = auclnt_get_dev_hw_info(d, &iter)) != NULL) { 1211 (void) strlcat(ci->hw_info, info, sizeof (ci->hw_info)); 1212 (void) strlcat(ci->hw_info, "\n", sizeof (ci->hw_info)); 1213 } 1214 1215 /* 1216 * We don't report interrupt counts, ack counts (which are 1217 * just "read" interrupts, not spurious), or any other flags. 1218 * Nothing should be using any of this data anyway ... these 1219 * values were intended for 4Front's debugging purposes. In 1220 * Solaris, drivers should use interrupt kstats to report 1221 * interrupt related statistics. 1222 */ 1223 if (release) 1224 auclnt_release_dev(d); 1225 return (0); 1226 } 1227 1228 static int 1229 audioinfo_walker(audio_engine_t *e, void *a) 1230 { 1231 oss_audioinfo *si = a; 1232 int fmt, nchan, rate, cap; 1233 1234 fmt = auclnt_engine_get_format(e); 1235 nchan = auclnt_engine_get_channels(e); 1236 rate = auclnt_engine_get_rate(e); 1237 cap = auclnt_engine_get_capab(e); 1238 1239 for (int i = 0; oss_formats[i].fmt != AUDIO_FORMAT_NONE; i++) { 1240 if (fmt == oss_formats[i].fmt) { 1241 if (cap & AUDIO_CLIENT_CAP_PLAY) { 1242 si->oformats |= oss_formats[i].oss; 1243 } 1244 if (cap & AUDIO_CLIENT_CAP_RECORD) { 1245 si->iformats |= oss_formats[i].oss; 1246 } 1247 break; 1248 } 1249 } 1250 si->max_channels = max(nchan, si->max_channels); 1251 si->max_rate = max(rate, si->max_rate); 1252 1253 return (AUDIO_WALK_CONTINUE); 1254 } 1255 1256 static int 1257 sndctl_audioinfo(audio_client_t *c, oss_audioinfo *si) 1258 { 1259 audio_dev_t *d; 1260 const char *name; 1261 int n; 1262 boolean_t release; 1263 unsigned cap; 1264 1265 if ((n = si->dev) == -1) { 1266 release = B_FALSE; 1267 d = auclnt_get_dev(c); 1268 n = auclnt_get_dev_index(d); 1269 } else { 1270 release = B_TRUE; 1271 n++; /* skip pseudo device */ 1272 d = auclnt_hold_dev_by_index(n); 1273 } 1274 1275 bzero(si, sizeof (*si)); 1276 si->dev = n - 1; 1277 1278 if (d == NULL) { 1279 /* if device not present, forge a false entry */ 1280 si->card_number = n; 1281 si->mixer_dev = n - 1; 1282 si->legacy_device = -1; 1283 si->enabled = 0; 1284 (void) snprintf(si->name, sizeof (si->name), "<removed>"); 1285 return (0); 1286 } 1287 1288 name = auclnt_get_dev_name(d); 1289 (void) snprintf(si->name, sizeof (si->name), "%s", name); 1290 1291 si->legacy_device = auclnt_get_dev_number(d); 1292 si->caps = 0; 1293 1294 auclnt_dev_walk_engines(d, audioinfo_walker, si); 1295 1296 cap = auclnt_get_dev_capab(d); 1297 1298 if (cap & AUDIO_CLIENT_CAP_DUPLEX) { 1299 si->caps |= PCM_CAP_DUPLEX; 1300 } 1301 if (cap & AUDIO_CLIENT_CAP_PLAY) { 1302 si->caps |= PCM_CAP_OUTPUT; 1303 } 1304 if (cap & AUDIO_CLIENT_CAP_RECORD) { 1305 si->caps |= PCM_CAP_INPUT; 1306 } 1307 1308 if (si->caps != 0) { 1309 /* AC3: PCM_CAP_MULTI would be wrong for an AC3 only device */ 1310 si->caps |= PCM_CAP_BATCH | PCM_CAP_TRIGGER | PCM_CAP_MULTI; 1311 /* MMAP: we add PCM_CAP_MMAP when we we support it */ 1312 si->enabled = 1; 1313 si->rate_source = si->dev; 1314 1315 /* we can convert PCM formats */ 1316 if ((si->iformats | si->oformats) & 1317 AUDIO_FORMAT_PCM) { 1318 si->min_channels = min(2, si->max_channels); 1319 si->min_rate = min(5000, si->max_rate); 1320 si->caps |= PCM_CAP_FREERATE; 1321 } 1322 (void) snprintf(si->devnode, sizeof (si->devnode), 1323 "/dev/sound/%s:%ddsp", 1324 auclnt_get_dev_driver(d), auclnt_get_dev_instance(d)); 1325 } else { 1326 si->enabled = 0; /* stops apps from using us directly */ 1327 si->caps = PCM_CAP_VIRTUAL; 1328 (void) snprintf(si->devnode, sizeof (si->devnode), 1329 "/dev/sndstat"); 1330 } 1331 1332 si->pid = -1; 1333 (void) snprintf(si->handle, sizeof (si->handle), "%s", name); 1334 (void) snprintf(si->label, sizeof (si->label), "%s", name); 1335 si->latency = -1; 1336 si->card_number = n; 1337 si->mixer_dev = n - 1; 1338 1339 if (release) 1340 auclnt_release_dev(d); 1341 1342 return (0); 1343 } 1344 1345 static int 1346 sound_mixer_info(audio_client_t *c, mixer_info *mi) 1347 { 1348 audio_dev_t *d; 1349 ossdev_t *odev; 1350 ossclient_t *sc; 1351 const char *name; 1352 1353 sc = auclnt_get_private(c); 1354 odev = sc->o_ossdev; 1355 1356 d = auclnt_get_dev(c); 1357 1358 name = auclnt_get_dev_name(d); 1359 (void) snprintf(mi->id, sizeof (mi->id), "%s", name); 1360 (void) snprintf(mi->name, sizeof (mi->name), "%s", name); 1361 (void) snprintf(mi->handle, sizeof (mi->handle), "%s", name); 1362 mi->modify_counter = odev->d_modify_cnt; 1363 mi->card_number = auclnt_get_dev_index(d); 1364 mi->port_number = 0; 1365 return (0); 1366 } 1367 1368 static int 1369 sound_mixer_read_devmask(audio_client_t *c, int *devmask) 1370 { 1371 _NOTE(ARGUNUSED(c)); 1372 *devmask = SOUND_MASK_VOLUME | SOUND_MASK_PCM | SOUND_MASK_IGAIN; 1373 return (0); 1374 } 1375 1376 static int 1377 sound_mixer_read_recmask(audio_client_t *c, int *recmask) 1378 { 1379 _NOTE(ARGUNUSED(c)); 1380 *recmask = 0; 1381 return (0); 1382 } 1383 1384 static int 1385 sound_mixer_read_recsrc(audio_client_t *c, int *recsrc) 1386 { 1387 _NOTE(ARGUNUSED(c)); 1388 *recsrc = 0; 1389 return (0); 1390 } 1391 1392 static int 1393 sound_mixer_read_caps(audio_client_t *c, int *caps) 1394 { 1395 _NOTE(ARGUNUSED(c)); 1396 /* single recording source... sort of */ 1397 *caps = SOUND_CAP_EXCL_INPUT; 1398 return (0); 1399 } 1400 1401 static int 1402 sndctl_mixerinfo(audio_client_t *c, oss_mixerinfo *mi) 1403 { 1404 audio_dev_t *d; 1405 ossdev_t *odev; 1406 const char *name; 1407 int n; 1408 boolean_t release = B_FALSE; 1409 1410 if ((n = mi->dev) == -1) { 1411 release = B_FALSE; 1412 d = auclnt_get_dev(c); 1413 n = auclnt_get_dev_index(d); 1414 } else { 1415 release = B_TRUE; 1416 n++; 1417 d = auclnt_hold_dev_by_index(n); 1418 } 1419 1420 bzero(mi, sizeof (*mi)); 1421 mi->dev = n - 1; 1422 1423 if (d == NULL) { 1424 mi->card_number = n; 1425 mi->enabled = 0; 1426 mi->legacy_device = -1; 1427 (void) snprintf(mi->name, sizeof (mi->name), "<removed>"); 1428 (void) snprintf(mi->id, sizeof (mi->id), "<removed>"); 1429 return (0); 1430 } 1431 1432 if ((odev = auclnt_get_dev_minor_data(d, AUDIO_MINOR_DSP)) == NULL) { 1433 if (release) 1434 auclnt_release_dev(d); 1435 return (EINVAL); 1436 } 1437 1438 name = auclnt_get_dev_name(d); 1439 (void) snprintf(mi->name, sizeof (mi->name), "%s", name); 1440 (void) snprintf(mi->id, sizeof (mi->id), "%s", name); 1441 (void) snprintf(mi->handle, sizeof (mi->handle), "%s", name); 1442 mi->modify_counter = odev->d_modify_cnt; 1443 mi->card_number = auclnt_get_dev_index(d); 1444 mi->legacy_device = auclnt_get_dev_number(d); 1445 if (mi->legacy_device >= 0) { 1446 (void) snprintf(mi->devnode, sizeof (mi->devnode), 1447 "/dev/sound/%s:%dmixer", 1448 auclnt_get_dev_driver(d), auclnt_get_dev_instance(d)); 1449 mi->enabled = 1; 1450 } else { 1451 /* special nodes use generic sndstat node */ 1452 (void) snprintf(mi->devnode, sizeof (mi->devnode), 1453 "/dev/sndstat"); 1454 mi->enabled = 0; 1455 } 1456 mi->nrext = odev->d_nctrl; 1457 1458 if (release) 1459 auclnt_release_dev(d); 1460 1461 return (0); 1462 } 1463 1464 static int 1465 sndctl_dsp_getblksize(audio_client_t *c, int *fragsz) 1466 { 1467 int oflag = auclnt_get_oflag(c); 1468 1469 if (oflag & FWRITE) 1470 *fragsz = auclnt_get_fragsz(auclnt_output_stream(c)); 1471 else if (oflag & FREAD) 1472 *fragsz = auclnt_get_fragsz(auclnt_input_stream(c)); 1473 1474 return (0); 1475 } 1476 1477 static int 1478 sndctl_dsp_getospace(audio_client_t *c, audio_buf_info *bi) 1479 { 1480 audio_stream_t *sp; 1481 unsigned n; 1482 1483 if ((auclnt_get_oflag(c) & FWRITE) == 0) { 1484 return (EACCES); 1485 } 1486 1487 sp = auclnt_output_stream(c); 1488 n = auclnt_get_nframes(sp) - auclnt_get_count(sp); 1489 1490 bi->fragsize = auclnt_get_fragsz(sp); 1491 bi->fragstotal = auclnt_get_nfrags(sp); 1492 bi->bytes = (n * auclnt_get_framesz(sp)); 1493 bi->fragments = bi->bytes / bi->fragsize; 1494 1495 return (0); 1496 } 1497 1498 static int 1499 sndctl_dsp_getispace(audio_client_t *c, audio_buf_info *bi) 1500 { 1501 audio_stream_t *sp; 1502 unsigned n; 1503 1504 if ((auclnt_get_oflag(c) & FREAD) == 0) { 1505 return (EACCES); 1506 } 1507 1508 sp = auclnt_input_stream(c); 1509 n = auclnt_get_count(sp); 1510 1511 bi->fragsize = auclnt_get_fragsz(sp); 1512 bi->fragstotal = auclnt_get_nfrags(sp); 1513 bi->bytes = (n * auclnt_get_framesz(sp)); 1514 bi->fragments = bi->bytes / bi->fragsize; 1515 1516 return (0); 1517 } 1518 1519 static int 1520 sndctl_dsp_getodelay(audio_client_t *c, int *bytes) 1521 { 1522 unsigned framesz; 1523 unsigned slen, flen; 1524 1525 if (auclnt_get_oflag(c) & FWRITE) { 1526 audio_stream_t *sp = auclnt_output_stream(c); 1527 framesz = auclnt_get_framesz(sp); 1528 auclnt_get_output_qlen(c, &slen, &flen); 1529 *bytes = (slen + flen) * framesz; 1530 } else { 1531 *bytes = 0; 1532 } 1533 return (0); 1534 } 1535 1536 static int 1537 sndctl_dsp_current_iptr(audio_client_t *c, oss_count_t *count) 1538 { 1539 if (auclnt_get_oflag(c) & FREAD) { 1540 count->samples = auclnt_get_samples(auclnt_input_stream(c)); 1541 count->fifo_samples = 0; /* not quite accurate */ 1542 } else { 1543 count->samples = 0; 1544 count->fifo_samples = 0; 1545 } 1546 return (0); 1547 } 1548 1549 static int 1550 sndctl_dsp_current_optr(audio_client_t *c, oss_count_t *count) 1551 { 1552 unsigned samples, fifo; 1553 1554 if (auclnt_get_oflag(c) & FWRITE) { 1555 auclnt_get_output_qlen(c, &samples, &fifo); 1556 count->samples = samples; 1557 count->fifo_samples = fifo; 1558 } else { 1559 count->samples = 0; 1560 count->fifo_samples = 0; 1561 } 1562 return (0); 1563 } 1564 1565 static int 1566 sndctl_dsp_getoptr(audio_client_t *c, count_info *ci) 1567 { 1568 audio_stream_t *sp; 1569 unsigned framesz; 1570 unsigned fragsz; 1571 1572 bzero(ci, sizeof (*ci)); 1573 if ((auclnt_get_oflag(c) & FWRITE) == 0) { 1574 return (0); 1575 } 1576 sp = auclnt_output_stream(c); 1577 framesz = auclnt_get_framesz(sp); 1578 fragsz = auclnt_get_fragsz(sp); 1579 ci->blocks = auclnt_get_samples(sp) * framesz / fragsz; 1580 auclnt_set_samples(sp, 0); 1581 ci->bytes = auclnt_get_tail(sp) * framesz; 1582 ci->ptr = auclnt_get_tidx(sp) * framesz; 1583 return (0); 1584 } 1585 1586 static int 1587 sndctl_dsp_getiptr(audio_client_t *c, count_info *ci) 1588 { 1589 audio_stream_t *sp; 1590 unsigned framesz; 1591 unsigned fragsz; 1592 1593 bzero(ci, sizeof (*ci)); 1594 if ((auclnt_get_oflag(c) & FREAD) == 0) { 1595 return (0); 1596 } 1597 sp = auclnt_input_stream(c); 1598 framesz = auclnt_get_framesz(sp); 1599 fragsz = auclnt_get_fragsz(sp); 1600 ci->blocks = auclnt_get_samples(sp) * framesz / fragsz; 1601 auclnt_set_samples(sp, 0); 1602 ci->bytes = auclnt_get_head(sp) * framesz; 1603 ci->ptr = auclnt_get_hidx(sp) * framesz; 1604 return (0); 1605 } 1606 1607 static int 1608 sndctl_dsp_geterror(audio_client_t *c, audio_errinfo *bi) 1609 { 1610 audio_stream_t *sp; 1611 unsigned fragsz; 1612 /* 1613 * Note: The use of this structure is unsafe... different 1614 * meanings for error codes are used by different implementations, 1615 * according to the spec. (Even different versions of the same 1616 * implementation could have different values.) 1617 * 1618 * Rather than try to come up with a reliable solution here, we 1619 * don't use it. If you want to report errors, or see the result 1620 * of errors, use syslog. 1621 */ 1622 bzero(bi, sizeof (*bi)); 1623 1624 sp = auclnt_output_stream(c); 1625 fragsz = max(auclnt_get_fragsz(sp), 1); 1626 bi->play_underruns = (int)((auclnt_get_errors(sp) + (fragsz - 1)) / 1627 fragsz); 1628 auclnt_set_errors(sp, 0); 1629 1630 sp = auclnt_input_stream(c); 1631 fragsz = max(auclnt_get_fragsz(sp), 1); 1632 bi->rec_overruns = (int)((auclnt_get_errors(sp) + (fragsz - 1)) / 1633 fragsz); 1634 auclnt_set_errors(sp, 0); 1635 1636 return (0); 1637 } 1638 1639 static int 1640 sndctl_sun_send_number(audio_client_t *c, int *num, cred_t *cr) 1641 { 1642 audio_dev_t *dev; 1643 int rv; 1644 1645 if ((rv = drv_priv(cr)) != 0) { 1646 return (rv); 1647 } 1648 1649 dev = auclnt_get_dev(c); 1650 auclnt_set_dev_number(dev, *num); 1651 return (0); 1652 } 1653 1654 static int 1655 oss_getversion(int *versp) 1656 { 1657 *versp = OSS_VERSION; 1658 return (0); 1659 } 1660 1661 static int 1662 oss_ioctl(audio_client_t *c, int cmd, intptr_t arg, int mode, cred_t *credp, 1663 int *rvalp) 1664 { 1665 int sz; 1666 void *data; 1667 int rv = 0; 1668 1669 _NOTE(ARGUNUSED(credp)); 1670 1671 sz = OSSIOC_GETSZ(cmd); 1672 1673 if ((cmd & (OSSIOC_IN | OSSIOC_OUT)) && sz) { 1674 if ((data = kmem_zalloc(sz, KM_NOSLEEP)) == NULL) { 1675 return (ENOMEM); 1676 } 1677 } else { 1678 sz = 0; 1679 } 1680 1681 if (cmd & OSSIOC_IN) { 1682 if ((rv = ddi_copyin((void *)arg, data, sz, mode)) != 0) { 1683 goto done; 1684 } 1685 } 1686 1687 switch (cmd) { 1688 /* 1689 * DSP specific ioctls 1690 */ 1691 case SNDCTL_DSP_HALT: 1692 rv = sndctl_dsp_halt(c); 1693 break; 1694 1695 case SNDCTL_DSP_SYNC: 1696 rv = sndctl_dsp_sync(c); 1697 break; 1698 1699 case SNDCTL_DSP_SPEED: 1700 rv = sndctl_dsp_speed(c, (int *)data); 1701 break; 1702 case SNDCTL_DSP_SETFMT: 1703 rv = sndctl_dsp_setfmt(c, (int *)data); 1704 break; 1705 case SNDCTL_DSP_GETFMTS: 1706 rv = sndctl_dsp_getfmts(c, (int *)data); 1707 break; 1708 case SNDCTL_DSP_STEREO: 1709 rv = sndctl_dsp_stereo(c, (int *)data); 1710 break; 1711 case SNDCTL_DSP_CHANNELS: 1712 rv = sndctl_dsp_channels(c, (int *)data); 1713 break; 1714 case SNDCTL_DSP_POST: 1715 rv = sndctl_dsp_post(c); 1716 break; 1717 case SNDCTL_DSP_GETCAPS: 1718 rv = sndctl_dsp_getcaps(c, (int *)data); 1719 break; 1720 case SNDCTL_DSP_GETTRIGGER: 1721 rv = sndctl_dsp_gettrigger(c, (int *)data); 1722 break; 1723 case SNDCTL_DSP_SETTRIGGER: 1724 rv = sndctl_dsp_settrigger(c, (int *)data); 1725 break; 1726 case SNDCTL_DSP_GETPLAYVOL: 1727 case SOUND_MIXER_READ_VOLUME: /* legacy mixer on dsp */ 1728 case SOUND_MIXER_READ_PCM: /* legacy mixer on dsp */ 1729 case SOUND_MIXER_READ_OGAIN: /* legacy mixer on dsp */ 1730 rv = sndctl_dsp_getplayvol(c, (int *)data); 1731 break; 1732 case SOUND_MIXER_WRITE_VOLUME: /* legacy mixer on dsp */ 1733 case SOUND_MIXER_WRITE_PCM: /* legacy mixer on dsp */ 1734 case SOUND_MIXER_WRITE_OGAIN: /* legacy mixer on dsp */ 1735 rv = sound_mixer_write_ogain(c, (int *)data); 1736 break; 1737 case SNDCTL_DSP_SETPLAYVOL: 1738 rv = sndctl_dsp_setplayvol(c, (int *)data); 1739 break; 1740 case SNDCTL_DSP_READCTL: 1741 rv = sndctl_dsp_readctl(c, (oss_digital_control *)data); 1742 break; 1743 case SNDCTL_DSP_WRITECTL: 1744 rv = sndctl_dsp_writectl(c, (oss_digital_control *)data); 1745 break; 1746 case SNDCTL_DSP_COOKEDMODE: 1747 rv = sndctl_dsp_cookedmode(c, (int *)data); 1748 break; 1749 case SNDCTL_DSP_SILENCE: 1750 rv = sndctl_dsp_silence(c); 1751 break; 1752 case SNDCTL_DSP_SKIP: 1753 rv = sndctl_dsp_skip(c); 1754 break; 1755 case SNDCTL_DSP_HALT_INPUT: 1756 rv = sndctl_dsp_halt_input(c); 1757 break; 1758 case SNDCTL_DSP_HALT_OUTPUT: 1759 rv = sndctl_dsp_halt_output(c); 1760 break; 1761 case SNDCTL_DSP_GET_RECSRC_NAMES: 1762 rv = sndctl_dsp_get_recsrc_names(c, (oss_mixer_enuminfo *)data); 1763 break; 1764 case SNDCTL_DSP_SETFRAGMENT: 1765 rv = sndctl_dsp_setfragment(c, (int *)data); 1766 break; 1767 case SNDCTL_DSP_GET_RECSRC: 1768 rv = sndctl_dsp_get_recsrc(c, (int *)data); 1769 break; 1770 case SNDCTL_DSP_SET_RECSRC: 1771 rv = sndctl_dsp_set_recsrc(c, (int *)data); 1772 break; 1773 case SNDCTL_DSP_GET_PLAYTGT_NAMES: 1774 rv = sndctl_dsp_get_playtgt_names(c, 1775 (oss_mixer_enuminfo *)data); 1776 break; 1777 case SNDCTL_DSP_GET_PLAYTGT: 1778 rv = sndctl_dsp_get_playtgt(c, (int *)data); 1779 break; 1780 case SNDCTL_DSP_SET_PLAYTGT: 1781 rv = sndctl_dsp_set_playtgt(c, (int *)data); 1782 break; 1783 case SNDCTL_DSP_GETRECVOL: 1784 case SOUND_MIXER_READ_RECGAIN: /* legacy mixer on dsp */ 1785 case SOUND_MIXER_READ_RECLEV: /* legacy mixer on dsp */ 1786 case SOUND_MIXER_READ_IGAIN: /* legacy mixer on dsp */ 1787 rv = sndctl_dsp_getrecvol(c, (int *)data); 1788 break; 1789 case SOUND_MIXER_WRITE_RECGAIN: /* legacy mixer on dsp */ 1790 case SOUND_MIXER_WRITE_RECLEV: /* legacy mixer on dsp */ 1791 case SOUND_MIXER_WRITE_IGAIN: /* legacy mixer on dsp */ 1792 rv = sound_mixer_write_igain(c, (int *)data); 1793 break; 1794 case SNDCTL_DSP_SETRECVOL: 1795 rv = sndctl_dsp_setrecvol(c, (int *)data); 1796 break; 1797 case SNDCTL_DSP_SUBDIVIDE: /* Ignored */ 1798 case SNDCTL_DSP_SETDUPLEX: /* Ignored */ 1799 case SNDCTL_DSP_LOW_WATER: /* Ignored */ 1800 case SNDCTL_DSP_PROFILE: /* Ignored */ 1801 rv = 0; 1802 break; 1803 case SNDCTL_DSP_POLICY: 1804 rv = sndctl_dsp_policy(c, (int *)data); 1805 break; 1806 case SNDCTL_DSP_GETBLKSIZE: 1807 rv = sndctl_dsp_getblksize(c, (int *)data); 1808 break; 1809 case SNDCTL_DSP_GETOSPACE: 1810 rv = sndctl_dsp_getospace(c, (audio_buf_info *)data); 1811 break; 1812 case SNDCTL_DSP_GETISPACE: 1813 rv = sndctl_dsp_getispace(c, (audio_buf_info *)data); 1814 break; 1815 case SNDCTL_DSP_GETODELAY: 1816 rv = sndctl_dsp_getodelay(c, (int *)data); 1817 break; 1818 case SNDCTL_DSP_GETOPTR: 1819 rv = sndctl_dsp_getoptr(c, (count_info *)data); 1820 break; 1821 case SNDCTL_DSP_GETIPTR: 1822 rv = sndctl_dsp_getiptr(c, (count_info *)data); 1823 break; 1824 case SNDCTL_DSP_GETERROR: 1825 rv = sndctl_dsp_geterror(c, (audio_errinfo *)data); 1826 break; 1827 case SNDCTL_DSP_CURRENT_IPTR: 1828 rv = sndctl_dsp_current_iptr(c, (oss_count_t *)data); 1829 break; 1830 case SNDCTL_DSP_CURRENT_OPTR: 1831 rv = sndctl_dsp_current_optr(c, (oss_count_t *)data); 1832 break; 1833 1834 /* 1835 * Shared ioctls with /dev/mixer. 1836 */ 1837 case OSS_GETVERSION: 1838 rv = oss_getversion((int *)data); 1839 break; 1840 case SNDCTL_CARDINFO: 1841 rv = sndctl_cardinfo(c, (oss_card_info *)data); 1842 break; 1843 case SNDCTL_ENGINEINFO: 1844 case SNDCTL_AUDIOINFO: 1845 case SNDCTL_AUDIOINFO_EX: 1846 rv = sndctl_audioinfo(c, (oss_audioinfo *)data); 1847 break; 1848 case SNDCTL_SYSINFO: 1849 rv = sndctl_sysinfo((oss_sysinfo *)data); 1850 break; 1851 case SNDCTL_MIXERINFO: 1852 rv = sndctl_mixerinfo(c, (oss_mixerinfo *)data); 1853 break; 1854 case SOUND_MIXER_INFO: 1855 rv = sound_mixer_info(c, (mixer_info *)data); 1856 break; 1857 1858 /* 1859 * These are mixer ioctls that are virtualized for the DSP 1860 * device. They are accessible via either /dev/mixer or 1861 * /dev/dsp. 1862 */ 1863 case SOUND_MIXER_READ_RECSRC: 1864 case SOUND_MIXER_WRITE_RECSRC: 1865 rv = sound_mixer_read_recsrc(c, (int *)data); 1866 break; 1867 1868 case SOUND_MIXER_READ_DEVMASK: 1869 case SOUND_MIXER_READ_STEREODEVS: 1870 rv = sound_mixer_read_devmask(c, (int *)data); 1871 break; 1872 1873 case SOUND_MIXER_READ_RECMASK: 1874 rv = sound_mixer_read_recmask(c, (int *)data); 1875 break; 1876 1877 case SOUND_MIXER_READ_CAPS: 1878 rv = sound_mixer_read_caps(c, (int *)data); 1879 break; 1880 1881 /* 1882 * Ioctls we have chosen not to support for now. Some 1883 * of these are of legacy interest only. 1884 */ 1885 case SNDCTL_SETSONG: 1886 case SNDCTL_GETSONG: 1887 case SNDCTL_DSP_SYNCGROUP: 1888 case SNDCTL_DSP_SYNCSTART: 1889 case SNDCTL_DSP_GET_CHNORDER: 1890 case SNDCTL_DSP_SET_CHNORDER: 1891 case SNDCTL_DSP_GETIPEAKS: 1892 case SNDCTL_DSP_GETOPEAKS: 1893 case SNDCTL_DSP_GETCHANNELMASK: 1894 case SNDCTL_DSP_BIND_CHANNEL: 1895 case SNDCTL_DSP_SETSYNCRO: 1896 default: 1897 rv = EINVAL; 1898 break; 1899 } 1900 1901 if ((rv == 0) && (cmd & OSSIOC_OUT)) { 1902 rv = ddi_copyout(data, (void *)arg, sz, mode); 1903 } 1904 if (rv == 0) { 1905 *rvalp = 0; 1906 } 1907 1908 done: 1909 if (sz) { 1910 kmem_free(data, sz); 1911 } 1912 return (rv); 1913 } 1914 1915 static void 1916 oss_output(audio_client_t *c) 1917 { 1918 auclnt_pollwakeup(c, POLLOUT); 1919 } 1920 1921 static void 1922 oss_input(audio_client_t *c) 1923 { 1924 auclnt_pollwakeup(c, POLLIN | POLLRDNORM); 1925 } 1926 1927 static void 1928 oss_notify(audio_client_t *c) 1929 { 1930 audio_dev_t *d; 1931 ossdev_t *odev; 1932 1933 d = auclnt_get_dev(c); 1934 if ((odev = auclnt_get_dev_minor_data(d, AUDIO_MINOR_DSP)) == NULL) { 1935 return; 1936 } 1937 odev->d_modify_cnt++; 1938 } 1939 1940 static int 1941 ossmix_open(audio_client_t *c, int oflag) 1942 { 1943 int rv; 1944 ossclient_t *sc; 1945 ossdev_t *odev; 1946 1947 _NOTE(ARGUNUSED(oflag)); 1948 1949 if ((rv = auclnt_open(c, AUDIO_FORMAT_NONE, 0)) != 0) { 1950 return (rv); 1951 } 1952 1953 if ((sc = kmem_zalloc(sizeof (*sc), KM_NOSLEEP)) == NULL) { 1954 return (ENOMEM); 1955 } 1956 sc->o_ss_sz = 8192; 1957 if ((sc->o_ss_buf = kmem_zalloc(sc->o_ss_sz, KM_NOSLEEP)) == NULL) { 1958 kmem_free(sc, sizeof (*sc)); 1959 return (ENOMEM); 1960 } 1961 auclnt_set_private(c, sc); 1962 1963 odev = auclnt_get_minor_data(c, AUDIO_MINOR_DSP); 1964 1965 /* set a couple of common fields */ 1966 sc->o_client = c; 1967 sc->o_ossdev = odev; 1968 1969 return (rv); 1970 } 1971 1972 static void 1973 ossmix_close(audio_client_t *c) 1974 { 1975 ossclient_t *sc; 1976 1977 sc = auclnt_get_private(c); 1978 1979 kmem_free(sc->o_ss_buf, sc->o_ss_sz); 1980 kmem_free(sc, sizeof (*sc)); 1981 1982 auclnt_close(c); 1983 } 1984 1985 static int 1986 sndctl_mix_nrext(audio_client_t *c, int *ncp) 1987 { 1988 audio_dev_t *d; 1989 ossdev_t *odev; 1990 1991 d = auclnt_get_dev(c); 1992 1993 if ((*ncp != -1) && (*ncp != (auclnt_get_dev_index(d) - 1))) { 1994 return (ENXIO); 1995 } 1996 1997 if ((odev = auclnt_get_dev_minor_data(d, AUDIO_MINOR_DSP)) == NULL) { 1998 return (EINVAL); 1999 } 2000 2001 *ncp = odev->d_nctrl; 2002 2003 return (0); 2004 } 2005 2006 static int 2007 sndctl_mix_extinfo(audio_client_t *c, oss_mixext *pext) 2008 { 2009 audio_dev_t *d; 2010 ossdev_t *odev; 2011 int rv = 0; 2012 int dev; 2013 2014 d = auclnt_get_dev(c); 2015 2016 if (((dev = pext->dev) != -1) && (dev != (auclnt_get_dev_index(d) - 1))) 2017 return (ENXIO); 2018 2019 if (((odev = auclnt_get_dev_minor_data(d, AUDIO_MINOR_DSP)) == NULL) || 2020 (pext->ctrl >= odev->d_nctrl)) { 2021 return (EINVAL); 2022 } 2023 2024 bcopy(&odev->d_exts[pext->ctrl], pext, sizeof (*pext)); 2025 pext->enumbit = 0; 2026 pext->dev = dev; 2027 2028 return (rv); 2029 } 2030 2031 static int 2032 sndctl_mix_enuminfo(audio_client_t *c, oss_mixer_enuminfo *ei) 2033 { 2034 audio_dev_t *d; 2035 audio_ctrl_desc_t desc; 2036 audio_ctrl_t *ctrl; 2037 ossdev_t *odev; 2038 uint64_t mask; 2039 int bit; 2040 ushort_t nxt; 2041 2042 d = auclnt_get_dev(c); 2043 2044 if ((ei->dev != -1) && (ei->dev != (auclnt_get_dev_index(d) - 1))) 2045 return (ENXIO); 2046 2047 if (((odev = auclnt_get_dev_minor_data(d, AUDIO_MINOR_DSP)) == NULL) || 2048 (ei->ctrl >= odev->d_nctrl) || 2049 (odev->d_exts[ei->ctrl].type != MIXT_ENUM) || 2050 ((ctrl = odev->d_ctrls[ei->ctrl]) == NULL) || 2051 (auclnt_control_describe(ctrl, &desc) != 0)) { 2052 return (EINVAL); 2053 } 2054 2055 mask = desc.acd_maxvalue; 2056 bit = 0; 2057 nxt = 0; 2058 ei->nvalues = 0; 2059 bzero(ei->strings, sizeof (ei->strings)); 2060 bzero(ei->strindex, sizeof (ei->strindex)); 2061 2062 while (mask) { 2063 const char *name = desc.acd_enum[bit]; 2064 nxt = oss_set_enum(ei, nxt, name ? name : ""); 2065 mask >>= 1; 2066 bit++; 2067 } 2068 2069 return (0); 2070 } 2071 2072 static int 2073 sndctl_mix_read(audio_client_t *c, oss_mixer_value *vr) 2074 { 2075 int rv; 2076 uint64_t v; 2077 audio_dev_t *d; 2078 audio_ctrl_t *ctrl; 2079 ossdev_t *odev; 2080 2081 d = auclnt_get_dev(c); 2082 2083 if ((vr->dev != -1) && (vr->dev != (auclnt_get_dev_index(d) - 1))) 2084 return (ENXIO); 2085 2086 if (((odev = auclnt_get_dev_minor_data(d, AUDIO_MINOR_DSP)) == NULL) || 2087 (vr->ctrl >= odev->d_nctrl) || 2088 ((ctrl = odev->d_ctrls[vr->ctrl]) == NULL)) { 2089 return (EINVAL); 2090 } 2091 if ((rv = auclnt_control_read(ctrl, &v)) == 0) { 2092 switch (odev->d_exts[vr->ctrl].type) { 2093 case MIXT_ENUM: 2094 /* translate this from an enum style bit mask */ 2095 vr->value = ddi_ffs((unsigned long)v) - 1; 2096 break; 2097 case MIXT_STEREOSLIDER: 2098 vr->value = (int)ddi_swap16(v & 0xffff); 2099 break; 2100 case MIXT_MONOSLIDER: 2101 vr->value = (int)(v | (v << 8)); 2102 break; 2103 case MIXT_ONOFF: 2104 /* this could be simple, or could be part of a multi */ 2105 if (odev->d_exts[vr->ctrl].enumbit >= 0) { 2106 uint64_t mask; 2107 mask = 1; 2108 mask <<= (odev->d_exts[vr->ctrl].enumbit); 2109 vr->value = (v & mask) ? 1 : 0; 2110 } else { 2111 vr->value = v ? 1 : 0; 2112 } 2113 break; 2114 2115 default: 2116 vr->value = (int)v; 2117 break; 2118 } 2119 } 2120 2121 return (rv); 2122 } 2123 2124 static int 2125 sndctl_mix_write(audio_client_t *c, oss_mixer_value *vr) 2126 { 2127 int rv; 2128 uint64_t v; 2129 audio_dev_t *d; 2130 audio_ctrl_t *ctrl; 2131 ossdev_t *odev; 2132 2133 d = auclnt_get_dev(c); 2134 2135 if ((vr->dev != -1) && (vr->dev != (auclnt_get_dev_index(d) - 1))) 2136 return (ENXIO); 2137 2138 if (((odev = auclnt_get_dev_minor_data(d, AUDIO_MINOR_DSP)) == NULL) || 2139 (vr->ctrl >= odev->d_nctrl) || 2140 ((ctrl = odev->d_ctrls[vr->ctrl]) == NULL)) { 2141 return (EINVAL); 2142 } 2143 2144 switch (odev->d_exts[vr->ctrl].type) { 2145 case MIXT_ONOFF: 2146 /* this could be standalone, or it could be part of a multi */ 2147 if (odev->d_exts[vr->ctrl].enumbit >= 0) { 2148 uint64_t mask; 2149 if ((rv = auclnt_control_read(ctrl, &v)) != 0) { 2150 return (EINVAL); 2151 } 2152 mask = 1; 2153 mask <<= (odev->d_exts[vr->ctrl].enumbit); 2154 if (vr->value) { 2155 v |= mask; 2156 } else { 2157 v &= ~mask; 2158 } 2159 } else { 2160 v = vr->value; 2161 } 2162 break; 2163 case MIXT_ENUM: 2164 /* translate this to an enum style bit mask */ 2165 v = 1U << vr->value; 2166 break; 2167 case MIXT_MONOSLIDER: 2168 /* mask off high order bits */ 2169 v = vr->value & 0xff; 2170 break; 2171 case MIXT_STEREOSLIDER: 2172 /* OSS uses reverse byte ordering */ 2173 v = vr->value; 2174 v = ddi_swap16(vr->value & 0xffff); 2175 break; 2176 default: 2177 v = vr->value; 2178 } 2179 rv = auclnt_control_write(ctrl, v); 2180 2181 return (rv); 2182 } 2183 2184 static int 2185 sndctl_mix_nrmix(audio_client_t *c, int *nmixp) 2186 { 2187 _NOTE(ARGUNUSED(c)); 2188 *nmixp = oss_cnt_devs() - 1; 2189 return (0); 2190 } 2191 2192 static int 2193 ossmix_ioctl(audio_client_t *c, int cmd, intptr_t arg, int mode, cred_t *credp, 2194 int *rvalp) 2195 { 2196 int sz; 2197 void *data; 2198 int rv = 0; 2199 2200 sz = OSSIOC_GETSZ(cmd); 2201 2202 if ((cmd & (OSSIOC_IN | OSSIOC_OUT)) && sz) { 2203 if ((data = kmem_zalloc(sz, KM_NOSLEEP)) == NULL) { 2204 return (ENOMEM); 2205 } 2206 } else { 2207 sz = 0; 2208 } 2209 2210 if (cmd & OSSIOC_IN) { 2211 if ((rv = ddi_copyin((void *)arg, data, sz, mode)) != 0) { 2212 goto done; 2213 } 2214 } 2215 2216 switch (cmd) { 2217 /* 2218 * Mixer specific ioctls 2219 */ 2220 case SNDCTL_MIX_NREXT: 2221 rv = sndctl_mix_nrext(c, (int *)data); 2222 break; 2223 case SNDCTL_MIX_EXTINFO: 2224 rv = sndctl_mix_extinfo(c, (oss_mixext *)data); 2225 break; 2226 case SNDCTL_MIX_ENUMINFO: 2227 rv = sndctl_mix_enuminfo(c, (oss_mixer_enuminfo *)data); 2228 break; 2229 case SNDCTL_MIX_READ: 2230 rv = sndctl_mix_read(c, (oss_mixer_value *)data); 2231 break; 2232 case SNDCTL_MIX_WRITE: 2233 rv = sndctl_mix_write(c, (oss_mixer_value *)data); 2234 break; 2235 case SNDCTL_MIX_NRMIX: 2236 rv = sndctl_mix_nrmix(c, (int *)data); 2237 break; 2238 2239 /* 2240 * Legacy ioctls. These are treated as soft values only, 2241 * and do not affect global hardware state. For use by 2242 * legacy DSP applications. 2243 */ 2244 case SOUND_MIXER_READ_VOLUME: 2245 case SOUND_MIXER_READ_PCM: 2246 case SOUND_MIXER_READ_OGAIN: 2247 rv = sndctl_dsp_getplayvol(c, (int *)data); 2248 break; 2249 2250 case SOUND_MIXER_WRITE_VOLUME: 2251 case SOUND_MIXER_WRITE_PCM: 2252 case SOUND_MIXER_WRITE_OGAIN: 2253 rv = sound_mixer_write_ogain(c, (int *)data); 2254 break; 2255 2256 case SOUND_MIXER_READ_RECGAIN: 2257 case SOUND_MIXER_READ_RECLEV: 2258 case SOUND_MIXER_READ_IGAIN: 2259 rv = sndctl_dsp_getrecvol(c, (int *)data); 2260 break; 2261 2262 case SOUND_MIXER_WRITE_RECGAIN: 2263 case SOUND_MIXER_WRITE_RECLEV: 2264 case SOUND_MIXER_WRITE_IGAIN: 2265 rv = sound_mixer_write_igain(c, (int *)data); 2266 break; 2267 2268 case SOUND_MIXER_READ_RECSRC: 2269 case SOUND_MIXER_WRITE_RECSRC: 2270 rv = sound_mixer_read_recsrc(c, (int *)data); 2271 break; 2272 2273 case SOUND_MIXER_READ_DEVMASK: 2274 case SOUND_MIXER_READ_STEREODEVS: 2275 rv = sound_mixer_read_devmask(c, (int *)data); 2276 break; 2277 2278 case SOUND_MIXER_READ_RECMASK: 2279 rv = sound_mixer_read_recmask(c, (int *)data); 2280 break; 2281 2282 /* 2283 * Common ioctls shared with DSP 2284 */ 2285 case OSS_GETVERSION: 2286 rv = oss_getversion((int *)data); 2287 break; 2288 2289 case SNDCTL_CARDINFO: 2290 rv = sndctl_cardinfo(c, (oss_card_info *)data); 2291 break; 2292 2293 case SNDCTL_ENGINEINFO: 2294 case SNDCTL_AUDIOINFO: 2295 case SNDCTL_AUDIOINFO_EX: 2296 rv = sndctl_audioinfo(c, (oss_audioinfo *)data); 2297 break; 2298 2299 case SNDCTL_SYSINFO: 2300 rv = sndctl_sysinfo((oss_sysinfo *)data); 2301 break; 2302 2303 case SNDCTL_MIXERINFO: 2304 rv = sndctl_mixerinfo(c, (oss_mixerinfo *)data); 2305 break; 2306 2307 case SOUND_MIXER_INFO: 2308 rv = sound_mixer_info(c, (mixer_info *)data); 2309 break; 2310 2311 case SNDCTL_MIX_DESCRIPTION: /* NOT SUPPORTED: tooltip */ 2312 rv = EIO; /* OSS returns EIO for this one */ 2313 break; 2314 2315 /* 2316 * Special implementation-private ioctls. 2317 */ 2318 case SNDCTL_SUN_SEND_NUMBER: 2319 rv = sndctl_sun_send_number(c, (int *)data, credp); 2320 break; 2321 2322 /* 2323 * Legacy ioctls we don't support. 2324 */ 2325 case SOUND_MIXER_WRITE_MONGAIN: 2326 case SOUND_MIXER_READ_MONGAIN: 2327 case SOUND_MIXER_READ_BASS: 2328 case SOUND_MIXER_READ_TREBLE: 2329 case SOUND_MIXER_READ_SPEAKER: 2330 case SOUND_MIXER_READ_LINE: 2331 case SOUND_MIXER_READ_MIC: 2332 case SOUND_MIXER_READ_CD: 2333 case SOUND_MIXER_READ_IMIX: 2334 case SOUND_MIXER_READ_ALTPCM: 2335 case SOUND_MIXER_READ_SYNTH: 2336 case SOUND_MIXER_READ_LINE1: 2337 case SOUND_MIXER_READ_LINE2: 2338 case SOUND_MIXER_READ_LINE3: 2339 case SOUND_MIXER_WRITE_BASS: 2340 case SOUND_MIXER_WRITE_TREBLE: 2341 case SOUND_MIXER_WRITE_SPEAKER: 2342 case SOUND_MIXER_WRITE_LINE: 2343 case SOUND_MIXER_WRITE_MIC: 2344 case SOUND_MIXER_WRITE_CD: 2345 case SOUND_MIXER_WRITE_IMIX: 2346 case SOUND_MIXER_WRITE_ALTPCM: 2347 case SOUND_MIXER_WRITE_SYNTH: 2348 case SOUND_MIXER_WRITE_LINE1: 2349 case SOUND_MIXER_WRITE_LINE2: 2350 case SOUND_MIXER_WRITE_LINE3: 2351 /* 2352 * Additional ioctls we *could* support, but don't. 2353 */ 2354 case SNDCTL_SETSONG: 2355 case SNDCTL_SETLABEL: 2356 case SNDCTL_GETSONG: 2357 case SNDCTL_GETLABEL: 2358 case SNDCTL_MIDIINFO: 2359 case SNDCTL_SETNAME: 2360 default: 2361 rv = EINVAL; 2362 break; 2363 } 2364 2365 if ((rv == 0) && (cmd & OSSIOC_OUT)) { 2366 rv = ddi_copyout(data, (void *)arg, sz, mode); 2367 } 2368 if (rv == 0) { 2369 *rvalp = 0; 2370 } 2371 2372 done: 2373 if (sz) { 2374 kmem_free(data, sz); 2375 } 2376 return (rv); 2377 } 2378 2379 static void * 2380 oss_dev_init(audio_dev_t *dev) 2381 { 2382 ossdev_t *odev; 2383 2384 odev = kmem_zalloc(sizeof (*odev), KM_SLEEP); 2385 odev->d_dev = dev; 2386 2387 mutex_init(&odev->d_mx, NULL, MUTEX_DRIVER, NULL); 2388 cv_init(&odev->d_cv, NULL, CV_DRIVER, NULL); 2389 oss_alloc_controls(odev); 2390 2391 return (odev); 2392 } 2393 2394 static void 2395 oss_dev_fini(void *arg) 2396 { 2397 ossdev_t *odev = arg; 2398 2399 if (odev != NULL) { 2400 oss_free_controls(odev); 2401 mutex_destroy(&odev->d_mx); 2402 cv_destroy(&odev->d_cv); 2403 kmem_free(odev, sizeof (*odev)); 2404 } 2405 } 2406 2407 static void 2408 sndstat_printf(ossclient_t *oc, const char *fmt, ...) 2409 { 2410 va_list va; 2411 2412 va_start(va, fmt); 2413 (void) vsnprintf(oc->o_ss_buf + oc->o_ss_len, 2414 oc->o_ss_sz - oc->o_ss_len, fmt, va); 2415 va_end(va); 2416 oc->o_ss_len = strlen(oc->o_ss_buf); 2417 } 2418 2419 static int 2420 sndstat_dev_walker(audio_dev_t *d, void *arg) 2421 { 2422 ossclient_t *oc = arg; 2423 const char *capstr; 2424 unsigned cap; 2425 2426 cap = auclnt_get_dev_capab(d); 2427 2428 if (cap & AUDIO_CLIENT_CAP_DUPLEX) { 2429 capstr = "DUPLEX"; 2430 } else if ((cap & AUDIO_CLIENT_CAP_PLAY) && 2431 (cap & AUDIO_CLIENT_CAP_RECORD)) { 2432 capstr = "INPUT,OUTPUT"; 2433 } else if (cap & AUDIO_CLIENT_CAP_PLAY) { 2434 capstr = "OUTPUT"; 2435 } else if (cap & AUDIO_CLIENT_CAP_RECORD) { 2436 capstr = "INPUT"; 2437 } else { 2438 capstr = NULL; 2439 } 2440 2441 if (capstr == NULL) 2442 return (AUDIO_WALK_CONTINUE); 2443 2444 sndstat_printf(oc, "%d: %s %s, %s (%s)\n", 2445 auclnt_get_dev_number(d), auclnt_get_dev_name(d), 2446 auclnt_get_dev_description(d), auclnt_get_dev_version(d), capstr); 2447 2448 return (AUDIO_WALK_CONTINUE); 2449 } 2450 2451 static int 2452 sndstat_mixer_walker(audio_dev_t *d, void *arg) 2453 { 2454 ossclient_t *oc = arg; 2455 unsigned cap; 2456 void *iter; 2457 const char *info; 2458 2459 cap = auclnt_get_dev_capab(d); 2460 2461 if ((cap & (AUDIO_CLIENT_CAP_PLAY|AUDIO_CLIENT_CAP_RECORD)) == 0) 2462 return (AUDIO_WALK_CONTINUE); 2463 2464 sndstat_printf(oc, "%d: %s %s, %s\n", 2465 auclnt_get_dev_number(d), auclnt_get_dev_name(d), 2466 auclnt_get_dev_description(d), auclnt_get_dev_version(d)); 2467 iter = NULL; 2468 while ((info = auclnt_get_dev_hw_info(d, &iter)) != NULL) { 2469 sndstat_printf(oc, "\t%s\n", info); 2470 } 2471 return (AUDIO_WALK_CONTINUE); 2472 } 2473 2474 static int 2475 ossmix_write(audio_client_t *c, struct uio *uio, cred_t *cr) 2476 { 2477 /* write on sndstat is a no-op */ 2478 _NOTE(ARGUNUSED(c)); 2479 _NOTE(ARGUNUSED(uio)); 2480 _NOTE(ARGUNUSED(cr)); 2481 2482 return (0); 2483 } 2484 2485 static int 2486 ossmix_read(audio_client_t *c, struct uio *uio, cred_t *cr) 2487 { 2488 ossclient_t *oc; 2489 unsigned n; 2490 int rv; 2491 2492 _NOTE(ARGUNUSED(cr)); 2493 2494 if (uio->uio_resid == 0) { 2495 return (0); 2496 } 2497 2498 oc = auclnt_get_private(c); 2499 2500 mutex_enter(&oc->o_ss_lock); 2501 2502 if (oc->o_ss_off == 0) { 2503 2504 sndstat_printf(oc, "SunOS Audio Framework\n"); 2505 2506 sndstat_printf(oc, "\nAudio Devices:\n"); 2507 auclnt_walk_devs_by_number(sndstat_dev_walker, oc); 2508 2509 sndstat_printf(oc, "\nMixers:\n"); 2510 auclnt_walk_devs_by_number(sndstat_mixer_walker, oc); 2511 } 2512 2513 /* 2514 * For simplicity's sake, we implement a non-seekable device. We could 2515 * support seekability, but offsets would be rather meaningless between 2516 * changes. 2517 */ 2518 n = min(uio->uio_resid, (oc->o_ss_len - oc->o_ss_off)); 2519 2520 rv = uiomove(oc->o_ss_buf + oc->o_ss_off, n, UIO_READ, uio); 2521 if (rv != 0) { 2522 n = 0; 2523 } 2524 oc->o_ss_off += n; 2525 2526 if (n == 0) { 2527 /* 2528 * end-of-file reached... clear the sndstat buffer so that 2529 * subsequent reads will get the latest data. 2530 */ 2531 oc->o_ss_off = oc->o_ss_len = 0; 2532 } 2533 mutex_exit(&oc->o_ss_lock); 2534 return (rv); 2535 } 2536 2537 int 2538 oss_read(audio_client_t *c, struct uio *uio, cred_t *cr) 2539 { 2540 _NOTE(ARGUNUSED(cr)); 2541 2542 auclnt_clear_paused(auclnt_input_stream(c)); 2543 2544 return (auclnt_read(c, uio)); 2545 } 2546 2547 int 2548 oss_write(audio_client_t *c, struct uio *uio, cred_t *cr) 2549 { 2550 _NOTE(ARGUNUSED(cr)); 2551 2552 auclnt_clear_paused(auclnt_output_stream(c)); 2553 2554 return (auclnt_write(c, uio)); 2555 } 2556 2557 int 2558 oss_chpoll(audio_client_t *c, short events, int anyyet, short *reventsp, 2559 struct pollhead **phpp) 2560 { 2561 return (auclnt_chpoll(c, events, anyyet, reventsp, phpp)); 2562 } 2563 2564 static struct audio_client_ops oss_ops = { 2565 "sound,dsp", 2566 oss_dev_init, 2567 oss_dev_fini, 2568 oss_open, 2569 oss_close, 2570 oss_read, 2571 oss_write, 2572 oss_ioctl, 2573 oss_chpoll, 2574 NULL, /* mmap */ 2575 oss_input, 2576 oss_output, 2577 NULL, /* notify */ 2578 NULL, /* drain */ 2579 }; 2580 2581 static struct audio_client_ops ossmix_ops = { 2582 "sound,mixer", 2583 NULL, 2584 NULL, 2585 ossmix_open, 2586 ossmix_close, 2587 ossmix_read, 2588 ossmix_write, 2589 ossmix_ioctl, 2590 NULL, /* chpoll */ 2591 NULL, /* mmap */ 2592 NULL, /* input */ 2593 NULL, /* output */ 2594 oss_notify, 2595 NULL, /* drain */ 2596 }; 2597 2598 /* nearly the same as ossxmix; different minor name helps devfsadm */ 2599 static struct audio_client_ops sndstat_ops = { 2600 "sound,sndstat", 2601 NULL, /* dev_init */ 2602 NULL, /* dev_fini */ 2603 ossmix_open, 2604 ossmix_close, 2605 ossmix_read, 2606 ossmix_write, 2607 ossmix_ioctl, 2608 NULL, /* chpoll */ 2609 NULL, /* mmap */ 2610 NULL, /* input */ 2611 NULL, /* output */ 2612 NULL, /* notify */ 2613 NULL, /* drain */ 2614 }; 2615 2616 void 2617 auimpl_oss_init(void) 2618 { 2619 auclnt_register_ops(AUDIO_MINOR_DSP, &oss_ops); 2620 auclnt_register_ops(AUDIO_MINOR_MIXER, &ossmix_ops); 2621 auclnt_register_ops(AUDIO_MINOR_SNDSTAT, &sndstat_ops); 2622 } 2623