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 } 512 513 if (oflag & FREAD) { 514 if (((rv = auclnt_set_format(isp, OSS_FMT)) != 0) || 515 ((rv = auclnt_set_rate(isp, OSS_RATE)) != 0) || 516 ((rv = auclnt_set_channels(isp, OSS_CHANNELS)) != 0)) { 517 goto failed; 518 } 519 } 520 521 return (0); 522 523 failed: 524 auclnt_close(c); 525 return (rv); 526 } 527 528 static void 529 oss_close(audio_client_t *c) 530 { 531 ossclient_t *sc; 532 533 sc = auclnt_get_private(c); 534 535 if (ddi_can_receive_sig() || (ddi_get_pid() == 0)) { 536 (void) auclnt_drain(c); 537 } 538 539 kmem_free(sc, sizeof (*sc)); 540 541 auclnt_close(c); 542 } 543 544 /* 545 * This is used to generate an array of names for an enumeration 546 */ 547 static ushort_t 548 oss_set_enum(oss_mixer_enuminfo *ei, ushort_t nxt, const char *name) 549 { 550 uint32_t n; 551 552 /* Get current entry to fill in */ 553 n = ei->nvalues; 554 (void) snprintf(&ei->strings[nxt], ((sizeof (ei->strings) - nxt) - 1), 555 "%s", name); 556 ei->strindex[n] = nxt; 557 558 /* Adjust everything for next entry */ 559 nxt += strnlen(name, ((sizeof (ei->strings) - nxt) - 1)); 560 ei->strings[nxt++] = '\0'; 561 562 ei->nvalues++; 563 return (nxt); 564 } 565 566 /* 567 * The following two functions are used to count the number of devices 568 * in under the boomer framework. 569 * 570 * We actually report the highest "index", and then if an audio device 571 * is not found, we report a bogus removed device for it in the actual 572 * ioctls. This goofiness is required to make the OSS API happy. 573 */ 574 int 575 oss_dev_walker(audio_dev_t *d, void *arg) 576 { 577 int *pcnt = arg; 578 int cnt; 579 int index; 580 581 cnt = *pcnt; 582 index = auclnt_get_dev_index(d); 583 if ((index + 1) > cnt) { 584 cnt = index + 1; 585 *pcnt = cnt; 586 } 587 588 return (AUDIO_WALK_CONTINUE); 589 } 590 591 static int 592 oss_cnt_devs(void) 593 { 594 int cnt = 0; 595 596 auclnt_walk_devs(oss_dev_walker, &cnt); 597 return (cnt); 598 } 599 600 static int 601 sndctl_dsp_speed(audio_client_t *c, int *ratep) 602 { 603 int rv; 604 int rate; 605 int oflag; 606 607 rate = *ratep; 608 609 oflag = auclnt_get_oflag(c); 610 if (oflag & FREAD) { 611 if ((rv = auclnt_set_rate(auclnt_input_stream(c), rate)) != 0) 612 return (rv); 613 } 614 615 if (oflag & FWRITE) { 616 if ((rv = auclnt_set_rate(auclnt_output_stream(c), rate)) != 0) 617 return (rv); 618 } 619 620 return (0); 621 } 622 623 static int 624 sndctl_dsp_setfmt(audio_client_t *c, int *fmtp) 625 { 626 int rv; 627 int fmt; 628 int i; 629 int oflag; 630 631 oflag = auclnt_get_oflag(c); 632 633 if (*fmtp != AFMT_QUERY) { 634 /* convert from OSS */ 635 for (i = 0; oss_formats[i].fmt != AUDIO_FORMAT_NONE; i++) { 636 if (oss_formats[i].oss == *fmtp) { 637 fmt = oss_formats[i].fmt; 638 break; 639 } 640 } 641 if (fmt == AUDIO_FORMAT_NONE) { 642 /* if format not known, return ENOTSUP */ 643 return (ENOTSUP); 644 } 645 646 if (oflag & FWRITE) { 647 rv = auclnt_set_format(auclnt_output_stream(c), fmt); 648 if (rv != 0) 649 return (rv); 650 } 651 652 if (oflag & FREAD) { 653 rv = auclnt_set_format(auclnt_input_stream(c), fmt); 654 if (rv != 0) 655 return (rv); 656 } 657 } 658 659 if (oflag & FWRITE) { 660 fmt = auclnt_get_format(auclnt_output_stream(c)); 661 } else if (oflag & FREAD) { 662 fmt = auclnt_get_format(auclnt_input_stream(c)); 663 } 664 665 /* convert back to OSS */ 666 *(int *)fmtp = AFMT_QUERY; 667 for (i = 0; oss_formats[i].fmt != AUDIO_FORMAT_NONE; i++) { 668 if (oss_formats[i].fmt == fmt) { 669 *(int *)fmtp = oss_formats[i].oss; 670 } 671 } 672 673 return (0); 674 } 675 676 static int 677 sndctl_dsp_getfmts(audio_client_t *c, int *fmtsp) 678 { 679 _NOTE(ARGUNUSED(c)); 680 681 /* 682 * For now, we support all the standard ones. Later we might 683 * add in conditional support for AC3. 684 */ 685 *fmtsp = (AFMT_MU_LAW | AFMT_A_LAW | 686 AFMT_U8 | AFMT_S8 | 687 AFMT_S16_LE |AFMT_S16_BE | 688 AFMT_S24_LE | AFMT_S24_BE | 689 AFMT_S32_LE | AFMT_S32_BE | 690 AFMT_S24_PACKED); 691 692 return (0); 693 } 694 695 static int 696 sndctl_dsp_channels(audio_client_t *c, int *chanp) 697 { 698 int rv; 699 int nchan; 700 int oflag; 701 702 oflag = auclnt_get_oflag(c); 703 704 nchan = *chanp; 705 if (nchan != 0) { 706 if (oflag & FWRITE) { 707 rv = auclnt_set_channels(auclnt_output_stream(c), 708 nchan); 709 if (rv != 0) 710 return (rv); 711 } 712 713 if (oflag & FREAD) { 714 rv = auclnt_set_channels(auclnt_input_stream(c), nchan); 715 if (rv != 0) 716 return (rv); 717 } 718 } 719 720 if (oflag & FWRITE) { 721 nchan = auclnt_get_channels(auclnt_output_stream(c)); 722 } else if (oflag & FREAD) { 723 nchan = auclnt_get_channels(auclnt_input_stream(c)); 724 } 725 *chanp = nchan; 726 return (0); 727 } 728 729 static int 730 sndctl_dsp_stereo(audio_client_t *c, int *onoff) 731 { 732 int nchan; 733 734 switch (*onoff) { 735 case 0: 736 nchan = 1; 737 break; 738 case 1: 739 nchan = 2; 740 break; 741 default: 742 return (EINVAL); 743 } 744 745 return (sndctl_dsp_channels(c, &nchan)); 746 } 747 748 static int 749 sndctl_dsp_post(audio_client_t *c) 750 { 751 if (auclnt_get_oflag(c) & FWRITE) { 752 audio_stream_t *sp = auclnt_output_stream(c); 753 auclnt_flush(sp); 754 auclnt_clear_paused(sp); 755 } 756 return (0); 757 } 758 759 static int 760 sndctl_dsp_getcaps(audio_client_t *c, int *capsp) 761 { 762 int ncaps; 763 int osscaps = 0; 764 765 ncaps = auclnt_get_dev_capab(auclnt_get_dev(c)); 766 767 if (ncaps & AUDIO_CLIENT_CAP_PLAY) 768 osscaps |= PCM_CAP_OUTPUT; 769 if (ncaps & AUDIO_CLIENT_CAP_RECORD) 770 osscaps |= PCM_CAP_INPUT; 771 if (ncaps & AUDIO_CLIENT_CAP_DUPLEX) 772 osscaps |= PCM_CAP_DUPLEX; 773 774 *capsp = osscaps; 775 return (0); 776 } 777 778 static int 779 sndctl_dsp_gettrigger(audio_client_t *c, int *trigp) 780 { 781 int triggers = 0; 782 int oflag; 783 784 oflag = auclnt_get_oflag(c); 785 786 if (oflag & FWRITE) { 787 if (!auclnt_is_paused(auclnt_output_stream(c))) { 788 triggers |= PCM_ENABLE_OUTPUT; 789 } 790 } 791 792 if (oflag & FREAD) { 793 if (!auclnt_is_paused(auclnt_input_stream(c))) { 794 triggers |= PCM_ENABLE_INPUT; 795 } 796 } 797 *trigp = triggers; 798 799 return (0); 800 } 801 802 static int 803 sndctl_dsp_settrigger(audio_client_t *c, int *trigp) 804 { 805 int triggers; 806 int oflag; 807 audio_stream_t *sp; 808 809 oflag = auclnt_get_oflag(c); 810 triggers = *trigp; 811 812 if ((oflag & FWRITE) && (triggers & PCM_ENABLE_OUTPUT)) { 813 sp = auclnt_output_stream(c); 814 auclnt_clear_paused(sp); 815 auclnt_start(sp); 816 } 817 818 if ((oflag & FREAD) && (triggers & PCM_ENABLE_INPUT)) { 819 sp = auclnt_input_stream(c); 820 auclnt_clear_paused(sp); 821 auclnt_start(sp); 822 } 823 824 return (0); 825 } 826 827 struct oss_legacy_volume { 828 pid_t pid; 829 uint8_t ogain; 830 uint8_t igain; 831 }; 832 833 static int 834 oss_legacy_volume_walker(audio_client_t *c, void *arg) 835 { 836 struct oss_legacy_volume *olv = arg; 837 838 if (auclnt_get_pid(c) == olv->pid) { 839 if (olv->ogain <= 100) { 840 auclnt_set_gain(auclnt_output_stream(c), olv->ogain); 841 } 842 if (olv->igain <= 100) { 843 auclnt_set_gain(auclnt_input_stream(c), olv->igain); 844 } 845 } 846 return (AUDIO_WALK_CONTINUE); 847 } 848 849 static void 850 oss_set_legacy_volume(audio_client_t *c, uint8_t ogain, uint8_t igain) 851 { 852 struct oss_legacy_volume olv; 853 854 olv.pid = auclnt_get_pid(c); 855 olv.ogain = ogain; 856 olv.igain = igain; 857 auclnt_dev_walk_clients(auclnt_get_dev(c), 858 oss_legacy_volume_walker, &olv); 859 } 860 861 static int 862 sndctl_dsp_getplayvol(audio_client_t *c, int *volp) 863 { 864 int vol; 865 866 /* convert monophonic soft value to OSS stereo value */ 867 vol = auclnt_get_gain(auclnt_output_stream(c)); 868 *volp = vol | (vol << 8); 869 return (0); 870 } 871 872 static int 873 sndctl_dsp_setplayvol(audio_client_t *c, int *volp) 874 { 875 uint8_t vol; 876 877 vol = *volp & 0xff; 878 if (vol > 100) { 879 return (EINVAL); 880 } 881 882 auclnt_set_gain(auclnt_output_stream(c), vol); 883 *volp = (vol | (vol << 8)); 884 885 return (0); 886 } 887 888 static int 889 sndctl_dsp_getrecvol(audio_client_t *c, int *volp) 890 { 891 int vol; 892 893 vol = auclnt_get_gain(auclnt_input_stream(c)); 894 *volp = (vol | (vol << 8)); 895 return (0); 896 } 897 898 static int 899 sndctl_dsp_setrecvol(audio_client_t *c, int *volp) 900 { 901 uint8_t vol; 902 903 vol = *volp & 0xff; 904 if (vol > 100) { 905 return (EINVAL); 906 } 907 908 auclnt_set_gain(auclnt_input_stream(c), vol); 909 *volp = (vol | (vol << 8)); 910 911 return (0); 912 } 913 914 static int 915 sound_mixer_write_ogain(audio_client_t *c, int *volp) 916 { 917 uint8_t vol; 918 919 vol = *volp & 0xff; 920 if (vol > 100) { 921 return (EINVAL); 922 } 923 oss_set_legacy_volume(c, vol, 255); 924 *volp = (vol | (vol << 8)); 925 return (0); 926 } 927 928 static int 929 sound_mixer_write_igain(audio_client_t *c, int *volp) 930 { 931 uint8_t vol; 932 933 vol = *volp & 0xff; 934 if (vol > 100) { 935 return (EINVAL); 936 } 937 oss_set_legacy_volume(c, 255, vol); 938 *volp = (vol | (vol << 8)); 939 return (0); 940 } 941 942 static int 943 sndctl_dsp_readctl(audio_client_t *c, oss_digital_control *ctl) 944 { 945 /* SPDIF: need to add support with spdif */ 946 _NOTE(ARGUNUSED(c)); 947 _NOTE(ARGUNUSED(ctl)); 948 return (ENOTSUP); 949 } 950 951 static int 952 sndctl_dsp_writectl(audio_client_t *c, oss_digital_control *ctl) 953 { 954 /* SPDIF: need to add support with spdif */ 955 _NOTE(ARGUNUSED(c)); 956 _NOTE(ARGUNUSED(ctl)); 957 return (ENOTSUP); 958 } 959 960 static int 961 sndctl_dsp_cookedmode(audio_client_t *c, int *rvp) 962 { 963 _NOTE(ARGUNUSED(c)); 964 965 /* We are *always* in cooked mode -- at least until we have AC3. */ 966 if (*rvp == 0) { 967 return (ENOTSUP); 968 } else { 969 return (0); 970 } 971 } 972 973 static int 974 sndctl_dsp_silence(audio_client_t *c) 975 { 976 if (auclnt_get_oflag(c) & FWRITE) { 977 audio_stream_t *sp = auclnt_output_stream(c); 978 auclnt_set_paused(sp); 979 auclnt_flush(sp); 980 } 981 return (0); 982 } 983 984 static int 985 sndctl_dsp_skip(audio_client_t *c) 986 { 987 if (auclnt_get_oflag(c) & FWRITE) { 988 audio_stream_t *sp = auclnt_output_stream(c); 989 auclnt_set_paused(sp); 990 auclnt_flush(sp); 991 auclnt_clear_paused(sp); 992 } 993 return (0); 994 } 995 996 static int 997 sndctl_dsp_halt_input(audio_client_t *c) 998 { 999 if (auclnt_get_oflag(c) & FREAD) { 1000 audio_stream_t *sp = auclnt_input_stream(c); 1001 auclnt_set_paused(sp); 1002 auclnt_flush(sp); 1003 } 1004 return (0); 1005 } 1006 1007 static int 1008 sndctl_dsp_halt_output(audio_client_t *c) 1009 { 1010 if (auclnt_get_oflag(c) & FWRITE) { 1011 audio_stream_t *sp = auclnt_output_stream(c); 1012 auclnt_set_paused(sp); 1013 auclnt_flush(sp); 1014 } 1015 return (0); 1016 } 1017 1018 static int 1019 sndctl_dsp_halt(audio_client_t *c) 1020 { 1021 (void) sndctl_dsp_halt_input(c); 1022 (void) sndctl_dsp_halt_output(c); 1023 return (0); 1024 } 1025 1026 static int 1027 sndctl_dsp_sync(audio_client_t *c) 1028 { 1029 return (auclnt_drain(c)); 1030 } 1031 1032 static int 1033 sndctl_dsp_setfragment(audio_client_t *c, int *fragp) 1034 { 1035 _NOTE(ARGUNUSED(c)); 1036 _NOTE(ARGUNUSED(fragp)); 1037 /* 1038 * We don't really implement this "properly" at this time. 1039 * The problems with this ioctl are various: the API insists 1040 * that fragment sizes be a power of two -- and we can't cope 1041 * with accurately reporting fragment sizes in the face of 1042 * mixing and format conversion. 1043 * 1044 * Well behaved applications should really not use this API. 1045 * 1046 * According to the OSS API documentation, the values provided 1047 * are nothing more than a "hint" and not to be relied upon 1048 * anyway. And we aren't obligated to report the actual 1049 * values back! 1050 */ 1051 return (0); 1052 } 1053 1054 /* 1055 * A word about recsrc, and playtgt ioctls: We don't allow ordinary DSP 1056 * applications to change port configurations, because these could have a 1057 * bad effect for other applications. Instead, these settings have to 1058 * be changed using the master mixer panel. In order to make applications 1059 * happy, we just present a single "default" source/target. 1060 */ 1061 static int 1062 sndctl_dsp_get_recsrc_names(audio_client_t *c, oss_mixer_enuminfo *ei) 1063 { 1064 _NOTE(ARGUNUSED(c)); 1065 1066 ei->nvalues = 1; 1067 (void) snprintf(ei->strings, sizeof (ei->strings), "default"); 1068 ei->strindex[0] = 0; 1069 1070 return (0); 1071 } 1072 1073 static int 1074 sndctl_dsp_get_recsrc(audio_client_t *c, int *srcp) 1075 { 1076 _NOTE(ARGUNUSED(c)); 1077 *srcp = 0; 1078 return (0); 1079 } 1080 1081 static int 1082 sndctl_dsp_set_recsrc(audio_client_t *c, int *srcp) 1083 { 1084 _NOTE(ARGUNUSED(c)); 1085 *srcp = 0; 1086 return (0); 1087 } 1088 1089 static int 1090 sndctl_dsp_get_playtgt_names(audio_client_t *c, oss_mixer_enuminfo *ei) 1091 { 1092 _NOTE(ARGUNUSED(c)); 1093 1094 ei->nvalues = 1; 1095 (void) snprintf(ei->strings, sizeof (ei->strings), "default"); 1096 ei->strindex[0] = 0; 1097 1098 return (0); 1099 } 1100 1101 static int 1102 sndctl_dsp_get_playtgt(audio_client_t *c, int *tgtp) 1103 { 1104 _NOTE(ARGUNUSED(c)); 1105 *tgtp = 0; 1106 return (0); 1107 } 1108 1109 static int 1110 sndctl_dsp_set_playtgt(audio_client_t *c, int *tgtp) 1111 { 1112 _NOTE(ARGUNUSED(c)); 1113 *tgtp = 0; 1114 return (0); 1115 } 1116 1117 static int 1118 sndctl_sysinfo(oss_sysinfo *si) 1119 { 1120 bzero(si, sizeof (*si)); 1121 (void) snprintf(si->product, sizeof (si->product), "SunOS Audio"); 1122 (void) snprintf(si->version, sizeof (si->version), "4.0"); 1123 si->versionnum = OSS_VERSION; 1124 si->numcards = oss_cnt_devs(); 1125 si->nummixers = si->numcards - 1; 1126 si->numaudios = si->numcards - 1; 1127 si->numaudioengines = si->numaudios; 1128 (void) snprintf(si->license, sizeof (si->license), "CDDL"); 1129 return (0); 1130 } 1131 1132 static int 1133 sndctl_cardinfo(audio_client_t *c, oss_card_info *ci) 1134 { 1135 audio_dev_t *d; 1136 void *iter; 1137 const char *info; 1138 int n; 1139 boolean_t release; 1140 1141 if ((n = ci->card) == -1) { 1142 release = B_FALSE; 1143 d = auclnt_get_dev(c); 1144 n = auclnt_get_dev_index(d); 1145 } else { 1146 release = B_TRUE; 1147 d = auclnt_hold_dev_by_index(n); 1148 } 1149 1150 bzero(ci, sizeof (*ci)); 1151 ci->card = n; 1152 1153 if (d == NULL) { 1154 /* 1155 * If device removed (e.g. for DR), then 1156 * report a bogus removed entry. 1157 */ 1158 (void) snprintf(ci->shortname, sizeof (ci->shortname), 1159 "<removed>"); 1160 (void) snprintf(ci->longname, sizeof (ci->longname), 1161 "<removed>"); 1162 return (0); 1163 } 1164 1165 (void) snprintf(ci->shortname, sizeof (ci->shortname), 1166 "%s", auclnt_get_dev_name(d)); 1167 (void) snprintf(ci->longname, sizeof (ci->longname), 1168 "%s (%s)", auclnt_get_dev_description(d), 1169 auclnt_get_dev_version(d)); 1170 1171 iter = NULL; 1172 while ((info = auclnt_get_dev_hw_info(d, &iter)) != NULL) { 1173 (void) strlcat(ci->hw_info, info, sizeof (ci->hw_info)); 1174 (void) strlcat(ci->hw_info, "\n", sizeof (ci->hw_info)); 1175 } 1176 1177 /* 1178 * We don't report interrupt counts, ack counts (which are 1179 * just "read" interrupts, not spurious), or any other flags. 1180 * Nothing should be using any of this data anyway ... these 1181 * values were intended for 4Front's debugging purposes. In 1182 * Solaris, drivers should use interrupt kstats to report 1183 * interrupt related statistics. 1184 */ 1185 if (release) 1186 auclnt_release_dev(d); 1187 return (0); 1188 } 1189 1190 static int 1191 audioinfo_walker(audio_engine_t *e, void *a) 1192 { 1193 oss_audioinfo *si = a; 1194 int fmt, nchan, rate, cap; 1195 1196 fmt = auclnt_engine_get_format(e); 1197 nchan = auclnt_engine_get_channels(e); 1198 rate = auclnt_engine_get_rate(e); 1199 cap = auclnt_engine_get_capab(e); 1200 1201 for (int i = 0; oss_formats[i].fmt != AUDIO_FORMAT_NONE; i++) { 1202 if (fmt == oss_formats[i].fmt) { 1203 if (cap & AUDIO_CLIENT_CAP_PLAY) { 1204 si->oformats |= oss_formats[i].oss; 1205 } 1206 if (cap & AUDIO_CLIENT_CAP_RECORD) { 1207 si->iformats |= oss_formats[i].oss; 1208 } 1209 break; 1210 } 1211 } 1212 si->max_channels = max(nchan, si->max_channels); 1213 si->max_rate = max(rate, si->max_rate); 1214 1215 return (AUDIO_WALK_CONTINUE); 1216 } 1217 1218 static int 1219 sndctl_audioinfo(audio_client_t *c, oss_audioinfo *si) 1220 { 1221 audio_dev_t *d; 1222 const char *name; 1223 int n; 1224 boolean_t release; 1225 unsigned cap; 1226 1227 if ((n = si->dev) == -1) { 1228 release = B_FALSE; 1229 d = auclnt_get_dev(c); 1230 n = auclnt_get_dev_index(d); 1231 } else { 1232 release = B_TRUE; 1233 n++; /* skip pseudo device */ 1234 d = auclnt_hold_dev_by_index(n); 1235 } 1236 1237 bzero(si, sizeof (*si)); 1238 si->dev = n - 1; 1239 1240 if (d == NULL) { 1241 /* if device not present, forge a false entry */ 1242 si->card_number = n; 1243 si->mixer_dev = n - 1; 1244 si->legacy_device = -1; 1245 si->enabled = 0; 1246 (void) snprintf(si->name, sizeof (si->name), "<removed>"); 1247 return (0); 1248 } 1249 1250 name = auclnt_get_dev_name(d); 1251 (void) snprintf(si->name, sizeof (si->name), "%s", name); 1252 1253 si->legacy_device = auclnt_get_dev_number(d); 1254 si->caps = 0; 1255 1256 auclnt_dev_walk_engines(d, audioinfo_walker, si); 1257 1258 cap = auclnt_get_dev_capab(d); 1259 1260 if (cap & AUDIO_CLIENT_CAP_DUPLEX) { 1261 si->caps |= PCM_CAP_DUPLEX; 1262 } 1263 if (cap & AUDIO_CLIENT_CAP_PLAY) { 1264 si->caps |= PCM_CAP_OUTPUT; 1265 } 1266 if (cap & AUDIO_CLIENT_CAP_RECORD) { 1267 si->caps |= PCM_CAP_INPUT; 1268 } 1269 1270 if (si->caps != 0) { 1271 /* AC3: PCM_CAP_MULTI would be wrong for an AC3 only device */ 1272 si->caps |= PCM_CAP_BATCH | PCM_CAP_TRIGGER | PCM_CAP_MULTI; 1273 /* MMAP: we add PCM_CAP_MMAP when we we support it */ 1274 si->enabled = 1; 1275 si->rate_source = si->dev; 1276 1277 /* we can convert PCM formats */ 1278 if ((si->iformats | si->oformats) & 1279 AUDIO_FORMAT_PCM) { 1280 si->min_channels = min(2, si->max_channels); 1281 si->min_rate = min(5000, si->max_rate); 1282 si->caps |= PCM_CAP_FREERATE; 1283 } 1284 (void) snprintf(si->devnode, sizeof (si->devnode), 1285 "/dev/sound/%s:%ddsp", 1286 auclnt_get_dev_driver(d), auclnt_get_dev_instance(d)); 1287 } else { 1288 si->enabled = 0; /* stops apps from using us directly */ 1289 si->caps = PCM_CAP_VIRTUAL; 1290 (void) snprintf(si->devnode, sizeof (si->devnode), 1291 "/dev/sndstat"); 1292 } 1293 1294 si->pid = -1; 1295 (void) snprintf(si->handle, sizeof (si->handle), "%s", name); 1296 (void) snprintf(si->label, sizeof (si->label), "%s", name); 1297 si->latency = -1; 1298 si->card_number = n; 1299 si->mixer_dev = n - 1; 1300 1301 if (release) 1302 auclnt_release_dev(d); 1303 1304 return (0); 1305 } 1306 1307 static int 1308 sound_mixer_info(audio_client_t *c, mixer_info *mi) 1309 { 1310 audio_dev_t *d; 1311 ossdev_t *odev; 1312 ossclient_t *sc; 1313 const char *name; 1314 1315 sc = auclnt_get_private(c); 1316 odev = sc->o_ossdev; 1317 1318 d = auclnt_get_dev(c); 1319 1320 name = auclnt_get_dev_name(d); 1321 (void) snprintf(mi->id, sizeof (mi->id), "%s", name); 1322 (void) snprintf(mi->name, sizeof (mi->name), "%s", name); 1323 (void) snprintf(mi->handle, sizeof (mi->handle), "%s", name); 1324 mi->modify_counter = odev->d_modify_cnt; 1325 mi->card_number = auclnt_get_dev_index(d); 1326 mi->port_number = 0; 1327 return (0); 1328 } 1329 1330 static int 1331 sound_mixer_read_devmask(audio_client_t *c, int *devmask) 1332 { 1333 _NOTE(ARGUNUSED(c)); 1334 *devmask = SOUND_MASK_VOLUME | SOUND_MASK_PCM | SOUND_MASK_IGAIN; 1335 return (0); 1336 } 1337 1338 static int 1339 sound_mixer_read_recmask(audio_client_t *c, int *recmask) 1340 { 1341 _NOTE(ARGUNUSED(c)); 1342 *recmask = 0; 1343 return (0); 1344 } 1345 1346 static int 1347 sound_mixer_read_recsrc(audio_client_t *c, int *recsrc) 1348 { 1349 _NOTE(ARGUNUSED(c)); 1350 *recsrc = 0; 1351 return (0); 1352 } 1353 1354 static int 1355 sound_mixer_read_caps(audio_client_t *c, int *caps) 1356 { 1357 _NOTE(ARGUNUSED(c)); 1358 /* single recording source... sort of */ 1359 *caps = SOUND_CAP_EXCL_INPUT; 1360 return (0); 1361 } 1362 1363 static int 1364 sndctl_mixerinfo(audio_client_t *c, oss_mixerinfo *mi) 1365 { 1366 audio_dev_t *d; 1367 ossdev_t *odev; 1368 const char *name; 1369 int n; 1370 boolean_t release = B_FALSE; 1371 1372 if ((n = mi->dev) == -1) { 1373 release = B_FALSE; 1374 d = auclnt_get_dev(c); 1375 n = auclnt_get_dev_index(d); 1376 } else { 1377 release = B_TRUE; 1378 n++; 1379 d = auclnt_hold_dev_by_index(n); 1380 } 1381 1382 bzero(mi, sizeof (*mi)); 1383 mi->dev = n - 1; 1384 1385 if (d == NULL) { 1386 mi->card_number = n; 1387 mi->enabled = 0; 1388 mi->legacy_device = -1; 1389 (void) snprintf(mi->name, sizeof (mi->name), "<removed>"); 1390 (void) snprintf(mi->id, sizeof (mi->id), "<removed>"); 1391 return (0); 1392 } 1393 1394 if ((odev = auclnt_get_dev_minor_data(d, AUDIO_MINOR_DSP)) == NULL) { 1395 if (release) 1396 auclnt_release_dev(d); 1397 return (EINVAL); 1398 } 1399 1400 name = auclnt_get_dev_name(d); 1401 (void) snprintf(mi->name, sizeof (mi->name), "%s", name); 1402 (void) snprintf(mi->id, sizeof (mi->id), "%s", name); 1403 (void) snprintf(mi->handle, sizeof (mi->handle), "%s", name); 1404 mi->modify_counter = odev->d_modify_cnt; 1405 mi->card_number = auclnt_get_dev_index(d); 1406 mi->legacy_device = auclnt_get_dev_number(d); 1407 if (mi->legacy_device >= 0) { 1408 (void) snprintf(mi->devnode, sizeof (mi->devnode), 1409 "/dev/sound/%s:%dmixer", 1410 auclnt_get_dev_driver(d), auclnt_get_dev_instance(d)); 1411 mi->enabled = 1; 1412 } else { 1413 /* special nodes use generic sndstat node */ 1414 (void) snprintf(mi->devnode, sizeof (mi->devnode), 1415 "/dev/sndstat"); 1416 mi->enabled = 0; 1417 } 1418 mi->nrext = odev->d_nctrl; 1419 1420 if (release) 1421 auclnt_release_dev(d); 1422 1423 return (0); 1424 } 1425 1426 static int 1427 sndctl_dsp_getblksize(audio_client_t *c, int *fragsz) 1428 { 1429 int oflag = auclnt_get_oflag(c); 1430 1431 if (oflag & FWRITE) 1432 *fragsz = auclnt_get_fragsz(auclnt_output_stream(c)); 1433 else if (oflag & FREAD) 1434 *fragsz = auclnt_get_fragsz(auclnt_input_stream(c)); 1435 1436 return (0); 1437 } 1438 1439 static int 1440 sndctl_dsp_getospace(audio_client_t *c, audio_buf_info *bi) 1441 { 1442 audio_stream_t *sp; 1443 unsigned n; 1444 1445 if ((auclnt_get_oflag(c) & FWRITE) == 0) { 1446 return (EACCES); 1447 } 1448 1449 sp = auclnt_output_stream(c); 1450 n = auclnt_get_nframes(sp) - auclnt_get_count(sp); 1451 1452 bi->fragsize = auclnt_get_fragsz(sp); 1453 bi->fragstotal = auclnt_get_nfrags(sp); 1454 bi->bytes = (n * auclnt_get_framesz(sp)); 1455 bi->fragments = bi->bytes / bi->fragsize; 1456 1457 return (0); 1458 } 1459 1460 static int 1461 sndctl_dsp_getispace(audio_client_t *c, audio_buf_info *bi) 1462 { 1463 audio_stream_t *sp; 1464 unsigned n; 1465 1466 if ((auclnt_get_oflag(c) & FREAD) == 0) { 1467 return (EACCES); 1468 } 1469 1470 sp = auclnt_input_stream(c); 1471 n = auclnt_get_count(sp); 1472 1473 bi->fragsize = auclnt_get_fragsz(sp); 1474 bi->fragstotal = auclnt_get_nfrags(sp); 1475 bi->bytes = (n * auclnt_get_framesz(sp)); 1476 bi->fragments = bi->bytes / bi->fragsize; 1477 1478 return (0); 1479 } 1480 1481 static int 1482 sndctl_dsp_getodelay(audio_client_t *c, int *bytes) 1483 { 1484 unsigned framesz; 1485 unsigned slen, flen; 1486 1487 if (auclnt_get_oflag(c) & FWRITE) { 1488 audio_stream_t *sp = auclnt_output_stream(c); 1489 framesz = auclnt_get_framesz(sp); 1490 auclnt_get_output_qlen(c, &slen, &flen); 1491 *bytes = (slen + flen) * framesz; 1492 } else { 1493 *bytes = 0; 1494 } 1495 return (0); 1496 } 1497 1498 static int 1499 sndctl_dsp_current_iptr(audio_client_t *c, oss_count_t *count) 1500 { 1501 if (auclnt_get_oflag(c) & FREAD) { 1502 count->samples = auclnt_get_samples(auclnt_input_stream(c)); 1503 count->fifo_samples = 0; /* not quite accurate */ 1504 } else { 1505 count->samples = 0; 1506 count->fifo_samples = 0; 1507 } 1508 return (0); 1509 } 1510 1511 static int 1512 sndctl_dsp_current_optr(audio_client_t *c, oss_count_t *count) 1513 { 1514 unsigned samples, fifo; 1515 1516 if (auclnt_get_oflag(c) & FWRITE) { 1517 auclnt_get_output_qlen(c, &samples, &fifo); 1518 count->samples = samples; 1519 count->fifo_samples = fifo; 1520 } else { 1521 count->samples = 0; 1522 count->fifo_samples = 0; 1523 } 1524 return (0); 1525 } 1526 1527 static int 1528 sndctl_dsp_getoptr(audio_client_t *c, count_info *ci) 1529 { 1530 audio_stream_t *sp; 1531 unsigned framesz; 1532 unsigned fragsz; 1533 1534 bzero(ci, sizeof (*ci)); 1535 if ((auclnt_get_oflag(c) & FWRITE) == 0) { 1536 return (0); 1537 } 1538 sp = auclnt_output_stream(c); 1539 framesz = auclnt_get_framesz(sp); 1540 fragsz = auclnt_get_fragsz(sp); 1541 ci->blocks = auclnt_get_samples(sp) * framesz / fragsz; 1542 auclnt_set_samples(sp, 0); 1543 ci->bytes = auclnt_get_tail(sp) * framesz; 1544 ci->ptr = auclnt_get_tidx(sp) * framesz; 1545 return (0); 1546 } 1547 1548 static int 1549 sndctl_dsp_getiptr(audio_client_t *c, count_info *ci) 1550 { 1551 audio_stream_t *sp; 1552 unsigned framesz; 1553 unsigned fragsz; 1554 1555 bzero(ci, sizeof (*ci)); 1556 if ((auclnt_get_oflag(c) & FREAD) == 0) { 1557 return (0); 1558 } 1559 sp = auclnt_input_stream(c); 1560 framesz = auclnt_get_framesz(sp); 1561 fragsz = auclnt_get_fragsz(sp); 1562 ci->blocks = auclnt_get_samples(sp) * framesz / fragsz; 1563 auclnt_set_samples(sp, 0); 1564 ci->bytes = auclnt_get_head(sp) * framesz; 1565 ci->ptr = auclnt_get_hidx(sp) * framesz; 1566 return (0); 1567 } 1568 1569 static int 1570 sndctl_dsp_geterror(audio_client_t *c, audio_errinfo *bi) 1571 { 1572 audio_stream_t *sp; 1573 unsigned fragsz; 1574 /* 1575 * Note: The use of this structure is unsafe... different 1576 * meanings for error codes are used by different implementations, 1577 * according to the spec. (Even different versions of the same 1578 * implementation could have different values.) 1579 * 1580 * Rather than try to come up with a reliable solution here, we 1581 * don't use it. If you want to report errors, or see the result 1582 * of errors, use syslog. 1583 */ 1584 bzero(bi, sizeof (*bi)); 1585 1586 sp = auclnt_output_stream(c); 1587 fragsz = max(auclnt_get_fragsz(sp), 1); 1588 bi->play_underruns = (int)((auclnt_get_errors(sp) + (fragsz - 1)) / 1589 fragsz); 1590 auclnt_set_errors(sp, 0); 1591 1592 sp = auclnt_input_stream(c); 1593 fragsz = max(auclnt_get_fragsz(sp), 1); 1594 bi->rec_overruns = (int)((auclnt_get_errors(sp) + (fragsz - 1)) / 1595 fragsz); 1596 auclnt_set_errors(sp, 0); 1597 1598 return (0); 1599 } 1600 1601 static int 1602 sndctl_sun_send_number(audio_client_t *c, int *num, cred_t *cr) 1603 { 1604 audio_dev_t *dev; 1605 int rv; 1606 1607 if ((rv = drv_priv(cr)) != 0) { 1608 return (rv); 1609 } 1610 1611 dev = auclnt_get_dev(c); 1612 auclnt_set_dev_number(dev, *num); 1613 return (0); 1614 } 1615 1616 static int 1617 oss_getversion(int *versp) 1618 { 1619 *versp = OSS_VERSION; 1620 return (0); 1621 } 1622 1623 static int 1624 oss_ioctl(audio_client_t *c, int cmd, intptr_t arg, int mode, cred_t *credp, 1625 int *rvalp) 1626 { 1627 int sz; 1628 void *data; 1629 int rv = 0; 1630 1631 _NOTE(ARGUNUSED(credp)); 1632 1633 sz = OSSIOC_GETSZ(cmd); 1634 1635 if ((cmd & (OSSIOC_IN | OSSIOC_OUT)) && sz) { 1636 if ((data = kmem_zalloc(sz, KM_NOSLEEP)) == NULL) { 1637 return (ENOMEM); 1638 } 1639 } else { 1640 sz = 0; 1641 } 1642 1643 if (cmd & OSSIOC_IN) { 1644 if ((rv = ddi_copyin((void *)arg, data, sz, mode)) != 0) { 1645 goto done; 1646 } 1647 } 1648 1649 switch (cmd) { 1650 /* 1651 * DSP specific ioctls 1652 */ 1653 case SNDCTL_DSP_HALT: 1654 rv = sndctl_dsp_halt(c); 1655 break; 1656 1657 case SNDCTL_DSP_SYNC: 1658 rv = sndctl_dsp_sync(c); 1659 break; 1660 1661 case SNDCTL_DSP_SPEED: 1662 rv = sndctl_dsp_speed(c, (int *)data); 1663 break; 1664 case SNDCTL_DSP_SETFMT: 1665 rv = sndctl_dsp_setfmt(c, (int *)data); 1666 break; 1667 case SNDCTL_DSP_GETFMTS: 1668 rv = sndctl_dsp_getfmts(c, (int *)data); 1669 break; 1670 case SNDCTL_DSP_STEREO: 1671 rv = sndctl_dsp_stereo(c, (int *)data); 1672 break; 1673 case SNDCTL_DSP_CHANNELS: 1674 rv = sndctl_dsp_channels(c, (int *)data); 1675 break; 1676 case SNDCTL_DSP_POST: 1677 rv = sndctl_dsp_post(c); 1678 break; 1679 case SNDCTL_DSP_GETCAPS: 1680 rv = sndctl_dsp_getcaps(c, (int *)data); 1681 break; 1682 case SNDCTL_DSP_GETTRIGGER: 1683 rv = sndctl_dsp_gettrigger(c, (int *)data); 1684 break; 1685 case SNDCTL_DSP_SETTRIGGER: 1686 rv = sndctl_dsp_settrigger(c, (int *)data); 1687 break; 1688 case SNDCTL_DSP_GETPLAYVOL: 1689 case SOUND_MIXER_READ_VOLUME: /* legacy mixer on dsp */ 1690 case SOUND_MIXER_READ_PCM: /* legacy mixer on dsp */ 1691 case SOUND_MIXER_READ_OGAIN: /* legacy mixer on dsp */ 1692 rv = sndctl_dsp_getplayvol(c, (int *)data); 1693 break; 1694 case SOUND_MIXER_WRITE_VOLUME: /* legacy mixer on dsp */ 1695 case SOUND_MIXER_WRITE_PCM: /* legacy mixer on dsp */ 1696 case SOUND_MIXER_WRITE_OGAIN: /* legacy mixer on dsp */ 1697 rv = sound_mixer_write_ogain(c, (int *)data); 1698 break; 1699 case SNDCTL_DSP_SETPLAYVOL: 1700 rv = sndctl_dsp_setplayvol(c, (int *)data); 1701 break; 1702 case SNDCTL_DSP_READCTL: 1703 rv = sndctl_dsp_readctl(c, (oss_digital_control *)data); 1704 break; 1705 case SNDCTL_DSP_WRITECTL: 1706 rv = sndctl_dsp_writectl(c, (oss_digital_control *)data); 1707 break; 1708 case SNDCTL_DSP_COOKEDMODE: 1709 rv = sndctl_dsp_cookedmode(c, (int *)data); 1710 break; 1711 case SNDCTL_DSP_SILENCE: 1712 rv = sndctl_dsp_silence(c); 1713 break; 1714 case SNDCTL_DSP_SKIP: 1715 rv = sndctl_dsp_skip(c); 1716 break; 1717 case SNDCTL_DSP_HALT_INPUT: 1718 rv = sndctl_dsp_halt_input(c); 1719 break; 1720 case SNDCTL_DSP_HALT_OUTPUT: 1721 rv = sndctl_dsp_halt_output(c); 1722 break; 1723 case SNDCTL_DSP_GET_RECSRC_NAMES: 1724 rv = sndctl_dsp_get_recsrc_names(c, (oss_mixer_enuminfo *)data); 1725 break; 1726 case SNDCTL_DSP_SUBDIVIDE: 1727 case SNDCTL_DSP_SETFRAGMENT: 1728 rv = sndctl_dsp_setfragment(c, (int *)data); 1729 break; 1730 case SNDCTL_DSP_GET_RECSRC: 1731 rv = sndctl_dsp_get_recsrc(c, (int *)data); 1732 break; 1733 case SNDCTL_DSP_SET_RECSRC: 1734 rv = sndctl_dsp_set_recsrc(c, (int *)data); 1735 break; 1736 case SNDCTL_DSP_GET_PLAYTGT_NAMES: 1737 rv = sndctl_dsp_get_playtgt_names(c, 1738 (oss_mixer_enuminfo *)data); 1739 break; 1740 case SNDCTL_DSP_GET_PLAYTGT: 1741 rv = sndctl_dsp_get_playtgt(c, (int *)data); 1742 break; 1743 case SNDCTL_DSP_SET_PLAYTGT: 1744 rv = sndctl_dsp_set_playtgt(c, (int *)data); 1745 break; 1746 case SNDCTL_DSP_GETRECVOL: 1747 case SOUND_MIXER_READ_RECGAIN: /* legacy mixer on dsp */ 1748 case SOUND_MIXER_READ_RECLEV: /* legacy mixer on dsp */ 1749 case SOUND_MIXER_READ_IGAIN: /* legacy mixer on dsp */ 1750 rv = sndctl_dsp_getrecvol(c, (int *)data); 1751 break; 1752 case SOUND_MIXER_WRITE_RECGAIN: /* legacy mixer on dsp */ 1753 case SOUND_MIXER_WRITE_RECLEV: /* legacy mixer on dsp */ 1754 case SOUND_MIXER_WRITE_IGAIN: /* legacy mixer on dsp */ 1755 rv = sound_mixer_write_igain(c, (int *)data); 1756 break; 1757 case SNDCTL_DSP_SETRECVOL: 1758 rv = sndctl_dsp_setrecvol(c, (int *)data); 1759 break; 1760 case SNDCTL_DSP_SETDUPLEX: /* Ignored */ 1761 case SNDCTL_DSP_LOW_WATER: /* Ignored */ 1762 case SNDCTL_DSP_POLICY: /* Ignored */ 1763 case SNDCTL_DSP_PROFILE: /* Ignored */ 1764 rv = 0; 1765 break; 1766 case SNDCTL_DSP_GETBLKSIZE: 1767 rv = sndctl_dsp_getblksize(c, (int *)data); 1768 break; 1769 case SNDCTL_DSP_GETOSPACE: 1770 rv = sndctl_dsp_getospace(c, (audio_buf_info *)data); 1771 break; 1772 case SNDCTL_DSP_GETISPACE: 1773 rv = sndctl_dsp_getispace(c, (audio_buf_info *)data); 1774 break; 1775 case SNDCTL_DSP_GETODELAY: 1776 rv = sndctl_dsp_getodelay(c, (int *)data); 1777 break; 1778 case SNDCTL_DSP_GETOPTR: 1779 rv = sndctl_dsp_getoptr(c, (count_info *)data); 1780 break; 1781 case SNDCTL_DSP_GETIPTR: 1782 rv = sndctl_dsp_getiptr(c, (count_info *)data); 1783 break; 1784 case SNDCTL_DSP_GETERROR: 1785 rv = sndctl_dsp_geterror(c, (audio_errinfo *)data); 1786 break; 1787 case SNDCTL_DSP_CURRENT_IPTR: 1788 rv = sndctl_dsp_current_iptr(c, (oss_count_t *)data); 1789 break; 1790 case SNDCTL_DSP_CURRENT_OPTR: 1791 rv = sndctl_dsp_current_optr(c, (oss_count_t *)data); 1792 break; 1793 1794 /* 1795 * Shared ioctls with /dev/mixer. 1796 */ 1797 case OSS_GETVERSION: 1798 rv = oss_getversion((int *)data); 1799 break; 1800 case SNDCTL_CARDINFO: 1801 rv = sndctl_cardinfo(c, (oss_card_info *)data); 1802 break; 1803 case SNDCTL_ENGINEINFO: 1804 case SNDCTL_AUDIOINFO: 1805 case SNDCTL_AUDIOINFO_EX: 1806 rv = sndctl_audioinfo(c, (oss_audioinfo *)data); 1807 break; 1808 case SNDCTL_SYSINFO: 1809 rv = sndctl_sysinfo((oss_sysinfo *)data); 1810 break; 1811 case SNDCTL_MIXERINFO: 1812 rv = sndctl_mixerinfo(c, (oss_mixerinfo *)data); 1813 break; 1814 case SOUND_MIXER_INFO: 1815 rv = sound_mixer_info(c, (mixer_info *)data); 1816 break; 1817 1818 /* 1819 * These are mixer ioctls that are virtualized for the DSP 1820 * device. They are accessible via either /dev/mixer or 1821 * /dev/dsp. 1822 */ 1823 case SOUND_MIXER_READ_RECSRC: 1824 case SOUND_MIXER_WRITE_RECSRC: 1825 rv = sound_mixer_read_recsrc(c, (int *)data); 1826 break; 1827 1828 case SOUND_MIXER_READ_DEVMASK: 1829 case SOUND_MIXER_READ_STEREODEVS: 1830 rv = sound_mixer_read_devmask(c, (int *)data); 1831 break; 1832 1833 case SOUND_MIXER_READ_RECMASK: 1834 rv = sound_mixer_read_recmask(c, (int *)data); 1835 break; 1836 1837 case SOUND_MIXER_READ_CAPS: 1838 rv = sound_mixer_read_caps(c, (int *)data); 1839 break; 1840 1841 /* 1842 * Ioctls we have chosen not to support for now. Some 1843 * of these are of legacy interest only. 1844 */ 1845 case SNDCTL_SETSONG: 1846 case SNDCTL_GETSONG: 1847 case SNDCTL_DSP_SYNCGROUP: 1848 case SNDCTL_DSP_SYNCSTART: 1849 case SNDCTL_DSP_GET_CHNORDER: 1850 case SNDCTL_DSP_SET_CHNORDER: 1851 case SNDCTL_DSP_GETIPEAKS: 1852 case SNDCTL_DSP_GETOPEAKS: 1853 case SNDCTL_DSP_GETCHANNELMASK: 1854 case SNDCTL_DSP_BIND_CHANNEL: 1855 case SNDCTL_DSP_SETSYNCRO: 1856 default: 1857 rv = EINVAL; 1858 break; 1859 } 1860 1861 if ((rv == 0) && (cmd & OSSIOC_OUT)) { 1862 rv = ddi_copyout(data, (void *)arg, sz, mode); 1863 } 1864 if (rv == 0) { 1865 *rvalp = 0; 1866 } 1867 1868 done: 1869 if (sz) { 1870 kmem_free(data, sz); 1871 } 1872 return (rv); 1873 } 1874 1875 static void 1876 oss_output(audio_client_t *c) 1877 { 1878 auclnt_pollwakeup(c, POLLOUT); 1879 } 1880 1881 static void 1882 oss_input(audio_client_t *c) 1883 { 1884 auclnt_pollwakeup(c, POLLIN | POLLRDNORM); 1885 } 1886 1887 static void 1888 oss_notify(audio_client_t *c) 1889 { 1890 audio_dev_t *d; 1891 ossdev_t *odev; 1892 1893 d = auclnt_get_dev(c); 1894 if ((odev = auclnt_get_dev_minor_data(d, AUDIO_MINOR_DSP)) == NULL) { 1895 return; 1896 } 1897 odev->d_modify_cnt++; 1898 } 1899 1900 static int 1901 ossmix_open(audio_client_t *c, int oflag) 1902 { 1903 int rv; 1904 ossclient_t *sc; 1905 ossdev_t *odev; 1906 1907 _NOTE(ARGUNUSED(oflag)); 1908 1909 if ((rv = auclnt_open(c, AUDIO_FORMAT_NONE, 0)) != 0) { 1910 return (rv); 1911 } 1912 1913 if ((sc = kmem_zalloc(sizeof (*sc), KM_NOSLEEP)) == NULL) { 1914 return (ENOMEM); 1915 } 1916 sc->o_ss_sz = 8192; 1917 if ((sc->o_ss_buf = kmem_zalloc(sc->o_ss_sz, KM_NOSLEEP)) == NULL) { 1918 kmem_free(sc, sizeof (*sc)); 1919 return (ENOMEM); 1920 } 1921 auclnt_set_private(c, sc); 1922 1923 odev = auclnt_get_minor_data(c, AUDIO_MINOR_DSP); 1924 1925 /* set a couple of common fields */ 1926 sc->o_client = c; 1927 sc->o_ossdev = odev; 1928 1929 return (rv); 1930 } 1931 1932 static void 1933 ossmix_close(audio_client_t *c) 1934 { 1935 ossclient_t *sc; 1936 1937 sc = auclnt_get_private(c); 1938 1939 kmem_free(sc->o_ss_buf, sc->o_ss_sz); 1940 kmem_free(sc, sizeof (*sc)); 1941 1942 auclnt_close(c); 1943 } 1944 1945 static int 1946 sndctl_mix_nrext(audio_client_t *c, int *ncp) 1947 { 1948 audio_dev_t *d; 1949 ossdev_t *odev; 1950 1951 d = auclnt_get_dev(c); 1952 1953 if ((*ncp != -1) && (*ncp != (auclnt_get_dev_index(d) - 1))) { 1954 return (ENXIO); 1955 } 1956 1957 if ((odev = auclnt_get_dev_minor_data(d, AUDIO_MINOR_DSP)) == NULL) { 1958 return (EINVAL); 1959 } 1960 1961 *ncp = odev->d_nctrl; 1962 1963 return (0); 1964 } 1965 1966 static int 1967 sndctl_mix_extinfo(audio_client_t *c, oss_mixext *pext) 1968 { 1969 audio_dev_t *d; 1970 ossdev_t *odev; 1971 int rv = 0; 1972 int dev; 1973 1974 d = auclnt_get_dev(c); 1975 1976 if (((dev = pext->dev) != -1) && (dev != (auclnt_get_dev_index(d) - 1))) 1977 return (ENXIO); 1978 1979 if (((odev = auclnt_get_dev_minor_data(d, AUDIO_MINOR_DSP)) == NULL) || 1980 (pext->ctrl >= odev->d_nctrl)) { 1981 return (EINVAL); 1982 } 1983 1984 bcopy(&odev->d_exts[pext->ctrl], pext, sizeof (*pext)); 1985 pext->enumbit = 0; 1986 pext->dev = dev; 1987 1988 return (rv); 1989 } 1990 1991 static int 1992 sndctl_mix_enuminfo(audio_client_t *c, oss_mixer_enuminfo *ei) 1993 { 1994 audio_dev_t *d; 1995 audio_ctrl_desc_t desc; 1996 audio_ctrl_t *ctrl; 1997 ossdev_t *odev; 1998 uint64_t mask; 1999 int bit; 2000 ushort_t nxt; 2001 2002 d = auclnt_get_dev(c); 2003 2004 if ((ei->dev != -1) && (ei->dev != (auclnt_get_dev_index(d) - 1))) 2005 return (ENXIO); 2006 2007 if (((odev = auclnt_get_dev_minor_data(d, AUDIO_MINOR_DSP)) == NULL) || 2008 (ei->ctrl >= odev->d_nctrl) || 2009 (odev->d_exts[ei->ctrl].type != MIXT_ENUM) || 2010 ((ctrl = odev->d_ctrls[ei->ctrl]) == NULL) || 2011 (auclnt_control_describe(ctrl, &desc) != 0)) { 2012 return (EINVAL); 2013 } 2014 2015 mask = desc.acd_maxvalue; 2016 bit = 0; 2017 nxt = 0; 2018 ei->nvalues = 0; 2019 bzero(ei->strings, sizeof (ei->strings)); 2020 bzero(ei->strindex, sizeof (ei->strindex)); 2021 2022 while (mask) { 2023 const char *name = desc.acd_enum[bit]; 2024 nxt = oss_set_enum(ei, nxt, name ? name : ""); 2025 mask >>= 1; 2026 bit++; 2027 } 2028 2029 return (0); 2030 } 2031 2032 static int 2033 sndctl_mix_read(audio_client_t *c, oss_mixer_value *vr) 2034 { 2035 int rv; 2036 uint64_t v; 2037 audio_dev_t *d; 2038 audio_ctrl_t *ctrl; 2039 ossdev_t *odev; 2040 2041 d = auclnt_get_dev(c); 2042 2043 if ((vr->dev != -1) && (vr->dev != (auclnt_get_dev_index(d) - 1))) 2044 return (ENXIO); 2045 2046 if (((odev = auclnt_get_dev_minor_data(d, AUDIO_MINOR_DSP)) == NULL) || 2047 (vr->ctrl >= odev->d_nctrl) || 2048 ((ctrl = odev->d_ctrls[vr->ctrl]) == NULL)) { 2049 return (EINVAL); 2050 } 2051 if ((rv = auclnt_control_read(ctrl, &v)) == 0) { 2052 switch (odev->d_exts[vr->ctrl].type) { 2053 case MIXT_ENUM: 2054 /* translate this from an enum style bit mask */ 2055 vr->value = ddi_ffs((unsigned long)v) - 1; 2056 break; 2057 case MIXT_STEREOSLIDER: 2058 vr->value = (int)ddi_swap16(v & 0xffff); 2059 break; 2060 case MIXT_MONOSLIDER: 2061 vr->value = (int)(v | (v << 8)); 2062 break; 2063 case MIXT_ONOFF: 2064 /* this could be simple, or could be part of a multi */ 2065 if (odev->d_exts[vr->ctrl].enumbit >= 0) { 2066 uint64_t mask; 2067 mask = 1; 2068 mask <<= (odev->d_exts[vr->ctrl].enumbit); 2069 vr->value = (v & mask) ? 1 : 0; 2070 } else { 2071 vr->value = v ? 1 : 0; 2072 } 2073 break; 2074 2075 default: 2076 vr->value = (int)v; 2077 break; 2078 } 2079 } 2080 2081 return (rv); 2082 } 2083 2084 static int 2085 sndctl_mix_write(audio_client_t *c, oss_mixer_value *vr) 2086 { 2087 int rv; 2088 uint64_t v; 2089 audio_dev_t *d; 2090 audio_ctrl_t *ctrl; 2091 ossdev_t *odev; 2092 2093 d = auclnt_get_dev(c); 2094 2095 if ((vr->dev != -1) && (vr->dev != (auclnt_get_dev_index(d) - 1))) 2096 return (ENXIO); 2097 2098 if (((odev = auclnt_get_dev_minor_data(d, AUDIO_MINOR_DSP)) == NULL) || 2099 (vr->ctrl >= odev->d_nctrl) || 2100 ((ctrl = odev->d_ctrls[vr->ctrl]) == NULL)) { 2101 return (EINVAL); 2102 } 2103 2104 switch (odev->d_exts[vr->ctrl].type) { 2105 case MIXT_ONOFF: 2106 /* this could be standalone, or it could be part of a multi */ 2107 if (odev->d_exts[vr->ctrl].enumbit >= 0) { 2108 uint64_t mask; 2109 if ((rv = auclnt_control_read(ctrl, &v)) != 0) { 2110 return (EINVAL); 2111 } 2112 mask = 1; 2113 mask <<= (odev->d_exts[vr->ctrl].enumbit); 2114 if (vr->value) { 2115 v |= mask; 2116 } else { 2117 v &= ~mask; 2118 } 2119 } else { 2120 v = vr->value; 2121 } 2122 break; 2123 case MIXT_ENUM: 2124 /* translate this to an enum style bit mask */ 2125 v = 1U << vr->value; 2126 break; 2127 case MIXT_MONOSLIDER: 2128 /* mask off high order bits */ 2129 v = vr->value & 0xff; 2130 break; 2131 case MIXT_STEREOSLIDER: 2132 /* OSS uses reverse byte ordering */ 2133 v = vr->value; 2134 v = ddi_swap16(vr->value & 0xffff); 2135 break; 2136 default: 2137 v = vr->value; 2138 } 2139 rv = auclnt_control_write(ctrl, v); 2140 2141 return (rv); 2142 } 2143 2144 static int 2145 sndctl_mix_nrmix(audio_client_t *c, int *nmixp) 2146 { 2147 _NOTE(ARGUNUSED(c)); 2148 *nmixp = oss_cnt_devs() - 1; 2149 return (0); 2150 } 2151 2152 static int 2153 ossmix_ioctl(audio_client_t *c, int cmd, intptr_t arg, int mode, cred_t *credp, 2154 int *rvalp) 2155 { 2156 int sz; 2157 void *data; 2158 int rv = 0; 2159 2160 sz = OSSIOC_GETSZ(cmd); 2161 2162 if ((cmd & (OSSIOC_IN | OSSIOC_OUT)) && sz) { 2163 if ((data = kmem_zalloc(sz, KM_NOSLEEP)) == NULL) { 2164 return (ENOMEM); 2165 } 2166 } else { 2167 sz = 0; 2168 } 2169 2170 if (cmd & OSSIOC_IN) { 2171 if ((rv = ddi_copyin((void *)arg, data, sz, mode)) != 0) { 2172 goto done; 2173 } 2174 } 2175 2176 switch (cmd) { 2177 /* 2178 * Mixer specific ioctls 2179 */ 2180 case SNDCTL_MIX_NREXT: 2181 rv = sndctl_mix_nrext(c, (int *)data); 2182 break; 2183 case SNDCTL_MIX_EXTINFO: 2184 rv = sndctl_mix_extinfo(c, (oss_mixext *)data); 2185 break; 2186 case SNDCTL_MIX_ENUMINFO: 2187 rv = sndctl_mix_enuminfo(c, (oss_mixer_enuminfo *)data); 2188 break; 2189 case SNDCTL_MIX_READ: 2190 rv = sndctl_mix_read(c, (oss_mixer_value *)data); 2191 break; 2192 case SNDCTL_MIX_WRITE: 2193 rv = sndctl_mix_write(c, (oss_mixer_value *)data); 2194 break; 2195 case SNDCTL_MIX_NRMIX: 2196 rv = sndctl_mix_nrmix(c, (int *)data); 2197 break; 2198 2199 /* 2200 * Legacy ioctls. These are treated as soft values only, 2201 * and do not affect global hardware state. For use by 2202 * legacy DSP applications. 2203 */ 2204 case SOUND_MIXER_READ_VOLUME: 2205 case SOUND_MIXER_READ_PCM: 2206 case SOUND_MIXER_READ_OGAIN: 2207 rv = sndctl_dsp_getplayvol(c, (int *)data); 2208 break; 2209 2210 case SOUND_MIXER_WRITE_VOLUME: 2211 case SOUND_MIXER_WRITE_PCM: 2212 case SOUND_MIXER_WRITE_OGAIN: 2213 rv = sound_mixer_write_ogain(c, (int *)data); 2214 break; 2215 2216 case SOUND_MIXER_READ_RECGAIN: 2217 case SOUND_MIXER_READ_RECLEV: 2218 case SOUND_MIXER_READ_IGAIN: 2219 rv = sndctl_dsp_getrecvol(c, (int *)data); 2220 break; 2221 2222 case SOUND_MIXER_WRITE_RECGAIN: 2223 case SOUND_MIXER_WRITE_RECLEV: 2224 case SOUND_MIXER_WRITE_IGAIN: 2225 rv = sound_mixer_write_igain(c, (int *)data); 2226 break; 2227 2228 case SOUND_MIXER_READ_RECSRC: 2229 case SOUND_MIXER_WRITE_RECSRC: 2230 rv = sound_mixer_read_recsrc(c, (int *)data); 2231 break; 2232 2233 case SOUND_MIXER_READ_DEVMASK: 2234 case SOUND_MIXER_READ_STEREODEVS: 2235 rv = sound_mixer_read_devmask(c, (int *)data); 2236 break; 2237 2238 case SOUND_MIXER_READ_RECMASK: 2239 rv = sound_mixer_read_recmask(c, (int *)data); 2240 break; 2241 2242 /* 2243 * Common ioctls shared with DSP 2244 */ 2245 case OSS_GETVERSION: 2246 rv = oss_getversion((int *)data); 2247 break; 2248 2249 case SNDCTL_CARDINFO: 2250 rv = sndctl_cardinfo(c, (oss_card_info *)data); 2251 break; 2252 2253 case SNDCTL_ENGINEINFO: 2254 case SNDCTL_AUDIOINFO: 2255 case SNDCTL_AUDIOINFO_EX: 2256 rv = sndctl_audioinfo(c, (oss_audioinfo *)data); 2257 break; 2258 2259 case SNDCTL_SYSINFO: 2260 rv = sndctl_sysinfo((oss_sysinfo *)data); 2261 break; 2262 2263 case SNDCTL_MIXERINFO: 2264 rv = sndctl_mixerinfo(c, (oss_mixerinfo *)data); 2265 break; 2266 2267 case SOUND_MIXER_INFO: 2268 rv = sound_mixer_info(c, (mixer_info *)data); 2269 break; 2270 2271 case SNDCTL_MIX_DESCRIPTION: /* NOT SUPPORTED: tooltip */ 2272 rv = EIO; /* OSS returns EIO for this one */ 2273 break; 2274 2275 /* 2276 * Special implementation-private ioctls. 2277 */ 2278 case SNDCTL_SUN_SEND_NUMBER: 2279 rv = sndctl_sun_send_number(c, (int *)data, credp); 2280 break; 2281 2282 /* 2283 * Legacy ioctls we don't support. 2284 */ 2285 case SOUND_MIXER_WRITE_MONGAIN: 2286 case SOUND_MIXER_READ_MONGAIN: 2287 case SOUND_MIXER_READ_BASS: 2288 case SOUND_MIXER_READ_TREBLE: 2289 case SOUND_MIXER_READ_SPEAKER: 2290 case SOUND_MIXER_READ_LINE: 2291 case SOUND_MIXER_READ_MIC: 2292 case SOUND_MIXER_READ_CD: 2293 case SOUND_MIXER_READ_IMIX: 2294 case SOUND_MIXER_READ_ALTPCM: 2295 case SOUND_MIXER_READ_SYNTH: 2296 case SOUND_MIXER_READ_LINE1: 2297 case SOUND_MIXER_READ_LINE2: 2298 case SOUND_MIXER_READ_LINE3: 2299 case SOUND_MIXER_WRITE_BASS: 2300 case SOUND_MIXER_WRITE_TREBLE: 2301 case SOUND_MIXER_WRITE_SPEAKER: 2302 case SOUND_MIXER_WRITE_LINE: 2303 case SOUND_MIXER_WRITE_MIC: 2304 case SOUND_MIXER_WRITE_CD: 2305 case SOUND_MIXER_WRITE_IMIX: 2306 case SOUND_MIXER_WRITE_ALTPCM: 2307 case SOUND_MIXER_WRITE_SYNTH: 2308 case SOUND_MIXER_WRITE_LINE1: 2309 case SOUND_MIXER_WRITE_LINE2: 2310 case SOUND_MIXER_WRITE_LINE3: 2311 /* 2312 * Additional ioctls we *could* support, but don't. 2313 */ 2314 case SNDCTL_SETSONG: 2315 case SNDCTL_SETLABEL: 2316 case SNDCTL_GETSONG: 2317 case SNDCTL_GETLABEL: 2318 case SNDCTL_MIDIINFO: 2319 case SNDCTL_SETNAME: 2320 default: 2321 rv = EINVAL; 2322 break; 2323 } 2324 2325 if ((rv == 0) && (cmd & OSSIOC_OUT)) { 2326 rv = ddi_copyout(data, (void *)arg, sz, mode); 2327 } 2328 if (rv == 0) { 2329 *rvalp = 0; 2330 } 2331 2332 done: 2333 if (sz) { 2334 kmem_free(data, sz); 2335 } 2336 return (rv); 2337 } 2338 2339 static void * 2340 oss_dev_init(audio_dev_t *dev) 2341 { 2342 ossdev_t *odev; 2343 2344 odev = kmem_zalloc(sizeof (*odev), KM_SLEEP); 2345 odev->d_dev = dev; 2346 2347 mutex_init(&odev->d_mx, NULL, MUTEX_DRIVER, NULL); 2348 cv_init(&odev->d_cv, NULL, CV_DRIVER, NULL); 2349 oss_alloc_controls(odev); 2350 2351 return (odev); 2352 } 2353 2354 static void 2355 oss_dev_fini(void *arg) 2356 { 2357 ossdev_t *odev = arg; 2358 2359 if (odev != NULL) { 2360 oss_free_controls(odev); 2361 mutex_destroy(&odev->d_mx); 2362 cv_destroy(&odev->d_cv); 2363 kmem_free(odev, sizeof (*odev)); 2364 } 2365 } 2366 2367 static void 2368 sndstat_printf(ossclient_t *oc, const char *fmt, ...) 2369 { 2370 va_list va; 2371 2372 va_start(va, fmt); 2373 (void) vsnprintf(oc->o_ss_buf + oc->o_ss_len, 2374 oc->o_ss_sz - oc->o_ss_len, fmt, va); 2375 va_end(va); 2376 oc->o_ss_len = strlen(oc->o_ss_buf); 2377 } 2378 2379 static int 2380 sndstat_dev_walker(audio_dev_t *d, void *arg) 2381 { 2382 ossclient_t *oc = arg; 2383 const char *capstr; 2384 unsigned cap; 2385 2386 cap = auclnt_get_dev_capab(d); 2387 2388 if (cap & AUDIO_CLIENT_CAP_DUPLEX) { 2389 capstr = "DUPLEX"; 2390 } else if ((cap & AUDIO_CLIENT_CAP_PLAY) && 2391 (cap & AUDIO_CLIENT_CAP_RECORD)) { 2392 capstr = "INPUT,OUTPUT"; 2393 } else if (cap & AUDIO_CLIENT_CAP_PLAY) { 2394 capstr = "OUTPUT"; 2395 } else if (cap & AUDIO_CLIENT_CAP_RECORD) { 2396 capstr = "INPUT"; 2397 } else { 2398 capstr = NULL; 2399 } 2400 2401 if (capstr == NULL) 2402 return (AUDIO_WALK_CONTINUE); 2403 2404 sndstat_printf(oc, "%d: %s %s, %s (%s)\n", 2405 auclnt_get_dev_number(d), auclnt_get_dev_name(d), 2406 auclnt_get_dev_description(d), auclnt_get_dev_version(d), capstr); 2407 2408 return (AUDIO_WALK_CONTINUE); 2409 } 2410 2411 static int 2412 sndstat_mixer_walker(audio_dev_t *d, void *arg) 2413 { 2414 ossclient_t *oc = arg; 2415 unsigned cap; 2416 void *iter; 2417 const char *info; 2418 2419 cap = auclnt_get_dev_capab(d); 2420 2421 if ((cap & (AUDIO_CLIENT_CAP_PLAY|AUDIO_CLIENT_CAP_RECORD)) == 0) 2422 return (AUDIO_WALK_CONTINUE); 2423 2424 sndstat_printf(oc, "%d: %s %s, %s\n", 2425 auclnt_get_dev_number(d), auclnt_get_dev_name(d), 2426 auclnt_get_dev_description(d), auclnt_get_dev_version(d)); 2427 iter = NULL; 2428 while ((info = auclnt_get_dev_hw_info(d, &iter)) != NULL) { 2429 sndstat_printf(oc, "\t%s\n", info); 2430 } 2431 return (AUDIO_WALK_CONTINUE); 2432 } 2433 2434 static int 2435 ossmix_write(audio_client_t *c, struct uio *uio, cred_t *cr) 2436 { 2437 /* write on sndstat is a no-op */ 2438 _NOTE(ARGUNUSED(c)); 2439 _NOTE(ARGUNUSED(uio)); 2440 _NOTE(ARGUNUSED(cr)); 2441 2442 return (0); 2443 } 2444 2445 static int 2446 ossmix_read(audio_client_t *c, struct uio *uio, cred_t *cr) 2447 { 2448 ossclient_t *oc; 2449 unsigned n; 2450 int rv; 2451 2452 _NOTE(ARGUNUSED(cr)); 2453 2454 if (uio->uio_resid == 0) { 2455 return (0); 2456 } 2457 2458 oc = auclnt_get_private(c); 2459 2460 mutex_enter(&oc->o_ss_lock); 2461 2462 if (oc->o_ss_off == 0) { 2463 2464 sndstat_printf(oc, "SunOS Audio Framework\n"); 2465 2466 sndstat_printf(oc, "\nAudio Devices:\n"); 2467 auclnt_walk_devs_by_number(sndstat_dev_walker, oc); 2468 2469 sndstat_printf(oc, "\nMixers:\n"); 2470 auclnt_walk_devs_by_number(sndstat_mixer_walker, oc); 2471 } 2472 2473 /* 2474 * For simplicity's sake, we implement a non-seekable device. We could 2475 * support seekability, but offsets would be rather meaningless between 2476 * changes. 2477 */ 2478 n = min(uio->uio_resid, (oc->o_ss_len - oc->o_ss_off)); 2479 2480 rv = uiomove(oc->o_ss_buf + oc->o_ss_off, n, UIO_READ, uio); 2481 if (rv != 0) { 2482 n = 0; 2483 } 2484 oc->o_ss_off += n; 2485 2486 if (n == 0) { 2487 /* 2488 * end-of-file reached... clear the sndstat buffer so that 2489 * subsequent reads will get the latest data. 2490 */ 2491 oc->o_ss_off = oc->o_ss_len = 0; 2492 } 2493 mutex_exit(&oc->o_ss_lock); 2494 return (rv); 2495 } 2496 2497 int 2498 oss_read(audio_client_t *c, struct uio *uio, cred_t *cr) 2499 { 2500 _NOTE(ARGUNUSED(cr)); 2501 2502 auclnt_clear_paused(auclnt_input_stream(c)); 2503 2504 return (auclnt_read(c, uio)); 2505 } 2506 2507 int 2508 oss_write(audio_client_t *c, struct uio *uio, cred_t *cr) 2509 { 2510 _NOTE(ARGUNUSED(cr)); 2511 2512 auclnt_clear_paused(auclnt_output_stream(c)); 2513 2514 return (auclnt_write(c, uio)); 2515 } 2516 2517 int 2518 oss_chpoll(audio_client_t *c, short events, int anyyet, short *reventsp, 2519 struct pollhead **phpp) 2520 { 2521 return (auclnt_chpoll(c, events, anyyet, reventsp, phpp)); 2522 } 2523 2524 static struct audio_client_ops oss_ops = { 2525 "sound,dsp", 2526 oss_dev_init, 2527 oss_dev_fini, 2528 oss_open, 2529 oss_close, 2530 oss_read, 2531 oss_write, 2532 oss_ioctl, 2533 oss_chpoll, 2534 NULL, /* mmap */ 2535 oss_input, 2536 oss_output, 2537 NULL, /* notify */ 2538 NULL, /* drain */ 2539 }; 2540 2541 static struct audio_client_ops ossmix_ops = { 2542 "sound,mixer", 2543 NULL, 2544 NULL, 2545 ossmix_open, 2546 ossmix_close, 2547 ossmix_read, 2548 ossmix_write, 2549 ossmix_ioctl, 2550 NULL, /* chpoll */ 2551 NULL, /* mmap */ 2552 NULL, /* input */ 2553 NULL, /* output */ 2554 oss_notify, 2555 NULL, /* drain */ 2556 }; 2557 2558 /* nearly the same as ossxmix; different minor name helps devfsadm */ 2559 static struct audio_client_ops sndstat_ops = { 2560 "sound,sndstat", 2561 NULL, /* dev_init */ 2562 NULL, /* dev_fini */ 2563 ossmix_open, 2564 ossmix_close, 2565 ossmix_read, 2566 ossmix_write, 2567 ossmix_ioctl, 2568 NULL, /* chpoll */ 2569 NULL, /* mmap */ 2570 NULL, /* input */ 2571 NULL, /* output */ 2572 NULL, /* notify */ 2573 NULL, /* drain */ 2574 }; 2575 2576 void 2577 auimpl_oss_init(void) 2578 { 2579 auclnt_register_ops(AUDIO_MINOR_DSP, &oss_ops); 2580 auclnt_register_ops(AUDIO_MINOR_MIXER, &ossmix_ops); 2581 auclnt_register_ops(AUDIO_MINOR_SNDSTAT, &sndstat_ops); 2582 } 2583