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