xref: /onnv-gate/usr/src/uts/common/io/usb/hwa/hwahc/hwahc_util.c (revision 11066:cebb50cbe4f9)
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 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * The Data Transfer Interface driver for Host Wire Adapter device
28  *
29  * This file mainly contains the entries for HCDI interfaces.
30  */
31 #include <sys/usb/usba/usba_impl.h> /* usba_get_dip */
32 #include <sys/usb/hwa/hwahc/hwahc.h>
33 #include <sys/usb/hwa/hwahc/hwahc_util.h>
34 #include <sys/strsubr.h>
35 #include <sys/strsun.h> /* MBLKL */
36 
37 #define	WUSB_GTK 1
38 #define	WUSB_PTK 2
39 
40 /* function prototypes */
41 static int hwahc_state_is_operational(hwahc_state_t *hwahcp);
42 static hwahc_state_t *hwahc_obtain_state(dev_info_t *dip);
43 static void hwahc_wait_for_xfer_completion(hwahc_state_t *hwahcp,
44 	hwahc_pipe_private_t *pp);
45 static void hwahc_traverse_requests(hwahc_state_t *hwahcp,
46 	hwahc_pipe_private_t *pp);
47 static void hwahc_pipe_cleanup(hwahc_state_t *hwahcp,
48 	usba_pipe_handle_data_t *ph);
49 int hwahc_set_dev_encrypt(usb_pipe_handle_t ph, uint8_t ifc,
50 	usb_port_t index, wusb_secrt_data_t *secrt_data, uint8_t type);
51 
52 static int hwahc_hcdi_pm_support(dev_info_t *dip);
53 static int hwahc_hcdi_pipe_open(usba_pipe_handle_data_t *ph,
54 	usb_flags_t flags);
55 static int hwahc_hcdi_pipe_close(usba_pipe_handle_data_t *ph,
56 	usb_flags_t flags);
57 static int hwahc_hcdi_pipe_reset(usba_pipe_handle_data_t *ph,
58 	usb_flags_t flags);
59 static void hwahc_hcdi_pipe_reset_data_toggle(usba_pipe_handle_data_t *ph);
60 static int hwahc_hcdi_pipe_ctrl_xfer(usba_pipe_handle_data_t *ph,
61 	usb_ctrl_req_t *ctrl_reqp, usb_flags_t usb_flags);
62 static int hwahc_hcdi_pipe_bulk_xfer(usba_pipe_handle_data_t *ph,
63 	usb_bulk_req_t *bulk_reqp, usb_flags_t usb_flags);
64 static int hwahc_hcdi_pipe_intr_xfer(usba_pipe_handle_data_t *ph,
65 	usb_intr_req_t *intr_reqp, usb_flags_t usb_flags);
66 static int hwahc_hcdi_pipe_isoc_xfer(usba_pipe_handle_data_t *ph,
67 	usb_isoc_req_t *isoc_reqp, usb_flags_t usb_flags);
68 static int hwahc_hcdi_bulk_transfer_size(usba_device_t *usba_device,
69 	size_t *size);
70 static int hwahc_hcdi_pipe_stop_intr_polling(usba_pipe_handle_data_t *ph,
71 	usb_flags_t flags);
72 static int hwahc_hcdi_pipe_stop_isoc_polling(usba_pipe_handle_data_t *ph,
73 	usb_flags_t flags);
74 static int hwahc_hcdi_get_current_frame_number(usba_device_t *usba_device,
75 	usb_frame_number_t *frame_number);
76 static int hwahc_hcdi_get_max_isoc_pkts(usba_device_t *usba_device,
77 	uint_t *max_pkts);
78 static int hwahc_hcdi_polled_input_init(usba_pipe_handle_data_t *ph,
79 	uchar_t **polled_buf, usb_console_info_impl_t *console_input_info);
80 static int hwahc_hcdi_polled_input_fini(usb_console_info_impl_t *info);
81 static int hwahc_hcdi_polled_input_enter(usb_console_info_impl_t *info);
82 static int hwahc_hcdi_polled_input_exit(usb_console_info_impl_t *info);
83 static int hwahc_hcdi_polled_read(usb_console_info_impl_t *info,
84 	uint_t *num_characters);
85 usba_hcdi_ops_t *hwahc_alloc_hcdi_ops(hwahc_state_t *hwahcp);
86 
87 extern void *hwahc_statep;
88 
89 /* Check the Host controller state and return proper values */
90 static int
hwahc_state_is_operational(hwahc_state_t * hwahcp)91 hwahc_state_is_operational(hwahc_state_t *hwahcp)
92 {
93 	int	rval;
94 
95 	ASSERT(mutex_owned(&hwahcp->hwahc_mutex));
96 
97 	if (hwahcp->hwahc_dev_state != USB_DEV_ONLINE) {
98 
99 		return (USB_FAILURE);
100 	}
101 
102 	switch (hwahcp->hwahc_hc_soft_state) {
103 	case HWAHC_CTRL_INIT_STATE:
104 		rval = USB_FAILURE;
105 		break;
106 	case HWAHC_CTRL_OPERATIONAL_STATE:
107 		/* still need to check if channel is operational */
108 		if (hwahcp->hwahc_hw_state != HWAHC_HW_STARTED) {
109 			rval = USB_FAILURE;
110 		} else {
111 			rval = USB_SUCCESS;
112 		}
113 
114 		break;
115 	case HWAHC_CTRL_ERROR_STATE:
116 		rval = USB_HC_HARDWARE_ERROR;
117 		break;
118 	default:
119 		rval = USB_FAILURE;
120 		break;
121 	}
122 
123 	return (rval);
124 }
125 
126 /* get soft state pointer */
127 hwahc_state_t *
hwahc_obtain_state(dev_info_t * dip)128 hwahc_obtain_state(dev_info_t *dip)
129 {
130 	int instance = ddi_get_instance(dip);
131 
132 	hwahc_state_t *hwahcp = ddi_get_soft_state(hwahc_statep, instance);
133 
134 	ASSERT(hwahcp != NULL);
135 
136 	return (hwahcp);
137 }
138 
139 
140 /*
141  * Do not support wusb bus PM now
142  */
143 /* ARGSUSED */
144 static int
hwahc_hcdi_pm_support(dev_info_t * dip)145 hwahc_hcdi_pm_support(dev_info_t *dip)
146 {
147 	return (USB_FAILURE);
148 }
149 
150 static void
151 /* ARGSUSED */
hwahc_hcdi_pipe_reset_data_toggle(usba_pipe_handle_data_t * ph)152 hwahc_hcdi_pipe_reset_data_toggle(usba_pipe_handle_data_t *ph)
153 {
154 	/* don't do anything now */
155 }
156 
157 /* Wait for processing all completed transfers and to send results */
158 static void
hwahc_wait_for_xfer_completion(hwahc_state_t * hwahcp,hwahc_pipe_private_t * pp)159 hwahc_wait_for_xfer_completion(hwahc_state_t *hwahcp, hwahc_pipe_private_t *pp)
160 {
161 	wusb_wa_rpipe_hdl_t	*hdl = pp->pp_rp;
162 
163 	mutex_enter(&hdl->rp_mutex);
164 	if (hdl->rp_state != WA_RPIPE_STATE_ACTIVE) {
165 		mutex_exit(&hdl->rp_mutex);
166 
167 		return;
168 	}
169 	mutex_exit(&hdl->rp_mutex);
170 
171 	/* wait 3s */
172 	(void) cv_reltimedwait(&pp->pp_xfer_cmpl_cv, &hwahcp->hwahc_mutex,
173 	    drv_usectohz(3000000), TR_CLOCK_TICK);
174 
175 	mutex_enter(&hdl->rp_mutex);
176 	if (hdl->rp_state == WA_RPIPE_STATE_ACTIVE) {
177 		USB_DPRINTF_L2(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
178 		    "hwahc_wait_for_xfer_completion: no transfer completion "
179 		    "confirmation received");
180 	}
181 	mutex_exit(&hdl->rp_mutex);
182 }
183 
184 /* remove all the unprocessed requests and do callback */
185 /* ARGSUSED */
186 static void
hwahc_traverse_requests(hwahc_state_t * hwahcp,hwahc_pipe_private_t * pp)187 hwahc_traverse_requests(hwahc_state_t *hwahcp, hwahc_pipe_private_t *pp)
188 {
189 	wusb_wa_rpipe_hdl_t	*hdl = pp->pp_rp;
190 	wusb_wa_trans_wrapper_t	*wr;
191 
192 	mutex_enter(&hdl->rp_mutex);
193 
194 	USB_DPRINTF_L4(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
195 	    "hwahc_traverse_requests: pp = 0x%p, wr=%p", (void*)pp,
196 	    (void *)hdl->rp_curr_wr);
197 
198 	wr = hdl->rp_curr_wr;
199 	if (wr != NULL) {
200 		wusb_wa_stop_xfer_timer(wr);
201 		hdl->rp_state = WA_RPIPE_STATE_IDLE;
202 		hdl->rp_curr_wr = NULL;
203 		wr->wr_state = WR_ABORTED;
204 		mutex_exit(&hdl->rp_mutex);
205 
206 		mutex_exit(&hwahcp->hwahc_mutex);
207 
208 		/*
209 		 * This CR is to tell USBA to mark this pipe as IDLE,
210 		 * so that do not queue client requests at USBA. Requests
211 		 * sent after pipe close/reset will be handled by hwahc.
212 		 */
213 		wr->wr_cb(wr->wr_wa_data, wr, USB_CR_NOT_SUPPORTED, 0);
214 
215 		mutex_enter(&hwahcp->hwahc_mutex);
216 		mutex_enter(&hdl->rp_mutex);
217 	}
218 	mutex_exit(&hdl->rp_mutex);
219 }
220 
221 /* process periodic(INTR/ISOC) requests */
222 static void
hwahc_do_client_periodic_in_req_callback(hwahc_state_t * hwahcp,hwahc_pipe_private_t * pp,usb_cr_t completion_reason)223 hwahc_do_client_periodic_in_req_callback(hwahc_state_t *hwahcp,
224 	hwahc_pipe_private_t *pp, usb_cr_t completion_reason)
225 {
226 	usb_ep_descr_t	*eptd;
227 
228 	USB_DPRINTF_L4(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
229 	    "hwahc_do_client_periodic_in_req_callback: enter");
230 
231 	/*
232 	 * Check for Interrupt/Isochronous IN, whether we need to do
233 	 * callback for the original client's periodic IN request.
234 	 */
235 	eptd = &(pp->pp_pipe_handle->p_ep);
236 	if (pp->pp_client_periodic_in_reqp) {
237 		if (WUSB_ISOC_ENDPOINT(eptd)) {
238 			/* not supported */
239 			USB_DPRINTF_L4(PRINT_MASK_HCDI,
240 			    hwahcp->hwahc_log_handle,
241 			    "hwahc_do_client_periodic_in_req_callback: "
242 			    "ISOC xfer not support");
243 		} else {
244 			/*
245 			 * NULL wr to tell the function that we're done and
246 			 * should clear pipe's pp_client_periodic_in_reqp
247 			 */
248 			wusb_wa_callback(&hwahcp->hwahc_wa_data,
249 			    pp->pp_pipe_handle, NULL, completion_reason);
250 		}
251 	}
252 
253 	USB_DPRINTF_L4(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
254 	    "hwahc_do_client_periodic_in_req_callback: end");
255 }
256 
257 /*
258  * clean up the pipe, called by pipe_close/pipe_reset
259  *	- Abort RPipe operation
260  *	- Clean pending requests queueing on this pipe
261  */
262 static void
hwahc_pipe_cleanup(hwahc_state_t * hwahcp,usba_pipe_handle_data_t * ph)263 hwahc_pipe_cleanup(hwahc_state_t *hwahcp, usba_pipe_handle_data_t *ph)
264 {
265 	hwahc_pipe_private_t	*pp;
266 	wusb_wa_rpipe_hdl_t	*hdl;
267 	int			rval;
268 	usb_ep_descr_t		*eptd;
269 	usb_cr_t		completion_reason;
270 
271 	pp = (hwahc_pipe_private_t *)ph->p_hcd_private;
272 
273 	USB_DPRINTF_L4(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
274 	    "hwahc_pipe_cleanup: ph = 0x%p, p_req_cnt, ep=0x%02x,"
275 	    " state=%d", (void *) ph, ph->p_ep.bEndpointAddress,
276 	    pp->pp_state);
277 
278 	ASSERT(mutex_owned(&hwahcp->hwahc_mutex));
279 	ASSERT(!servicing_interrupt());
280 
281 	hdl = pp->pp_rp;
282 
283 	if (hwahcp->hwahc_dev_state == USB_DEV_ONLINE) {
284 		/* abort rpipe */
285 		mutex_enter(&hdl->rp_mutex);
286 
287 		/* if active, abort the requests */
288 		if (hdl->rp_state == WA_RPIPE_STATE_ACTIVE) {
289 			mutex_exit(&hdl->rp_mutex);
290 			mutex_exit(&hwahcp->hwahc_mutex);
291 			rval = wusb_wa_rpipe_abort(hwahcp->hwahc_dip,
292 			    hwahcp->hwahc_default_pipe, hdl);
293 			mutex_enter(&hwahcp->hwahc_mutex);
294 			mutex_enter(&hdl->rp_mutex);
295 		}
296 		mutex_exit(&hdl->rp_mutex);
297 
298 		/* wait for transfers to complete */
299 		hwahc_wait_for_xfer_completion(hwahcp, pp);
300 	}
301 
302 	/* remove all unprocessed requests on this pipe and do callback */
303 	hwahc_traverse_requests(hwahcp, pp);
304 
305 	switch (pp->pp_state) {
306 	case HWAHC_PIPE_STATE_CLOSE:
307 		completion_reason = USB_CR_PIPE_CLOSING;
308 
309 		mutex_exit(&hwahcp->hwahc_mutex);
310 		(void) wusb_wa_rpipe_reset(hwahcp->hwahc_dip, ph, hdl, 0);
311 		mutex_enter(&hwahcp->hwahc_mutex);
312 
313 		break;
314 	case HWAHC_PIPE_STATE_RESET:
315 	case HWAHC_PIPE_STATE_ERROR:
316 		completion_reason = USB_CR_PIPE_RESET;
317 		if (hwahcp->hwahc_dev_state == USB_DEV_ONLINE) {
318 			mutex_exit(&hwahcp->hwahc_mutex);
319 			/*
320 			 * reset WA's RPipe.
321 			 * If this pipe is not bound to the default endpoint,
322 			 * also send a clear_feature request to that ep.
323 			 */
324 			rval = wusb_wa_rpipe_reset(hwahcp->hwahc_dip,
325 			    ph, hdl, 1);
326 			mutex_enter(&hwahcp->hwahc_mutex);
327 
328 			USB_DPRINTF_L4(PRINT_MASK_HCDI,
329 			    hwahcp->hwahc_log_handle,
330 			    "hwahc_pipe_cleanup: rp reset, rv=%d",
331 			    rval);
332 
333 			pp->pp_state = HWAHC_PIPE_STATE_IDLE;
334 		}
335 
336 		break;
337 	case HWAHC_PIPE_STATE_STOP_POLLING:
338 		completion_reason = USB_CR_STOPPED_POLLING;
339 		pp->pp_state = HWAHC_PIPE_STATE_IDLE;
340 
341 		break;
342 	}
343 
344 	/*
345 	 * Do the callback for the original client
346 	 * periodic IN request.
347 	 */
348 	eptd = &ph->p_ep;
349 
350 	USB_DPRINTF_L4(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
351 	    "hwahc_pipe_cleanup: end");
352 
353 	if ((WUSB_PERIODIC_ENDPOINT(eptd)) &&
354 	    ((ph->p_ep.bEndpointAddress & USB_EP_DIR_MASK) ==
355 	    USB_EP_DIR_IN)) {
356 		mutex_exit(&hwahcp->hwahc_mutex);
357 
358 		hwahc_do_client_periodic_in_req_callback(
359 		    hwahcp, pp, completion_reason);
360 
361 		mutex_enter(&hwahcp->hwahc_mutex);
362 	}
363 }
364 
365 /*
366  * set the pipe's parent device information
367  */
368 static int
hwahc_set_pipe_dev_info(hwahc_state_t * hwahcp,usba_pipe_handle_data_t * ph,hwahc_pipe_private_t * pp)369 hwahc_set_pipe_dev_info(hwahc_state_t *hwahcp,
370     usba_pipe_handle_data_t *ph, hwahc_pipe_private_t *pp)
371 {
372 	dev_info_t *dip = NULL;
373 	wusb_hc_data_t *hc_data;
374 	int i;
375 
376 	dip = usba_get_dip((usb_pipe_handle_t)ph->p_ph_impl);
377 	if (dip == NULL) {
378 
379 		return (USB_FAILURE);
380 	}
381 
382 	hc_data = &hwahcp->hwahc_hc_data;
383 
384 	mutex_enter(&hc_data->hc_mutex);
385 	for (i = 1; i <= hc_data->hc_num_ports; i++) {
386 		if ((dip == hc_data->hc_children_dips[i])) {
387 			pp->pp_wdev = hc_data->hc_dev_infos[i];
388 
389 			USB_DPRINTF_L3(DPRINT_MASK_HCDI,
390 			    hwahcp->hwahc_log_handle,
391 			    "hwahc_set_pipe_dev_info: pp(%p) device(%p) set",
392 			    (void *) pp, (void *) pp->pp_wdev);
393 
394 			break;
395 		}
396 	}
397 
398 	mutex_exit(&hc_data->hc_mutex);
399 
400 	if (pp->pp_wdev) {
401 		return (USB_SUCCESS);
402 	} else {
403 		return (USB_FAILURE);
404 	}
405 }
406 
407 /*
408  * HWA HCDI entry points
409  *
410  * The Host Controller Driver Interfaces (HCDI) are the software interfaces
411  * between the Universal Serial Bus Layer (USBA) and the Host Controller
412  * Driver (HCD). The HCDI interfaces or entry points are subject to change.
413  */
414 
415 /*
416  * hwahc_hcdi_pipe_open:
417  * Member of HCD Ops structure and called during client specific pipe open.
418  * Assign rpipe for wireless transaction to work.
419  * The rpipe is assigned to an endpoint until the endpoint is closed.
420  */
421 static int
hwahc_hcdi_pipe_open(usba_pipe_handle_data_t * ph,usb_flags_t flags)422 hwahc_hcdi_pipe_open(
423 	usba_pipe_handle_data_t	*ph,
424 	usb_flags_t		flags)
425 {
426 	int			rval;
427 	hwahc_state_t		*hwahcp;
428 	int			kmflag;
429 	hwahc_pipe_private_t	*pp;
430 	usb_ep_descr_t		*epdt = &ph->p_ep;
431 	uint8_t			type;
432 	wusb_wa_data_t		*wa;
433 
434 	hwahcp = hwahc_obtain_state(ph->p_usba_device->usb_root_hub_dip);
435 	wa = &hwahcp->hwahc_wa_data;
436 
437 	USB_DPRINTF_L4(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
438 	    "hwahc_hcdi_pipe_open: hwahc=0x%p, ph=0x%p,"
439 	    " addr = 0x%x, ep=0x%02X", (void *) hwahcp, (void *) ph,
440 	    ph->p_usba_device->usb_addr, epdt->bEndpointAddress);
441 
442 	kmflag = (flags & USB_FLAGS_SLEEP) ? KM_SLEEP : KM_NOSLEEP;
443 
444 	if (ph->p_hcd_private) {
445 		USB_DPRINTF_L2(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
446 		    "hwahc_hcdi_pipe_open: Pipe is already opened");
447 
448 		return (USB_FAILURE);
449 	}
450 
451 	pp = kmem_zalloc(sizeof (hwahc_pipe_private_t), kmflag);
452 	if (pp == NULL) {
453 		USB_DPRINTF_L2(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
454 		    "hwahc_hcdi_pipe_open: alloc pp failed");
455 
456 		return (USB_NO_RESOURCES);
457 	}
458 
459 	mutex_enter(&hwahcp->hwahc_mutex);
460 
461 	if (hwahc_set_pipe_dev_info(hwahcp, ph, pp) < 0) {
462 		USB_DPRINTF_L2(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
463 		    "hwahc_hcdi_pipe_open: set pipe dev_info failed");
464 		mutex_exit(&hwahcp->hwahc_mutex);
465 
466 		return (USB_FAILURE);
467 	}
468 
469 	rval = hwahc_state_is_operational(hwahcp);
470 	if (rval != USB_SUCCESS) {
471 		USB_DPRINTF_L2(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
472 		    "hwahc_hcdi_pipe_open: state error: %d", rval);
473 		kmem_free(pp, sizeof (hwahc_pipe_private_t));
474 		mutex_exit(&hwahcp->hwahc_mutex);
475 
476 		return (rval);
477 	}
478 
479 	/* assign rpipe to the endpoint */
480 	type = epdt->bmAttributes & USB_EP_ATTR_MASK;
481 	rval = wusb_wa_get_rpipe(&hwahcp->hwahc_wa_data,
482 	    hwahcp->hwahc_default_pipe, type, &pp->pp_rp,
483 	    PRINT_MASK_HCDI, hwahcp->hwahc_log_handle);
484 	if (rval != USB_SUCCESS) {
485 		USB_DPRINTF_L2(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
486 		    "hwahc_hcdi_pipe_open: getting rpipe failed");
487 		kmem_free(pp, sizeof (hwahc_pipe_private_t));
488 		mutex_exit(&hwahcp->hwahc_mutex);
489 
490 		return (USB_NO_RESOURCES);
491 	}
492 
493 	mutex_exit(&hwahcp->hwahc_mutex);
494 	/* target the rpipe to the endpoint */
495 	rval = wusb_wa_set_rpipe_target(hwahcp->hwahc_dip, wa,
496 	    hwahcp->hwahc_default_pipe, ph, pp->pp_rp);
497 	mutex_enter(&hwahcp->hwahc_mutex);
498 
499 	if (rval != USB_SUCCESS) {
500 		USB_DPRINTF_L2(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
501 		    "hwahc_hcdi_pipe_open: set target for rpipe failed");
502 		(void) wusb_wa_release_rpipe(wa, pp->pp_rp);
503 		kmem_free(pp, sizeof (hwahc_pipe_private_t));
504 		mutex_exit(&hwahcp->hwahc_mutex);
505 
506 		return (USB_FAILURE);
507 	}
508 
509 	pp->pp_pipe_handle = ph;
510 	cv_init(&pp->pp_xfer_cmpl_cv, NULL, CV_DRIVER, NULL);
511 
512 	mutex_enter(&ph->p_mutex);
513 	ph->p_hcd_private = (usb_opaque_t)pp;
514 	bcopy(&ph->p_policy, &pp->pp_policy, sizeof (usb_pipe_policy_t));
515 	mutex_exit(&ph->p_mutex);
516 
517 	pp->pp_state = HWAHC_PIPE_STATE_IDLE;
518 	hwahcp->hwahc_open_pipe_count++;
519 	mutex_exit(&hwahcp->hwahc_mutex);
520 
521 	return (USB_SUCCESS);
522 }
523 
524 
525 /*
526  * hwahc_hcdi_pipe_close:
527  * Member of HCD Ops structure and called during the client specific pipe
528  * close.
529  * Remove unprocessed transfers from the pipe and free rpipe resource.
530  */
531 /* ARGSUSED */
532 static int
hwahc_hcdi_pipe_close(usba_pipe_handle_data_t * ph,usb_flags_t flags)533 hwahc_hcdi_pipe_close(
534 	usba_pipe_handle_data_t	*ph,
535 	usb_flags_t		flags)
536 {
537 	hwahc_state_t		*hwahcp;
538 	hwahc_pipe_private_t	*pp;
539 	usb_ep_descr_t		*epdt = &ph->p_ep;
540 
541 	hwahcp = hwahc_obtain_state(ph->p_usba_device->usb_root_hub_dip);
542 
543 	USB_DPRINTF_L4(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
544 	    "hwahc_hcdi_pipe_close:ph=0x%p addr = 0x%x, ep = 0x%x",
545 	    (void *) ph, ph->p_usba_device->usb_addr,
546 	    epdt->bEndpointAddress);
547 
548 	ASSERT(ph->p_hcd_private != NULL);
549 	pp = (hwahc_pipe_private_t *)ph->p_hcd_private;
550 
551 	mutex_enter(&hwahcp->hwahc_mutex);
552 
553 	pp->pp_state = HWAHC_PIPE_STATE_CLOSE;
554 
555 	hwahc_pipe_cleanup(hwahcp, ph);
556 
557 	mutex_exit(&hwahcp->hwahc_mutex);
558 
559 	wusb_wa_clear_dev_ep(ph); /* clear the remote dev's endpoint */
560 	mutex_enter(&hwahcp->hwahc_mutex);
561 
562 	(void) wusb_wa_release_rpipe(&hwahcp->hwahc_wa_data, pp->pp_rp);
563 
564 	mutex_enter(&ph->p_mutex);
565 	cv_destroy(&pp->pp_xfer_cmpl_cv);
566 	kmem_free(pp, sizeof (hwahc_pipe_private_t));
567 	ph->p_hcd_private = NULL;
568 	mutex_exit(&ph->p_mutex);
569 	hwahcp->hwahc_open_pipe_count--;
570 	mutex_exit(&hwahcp->hwahc_mutex);
571 
572 	USB_DPRINTF_L4(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
573 	    "hwahc_hcdi_pipe_close: end");
574 
575 	return (USB_SUCCESS);
576 }
577 
578 
579 /*
580  * hwahc_hcdi_pipe_reset:
581  *	- clean up this pipe and change its state
582  */
583 /* ARGSUSED */
584 static int
hwahc_hcdi_pipe_reset(usba_pipe_handle_data_t * ph,usb_flags_t flags)585 hwahc_hcdi_pipe_reset(
586 	usba_pipe_handle_data_t	*ph,
587 	usb_flags_t		flags)
588 {
589 	hwahc_state_t		*hwahcp;
590 	hwahc_pipe_private_t	*pp;
591 
592 	hwahcp = hwahc_obtain_state(ph->p_usba_device->usb_root_hub_dip);
593 
594 	USB_DPRINTF_L4(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
595 	    "hwahc_hcdi_pipe_reset: ph = 0x%p, ep=0x%02x",
596 	    (void *) ph, ph->p_ep.bEndpointAddress);
597 
598 	ASSERT(ph->p_hcd_private != NULL);
599 	pp = (hwahc_pipe_private_t *)ph->p_hcd_private;
600 
601 	mutex_enter(&hwahcp->hwahc_mutex);
602 	pp->pp_state = HWAHC_PIPE_STATE_RESET;
603 	hwahc_pipe_cleanup(hwahcp, ph);
604 	mutex_exit(&hwahcp->hwahc_mutex);
605 
606 	USB_DPRINTF_L4(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
607 	    "hwahc_hcdi_pipe_reset: end");
608 
609 	return (USB_SUCCESS);
610 }
611 
612 
613 /*
614  * hwahc_hcdi_pipe_ctrl_xfer:
615  *	- usba_hcdi_pipe_ctrl_xfer entry
616  *	- check pipe state
617  *	- call wa_xfer to do this request
618  */
619 static int
hwahc_hcdi_pipe_ctrl_xfer(usba_pipe_handle_data_t * ph,usb_ctrl_req_t * ctrl_reqp,usb_flags_t usb_flags)620 hwahc_hcdi_pipe_ctrl_xfer(
621 	usba_pipe_handle_data_t	*ph,
622 	usb_ctrl_req_t		*ctrl_reqp,
623 	usb_flags_t		usb_flags)
624 {
625 	hwahc_state_t		*hwahcp;
626 	hwahc_pipe_private_t	*pp;
627 	int			rval;
628 	uint8_t			ep_addr = ph->p_ep.bEndpointAddress;
629 
630 	hwahcp = hwahc_obtain_state(ph->p_usba_device->usb_root_hub_dip);
631 
632 	USB_DPRINTF_L4(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
633 	    "hwahc_hcdi_pipe_ctrl_xfer: hwahcp=0x%p ph = 0x%p"
634 	    " reqp = 0x%p flags = %x", (void *) hwahcp, (void *) ph,
635 	    (void *) ctrl_reqp, usb_flags);
636 
637 	ASSERT(ph->p_hcd_private != NULL);
638 	pp = (hwahc_pipe_private_t *)ph->p_hcd_private;
639 
640 	mutex_enter(&hwahcp->hwahc_mutex);
641 	rval = hwahc_state_is_operational(hwahcp);
642 	if (rval != USB_SUCCESS) {
643 		mutex_exit(&hwahcp->hwahc_mutex);
644 
645 		return (rval);
646 	}
647 
648 	/*
649 	 * if doing ctrl transfer on non-zero pipe and its state is error
650 	 * The default endpoint is critical for any other operations.
651 	 * We should not depend on upper layer to reset it.
652 	 */
653 	if ((pp->pp_state == HWAHC_PIPE_STATE_ERROR)) {
654 		USB_DPRINTF_L2(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
655 		    "hwahc_hcdi_pipe_ctrl_xfer: Pipe(%d) is in error"
656 		    " state, need pipe reset to continue", ep_addr);
657 
658 		if (ep_addr == 0) {
659 			/*
660 			 * some error with the RPipe of EP 0,
661 			 * we need to reset this RPipe by ourself
662 			 */
663 			mutex_exit(&hwahcp->hwahc_mutex);
664 			(void) wusb_wa_rpipe_reset(hwahcp->hwahc_dip, ph,
665 			    pp->pp_rp, 1);
666 			mutex_enter(&hwahcp->hwahc_mutex);
667 			pp->pp_state = 0;
668 		} else {
669 		/* client driver should clear non-default endpoint's state */
670 			mutex_exit(&hwahcp->hwahc_mutex);
671 
672 			return (USB_FAILURE);
673 		}
674 	} else if ((pp->pp_state != HWAHC_PIPE_STATE_IDLE) &&
675 	    (pp->pp_state != HWAHC_PIPE_STATE_ERROR)) {
676 			mutex_exit(&hwahcp->hwahc_mutex);
677 
678 			return (USB_PIPE_ERROR);
679 	}
680 
681 	mutex_exit(&hwahcp->hwahc_mutex);
682 
683 	rval = wusb_wa_ctrl_xfer(&hwahcp->hwahc_wa_data, pp->pp_rp, ph,
684 	    ctrl_reqp, usb_flags);
685 	if (rval != USB_SUCCESS) {
686 		USB_DPRINTF_L2(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
687 		    "hwahc_hcdi_pipe_ctrl_xfer failed, rval = %d", rval);
688 	}
689 
690 
691 	return (rval);
692 }
693 
694 
695 /*
696  * hwahc_hcdi_pipe_bulk_xfer:
697  *	- usba_hcid_pipe_bulk_xfer entry
698  *	- check the target pipe status first
699  *	- process this request
700  */
701 static int
hwahc_hcdi_pipe_bulk_xfer(usba_pipe_handle_data_t * ph,usb_bulk_req_t * bulk_reqp,usb_flags_t usb_flags)702 hwahc_hcdi_pipe_bulk_xfer(
703 	usba_pipe_handle_data_t	*ph,
704 	usb_bulk_req_t		*bulk_reqp,
705 	usb_flags_t		usb_flags)
706 {
707 	hwahc_state_t		*hwahcp;
708 	hwahc_pipe_private_t	*pp;
709 	int			rval;
710 
711 	hwahcp = hwahc_obtain_state(ph->p_usba_device->usb_root_hub_dip);
712 
713 	USB_DPRINTF_L4(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
714 	    "hwahc_hcdi_pipe_bulk_xfer: hwahcp=0x%p ph = 0x%p reqp = 0x%p"
715 	    " flags = %x", (void *) hwahcp, (void *) ph,
716 	    (void *) bulk_reqp, usb_flags);
717 
718 	ASSERT(ph->p_hcd_private != NULL);
719 
720 	pp = (hwahc_pipe_private_t *)ph->p_hcd_private;
721 
722 	mutex_enter(&hwahcp->hwahc_mutex);
723 	rval = hwahc_state_is_operational(hwahcp);
724 	if (rval != USB_SUCCESS) {
725 		mutex_exit(&hwahcp->hwahc_mutex);
726 
727 		return (rval);
728 	}
729 
730 	USB_DPRINTF_L4(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
731 	    "hwahc_hcdi_pipe_bulk_xfer: pp = 0x%p state= %x", (void *) pp,
732 	    pp->pp_state);
733 
734 	if (pp->pp_state == HWAHC_PIPE_STATE_ERROR) {
735 		USB_DPRINTF_L2(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
736 		    "hwahc_hcdi_pipe_bulk_xfer: "
737 		    "Pipe is in error state, need pipe reset to continue");
738 
739 		mutex_exit(&hwahcp->hwahc_mutex);
740 
741 		return (USB_FAILURE);
742 	}
743 
744 	mutex_exit(&hwahcp->hwahc_mutex);
745 	rval = wusb_wa_bulk_xfer(&hwahcp->hwahc_wa_data, pp->pp_rp, ph,
746 	    bulk_reqp, usb_flags);
747 	mutex_enter(&hwahcp->hwahc_mutex);
748 	if (rval != USB_SUCCESS) {
749 		USB_DPRINTF_L2(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
750 		    "hwahc_hcdi_pipe_bulk_xfer failed, rval = %d", rval);
751 	}
752 	mutex_exit(&hwahcp->hwahc_mutex);
753 
754 	return (rval);
755 }
756 
757 /*
758  * hwahc_hcdi_pipe_intr_xfer:
759  *	- usba_hcdi_pipe_intr_xfer entry
760  *	- check pipe state
761  *	- process this request
762  */
763 static int
hwahc_hcdi_pipe_intr_xfer(usba_pipe_handle_data_t * ph,usb_intr_req_t * intr_reqp,usb_flags_t usb_flags)764 hwahc_hcdi_pipe_intr_xfer(
765 	usba_pipe_handle_data_t	*ph,
766 	usb_intr_req_t		*intr_reqp,
767 	usb_flags_t		usb_flags)
768 {
769 	hwahc_state_t		*hwahcp;
770 	hwahc_pipe_private_t	*pp;
771 	int			rval, pipe_dir;
772 
773 	hwahcp = hwahc_obtain_state(ph->p_usba_device->usb_root_hub_dip);
774 
775 	USB_DPRINTF_L4(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
776 	    "hwahc_hcdi_pipe_intr_xfer: hwahcp=0x%p ph = 0x%p"
777 	    " reqp = 0x%p flags = %x", (void *) hwahcp, (void *) ph,
778 	    (void *) intr_reqp, usb_flags);
779 
780 	ASSERT(ph->p_hcd_private != NULL);
781 	pp = (hwahc_pipe_private_t *)ph->p_hcd_private;
782 
783 	mutex_enter(&hwahcp->hwahc_mutex);
784 	rval = hwahc_state_is_operational(hwahcp);
785 	if (rval != USB_SUCCESS) {
786 		mutex_exit(&hwahcp->hwahc_mutex);
787 
788 		return (rval);
789 	}
790 
791 	USB_DPRINTF_L4(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
792 	    "hwahc_hcdi_pipe_intr_xfer: pp = 0x%p state= %x", (void *) pp,
793 	    pp->pp_state);
794 
795 	if (pp->pp_state == HWAHC_PIPE_STATE_ERROR) {
796 		USB_DPRINTF_L2(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
797 		    "hwahc_hcdi_pipe_intr_xfer: "
798 		    "Pipe is in error state, need pipe reset to continue");
799 
800 		mutex_exit(&hwahcp->hwahc_mutex);
801 
802 		return (USB_FAILURE);
803 	}
804 
805 	pipe_dir = ph->p_ep.bEndpointAddress & USB_EP_DIR_MASK;
806 
807 
808 	mutex_exit(&hwahcp->hwahc_mutex);
809 	rval = wusb_wa_intr_xfer(&hwahcp->hwahc_wa_data, pp->pp_rp, ph,
810 	    intr_reqp, usb_flags);
811 	mutex_enter(&hwahcp->hwahc_mutex);
812 	if (rval != USB_SUCCESS) {
813 		USB_DPRINTF_L2(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
814 		    "hwahc_hcdi_pipe_intr_xfer failed, rval = %d", rval);
815 	}
816 
817 	if ((pipe_dir == USB_EP_DIR_IN) &&(rval == USB_SUCCESS)) {
818 		/*
819 		 * the request has been submitted successfully,
820 		 * save the original one; free this request when polling
821 		 * stopped
822 		 */
823 		pp->pp_client_periodic_in_reqp = (usb_opaque_t)intr_reqp;
824 		pp->pp_state = HWAHC_PIPE_STATE_ACTIVE;
825 	}
826 
827 	mutex_exit(&hwahcp->hwahc_mutex);
828 
829 	return (rval);
830 }
831 
832 /*
833  * hwahc_hcdi_pipe_isoc_xfer:
834  */
835 /* ARGSUSED */
836 static int
hwahc_hcdi_pipe_isoc_xfer(usba_pipe_handle_data_t * ph,usb_isoc_req_t * isoc_reqp,usb_flags_t usb_flags)837 hwahc_hcdi_pipe_isoc_xfer(
838 	usba_pipe_handle_data_t	*ph,
839 	usb_isoc_req_t		*isoc_reqp,
840 	usb_flags_t		usb_flags)
841 {
842 	return (USB_NOT_SUPPORTED);
843 }
844 
845 
846 /*
847  * hwahc_hcdi_bulk_transfer_size:
848  *
849  * Return maximum bulk transfer size
850  */
851 /* ARGSUSED */
852 static int
hwahc_hcdi_bulk_transfer_size(usba_device_t * usba_device,size_t * size)853 hwahc_hcdi_bulk_transfer_size(
854 	usba_device_t	*usba_device,
855 	size_t		*size)
856 {
857 	hwahc_state_t		*hwahcp;
858 	int			rval;
859 
860 	hwahcp = hwahc_obtain_state(usba_device->usb_root_hub_dip);
861 
862 	USB_DPRINTF_L4(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
863 	    "hwahc_hcdi_bulk_transfer_size:");
864 
865 	mutex_enter(&hwahcp->hwahc_mutex);
866 	rval = hwahc_state_is_operational(hwahcp);
867 	mutex_exit(&hwahcp->hwahc_mutex);
868 
869 	if (rval != USB_SUCCESS) {
870 
871 		return (rval);
872 	}
873 
874 	*size = WA_MAX_SEG_COUNT * 1024;
875 
876 	return (USB_SUCCESS);
877 }
878 
879 /*
880  * hwahc_hcdi_pipe_stop_intr_polling()
881  */
882 /* ARGSUSED */
883 static int
hwahc_hcdi_pipe_stop_intr_polling(usba_pipe_handle_data_t * ph,usb_flags_t flags)884 hwahc_hcdi_pipe_stop_intr_polling(
885 	usba_pipe_handle_data_t	*ph,
886 	usb_flags_t		flags)
887 {
888 	hwahc_state_t		*hwahcp;
889 	hwahc_pipe_private_t	*pp;
890 
891 	hwahcp = hwahc_obtain_state(ph->p_usba_device->usb_root_hub_dip);
892 
893 	USB_DPRINTF_L4(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
894 	    "hwahc_hcdi_pipe_stop_intr_polling: hwahcp=0x%p ph = 0x%p"
895 	    " flags = %x", (void *) hwahcp, (void *) ph, flags);
896 
897 	ASSERT(ph->p_hcd_private != NULL);
898 
899 	mutex_enter(&hwahcp->hwahc_mutex);
900 	pp = (hwahc_pipe_private_t *)ph->p_hcd_private;
901 
902 	if (pp->pp_state != HWAHC_PIPE_STATE_ACTIVE) {
903 		USB_DPRINTF_L2(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
904 		    "hwahc_hcdi_pipe_stop_intr_polling: "
905 		    "Polling already stopped");
906 		mutex_exit(&hwahcp->hwahc_mutex);
907 
908 		return (USB_SUCCESS);
909 	}
910 
911 	pp->pp_state = HWAHC_PIPE_STATE_STOP_POLLING;
912 
913 	hwahc_pipe_cleanup(hwahcp, ph);
914 
915 	mutex_exit(&hwahcp->hwahc_mutex);
916 
917 	return (USB_SUCCESS);
918 }
919 
920 
921 /*
922  * hwahc_hcdi_pipe_stop_isoc_polling()
923  */
924 /*ARGSUSED*/
925 static int
hwahc_hcdi_pipe_stop_isoc_polling(usba_pipe_handle_data_t * ph,usb_flags_t flags)926 hwahc_hcdi_pipe_stop_isoc_polling(
927 	usba_pipe_handle_data_t	*ph,
928 	usb_flags_t		flags)
929 {
930 	return (USB_NOT_SUPPORTED);
931 }
932 
933 
934 /*
935  * hwahc_hcdi_get_current_frame_number:
936  *
937  * Get the current usb frame number.
938  * Return whether the request is handled successfully
939  */
940 /* ARGSUSED */
941 static int
hwahc_hcdi_get_current_frame_number(usba_device_t * usba_device,usb_frame_number_t * frame_number)942 hwahc_hcdi_get_current_frame_number(
943 	usba_device_t		*usba_device,
944 	usb_frame_number_t	*frame_number)
945 {
946 	return (USB_NOT_SUPPORTED);
947 }
948 
949 
950 /*
951  * hwahc_hcdi_get_max_isoc_pkts:
952  *
953  * Get maximum isochronous packets per usb isochronous request.
954  * Return whether the request is handled successfully
955  */
956 /* ARGSUSED */
957 static int
hwahc_hcdi_get_max_isoc_pkts(usba_device_t * usba_device,uint_t * max_pkts)958 hwahc_hcdi_get_max_isoc_pkts(
959 	usba_device_t	*usba_device,
960 	uint_t		*max_pkts)
961 {
962 	return (USB_NOT_SUPPORTED);
963 }
964 
965 
966 /*
967  * POLLED entry points
968  *
969  * These functions are entry points into the POLLED code.
970  */
971 /*
972  * hwahc_hcdi_polled_input_init:
973  *
974  * This is the initialization routine for handling the USB keyboard
975  * in POLLED mode.  This routine is not called from POLLED mode, so
976  * it is OK to acquire mutexes.
977  */
978 /* ARGSUSED */
979 static int
hwahc_hcdi_polled_input_init(usba_pipe_handle_data_t * ph,uchar_t ** polled_buf,usb_console_info_impl_t * console_input_info)980 hwahc_hcdi_polled_input_init(
981 	usba_pipe_handle_data_t	*ph,
982 	uchar_t			**polled_buf,
983 	usb_console_info_impl_t	*console_input_info)
984 {
985 	return (USB_FAILURE);
986 }
987 
988 
989 /*
990  * hwahc_hcdi_polled_input_fini:
991  */
992 /* ARGSUSED */
993 static int
hwahc_hcdi_polled_input_fini(usb_console_info_impl_t * info)994 hwahc_hcdi_polled_input_fini(usb_console_info_impl_t *info)
995 {
996 	return (USB_FAILURE);
997 }
998 
999 
1000 /*
1001  * hwahc_hcdi_polled_input_enter:
1002  *
1003  * This is where we enter into POLLED mode.  This routine sets up
1004  * everything so that calls to	hwahc_hcdi_polled_read will return
1005  * characters.
1006  */
1007 /* ARGSUSED */
1008 static int
hwahc_hcdi_polled_input_enter(usb_console_info_impl_t * info)1009 hwahc_hcdi_polled_input_enter(usb_console_info_impl_t *info)
1010 {
1011 	return (USB_FAILURE);
1012 }
1013 
1014 
1015 /*
1016  * hwahc_hcdi_polled_input_exit:
1017  *
1018  * This is where we exit POLLED mode. This routine restores
1019  * everything that is needed to continue operation.
1020  */
1021 /* ARGSUSED */
1022 static int
hwahc_hcdi_polled_input_exit(usb_console_info_impl_t * info)1023 hwahc_hcdi_polled_input_exit(usb_console_info_impl_t *info)
1024 {
1025 	return (USB_FAILURE);
1026 }
1027 
1028 
1029 /*
1030  * hwahc_hcdi_polled_read:
1031  *
1032  * Get a key character
1033  */
1034 /* ARGSUSED */
1035 static int
hwahc_hcdi_polled_read(usb_console_info_impl_t * info,uint_t * num_characters)1036 hwahc_hcdi_polled_read(
1037 	usb_console_info_impl_t	*info,
1038 	uint_t			*num_characters)
1039 {
1040 	return (USB_FAILURE);
1041 }
1042 
1043 
1044 /*
1045  * hwahc_alloc_hcdi_ops:
1046  *
1047  * The HCDI interfaces or entry points are the software interfaces used by
1048  * the Universal Serial Bus Driver  (USBA) to  access the services of the
1049  * Host Controller Driver (HCD).  During HCD initialization, inform  USBA
1050  * about all available HCDI interfaces or entry points.
1051  */
1052 usba_hcdi_ops_t *
hwahc_alloc_hcdi_ops(hwahc_state_t * hwahcp)1053 hwahc_alloc_hcdi_ops(hwahc_state_t *hwahcp)
1054 {
1055 	usba_hcdi_ops_t			*usba_hcdi_ops;
1056 
1057 	USB_DPRINTF_L2(PRINT_MASK_ATTA, hwahcp->hwahc_log_handle,
1058 	    "hwahc_alloc_hcdi_ops:");
1059 
1060 	usba_hcdi_ops = usba_alloc_hcdi_ops();
1061 
1062 	usba_hcdi_ops->usba_hcdi_ops_version = HCDI_OPS_VERSION;
1063 
1064 	usba_hcdi_ops->usba_hcdi_pm_support = hwahc_hcdi_pm_support;
1065 	usba_hcdi_ops->usba_hcdi_pipe_open = hwahc_hcdi_pipe_open;
1066 	usba_hcdi_ops->usba_hcdi_pipe_close = hwahc_hcdi_pipe_close;
1067 
1068 	usba_hcdi_ops->usba_hcdi_pipe_reset = hwahc_hcdi_pipe_reset;
1069 	usba_hcdi_ops->usba_hcdi_pipe_reset_data_toggle =
1070 	    hwahc_hcdi_pipe_reset_data_toggle;
1071 
1072 	usba_hcdi_ops->usba_hcdi_pipe_ctrl_xfer = hwahc_hcdi_pipe_ctrl_xfer;
1073 	usba_hcdi_ops->usba_hcdi_pipe_bulk_xfer = hwahc_hcdi_pipe_bulk_xfer;
1074 	usba_hcdi_ops->usba_hcdi_pipe_intr_xfer = hwahc_hcdi_pipe_intr_xfer;
1075 	usba_hcdi_ops->usba_hcdi_pipe_isoc_xfer = hwahc_hcdi_pipe_isoc_xfer;
1076 
1077 	usba_hcdi_ops->usba_hcdi_bulk_transfer_size =
1078 	    hwahc_hcdi_bulk_transfer_size;
1079 
1080 	usba_hcdi_ops->usba_hcdi_pipe_stop_intr_polling =
1081 	    hwahc_hcdi_pipe_stop_intr_polling;
1082 	usba_hcdi_ops->usba_hcdi_pipe_stop_isoc_polling =
1083 	    hwahc_hcdi_pipe_stop_isoc_polling;
1084 
1085 	usba_hcdi_ops->usba_hcdi_get_current_frame_number =
1086 	    hwahc_hcdi_get_current_frame_number;
1087 	usba_hcdi_ops->usba_hcdi_get_max_isoc_pkts =
1088 	    hwahc_hcdi_get_max_isoc_pkts;
1089 
1090 	usba_hcdi_ops->usba_hcdi_console_input_init =
1091 	    hwahc_hcdi_polled_input_init;
1092 	usba_hcdi_ops->usba_hcdi_console_input_enter =
1093 	    hwahc_hcdi_polled_input_enter;
1094 	usba_hcdi_ops->usba_hcdi_console_read =
1095 	    hwahc_hcdi_polled_read;
1096 	usba_hcdi_ops->usba_hcdi_console_input_exit =
1097 	    hwahc_hcdi_polled_input_exit;
1098 	usba_hcdi_ops->usba_hcdi_console_input_fini =
1099 	    hwahc_hcdi_polled_input_fini;
1100 
1101 	return (usba_hcdi_ops);
1102 }
1103 
1104 
1105 /*
1106  * Set cluster ID.
1107  * see 8.5.3.11
1108  */
1109 int
hwahc_set_cluster_id(dev_info_t * dip,uint8_t cluster_id)1110 hwahc_set_cluster_id(dev_info_t *dip, uint8_t cluster_id)
1111 {
1112 	usb_cr_t	completion_reason;
1113 	usb_cb_flags_t	cb_flags;
1114 	int		rval;
1115 	hwahc_state_t	*hwahcp;
1116 
1117 	if (dip == NULL) {
1118 
1119 		return (USB_INVALID_ARGS);
1120 	}
1121 
1122 	hwahcp = ddi_get_soft_state(hwahc_statep, ddi_get_instance(dip));
1123 	if (hwahcp == NULL) {
1124 
1125 		return (USB_INVALID_ARGS);
1126 	}
1127 
1128 	rval = usb_pipe_sync_ctrl_xfer(dip, hwahcp->hwahc_default_pipe,
1129 	    WUSB_CLASS_IF_REQ_OUT_TYPE,
1130 	    HWA_REQ_SET_CLUSTER_ID,
1131 	    cluster_id,
1132 	    hwahcp->hwahc_wa_data.wa_ifno,
1133 	    0,
1134 	    NULL, 0,
1135 	    &completion_reason, &cb_flags, 0);
1136 
1137 	if (rval != USB_SUCCESS) {
1138 		USB_DPRINTF_L2(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
1139 		    "Set_Cluster_ID fails: rval=%d cr=%d cb=0x%x",
1140 		    rval, completion_reason, cb_flags);
1141 	}
1142 
1143 	return (rval);
1144 }
1145 
1146 /*
1147  * Set WUSB Stream Index. see 8.5.3.13
1148  */
1149 int
hwahc_set_stream_idx(dev_info_t * dip,uint8_t stream_idx)1150 hwahc_set_stream_idx(dev_info_t *dip, uint8_t stream_idx)
1151 {
1152 	usb_cr_t	completion_reason;
1153 	usb_cb_flags_t	cb_flags;
1154 	int		rval;
1155 	hwahc_state_t	*hwahcp;
1156 
1157 	if ((dip == NULL))  {
1158 
1159 		return (USB_INVALID_ARGS);
1160 	}
1161 
1162 	hwahcp = ddi_get_soft_state(hwahc_statep, ddi_get_instance(dip));
1163 	if (hwahcp == NULL) {
1164 
1165 		return (USB_INVALID_ARGS);
1166 	}
1167 
1168 	rval = usb_pipe_sync_ctrl_xfer(dip, hwahcp->hwahc_default_pipe,
1169 	    WUSB_CLASS_IF_REQ_OUT_TYPE,
1170 	    HWA_REQ_SET_STREAM_IDX,
1171 	    stream_idx,
1172 	    hwahcp->hwahc_wa_data.wa_ifno,
1173 	    0, NULL, 0, &completion_reason,
1174 	    &cb_flags, 0);
1175 
1176 	if (rval != USB_SUCCESS) {
1177 		USB_DPRINTF_L2(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
1178 		    "Set_Stream_Idx fails: rval=%d cr=%d cb=0x%x",
1179 		    rval, completion_reason, cb_flags);
1180 	}
1181 
1182 	return (rval);
1183 }
1184 
1185 /*
1186  * 8.5.3.12 - Set WUSB MAS
1187  *	Caller must ensure the data is WUSB_SET_WUSB_MAS_LEN long.
1188  */
1189 int
hwahc_set_wusb_mas(dev_info_t * dip,uint8_t * data)1190 hwahc_set_wusb_mas(dev_info_t *dip, uint8_t *data)
1191 {
1192 	usb_cr_t	completion_reason;
1193 	usb_cb_flags_t	cb_flags;
1194 	mblk_t		*blk;
1195 	int		rval, i;
1196 	hwahc_state_t	*hwahcp;
1197 
1198 	if ((dip == NULL))  {
1199 
1200 		return (USB_INVALID_ARGS);
1201 	}
1202 
1203 	hwahcp = ddi_get_soft_state(hwahc_statep, ddi_get_instance(dip));
1204 	if (hwahcp == NULL) {
1205 
1206 		return (USB_INVALID_ARGS);
1207 	}
1208 
1209 	blk = allocb_wait(WUSB_SET_WUSB_MAS_LEN, BPRI_LO, STR_NOSIG, NULL);
1210 
1211 	for (i = 0; i < WUSB_SET_WUSB_MAS_LEN; i++) {
1212 		*blk->b_wptr++ = data[i];
1213 	}
1214 
1215 	rval = usb_pipe_sync_ctrl_xfer(dip, hwahcp->hwahc_default_pipe,
1216 	    WUSB_CLASS_IF_REQ_OUT_TYPE,
1217 	    HWA_REQ_SET_WUSB_MAS,
1218 	    0,
1219 	    hwahcp->hwahc_wa_data.wa_ifno,
1220 	    WUSB_SET_WUSB_MAS_LEN,
1221 	    &blk, 0,
1222 	    &completion_reason, &cb_flags, 0);
1223 
1224 	if (rval != USB_SUCCESS) {
1225 		USB_DPRINTF_L2(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
1226 		    "Set_WUSB_MAS fails: rval=%d cr=%d cb=0x%x",
1227 		    rval, completion_reason, cb_flags);
1228 	}
1229 	freemsg(blk);
1230 
1231 	return (rval);
1232 }
1233 
1234 /* 8.5.3.1 - Add MMC IE */
1235 int
hwahc_add_mmc_ie(dev_info_t * dip,uint8_t interval,uint8_t rcnt,uint8_t iehdl,uint16_t len,uint8_t * data)1236 hwahc_add_mmc_ie(dev_info_t *dip, uint8_t interval, uint8_t rcnt,
1237 	uint8_t iehdl, uint16_t len, uint8_t *data)
1238 {
1239 	usb_cr_t	completion_reason;
1240 	usb_cb_flags_t	cb_flags;
1241 	mblk_t		*blk;
1242 	int		i, rval;
1243 	hwahc_state_t	*hwahcp;
1244 
1245 	if (dip == NULL)  {
1246 
1247 		return (USB_INVALID_ARGS);
1248 	}
1249 
1250 	hwahcp = ddi_get_soft_state(hwahc_statep, ddi_get_instance(dip));
1251 	if (hwahcp == NULL) {
1252 
1253 		return (USB_INVALID_ARGS);
1254 	}
1255 
1256 	blk = allocb_wait(len, BPRI_LO, STR_NOSIG, NULL);
1257 
1258 	for (i = 0; i < len; i++) {
1259 		*blk->b_wptr++ = data[i];
1260 	}
1261 
1262 	rval = usb_pipe_sync_ctrl_xfer(dip, hwahcp->hwahc_default_pipe,
1263 	    WUSB_CLASS_IF_REQ_OUT_TYPE,
1264 	    HWA_REQ_ADD_MMC_IE,
1265 	    (interval << 8) | rcnt,
1266 	    (iehdl << 8) | hwahcp->hwahc_wa_data.wa_ifno,
1267 	    len,
1268 	    &blk, 0,
1269 	    &completion_reason, &cb_flags, 0);
1270 
1271 	if (rval != USB_SUCCESS) {
1272 		USB_DPRINTF_L2(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
1273 		    "Add_MMC_IE fails: rval=%d cr=%d cb=0x%x",
1274 		    rval, completion_reason, cb_flags);
1275 	}
1276 
1277 	freemsg(blk);
1278 
1279 	return (rval);
1280 }
1281 
1282 /* 8.5.3.5 - Remove MMC IE */
1283 int
hwahc_remove_mmc_ie(dev_info_t * dip,uint8_t iehdl)1284 hwahc_remove_mmc_ie(dev_info_t *dip, uint8_t iehdl)
1285 {
1286 	usb_cr_t	completion_reason;
1287 	usb_cb_flags_t	cb_flags;
1288 	int		rval;
1289 	hwahc_state_t	*hwahcp;
1290 
1291 	if (dip == NULL) {
1292 
1293 		return (USB_INVALID_ARGS);
1294 	}
1295 
1296 	hwahcp = ddi_get_soft_state(hwahc_statep, ddi_get_instance(dip));
1297 	if (hwahcp == NULL) {
1298 		return (USB_INVALID_ARGS);
1299 	}
1300 
1301 	rval = usb_pipe_sync_ctrl_xfer(dip, hwahcp->hwahc_default_pipe,
1302 	    WUSB_CLASS_IF_REQ_OUT_TYPE,
1303 	    HWA_REQ_REMOVE_MMC_IE,
1304 	    0,
1305 	    (iehdl << 8) | hwahcp->hwahc_wa_data.wa_ifno,
1306 	    0,
1307 	    NULL, 0,
1308 	    &completion_reason, &cb_flags, 0);
1309 
1310 	if (rval != USB_SUCCESS) {
1311 		USB_DPRINTF_L2(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
1312 		    "Remove_MMC_IE fails: rval=%d cr=%d cb=0x%x",
1313 		    rval, completion_reason, cb_flags);
1314 	}
1315 
1316 	return (rval);
1317 }
1318 
1319 /* 8.5.3.14 - WUSB Channel Stop */
1320 int
hwahc_stop_ch(dev_info_t * dip,uint32_t timeoff)1321 hwahc_stop_ch(dev_info_t *dip, uint32_t timeoff)
1322 {
1323 	int		rval;
1324 	usb_cr_t	completion_reason;
1325 	usb_cb_flags_t	cb_flags;
1326 	hwahc_state_t	*hwahcp;
1327 
1328 	if (dip == NULL) {
1329 
1330 		return (USB_INVALID_ARGS);
1331 	}
1332 
1333 	hwahcp = ddi_get_soft_state(hwahc_statep, ddi_get_instance(dip));
1334 	if (hwahcp == NULL) {
1335 
1336 		return (USB_INVALID_ARGS);
1337 	}
1338 
1339 	rval = usb_pipe_sync_ctrl_xfer(dip, hwahcp->hwahc_default_pipe,
1340 	    WUSB_CLASS_IF_REQ_OUT_TYPE,
1341 	    HWA_REQ_CH_STOP,
1342 	    timeoff & 0x00ffffff,
1343 	    hwahcp->hwahc_wa_data.wa_ifno,
1344 	    0,
1345 	    NULL, 0,
1346 	    &completion_reason, &cb_flags, 0);
1347 
1348 	if (rval != USB_SUCCESS) {
1349 		USB_DPRINTF_L2(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
1350 		    "WUSB_Ch_Stop fails: rval=%d cr=%d cb=0x%x",
1351 		    rval, completion_reason, cb_flags);
1352 	}
1353 
1354 	return (rval);
1355 }
1356 
1357 /* 8.5. 3.10 - Set Num DNTS Slots */
1358 int
hwahc_set_num_dnts(dev_info_t * dip,uint8_t interval,uint8_t nslots)1359 hwahc_set_num_dnts(dev_info_t *dip, uint8_t interval, uint8_t nslots)
1360 {
1361 	usb_cr_t	completion_reason;
1362 	usb_cb_flags_t	cb_flags;
1363 	int		rval;
1364 	hwahc_state_t	*hwahcp;
1365 
1366 	if (dip == NULL) {
1367 
1368 		return (USB_INVALID_ARGS);
1369 	}
1370 
1371 	hwahcp = ddi_get_soft_state(hwahc_statep, ddi_get_instance(dip));
1372 	if (hwahcp == NULL) {
1373 
1374 		return (USB_INVALID_ARGS);
1375 	}
1376 
1377 	rval = usb_pipe_sync_ctrl_xfer(dip, hwahcp->hwahc_default_pipe,
1378 	    WUSB_CLASS_IF_REQ_OUT_TYPE,
1379 	    HWA_REQ_SET_NUM_DNTS,
1380 	    (interval << 8) | nslots,
1381 	    hwahcp->hwahc_wa_data.wa_ifno,
1382 	    0,
1383 	    NULL, 0,
1384 	    &completion_reason, &cb_flags, 0);
1385 
1386 	if (rval != USB_SUCCESS) {
1387 		USB_DPRINTF_L2(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
1388 		    "Set_Num_DNTS fails: rval=%d cr=%d cb=0x%x",
1389 		    rval, completion_reason, cb_flags);
1390 	}
1391 
1392 	return (rval);
1393 }
1394 
1395 /* set encryptiion type for host */
1396 int
hwahc_set_encrypt(dev_info_t * dip,usb_port_t port,uint8_t type)1397 hwahc_set_encrypt(dev_info_t *dip, usb_port_t port, uint8_t type)
1398 {
1399 	hwahc_state_t	*hwahcp;
1400 	int		rval;
1401 
1402 	if ((hwahcp = ddi_get_soft_state(hwahc_statep,
1403 	    ddi_get_instance(dip))) == NULL) {
1404 
1405 		return (USB_INVALID_ARGS);
1406 	}
1407 	/* DEVICE INDEX */
1408 	rval = hwahc_set_dev_encrypt(hwahcp->hwahc_default_pipe,
1409 	    hwahcp->hwahc_wa_data.wa_ifno, port - 1,
1410 	    &hwahcp->hwahc_secrt_data, type);
1411 	if (rval != USB_SUCCESS) {
1412 		USB_DPRINTF_L2(PRINT_MASK_CBOPS, hwahcp->hwahc_log_handle,
1413 		    "hwahc_set_encrypt: set device encryption for port %d "
1414 		    "failed", port);
1415 	}
1416 
1417 	return (rval);
1418 }
1419 
1420 
1421 /*
1422  * Set Device Key for WUSB host, refer to WUSB 1.0/8.5.3.8
1423  *
1424  * Set group/device key:
1425  * devindex = actual port number - 1, so it is zero based
1426  *
1427  */
hwahc_set_keys(hwahc_state_t * hwahcp,usb_key_descr_t * key_descr,size_t klen,uint8_t devindex,uint8_t keydex,uint8_t flag)1428 int hwahc_set_keys(hwahc_state_t *hwahcp, usb_key_descr_t *key_descr,
1429     size_t klen, uint8_t devindex, uint8_t keydex, uint8_t flag)
1430 {
1431 	usb_ctrl_setup_t	setup;
1432 	usb_cr_t		cr;
1433 	usb_cb_flags_t		cb_flags;
1434 	mblk_t			*pdata;
1435 	int			rval;
1436 	uint8_t			keyindex;
1437 
1438 	USB_DPRINTF_L4(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
1439 	    "hwahc_set_keys: klen = %d, devindex = %d", (int)klen,
1440 	    devindex);
1441 
1442 	/* Table 7-21 and Errata 2005/07 */
1443 	if (flag == WUSB_GTK) {
1444 		if (devindex != 0) {
1445 			return (USB_FAILURE);
1446 		}
1447 
1448 		/* See 7.3.2.4 for key index format */
1449 		keyindex = (1 << 5) | keydex;
1450 	} else if (flag == WUSB_PTK) {
1451 
1452 		keyindex = keydex;
1453 	} else {
1454 
1455 		return (USB_FAILURE);
1456 	}
1457 
1458 	setup.bmRequestType = USB_DEV_REQ_HOST_TO_DEV |
1459 	    USB_DEV_REQ_TYPE_CLASS | USB_DEV_REQ_RCPT_IF;
1460 	setup.bRequest = USB_REQ_SET_DESCR;
1461 	setup.wValue = (USB_DESCR_TYPE_KEY << 8) | keyindex;
1462 	setup.wIndex = devindex << 8 | hwahcp->hwahc_wa_data.wa_ifno;
1463 	setup.wLength = (uint16_t)klen;
1464 	setup.attrs = USB_ATTRS_NONE;
1465 
1466 	if ((pdata = allocb(klen, BPRI_HI)) == NULL) {
1467 
1468 		return (USB_FAILURE);
1469 	}
1470 	bcopy(key_descr, pdata->b_wptr, klen);
1471 	pdata->b_wptr += klen;
1472 
1473 	rval = usb_pipe_ctrl_xfer_wait(hwahcp->hwahc_default_pipe, &setup,
1474 	    &pdata, &cr, &cb_flags, USB_FLAGS_SLEEP);
1475 
1476 	if (rval != USB_SUCCESS) {
1477 		USB_DPRINTF_L4(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
1478 		    "hwahc_set_keys:fail, rv=%d,cr=%d,cb=%d", rval, cr,
1479 		    cb_flags);
1480 	}
1481 
1482 	freemsg(pdata);
1483 
1484 	return (rval);
1485 }
1486 
1487 /* set PTK for host */
1488 int
hwahc_set_ptk(dev_info_t * dip,usb_key_descr_t * key_descr,size_t klen,usb_port_t port)1489 hwahc_set_ptk(dev_info_t *dip, usb_key_descr_t *key_descr, size_t klen,
1490 	usb_port_t port)
1491 {
1492 	hwahc_state_t	*hwahcp;
1493 	int		rval;
1494 	uint8_t		keyindex = 1;
1495 
1496 	if ((hwahcp = ddi_get_soft_state(hwahc_statep,
1497 	    ddi_get_instance(dip))) == NULL) {
1498 
1499 		return (USB_INVALID_ARGS);
1500 	}
1501 	/* DEVICE INDEX */
1502 	rval = hwahc_set_keys(hwahcp, key_descr, klen, port - 1, keyindex,
1503 	    WUSB_PTK);
1504 	if (rval != USB_SUCCESS) {
1505 		USB_DPRINTF_L2(PRINT_MASK_CBOPS, hwahcp->hwahc_log_handle,
1506 		    "hwahc_set_ptk: set device key descr for port %d "
1507 		    "failed", port);
1508 	}
1509 
1510 	return (rval);
1511 }
1512 
1513 /* set GTK for host */
1514 int
hwahc_set_gtk(dev_info_t * dip,usb_key_descr_t * key_descr,size_t klen)1515 hwahc_set_gtk(dev_info_t *dip, usb_key_descr_t *key_descr, size_t klen)
1516 {
1517 	hwahc_state_t		*hwahcp;
1518 	int			rval;
1519 
1520 	if ((hwahcp = ddi_get_soft_state(hwahc_statep,
1521 	    ddi_get_instance(dip))) == NULL) {
1522 
1523 		return (USB_INVALID_ARGS);
1524 	}
1525 
1526 	rval = hwahc_set_keys(hwahcp, key_descr, klen, 0, 0, WUSB_GTK);
1527 	if (rval != USB_SUCCESS) {
1528 		USB_DPRINTF_L2(PRINT_MASK_CBOPS, hwahcp->hwahc_log_handle,
1529 		    "hwahc_set_gtk: set group key descr failed");
1530 	}
1531 
1532 	return (rval);
1533 }
1534 
1535 /*
1536  * set device info for host
1537  * Section 8.5.3.7.
1538  */
1539 int
hwahc_set_device_info(dev_info_t * dip,wusb_dev_info_t * dev_info,usb_port_t port)1540 hwahc_set_device_info(dev_info_t *dip, wusb_dev_info_t *dev_info,
1541 	usb_port_t port)
1542 {
1543 	hwahc_state_t		*hwahcp;
1544 	int			rval;
1545 	hwa_dev_info_t		info;
1546 	usb_ctrl_setup_t	setup;
1547 	usb_cr_t		cr;
1548 	usb_cb_flags_t		cb_flags;
1549 	mblk_t			*pdata;
1550 
1551 	if ((hwahcp = ddi_get_soft_state(hwahc_statep,
1552 	    ddi_get_instance(dip))) == NULL) {
1553 
1554 		return (USB_INVALID_ARGS);
1555 	}
1556 
1557 	/* the device can use all the host's reserved MASes to communicate */
1558 	(void) memcpy(info.bmDeviceAvailablilityInfo,
1559 	    hwahcp->hwahc_hc_data.hc_mas, WUSB_SET_WUSB_MAS_LEN);
1560 
1561 	info.bDeviceAddress = dev_info->wdev_addr;
1562 
1563 	/* To tell HWA device what data rates this child device supports */
1564 	if (dev_info->wdev_uwb_descr == NULL) {
1565 		/* bitmap, see7.4.1.1. Must support 53.3/106.7/200 Mbps */
1566 		info.wPHYRates[0] = WUSB_DATA_RATE_BIT_53 |
1567 		    WUSB_DATA_RATE_BIT_106 | WUSB_DATA_RATE_BIT_200;
1568 		info.wPHYRates[1] = 0;
1569 	} else {
1570 		info.wPHYRates[0] =
1571 		    dev_info->wdev_uwb_descr->wPHYRates && 0xff;
1572 		info.wPHYRates[1] =
1573 		    (dev_info->wdev_uwb_descr->wPHYRates >> 8) && 0xff;
1574 	}
1575 	info.bmDeviceAttribute = 0;
1576 
1577 	setup.bmRequestType = USB_DEV_REQ_HOST_TO_DEV |
1578 	    USB_DEV_REQ_TYPE_CLASS | USB_DEV_REQ_RCPT_IF;
1579 	setup.bRequest = HWA_REQ_SET_DEVICE_INFO;
1580 	setup.wValue = 0;
1581 
1582 	/* DEVICE INDEX */
1583 	setup.wIndex = (port - 1) << 8 | hwahcp->hwahc_wa_data.wa_ifno;
1584 	setup.wLength = WUSB_SET_DEV_INFO_LEN;
1585 	setup.attrs = USB_ATTRS_NONE;
1586 
1587 	if ((pdata = allocb(WUSB_SET_DEV_INFO_LEN, BPRI_HI)) == NULL) {
1588 
1589 		return (USB_FAILURE);
1590 	}
1591 	bcopy(&info, pdata->b_wptr, WUSB_SET_DEV_INFO_LEN);
1592 	pdata->b_wptr += WUSB_SET_DEV_INFO_LEN;
1593 
1594 	rval = usb_pipe_ctrl_xfer_wait(hwahcp->hwahc_default_pipe, &setup,
1595 	    &pdata, &cr, &cb_flags, USB_FLAGS_SLEEP);
1596 
1597 	freemsg(pdata);
1598 
1599 	return (rval);
1600 }
1601 
1602 /*
1603  * 8.5.3.2 - 8.5.3.4 Get Time
1604  * time_type:
1605  *	WUSB_TIME_ADJ	- Get BPST Adjustment
1606  *	WUSB_TIME_BPST	- Get BPST Time
1607  *	WUSB_TIME_WUSB	- Get WUSB Time
1608  */
1609 int
hwahc_get_time(dev_info_t * dip,uint8_t time_type,uint16_t len,uint32_t * time)1610 hwahc_get_time(dev_info_t *dip, uint8_t time_type,
1611     uint16_t len, uint32_t *time)
1612 {
1613 	usb_cr_t	completion_reason;
1614 	usb_cb_flags_t	cb_flags;
1615 	mblk_t		*blk = NULL;
1616 	int		rval;
1617 	uint8_t		*data;
1618 	uint16_t	length;
1619 	hwahc_state_t	*hwahcp = NULL;
1620 
1621 	if (dip == NULL) {
1622 
1623 		return (USB_INVALID_ARGS);
1624 	}
1625 
1626 	hwahcp = ddi_get_soft_state(hwahc_statep, ddi_get_instance(dip));
1627 	if (hwahcp == NULL) {
1628 
1629 		return (USB_INVALID_ARGS);
1630 	}
1631 
1632 	/* according to WUSB 8.5.3, len is 1 or 3 */
1633 	if ((len != 1) && (len != 3)) {
1634 
1635 		return (USB_INVALID_ARGS);
1636 	}
1637 
1638 	rval = usb_pipe_sync_ctrl_xfer(dip, hwahcp->hwahc_default_pipe,
1639 	    WUSB_CLASS_IF_REQ_OUT_TYPE, HWA_REQ_GET_TIME,
1640 	    time_type, hwahcp->hwahc_wa_data.wa_ifno,
1641 	    len, &blk, 0, &completion_reason, &cb_flags, 0);
1642 
1643 	if (rval != USB_SUCCESS) {
1644 		freemsg(blk);
1645 
1646 		USB_DPRINTF_L2(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
1647 		    "Get_Time fails: rval=%d cr=%d cb=0x%x",
1648 		    rval, completion_reason, cb_flags);
1649 
1650 		return (rval);
1651 	} else if (blk == NULL) {
1652 		USB_DPRINTF_L2(PRINT_MASK_HCDI, hwahcp->hwahc_log_handle,
1653 		    "Get_Time returns null data");
1654 
1655 		return (USB_FAILURE);
1656 	} else {
1657 		length = MBLKL(blk);
1658 
1659 		if (length < len) {
1660 			freemsg(blk);
1661 
1662 			USB_DPRINTF_L2(PRINT_MASK_HCDI,
1663 			    hwahcp->hwahc_log_handle,
1664 			    "Get_Time returns short length %d", length);
1665 
1666 			return (USB_FAILURE);
1667 		}
1668 
1669 		data = blk->b_rptr;
1670 		if (len == 1) {
1671 			*time = *data;
1672 		} else {
1673 			*time = (data[2] << 16) | (data[1] << 8) | data[0];
1674 		}
1675 		freemsg(blk);
1676 
1677 		return (USB_SUCCESS);
1678 	}
1679 }
1680