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