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