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