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_nctrl; /* num actual controls */ 82 uint_t d_nalloc; /* num allocated controls */ 83 audio_ctrl_t **d_ctrls; /* array of control handles */ 84 oss_mixext *d_exts; /* array of mixer descs */ 85 86 int d_play_grp; 87 int d_rec_grp; 88 int d_mon_grp; 89 int d_misc_grp; 90 91 kmutex_t d_mx; 92 kcondvar_t d_cv; 93 }; 94 95 static int 96 oss_cnt_controls(audio_ctrl_t *ctrl, void *arg) 97 { 98 int *pint = (int *)arg; 99 int cnt; 100 audio_ctrl_desc_t desc; 101 102 cnt = *pint; 103 cnt++; 104 *pint = cnt; 105 106 if (auclnt_control_describe(ctrl, &desc) != 0) 107 return (AUDIO_WALK_CONTINUE); 108 109 if (desc.acd_flags & AUDIO_CTRL_FLAG_MULTI) { 110 for (uint64_t mask = desc.acd_maxvalue; mask; mask >>= 1) { 111 if (mask & 1) { 112 cnt++; 113 } 114 } 115 *pint = cnt; 116 } 117 118 return (AUDIO_WALK_CONTINUE); 119 } 120 121 /* 122 * Add one entry to the OSS user control table to internal control 123 * helper table. 124 * 125 * This is used with auimpl_walk_controls. The table must be pre- 126 * allocated before it is walk'd. This includes the root and 127 * extended control markers! 128 */ 129 static int 130 oss_add_control(audio_ctrl_t *ctrl, void *arg) 131 { 132 ossdev_t *odev = arg; 133 audio_ctrl_desc_t desc; 134 oss_mixext *ext; 135 int bit; 136 uint64_t mask; 137 const char *name; 138 int parent; 139 int flags; 140 unsigned scope; 141 142 if (auclnt_control_describe(ctrl, &desc)) 143 return (AUDIO_WALK_CONTINUE); 144 145 parent = 0; 146 147 /* 148 * Add appropriate group if not already done so. 149 */ 150 if (desc.acd_flags & AUDIO_CTRL_FLAG_PLAY) { 151 if (!odev->d_play_grp) { 152 ext = &odev->d_exts[odev->d_nctrl]; 153 ext->ctrl = odev->d_nctrl; 154 ext->control_no = -1; 155 ext->type = MIXT_GROUP; 156 ext->desc = MIXEXT_SCOPE_OUTPUT; 157 ext->timestamp = gethrtime(); 158 (void) snprintf(ext->id, sizeof (ext->id), "PLAYBACK"); 159 odev->d_play_grp = odev->d_nctrl; 160 odev->d_nctrl++; 161 } 162 scope = MIXEXT_SCOPE_OUTPUT; 163 parent = odev->d_play_grp; 164 } else if (desc.acd_flags & AUDIO_CTRL_FLAG_REC) { 165 if (!odev->d_rec_grp) { 166 ext = &odev->d_exts[odev->d_nctrl]; 167 ext->ctrl = odev->d_nctrl; 168 ext->control_no = -1; 169 ext->type = MIXT_GROUP; 170 ext->desc = MIXEXT_SCOPE_INPUT; 171 ext->timestamp = gethrtime(); 172 (void) snprintf(ext->id, sizeof (ext->id), "RECORD"); 173 odev->d_rec_grp = odev->d_nctrl; 174 odev->d_nctrl++; 175 } 176 scope = MIXEXT_SCOPE_INPUT; 177 parent = odev->d_rec_grp; 178 } else if (desc.acd_flags & AUDIO_CTRL_FLAG_MONITOR) { 179 if (!odev->d_mon_grp) { 180 ext = &odev->d_exts[odev->d_nctrl]; 181 ext->ctrl = odev->d_nctrl; 182 ext->control_no = -1; 183 ext->type = MIXT_GROUP; 184 ext->desc = MIXEXT_SCOPE_MONITOR; 185 ext->timestamp = gethrtime(); 186 (void) snprintf(ext->id, sizeof (ext->id), "MONITOR"); 187 odev->d_mon_grp = odev->d_nctrl; 188 odev->d_nctrl++; 189 } 190 scope = MIXEXT_SCOPE_MONITOR; 191 parent = odev->d_mon_grp; 192 } else { 193 if (!odev->d_misc_grp) { 194 ext = &odev->d_exts[odev->d_nctrl]; 195 ext->ctrl = odev->d_nctrl; 196 ext->control_no = -1; 197 ext->type = MIXT_GROUP; 198 ext->desc = MIXEXT_SCOPE_OTHER; 199 ext->timestamp = gethrtime(); 200 (void) snprintf(ext->id, sizeof (ext->id), "MISC"); 201 odev->d_misc_grp = odev->d_nctrl; 202 odev->d_nctrl++; 203 } 204 scope = MIXEXT_SCOPE_OTHER; 205 parent = odev->d_misc_grp; 206 } 207 208 name = desc.acd_name ? desc.acd_name : ""; 209 210 if (desc.acd_flags & AUDIO_CTRL_FLAG_MULTI) { 211 ext = &odev->d_exts[odev->d_nctrl]; 212 ext->ctrl = odev->d_nctrl; 213 ext->control_no = -1; 214 ext->type = MIXT_GROUP; 215 ext->timestamp = gethrtime(); 216 ext->parent = parent; 217 ext->desc = scope; 218 (void) snprintf(ext->id, sizeof (ext->id), "%s", name); 219 (void) snprintf(ext->extname, sizeof (ext->extname), 220 "%s", name); 221 parent = odev->d_nctrl++; 222 } 223 224 /* Next available open entry */ 225 ext = &odev->d_exts[odev->d_nctrl]; 226 227 /* Record the underlying control handle */ 228 odev->d_ctrls[odev->d_nctrl] = ctrl; 229 230 /* 231 * Now setup the oss entry 232 */ 233 234 ext->ctrl = odev->d_nctrl; 235 ext->control_no = -1; 236 ext->maxvalue = (int)desc.acd_maxvalue; 237 ext->minvalue = (int)desc.acd_minvalue; 238 ext->timestamp = gethrtime(); 239 ext->parent = parent; 240 ext->desc = scope; 241 /* all controls should be pollable for now */ 242 flags = MIXF_POLL; 243 244 /* 245 * The following flags are intended to help out applications 246 * which need to figure out where to place certain controls. 247 * A few further words of guidance: 248 * 249 * Apps that just want a single master volume control should 250 * adjust the control(s) that are labelled with MIXF_PCMVOL if 251 * present. They can fall back to adjusting all MAINVOL 252 * levels instead, if no PCMVOL is present. 253 * 254 * Controls that are one type on a certain device might be a 255 * different type on another device. For example, 256 * audiopci/ak4531 can adjust input gains for individual 257 * levels, but lacks a master record gain. AC'97, on the 258 * other hand, has individual monitor gains for inputs, but 259 * only a single master recording gain. 260 */ 261 if (desc.acd_flags & AUDIO_CTRL_FLAG_READABLE) 262 flags |= MIXF_READABLE; 263 if (desc.acd_flags & AUDIO_CTRL_FLAG_WRITEABLE) 264 flags |= MIXF_WRITEABLE; 265 if (desc.acd_flags & AUDIO_CTRL_FLAG_CENTIBEL) 266 flags |= MIXF_CENTIBEL; 267 if (desc.acd_flags & AUDIO_CTRL_FLAG_DECIBEL) 268 flags |= MIXF_DECIBEL; 269 if (desc.acd_flags & AUDIO_CTRL_FLAG_MAINVOL) 270 flags |= MIXF_MAINVOL; 271 if (desc.acd_flags & AUDIO_CTRL_FLAG_PCMVOL) 272 flags |= MIXF_PCMVOL; 273 if (desc.acd_flags & AUDIO_CTRL_FLAG_RECVOL) 274 flags |= MIXF_RECVOL; 275 if (desc.acd_flags & AUDIO_CTRL_FLAG_MONVOL) 276 flags |= MIXF_MONVOL; 277 ext->flags = flags; 278 279 (void) snprintf(ext->id, sizeof (ext->id), "%s", name); 280 281 /* 282 * For now just use the same extname as the real name. 283 */ 284 (void) snprintf(ext->extname, sizeof (ext->extname), name); 285 286 /* 287 * Now we deal with various control types. 288 */ 289 switch (desc.acd_type) { 290 case AUDIO_CTRL_TYPE_BOOLEAN: 291 ext->type = MIXT_ONOFF; 292 ext->enumbit = -1; 293 break; 294 case AUDIO_CTRL_TYPE_STEREO: 295 ext->type = MIXT_STEREOSLIDER; 296 break; 297 case AUDIO_CTRL_TYPE_MONO: 298 ext->type = MIXT_MONOSLIDER; 299 break; 300 case AUDIO_CTRL_TYPE_ENUM: 301 302 if (desc.acd_flags & AUDIO_CTRL_FLAG_MULTI) { 303 /* 304 * We turn AUDIO_CTRL_FLAG_MULTI into a group 305 * of checkboxes, since OSS can't represent it 306 * natively. 307 */ 308 mask = desc.acd_maxvalue; 309 bit = 0; 310 while (mask) { 311 if (mask & 1) { 312 ext = &odev->d_exts[odev->d_nctrl]; 313 (void) snprintf(ext->extname, 314 sizeof (ext->extname), "%s.%s", 315 name, desc.acd_enum[bit]); 316 (void) snprintf(ext->id, 317 sizeof (ext->id), "%s", 318 desc.acd_enum[bit]); 319 ext->ctrl = odev->d_nctrl; 320 ext->control_no = -1; 321 ext->parent = parent; 322 ext->timestamp = gethrtime(); 323 ext->type = MIXT_ONOFF; 324 ext->minvalue = 0; 325 ext->maxvalue = 1; 326 ext->enumbit = bit; 327 ext->flags = flags; 328 odev->d_ctrls[odev->d_nctrl] = ctrl; 329 odev->d_nctrl++; 330 } 331 bit++; 332 mask >>= 1; 333 } 334 return (AUDIO_WALK_CONTINUE); 335 } else { 336 /* 337 * NB: This is sufficient only for controls 338 * with a single value. It cannot express the 339 * richer bitmask capabilities. 340 */ 341 ext->type = MIXT_ENUM; 342 ext->minvalue = 0; 343 344 /* 345 * For an enumaration, we need to figure out 346 * which values are present, and set the 347 * appropriate mask and max value. 348 */ 349 bzero(ext->enum_present, sizeof (ext->enum_present)); 350 mask = desc.acd_maxvalue; 351 bit = 0; 352 while (mask) { 353 if (mask & 1) { 354 ext->enum_present[bit / 8] |= 355 (1 << (bit % 8)); 356 } 357 mask >>= 1; 358 bit++; 359 } 360 ext->maxvalue = bit; 361 } 362 break; 363 364 case AUDIO_CTRL_TYPE_METER: 365 default: 366 /* Its an unknown or unsupported (for now) control, skip */ 367 return (AUDIO_WALK_CONTINUE); 368 } 369 370 odev->d_nctrl++; 371 372 return (AUDIO_WALK_CONTINUE); 373 } 374 375 /* 376 * Free up an OSS user land control to internal control, 377 * helper table. 378 */ 379 static void 380 oss_free_controls(ossdev_t *odev) 381 { 382 kmem_free(odev->d_ctrls, sizeof (audio_ctrl_t *) * odev->d_nalloc); 383 kmem_free(odev->d_exts, sizeof (oss_mixext) * odev->d_nalloc); 384 odev->d_nctrl = 0; 385 odev->d_nalloc = 0; 386 } 387 388 /* 389 * Allocate and fill in an OSS user land controls to internal controls 390 * helper table. This is done on one audio_dev device. 391 */ 392 static void 393 oss_alloc_controls(ossdev_t *odev) 394 { 395 audio_dev_t *d = odev->d_dev; 396 int nctrl = 0; 397 oss_mixext *ext; 398 oss_mixext_root *root_data; 399 400 /* Find out who many entries we need */ 401 auclnt_walk_controls(d, oss_cnt_controls, &nctrl); 402 nctrl++; /* Needs space for the device root node */ 403 nctrl++; /* Needs space for the device ext marker */ 404 nctrl++; /* Needs space for the play group */ 405 nctrl++; /* Needs space for the record group */ 406 nctrl++; /* Needs space for the monitor group */ 407 nctrl++; /* Needs space for the tone group */ 408 nctrl++; /* Needs space for the 3D group */ 409 nctrl++; /* Needs space for the misc group */ 410 411 /* Allocate the OSS to boomer helper table */ 412 odev->d_nalloc = nctrl; 413 odev->d_ctrls = kmem_zalloc(sizeof (audio_ctrl_t *) * nctrl, KM_SLEEP); 414 odev->d_exts = kmem_zalloc(sizeof (oss_mixext) * nctrl, KM_SLEEP); 415 416 /* 417 * Setup special case outputs to output OSS routes helper tables 418 */ 419 420 /* 421 * Root node is first, that way all others parent is this one 422 */ 423 ext = &odev->d_exts[odev->d_nctrl]; 424 ext->ctrl = 0; 425 ext->parent = -1; 426 ext->type = MIXT_DEVROOT; 427 ext->timestamp = gethrtime(); 428 (void) snprintf(ext->id, sizeof (ext->id), "DEVROOT"); 429 /* 430 * Root data... nobody should be using this though. 431 */ 432 root_data = (oss_mixext_root *)&ext->data; 433 (void) snprintf(root_data->name, sizeof (root_data->name), "%s", 434 auclnt_get_dev_name(d)); 435 (void) snprintf(root_data->id, sizeof (root_data->id), "%s", 436 auclnt_get_dev_name(d)); 437 438 odev->d_nctrl++; 439 440 /* 441 * Insert an extra marker -- needed to keep layout apps hapy. 442 * This prevents some apps from assuming we are in "LEGACY" mode. 443 */ 444 ext = &odev->d_exts[odev->d_nctrl]; 445 ext->ctrl = odev->d_nctrl; 446 ext->control_no = -1; 447 ext->type = MIXT_MARKER; 448 ext->timestamp = gethrtime(); 449 ext->parent = 0; 450 odev->d_nctrl++; 451 452 /* Fill in the complete table now */ 453 auclnt_walk_controls(d, oss_add_control, odev); 454 455 /* Update the update_counter reference counter for groups */ 456 for (nctrl = 0; nctrl < odev->d_nctrl; nctrl++) { 457 int i; 458 459 ext = &odev->d_exts[nctrl]; 460 i = ext->parent; 461 while ((i >= 0) && (i < odev->d_nctrl)) { 462 463 ext = &odev->d_exts[i]; 464 ASSERT(ext->parent < i); 465 ASSERT((ext->type == MIXT_GROUP) || 466 (ext->type == MIXT_DEVROOT)); 467 ext->update_counter++; 468 i = ext->parent; 469 } 470 } 471 472 ASSERT(odev->d_nctrl <= odev->d_nalloc); 473 } 474 475 static int 476 oss_open(audio_client_t *c, int oflag) 477 { 478 int rv; 479 ossdev_t *odev; 480 ossclient_t *sc; 481 audio_stream_t *isp, *osp; 482 483 isp = auclnt_input_stream(c); 484 osp = auclnt_output_stream(c); 485 486 /* note that OSS always uses nonblocking open() semantics */ 487 if ((rv = auclnt_open(c, AUDIO_FORMAT_PCM, oflag | FNDELAY)) != 0) { 488 return (rv); 489 } 490 491 if ((sc = kmem_zalloc(sizeof (*sc), KM_NOSLEEP)) == NULL) { 492 auclnt_close(c); 493 return (ENOMEM); 494 } 495 auclnt_set_private(c, sc); 496 497 odev = auclnt_get_minor_data(c, AUDIO_MINOR_DSP); 498 499 /* set a couple of common fields */ 500 sc->o_client = c; 501 sc->o_ossdev = odev; 502 503 /* set all default parameters */ 504 if (oflag & FWRITE) { 505 if (((rv = auclnt_set_format(osp, OSS_FMT)) != 0) || 506 ((rv = auclnt_set_rate(osp, OSS_RATE)) != 0) || 507 ((rv = auclnt_set_channels(osp, OSS_CHANNELS)) != 0)) { 508 goto failed; 509 } 510 /* default to 5 fragments to provide reasonable latency */ 511 auclnt_set_latency(osp, 5, 0); 512 } 513 514 if (oflag & FREAD) { 515 if (((rv = auclnt_set_format(isp, OSS_FMT)) != 0) || 516 ((rv = auclnt_set_rate(isp, OSS_RATE)) != 0) || 517 ((rv = auclnt_set_channels(isp, OSS_CHANNELS)) != 0)) { 518 goto failed; 519 } 520 /* default to 5 fragments to provide reasonable latency */ 521 auclnt_set_latency(isp, 5, 0); 522 } 523 524 return (0); 525 526 failed: 527 auclnt_close(c); 528 return (rv); 529 } 530 531 static void 532 oss_close(audio_client_t *c) 533 { 534 ossclient_t *sc; 535 536 sc = auclnt_get_private(c); 537 538 if (ddi_can_receive_sig() || (ddi_get_pid() == 0)) { 539 (void) auclnt_drain(c); 540 } 541 542 kmem_free(sc, sizeof (*sc)); 543 544 auclnt_close(c); 545 } 546 547 /* 548 * This is used to generate an array of names for an enumeration 549 */ 550 static ushort_t 551 oss_set_enum(oss_mixer_enuminfo *ei, ushort_t nxt, const char *name) 552 { 553 uint32_t n; 554 555 /* Get current entry to fill in */ 556 n = ei->nvalues; 557 (void) snprintf(&ei->strings[nxt], ((sizeof (ei->strings) - nxt) - 1), 558 "%s", name); 559 ei->strindex[n] = nxt; 560 561 /* Adjust everything for next entry */ 562 nxt += strnlen(name, ((sizeof (ei->strings) - nxt) - 1)); 563 ei->strings[nxt++] = '\0'; 564 565 ei->nvalues++; 566 return (nxt); 567 } 568 569 /* 570 * The following two functions are used to count the number of devices 571 * in under the boomer framework. 572 * 573 * We actually report the highest "index", and then if an audio device 574 * is not found, we report a bogus removed device for it in the actual 575 * ioctls. This goofiness is required to make the OSS API happy. 576 */ 577 int 578 oss_dev_walker(audio_dev_t *d, void *arg) 579 { 580 int *pcnt = arg; 581 int cnt; 582 int index; 583 584 cnt = *pcnt; 585 index = auclnt_get_dev_index(d); 586 if ((index + 1) > cnt) { 587 cnt = index + 1; 588 *pcnt = cnt; 589 } 590 591 return (AUDIO_WALK_CONTINUE); 592 } 593 594 static int 595 oss_cnt_devs(void) 596 { 597 int cnt = 0; 598 599 auclnt_walk_devs(oss_dev_walker, &cnt); 600 return (cnt); 601 } 602 603 static int 604 sndctl_dsp_speed(audio_client_t *c, int *ratep) 605 { 606 int rate; 607 int oflag; 608 609 rate = *ratep; 610 611 oflag = auclnt_get_oflag(c); 612 if (oflag & FREAD) { 613 (void) auclnt_set_rate(auclnt_input_stream(c), rate); 614 *ratep = auclnt_get_rate(auclnt_input_stream(c)); 615 } 616 617 if (oflag & FWRITE) { 618 (void) auclnt_set_rate(auclnt_output_stream(c), rate); 619 *ratep = auclnt_get_rate(auclnt_output_stream(c)); 620 } 621 622 return (0); 623 } 624 625 static int 626 sndctl_dsp_setfmt(audio_client_t *c, int *fmtp) 627 { 628 int fmt; 629 int i; 630 int oflag; 631 632 oflag = auclnt_get_oflag(c); 633 634 if (*fmtp != AFMT_QUERY) { 635 /* convert from OSS */ 636 for (i = 0; oss_formats[i].fmt != AUDIO_FORMAT_NONE; i++) { 637 if (oss_formats[i].oss == *fmtp) { 638 fmt = oss_formats[i].fmt; 639 break; 640 } 641 } 642 if (fmt == AUDIO_FORMAT_NONE) { 643 /* if format not known, return */ 644 goto done; 645 } 646 647 if (oflag & FWRITE) { 648 (void) auclnt_set_format(auclnt_output_stream(c), fmt); 649 } 650 651 if (oflag & FREAD) { 652 (void) auclnt_set_format(auclnt_input_stream(c), fmt); 653 } 654 } 655 656 done: 657 if (oflag & FWRITE) { 658 fmt = auclnt_get_format(auclnt_output_stream(c)); 659 } else if (oflag & FREAD) { 660 fmt = auclnt_get_format(auclnt_input_stream(c)); 661 } 662 663 /* convert back to OSS */ 664 *(int *)fmtp = AFMT_QUERY; 665 for (i = 0; oss_formats[i].fmt != AUDIO_FORMAT_NONE; i++) { 666 if (oss_formats[i].fmt == fmt) { 667 *(int *)fmtp = oss_formats[i].oss; 668 } 669 } 670 671 return (0); 672 } 673 674 static int 675 sndctl_dsp_getfmts(audio_client_t *c, int *fmtsp) 676 { 677 _NOTE(ARGUNUSED(c)); 678 679 /* 680 * For now, we support all the standard ones. Later we might 681 * add in conditional support for AC3. 682 */ 683 *fmtsp = (AFMT_MU_LAW | AFMT_A_LAW | 684 AFMT_U8 | AFMT_S8 | 685 AFMT_S16_LE |AFMT_S16_BE | 686 AFMT_S24_LE | AFMT_S24_BE | 687 AFMT_S32_LE | AFMT_S32_BE | 688 AFMT_S24_PACKED); 689 690 return (0); 691 } 692 693 static int 694 sndctl_dsp_channels(audio_client_t *c, int *chanp) 695 { 696 int nchan; 697 int oflag; 698 699 oflag = auclnt_get_oflag(c); 700 701 nchan = *chanp; 702 if (nchan != 0) { 703 if (oflag & FWRITE) { 704 (void) auclnt_set_channels(auclnt_output_stream(c), 705 nchan); 706 } 707 708 if (oflag & FREAD) { 709 (void) auclnt_set_channels(auclnt_input_stream(c), 710 nchan); 711 } 712 } 713 714 if (oflag & FWRITE) { 715 nchan = auclnt_get_channels(auclnt_output_stream(c)); 716 } else if (oflag & FREAD) { 717 nchan = auclnt_get_channels(auclnt_input_stream(c)); 718 } 719 *chanp = nchan; 720 return (0); 721 } 722 723 static int 724 sndctl_dsp_stereo(audio_client_t *c, int *onoff) 725 { 726 int nchan; 727 728 switch (*onoff) { 729 case 0: 730 nchan = 1; 731 break; 732 case 1: 733 nchan = 2; 734 break; 735 default: 736 return (EINVAL); 737 } 738 739 return (sndctl_dsp_channels(c, &nchan)); 740 } 741 742 static int 743 sndctl_dsp_post(audio_client_t *c) 744 { 745 if (auclnt_get_oflag(c) & FWRITE) { 746 audio_stream_t *sp = auclnt_output_stream(c); 747 auclnt_flush(sp); 748 auclnt_clear_paused(sp); 749 } 750 return (0); 751 } 752 753 static int 754 sndctl_dsp_getcaps(audio_client_t *c, int *capsp) 755 { 756 int ncaps; 757 int osscaps = 0; 758 759 ncaps = auclnt_get_dev_capab(auclnt_get_dev(c)); 760 761 if (ncaps & AUDIO_CLIENT_CAP_PLAY) 762 osscaps |= PCM_CAP_OUTPUT; 763 if (ncaps & AUDIO_CLIENT_CAP_RECORD) 764 osscaps |= PCM_CAP_INPUT; 765 if (ncaps & AUDIO_CLIENT_CAP_DUPLEX) 766 osscaps |= PCM_CAP_DUPLEX; 767 768 if (osscaps != 0) { 769 osscaps |= PCM_CAP_TRIGGER | PCM_CAP_BATCH; 770 if (!(ncaps & AUDIO_CLIENT_CAP_OPAQUE)) { 771 osscaps |= PCM_CAP_FREERATE | PCM_CAP_MULTI; 772 } 773 } else { 774 /* This is the sndstat device! */ 775 osscaps = PCM_CAP_VIRTUAL; 776 } 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 /* MMAP: we add PCM_CAP_MMAP when we we support it */ 1310 si->caps |= PCM_CAP_TRIGGER | PCM_CAP_BATCH; 1311 si->enabled = 1; 1312 si->rate_source = si->dev; 1313 1314 /* we can convert and mix PCM formats */ 1315 if (!(cap & AUDIO_CLIENT_CAP_OPAQUE)) { 1316 si->min_channels = min(2, si->max_channels); 1317 si->min_rate = min(5000, si->max_rate); 1318 si->caps |= PCM_CAP_FREERATE | PCM_CAP_MULTI; 1319 } 1320 (void) snprintf(si->devnode, sizeof (si->devnode), 1321 "/dev/sound/%s:%ddsp", 1322 auclnt_get_dev_driver(d), auclnt_get_dev_instance(d)); 1323 } else { 1324 si->enabled = 0; /* stops apps from using us directly */ 1325 si->caps = PCM_CAP_VIRTUAL; 1326 (void) snprintf(si->devnode, sizeof (si->devnode), 1327 "/dev/sndstat"); 1328 } 1329 1330 si->pid = -1; 1331 (void) snprintf(si->handle, sizeof (si->handle), "%s", name); 1332 (void) snprintf(si->label, sizeof (si->label), "%s", name); 1333 si->latency = -1; 1334 si->card_number = n; 1335 si->mixer_dev = n - 1; 1336 1337 if (release) 1338 auclnt_release_dev(d); 1339 1340 return (0); 1341 } 1342 1343 static int 1344 sound_mixer_info(audio_client_t *c, mixer_info *mi) 1345 { 1346 audio_dev_t *d; 1347 const char *name; 1348 1349 d = auclnt_get_dev(c); 1350 1351 name = auclnt_get_dev_name(d); 1352 (void) snprintf(mi->id, sizeof (mi->id), "%s", name); 1353 (void) snprintf(mi->name, sizeof (mi->name), "%s", name); 1354 (void) snprintf(mi->handle, sizeof (mi->handle), "%s", name); 1355 mi->modify_counter = (int)auclnt_dev_get_serial(d); 1356 mi->card_number = auclnt_get_dev_index(d); 1357 mi->port_number = 0; 1358 return (0); 1359 } 1360 1361 static int 1362 sound_mixer_read_devmask(audio_client_t *c, int *devmask) 1363 { 1364 _NOTE(ARGUNUSED(c)); 1365 *devmask = SOUND_MASK_VOLUME | SOUND_MASK_PCM | SOUND_MASK_IGAIN; 1366 return (0); 1367 } 1368 1369 static int 1370 sound_mixer_read_recmask(audio_client_t *c, int *recmask) 1371 { 1372 _NOTE(ARGUNUSED(c)); 1373 *recmask = 0; 1374 return (0); 1375 } 1376 1377 static int 1378 sound_mixer_read_recsrc(audio_client_t *c, int *recsrc) 1379 { 1380 _NOTE(ARGUNUSED(c)); 1381 *recsrc = 0; 1382 return (0); 1383 } 1384 1385 static int 1386 sound_mixer_read_caps(audio_client_t *c, int *caps) 1387 { 1388 _NOTE(ARGUNUSED(c)); 1389 /* single recording source... sort of */ 1390 *caps = SOUND_CAP_EXCL_INPUT; 1391 return (0); 1392 } 1393 1394 static int 1395 sndctl_mixerinfo(audio_client_t *c, oss_mixerinfo *mi) 1396 { 1397 audio_dev_t *d; 1398 ossdev_t *odev; 1399 const char *name; 1400 int n; 1401 boolean_t release = B_FALSE; 1402 1403 if ((n = mi->dev) == -1) { 1404 release = B_FALSE; 1405 d = auclnt_get_dev(c); 1406 n = auclnt_get_dev_index(d); 1407 } else { 1408 release = B_TRUE; 1409 n++; 1410 d = auclnt_hold_dev_by_index(n); 1411 } 1412 1413 bzero(mi, sizeof (*mi)); 1414 mi->dev = n - 1; 1415 1416 if (d == NULL) { 1417 mi->card_number = n; 1418 mi->enabled = 0; 1419 mi->legacy_device = -1; 1420 (void) snprintf(mi->name, sizeof (mi->name), "<removed>"); 1421 (void) snprintf(mi->id, sizeof (mi->id), "<removed>"); 1422 return (0); 1423 } 1424 1425 if ((odev = auclnt_get_dev_minor_data(d, AUDIO_MINOR_DSP)) == NULL) { 1426 if (release) 1427 auclnt_release_dev(d); 1428 return (EINVAL); 1429 } 1430 1431 name = auclnt_get_dev_name(d); 1432 (void) snprintf(mi->name, sizeof (mi->name), "%s", name); 1433 (void) snprintf(mi->id, sizeof (mi->id), "%s", name); 1434 (void) snprintf(mi->handle, sizeof (mi->handle), "%s", name); 1435 mi->modify_counter = (int)auclnt_dev_get_serial(d); 1436 mi->card_number = auclnt_get_dev_index(d); 1437 mi->legacy_device = auclnt_get_dev_number(d); 1438 if (mi->legacy_device >= 0) { 1439 (void) snprintf(mi->devnode, sizeof (mi->devnode), 1440 "/dev/sound/%s:%dmixer", 1441 auclnt_get_dev_driver(d), auclnt_get_dev_instance(d)); 1442 mi->enabled = 1; 1443 } else { 1444 /* special nodes use generic sndstat node */ 1445 (void) snprintf(mi->devnode, sizeof (mi->devnode), 1446 "/dev/sndstat"); 1447 mi->enabled = 0; 1448 } 1449 mi->nrext = odev->d_nctrl; 1450 1451 if (release) 1452 auclnt_release_dev(d); 1453 1454 return (0); 1455 } 1456 1457 static int 1458 sndctl_dsp_getblksize(audio_client_t *c, int *fragsz) 1459 { 1460 int oflag = auclnt_get_oflag(c); 1461 1462 if (oflag & FWRITE) 1463 *fragsz = auclnt_get_fragsz(auclnt_output_stream(c)); 1464 else if (oflag & FREAD) 1465 *fragsz = auclnt_get_fragsz(auclnt_input_stream(c)); 1466 1467 return (0); 1468 } 1469 1470 static int 1471 sndctl_dsp_getospace(audio_client_t *c, audio_buf_info *bi) 1472 { 1473 audio_stream_t *sp; 1474 unsigned n; 1475 1476 if ((auclnt_get_oflag(c) & FWRITE) == 0) { 1477 return (EACCES); 1478 } 1479 1480 sp = auclnt_output_stream(c); 1481 n = auclnt_get_nframes(sp) - auclnt_get_count(sp); 1482 1483 bi->fragsize = auclnt_get_fragsz(sp); 1484 bi->fragstotal = auclnt_get_nfrags(sp); 1485 bi->bytes = (n * auclnt_get_framesz(sp)); 1486 bi->fragments = bi->bytes / bi->fragsize; 1487 1488 return (0); 1489 } 1490 1491 static int 1492 sndctl_dsp_getispace(audio_client_t *c, audio_buf_info *bi) 1493 { 1494 audio_stream_t *sp; 1495 unsigned n; 1496 1497 if ((auclnt_get_oflag(c) & FREAD) == 0) { 1498 return (EACCES); 1499 } 1500 1501 sp = auclnt_input_stream(c); 1502 n = auclnt_get_count(sp); 1503 1504 bi->fragsize = auclnt_get_fragsz(sp); 1505 bi->fragstotal = auclnt_get_nfrags(sp); 1506 bi->bytes = (n * auclnt_get_framesz(sp)); 1507 bi->fragments = bi->bytes / bi->fragsize; 1508 1509 return (0); 1510 } 1511 1512 static int 1513 sndctl_dsp_getodelay(audio_client_t *c, int *bytes) 1514 { 1515 unsigned framesz; 1516 unsigned slen, flen; 1517 1518 if (auclnt_get_oflag(c) & FWRITE) { 1519 audio_stream_t *sp = auclnt_output_stream(c); 1520 framesz = auclnt_get_framesz(sp); 1521 auclnt_get_output_qlen(c, &slen, &flen); 1522 *bytes = (slen + flen) * framesz; 1523 } else { 1524 *bytes = 0; 1525 } 1526 return (0); 1527 } 1528 1529 static int 1530 sndctl_dsp_current_iptr(audio_client_t *c, oss_count_t *count) 1531 { 1532 if (auclnt_get_oflag(c) & FREAD) { 1533 count->samples = auclnt_get_samples(auclnt_input_stream(c)); 1534 count->fifo_samples = 0; /* not quite accurate */ 1535 } else { 1536 count->samples = 0; 1537 count->fifo_samples = 0; 1538 } 1539 return (0); 1540 } 1541 1542 static int 1543 sndctl_dsp_current_optr(audio_client_t *c, oss_count_t *count) 1544 { 1545 unsigned samples, fifo; 1546 1547 if (auclnt_get_oflag(c) & FWRITE) { 1548 auclnt_get_output_qlen(c, &samples, &fifo); 1549 count->samples = samples; 1550 count->fifo_samples = fifo; 1551 } else { 1552 count->samples = 0; 1553 count->fifo_samples = 0; 1554 } 1555 return (0); 1556 } 1557 1558 static int 1559 sndctl_dsp_getoptr(audio_client_t *c, count_info *ci) 1560 { 1561 audio_stream_t *sp; 1562 unsigned framesz; 1563 unsigned fragsz; 1564 1565 bzero(ci, sizeof (*ci)); 1566 if ((auclnt_get_oflag(c) & FWRITE) == 0) { 1567 return (0); 1568 } 1569 sp = auclnt_output_stream(c); 1570 framesz = auclnt_get_framesz(sp); 1571 fragsz = auclnt_get_fragsz(sp); 1572 ci->blocks = auclnt_get_samples(sp) * framesz / fragsz; 1573 auclnt_set_samples(sp, 0); 1574 ci->bytes = auclnt_get_tail(sp) * framesz; 1575 ci->ptr = auclnt_get_tidx(sp) * framesz; 1576 return (0); 1577 } 1578 1579 static int 1580 sndctl_dsp_getiptr(audio_client_t *c, count_info *ci) 1581 { 1582 audio_stream_t *sp; 1583 unsigned framesz; 1584 unsigned fragsz; 1585 1586 bzero(ci, sizeof (*ci)); 1587 if ((auclnt_get_oflag(c) & FREAD) == 0) { 1588 return (0); 1589 } 1590 sp = auclnt_input_stream(c); 1591 framesz = auclnt_get_framesz(sp); 1592 fragsz = auclnt_get_fragsz(sp); 1593 ci->blocks = auclnt_get_samples(sp) * framesz / fragsz; 1594 auclnt_set_samples(sp, 0); 1595 ci->bytes = auclnt_get_head(sp) * framesz; 1596 ci->ptr = auclnt_get_hidx(sp) * framesz; 1597 return (0); 1598 } 1599 1600 static int 1601 sndctl_dsp_geterror(audio_client_t *c, audio_errinfo *bi) 1602 { 1603 audio_stream_t *sp; 1604 unsigned fragsz; 1605 /* 1606 * Note: The use of this structure is unsafe... different 1607 * meanings for error codes are used by different implementations, 1608 * according to the spec. (Even different versions of the same 1609 * implementation could have different values.) 1610 * 1611 * Rather than try to come up with a reliable solution here, we 1612 * don't use it. If you want to report errors, or see the result 1613 * of errors, use syslog. 1614 */ 1615 bzero(bi, sizeof (*bi)); 1616 1617 sp = auclnt_output_stream(c); 1618 fragsz = max(auclnt_get_fragsz(sp), 1); 1619 bi->play_underruns = (int)((auclnt_get_errors(sp) + (fragsz - 1)) / 1620 fragsz); 1621 auclnt_set_errors(sp, 0); 1622 1623 sp = auclnt_input_stream(c); 1624 fragsz = max(auclnt_get_fragsz(sp), 1); 1625 bi->rec_overruns = (int)((auclnt_get_errors(sp) + (fragsz - 1)) / 1626 fragsz); 1627 auclnt_set_errors(sp, 0); 1628 1629 return (0); 1630 } 1631 1632 static int 1633 sndctl_sun_send_number(audio_client_t *c, int *num, cred_t *cr) 1634 { 1635 audio_dev_t *dev; 1636 int rv; 1637 1638 if ((rv = drv_priv(cr)) != 0) { 1639 return (rv); 1640 } 1641 1642 dev = auclnt_get_dev(c); 1643 auclnt_set_dev_number(dev, *num); 1644 return (0); 1645 } 1646 1647 static int 1648 oss_getversion(int *versp) 1649 { 1650 *versp = OSS_VERSION; 1651 return (0); 1652 } 1653 1654 static int 1655 oss_ioctl(audio_client_t *c, int cmd, intptr_t arg, int mode, cred_t *credp, 1656 int *rvalp) 1657 { 1658 int sz; 1659 void *data; 1660 int rv = 0; 1661 1662 _NOTE(ARGUNUSED(credp)); 1663 1664 sz = OSSIOC_GETSZ(cmd); 1665 1666 if ((cmd & (OSSIOC_IN | OSSIOC_OUT)) && sz) { 1667 if ((data = kmem_zalloc(sz, KM_NOSLEEP)) == NULL) { 1668 return (ENOMEM); 1669 } 1670 } else { 1671 sz = 0; 1672 } 1673 1674 if (cmd & OSSIOC_IN) { 1675 if ((rv = ddi_copyin((void *)arg, data, sz, mode)) != 0) { 1676 goto done; 1677 } 1678 } 1679 1680 switch (cmd) { 1681 /* 1682 * DSP specific ioctls 1683 */ 1684 case SNDCTL_DSP_HALT: 1685 rv = sndctl_dsp_halt(c); 1686 break; 1687 1688 case SNDCTL_DSP_SYNC: 1689 rv = sndctl_dsp_sync(c); 1690 break; 1691 1692 case SNDCTL_DSP_SPEED: 1693 rv = sndctl_dsp_speed(c, (int *)data); 1694 break; 1695 case SNDCTL_DSP_SETFMT: 1696 rv = sndctl_dsp_setfmt(c, (int *)data); 1697 break; 1698 case SNDCTL_DSP_GETFMTS: 1699 rv = sndctl_dsp_getfmts(c, (int *)data); 1700 break; 1701 case SNDCTL_DSP_STEREO: 1702 rv = sndctl_dsp_stereo(c, (int *)data); 1703 break; 1704 case SNDCTL_DSP_CHANNELS: 1705 rv = sndctl_dsp_channels(c, (int *)data); 1706 break; 1707 case SNDCTL_DSP_POST: 1708 rv = sndctl_dsp_post(c); 1709 break; 1710 case SNDCTL_DSP_GETCAPS: 1711 rv = sndctl_dsp_getcaps(c, (int *)data); 1712 break; 1713 case SNDCTL_DSP_GETTRIGGER: 1714 rv = sndctl_dsp_gettrigger(c, (int *)data); 1715 break; 1716 case SNDCTL_DSP_SETTRIGGER: 1717 rv = sndctl_dsp_settrigger(c, (int *)data); 1718 break; 1719 case SNDCTL_DSP_GETPLAYVOL: 1720 case SOUND_MIXER_READ_VOLUME: /* legacy mixer on dsp */ 1721 case SOUND_MIXER_READ_PCM: /* legacy mixer on dsp */ 1722 case SOUND_MIXER_READ_OGAIN: /* legacy mixer on dsp */ 1723 rv = sndctl_dsp_getplayvol(c, (int *)data); 1724 break; 1725 case SOUND_MIXER_WRITE_VOLUME: /* legacy mixer on dsp */ 1726 case SOUND_MIXER_WRITE_PCM: /* legacy mixer on dsp */ 1727 case SOUND_MIXER_WRITE_OGAIN: /* legacy mixer on dsp */ 1728 rv = sound_mixer_write_ogain(c, (int *)data); 1729 break; 1730 case SNDCTL_DSP_SETPLAYVOL: 1731 rv = sndctl_dsp_setplayvol(c, (int *)data); 1732 break; 1733 case SNDCTL_DSP_READCTL: 1734 rv = sndctl_dsp_readctl(c, (oss_digital_control *)data); 1735 break; 1736 case SNDCTL_DSP_WRITECTL: 1737 rv = sndctl_dsp_writectl(c, (oss_digital_control *)data); 1738 break; 1739 case SNDCTL_DSP_COOKEDMODE: 1740 rv = sndctl_dsp_cookedmode(c, (int *)data); 1741 break; 1742 case SNDCTL_DSP_SILENCE: 1743 rv = sndctl_dsp_silence(c); 1744 break; 1745 case SNDCTL_DSP_SKIP: 1746 rv = sndctl_dsp_skip(c); 1747 break; 1748 case SNDCTL_DSP_HALT_INPUT: 1749 rv = sndctl_dsp_halt_input(c); 1750 break; 1751 case SNDCTL_DSP_HALT_OUTPUT: 1752 rv = sndctl_dsp_halt_output(c); 1753 break; 1754 case SNDCTL_DSP_GET_RECSRC_NAMES: 1755 rv = sndctl_dsp_get_recsrc_names(c, (oss_mixer_enuminfo *)data); 1756 break; 1757 case SNDCTL_DSP_SETFRAGMENT: 1758 rv = sndctl_dsp_setfragment(c, (int *)data); 1759 break; 1760 case SNDCTL_DSP_GET_RECSRC: 1761 rv = sndctl_dsp_get_recsrc(c, (int *)data); 1762 break; 1763 case SNDCTL_DSP_SET_RECSRC: 1764 rv = sndctl_dsp_set_recsrc(c, (int *)data); 1765 break; 1766 case SNDCTL_DSP_GET_PLAYTGT_NAMES: 1767 rv = sndctl_dsp_get_playtgt_names(c, 1768 (oss_mixer_enuminfo *)data); 1769 break; 1770 case SNDCTL_DSP_GET_PLAYTGT: 1771 rv = sndctl_dsp_get_playtgt(c, (int *)data); 1772 break; 1773 case SNDCTL_DSP_SET_PLAYTGT: 1774 rv = sndctl_dsp_set_playtgt(c, (int *)data); 1775 break; 1776 case SNDCTL_DSP_GETRECVOL: 1777 case SOUND_MIXER_READ_RECGAIN: /* legacy mixer on dsp */ 1778 case SOUND_MIXER_READ_RECLEV: /* legacy mixer on dsp */ 1779 case SOUND_MIXER_READ_IGAIN: /* legacy mixer on dsp */ 1780 rv = sndctl_dsp_getrecvol(c, (int *)data); 1781 break; 1782 case SOUND_MIXER_WRITE_RECGAIN: /* legacy mixer on dsp */ 1783 case SOUND_MIXER_WRITE_RECLEV: /* legacy mixer on dsp */ 1784 case SOUND_MIXER_WRITE_IGAIN: /* legacy mixer on dsp */ 1785 rv = sound_mixer_write_igain(c, (int *)data); 1786 break; 1787 case SNDCTL_DSP_SETRECVOL: 1788 rv = sndctl_dsp_setrecvol(c, (int *)data); 1789 break; 1790 case SNDCTL_DSP_SUBDIVIDE: /* Ignored */ 1791 case SNDCTL_DSP_SETDUPLEX: /* Ignored */ 1792 case SNDCTL_DSP_LOW_WATER: /* Ignored */ 1793 case SNDCTL_DSP_PROFILE: /* Ignored */ 1794 rv = 0; 1795 break; 1796 case SNDCTL_DSP_POLICY: 1797 rv = sndctl_dsp_policy(c, (int *)data); 1798 break; 1799 case SNDCTL_DSP_GETBLKSIZE: 1800 rv = sndctl_dsp_getblksize(c, (int *)data); 1801 break; 1802 case SNDCTL_DSP_GETOSPACE: 1803 rv = sndctl_dsp_getospace(c, (audio_buf_info *)data); 1804 break; 1805 case SNDCTL_DSP_GETISPACE: 1806 rv = sndctl_dsp_getispace(c, (audio_buf_info *)data); 1807 break; 1808 case SNDCTL_DSP_GETODELAY: 1809 rv = sndctl_dsp_getodelay(c, (int *)data); 1810 break; 1811 case SNDCTL_DSP_GETOPTR: 1812 rv = sndctl_dsp_getoptr(c, (count_info *)data); 1813 break; 1814 case SNDCTL_DSP_GETIPTR: 1815 rv = sndctl_dsp_getiptr(c, (count_info *)data); 1816 break; 1817 case SNDCTL_DSP_GETERROR: 1818 rv = sndctl_dsp_geterror(c, (audio_errinfo *)data); 1819 break; 1820 case SNDCTL_DSP_CURRENT_IPTR: 1821 rv = sndctl_dsp_current_iptr(c, (oss_count_t *)data); 1822 break; 1823 case SNDCTL_DSP_CURRENT_OPTR: 1824 rv = sndctl_dsp_current_optr(c, (oss_count_t *)data); 1825 break; 1826 1827 /* 1828 * Shared ioctls with /dev/mixer. 1829 */ 1830 case OSS_GETVERSION: 1831 rv = oss_getversion((int *)data); 1832 break; 1833 case SNDCTL_CARDINFO: 1834 rv = sndctl_cardinfo(c, (oss_card_info *)data); 1835 break; 1836 case SNDCTL_ENGINEINFO: 1837 case SNDCTL_AUDIOINFO: 1838 case SNDCTL_AUDIOINFO_EX: 1839 rv = sndctl_audioinfo(c, (oss_audioinfo *)data); 1840 break; 1841 case SNDCTL_SYSINFO: 1842 rv = sndctl_sysinfo((oss_sysinfo *)data); 1843 break; 1844 case SNDCTL_MIXERINFO: 1845 rv = sndctl_mixerinfo(c, (oss_mixerinfo *)data); 1846 break; 1847 case SOUND_MIXER_INFO: 1848 rv = sound_mixer_info(c, (mixer_info *)data); 1849 break; 1850 1851 /* 1852 * These are mixer ioctls that are virtualized for the DSP 1853 * device. They are accessible via either /dev/mixer or 1854 * /dev/dsp. 1855 */ 1856 case SOUND_MIXER_READ_RECSRC: 1857 case SOUND_MIXER_WRITE_RECSRC: 1858 rv = sound_mixer_read_recsrc(c, (int *)data); 1859 break; 1860 1861 case SOUND_MIXER_READ_DEVMASK: 1862 case SOUND_MIXER_READ_STEREODEVS: 1863 rv = sound_mixer_read_devmask(c, (int *)data); 1864 break; 1865 1866 case SOUND_MIXER_READ_RECMASK: 1867 rv = sound_mixer_read_recmask(c, (int *)data); 1868 break; 1869 1870 case SOUND_MIXER_READ_CAPS: 1871 rv = sound_mixer_read_caps(c, (int *)data); 1872 break; 1873 1874 /* 1875 * Ioctls we have chosen not to support for now. Some 1876 * of these are of legacy interest only. 1877 */ 1878 case SNDCTL_SETSONG: 1879 case SNDCTL_GETSONG: 1880 case SNDCTL_DSP_SYNCGROUP: 1881 case SNDCTL_DSP_SYNCSTART: 1882 case SNDCTL_DSP_GET_CHNORDER: 1883 case SNDCTL_DSP_SET_CHNORDER: 1884 case SNDCTL_DSP_GETIPEAKS: 1885 case SNDCTL_DSP_GETOPEAKS: 1886 case SNDCTL_DSP_GETCHANNELMASK: 1887 case SNDCTL_DSP_BIND_CHANNEL: 1888 case SNDCTL_DSP_SETSYNCRO: 1889 case SNDCTL_DSP_NONBLOCK: 1890 default: 1891 rv = EINVAL; 1892 break; 1893 } 1894 1895 if ((rv == 0) && (cmd & OSSIOC_OUT)) { 1896 rv = ddi_copyout(data, (void *)arg, sz, mode); 1897 } 1898 if (rv == 0) { 1899 *rvalp = 0; 1900 } 1901 1902 done: 1903 if (sz) { 1904 kmem_free(data, sz); 1905 } 1906 return (rv); 1907 } 1908 1909 static void 1910 oss_output(audio_client_t *c) 1911 { 1912 auclnt_pollwakeup(c, POLLOUT); 1913 } 1914 1915 static void 1916 oss_input(audio_client_t *c) 1917 { 1918 auclnt_pollwakeup(c, POLLIN | POLLRDNORM); 1919 } 1920 1921 static int 1922 ossmix_open(audio_client_t *c, int oflag) 1923 { 1924 int rv; 1925 ossclient_t *sc; 1926 ossdev_t *odev; 1927 1928 _NOTE(ARGUNUSED(oflag)); 1929 1930 if ((rv = auclnt_open(c, AUDIO_FORMAT_NONE, 0)) != 0) { 1931 return (rv); 1932 } 1933 1934 if ((sc = kmem_zalloc(sizeof (*sc), KM_NOSLEEP)) == NULL) { 1935 return (ENOMEM); 1936 } 1937 sc->o_ss_sz = 8192; 1938 if ((sc->o_ss_buf = kmem_zalloc(sc->o_ss_sz, KM_NOSLEEP)) == NULL) { 1939 kmem_free(sc, sizeof (*sc)); 1940 return (ENOMEM); 1941 } 1942 auclnt_set_private(c, sc); 1943 1944 odev = auclnt_get_minor_data(c, AUDIO_MINOR_DSP); 1945 1946 /* set a couple of common fields */ 1947 sc->o_client = c; 1948 sc->o_ossdev = odev; 1949 1950 return (rv); 1951 } 1952 1953 static void 1954 ossmix_close(audio_client_t *c) 1955 { 1956 ossclient_t *sc; 1957 1958 sc = auclnt_get_private(c); 1959 1960 kmem_free(sc->o_ss_buf, sc->o_ss_sz); 1961 kmem_free(sc, sizeof (*sc)); 1962 1963 auclnt_close(c); 1964 } 1965 1966 static int 1967 sndctl_mix_nrext(audio_client_t *c, int *ncp) 1968 { 1969 audio_dev_t *d; 1970 ossdev_t *odev; 1971 1972 d = auclnt_get_dev(c); 1973 1974 if ((*ncp != -1) && (*ncp != (auclnt_get_dev_index(d) - 1))) { 1975 return (ENXIO); 1976 } 1977 1978 if ((odev = auclnt_get_dev_minor_data(d, AUDIO_MINOR_DSP)) == NULL) { 1979 return (EINVAL); 1980 } 1981 1982 *ncp = odev->d_nctrl; 1983 1984 return (0); 1985 } 1986 1987 static int 1988 sndctl_mix_extinfo(audio_client_t *c, oss_mixext *pext) 1989 { 1990 audio_dev_t *d; 1991 ossdev_t *odev; 1992 int rv = 0; 1993 int dev; 1994 1995 d = auclnt_get_dev(c); 1996 1997 if (((dev = pext->dev) != -1) && (dev != (auclnt_get_dev_index(d) - 1))) 1998 return (ENXIO); 1999 2000 if (((odev = auclnt_get_dev_minor_data(d, AUDIO_MINOR_DSP)) == NULL) || 2001 (pext->ctrl >= odev->d_nctrl)) { 2002 return (EINVAL); 2003 } 2004 2005 bcopy(&odev->d_exts[pext->ctrl], pext, sizeof (*pext)); 2006 pext->enumbit = 0; 2007 pext->dev = dev; 2008 2009 return (rv); 2010 } 2011 2012 static int 2013 sndctl_mix_enuminfo(audio_client_t *c, oss_mixer_enuminfo *ei) 2014 { 2015 audio_dev_t *d; 2016 audio_ctrl_desc_t desc; 2017 audio_ctrl_t *ctrl; 2018 ossdev_t *odev; 2019 uint64_t mask; 2020 int bit; 2021 ushort_t nxt; 2022 2023 d = auclnt_get_dev(c); 2024 2025 if ((ei->dev != -1) && (ei->dev != (auclnt_get_dev_index(d) - 1))) 2026 return (ENXIO); 2027 2028 if (((odev = auclnt_get_dev_minor_data(d, AUDIO_MINOR_DSP)) == NULL) || 2029 (ei->ctrl >= odev->d_nctrl) || 2030 (odev->d_exts[ei->ctrl].type != MIXT_ENUM) || 2031 ((ctrl = odev->d_ctrls[ei->ctrl]) == NULL) || 2032 (auclnt_control_describe(ctrl, &desc) != 0)) { 2033 return (EINVAL); 2034 } 2035 2036 mask = desc.acd_maxvalue; 2037 bit = 0; 2038 nxt = 0; 2039 ei->nvalues = 0; 2040 bzero(ei->strings, sizeof (ei->strings)); 2041 bzero(ei->strindex, sizeof (ei->strindex)); 2042 2043 while (mask) { 2044 const char *name = desc.acd_enum[bit]; 2045 nxt = oss_set_enum(ei, nxt, name ? name : ""); 2046 mask >>= 1; 2047 bit++; 2048 } 2049 2050 return (0); 2051 } 2052 2053 static int 2054 sndctl_mix_read(audio_client_t *c, oss_mixer_value *vr) 2055 { 2056 int rv; 2057 uint64_t v; 2058 audio_dev_t *d; 2059 audio_ctrl_t *ctrl; 2060 ossdev_t *odev; 2061 2062 d = auclnt_get_dev(c); 2063 2064 if ((vr->dev != -1) && (vr->dev != (auclnt_get_dev_index(d) - 1))) 2065 return (ENXIO); 2066 2067 if (((odev = auclnt_get_dev_minor_data(d, AUDIO_MINOR_DSP)) == NULL) || 2068 (vr->ctrl >= odev->d_nctrl) || 2069 ((ctrl = odev->d_ctrls[vr->ctrl]) == NULL)) { 2070 return (EINVAL); 2071 } 2072 if ((rv = auclnt_control_read(ctrl, &v)) == 0) { 2073 switch (odev->d_exts[vr->ctrl].type) { 2074 case MIXT_ENUM: 2075 /* translate this from an enum style bit mask */ 2076 vr->value = ddi_ffs((unsigned long)v) - 1; 2077 break; 2078 case MIXT_STEREOSLIDER: 2079 vr->value = (int)ddi_swap16(v & 0xffff); 2080 break; 2081 case MIXT_MONOSLIDER: 2082 vr->value = (int)(v | (v << 8)); 2083 break; 2084 case MIXT_ONOFF: 2085 /* this could be simple, or could be part of a multi */ 2086 if (odev->d_exts[vr->ctrl].enumbit >= 0) { 2087 uint64_t mask; 2088 mask = 1; 2089 mask <<= (odev->d_exts[vr->ctrl].enumbit); 2090 vr->value = (v & mask) ? 1 : 0; 2091 } else { 2092 vr->value = v ? 1 : 0; 2093 } 2094 break; 2095 2096 default: 2097 vr->value = (int)v; 2098 break; 2099 } 2100 } 2101 2102 return (rv); 2103 } 2104 2105 static int 2106 sndctl_mix_write(audio_client_t *c, oss_mixer_value *vr) 2107 { 2108 int rv; 2109 uint64_t v; 2110 audio_dev_t *d; 2111 audio_ctrl_t *ctrl; 2112 ossdev_t *odev; 2113 2114 d = auclnt_get_dev(c); 2115 2116 if ((vr->dev != -1) && (vr->dev != (auclnt_get_dev_index(d) - 1))) 2117 return (ENXIO); 2118 2119 if (((odev = auclnt_get_dev_minor_data(d, AUDIO_MINOR_DSP)) == NULL) || 2120 (vr->ctrl >= odev->d_nctrl) || 2121 ((ctrl = odev->d_ctrls[vr->ctrl]) == NULL)) { 2122 return (EINVAL); 2123 } 2124 2125 switch (odev->d_exts[vr->ctrl].type) { 2126 case MIXT_ONOFF: 2127 /* this could be standalone, or it could be part of a multi */ 2128 if (odev->d_exts[vr->ctrl].enumbit >= 0) { 2129 uint64_t mask; 2130 if ((rv = auclnt_control_read(ctrl, &v)) != 0) { 2131 return (EINVAL); 2132 } 2133 mask = 1; 2134 mask <<= (odev->d_exts[vr->ctrl].enumbit); 2135 if (vr->value) { 2136 v |= mask; 2137 } else { 2138 v &= ~mask; 2139 } 2140 } else { 2141 v = vr->value; 2142 } 2143 break; 2144 case MIXT_ENUM: 2145 /* translate this to an enum style bit mask */ 2146 v = 1U << vr->value; 2147 break; 2148 case MIXT_MONOSLIDER: 2149 /* mask off high order bits */ 2150 v = vr->value & 0xff; 2151 break; 2152 case MIXT_STEREOSLIDER: 2153 /* OSS uses reverse byte ordering */ 2154 v = vr->value; 2155 v = ddi_swap16(vr->value & 0xffff); 2156 break; 2157 default: 2158 v = vr->value; 2159 } 2160 rv = auclnt_control_write(ctrl, v); 2161 2162 return (rv); 2163 } 2164 2165 static int 2166 sndctl_mix_nrmix(audio_client_t *c, int *nmixp) 2167 { 2168 _NOTE(ARGUNUSED(c)); 2169 *nmixp = oss_cnt_devs() - 1; 2170 return (0); 2171 } 2172 2173 static int 2174 ossmix_ioctl(audio_client_t *c, int cmd, intptr_t arg, int mode, cred_t *credp, 2175 int *rvalp) 2176 { 2177 int sz; 2178 void *data; 2179 int rv = 0; 2180 2181 sz = OSSIOC_GETSZ(cmd); 2182 2183 if ((cmd & (OSSIOC_IN | OSSIOC_OUT)) && sz) { 2184 if ((data = kmem_zalloc(sz, KM_NOSLEEP)) == NULL) { 2185 return (ENOMEM); 2186 } 2187 } else { 2188 sz = 0; 2189 } 2190 2191 if (cmd & OSSIOC_IN) { 2192 if ((rv = ddi_copyin((void *)arg, data, sz, mode)) != 0) { 2193 goto done; 2194 } 2195 } 2196 2197 switch (cmd) { 2198 /* 2199 * Mixer specific ioctls 2200 */ 2201 case SNDCTL_MIX_NREXT: 2202 rv = sndctl_mix_nrext(c, (int *)data); 2203 break; 2204 case SNDCTL_MIX_EXTINFO: 2205 rv = sndctl_mix_extinfo(c, (oss_mixext *)data); 2206 break; 2207 case SNDCTL_MIX_ENUMINFO: 2208 rv = sndctl_mix_enuminfo(c, (oss_mixer_enuminfo *)data); 2209 break; 2210 case SNDCTL_MIX_READ: 2211 rv = sndctl_mix_read(c, (oss_mixer_value *)data); 2212 break; 2213 case SNDCTL_MIX_WRITE: 2214 rv = sndctl_mix_write(c, (oss_mixer_value *)data); 2215 break; 2216 case SNDCTL_MIX_NRMIX: 2217 rv = sndctl_mix_nrmix(c, (int *)data); 2218 break; 2219 2220 /* 2221 * Legacy ioctls. These are treated as soft values only, 2222 * and do not affect global hardware state. For use by 2223 * legacy DSP applications. 2224 */ 2225 case SOUND_MIXER_READ_VOLUME: 2226 case SOUND_MIXER_READ_PCM: 2227 case SOUND_MIXER_READ_OGAIN: 2228 rv = sndctl_dsp_getplayvol(c, (int *)data); 2229 break; 2230 2231 case SOUND_MIXER_WRITE_VOLUME: 2232 case SOUND_MIXER_WRITE_PCM: 2233 case SOUND_MIXER_WRITE_OGAIN: 2234 rv = sound_mixer_write_ogain(c, (int *)data); 2235 break; 2236 2237 case SOUND_MIXER_READ_RECGAIN: 2238 case SOUND_MIXER_READ_RECLEV: 2239 case SOUND_MIXER_READ_IGAIN: 2240 rv = sndctl_dsp_getrecvol(c, (int *)data); 2241 break; 2242 2243 case SOUND_MIXER_WRITE_RECGAIN: 2244 case SOUND_MIXER_WRITE_RECLEV: 2245 case SOUND_MIXER_WRITE_IGAIN: 2246 rv = sound_mixer_write_igain(c, (int *)data); 2247 break; 2248 2249 case SOUND_MIXER_READ_RECSRC: 2250 case SOUND_MIXER_WRITE_RECSRC: 2251 rv = sound_mixer_read_recsrc(c, (int *)data); 2252 break; 2253 2254 case SOUND_MIXER_READ_DEVMASK: 2255 case SOUND_MIXER_READ_STEREODEVS: 2256 rv = sound_mixer_read_devmask(c, (int *)data); 2257 break; 2258 2259 case SOUND_MIXER_READ_RECMASK: 2260 rv = sound_mixer_read_recmask(c, (int *)data); 2261 break; 2262 2263 case SOUND_MIXER_READ_CAPS: 2264 rv = sound_mixer_read_caps(c, (int *)data); 2265 break; 2266 2267 /* 2268 * Common ioctls shared with DSP 2269 */ 2270 case OSS_GETVERSION: 2271 rv = oss_getversion((int *)data); 2272 break; 2273 2274 case SNDCTL_CARDINFO: 2275 rv = sndctl_cardinfo(c, (oss_card_info *)data); 2276 break; 2277 2278 case SNDCTL_ENGINEINFO: 2279 case SNDCTL_AUDIOINFO: 2280 case SNDCTL_AUDIOINFO_EX: 2281 rv = sndctl_audioinfo(c, (oss_audioinfo *)data); 2282 break; 2283 2284 case SNDCTL_SYSINFO: 2285 rv = sndctl_sysinfo((oss_sysinfo *)data); 2286 break; 2287 2288 case SNDCTL_MIXERINFO: 2289 rv = sndctl_mixerinfo(c, (oss_mixerinfo *)data); 2290 break; 2291 2292 case SOUND_MIXER_INFO: 2293 rv = sound_mixer_info(c, (mixer_info *)data); 2294 break; 2295 2296 case SNDCTL_MIX_DESCRIPTION: /* NOT SUPPORTED: tooltip */ 2297 rv = EIO; /* OSS returns EIO for this one */ 2298 break; 2299 2300 /* 2301 * Special implementation-private ioctls. 2302 */ 2303 case SNDCTL_SUN_SEND_NUMBER: 2304 rv = sndctl_sun_send_number(c, (int *)data, credp); 2305 break; 2306 2307 /* 2308 * Legacy ioctls we don't support. 2309 */ 2310 case SOUND_MIXER_WRITE_MONGAIN: 2311 case SOUND_MIXER_READ_MONGAIN: 2312 case SOUND_MIXER_READ_BASS: 2313 case SOUND_MIXER_READ_TREBLE: 2314 case SOUND_MIXER_READ_SPEAKER: 2315 case SOUND_MIXER_READ_LINE: 2316 case SOUND_MIXER_READ_MIC: 2317 case SOUND_MIXER_READ_CD: 2318 case SOUND_MIXER_READ_IMIX: 2319 case SOUND_MIXER_READ_ALTPCM: 2320 case SOUND_MIXER_READ_SYNTH: 2321 case SOUND_MIXER_READ_LINE1: 2322 case SOUND_MIXER_READ_LINE2: 2323 case SOUND_MIXER_READ_LINE3: 2324 case SOUND_MIXER_WRITE_BASS: 2325 case SOUND_MIXER_WRITE_TREBLE: 2326 case SOUND_MIXER_WRITE_SPEAKER: 2327 case SOUND_MIXER_WRITE_LINE: 2328 case SOUND_MIXER_WRITE_MIC: 2329 case SOUND_MIXER_WRITE_CD: 2330 case SOUND_MIXER_WRITE_IMIX: 2331 case SOUND_MIXER_WRITE_ALTPCM: 2332 case SOUND_MIXER_WRITE_SYNTH: 2333 case SOUND_MIXER_WRITE_LINE1: 2334 case SOUND_MIXER_WRITE_LINE2: 2335 case SOUND_MIXER_WRITE_LINE3: 2336 /* 2337 * Additional ioctls we *could* support, but don't. 2338 */ 2339 case SNDCTL_SETSONG: 2340 case SNDCTL_SETLABEL: 2341 case SNDCTL_GETSONG: 2342 case SNDCTL_GETLABEL: 2343 case SNDCTL_MIDIINFO: 2344 case SNDCTL_SETNAME: 2345 default: 2346 rv = EINVAL; 2347 break; 2348 } 2349 2350 if ((rv == 0) && (cmd & OSSIOC_OUT)) { 2351 rv = ddi_copyout(data, (void *)arg, sz, mode); 2352 } 2353 if (rv == 0) { 2354 *rvalp = 0; 2355 } 2356 2357 done: 2358 if (sz) { 2359 kmem_free(data, sz); 2360 } 2361 return (rv); 2362 } 2363 2364 static void * 2365 oss_dev_init(audio_dev_t *dev) 2366 { 2367 ossdev_t *odev; 2368 2369 odev = kmem_zalloc(sizeof (*odev), KM_SLEEP); 2370 odev->d_dev = dev; 2371 2372 mutex_init(&odev->d_mx, NULL, MUTEX_DRIVER, NULL); 2373 cv_init(&odev->d_cv, NULL, CV_DRIVER, NULL); 2374 oss_alloc_controls(odev); 2375 2376 return (odev); 2377 } 2378 2379 static void 2380 oss_dev_fini(void *arg) 2381 { 2382 ossdev_t *odev = arg; 2383 2384 if (odev != NULL) { 2385 oss_free_controls(odev); 2386 mutex_destroy(&odev->d_mx); 2387 cv_destroy(&odev->d_cv); 2388 kmem_free(odev, sizeof (*odev)); 2389 } 2390 } 2391 2392 static void 2393 sndstat_printf(ossclient_t *oc, const char *fmt, ...) 2394 { 2395 va_list va; 2396 2397 va_start(va, fmt); 2398 (void) vsnprintf(oc->o_ss_buf + oc->o_ss_len, 2399 oc->o_ss_sz - oc->o_ss_len, fmt, va); 2400 va_end(va); 2401 oc->o_ss_len = strlen(oc->o_ss_buf); 2402 } 2403 2404 static int 2405 sndstat_dev_walker(audio_dev_t *d, void *arg) 2406 { 2407 ossclient_t *oc = arg; 2408 const char *capstr; 2409 unsigned cap; 2410 2411 cap = auclnt_get_dev_capab(d); 2412 2413 if (cap & AUDIO_CLIENT_CAP_DUPLEX) { 2414 capstr = "DUPLEX"; 2415 } else if ((cap & AUDIO_CLIENT_CAP_PLAY) && 2416 (cap & AUDIO_CLIENT_CAP_RECORD)) { 2417 capstr = "INPUT,OUTPUT"; 2418 } else if (cap & AUDIO_CLIENT_CAP_PLAY) { 2419 capstr = "OUTPUT"; 2420 } else if (cap & AUDIO_CLIENT_CAP_RECORD) { 2421 capstr = "INPUT"; 2422 } else { 2423 capstr = NULL; 2424 } 2425 2426 if (capstr == NULL) 2427 return (AUDIO_WALK_CONTINUE); 2428 2429 sndstat_printf(oc, "%d: %s %s, %s (%s)\n", 2430 auclnt_get_dev_number(d), auclnt_get_dev_name(d), 2431 auclnt_get_dev_description(d), auclnt_get_dev_version(d), capstr); 2432 2433 return (AUDIO_WALK_CONTINUE); 2434 } 2435 2436 static int 2437 sndstat_mixer_walker(audio_dev_t *d, void *arg) 2438 { 2439 ossclient_t *oc = arg; 2440 unsigned cap; 2441 void *iter; 2442 const char *info; 2443 2444 cap = auclnt_get_dev_capab(d); 2445 2446 if ((cap & (AUDIO_CLIENT_CAP_PLAY|AUDIO_CLIENT_CAP_RECORD)) == 0) 2447 return (AUDIO_WALK_CONTINUE); 2448 2449 sndstat_printf(oc, "%d: %s %s, %s\n", 2450 auclnt_get_dev_number(d), auclnt_get_dev_name(d), 2451 auclnt_get_dev_description(d), auclnt_get_dev_version(d)); 2452 iter = NULL; 2453 while ((info = auclnt_get_dev_hw_info(d, &iter)) != NULL) { 2454 sndstat_printf(oc, "\t%s\n", info); 2455 } 2456 return (AUDIO_WALK_CONTINUE); 2457 } 2458 2459 static int 2460 ossmix_write(audio_client_t *c, struct uio *uio, cred_t *cr) 2461 { 2462 /* write on sndstat is a no-op */ 2463 _NOTE(ARGUNUSED(c)); 2464 _NOTE(ARGUNUSED(uio)); 2465 _NOTE(ARGUNUSED(cr)); 2466 2467 return (0); 2468 } 2469 2470 static int 2471 ossmix_read(audio_client_t *c, struct uio *uio, cred_t *cr) 2472 { 2473 ossclient_t *oc; 2474 unsigned n; 2475 int rv; 2476 2477 _NOTE(ARGUNUSED(cr)); 2478 2479 if (uio->uio_resid == 0) { 2480 return (0); 2481 } 2482 2483 oc = auclnt_get_private(c); 2484 2485 mutex_enter(&oc->o_ss_lock); 2486 2487 if (oc->o_ss_off == 0) { 2488 2489 sndstat_printf(oc, "SunOS Audio Framework\n"); 2490 2491 sndstat_printf(oc, "\nAudio Devices:\n"); 2492 auclnt_walk_devs_by_number(sndstat_dev_walker, oc); 2493 2494 sndstat_printf(oc, "\nMixers:\n"); 2495 auclnt_walk_devs_by_number(sndstat_mixer_walker, oc); 2496 } 2497 2498 /* 2499 * For simplicity's sake, we implement a non-seekable device. We could 2500 * support seekability, but offsets would be rather meaningless between 2501 * changes. 2502 */ 2503 n = min(uio->uio_resid, (oc->o_ss_len - oc->o_ss_off)); 2504 2505 rv = uiomove(oc->o_ss_buf + oc->o_ss_off, n, UIO_READ, uio); 2506 if (rv != 0) { 2507 n = 0; 2508 } 2509 oc->o_ss_off += n; 2510 2511 if (n == 0) { 2512 /* 2513 * end-of-file reached... clear the sndstat buffer so that 2514 * subsequent reads will get the latest data. 2515 */ 2516 oc->o_ss_off = oc->o_ss_len = 0; 2517 } 2518 mutex_exit(&oc->o_ss_lock); 2519 return (rv); 2520 } 2521 2522 int 2523 oss_read(audio_client_t *c, struct uio *uio, cred_t *cr) 2524 { 2525 _NOTE(ARGUNUSED(cr)); 2526 2527 auclnt_clear_paused(auclnt_input_stream(c)); 2528 2529 return (auclnt_read(c, uio)); 2530 } 2531 2532 int 2533 oss_write(audio_client_t *c, struct uio *uio, cred_t *cr) 2534 { 2535 _NOTE(ARGUNUSED(cr)); 2536 2537 auclnt_clear_paused(auclnt_output_stream(c)); 2538 2539 return (auclnt_write(c, uio)); 2540 } 2541 2542 int 2543 oss_chpoll(audio_client_t *c, short events, int anyyet, short *reventsp, 2544 struct pollhead **phpp) 2545 { 2546 return (auclnt_chpoll(c, events, anyyet, reventsp, phpp)); 2547 } 2548 2549 static struct audio_client_ops oss_ops = { 2550 "sound,dsp", 2551 oss_dev_init, 2552 oss_dev_fini, 2553 oss_open, 2554 oss_close, 2555 oss_read, 2556 oss_write, 2557 oss_ioctl, 2558 oss_chpoll, 2559 NULL, /* mmap */ 2560 oss_input, 2561 oss_output, 2562 NULL, /* drain */ 2563 }; 2564 2565 static struct audio_client_ops ossmix_ops = { 2566 "sound,mixer", 2567 NULL, 2568 NULL, 2569 ossmix_open, 2570 ossmix_close, 2571 ossmix_read, 2572 ossmix_write, 2573 ossmix_ioctl, 2574 NULL, /* chpoll */ 2575 NULL, /* mmap */ 2576 NULL, /* input */ 2577 NULL, /* output */ 2578 NULL, /* drain */ 2579 NULL, /* wput */ 2580 NULL, /* wsrv */ 2581 }; 2582 2583 /* nearly the same as ossxmix; different minor name helps devfsadm */ 2584 static struct audio_client_ops sndstat_ops = { 2585 "sound,sndstat", 2586 NULL, /* dev_init */ 2587 NULL, /* dev_fini */ 2588 ossmix_open, 2589 ossmix_close, 2590 ossmix_read, 2591 ossmix_write, 2592 ossmix_ioctl, 2593 NULL, /* chpoll */ 2594 NULL, /* mmap */ 2595 NULL, /* input */ 2596 NULL, /* output */ 2597 NULL, /* drain */ 2598 NULL, /* wput */ 2599 NULL, /* wsrv */ 2600 }; 2601 2602 void 2603 auimpl_oss_init(void) 2604 { 2605 auclnt_register_ops(AUDIO_MINOR_DSP, &oss_ops); 2606 auclnt_register_ops(AUDIO_MINOR_MIXER, &ossmix_ops); 2607 auclnt_register_ops(AUDIO_MINOR_SNDSTAT, &sndstat_ops); 2608 } 2609