xref: /illumos-gate/usr/src/uts/common/io/usb/clients/audio/usb_ah/usb_ah.c (revision 0bb073995ac5a95bd35f2dd790df1ea3d8c2d507)
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 
27 /*
28  * USB audio hid streams module - processes hid data
29  * from HID driver and converts to a format that SADA
30  * understands. The stack looks like this :
31  *	hid --> usb_ah --> usb_ac --> audio framework
32  * usb_ac just acts as a passthrough layer for the converted data.
33  *
34  * During open, usb_ah gets the parser handle from hid and gets
35  * the hardware information passed as report descriptor. Then
36  * it finds out the relevant usages and stores the bitmap and other
37  * information in internal data structure. When a button is pressed
38  * to. say, increase/decrease the volume, a report is generated and
39  * hid sends that data up through the streams. usb_ah, upon getting
40  * this information and with the prior knowledge about the bitmap
41  * for each button, calculates the value and sends up to SADA
42  * through usb_ac. SADA in turn sends a command down to speaker to
43  * increase the volume of the speaker that is managed by usb_ac.
44  */
45 #include <sys/usb/usba.h>
46 #include <sys/usb/clients/hid/hid.h>
47 #include <sys/usb/clients/hidparser/hidparser.h>
48 #include <sys/stropts.h>
49 #include <sys/strsun.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",
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 (MBLKL(mp) == usb_ahd->usb_ah_packet_size) {
441 
442 			/*
443 			 * Process this report if the device doesn't have
444 			 * multiple reports, or this is the one we support
445 			 */
446 			if ((usb_ahd->usb_ah_report_id ==
447 			    HID_REPORT_ID_UNDEFINED) ||
448 			    (usb_ahd->usb_ah_report_id == (int)*mp->b_rptr)) {
449 				/* we now have a complete packet */
450 				usb_ah_check_usage_send_data(usb_ahd, mp);
451 			} else {
452 				USB_DPRINTF_L2(PRINT_MASK_ALL,
453 				    usb_ah_log_handle,
454 				    "usb_ah_rput: skipping report with "
455 				    "id= %d", *mp->b_rptr);
456 
457 				/* skip the reports we don't support */
458 				freemsg(mp);
459 			}
460 		} else {
461 			/* filter out spurious packets */
462 			freemsg(mp);
463 		}
464 
465 		break;
466 	case M_CTL:
467 		usb_ah_mctl_receive(q, mp);
468 
469 		return;
470 	case M_IOCACK:
471 	case M_IOCNAK:
472 		putnext(q, mp);
473 
474 		return;
475 	default:
476 		putnext(q, mp);
477 
478 		return;
479 	}
480 }
481 
482 
483 /*
484  * usb_ah_mctl_receive :
485  *	Handle M_CTL messages from hid. If we don't understand
486  *	the command, send it up.
487  */
488 static void
489 usb_ah_mctl_receive(register queue_t *q, register mblk_t *mp)
490 {
491 	register usb_ah_state_t *usb_ahd = (usb_ah_state_t *)q->q_ptr;
492 	register struct iocblk *iocp;
493 	caddr_t  data;
494 
495 	iocp = (struct iocblk *)mp->b_rptr;
496 	if (mp->b_cont != NULL)
497 		data = (caddr_t)mp->b_cont->b_rptr;
498 
499 	switch (iocp->ioc_cmd) {
500 	case HID_GET_PARSER_HANDLE:
501 		USB_DPRINTF_L3(PRINT_MASK_ALL, usb_ah_log_handle,
502 		    "usb_ah_mctl_receive HID_GET_PARSER_HANDL mctl");
503 		if ((data != NULL) &&
504 		    (iocp->ioc_count == sizeof (hidparser_handle_t)) &&
505 		    (MBLKL(mp->b_cont) == iocp->ioc_count)) {
506 			usb_ahd->usb_ah_report_descr =
507 			    *(hidparser_handle_t *)data;
508 		} else {
509 			usb_ahd->usb_ah_report_descr = NULL;
510 		}
511 		freemsg(mp);
512 		usb_ahd->usb_ah_flags &= ~USB_AH_QWAIT;
513 
514 		break;
515 	case HID_DISCONNECT_EVENT :
516 	case HID_POWER_OFF:
517 		USB_DPRINTF_L3(PRINT_MASK_ALL, usb_ah_log_handle,
518 		    "usb_ah_mctl_receive HID_DISCONNECT_EVENT/HID_POWER_OFF");
519 
520 		/* Cancel any auto repeat keys */
521 		usb_ah_cancel_timeout(usb_ahd);
522 
523 		freemsg(mp);
524 
525 		break;
526 	case HID_CONNECT_EVENT:
527 	case HID_FULL_POWER:
528 		USB_DPRINTF_L3(PRINT_MASK_ALL, usb_ah_log_handle,
529 		    "usb_ah_mctl_receive HID_CONNECT_EVENT/HID_FULL_POWER");
530 		freemsg(mp);
531 
532 		break;
533 	default:
534 		putnext(q, mp);
535 	}
536 }
537 
538 
539 /*
540  * usb_ah_repeat_send
541  *	This function sends a M_CTL message to usb_ac repeatedly
542  */
543 static void
544 usb_ah_repeat_send(usb_ah_state_t *usb_ahd, usb_ah_button_descr_t *bd,
545 		struct iocblk mctlmsg, char *buf, int len)
546 {
547 	mblk_t	*dup_mp;
548 
549 	bd->mblk = usba_mk_mctl(mctlmsg, buf, len);
550 
551 	if (bd->mblk != NULL) {
552 		dup_mp = usb_ah_cp_mblk(bd->mblk);
553 
554 		if (dup_mp != NULL) {
555 			mutex_exit(&usb_ahd->usb_ah_mutex);
556 			putnext(usb_ahd->usb_ah_readq, dup_mp);
557 			mutex_enter(&usb_ahd->usb_ah_mutex);
558 		}
559 
560 		usb_ahd->usb_ah_cur_bd = bd;
561 		usb_ahd->usb_ah_tid = qtimeout(usb_ahd->usb_ah_readq,
562 		    usb_ah_timeout, bd, usb_ah_rpt_tick);
563 	}
564 }
565 
566 
567 /*
568  * usb_ah_timeout:
569  *	Timeout routine to handle autorepeat of buttons
570  */
571 static void
572 usb_ah_timeout(void *addr)
573 {
574 	usb_ah_button_descr_t *bd;
575 	usb_ah_state_t	*usb_ahd;
576 	mblk_t		*dup_mp;
577 
578 	bd = (usb_ah_button_descr_t *)addr;
579 	usb_ahd = (usb_ah_state_t *)bd->uahp;
580 
581 	mutex_enter(&usb_ahd->usb_ah_mutex);
582 	USB_DPRINTF_L4(PRINT_MASK_ALL, usb_ah_log_handle,
583 	    "usb_ah_timeout: tid=0x%p", usb_ahd->usb_ah_tid);
584 
585 	/*
586 	 * If a release event still hasn't reached, tid will be non-zero
587 	 * Send another press event up
588 	 */
589 	if (usb_ahd->usb_ah_tid) {
590 		dup_mp = usb_ah_cp_mblk(bd->mblk);
591 		if (dup_mp != NULL) {
592 			mutex_exit(&usb_ahd->usb_ah_mutex);
593 			putnext(usb_ahd->usb_ah_readq, dup_mp);
594 			mutex_enter(&usb_ahd->usb_ah_mutex);
595 		}
596 		if (bd->mblk != NULL) {
597 			usb_ahd->usb_ah_cur_bd = bd;
598 			usb_ahd->usb_ah_tid = qtimeout(usb_ahd->usb_ah_readq,
599 			    usb_ah_timeout, bd, usb_ah_rpt_tick);
600 		}
601 	}
602 	mutex_exit(&usb_ahd->usb_ah_mutex);
603 }
604 
605 
606 /*
607  * usb_ah_cancel_timeout:
608  *	Cancels the timeout for autorepeat sequence
609  */
610 static void
611 usb_ah_cancel_timeout(usb_ah_state_t *usb_ahd)
612 {
613 	queue_t	*rq = usb_ahd->usb_ah_readq;
614 
615 	USB_DPRINTF_L4(PRINT_MASK_ALL, usb_ah_log_handle,
616 	    "usb_ah_cancel_timeout: tid=0x%p", usb_ahd->usb_ah_tid);
617 
618 	if (usb_ahd->usb_ah_tid) {
619 		(void) quntimeout(rq, usb_ahd->usb_ah_tid);
620 		usb_ahd->usb_ah_tid = 0;
621 		usb_ahd->usb_ah_cur_bd->pressed = 0;
622 		freemsg(usb_ahd->usb_ah_cur_bd->mblk);
623 		usb_ahd->usb_ah_cur_bd = NULL;
624 	}
625 }
626 
627 
628 /*
629  * usb_ah_cp_mblk
630  *	Create an identical 2-mblk as the one passed through argument
631  */
632 static mblk_t *
633 usb_ah_cp_mblk(mblk_t *mp)
634 {
635 	mblk_t *bp1, *bp2;
636 	int len;
637 	struct iocblk	*iocp;
638 
639 	if ((bp1 = allocb((int)sizeof (struct iocblk), BPRI_HI)) == NULL) {
640 		USB_DPRINTF_L4(PRINT_MASK_ALL, usb_ah_log_handle,
641 		    "usb_ah_cp_mblk: 1st allocb failed");
642 
643 		return (NULL);
644 	}
645 
646 	iocp = (struct iocblk *)mp->b_rptr;
647 	bcopy(iocp, (struct iocblk *)bp1->b_datap->db_base,
648 	    sizeof (struct iocblk));
649 
650 	bp1->b_datap->db_type = M_CTL;
651 	bp1->b_wptr += sizeof (struct iocblk);
652 
653 	ASSERT(mp->b_cont != NULL);
654 	len = MBLKL(mp->b_cont);
655 
656 	if (mp->b_cont->b_datap->db_base) {
657 		if ((bp2 = allocb(len, BPRI_HI)) == NULL) {
658 			USB_DPRINTF_L4(PRINT_MASK_ALL, usb_ah_log_handle,
659 			    "usb_ah_cp_mblk: 2nd allocb failed");
660 			freemsg(bp1);
661 
662 			return (NULL);
663 		}
664 		bp1->b_cont = bp2;
665 		bcopy(mp->b_cont->b_datap->db_base, bp2->b_datap->db_base, len);
666 		bp2->b_wptr += len;
667 	}
668 
669 	return (bp1);
670 }
671 
672 
673 /*
674  * usb_ah_get_cooked_rd:
675  *	Cook the report descriptor by making hidparser calls and
676  *	put them in a library
677  */
678 static int
679 usb_ah_get_cooked_rd(usb_ah_state_t *usb_ahd)
680 {
681 	uint_t		location;
682 	uint_t		offset, i;
683 	usb_ah_button_descr_t	*bd;
684 	hidparser_usage_info_t	*ud;
685 	usb_ah_rpt_t	*rpt;
686 	hidparser_rpt_t	*hid_rpt;
687 
688 	rpt = &(usb_ahd->usb_ah_report[USB_AH_INPUT_RPT]);
689 	hid_rpt = &(usb_ahd->usb_ah_report[USB_AH_INPUT_RPT].hid_rpt);
690 
691 	if (hidparser_get_usage_list_in_order(
692 	    usb_ahd->usb_ah_report_descr,
693 	    usb_ahd->usb_ah_report_id,
694 	    HIDPARSER_ITEM_INPUT,
695 	    hid_rpt) == HIDPARSER_FAILURE) {
696 		USB_DPRINTF_L3(PRINT_MASK_OPEN,
697 		    usb_ah_log_handle, "getting usage list in order failed");
698 
699 		return (USB_FAILURE);
700 	}
701 
702 	USB_DPRINTF_L4(PRINT_MASK_OPEN, usb_ah_log_handle,
703 	    "usb_ah_open:no. of usages=%d", hid_rpt->no_of_usages);
704 
705 	location = offset = 0;
706 	for (i = 0; i < hid_rpt->no_of_usages; i++) {
707 		USB_DPRINTF_L4(PRINT_MASK_OPEN,
708 		    usb_ah_log_handle, "collection=0x%x, usage=0x%x/0x%x",
709 		    hid_rpt->usage_descr[i].collection_usage,
710 		    hid_rpt->usage_descr[i].usage_page,
711 		    hid_rpt->usage_descr[i].usage_id);
712 		ud = &(hid_rpt->usage_descr[i]);
713 		bd = &(rpt->button_descr[i]);
714 
715 		/* Initialize the variables */
716 		hid_rpt->main_item_value = 0;
717 
718 		/* get input items for each usages */
719 		(void) hidparser_get_main_item_data_descr(
720 		    usb_ahd->usb_ah_report_descr,
721 		    usb_ahd->usb_ah_report_id,
722 		    HIDPARSER_ITEM_INPUT,
723 		    hid_rpt->usage_descr[i].usage_page,
724 		    hid_rpt->usage_descr[i].usage_id,
725 		    &hid_rpt->main_item_value);
726 
727 		bd->location = location;
728 		bd->offset = offset;
729 		bd->no_of_bits = ud->rptsz;
730 
731 		USB_DPRINTF_L4(PRINT_MASK_ALL, usb_ah_log_handle,
732 		    "byte location %d, bit offset %d", bd->location,
733 		    bd->offset);
734 		offset += ud->rptsz;
735 		while (offset >= 8) {
736 			location++;
737 			offset -= 8;
738 		}
739 
740 	}
741 
742 	return (USB_SUCCESS);
743 }
744 
745 
746 /*
747  * usb_ah_check_usage_send_data:
748  *	Check if a button is pressed, if so, send the appropriate
749  *	message	up
750  */
751 static void
752 usb_ah_check_usage_send_data(usb_ah_state_t *usb_ahd, mblk_t *mp)
753 {
754 	int			i, mask;
755 	char			val;
756 	hidparser_rpt_t		*hid_rpt;
757 	usb_ah_button_descr_t	*bd;
758 	usb_ah_rpt_t		*rpt;
759 	uchar_t			*ptr;
760 	struct iocblk		mctlmsg;
761 	mblk_t			*mctl_ptr;
762 
763 	mutex_enter(&usb_ahd->usb_ah_mutex);
764 	rpt = &(usb_ahd->usb_ah_report[USB_AH_INPUT_RPT]);
765 	hid_rpt = &(usb_ahd->usb_ah_report[USB_AH_INPUT_RPT].hid_rpt);
766 
767 	for (i = 0; i < hid_rpt->no_of_usages; i++) {
768 
769 		bd = &(rpt->button_descr[i]);
770 		bd->uahp = (void *)usb_ahd;
771 
772 		USB_DPRINTF_L4(PRINT_MASK_ALL,
773 		    usb_ah_log_handle, "usb_ah_check_usage_send_data:"
774 		    "uses_report_id=%d, location=%d, offset=%d, "
775 		    "no_of_bits=%d", usb_ahd->usb_ah_uses_report_ids,
776 		    bd->location, bd->offset, bd->no_of_bits);
777 
778 		ptr = mp->b_rptr + bd->location;
779 
780 		/* XXX workaround */
781 		if (ptr > mp->b_wptr) {
782 			USB_DPRINTF_L2(PRINT_MASK_ALL,
783 			    usb_ah_log_handle, "usb_ah_check_usage_send_data:"
784 			    "bad report: location=%d", bd->location);
785 
786 			continue;
787 		}
788 
789 		ASSERT(ptr <= mp->b_wptr);
790 
791 		mask = ((1 << bd->no_of_bits) - 1);
792 		val = (char)((*ptr >> bd->offset) & mask);
793 
794 		USB_DPRINTF_L4(PRINT_MASK_ALL,
795 		    usb_ah_log_handle, "usb_ah_check_usage_send_data:"
796 		    "usage=0x%x, "
797 		    "mask=0x%x, val=0x%x", hid_rpt->usage_descr[i].usage_id,
798 		    mask, val);
799 
800 		if (hid_rpt->usage_descr[i].collection_usage !=
801 		    HID_CONSUMER_CONTROL) {
802 			/*
803 			 * skip item in unknown collections, for now.
804 			 * this includes the volume and mute controls
805 			 * in the microphone collection on plantronics
806 			 * dsp-300 device with 3.xx firmware.
807 			 */
808 			continue;
809 		}
810 
811 		switch (hid_rpt->usage_descr[i].usage_id) {
812 		case HID_CONSUMER_VOL:	/* LC */
813 			if (val != 0) {
814 				if (hid_rpt->main_item_value &
815 				    HID_MAIN_ITEM_RELATIVE) {
816 					/* Relative volume */
817 					mctlmsg.ioc_cmd = USB_AUDIO_VOL_CHANGE;
818 					mctlmsg.ioc_count = sizeof (uint_t);
819 					mctl_ptr = usba_mk_mctl(mctlmsg,
820 					    &val, mctlmsg.ioc_count);
821 					if (mctl_ptr != NULL) {
822 						mutex_exit(&usb_ahd->
823 						    usb_ah_mutex);
824 						putnext(usb_ahd->usb_ah_readq,
825 						    mctl_ptr);
826 						mutex_enter(&usb_ahd->
827 						    usb_ah_mutex);
828 					}
829 				} else {
830 					USB_DPRINTF_L2(PRINT_MASK_ALL,
831 					    usb_ah_log_handle, "usb_ah_rput:"
832 					    "Absolute volume change "
833 					    "not supported");
834 				}
835 			}
836 
837 			break;
838 		case HID_CONSUMER_VOL_DECR: /* RTC */
839 			if (val != 0) {
840 				val = -val;
841 			}
842 			/* FALLTHRU */
843 		case HID_CONSUMER_VOL_INCR:  /* RTC */
844 			if (val != 0) {
845 
846 				/*
847 				 * If another autorepeating button has been
848 				 * pressed, cancel that one first
849 				 */
850 				usb_ah_cancel_timeout(usb_ahd);
851 				mctlmsg.ioc_cmd = USB_AUDIO_VOL_CHANGE;
852 				mctlmsg.ioc_count = sizeof (uint_t);
853 				bd->pressed = 1;
854 				usb_ah_repeat_send(usb_ahd, bd,
855 				    mctlmsg, (char *)&val, mctlmsg.ioc_count);
856 			} else {
857 				/* Do not steal other's release event */
858 				if (bd->pressed) {
859 					usb_ah_cancel_timeout(usb_ahd);
860 				}
861 			}
862 
863 			break;
864 		case HID_CONSUMER_MUTE:	/* OOC */
865 			if (val) {
866 				mctlmsg.ioc_cmd = USB_AUDIO_MUTE;
867 				mctlmsg.ioc_count = sizeof (uint_t);
868 				mctl_ptr = usba_mk_mctl(mctlmsg,
869 				    &val, mctlmsg.ioc_count);
870 				if (mctl_ptr != NULL) {
871 					mutex_exit(&usb_ahd->usb_ah_mutex);
872 					putnext(usb_ahd->usb_ah_readq,
873 					    mctl_ptr);
874 					mutex_enter(&usb_ahd->usb_ah_mutex);
875 				}
876 
877 			}
878 
879 			break;
880 		case HID_CONSUMER_BASS:
881 		case HID_CONSUMER_TREBLE:
882 		default:
883 
884 			break;
885 		}
886 	}
887 	mutex_exit(&usb_ahd->usb_ah_mutex);
888 	freemsg(mp);
889 }
890