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 */
41static int hwahc_state_is_operational(hwahc_state_t *hwahcp);
42static hwahc_state_t *hwahc_obtain_state(dev_info_t *dip);
43static void hwahc_wait_for_xfer_completion(hwahc_state_t *hwahcp,
44	hwahc_pipe_private_t *pp);
45static void hwahc_traverse_requests(hwahc_state_t *hwahcp,
46	hwahc_pipe_private_t *pp);
47static void hwahc_pipe_cleanup(hwahc_state_t *hwahcp,
48	usba_pipe_handle_data_t *ph);
49int 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
52static int hwahc_hcdi_pm_support(dev_info_t *dip);
53static int hwahc_hcdi_pipe_open(usba_pipe_handle_data_t *ph,
54	usb_flags_t flags);
55static int hwahc_hcdi_pipe_close(usba_pipe_handle_data_t *ph,
56	usb_flags_t flags);
57static int hwahc_hcdi_pipe_reset(usba_pipe_handle_data_t *ph,
58	usb_flags_t flags);
59static void hwahc_hcdi_pipe_reset_data_toggle(usba_pipe_handle_data_t *ph);
60static int hwahc_hcdi_pipe_ctrl_xfer(usba_pipe_handle_data_t *ph,
61	usb_ctrl_req_t *ctrl_reqp, usb_flags_t usb_flags);
62static int hwahc_hcdi_pipe_bulk_xfer(usba_pipe_handle_data_t *ph,
63	usb_bulk_req_t *bulk_reqp, usb_flags_t usb_flags);
64static int hwahc_hcdi_pipe_intr_xfer(usba_pipe_handle_data_t *ph,
65	usb_intr_req_t *intr_reqp, usb_flags_t usb_flags);
66static int hwahc_hcdi_pipe_isoc_xfer(usba_pipe_handle_data_t *ph,
67	usb_isoc_req_t *isoc_reqp, usb_flags_t usb_flags);
68static int hwahc_hcdi_bulk_transfer_size(usba_device_t *usba_device,
69	size_t *size);
70static int hwahc_hcdi_pipe_stop_intr_polling(usba_pipe_handle_data_t *ph,
71	usb_flags_t flags);
72static int hwahc_hcdi_pipe_stop_isoc_polling(usba_pipe_handle_data_t *ph,
73	usb_flags_t flags);
74static int hwahc_hcdi_get_current_frame_number(usba_device_t *usba_device,
75	usb_frame_number_t *frame_number);
76static int hwahc_hcdi_get_max_isoc_pkts(usba_device_t *usba_device,
77	uint_t *max_pkts);
78static 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);
80static int hwahc_hcdi_polled_input_fini(usb_console_info_impl_t *info);
81static int hwahc_hcdi_polled_input_enter(usb_console_info_impl_t *info);
82static int hwahc_hcdi_polled_input_exit(usb_console_info_impl_t *info);
83static int hwahc_hcdi_polled_read(usb_console_info_impl_t *info,
84	uint_t *num_characters);
85usba_hcdi_ops_t *hwahc_alloc_hcdi_ops(hwahc_state_t *hwahcp);
86
87extern void *hwahc_statep;
88
89/* Check the Host controller state and return proper values */
90static int
91hwahc_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 */
127hwahc_state_t *
128hwahc_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 */
144static int
145hwahc_hcdi_pm_support(dev_info_t *dip)
146{
147	return (USB_FAILURE);
148}
149
150static void
151/* ARGSUSED */
152hwahc_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 */
158static void
159hwahc_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 */
186static void
187hwahc_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 */
222static void
223hwahc_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 */
262static void
263hwahc_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 */
368static int
369hwahc_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 */
421static int
422hwahc_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 */
532static int
533hwahc_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 */
584static int
585hwahc_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 */
619static int
620hwahc_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 */
701static int
702hwahc_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 */
763static int
764hwahc_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 */
836static int
837hwahc_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 */
852static int
853hwahc_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 */
883static int
884hwahc_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*/
925static int
926hwahc_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 */
941static int
942hwahc_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 */
957static int
958hwahc_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 */
979static int
980hwahc_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 */
993static int
994hwahc_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 */
1008static int
1009hwahc_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 */
1022static int
1023hwahc_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 */
1035static int
1036hwahc_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 */
1052usba_hcdi_ops_t *
1053hwahc_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 */
1109int
1110hwahc_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 */
1149int
1150hwahc_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 */
1189int
1190hwahc_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 */
1235int
1236hwahc_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 */
1283int
1284hwahc_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 */
1320int
1321hwahc_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 */
1358int
1359hwahc_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 */
1396int
1397hwahc_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 */
1428int 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 */
1488int
1489hwahc_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 */
1514int
1515hwahc_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 */
1539int
1540hwahc_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 */
1609int
1610hwahc_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