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