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 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * USB audio hid streams module - processes hid data 30 * from HID driver and converts to a format that SADA 31 * understands. The stack looks like this : 32 * hid --> usb_ah --> usb_ac --> audio framework 33 * usb_ac just acts as a passthrough layer for the converted data. 34 * 35 * During open, usb_ah gets the parser handle from hid and gets 36 * the hardware information passed as report descriptor. Then 37 * it finds out the relevant usages and stores the bitmap and other 38 * information in internal data structure. When a button is pressed 39 * to. say, increase/decrease the volume, a report is generated and 40 * hid sends that data up through the streams. usb_ah, upon getting 41 * this information and with the prior knowledge about the bitmap 42 * for each button, calculates the value and sends up to SADA 43 * through usb_ac. SADA in turn sends a command down to speaker to 44 * increase the volume of the speaker that is managed by usb_ac. 45 */ 46 #include <sys/usb/usba.h> 47 #include <sys/usb/clients/hid/hid.h> 48 #include <sys/usb/clients/hidparser/hidparser.h> 49 #include <sys/stropts.h> 50 51 #include <sys/audio.h> 52 #include <sys/audiovar.h> 53 #include <sys/audio/audio_support.h> 54 #include <sys/audio/audio_src.h> 55 #include <sys/mixer.h> 56 #include <sys/audio/audio_mixer.h> 57 #include <sys/audio/am_src1.h> 58 59 #include <sys/usb/clients/audio/usb_audio.h> 60 #include <sys/usb/clients/audio/usb_mixer.h> 61 #include <sys/usb/clients/audio/usb_ah/usb_ah.h> 62 63 /* debugging information */ 64 uint_t usb_ah_errmask = (uint_t)PRINT_MASK_ALL; 65 uint_t usb_ah_errlevel = USB_LOG_L4; 66 static usb_log_handle_t usb_ah_log_handle; 67 68 /* 69 * Internal Function Prototypes 70 */ 71 static void usb_ah_mctl_receive(queue_t *, mblk_t *); 72 static mblk_t *usb_ah_cp_mblk(mblk_t *); 73 static void usb_ah_timeout(void *); 74 static void usb_ah_repeat_send(usb_ah_state_t *, usb_ah_button_descr_t *, 75 struct iocblk, char *, int); 76 static void usb_ah_cancel_timeout(usb_ah_state_t *); 77 static void usb_ah_check_usage_send_data(usb_ah_state_t *, mblk_t *); 78 static int usb_ah_get_cooked_rd(usb_ah_state_t *); 79 80 /* stream qinit functions defined here */ 81 static int usb_ah_open(queue_t *, dev_t *, int, int, cred_t *); 82 static int usb_ah_close(queue_t *, int, cred_t *); 83 static void usb_ah_wput(queue_t *, mblk_t *); 84 static void usb_ah_rput(queue_t *, mblk_t *); 85 86 /* 87 * Global Variables 88 */ 89 int usb_ah_rpt_tick; 90 91 static struct streamtab usb_ah_info; 92 static struct fmodsw fsw = { 93 "usb_ah", 94 &usb_ah_info, 95 D_NEW | D_MP | D_MTPERMOD 96 }; 97 98 /* 99 * Module linkage information for the kernel. 100 */ 101 extern struct mod_ops mod_strmodops; 102 103 static struct modlstrmod modlstrmod = { 104 &mod_strmodops, 105 "USB audio hid streams %I%", 106 &fsw 107 }; 108 109 static struct modlinkage modlinkage = { 110 MODREV_1, 111 (void *)&modlstrmod, 112 NULL 113 }; 114 115 /* 116 * Warlock is not aware of the automatic locking mechanisms for 117 * streams modules. 118 * Since warlock is not aware of the streams perimeters, these notes 119 * have been added. 120 */ 121 _NOTE(SCHEME_PROTECTS_DATA("unique per call", iocblk)) 122 _NOTE(SCHEME_PROTECTS_DATA("unique per call", datab)) 123 _NOTE(SCHEME_PROTECTS_DATA("unique per call", msgb)) 124 _NOTE(SCHEME_PROTECTS_DATA("unique per call", queue)) 125 126 /* 127 * Module qinit functions 128 */ 129 static struct module_info usb_ah_minfo = { 130 0, /* module id number */ 131 "usb_ah", /* module name */ 132 0, /* min packet size accepted */ 133 INFPSZ, /* max packet size accepted */ 134 2048, /* hi-water mark */ 135 128 /* lo-water mark */ 136 }; 137 138 /* read side for key data and ioctl replies */ 139 static struct qinit usb_ah_rinit = { 140 (int (*)())usb_ah_rput, 141 (int (*)())NULL, /* service not used */ 142 usb_ah_open, 143 usb_ah_close, 144 (int (*)())NULL, 145 &usb_ah_minfo 146 }; 147 148 /* write side for ioctls */ 149 static struct qinit usb_ah_winit = { 150 (int (*)())usb_ah_wput, 151 (int (*)())NULL, 152 usb_ah_open, 153 usb_ah_close, 154 (int (*)())NULL, 155 &usb_ah_minfo 156 }; 157 158 static struct streamtab usb_ah_info = { 159 &usb_ah_rinit, 160 &usb_ah_winit, 161 NULL, /* for muxes */ 162 NULL, /* for muxes */ 163 }; 164 165 166 int 167 _init() 168 { 169 int rval = mod_install(&modlinkage); 170 171 if (rval == 0) { 172 usb_ah_rpt_tick = drv_usectohz(USB_AH_TIMEOUT); 173 usb_ah_log_handle = usb_alloc_log_hdl(NULL, "usb_ah", 174 &usb_ah_errlevel, &usb_ah_errmask, NULL, 0); 175 } 176 177 return (rval); 178 } 179 180 181 int 182 _fini() 183 { 184 int rval = mod_remove(&modlinkage); 185 186 if (rval == 0) { 187 usb_free_log_hdl(usb_ah_log_handle); 188 } 189 190 return (rval); 191 } 192 193 194 int 195 _info(struct modinfo *modinfop) 196 { 197 return (mod_info(&modlinkage, modinfop)); 198 } 199 200 201 /* 202 * usb_ah_open : 203 * Open a usb audio hid device 204 */ 205 /* ARGSUSED */ 206 static int 207 usb_ah_open(queue_t *q, dev_t *devp, int oflag, int sflag, cred_t *crp) 208 { 209 usb_ah_state_t *usb_ahd; 210 hidparser_packet_info_t hpack; 211 struct iocblk mctlmsg; 212 mblk_t *mctl_ptr; 213 214 if (q->q_ptr) { 215 USB_DPRINTF_L3(PRINT_MASK_OPEN, usb_ah_log_handle, 216 "usb_ah_open already opened"); 217 218 return (0); /* already opened */ 219 } 220 221 switch (sflag) { 222 case MODOPEN: 223 224 break; 225 case CLONEOPEN: 226 USB_DPRINTF_L3(PRINT_MASK_OPEN, usb_ah_log_handle, 227 "usb_ah_open: Clone open not supported"); 228 229 /* FALLTHRU */ 230 default: 231 232 return (EINVAL); 233 } 234 235 usb_ahd = kmem_zalloc(sizeof (usb_ah_state_t), KM_SLEEP); 236 237 USB_DPRINTF_L3(PRINT_MASK_OPEN, usb_ah_log_handle, 238 "usb_ah_state= 0x%p", (void *)usb_ahd); 239 240 mutex_init(&usb_ahd->usb_ah_mutex, NULL, MUTEX_DRIVER, NULL); 241 242 /* 243 * Set up private data. 244 */ 245 usb_ahd->usb_ah_readq = q; 246 usb_ahd->usb_ah_writeq = WR(q); 247 248 /* 249 * Set up queue pointers, so that the "put" procedure will accept 250 * the reply to the "ioctl" message we send down. 251 */ 252 q->q_ptr = (caddr_t)usb_ahd; 253 WR(q)->q_ptr = (caddr_t)usb_ahd; 254 255 qprocson(q); 256 257 /* request hid report descriptor from HID */ 258 mctlmsg.ioc_cmd = HID_GET_PARSER_HANDLE; 259 mctlmsg.ioc_count = 0; 260 mctl_ptr = usba_mk_mctl(mctlmsg, NULL, 0); 261 if (mctl_ptr == NULL) { 262 /* failure to allocate M_CTL message */ 263 qprocsoff(q); 264 mutex_destroy(&usb_ahd->usb_ah_mutex); 265 kmem_free(usb_ahd, sizeof (*usb_ahd)); 266 267 return (ENOMEM); 268 } 269 270 putnext(usb_ahd->usb_ah_writeq, mctl_ptr); 271 272 /* 273 * Now that signal has been sent, wait for report descriptor. 274 * Cleanup if user signals in the mean time 275 */ 276 usb_ahd->usb_ah_flags |= USB_AH_QWAIT; 277 while (usb_ahd->usb_ah_flags & USB_AH_QWAIT) { 278 279 if (qwait_sig(q) == 0) { 280 usb_ahd->usb_ah_flags = 0; 281 qprocsoff(q); 282 mutex_destroy(&usb_ahd->usb_ah_mutex); 283 kmem_free(usb_ahd, sizeof (*usb_ahd)); 284 285 return (EINTR); 286 } 287 } 288 289 if (usb_ahd->usb_ah_report_descr != NULL) { 290 hidparser_find_max_packet_size_from_report_descriptor( 291 usb_ahd->usb_ah_report_descr, &hpack); 292 293 /* round up to the nearest byte */ 294 usb_ahd->usb_ah_packet_size = (hpack.max_packet_size + 7) / 8; 295 296 if (hpack.report_id == HID_REPORT_ID_UNDEFINED) { 297 usb_ahd->usb_ah_uses_report_ids = 0; 298 usb_ahd->usb_ah_report_id = HID_REPORT_ID_UNDEFINED; 299 } else { 300 usb_ahd->usb_ah_uses_report_ids = 1; 301 usb_ahd->usb_ah_report_id = hpack.report_id; 302 /* add more more byte for report id */ 303 usb_ahd->usb_ah_packet_size++; 304 } 305 306 if (usb_ah_get_cooked_rd(usb_ahd) != USB_SUCCESS) { 307 qprocsoff(q); 308 mutex_destroy(&usb_ahd->usb_ah_mutex); 309 kmem_free(usb_ahd, sizeof (*usb_ahd)); 310 311 return (EIO); 312 } 313 } else { 314 USB_DPRINTF_L2(PRINT_MASK_OPEN, usb_ah_log_handle, 315 "usb_ah: Invalid Report Descriptor Tree."); 316 317 qprocsoff(q); 318 mutex_destroy(&usb_ahd->usb_ah_mutex); 319 kmem_free(usb_ahd, sizeof (*usb_ahd)); 320 321 return (EIO); 322 } 323 324 usb_ahd->usb_ah_flags |= USB_AH_OPEN; 325 326 USB_DPRINTF_L3(PRINT_MASK_OPEN, usb_ah_log_handle, 327 "usb_ah_open exiting"); 328 329 return (0); 330 } 331 332 333 /* 334 * usb_ah_close : 335 * Close a audio hid device 336 */ 337 /* ARGSUSED1 */ 338 static int 339 usb_ah_close(register queue_t *q, int flag, cred_t *crp) 340 { 341 usb_ah_state_t *usb_ahd = (usb_ah_state_t *)q->q_ptr; 342 343 mutex_enter(&usb_ahd->usb_ah_mutex); 344 345 /* 346 * Since we're about to destroy our private data, turn off 347 * our open flag first, so we don't accept any more input 348 * and try to use that data. 349 */ 350 usb_ahd->usb_ah_flags = 0; 351 usb_ah_cancel_timeout(usb_ahd); 352 353 flushq(q, FLUSHALL); 354 flushq(WR(q), FLUSHALL); 355 356 mutex_exit(&usb_ahd->usb_ah_mutex); 357 358 qprocsoff(q); 359 q->q_ptr = NULL; 360 WR(q)->q_ptr = NULL; 361 362 mutex_destroy(&usb_ahd->usb_ah_mutex); 363 kmem_free(usb_ahd, sizeof (usb_ah_state_t)); 364 365 USB_DPRINTF_L4(PRINT_MASK_CLOSE, usb_ah_log_handle, 366 "usb_ah_close exiting"); 367 368 return (0); 369 } 370 371 372 /* 373 * usb_ah_wput : 374 * usb_ah module output queue put procedure: handles M_IOCTL 375 * messages. 376 */ 377 static void 378 usb_ah_wput(register queue_t *q, register mblk_t *mp) 379 { 380 381 USB_DPRINTF_L4(PRINT_MASK_ALL, usb_ah_log_handle, 382 "usb_ah_wput entering"); 383 384 switch (mp->b_datap->db_type) { 385 case M_FLUSH: 386 if (*mp->b_rptr & FLUSHW) { 387 flushq(q, FLUSHDATA); 388 } 389 if (*mp->b_rptr & FLUSHR) { 390 flushq(RD(q), FLUSHDATA); 391 } 392 393 break; 394 default: 395 break; 396 } 397 398 putnext(q, mp); 399 400 USB_DPRINTF_L4(PRINT_MASK_ALL, usb_ah_log_handle, 401 "usb_ah_wput exiting:3"); 402 } 403 404 405 /* 406 * usb_ah_rput : 407 * Put procedure for input from driver end of stream (read queue). 408 */ 409 static void 410 usb_ah_rput(register queue_t *q, register mblk_t *mp) 411 { 412 usb_ah_state_t *usb_ahd; 413 414 usb_ahd = (usb_ah_state_t *)q->q_ptr; 415 416 USB_DPRINTF_L3(PRINT_MASK_ALL, usb_ah_log_handle, 417 "usb_ah_rput: Begin, usb_ah state=0x%p, q=0x%p, mp=0x%p", 418 (void *)usb_ahd, (void *)q, (void *)mp); 419 420 if (usb_ahd == 0) { 421 freemsg(mp); /* nobody's listening */ 422 423 return; 424 } 425 426 switch (mp->b_datap->db_type) { 427 case M_FLUSH: 428 if (*mp->b_rptr & FLUSHW) 429 flushq(WR(q), FLUSHDATA); 430 if (*mp->b_rptr & FLUSHR) 431 flushq(q, FLUSHDATA); 432 freemsg(mp); 433 434 return; 435 case M_DATA: 436 if (!(usb_ahd->usb_ah_flags & USB_AH_OPEN)) { 437 freemsg(mp); /* not ready to listen */ 438 439 return; 440 } else if ((mp->b_wptr - mp->b_rptr) == 441 usb_ahd->usb_ah_packet_size) { 442 443 /* 444 * Process this report if the device doesn't have 445 * multiple reports, or this is the one we support 446 */ 447 if ((usb_ahd->usb_ah_report_id == 448 HID_REPORT_ID_UNDEFINED) || 449 (usb_ahd->usb_ah_report_id == (int)*mp->b_rptr)) { 450 /* we now have a complete packet */ 451 usb_ah_check_usage_send_data(usb_ahd, mp); 452 } else { 453 USB_DPRINTF_L2(PRINT_MASK_ALL, 454 usb_ah_log_handle, 455 "usb_ah_rput: skipping report with " 456 "id= %d", *mp->b_rptr); 457 458 /* skip the reports we don't support */ 459 freemsg(mp); 460 } 461 } else { 462 /* filter out spurious packets */ 463 freemsg(mp); 464 } 465 466 break; 467 case M_CTL: 468 usb_ah_mctl_receive(q, mp); 469 470 return; 471 case M_IOCACK: 472 case M_IOCNAK: 473 putnext(q, mp); 474 475 return; 476 default: 477 putnext(q, mp); 478 479 return; 480 } 481 } 482 483 484 /* 485 * usb_ah_mctl_receive : 486 * Handle M_CTL messages from hid. If we don't understand 487 * the command, send it up. 488 */ 489 static void 490 usb_ah_mctl_receive(register queue_t *q, register mblk_t *mp) 491 { 492 register usb_ah_state_t *usb_ahd = (usb_ah_state_t *)q->q_ptr; 493 register struct iocblk *iocp; 494 caddr_t data; 495 496 iocp = (struct iocblk *)mp->b_rptr; 497 if (mp->b_cont != NULL) 498 data = (caddr_t)mp->b_cont->b_rptr; 499 500 switch (iocp->ioc_cmd) { 501 case HID_GET_PARSER_HANDLE: 502 USB_DPRINTF_L3(PRINT_MASK_ALL, usb_ah_log_handle, 503 "usb_ah_mctl_receive HID_GET_PARSER_HANDL mctl"); 504 if ((data != NULL) && 505 (iocp->ioc_count == sizeof (hidparser_handle_t)) && 506 ((mp->b_cont->b_wptr - mp->b_cont->b_rptr) == 507 iocp->ioc_count)) { 508 usb_ahd->usb_ah_report_descr = 509 *(hidparser_handle_t *)data; 510 } else { 511 usb_ahd->usb_ah_report_descr = NULL; 512 } 513 freemsg(mp); 514 usb_ahd->usb_ah_flags &= ~USB_AH_QWAIT; 515 516 break; 517 case HID_DISCONNECT_EVENT : 518 case HID_POWER_OFF: 519 USB_DPRINTF_L3(PRINT_MASK_ALL, usb_ah_log_handle, 520 "usb_ah_mctl_receive HID_DISCONNECT_EVENT/HID_POWER_OFF"); 521 522 /* Cancel any auto repeat keys */ 523 usb_ah_cancel_timeout(usb_ahd); 524 525 freemsg(mp); 526 527 break; 528 case HID_CONNECT_EVENT: 529 case HID_FULL_POWER: 530 USB_DPRINTF_L3(PRINT_MASK_ALL, usb_ah_log_handle, 531 "usb_ah_mctl_receive HID_CONNECT_EVENT/HID_FULL_POWER"); 532 freemsg(mp); 533 534 break; 535 default: 536 putnext(q, mp); 537 } 538 } 539 540 541 /* 542 * usb_ah_repeat_send 543 * This function sends a M_CTL message to usb_ac repeatedly 544 */ 545 static void 546 usb_ah_repeat_send(usb_ah_state_t *usb_ahd, usb_ah_button_descr_t *bd, 547 struct iocblk mctlmsg, char *buf, int len) 548 { 549 mblk_t *dup_mp; 550 551 bd->mblk = usba_mk_mctl(mctlmsg, buf, len); 552 553 if (bd->mblk != NULL) { 554 dup_mp = usb_ah_cp_mblk(bd->mblk); 555 556 if (dup_mp != NULL) { 557 mutex_exit(&usb_ahd->usb_ah_mutex); 558 putnext(usb_ahd->usb_ah_readq, dup_mp); 559 mutex_enter(&usb_ahd->usb_ah_mutex); 560 } 561 562 usb_ahd->usb_ah_cur_bd = bd; 563 usb_ahd->usb_ah_tid = qtimeout(usb_ahd->usb_ah_readq, 564 usb_ah_timeout, bd, usb_ah_rpt_tick); 565 } 566 } 567 568 569 /* 570 * usb_ah_timeout: 571 * Timeout routine to handle autorepeat of buttons 572 */ 573 static void 574 usb_ah_timeout(void *addr) 575 { 576 usb_ah_button_descr_t *bd; 577 usb_ah_state_t *usb_ahd; 578 mblk_t *dup_mp; 579 580 bd = (usb_ah_button_descr_t *)addr; 581 usb_ahd = (usb_ah_state_t *)bd->uahp; 582 583 mutex_enter(&usb_ahd->usb_ah_mutex); 584 USB_DPRINTF_L4(PRINT_MASK_ALL, usb_ah_log_handle, 585 "usb_ah_timeout: tid=0x%p", usb_ahd->usb_ah_tid); 586 587 /* 588 * If a release event still hasn't reached, tid will be non-zero 589 * Send another press event up 590 */ 591 if (usb_ahd->usb_ah_tid) { 592 dup_mp = usb_ah_cp_mblk(bd->mblk); 593 if (dup_mp != NULL) { 594 mutex_exit(&usb_ahd->usb_ah_mutex); 595 putnext(usb_ahd->usb_ah_readq, dup_mp); 596 mutex_enter(&usb_ahd->usb_ah_mutex); 597 } 598 if (bd->mblk != NULL) { 599 usb_ahd->usb_ah_cur_bd = bd; 600 usb_ahd->usb_ah_tid = qtimeout(usb_ahd->usb_ah_readq, 601 usb_ah_timeout, bd, usb_ah_rpt_tick); 602 } 603 } 604 mutex_exit(&usb_ahd->usb_ah_mutex); 605 } 606 607 608 /* 609 * usb_ah_cancel_timeout: 610 * Cancels the timeout for autorepeat sequence 611 */ 612 static void 613 usb_ah_cancel_timeout(usb_ah_state_t *usb_ahd) 614 { 615 queue_t *rq = usb_ahd->usb_ah_readq; 616 617 USB_DPRINTF_L4(PRINT_MASK_ALL, usb_ah_log_handle, 618 "usb_ah_cancel_timeout: tid=0x%p", usb_ahd->usb_ah_tid); 619 620 if (usb_ahd->usb_ah_tid) { 621 (void) quntimeout(rq, usb_ahd->usb_ah_tid); 622 usb_ahd->usb_ah_tid = 0; 623 usb_ahd->usb_ah_cur_bd->pressed = 0; 624 freemsg(usb_ahd->usb_ah_cur_bd->mblk); 625 usb_ahd->usb_ah_cur_bd = NULL; 626 } 627 } 628 629 630 /* 631 * usb_ah_cp_mblk 632 * Create an identical 2-mblk as the one passed through argument 633 */ 634 static mblk_t * 635 usb_ah_cp_mblk(mblk_t *mp) 636 { 637 mblk_t *bp1, *bp2; 638 int len; 639 struct iocblk *iocp; 640 641 if ((bp1 = allocb((int)sizeof (struct iocblk), BPRI_HI)) == NULL) { 642 USB_DPRINTF_L4(PRINT_MASK_ALL, usb_ah_log_handle, 643 "usb_ah_cp_mblk: 1st allocb failed"); 644 645 return (NULL); 646 } 647 648 iocp = (struct iocblk *)mp->b_rptr; 649 bcopy(iocp, (struct iocblk *)bp1->b_datap->db_base, 650 sizeof (struct iocblk)); 651 652 bp1->b_datap->db_type = M_CTL; 653 bp1->b_wptr += sizeof (struct iocblk); 654 655 ASSERT(mp->b_cont != NULL); 656 len = mp->b_cont->b_wptr - mp->b_cont->b_rptr; 657 658 if (mp->b_cont->b_datap->db_base) { 659 if ((bp2 = allocb(len, BPRI_HI)) == NULL) { 660 USB_DPRINTF_L4(PRINT_MASK_ALL, usb_ah_log_handle, 661 "usb_ah_cp_mblk: 2nd allocb failed"); 662 freemsg(bp1); 663 664 return (NULL); 665 } 666 bp1->b_cont = bp2; 667 bcopy(mp->b_cont->b_datap->db_base, bp2->b_datap->db_base, len); 668 bp2->b_wptr += len; 669 } 670 671 return (bp1); 672 } 673 674 675 /* 676 * usb_ah_get_cooked_rd: 677 * Cook the report descriptor by making hidparser calls and 678 * put them in a library 679 */ 680 static int 681 usb_ah_get_cooked_rd(usb_ah_state_t *usb_ahd) 682 { 683 uint_t location; 684 uint_t offset, i; 685 usb_ah_button_descr_t *bd; 686 hidparser_usage_info_t *ud; 687 usb_ah_rpt_t *rpt; 688 hidparser_rpt_t *hid_rpt; 689 690 rpt = &(usb_ahd->usb_ah_report[USB_AH_INPUT_RPT]); 691 hid_rpt = &(usb_ahd->usb_ah_report[USB_AH_INPUT_RPT].hid_rpt); 692 693 if (hidparser_get_usage_list_in_order( 694 usb_ahd->usb_ah_report_descr, 695 usb_ahd->usb_ah_report_id, 696 HIDPARSER_ITEM_INPUT, 697 hid_rpt) == HIDPARSER_FAILURE) { 698 USB_DPRINTF_L3(PRINT_MASK_OPEN, 699 usb_ah_log_handle, "getting usage list in order failed"); 700 701 return (USB_FAILURE); 702 } 703 704 USB_DPRINTF_L4(PRINT_MASK_OPEN, usb_ah_log_handle, 705 "usb_ah_open:no. of usages=%d", hid_rpt->no_of_usages); 706 707 location = offset = 0; 708 for (i = 0; i < hid_rpt->no_of_usages; i++) { 709 USB_DPRINTF_L4(PRINT_MASK_OPEN, 710 usb_ah_log_handle, "collection=0x%x, usage=0x%x/0x%x", 711 hid_rpt->usage_descr[i].collection_usage, 712 hid_rpt->usage_descr[i].usage_page, 713 hid_rpt->usage_descr[i].usage_id); 714 ud = &(hid_rpt->usage_descr[i]); 715 bd = &(rpt->button_descr[i]); 716 717 /* Initialize the variables */ 718 hid_rpt->main_item_value = 0; 719 720 /* get input items for each usages */ 721 (void) hidparser_get_main_item_data_descr( 722 usb_ahd->usb_ah_report_descr, 723 usb_ahd->usb_ah_report_id, 724 HIDPARSER_ITEM_INPUT, 725 hid_rpt->usage_descr[i].usage_page, 726 hid_rpt->usage_descr[i].usage_id, 727 &hid_rpt->main_item_value); 728 729 bd->location = location; 730 bd->offset = offset; 731 bd->no_of_bits = ud->rptsz; 732 733 USB_DPRINTF_L4(PRINT_MASK_ALL, usb_ah_log_handle, 734 "byte location %d, bit offset %d", bd->location, 735 bd->offset); 736 offset += ud->rptsz; 737 while (offset >= 8) { 738 location++; 739 offset -= 8; 740 } 741 742 } 743 744 return (USB_SUCCESS); 745 } 746 747 748 /* 749 * usb_ah_check_usage_send_data: 750 * Check if a button is pressed, if so, send the appropriate 751 * message up 752 */ 753 static void 754 usb_ah_check_usage_send_data(usb_ah_state_t *usb_ahd, mblk_t *mp) 755 { 756 int i, mask; 757 char val; 758 hidparser_rpt_t *hid_rpt; 759 usb_ah_button_descr_t *bd; 760 usb_ah_rpt_t *rpt; 761 uchar_t *ptr; 762 struct iocblk mctlmsg; 763 mblk_t *mctl_ptr; 764 765 mutex_enter(&usb_ahd->usb_ah_mutex); 766 rpt = &(usb_ahd->usb_ah_report[USB_AH_INPUT_RPT]); 767 hid_rpt = &(usb_ahd->usb_ah_report[USB_AH_INPUT_RPT].hid_rpt); 768 769 for (i = 0; i < hid_rpt->no_of_usages; i++) { 770 771 bd = &(rpt->button_descr[i]); 772 bd->uahp = (void *)usb_ahd; 773 774 USB_DPRINTF_L4(PRINT_MASK_ALL, 775 usb_ah_log_handle, "usb_ah_check_usage_send_data:" 776 "uses_report_id=%d, location=%d, offset=%d, " 777 "no_of_bits=%d", usb_ahd->usb_ah_uses_report_ids, 778 bd->location, bd->offset, bd->no_of_bits); 779 780 ptr = mp->b_rptr + bd->location; 781 782 /* XXX workaround */ 783 if (ptr > mp->b_wptr) { 784 USB_DPRINTF_L2(PRINT_MASK_ALL, 785 usb_ah_log_handle, "usb_ah_check_usage_send_data:" 786 "bad report: location=%d", bd->location); 787 788 continue; 789 } 790 791 ASSERT(ptr <= mp->b_wptr); 792 793 mask = ((1 << bd->no_of_bits) - 1); 794 val = (char)((*ptr >> bd->offset) & mask); 795 796 USB_DPRINTF_L4(PRINT_MASK_ALL, 797 usb_ah_log_handle, "usb_ah_check_usage_send_data:" 798 "usage=0x%x, " 799 "mask=0x%x, val=0x%x", hid_rpt->usage_descr[i].usage_id, 800 mask, val); 801 802 if (hid_rpt->usage_descr[i].collection_usage != 803 HID_CONSUMER_CONTROL) { 804 /* 805 * skip item in unknown collections, for now. 806 * this includes the volume and mute controls 807 * in the microphone collection on plantronics 808 * dsp-300 device with 3.xx firmware. 809 */ 810 continue; 811 } 812 813 switch (hid_rpt->usage_descr[i].usage_id) { 814 case HID_CONSUMER_VOL: /* LC */ 815 if (val != 0) { 816 if (hid_rpt->main_item_value & 817 HID_MAIN_ITEM_RELATIVE) { 818 /* Relative volume */ 819 mctlmsg.ioc_cmd = USB_AUDIO_VOL_CHANGE; 820 mctlmsg.ioc_count = sizeof (uint_t); 821 mctl_ptr = usba_mk_mctl(mctlmsg, 822 &val, mctlmsg.ioc_count); 823 if (mctl_ptr != NULL) { 824 mutex_exit(&usb_ahd-> 825 usb_ah_mutex); 826 putnext(usb_ahd->usb_ah_readq, 827 mctl_ptr); 828 mutex_enter(&usb_ahd-> 829 usb_ah_mutex); 830 } 831 } else { 832 USB_DPRINTF_L2(PRINT_MASK_ALL, 833 usb_ah_log_handle, "usb_ah_rput:" 834 "Absolute volume change " 835 "not supported"); 836 } 837 } 838 839 break; 840 case HID_CONSUMER_VOL_DECR: /* RTC */ 841 if (val != 0) { 842 val = -val; 843 } 844 /* FALLTHRU */ 845 case HID_CONSUMER_VOL_INCR: /* RTC */ 846 if (val != 0) { 847 848 /* 849 * If another autorepeating button has been 850 * pressed, cancel that one first 851 */ 852 usb_ah_cancel_timeout(usb_ahd); 853 mctlmsg.ioc_cmd = USB_AUDIO_VOL_CHANGE; 854 mctlmsg.ioc_count = sizeof (uint_t); 855 bd->pressed = 1; 856 usb_ah_repeat_send(usb_ahd, bd, 857 mctlmsg, (char *)&val, mctlmsg.ioc_count); 858 } else { 859 /* Do not steal other's release event */ 860 if (bd->pressed) { 861 usb_ah_cancel_timeout(usb_ahd); 862 } 863 } 864 865 break; 866 case HID_CONSUMER_MUTE: /* OOC */ 867 if (val) { 868 mctlmsg.ioc_cmd = USB_AUDIO_MUTE; 869 mctlmsg.ioc_count = sizeof (uint_t); 870 mctl_ptr = usba_mk_mctl(mctlmsg, 871 &val, mctlmsg.ioc_count); 872 if (mctl_ptr != NULL) { 873 mutex_exit(&usb_ahd->usb_ah_mutex); 874 putnext(usb_ahd->usb_ah_readq, 875 mctl_ptr); 876 mutex_enter(&usb_ahd->usb_ah_mutex); 877 } 878 879 } 880 881 break; 882 case HID_CONSUMER_BASS: 883 case HID_CONSUMER_TREBLE: 884 default: 885 886 break; 887 } 888 } 889 mutex_exit(&usb_ahd->usb_ah_mutex); 890 freemsg(mp); 891 } 892