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