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 * Wire Adapter Operations
28 * Both DWA and HWA have the same kind of functional components, the
29 * Wire Adapter. Functions defined in this file are to handle WA's
30 * class specific Descriptors, Requests, Notifications and Transfers.
31 * DWA or HWA specific descriptors, requests are not handled here.
32 */
33
34 #include <sys/usb/hwa/hwahc/hwahc.h>
35 #include <sys/usb/hwa/hwahc/hwahc_util.h>
36 #include <sys/usb/usba/wa.h>
37 #include <sys/usb/usba/wusba.h>
38 #include <sys/usb/usba/whcdi.h>
39 #include <sys/usb/usba.h>
40 #include <sys/usb/usba/usba_impl.h>
41 #include <sys/usb/usba/usba_devdb.h> /* usba_devdb_refresh */
42 #include <sys/usb/hubd/hubdvar.h>
43 #include <sys/usb/hubd/hubd_impl.h> /* hubd_ioctl_data_t */
44 #include <sys/strsubr.h> /* allocb_wait */
45 #include <sys/strsun.h> /* MBLKL macro */
46
47 extern usb_log_handle_t whcdi_log_handle;
48
49 /* default rpipe PHY transfer speed */
50 static uint8_t rp_default_speed = WUSB_PHY_TX_RATE_106;
51
52 /* function prototypes */
53 static void wusb_wa_remove_wr_from_timeout_list(wusb_wa_rpipe_hdl_t *hdl,
54 wusb_wa_trans_wrapper_t *tw);
55 static void wusb_wa_handle_error(wusb_wa_data_t *wa_data,
56 wusb_wa_trans_wrapper_t *wr, usb_cr_t cr);
57
58 /*
59 * Parse Wire Adapter class desriptor.
60 * - see 8.4.3.7 & 8.5.2.7
61 *
62 * wa_descr - the parsed descriptors.
63 * altif_data - the passed in raw descriptor data.
64 */
65 int
wusb_parse_wa_descr(usb_wa_descr_t * wa_descr,usb_alt_if_data_t * altif_data)66 wusb_parse_wa_descr(usb_wa_descr_t *wa_descr, usb_alt_if_data_t *altif_data)
67 {
68 usb_cvs_data_t *cvs_data;
69 int i;
70 size_t count;
71
72 if ((wa_descr == NULL) || (altif_data == NULL)) {
73 return (USB_INVALID_ARGS);
74 }
75
76 for (i = 0; i < altif_data->altif_n_cvs; i++) {
77 cvs_data = &altif_data->altif_cvs[i];
78 if (cvs_data->cvs_buf == NULL) {
79 continue;
80 }
81 if (cvs_data->cvs_buf[1] == USB_DESCR_TYPE_WA) {
82 count = usb_parse_data("ccsccsscccc",
83 cvs_data->cvs_buf, cvs_data->cvs_buf_len,
84 (void *)wa_descr,
85 (size_t)USB_WA_DESCR_SIZE);
86 if (count != USB_WA_DESCR_SIZE) {
87 return (USB_FAILURE);
88 } else {
89 return (USB_SUCCESS);
90 }
91 }
92 }
93
94 return (USB_FAILURE);
95 }
96
97 /* initialize rpipe structures */
98 void
wusb_wa_rpipes_init(wusb_wa_data_t * wa_data)99 wusb_wa_rpipes_init(wusb_wa_data_t *wa_data)
100 {
101 int i;
102 wusb_wa_rpipe_hdl_t *hdl;
103
104 for (i = 0; i < wa_data->wa_num_rpipes; i++) {
105 hdl = &wa_data->wa_rpipe_hdl[i];
106 mutex_init(&hdl->rp_mutex, NULL, MUTEX_DRIVER, NULL);
107 cv_init(&hdl->rp_cv, NULL, CV_DRIVER, NULL);
108
109 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*hdl));
110 hdl->rp_state = WA_RPIPE_STATE_FREE;
111 hdl->rp_refcnt = 0;
112 hdl->rp_timeout_list = NULL;
113 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*hdl));
114 }
115 }
116
117 /* deinitialize rpipe structures */
118 void
wusb_wa_rpipes_fini(wusb_wa_data_t * wa_data)119 wusb_wa_rpipes_fini(wusb_wa_data_t *wa_data)
120 {
121 int i;
122 wusb_wa_rpipe_hdl_t *hdl;
123
124 for (i = 0; i < wa_data->wa_num_rpipes; i++) {
125 hdl = &wa_data->wa_rpipe_hdl[i];
126 mutex_destroy(&hdl->rp_mutex);
127 cv_destroy(&hdl->rp_cv);
128 }
129 }
130
131
132 /*
133 * wusb_wa_data_init:
134 * WA interface validation
135 * Parse WA class descriptors
136 * Set up RPipes
137 * Set up callbacks
138 */
139 int
wusb_wa_data_init(dev_info_t * dip,wusb_wa_data_t * wa_data,wusb_wa_cb_t * cbs,usb_client_dev_data_t * dev_data,uint_t mask,usb_log_handle_t handle)140 wusb_wa_data_init(dev_info_t *dip, wusb_wa_data_t *wa_data, wusb_wa_cb_t *cbs,
141 usb_client_dev_data_t *dev_data,
142 uint_t mask, usb_log_handle_t handle)
143 {
144 usb_alt_if_data_t *altif_data;
145 usb_ep_data_t *ep_data;
146 int ifno;
147 int rval;
148
149 if ((wa_data == NULL) || (dev_data == NULL)) {
150
151 return (USB_INVALID_ARGS);
152 }
153
154 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*wa_data));
155
156 /* get inf descr and ept descrs from altif data */
157 altif_data = &dev_data->dev_curr_cfg->
158 cfg_if[dev_data->dev_curr_if].if_alt[0];
159
160 /* T.8-44. Wire Adapter */
161 if (altif_data->altif_descr.bInterfaceSubClass !=
162 USB_SUBCLS_WUSB_2) {
163 USB_DPRINTF_L2(mask, handle,
164 "wusb_init_wa_data: invalid interface subclass (0x%x)",
165 altif_data->altif_descr.bInterfaceSubClass);
166
167 return (USB_FAILURE);
168 }
169
170 /* at least 3 EPs, INTR IN + BULK IN + BULK OUT */
171 if (altif_data->altif_n_ep < 3) {
172 USB_DPRINTF_L2(mask, handle,
173 "wusb_init_wa_data: invalid alt 0 for interface %d",
174 dev_data->dev_curr_if);
175
176 return (USB_FAILURE);
177 }
178
179 wa_data->wa_ifno = ifno = dev_data->dev_curr_if;
180 wa_data->wa_if_descr = altif_data->altif_descr;
181
182 if ((ep_data = usb_lookup_ep_data(dip, dev_data, ifno, 0, 0,
183 USB_EP_ATTR_BULK, USB_EP_DIR_OUT)) != NULL) {
184 wa_data->wa_bulkout_ept = ep_data->ep_descr;
185 }
186 if ((ep_data = usb_lookup_ep_data(dip, dev_data, ifno, 0, 0,
187 USB_EP_ATTR_BULK, USB_EP_DIR_IN)) != NULL) {
188 wa_data->wa_bulkin_ept = ep_data->ep_descr;
189 }
190 if ((ep_data = usb_lookup_ep_data(dip, dev_data, ifno, 0, 0,
191 USB_EP_ATTR_INTR, USB_EP_DIR_IN)) != NULL) {
192 wa_data->wa_intr_ept = ep_data->ep_descr;
193 }
194
195 if ((wa_data->wa_bulkout_ept.bLength == 0) ||
196 (wa_data->wa_bulkin_ept.bLength == 0) ||
197 (wa_data->wa_intr_ept.bLength == 0)) {
198 USB_DPRINTF_L2(mask, handle,
199 "wusb_init_wa_data: the minimum endpoint set is not "
200 "supported");
201
202 return (USB_FAILURE);
203 }
204
205 /* parse the WA descriptor */
206 if ((rval = wusb_parse_wa_descr(&wa_data->wa_descr, altif_data)) !=
207 USB_SUCCESS) {
208 USB_DPRINTF_L2(mask, handle,
209 "wusb_init_wa_data: parse wire adapter class descr failed");
210
211 return (rval);
212 }
213 wa_data->wa_avail_blocks = wa_data->wa_descr.wRPipeMaxBlock;
214
215 wa_data->wa_dip = dip;
216
217 /* initialize rpipe handlers */
218 wa_data->wa_num_rpipes = wa_data->wa_descr.wNumRPipes;
219
220 wa_data->wa_rpipe_hdl = kmem_zalloc((wa_data->wa_num_rpipes *
221 sizeof (wusb_wa_rpipe_hdl_t)), KM_SLEEP);
222
223 /* init rpipes */
224 wusb_wa_rpipes_init(wa_data);
225
226 /* register callbacks */
227 wa_data->pipe_periodic_req = cbs->pipe_periodic_req;
228 wa_data->intr_cb = cbs->intr_cb;
229 wa_data->intr_exc_cb = cbs->intr_exc_cb;
230 wa_data->rpipe_xfer_cb = cbs->rpipe_xfer_cb;
231
232 mutex_init(&wa_data->wa_mutex, NULL, MUTEX_DRIVER, NULL);
233
234 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*wa_data));
235
236 return (USB_SUCCESS);
237 }
238
239 /* deinitialize data transfer related resources */
240 void
wusb_wa_data_fini(wusb_wa_data_t * wa_data)241 wusb_wa_data_fini(wusb_wa_data_t *wa_data)
242 {
243 mutex_enter(&wa_data->wa_mutex);
244 if (wa_data->wa_rpipe_hdl) {
245 wusb_wa_rpipes_fini(wa_data);
246 kmem_free(wa_data->wa_rpipe_hdl, wa_data->wa_num_rpipes *
247 sizeof (wusb_wa_rpipe_hdl_t));
248 }
249 mutex_exit(&wa_data->wa_mutex);
250 mutex_destroy(&wa_data->wa_mutex);
251 }
252
wusb_wa_dump_rpipe_descr(usb_wa_rpipe_descr_t * pd,uint_t mask,usb_log_handle_t handle)253 void wusb_wa_dump_rpipe_descr(usb_wa_rpipe_descr_t *pd, uint_t mask,
254 usb_log_handle_t handle)
255 {
256 USB_DPRINTF_L4(mask, handle, "RPipe Descriptor:\n"
257 "\tWRPipeIndex=%d wRequests=%d wBlocks=%d\n"
258 "\twMaxPacketSize=%d bHSHubAddress=%d\n"
259 "\tbHSHubPort=%d bSpeed=%d bDeviceAddress=%d\n"
260 "\tbEndpointAddress=0x%02x bDataSequence=%d\n"
261 "\tdwCurrentWindow=0x%08x bMaxDataSequence=%d",
262 pd->wRPipeIndex, pd->wRequests, pd->wBlocks, pd->wMaxPacketSize,
263 pd->wa_value.hwa_value.bMaxBurst,
264 pd->wa_value.hwa_value.bDeviceInfoIndex,
265 pd->bSpeed, pd->bDeviceAddress,
266 pd->bEndpointAddress, pd->bDataSequence, pd->dwCurrentWindow,
267 pd->bMaxDataSequence);
268
269 USB_DPRINTF_L4(mask, handle,
270 "(cont'ed)bInterval=%d bOverTheAirInterval=%d\n"
271 "\tbmAttribute=0x%02x bmCharacter=0x%02x\n"
272 "\tbmRetryOptions=0x%02x wNumTransactionErrors=%d\n",
273 pd->bInterval, pd->bOverTheAirInterval,
274 pd->bmAttribute, pd->bmCharacteristics, pd->bmRetryOptions,
275 pd->wNumTransactionErrors);
276
277 }
278
279 /* get rpipe descr of a certain index, refer to WUSB 1.0/8.3.1.4 */
280 int
wusb_wa_get_rpipe_descr(dev_info_t * dip,usb_pipe_handle_t ph,uint16_t idx,usb_wa_rpipe_descr_t * descr,uint_t mask,usb_log_handle_t handle)281 wusb_wa_get_rpipe_descr(dev_info_t *dip, usb_pipe_handle_t ph,
282 uint16_t idx, usb_wa_rpipe_descr_t *descr,
283 uint_t mask, usb_log_handle_t handle)
284 {
285 mblk_t *data = NULL;
286 usb_cr_t completion_reason;
287 usb_cb_flags_t cb_flags;
288 size_t count;
289 int rval;
290
291 /*
292 * This descriptor is critical for later operations to succeed.
293 * So, we must wait here.
294 */
295 rval = usb_pipe_sync_ctrl_xfer(dip, ph,
296 WA_CLASS_RPIPE_REQ_IN_TYPE,
297 USB_REQ_GET_DESCR,
298 USB_DESCR_TYPE_RPIPE << 8,
299 idx,
300 USB_RPIPE_DESCR_SIZE,
301 &data, 0,
302 &completion_reason, &cb_flags, 0);
303
304 if (rval != USB_SUCCESS) {
305 USB_DPRINTF_L2(mask, handle,
306 "wusb_wa_get_rpipe_descr: rval=%d, cr=%d, "
307 "cb=0x%x", rval, completion_reason, cb_flags);
308
309 goto done;
310 }
311
312 if (MBLKL(data) != USB_RPIPE_DESCR_SIZE) {
313 USB_DPRINTF_L2(mask, handle,
314 "wusb_wa_get_rpipe_descr: return size %d",
315 (int)MBLKL(data));
316 rval = USB_FAILURE;
317
318 goto done;
319 }
320
321 count = usb_parse_data("2c4s6cl6cs", data->b_rptr,
322 USB_RPIPE_DESCR_SIZE, descr, sizeof (usb_wa_rpipe_descr_t));
323
324 if (count == USB_PARSE_ERROR) {
325 USB_DPRINTF_L2(mask, handle,
326 "wusb_wa_get_rpipe_descr: parse error");
327 rval = USB_FAILURE;
328
329 goto done;
330 }
331
332 wusb_wa_dump_rpipe_descr(descr, mask, handle);
333
334 freemsg(data);
335 data = NULL;
336
337 return (USB_SUCCESS);
338
339 done:
340 if (data) {
341 freemsg(data);
342 }
343
344 return (rval);
345 }
346
347 /*
348 * Get All the RPipes' descriptors of an HWA
349 * - WA RPipe descriptor are not returned as part of the
350 * cofiguration descriptor. We have to get it separately.
351 * - See section 8.4.3.19 and 8.5.2.11
352 */
353 int
wusb_wa_get_rpipe_descrs(wusb_wa_data_t * wa_data,usb_pipe_handle_t ph,uint_t mask,usb_log_handle_t handle)354 wusb_wa_get_rpipe_descrs(wusb_wa_data_t *wa_data, usb_pipe_handle_t ph,
355 uint_t mask, usb_log_handle_t handle)
356 {
357 dev_info_t *dip = wa_data->wa_dip;
358 int i, rval;
359
360 if ((dip == NULL) || (ph == NULL)) {
361
362 return (USB_INVALID_ARGS);
363 }
364
365 /* called at initialization, no other threads yet */
366 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*wa_data));
367
368 for (i = 0; i < wa_data->wa_num_rpipes; i++) {
369 rval = wusb_wa_get_rpipe_descr(dip, ph, i,
370 &wa_data->wa_rpipe_hdl[i].rp_descr, mask, handle);
371
372 if (rval != USB_SUCCESS) {
373 USB_DPRINTF_L2(mask, handle,
374 "wusb_wa_get_rpipe_descrs: fail to get rpipe "
375 "descr for idx %d", i);
376
377 return (rval);
378 }
379 }
380 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*wa_data));
381
382 return (USB_SUCCESS);
383 }
384
385 /*
386 * Get Wire Adapter's Status
387 * See section 8.3.1.6
388 */
389 int
wusb_get_wa_status(wusb_wa_data_t * wa_data,usb_pipe_handle_t ph,uint32_t * status)390 wusb_get_wa_status(wusb_wa_data_t *wa_data, usb_pipe_handle_t ph,
391 uint32_t *status)
392 {
393 dev_info_t *dip = wa_data->wa_dip;
394 int rval = USB_SUCCESS;
395 mblk_t *data = NULL;
396 usb_cr_t completion_reason;
397 usb_cb_flags_t cb_flags;
398
399 if ((dip == NULL) || (ph == NULL)) {
400
401 return (USB_INVALID_ARGS);
402 }
403
404 rval = usb_pipe_sync_ctrl_xfer(dip, ph,
405 WUSB_CLASS_IF_REQ_IN_TYPE,
406 USB_REQ_GET_STATUS,
407 0,
408 wa_data->wa_ifno,
409 WA_GET_WA_STATUS_LEN,
410 &data, 0,
411 &completion_reason, &cb_flags, 0);
412
413 if (rval != USB_SUCCESS) {
414 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
415 "wusb_get_wa_status: can't retrieve status");
416
417 goto done;
418 }
419
420 *status = (*(data->b_rptr + 3) << 24) | (*(data->b_rptr + 2) << 16) |
421 (*(data->b_rptr + 1) << 8) | *(data->b_rptr);
422
423 done:
424 if (data) {
425 freemsg(data);
426 }
427
428 return (rval);
429 }
430
431 /*
432 * Reset WA
433 * See 8.3.1.9
434 */
435 int
wusb_wa_reset(wusb_wa_data_t * wa_data,usb_pipe_handle_t ph)436 wusb_wa_reset(wusb_wa_data_t *wa_data, usb_pipe_handle_t ph)
437 {
438 dev_info_t *dip = wa_data->wa_dip;
439 usb_cr_t completion_reason;
440 usb_cb_flags_t cb_flags;
441 int rval, i;
442 uint32_t status;
443
444 if ((dip == NULL) || (ph == NULL)) {
445
446 return (USB_INVALID_ARGS);
447 }
448
449 rval = usb_pipe_sync_ctrl_xfer(dip, ph,
450 WUSB_CLASS_IF_REQ_OUT_TYPE,
451 USB_REQ_SET_FEATURE,
452 WA_DEV_RESET,
453 wa_data->wa_ifno,
454 0,
455 NULL, 0,
456 &completion_reason, &cb_flags, 0);
457
458 if (rval != USB_SUCCESS) {
459 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
460 "wusb_wa_reset: can't reset wa, rval = %d, cr=%d", rval,
461 completion_reason);
462
463 return (rval);
464 }
465
466 for (i = 0; i < 10; i++) {
467 delay(drv_usectohz(50000));
468
469 rval = wusb_get_wa_status(wa_data, ph, &status);
470 if (rval != USB_SUCCESS) {
471 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
472 "wusb_wa_reset: can't get status, rval = %d",
473 rval);
474
475 return (rval);
476 }
477
478 if (!(status & WA_HC_RESET_IN_PROGRESS)) {
479
480 return (USB_SUCCESS);
481 }
482 }
483
484 return (USB_FAILURE);
485 }
486
487 /*
488 * Enable wire adapter.
489 * See 8.3.1.9
490 */
491 int
wusb_wa_enable(wusb_wa_data_t * wa_data,usb_pipe_handle_t ph)492 wusb_wa_enable(wusb_wa_data_t *wa_data, usb_pipe_handle_t ph)
493 {
494 dev_info_t *dip = wa_data->wa_dip;
495 usb_cr_t completion_reason;
496 usb_cb_flags_t cb_flags;
497 int rval, i;
498 uint32_t status;
499
500 if ((dip == NULL) || (ph == NULL)) {
501
502 return (USB_INVALID_ARGS);
503 }
504
505 rval = usb_pipe_sync_ctrl_xfer(dip, ph,
506 WUSB_CLASS_IF_REQ_OUT_TYPE,
507 USB_REQ_SET_FEATURE,
508 WA_DEV_ENABLE,
509 wa_data->wa_ifno,
510 0,
511 NULL, 0,
512 &completion_reason, &cb_flags, 0);
513
514 if (rval != USB_SUCCESS) {
515 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
516 "wusb_wa_enable: can't enable WA, rval = %d, cr=%d",
517 rval, completion_reason);
518
519 return (rval);
520 }
521
522 for (i = 0; i < 10; i++) {
523 delay(drv_usectohz(50000));
524
525 rval = wusb_get_wa_status(wa_data, ph, &status);
526 if (rval != USB_SUCCESS) {
527 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
528 "wusb_wa_enable: can't get status, rval = %d",
529 rval);
530
531 return (rval);
532 }
533
534 if (status & WA_HC_ENABLED) {
535
536 return (USB_SUCCESS);
537 }
538 }
539
540 return (USB_FAILURE);
541 }
542
543 /*
544 * Disable WA. Clear a fearture.
545 * See Section 8.3.1.3
546 */
547 int
wusb_wa_disable(wusb_wa_data_t * wa_data,usb_pipe_handle_t ph)548 wusb_wa_disable(wusb_wa_data_t *wa_data, usb_pipe_handle_t ph)
549 {
550 dev_info_t *dip = wa_data->wa_dip;
551 usb_cr_t completion_reason;
552 usb_cb_flags_t cb_flags;
553 int rval, i;
554 uint32_t status;
555
556 if ((dip == NULL) || (ph == NULL)) {
557
558 return (USB_INVALID_ARGS);
559 }
560
561 rval = usb_pipe_sync_ctrl_xfer(dip, ph,
562 WUSB_CLASS_IF_REQ_OUT_TYPE,
563 USB_REQ_CLEAR_FEATURE,
564 WA_DEV_ENABLE,
565 wa_data->wa_ifno,
566 0,
567 NULL, 0,
568 &completion_reason, &cb_flags, 0);
569
570 if (rval != USB_SUCCESS) {
571 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
572 "wusb_wa_disable: can't disable wa, rval = %d, cr = %d",
573 rval, completion_reason);
574
575 return (rval);
576 }
577
578 for (i = 0; i < 10; i++) {
579 delay(drv_usectohz(50000));
580
581 rval = wusb_get_wa_status(wa_data, ph, &status);
582 if (rval != USB_SUCCESS) {
583 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
584 "wusb_wa_disable: can't get status, rval = %d",
585 rval);
586
587 return (rval);
588 }
589
590 if (!(status & WA_HC_ENABLED)) {
591
592 return (USB_SUCCESS);
593 }
594 }
595
596 return (USB_FAILURE);
597 }
598
599 /*
600 * Open the two bulk endpoints and one interrupt IN endpoint, defined in
601 * a WA's data transfer interface. See 8.1.2
602 */
603 int
wusb_wa_open_pipes(wusb_wa_data_t * wa_data)604 wusb_wa_open_pipes(wusb_wa_data_t *wa_data)
605 {
606 int rval;
607
608 mutex_enter(&wa_data->wa_mutex);
609 if (wa_data->wa_state & WA_PIPES_OPENED) {
610 mutex_exit(&wa_data->wa_mutex);
611
612 return (USB_SUCCESS);
613 }
614 wa_data->wa_pipe_policy.pp_max_async_reqs = 1;
615 mutex_exit(&wa_data->wa_mutex);
616
617 rval = usb_pipe_open(wa_data->wa_dip, &wa_data->wa_intr_ept,
618 &wa_data->wa_pipe_policy, USB_FLAGS_SLEEP,
619 &wa_data->wa_intr_ph);
620 if (rval != USB_SUCCESS) {
621 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
622 "wusb_wa_open_pipes: can't open intr pipe, rval = %d",
623 rval);
624
625 return (rval);
626 }
627
628 rval = usb_pipe_open(wa_data->wa_dip, &wa_data->wa_bulkin_ept,
629 &wa_data->wa_pipe_policy, USB_FLAGS_SLEEP,
630 &wa_data->wa_bulkin_ph);
631 if (rval != USB_SUCCESS) {
632 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
633 "wusb_wa_open_pipes: can't open bulkin pipe, rval = %d",
634 rval);
635
636 usb_pipe_close(wa_data->wa_dip, wa_data->wa_intr_ph,
637 USB_FLAGS_SLEEP, NULL, NULL);
638 mutex_enter(&wa_data->wa_mutex);
639 wa_data->wa_intr_ph = NULL;
640 mutex_exit(&wa_data->wa_mutex);
641
642 return (rval);
643 }
644
645 rval = usb_pipe_open(wa_data->wa_dip, &wa_data->wa_bulkout_ept,
646 &wa_data->wa_pipe_policy, USB_FLAGS_SLEEP,
647 &wa_data->wa_bulkout_ph);
648
649 if (rval != USB_SUCCESS) {
650 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
651 "wusb_wa_open_pipes: can't open bulkout pipe, rval = %d",
652 rval);
653
654 usb_pipe_close(wa_data->wa_dip, wa_data->wa_intr_ph,
655 USB_FLAGS_SLEEP, NULL, NULL);
656 usb_pipe_close(wa_data->wa_dip, wa_data->wa_bulkin_ph,
657 USB_FLAGS_SLEEP, NULL, NULL);
658 mutex_enter(&wa_data->wa_mutex);
659 wa_data->wa_intr_ph = NULL;
660 wa_data->wa_bulkin_ph = NULL;
661 mutex_exit(&wa_data->wa_mutex);
662
663 return (rval);
664 }
665
666 mutex_enter(&wa_data->wa_mutex);
667 /* mark the state stopped until listening is started on the pipes */
668 wa_data->wa_intr_pipe_state = WA_PIPE_STOPPED;
669 wa_data->wa_bulkin_pipe_state = WA_PIPE_STOPPED;
670 /* no listening on this pipe, just mark it active */
671 wa_data->wa_bulkout_pipe_state = WA_PIPE_ACTIVE;
672 wa_data->wa_state |= WA_PIPES_OPENED;
673 mutex_exit(&wa_data->wa_mutex);
674
675 return (USB_SUCCESS);
676 }
677
678 /*
679 * Close WA's pipes.
680 */
681 void
wusb_wa_close_pipes(wusb_wa_data_t * wa_data)682 wusb_wa_close_pipes(wusb_wa_data_t *wa_data)
683 {
684 mutex_enter(&wa_data->wa_mutex);
685 if ((wa_data->wa_state & WA_PIPES_OPENED) == 0) {
686 mutex_exit(&wa_data->wa_mutex);
687
688 return;
689 }
690
691 mutex_exit(&wa_data->wa_mutex);
692
693 usb_pipe_close(wa_data->wa_dip, wa_data->wa_intr_ph,
694 USB_FLAGS_SLEEP, NULL, NULL);
695
696 if (wa_data->wa_bulkin_ph != NULL) {
697 usb_pipe_close(wa_data->wa_dip, wa_data->wa_bulkin_ph,
698 USB_FLAGS_SLEEP, NULL, NULL);
699 }
700
701 usb_pipe_close(wa_data->wa_dip, wa_data->wa_bulkout_ph,
702 USB_FLAGS_SLEEP, NULL, NULL);
703
704 mutex_enter(&wa_data->wa_mutex);
705 wa_data->wa_intr_ph = NULL;
706 wa_data->wa_bulkin_ph = NULL;
707 wa_data->wa_bulkout_ph = NULL;
708 wa_data->wa_intr_pipe_state = WA_PIPE_CLOSED;
709 wa_data->wa_bulkin_pipe_state = WA_PIPE_CLOSED;
710 wa_data->wa_bulkout_pipe_state = WA_PIPE_CLOSED;
711 wa_data->wa_state &= ~WA_PIPES_OPENED;
712 mutex_exit(&wa_data->wa_mutex);
713 }
714
715 /*
716 * start listening for transfer completion notifications or device
717 * notifications on the notification ept
718 */
719 int
wusb_wa_start_nep(wusb_wa_data_t * wa_data,usb_flags_t flag)720 wusb_wa_start_nep(wusb_wa_data_t *wa_data, usb_flags_t flag)
721 {
722 int rval;
723 usb_intr_req_t *reqp;
724
725 mutex_enter(&wa_data->wa_mutex);
726 if ((wa_data->wa_intr_ph == NULL) ||
727 (wa_data->wa_intr_pipe_state != WA_PIPE_STOPPED)) {
728 mutex_exit(&wa_data->wa_mutex);
729
730 return (USB_INVALID_PIPE);
731 }
732
733 reqp = usb_alloc_intr_req(wa_data->wa_dip, 0, flag);
734 if (!reqp) {
735 mutex_exit(&wa_data->wa_mutex);
736
737 return (USB_NO_RESOURCES);
738 }
739
740 reqp->intr_client_private = (usb_opaque_t)wa_data;
741 reqp->intr_attributes = USB_ATTRS_SHORT_XFER_OK |
742 USB_ATTRS_AUTOCLEARING;
743 reqp->intr_len = wa_data->wa_intr_ept.wMaxPacketSize;
744 reqp->intr_cb = wa_data->intr_cb;
745 reqp->intr_exc_cb = wa_data->intr_exc_cb;
746 mutex_exit(&wa_data->wa_mutex);
747
748 if ((rval = usb_pipe_intr_xfer(wa_data->wa_intr_ph, reqp,
749 flag)) != USB_SUCCESS) {
750 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
751 "wusb_wa_start_nep: intr xfer fail, rval = %d",
752 rval);
753
754 usb_free_intr_req(reqp);
755
756 return (rval);
757 }
758
759 mutex_enter(&wa_data->wa_mutex);
760 /* pipe state is active while the listening is on */
761 wa_data->wa_intr_pipe_state = WA_PIPE_ACTIVE;
762 mutex_exit(&wa_data->wa_mutex);
763
764 return (USB_SUCCESS);
765 }
766
767 /*
768 * stop the notification ept from listening
769 */
770 void
wusb_wa_stop_nep(wusb_wa_data_t * wa_data)771 wusb_wa_stop_nep(wusb_wa_data_t *wa_data)
772 {
773 mutex_enter(&wa_data->wa_mutex);
774 if ((wa_data->wa_intr_ph == NULL) ||
775 (wa_data->wa_intr_pipe_state != WA_PIPE_ACTIVE)) {
776 mutex_exit(&wa_data->wa_mutex);
777
778 return;
779 }
780 wa_data->wa_intr_pipe_state = WA_PIPE_STOPPED;
781 mutex_exit(&wa_data->wa_mutex);
782 /* stop intr in without closing the pipe */
783 usb_pipe_stop_intr_polling(wa_data->wa_intr_ph, USB_FLAGS_SLEEP);
784 }
785
786 /*
787 * allocate a rpipe for transfers on a pipe
788 * - Find a free RPipe
789 *
790 * For now, one rpipe is associated with only one usba pipe once
791 * the pipe is opened. In the future, the rpipe needs to be
792 * multiplexed between asynchronous endpoints
793 * input:
794 * type: 0 - ctrl, 1 - isoc, 2 - bulk, 3 - intr
795 *
796 */
797 /* ARGSUSED */
798 int
wusb_wa_get_rpipe(wusb_wa_data_t * wa_data,usb_pipe_handle_t ph,uint8_t type,wusb_wa_rpipe_hdl_t ** hdl,uint_t mask,usb_log_handle_t handle)799 wusb_wa_get_rpipe(wusb_wa_data_t *wa_data, usb_pipe_handle_t ph,
800 uint8_t type, wusb_wa_rpipe_hdl_t **hdl,
801 uint_t mask, usb_log_handle_t handle)
802 {
803 int i;
804 wusb_wa_rpipe_hdl_t *thdl;
805 uint8_t rp_type;
806 uint8_t ep_type = 1 << type;
807
808 *hdl = NULL;
809
810 mutex_enter(&wa_data->wa_mutex);
811 for (i = 0; i < wa_data->wa_num_rpipes; i++) {
812 /* find the first unused rpipe */
813 thdl = &wa_data->wa_rpipe_hdl[i];
814 mutex_enter(&thdl->rp_mutex);
815 if (thdl->rp_state != WA_RPIPE_STATE_FREE) {
816 mutex_exit(&thdl->rp_mutex);
817
818 continue;
819 }
820
821 /* check if the rpipe supports the ept transfer type */
822 rp_type = (thdl->rp_descr.bmCharacteristics &
823 USB_RPIPE_CHA_MASK);
824 if (rp_type & ep_type) {
825 thdl->rp_refcnt++;
826 thdl->rp_state = WA_RPIPE_STATE_IDLE;
827 thdl->rp_avail_reqs = thdl->rp_descr.wRequests;
828 *hdl = thdl;
829 mutex_exit(&thdl->rp_mutex);
830 mutex_exit(&wa_data->wa_mutex);
831
832 return (USB_SUCCESS);
833 }
834 mutex_exit(&thdl->rp_mutex);
835 }
836
837 USB_DPRINTF_L2(mask, handle,
838 "wusb_wa_get_rpipe: no matching rpipe is found");
839 mutex_exit(&wa_data->wa_mutex);
840
841 return (USB_FAILURE);
842 }
843
844 /*
845 * Decrease a RPipe's reference count.
846 * - if count == 0, mark it as free RPipe.
847 */
848 int
wusb_wa_release_rpipe(wusb_wa_data_t * wa,wusb_wa_rpipe_hdl_t * hdl)849 wusb_wa_release_rpipe(wusb_wa_data_t *wa, wusb_wa_rpipe_hdl_t *hdl)
850 {
851 if (hdl == NULL) {
852
853 return (USB_FAILURE);
854 }
855
856 mutex_enter(&wa->wa_mutex);
857 mutex_enter(&hdl->rp_mutex);
858 if (hdl->rp_refcnt == 0) {
859 mutex_exit(&hdl->rp_mutex);
860 mutex_exit(&wa->wa_mutex);
861
862 return (USB_FAILURE);
863 }
864
865 if (--hdl->rp_refcnt == 0) {
866 hdl->rp_state = WA_RPIPE_STATE_FREE;
867 }
868
869 if (hdl->rp_block_chg == 1) {
870 wa->wa_avail_blocks += hdl->rp_descr.wBlocks;
871 hdl->rp_descr.wBlocks = 0; /* to prevent misadd upon re-call */
872 hdl->rp_block_chg = 0;
873 }
874
875 mutex_exit(&hdl->rp_mutex);
876 mutex_exit(&wa->wa_mutex);
877
878 return (USB_SUCCESS);
879 }
880
881 /*
882 * Set a RPipe's Descriptor and make the rpipe configured
883 * See section 8.3.1.7
884 */
885 int
wusb_wa_set_rpipe_descr(dev_info_t * dip,usb_pipe_handle_t ph,usb_wa_rpipe_descr_t * rp_descr)886 wusb_wa_set_rpipe_descr(dev_info_t *dip, usb_pipe_handle_t ph,
887 usb_wa_rpipe_descr_t *rp_descr)
888 {
889 mblk_t *data = NULL;
890 usb_cr_t completion_reason;
891 usb_cb_flags_t cb_flags;
892 int rval;
893 uint8_t *p;
894
895 data = allocb_wait(USB_RPIPE_DESCR_SIZE, BPRI_LO, STR_NOSIG, NULL);
896 p = data->b_wptr;
897 p[0] = rp_descr->bLength;
898 p[1] = rp_descr->bDescriptorType;
899 p[2] = rp_descr->wRPipeIndex;
900 p[3] = rp_descr->wRPipeIndex >> 8;
901 p[4] = rp_descr->wRequests;
902 p[5] = rp_descr->wRequests >> 8;
903 p[6] = rp_descr->wBlocks;
904 p[7] = rp_descr->wBlocks >> 8;
905 p[8] = rp_descr->wMaxPacketSize;
906 p[9] = rp_descr->wMaxPacketSize >> 8;
907 p[10] = rp_descr->wa_value.hwa_value.bMaxBurst;
908 p[11] = rp_descr->wa_value.hwa_value.bDeviceInfoIndex;
909 p[12] = rp_descr->bSpeed;
910 p[13] = rp_descr->bDeviceAddress;
911 p[14] = rp_descr->bEndpointAddress;
912 p[15] = rp_descr->bDataSequence;
913 p[16] = rp_descr->dwCurrentWindow;
914 p[17] = rp_descr->dwCurrentWindow >> 8;
915 p[18] = rp_descr->dwCurrentWindow >> 16;
916 p[19] = rp_descr->dwCurrentWindow >> 24;
917 p[20] = rp_descr->bMaxDataSequence;
918 p[21] = rp_descr->bInterval;
919 p[22] = rp_descr->bOverTheAirInterval;
920 p[23] = rp_descr->bmAttribute;
921 p[24] = rp_descr->bmCharacteristics;
922 p[25] = rp_descr->bmRetryOptions;
923 p[26] = rp_descr->wNumTransactionErrors;
924 p[27] = rp_descr->wNumTransactionErrors >> 8;
925
926 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
927 "wusb_wa_set_rpipe_descr: RPipe Descriptors");
928 wusb_wa_dump_rpipe_descr(rp_descr, DPRINT_MASK_WHCDI, whcdi_log_handle);
929
930 rval = usb_pipe_sync_ctrl_xfer(dip, ph,
931 WA_CLASS_RPIPE_REQ_OUT_TYPE,
932 USB_REQ_SET_DESCR,
933 USB_DESCR_TYPE_RPIPE << 8,
934 rp_descr->wRPipeIndex,
935 USB_RPIPE_DESCR_SIZE,
936 &data, 0,
937 &completion_reason, &cb_flags, 0);
938
939 freemsg(data);
940
941 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
942 "wusb_wa_set_rpipe_descr: rval = %d", rval);
943
944 return (rval);
945 }
946
947 /* ept companion descr for the default ctrl pipe, refer to WUSB 1.0/4.8.1 */
948 usb_ep_comp_descr_t ep_comp0 = {
949 sizeof (usb_ep_comp_descr_t), USB_DESCR_TYPE_WIRELESS_EP_COMP,
950 1, 2,
951 };
952
953 /*
954 * Get the Endpoint Companion Descriptor for the pipe
955 * ph_data - the specified pipe
956 * ep_comp - the companion descriptor returned
957 */
958 int
wusb_wa_get_ep_comp_descr(usba_pipe_handle_data_t * ph_data,usb_ep_comp_descr_t * ep_comp)959 wusb_wa_get_ep_comp_descr(usba_pipe_handle_data_t *ph_data,
960 usb_ep_comp_descr_t *ep_comp)
961 {
962 usb_ep_descr_t *ep = &ph_data->p_ep;
963 usb_client_dev_data_t *dev_data;
964 usb_if_data_t *if_data;
965 usb_alt_if_data_t *altif_data;
966 usb_ep_data_t *ep_data;
967 int i, j;
968
969 /* default ctrl endpoint */
970 if (ep->bEndpointAddress == 0) {
971 *ep_comp = ep_comp0;
972
973 return (USB_SUCCESS);
974 }
975
976 if (usb_get_dev_data(ph_data->p_dip, &dev_data,
977 USB_PARSE_LVL_IF, 0) != USB_SUCCESS) {
978
979 return (USB_FAILURE);
980 }
981
982 /* retrieve ept companion descr from the dev data */
983 if_data = &dev_data->dev_curr_cfg->cfg_if[dev_data->dev_curr_if];
984 for (i = 0; i < if_data->if_n_alt; i++) {
985 altif_data = &if_data->if_alt[i];
986 for (j = 0; j < altif_data->altif_n_ep; j++) {
987 ep_data = &altif_data->altif_ep[j];
988 if (memcmp(&ep_data->ep_descr, ep,
989 sizeof (usb_ep_descr_t)) == 0) {
990 *ep_comp = ep_data->ep_comp_descr;
991 usb_free_dev_data(ph_data->p_dip, dev_data);
992
993 return (USB_SUCCESS);
994 }
995 }
996 }
997 usb_free_dev_data(ph_data->p_dip, dev_data);
998
999 return (USB_FAILURE);
1000 }
1001
1002 /* to check if the specified PHY speed is supported by the device */
1003 int
wusb_wa_is_speed_valid(usba_device_t * ud,uint8_t speed)1004 wusb_wa_is_speed_valid(usba_device_t *ud, uint8_t speed)
1005 {
1006 usb_uwb_cap_descr_t *uwb_descr = ud->usb_wireless_data->uwb_descr;
1007 uint8_t valid_spd[WUSB_PHY_TX_RATE_RES] = {
1008 WUSB_DATA_RATE_BIT_53, WUSB_DATA_RATE_BIT_106,
1009 WUSB_DATA_RATE_BIT_160, WUSB_DATA_RATE_BIT_200,
1010 WUSB_DATA_RATE_BIT_320, WUSB_DATA_RATE_BIT_400,
1011 WUSB_DATA_RATE_BIT_480, 0
1012 };
1013
1014 if (speed >= WUSB_PHY_TX_RATE_RES) {
1015
1016 return (0);
1017 }
1018
1019 /* this speed is not supported by the device */
1020 if (valid_spd[speed] != (uwb_descr->wPHYRates & valid_spd[speed])) {
1021
1022 return (0);
1023 }
1024
1025 return (1);
1026 }
1027
1028 /*
1029 * Set up a RPipe
1030 * - Associate a RPipe and a pipe handle. Hence, an endpoint has
1031 * RPipe to transfer data.
1032 * - Set this RPipe to bDeviceAddress:bEndpointAddress
1033 *
1034 * wa - wa data
1035 * ph - wa's default control pipe
1036 * ph_data - client driver's usba pipe to be opened
1037 * hdl - RPipe handle
1038 */
1039 int
wusb_wa_set_rpipe_target(dev_info_t * dip,wusb_wa_data_t * wa,usb_pipe_handle_t ph,usba_pipe_handle_data_t * ph_data,wusb_wa_rpipe_hdl_t * hdl)1040 wusb_wa_set_rpipe_target(dev_info_t *dip, wusb_wa_data_t *wa,
1041 usb_pipe_handle_t ph, usba_pipe_handle_data_t *ph_data,
1042 wusb_wa_rpipe_hdl_t *hdl)
1043 {
1044 int rval;
1045 usb_ep_comp_descr_t ep_comp;
1046 usb_ep_descr_t *ep = &ph_data->p_ep;
1047 usba_device_t *usba_device;
1048 uint8_t rp_status;
1049 usb_wa_descr_t *wa_desc = &wa->wa_descr;
1050 uint16_t blockcnt;
1051 uint16_t maxsize;
1052 uint16_t seg_len;
1053
1054
1055 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1056 "wusb_wa_set_rpipe_target: ph_data = 0x%p rp_hdl = 0x%p",
1057 (void*)ph_data, (void*)hdl);
1058
1059 /* Get client device's Endpoint companion descriptor */
1060 if ((rval = wusb_wa_get_ep_comp_descr(ph_data, &ep_comp)) !=
1061 USB_SUCCESS) {
1062 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1063 "wusb_wa_set_rpipe_target: get companion ep descr failed,"
1064 " rval = %d", rval);
1065
1066 return (rval);
1067 }
1068
1069 /* set the rpipe to unconfigured state */
1070 if ((rval = wusb_wa_rpipe_reset(dip, ph_data, hdl, 0)) != USB_SUCCESS) {
1071 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1072 "wusb_wa_set_rpipe_target: reset rpipe failed, rval = %d",
1073 rval);
1074
1075 return (rval);
1076 }
1077
1078 if ((rval = wusb_wa_get_rpipe_status(dip, ph,
1079 hdl->rp_descr.wRPipeIndex, &rp_status)) != USB_SUCCESS) {
1080 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1081 "wusb_wa_set_rpipe_target: get rpipe status failed, "
1082 "rval = %d", rval);
1083
1084 return (rval);
1085 }
1086
1087 if (rp_status & WA_RPIPE_CONFIGURED) {
1088 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1089 "wusb_wa_set_rpipe_target: reset rpipe unsuccessful");
1090
1091 return (USB_FAILURE);
1092 }
1093
1094 mutex_enter(&wa->wa_mutex);
1095 usba_device = usba_get_usba_device(ph_data->p_dip);
1096
1097 mutex_enter(&hdl->rp_mutex);
1098
1099 /* should be 0x200 for default ctrl pipe, refer to wusb 1.0/4.8.1 */
1100 hdl->rp_descr.wMaxPacketSize = ep->wMaxPacketSize;
1101
1102 /*
1103 * set rpipe descr values
1104 *
1105 * Try to use an average block value first. If it's too small,
1106 * then try to allocate the minimum block size to accomodate one
1107 * packet. If the required number of block is not available, return
1108 * failure.
1109 */
1110 if (hdl->rp_descr.wBlocks == 0) {
1111 blockcnt = wa_desc->wRPipeMaxBlock/wa_desc->wNumRPipes;
1112 maxsize = 1 << (wa_desc->bRPipeBlockSize - 1);
1113 seg_len = blockcnt * maxsize;
1114
1115 /* alloc enough blocks to accomodate one packet */
1116 if (ep->wMaxPacketSize > seg_len) {
1117 blockcnt = (ep->wMaxPacketSize + maxsize -1)/maxsize;
1118 }
1119
1120 /* WA don't have so many blocks to fulfill this reqirement */
1121 if (wa->wa_avail_blocks < blockcnt) {
1122 mutex_exit(&hdl->rp_mutex);
1123 mutex_exit(&wa->wa_mutex);
1124
1125 return (USB_FAILURE);
1126 }
1127
1128 /* we're satisfied */
1129 hdl->rp_descr.wBlocks = blockcnt;
1130 hdl->rp_block_chg = 1; /* the wBlocks is changed */
1131 wa->wa_avail_blocks -= blockcnt;
1132 }
1133 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1134 "wusb_wa_set_rpipe_target: wBlocks=%d, maxblock=%d, numR=%d, av=%d",
1135 hdl->rp_descr.wBlocks, wa_desc->wRPipeMaxBlock, wa_desc->wNumRPipes,
1136 wa->wa_avail_blocks);
1137
1138 hdl->rp_descr.wa_value.hwa_value.bMaxBurst = ep_comp.bMaxBurst;
1139
1140 /*
1141 * DEVICE INDEX
1142 * device info index should be zero based, refer
1143 * to WUSB 1.0/8.5.3.7
1144 */
1145 hdl->rp_descr.wa_value.hwa_value.bDeviceInfoIndex =
1146 usba_device->usb_port - 1;
1147
1148 /*
1149 * default ctrl pipe uses PHY base signaling rate
1150 * refer to wusb 1.0/4.8.1
1151 */
1152 if (ep->bEndpointAddress == 0) {
1153 hdl->rp_descr.bSpeed = WUSB_PHY_TX_RATE_53;
1154 } else {
1155 if (wusb_wa_is_speed_valid(usba_device, rp_default_speed)) {
1156 hdl->rp_descr.bSpeed = rp_default_speed;
1157 } else {
1158 /* use a must-supported speed */
1159 hdl->rp_descr.bSpeed = WUSB_PHY_TX_RATE_106;
1160 }
1161 }
1162 hdl->rp_descr.bDeviceAddress = usba_device->usb_addr;
1163 hdl->rp_descr.bEndpointAddress = ep->bEndpointAddress;
1164 hdl->rp_descr.bDataSequence = 0;
1165 hdl->rp_descr.dwCurrentWindow = 1;
1166 hdl->rp_descr.bMaxDataSequence = ep_comp.bMaxSequence - 1;
1167 hdl->rp_descr.bInterval = ep->bInterval;
1168 hdl->rp_descr.bOverTheAirInterval = ep_comp.bOverTheAirInterval;
1169 hdl->rp_descr.bmAttribute = ep->bmAttributes & 0x03;
1170 hdl->rp_descr.bmRetryOptions = 0; /* keep retrying */
1171 hdl->rp_descr.wNumTransactionErrors = 0;
1172 mutex_exit(&hdl->rp_mutex);
1173
1174 mutex_exit(&wa->wa_mutex);
1175
1176 /* set rpipe descr */
1177 rval = wusb_wa_set_rpipe_descr(dip, ph, &hdl->rp_descr);
1178 if (rval != USB_SUCCESS) {
1179 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1180 "wusb_wa_set_rpipe_target: set rpipe descr failed, "
1181 "rval = %d", rval);
1182
1183 return (rval);
1184 }
1185
1186 /* check rpipe status, must be configured and idle */
1187 if ((rval = wusb_wa_get_rpipe_status(dip, ph,
1188 hdl->rp_descr.wRPipeIndex, &rp_status)) != USB_SUCCESS) {
1189 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1190 "wusb_wa_set_rpipe_target: get rpipe status failed, "
1191 "rval = %d", rval);
1192
1193 return (rval);
1194 }
1195
1196 if (rp_status != (WA_RPIPE_CONFIGURED | WA_RPIPE_IDLE)) {
1197 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1198 "wusb_wa_set_rpipe_target: set rpipe descr unsuccessful");
1199
1200 return (USB_FAILURE);
1201 }
1202
1203 return (rval);
1204 }
1205
1206 /*
1207 * Abort a RPipe
1208 * - See Section 8.3.1.1
1209 * - Aborts all transfers pending on the given pipe
1210 */
1211 int
wusb_wa_rpipe_abort(dev_info_t * dip,usb_pipe_handle_t ph,wusb_wa_rpipe_hdl_t * hdl)1212 wusb_wa_rpipe_abort(dev_info_t *dip, usb_pipe_handle_t ph,
1213 wusb_wa_rpipe_hdl_t *hdl)
1214 {
1215 usb_cr_t completion_reason;
1216 usb_cb_flags_t cb_flags;
1217 int rval;
1218
1219 mutex_enter(&hdl->rp_mutex);
1220
1221 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1222 "wusb_wa_rpipe_abort: rp_hdl = 0x%p", (void *)hdl);
1223
1224 /* only abort when there is active transfer */
1225 if (hdl->rp_state != WA_RPIPE_STATE_ACTIVE) {
1226 mutex_exit(&hdl->rp_mutex);
1227
1228 return (USB_SUCCESS);
1229 }
1230
1231 mutex_exit(&hdl->rp_mutex);
1232 rval = usb_pipe_sync_ctrl_xfer(dip, ph,
1233 WA_CLASS_RPIPE_REQ_OUT_TYPE,
1234 WA_REQ_ABORT_RPIPE,
1235 0,
1236 hdl->rp_descr.wRPipeIndex,
1237 0,
1238 NULL, 0,
1239 &completion_reason, &cb_flags, 0);
1240
1241 if (rval != USB_SUCCESS) {
1242 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1243 "wusb_wa_rpipe_abort: abort failed, rval = %d", rval);
1244
1245 return (rval);
1246 }
1247
1248 return (USB_SUCCESS);
1249 }
1250
1251 /*
1252 * Clear status on the remote device's endpoint, specifically clear the
1253 * RPipe's target endpoint sequence number. See 4.5.3, 4.6.4 and Tab.8-49
1254 * for reference of data sequence.
1255 *
1256 * NOTE AGAIN:
1257 * The device endpoint will not respond to host request if the RPipe is
1258 * reset or re-targeted, while device endpoint is not reset!
1259 */
1260 void
wusb_wa_clear_dev_ep(usba_pipe_handle_data_t * ph)1261 wusb_wa_clear_dev_ep(usba_pipe_handle_data_t *ph)
1262 {
1263 uint8_t ept_addr;
1264
1265 if (ph == NULL) {
1266 return;
1267 }
1268
1269 ept_addr = ph->p_ep.bEndpointAddress;
1270
1271 USB_DPRINTF_L4(PRINT_MASK_HCDI, whcdi_log_handle,
1272 "wusb_wa_clear_dev_ep:clear endpoint = 0x%02x", ept_addr);
1273 if (ept_addr != 0) {
1274 /* only clear non-default endpoints */
1275 (void) usb_clr_feature(ph->p_dip, USB_DEV_REQ_RCPT_EP, 0,
1276 ept_addr, USB_FLAGS_SLEEP, NULL, NULL);
1277 }
1278 }
1279
1280 /*
1281 * Reset a RPipe
1282 * - Reset a RPipe to a known state
1283 * - Pending transfers must be drained or aborted before this
1284 * operation.
1285 * - See Section 8.3.1.10
1286 *
1287 * dip - the WA's devinfo
1288 * ph - RPipe's targeted remote device's endpoint pipe.
1289 * hdl - RPipe's handle
1290 *
1291 * flag = 1, reset the RPipe descriptor to its initial state and
1292 * also clear remote device endpoint
1293 * = 0, not reset the RPipe descriptor. Caller should use 0 flag
1294 * if it's the first time to open a pipe, because we don't have
1295 * a valid ph yet before successfully opening a pipe by using
1296 * usb_pipe_open().
1297 */
1298 int
wusb_wa_rpipe_reset(dev_info_t * dip,usba_pipe_handle_data_t * ph,wusb_wa_rpipe_hdl_t * hdl,int flag)1299 wusb_wa_rpipe_reset(dev_info_t *dip, usba_pipe_handle_data_t *ph,
1300 wusb_wa_rpipe_hdl_t *hdl, int flag)
1301 {
1302 int rval = 0;
1303 usb_cr_t completion_reason;
1304 usb_cb_flags_t cb_flags = 0;
1305 usb_pipe_handle_t default_ph;
1306
1307 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1308 "wusb_wa_rpipe_reset: rp_hdl = 0x%p, ep=0x%02x, flag = %d",
1309 (void *)hdl, ph->p_ep.bEndpointAddress, flag);
1310
1311 /* get WA's default pipe */
1312 default_ph = usba_get_dflt_pipe_handle(dip);
1313
1314 rval = usb_pipe_sync_ctrl_xfer(dip, default_ph,
1315 WA_CLASS_RPIPE_REQ_OUT_TYPE,
1316 WA_REQ_RESET_RPIPE,
1317 0,
1318 hdl->rp_descr.wRPipeIndex,
1319 0,
1320 NULL, 0,
1321 &completion_reason, &cb_flags, 0);
1322
1323 if (rval != USB_SUCCESS) {
1324 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1325 "wusb_wa_rpipe_reset: reset failed, rval=%d"
1326 " cr=%d cb=0x%02x",
1327 rval, (int)completion_reason, (int)cb_flags);
1328
1329 return (rval);
1330 }
1331
1332 if (flag == 0) {
1333 /* do nothing else, just return, the rpipe is unconfigured */
1334 return (USB_SUCCESS);
1335 }
1336
1337 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1338 "wusb_wa_rpipe_reset: need to clear dev pipe and reset RP descr");
1339
1340 /* set rpipe descr and make the rpipe configured */
1341 rval = wusb_wa_set_rpipe_descr(dip, default_ph, &hdl->rp_descr);
1342 if (rval != USB_SUCCESS) {
1343 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1344 "wusb_wa_rpipe_reset: set descr failed, rval = %d", rval);
1345
1346 return (rval);
1347 }
1348
1349 mutex_enter(&hdl->rp_mutex);
1350 hdl->rp_avail_reqs = hdl->rp_descr.wRequests;
1351 if (hdl->rp_state == WA_RPIPE_STATE_ERROR) {
1352 hdl->rp_state = WA_RPIPE_STATE_IDLE;
1353 }
1354 mutex_exit(&hdl->rp_mutex);
1355
1356 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1357 "wusb_wa_rpipe_reset: end");
1358
1359 return (USB_SUCCESS);
1360 }
1361
1362 /* get rpipe status, refer to WUSB 1.0/8.3.1.5 */
1363 int
wusb_wa_get_rpipe_status(dev_info_t * dip,usb_pipe_handle_t ph,uint16_t idx,uint8_t * status)1364 wusb_wa_get_rpipe_status(dev_info_t *dip, usb_pipe_handle_t ph, uint16_t idx,
1365 uint8_t *status)
1366 {
1367 mblk_t *data = NULL;
1368 usb_cr_t completion_reason;
1369 usb_cb_flags_t cb_flags;
1370 int rval;
1371
1372 rval = usb_pipe_sync_ctrl_xfer(dip, ph,
1373 WA_CLASS_RPIPE_REQ_IN_TYPE,
1374 USB_REQ_GET_STATUS,
1375 0,
1376 idx,
1377 1,
1378 &data, 0,
1379 &completion_reason, &cb_flags, 0);
1380
1381 if (rval != USB_SUCCESS) {
1382 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1383 "wusb_wa_get_rpipe_status: fail, rval=%d, cr=%d, "
1384 "cb=0x%x", rval, completion_reason, cb_flags);
1385 } else {
1386 *status = *data->b_rptr;
1387 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1388 "wusb_wa_get_rpipe_status: status = %x", *status);
1389 freemsg(data);
1390 }
1391
1392 return (rval);
1393 }
1394
1395 /*
1396 * WA specific operations end
1397 */
1398
1399 /* Transfer related routines */
1400 wusb_wa_trans_wrapper_t *
wusb_wa_alloc_tw(wusb_wa_data_t * wa_data,wusb_wa_rpipe_hdl_t * hdl,usba_pipe_handle_data_t * ph,uint32_t datalen,usb_flags_t usb_flags)1401 wusb_wa_alloc_tw(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl,
1402 usba_pipe_handle_data_t *ph, uint32_t datalen, usb_flags_t usb_flags)
1403 {
1404 uint_t seg_count;
1405 uint32_t seg_len, maxpktsize;
1406 wusb_wa_trans_wrapper_t *wr;
1407
1408 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1409 "wusb_wa_alloc_tw: ph = 0x%p rp_hdl = 0x%p ",
1410 (void*)ph, (void*)hdl);
1411
1412 mutex_enter(&hdl->rp_mutex);
1413
1414 /* compute the rpipe buffer size */
1415 seg_len = hdl->rp_descr.wBlocks *
1416 (1 << (wa_data->wa_descr.bRPipeBlockSize - 1));
1417 maxpktsize = hdl->rp_descr.wMaxPacketSize;
1418 mutex_exit(&hdl->rp_mutex);
1419
1420 if (seg_len < maxpktsize) {
1421 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1422 "wusb_wa_alloc_tw: fail, segment len(%d) "
1423 "< wMaxPacketSize(%d) ", seg_len, maxpktsize);
1424
1425 return (NULL);
1426 }
1427
1428 /*
1429 * the transfer length for each segment is a multiple of the
1430 * wMaxPacketSize except the last segment, and the length
1431 * cannot exceed the rpipe buffer size
1432 */
1433 seg_len = (seg_len / maxpktsize) * maxpktsize;
1434 if (datalen) {
1435 seg_count = (datalen + seg_len - 1) / seg_len;
1436 } else {
1437 seg_count = 1;
1438 }
1439
1440 if (seg_count > WA_MAX_SEG_COUNT) {
1441 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1442 "wusb_wa_alloc_tw: fail, seg count(%d)"
1443 " > Max allowed number(%d) ", seg_count, WA_MAX_SEG_COUNT);
1444
1445 return (NULL);
1446 }
1447
1448 if ((wr = kmem_zalloc(sizeof (wusb_wa_trans_wrapper_t),
1449 KM_NOSLEEP)) == NULL) {
1450
1451 return (NULL);
1452 }
1453
1454 /* allocation, not visible to other threads */
1455 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*wr));
1456
1457 if ((wr->wr_seg_array = kmem_zalloc(sizeof (wusb_wa_seg_t) * seg_count,
1458 KM_NOSLEEP)) == NULL) {
1459 kmem_free(wr, sizeof (wusb_wa_trans_wrapper_t));
1460
1461 return (NULL);
1462 }
1463
1464 /* assign a unique ID for each transfer */
1465 wr->wr_id = WA_GET_ID(wr);
1466 if (wr->wr_id == 0) {
1467 kmem_free(wr->wr_seg_array, sizeof (wusb_wa_seg_t) *
1468 seg_count);
1469 kmem_free(wr, sizeof (wusb_wa_trans_wrapper_t));
1470
1471 return (NULL);
1472 }
1473
1474 wr->wr_ph = ph;
1475 wr->wr_rp = hdl;
1476 wr->wr_wa_data = wa_data;
1477 wr->wr_flags = usb_flags;
1478 wr->wr_nsegs = (uint8_t)seg_count;
1479 wr->wr_max_seglen = seg_len;
1480 wr->wr_has_aborted = 0;
1481
1482 cv_init(&wr->wr_cv, NULL, CV_DRIVER, NULL);
1483
1484 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1485 "wusb_wa_alloc_tw: wr = 0x%p id = %x nseg = %d", (void*)wr,
1486 wr->wr_id, wr->wr_nsegs);
1487
1488 return (wr);
1489 }
1490
1491 /* create transfer wrapper for a ctrl request, return NULL on failure */
1492 wusb_wa_trans_wrapper_t *
wusb_wa_create_ctrl_wrapper(wusb_wa_data_t * wa_data,wusb_wa_rpipe_hdl_t * hdl,usba_pipe_handle_data_t * ph,usb_ctrl_req_t * ctrl_reqp,usb_flags_t usb_flags)1493 wusb_wa_create_ctrl_wrapper(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl,
1494 usba_pipe_handle_data_t *ph, usb_ctrl_req_t *ctrl_reqp,
1495 usb_flags_t usb_flags)
1496 {
1497 wusb_wa_trans_wrapper_t *wr = NULL;
1498
1499 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1500 "wusb_wa_create_ctrl_wrapper: ph = 0x%p rp_hdl = 0x%p reqp = 0x%p",
1501 (void *)ph, (void*)hdl, (void *)ctrl_reqp);
1502
1503 wr = wusb_wa_alloc_tw(wa_data, hdl, ph, ctrl_reqp->ctrl_wLength,
1504 usb_flags);
1505 if (wr == NULL) {
1506 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1507 "wusb_wa_create_ctrl_wrapper: fail to create tw for %p",
1508 (void *)ctrl_reqp);
1509
1510 return (NULL);
1511 }
1512
1513 /* not visible to other threads yet */
1514 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*wr));
1515
1516 if (ctrl_reqp->ctrl_bmRequestType & USB_DEV_REQ_DEV_TO_HOST) {
1517 wr->wr_dir = WA_DIR_IN;
1518 } else {
1519 wr->wr_dir = WA_DIR_OUT;
1520 }
1521
1522 wr->wr_type = WA_XFER_REQ_TYPE_CTRL;
1523 wr->wr_reqp = (usb_opaque_t)ctrl_reqp;
1524 wr->wr_timeout = (ctrl_reqp->ctrl_timeout == 0) ?
1525 WA_RPIPE_DEFAULT_TIMEOUT : ctrl_reqp->ctrl_timeout;
1526 wr->wr_cb = wusb_wa_handle_ctrl;
1527
1528 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1529 "wusb_wa_create_ctrl_wrapper: wr = 0x%p nseg = %d", (void *)wr,
1530 wr->wr_nsegs);
1531
1532 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*wr));
1533
1534 return (wr);
1535 }
1536
1537 /*
1538 * create transfer wrapper for a bulk request, return NULL on failure
1539 * - split the request into multiple segments
1540 * - every segment is N * wMaxPacketSize
1541 * - segment length <= bRPipeBlockSize * wBlocks
1542 */
1543 wusb_wa_trans_wrapper_t *
wusb_wa_create_bulk_wrapper(wusb_wa_data_t * wa_data,wusb_wa_rpipe_hdl_t * hdl,usba_pipe_handle_data_t * ph,usb_bulk_req_t * bulk_reqp,usb_flags_t usb_flags)1544 wusb_wa_create_bulk_wrapper(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl,
1545 usba_pipe_handle_data_t *ph, usb_bulk_req_t *bulk_reqp,
1546 usb_flags_t usb_flags)
1547 {
1548 wusb_wa_trans_wrapper_t *wr = NULL;
1549 usb_ep_descr_t *epdt = &ph->p_ep;
1550
1551 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1552 "wusb_wa_create_bulk_wrapper: ph = 0x%p rp_hdl = 0x%p reqp = 0x%p",
1553 (void *)ph, (void *)hdl, (void *)bulk_reqp);
1554
1555 wr = wusb_wa_alloc_tw(wa_data, hdl, ph, bulk_reqp->bulk_len,
1556 usb_flags);
1557 if (wr == NULL) {
1558 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1559 "wusb_wa_create_bulk_wrapper: fail to create tw for %p",
1560 (void *)bulk_reqp);
1561
1562 return (NULL);
1563 }
1564
1565 /* no locking needed */
1566 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*wr));
1567
1568 if ((epdt->bEndpointAddress & USB_EP_DIR_MASK) == USB_EP_DIR_IN) {
1569 wr->wr_dir = WA_DIR_IN;
1570 } else {
1571 wr->wr_dir = WA_DIR_OUT;
1572 }
1573
1574 wr->wr_type = WA_XFER_REQ_TYPE_BULK_INTR;
1575 wr->wr_reqp = (usb_opaque_t)bulk_reqp;
1576 wr->wr_timeout = (bulk_reqp->bulk_timeout == 0) ?
1577 WA_RPIPE_DEFAULT_TIMEOUT : bulk_reqp->bulk_timeout;
1578 wr->wr_cb = wusb_wa_handle_bulk;
1579
1580 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1581 "wusb_wa_create_bulk_wrapper: wr = 0x%p nseg = %d", (void *)wr,
1582 wr->wr_nsegs);
1583
1584 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*wr));
1585
1586 return (wr);
1587 }
1588
1589 /*
1590 * create transfer wrapper for a intr request, return NULL on failure
1591 * - split the request into multiple segments
1592 * - every segment is N * wMaxPacketSize
1593 * - segment length <= bRPipeBlockSize * wBlocks
1594 */
1595 wusb_wa_trans_wrapper_t *
wusb_wa_create_intr_wrapper(wusb_wa_data_t * wa_data,wusb_wa_rpipe_hdl_t * hdl,usba_pipe_handle_data_t * ph,usb_intr_req_t * intr_reqp,usb_flags_t usb_flags)1596 wusb_wa_create_intr_wrapper(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl,
1597 usba_pipe_handle_data_t *ph, usb_intr_req_t *intr_reqp,
1598 usb_flags_t usb_flags)
1599 {
1600 wusb_wa_trans_wrapper_t *wr;
1601 usb_ep_descr_t *epdt = &ph->p_ep;
1602 uint32_t tw_len;
1603 usb_intr_req_t *curr_intr_reqp;
1604
1605 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1606 "wusb_wa_create_intr_wrapper: ph = 0x%p rp_hdl = 0x%p reqp = 0x%p",
1607 (void *)ph, (void *)hdl, (void *)intr_reqp);
1608
1609 if ((ph->p_ep.bEndpointAddress & USB_EP_DIR_MASK) == USB_EP_DIR_IN) {
1610 tw_len = (intr_reqp->intr_len) ? intr_reqp->intr_len :
1611 ph->p_ep.wMaxPacketSize;
1612
1613 /* duplicate client's intr request */
1614 curr_intr_reqp = usba_hcdi_dup_intr_req(ph->p_dip,
1615 (usb_intr_req_t *)intr_reqp, tw_len, usb_flags);
1616 if (curr_intr_reqp == NULL) {
1617 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1618 "wusb_wa_create_intr_wrapper: fail to create reqp");
1619
1620 return (NULL);
1621 }
1622
1623 } else { /* OUT */
1624 tw_len = intr_reqp->intr_len;
1625 curr_intr_reqp = intr_reqp;
1626 }
1627
1628 wr = wusb_wa_alloc_tw(wa_data, hdl, ph, tw_len, usb_flags);
1629 if (wr == NULL) {
1630 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1631 "wusb_wa_create_bulk_wrapper: fail to create tw for %p",
1632 (void *)intr_reqp);
1633
1634 return (NULL);
1635 }
1636
1637 /* no locking needed */
1638 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*wr));
1639
1640 if ((epdt->bEndpointAddress & USB_EP_DIR_MASK) == USB_EP_DIR_IN) {
1641 wr->wr_dir = WA_DIR_IN;
1642 } else {
1643 wr->wr_dir = WA_DIR_OUT;
1644 }
1645
1646 wr->wr_type = WA_XFER_REQ_TYPE_BULK_INTR;
1647
1648 wr->wr_reqp = (usb_opaque_t)curr_intr_reqp;
1649
1650 wr->wr_timeout = (intr_reqp->intr_timeout == 0) ?
1651 WA_RPIPE_DEFAULT_TIMEOUT : intr_reqp->intr_timeout;
1652 wr->wr_cb = wusb_wa_handle_intr;
1653
1654 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1655 "wusb_wa_create_intr_wrapper: wr = 0x%p nseg = %d", (void *)wr,
1656 wr->wr_nsegs);
1657
1658 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*wr));
1659
1660 return (wr);
1661 }
1662
1663 /*
1664 * Setup the transfer request structure for a segment
1665 * len = transfer request structure length
1666 * - see section 8.3.3.1 and 8.3.3.2
1667 */
1668 void
wusb_wa_setup_trans_req(wusb_wa_trans_wrapper_t * wr,wusb_wa_seg_t * seg,uint8_t len)1669 wusb_wa_setup_trans_req(wusb_wa_trans_wrapper_t *wr, wusb_wa_seg_t *seg,
1670 uint8_t len)
1671 {
1672 mblk_t *data = seg->seg_trans_reqp->bulk_data;
1673 uint8_t *trans_req = data->b_wptr;
1674
1675 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1676 "wusb_wa_setup_trans_req: wr = 0x%p len = %d segnum = 0x%x",
1677 (void*)wr, len, seg->seg_num);
1678
1679 bzero(trans_req, len);
1680 trans_req[0] = len;
1681 trans_req[1] = wr->wr_type;
1682 trans_req[2] = wr->wr_rp->rp_descr.wRPipeIndex;
1683 trans_req[3] = wr->wr_rp->rp_descr.wRPipeIndex >> 8;
1684 trans_req[4] = seg->seg_id; /* dwTransferID */
1685 trans_req[5] = seg->seg_id >> 8;
1686 trans_req[6] = seg->seg_id >> 16;
1687 trans_req[7] = seg->seg_id >> 24;
1688 trans_req[8] = seg->seg_len;
1689 trans_req[9] = seg->seg_len >> 8;
1690 trans_req[10] = seg->seg_len >> 16;
1691 trans_req[11] = seg->seg_len >> 24;
1692 trans_req[12] = seg->seg_num;
1693
1694 /*
1695 * 8-byte setupdata only for the first segment of a ctrl
1696 * transfer request
1697 */
1698 if (wr->wr_type == WA_XFER_REQ_TYPE_CTRL) {
1699 usb_ctrl_req_t *ctrl_req = (usb_ctrl_req_t *)wr->wr_reqp;
1700
1701 /* what is the unsecured flag for ? */
1702 trans_req[13] = wr->wr_dir | WA_CTRL_SECRT_REGULAR;
1703 if ((seg->seg_num & 0x7f) == 0) {
1704 /* only send baSetupDate on the first segment */
1705 trans_req[16] = ctrl_req->ctrl_bmRequestType;
1706 trans_req[17] = ctrl_req->ctrl_bRequest;
1707 trans_req[18] = ctrl_req->ctrl_wValue;
1708 trans_req[19] = ctrl_req->ctrl_wValue >> 8;
1709 trans_req[20] = ctrl_req->ctrl_wIndex;
1710 trans_req[21] = ctrl_req->ctrl_wIndex >> 8;
1711 trans_req[22] = ctrl_req->ctrl_wLength;
1712 trans_req[23] = ctrl_req->ctrl_wLength >> 8;
1713
1714 }
1715 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1716 "wusb_wa_setup_trans_req: Ctrl segment = %02x",
1717 seg->seg_num);
1718
1719 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1720 "wusb_wa_setup_trans_req: Ctrl Setup Data: "
1721 "%02x %02x %02x %02x %02x %02x %02x %02x",
1722 trans_req[16], trans_req[17], trans_req[18],
1723 trans_req[19], trans_req[20], trans_req[21],
1724 trans_req[22], trans_req[23]);
1725 }
1726 data->b_wptr += len;
1727 }
1728
1729 /*
1730 * WA bulk pipe callbacks
1731 * wusb_wa_trans_bulk_cb: transfer request stage normal callback
1732 * wusb_wa_trans_bulk_exc_cb: transfer request stage exceptional callback
1733 *
1734 * wusb_wa_data_bulk_cb: transfer data stage normal callback
1735 * wusb_wa_data_bulk_exc_cb: transfer data stage exceptional callback
1736 *
1737 * see WUSB1.0 8.3.3 for details
1738 */
1739 void
wusb_wa_trans_bulk_cb(usb_pipe_handle_t ph,struct usb_bulk_req * req)1740 wusb_wa_trans_bulk_cb(usb_pipe_handle_t ph, struct usb_bulk_req *req)
1741 {
1742 wusb_wa_seg_t *seg = (wusb_wa_seg_t *)req->bulk_client_private;
1743 wusb_wa_trans_wrapper_t *wr = (wusb_wa_trans_wrapper_t *)seg->seg_wr;
1744
1745 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1746 "wusb_wa_trans_bulk_cb: ph=%p req=0x%p cr=%d", (void*)ph,
1747 (void*)req, req->bulk_completion_reason);
1748
1749 mutex_enter(&wr->wr_rp->rp_mutex);
1750
1751 /* callback returned, this seg can be freed */
1752 seg->seg_trans_req_state = 0;
1753
1754 cv_signal(&seg->seg_trans_cv);
1755 mutex_exit(&wr->wr_rp->rp_mutex);
1756 }
1757
1758 void
wusb_wa_trans_bulk_exc_cb(usb_pipe_handle_t ph,struct usb_bulk_req * req)1759 wusb_wa_trans_bulk_exc_cb(usb_pipe_handle_t ph, struct usb_bulk_req *req)
1760 {
1761 wusb_wa_seg_t *seg = (wusb_wa_seg_t *)req->bulk_client_private;
1762 wusb_wa_trans_wrapper_t *wr = (wusb_wa_trans_wrapper_t *)seg->seg_wr;
1763
1764 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1765 "wusb_wa_trans_bulk_exc_cb: ph=%p req=0x%p cr=%d", (void *)ph,
1766 (void *)req, req->bulk_completion_reason);
1767
1768 mutex_enter(&wr->wr_rp->rp_mutex);
1769
1770 /* callback returned, this seg can be freed */
1771 seg->seg_trans_req_state = 0;
1772
1773 cv_signal(&seg->seg_trans_cv);
1774 mutex_exit(&wr->wr_rp->rp_mutex);
1775 }
1776
1777 void
wusb_wa_data_bulk_cb(usb_pipe_handle_t ph,struct usb_bulk_req * req)1778 wusb_wa_data_bulk_cb(usb_pipe_handle_t ph, struct usb_bulk_req *req)
1779 {
1780 wusb_wa_seg_t *seg = (wusb_wa_seg_t *)req->bulk_client_private;
1781 wusb_wa_trans_wrapper_t *wr = (wusb_wa_trans_wrapper_t *)seg->seg_wr;
1782
1783 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1784 "wusb_wa_data_bulk_cb: ph=%p req=0x%p cr=%d", (void *)ph,
1785 (void *)req, req->bulk_completion_reason);
1786
1787 mutex_enter(&wr->wr_rp->rp_mutex);
1788
1789 /* callback returned, this seg can be freed */
1790 seg->seg_data_req_state = 0;
1791
1792 cv_signal(&seg->seg_data_cv);
1793 mutex_exit(&wr->wr_rp->rp_mutex);
1794 }
1795
1796 void
wusb_wa_data_bulk_exc_cb(usb_pipe_handle_t ph,struct usb_bulk_req * req)1797 wusb_wa_data_bulk_exc_cb(usb_pipe_handle_t ph, struct usb_bulk_req *req)
1798 {
1799 wusb_wa_seg_t *seg = (wusb_wa_seg_t *)req->bulk_client_private;
1800 wusb_wa_trans_wrapper_t *wr = (wusb_wa_trans_wrapper_t *)seg->seg_wr;
1801
1802 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1803 "wusb_wa_data_bulk_exc_cb: ph=%p req=0x%p cr=%d", (void *)ph,
1804 (void *)req, req->bulk_completion_reason);
1805
1806 mutex_enter(&wr->wr_rp->rp_mutex);
1807
1808 /* callback returned, this seg can be freed */
1809 seg->seg_data_req_state = 0;
1810
1811 cv_signal(&seg->seg_data_cv);
1812 mutex_exit(&wr->wr_rp->rp_mutex);
1813 }
1814
1815 /*
1816 * Setup all the transfer request segments, including the transfer request
1817 * stage and data stage for out transfer.
1818 * len = total size of payload data to transfer
1819 * - for every segment, allocate a new bulk request for Transfer
1820 * Request. Fill the request with the segment and wrapper data.
1821 * - for every segment, allocate a new bulk request for data stage.
1822 *
1823 */
1824 int
wusb_wa_setup_segs(wusb_wa_data_t * wa_data,wusb_wa_trans_wrapper_t * wr,uint32_t len,mblk_t * data)1825 wusb_wa_setup_segs(wusb_wa_data_t *wa_data, wusb_wa_trans_wrapper_t *wr,
1826 uint32_t len, mblk_t *data)
1827 {
1828 int i, rval;
1829 wusb_wa_seg_t *seg;
1830 usb_bulk_req_t *trans_req, *data_req;
1831 uint8_t trans_req_len;
1832 uint8_t *p;
1833 wusb_wa_rpipe_hdl_t *hdl = NULL;
1834
1835 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1836 "wusb_wa_setup_segs: wr = 0x%p len = %d data = 0x%p", (void *)wr,
1837 len, (void *)data);
1838
1839 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*wr));
1840
1841 if (wr == NULL) {
1842 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1843 "wusb_wa_setup_segs: invalid wr");
1844
1845 return (USB_INVALID_ARGS);
1846 }
1847
1848 if ((len != 0) && (data != NULL)) {
1849 p = data->b_rptr;
1850 }
1851
1852 for (i = 0; i < wr->wr_nsegs; i++) {
1853 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*seg));
1854
1855 seg = &wr->wr_seg_array[i];
1856 cv_init(&seg->seg_trans_cv, NULL, CV_DRIVER, NULL);
1857 cv_init(&seg->seg_data_cv, NULL, CV_DRIVER, NULL);
1858 seg->seg_wr = wr;
1859 seg->seg_num = (uint8_t)i; /* 0-based */
1860 seg->seg_len = wr->wr_max_seglen;
1861 if (i == (wr->wr_nsegs - 1)) {
1862 seg->seg_num |= 0x80; /* last segment */
1863 seg->seg_len = len;
1864 } else {
1865 len -= seg->seg_len;
1866 }
1867
1868 /*
1869 * set seg_id, all segs are the same or unique ??
1870 * now make all segs share the same id
1871 */
1872 seg->seg_id = wr->wr_id;
1873
1874 /* alloc transfer request and set values */
1875 switch (wr->wr_type) {
1876 case WA_XFER_REQ_TYPE_CTRL:
1877 trans_req_len = WA_CTRL_REQ_LEN;
1878 break;
1879 case WA_XFER_REQ_TYPE_BULK_INTR:
1880 trans_req_len = WA_BULK_INTR_REQ_LEN;
1881
1882 break;
1883 default:
1884 trans_req_len = 0;
1885 break;
1886 }
1887
1888 if (trans_req_len == 0) {
1889 rval = USB_NOT_SUPPORTED;
1890 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1891 "wusb_wa_setup_segs: trans len error");
1892
1893 goto error;
1894 }
1895
1896 /* alloc transfer request for the ith seg */
1897 trans_req = usb_alloc_bulk_req(wa_data->wa_dip,
1898 trans_req_len, USB_FLAGS_NOSLEEP);
1899 if (trans_req == NULL) {
1900 rval = USB_NO_RESOURCES;
1901 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1902 "wusb_wa_setup_segs: can't alloc_bulk_req");
1903
1904 goto error;
1905 }
1906
1907 /* setup the ith transfer request */
1908 trans_req->bulk_len = trans_req_len;
1909 trans_req->bulk_timeout = WA_RPIPE_DEFAULT_TIMEOUT;
1910 trans_req->bulk_attributes = USB_ATTRS_AUTOCLEARING;
1911 trans_req->bulk_cb = wusb_wa_trans_bulk_cb;
1912 trans_req->bulk_exc_cb = wusb_wa_trans_bulk_exc_cb;
1913 trans_req->bulk_client_private = (usb_opaque_t)seg;
1914
1915 seg->seg_trans_reqp = trans_req;
1916 wusb_wa_setup_trans_req(wr, seg, trans_req_len);
1917
1918 if (seg->seg_len != 0) {
1919 /* alloc request for data stage */
1920 data_req = usb_alloc_bulk_req(wa_data->wa_dip,
1921 seg->seg_len, USB_FLAGS_NOSLEEP);
1922 if (data_req == NULL) {
1923 rval = USB_NO_RESOURCES;
1924 USB_DPRINTF_L2(DPRINT_MASK_WHCDI,
1925 whcdi_log_handle,
1926 "wusb_wa_setup_segs: can't alloc_bulk_req"
1927 " for data");
1928
1929 goto error;
1930 }
1931
1932 /* setup the ith data transfer */
1933 data_req->bulk_len = seg->seg_len;
1934 data_req->bulk_timeout = WA_RPIPE_DEFAULT_TIMEOUT;
1935 data_req->bulk_attributes = USB_ATTRS_AUTOCLEARING;
1936
1937 data_req->bulk_cb = wusb_wa_data_bulk_cb;
1938 data_req->bulk_exc_cb = wusb_wa_data_bulk_exc_cb;
1939 data_req->bulk_client_private = (usb_opaque_t)seg;
1940
1941 seg->seg_data_reqp = data_req;
1942
1943 /*
1944 * Copy data from client driver to bulk request for
1945 * an OUT endpoint.
1946 */
1947 if (wr->wr_dir == WA_DIR_OUT) {
1948 ASSERT(data != NULL);
1949 /*
1950 * cannot increase data->b_rptr,
1951 * or scsa2usb panic at bulk out
1952 */
1953 ASSERT((intptr_t)((uintptr_t)data->b_wptr -
1954 (uintptr_t)p) >= seg->seg_len);
1955 bcopy(p,
1956 data_req->bulk_data->b_wptr,
1957 seg->seg_len);
1958 p += seg->seg_len;
1959
1960 data_req->bulk_data->b_wptr += seg->seg_len;
1961 }
1962 }
1963
1964 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*seg));
1965 }
1966
1967 /* zero timeout means to wait infinitely */
1968 /*
1969 * if this is the first time this WR to be transfered,
1970 * we'll add it to its rpipe handle's timeout queue
1971 */
1972 if (wr->wr_timeout > 0) {
1973 hdl = wr->wr_rp;
1974
1975 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1976 "wusb_wa_setup_segs: timeout=%d", wr->wr_timeout);
1977
1978 mutex_enter(&hdl->rp_mutex);
1979
1980 /* Add this new wrapper to the head of RPipe's timeout list */
1981 if (hdl->rp_timeout_list) {
1982 wr->wr_timeout_next = hdl->rp_timeout_list;
1983 }
1984
1985 hdl->rp_timeout_list = wr;
1986
1987 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*wr));
1988
1989 mutex_exit(&hdl->rp_mutex);
1990 }
1991
1992 return (USB_SUCCESS);
1993
1994 error:
1995 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1996 "wusb_wa_setup_segs: fail, rval = %d", rval);
1997
1998 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*wr));
1999
2000 mutex_enter(&hdl->rp_mutex);
2001 wusb_wa_free_segs(wr);
2002 mutex_exit(&hdl->rp_mutex);
2003
2004 return (rval);
2005 }
2006
2007 /* allocate transfer wrapper and setup all transfer segments */
2008 wusb_wa_trans_wrapper_t *
wusb_wa_alloc_ctrl_resources(wusb_wa_data_t * wa_data,wusb_wa_rpipe_hdl_t * hdl,usba_pipe_handle_data_t * ph,usb_ctrl_req_t * ctrl_reqp,usb_flags_t usb_flags)2009 wusb_wa_alloc_ctrl_resources(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl,
2010 usba_pipe_handle_data_t *ph, usb_ctrl_req_t *ctrl_reqp,
2011 usb_flags_t usb_flags)
2012 {
2013 wusb_wa_trans_wrapper_t *wr;
2014
2015 wr = wusb_wa_create_ctrl_wrapper(wa_data, hdl, ph, ctrl_reqp,
2016 usb_flags);
2017
2018 if (wr == NULL) {
2019 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2020 "wusb_wa_alloc_ctrl_resources failed");
2021
2022 return (NULL);
2023 }
2024
2025 if (wusb_wa_setup_segs(wa_data, wr, ctrl_reqp->ctrl_wLength,
2026 ctrl_reqp->ctrl_data) != USB_SUCCESS) {
2027 wusb_wa_free_trans_wrapper(wr);
2028
2029 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2030 "wusb_wa_alloc_ctrl_resources failed to setup segs");
2031
2032 return (NULL);
2033 }
2034
2035 return (wr);
2036 }
2037
2038 /* allocate transfer wrapper and setup all transfer segments */
2039 wusb_wa_trans_wrapper_t *
wusb_wa_alloc_bulk_resources(wusb_wa_data_t * wa_data,wusb_wa_rpipe_hdl_t * hdl,usba_pipe_handle_data_t * ph,usb_bulk_req_t * bulk_reqp,usb_flags_t usb_flags)2040 wusb_wa_alloc_bulk_resources(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl,
2041 usba_pipe_handle_data_t *ph, usb_bulk_req_t *bulk_reqp,
2042 usb_flags_t usb_flags)
2043 {
2044 wusb_wa_trans_wrapper_t *wr;
2045
2046 wr = wusb_wa_create_bulk_wrapper(wa_data, hdl, ph, bulk_reqp,
2047 usb_flags);
2048
2049 if (wr == NULL) {
2050
2051 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2052 "wusb_wa_alloc_bulk_resources: failed to create wr");
2053
2054 return (NULL);
2055 }
2056
2057 if (wusb_wa_setup_segs(wa_data, wr, bulk_reqp->bulk_len,
2058 bulk_reqp->bulk_data) != USB_SUCCESS) {
2059 wusb_wa_free_trans_wrapper(wr);
2060
2061 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2062 "wusb_wa_alloc_bulk_resources:failed to setup segs");
2063 return (NULL);
2064 }
2065
2066 return (wr);
2067 }
2068
2069 /*
2070 * allocate transfer wrapper and setup all transfer segments
2071 * if it's an IN request, duplicate it.
2072 */
2073 wusb_wa_trans_wrapper_t *
wusb_wa_alloc_intr_resources(wusb_wa_data_t * wa_data,wusb_wa_rpipe_hdl_t * hdl,usba_pipe_handle_data_t * ph,usb_intr_req_t * intr_reqp,usb_flags_t usb_flags)2074 wusb_wa_alloc_intr_resources(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl,
2075 usba_pipe_handle_data_t *ph, usb_intr_req_t *intr_reqp,
2076 usb_flags_t usb_flags)
2077 {
2078 wusb_wa_trans_wrapper_t *wr;
2079
2080 wr = wusb_wa_create_intr_wrapper(wa_data, hdl, ph, intr_reqp,
2081 usb_flags);
2082
2083 if (wr == NULL) {
2084 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2085 "wusb_wa_alloc_intr_resources: failed to create wr");
2086
2087 return (NULL);
2088 }
2089
2090 if (wusb_wa_setup_segs(wa_data, wr, intr_reqp->intr_len,
2091 intr_reqp->intr_data) != USB_SUCCESS) {
2092 wusb_wa_free_trans_wrapper(wr);
2093
2094 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2095 "wusb_wa_alloc_intr_resources: failed to setup segs");
2096
2097 return (NULL);
2098 }
2099
2100 return (wr);
2101 }
2102
2103 /* free the bulk request structures for all segments */
2104 void
wusb_wa_free_segs(wusb_wa_trans_wrapper_t * wr)2105 wusb_wa_free_segs(wusb_wa_trans_wrapper_t *wr)
2106 {
2107 int i;
2108 wusb_wa_seg_t *seg;
2109
2110 ASSERT(mutex_owned(&wr->wr_rp->rp_mutex));
2111
2112 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
2113 "wusb_wa_free_segs: wr = 0x%p, segs=%p", (void *)wr,
2114 (void *)wr->wr_seg_array);
2115
2116 if (wr->wr_seg_array == NULL) {
2117 return;
2118 }
2119
2120
2121 for (i = 0; i < wr->wr_nsegs; i++) {
2122 seg = &wr->wr_seg_array[i];
2123
2124 if (seg->seg_trans_reqp != NULL) {
2125 while (seg->seg_trans_req_state == 1) {
2126 cv_wait(&seg->seg_trans_cv,
2127 &wr->wr_rp->rp_mutex);
2128 }
2129 /* free the bulk req for transfer request */
2130 usb_free_bulk_req(seg->seg_trans_reqp);
2131 seg->seg_trans_reqp = NULL;
2132 }
2133
2134 if (seg->seg_data_reqp != NULL) {
2135 while (seg->seg_data_req_state == 1) {
2136 cv_wait(&seg->seg_data_cv,
2137 &wr->wr_rp->rp_mutex);
2138 }
2139 /* free the bulk req for data transfer */
2140 usb_free_bulk_req(seg->seg_data_reqp);
2141 seg->seg_data_reqp = NULL;
2142 }
2143
2144 cv_destroy(&seg->seg_trans_cv);
2145 cv_destroy(&seg->seg_data_cv);
2146 }
2147
2148 kmem_free(wr->wr_seg_array, sizeof (wusb_wa_seg_t) * wr->wr_nsegs);
2149
2150 wr->wr_seg_array = NULL;
2151 wr->wr_nsegs = 0;
2152 }
2153
2154 /* free transfer wrapper */
2155 void
wusb_wa_free_trans_wrapper(wusb_wa_trans_wrapper_t * wr)2156 wusb_wa_free_trans_wrapper(wusb_wa_trans_wrapper_t *wr)
2157 {
2158 wusb_wa_rpipe_hdl_t *hdl = NULL;
2159
2160 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
2161 "wusb_wa_free_trans_wrapper: wr = 0x%p", (void *)wr);
2162
2163 if (wr == NULL) {
2164 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
2165 "wusb_wa_free_trans_wrapper: NULL wrapper");
2166 return;
2167 }
2168
2169 hdl = wr->wr_rp;
2170
2171 mutex_enter(&hdl->rp_mutex);
2172
2173 wusb_wa_remove_wr_from_timeout_list(hdl, wr);
2174
2175 if (wr->wr_seg_array != NULL) {
2176 wusb_wa_free_segs(wr);
2177 kmem_free(wr->wr_seg_array,
2178 sizeof (wusb_wa_seg_t) * wr->wr_nsegs);
2179 }
2180
2181 if (wr->wr_id != 0) {
2182 WA_FREE_ID(wr->wr_id);
2183 }
2184
2185 cv_destroy(&wr->wr_cv);
2186
2187 kmem_free(wr, sizeof (wusb_wa_trans_wrapper_t));
2188
2189 mutex_exit(&hdl->rp_mutex);
2190 }
2191
2192 /* abort a transfer, refer to WUSB 1.0/8.3.3.5 */
2193 void
wusb_wa_abort_req(wusb_wa_data_t * wa_data,wusb_wa_trans_wrapper_t * wr,uint32_t id)2194 wusb_wa_abort_req(wusb_wa_data_t *wa_data, wusb_wa_trans_wrapper_t *wr,
2195 uint32_t id)
2196 {
2197 usb_bulk_req_t *req;
2198 uint8_t *p;
2199 int rval;
2200
2201 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
2202 "wusb_wa_abort_req: wr = 0x%p", (void *)wr);
2203
2204 req = usb_alloc_bulk_req(wa_data->wa_dip, WA_ABORT_REQ_LEN,
2205 USB_FLAGS_NOSLEEP);
2206 if (req == NULL) {
2207 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2208 "wusb_wa_abort_req: alloc bulk req failed");
2209
2210 return;
2211 }
2212
2213 req->bulk_len = WA_ABORT_REQ_LEN;
2214 req->bulk_timeout = WA_RPIPE_DEFAULT_TIMEOUT;
2215 req->bulk_attributes = USB_ATTRS_AUTOCLEARING;
2216 p = req->bulk_data->b_wptr;
2217 p[0] = WA_ABORT_REQ_LEN;
2218 p[1] = WA_XFER_REQ_TYPE_ABORT;
2219 p[2] = wr->wr_rp->rp_descr.wRPipeIndex;
2220 p[3] = wr->wr_rp->rp_descr.wRPipeIndex >> 8;
2221 p[4] = (uint8_t)id;
2222 p[5] = (uint8_t)(id >> 8);
2223 p[6] = (uint8_t)(id >> 16);
2224 p[7] = (uint8_t)(id >> 24);
2225 req->bulk_data->b_wptr += WA_ABORT_REQ_LEN;
2226
2227 mutex_exit(&wr->wr_rp->rp_mutex);
2228 rval = usb_pipe_bulk_xfer(wa_data->wa_bulkout_ph, req,
2229 USB_FLAGS_SLEEP);
2230 mutex_enter(&wr->wr_rp->rp_mutex);
2231 if (rval != USB_SUCCESS) {
2232 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2233 "wusb_wa_abort_req: send abort req failed, rval = %d",
2234 rval);
2235 }
2236 usb_free_bulk_req(req);
2237 }
2238
2239 static void
wusb_wa_remove_wr_from_timeout_list(wusb_wa_rpipe_hdl_t * hdl,wusb_wa_trans_wrapper_t * tw)2240 wusb_wa_remove_wr_from_timeout_list(wusb_wa_rpipe_hdl_t *hdl,
2241 wusb_wa_trans_wrapper_t *tw)
2242 {
2243 wusb_wa_trans_wrapper_t *prev, *next;
2244 int ret = 0; /* debug only */
2245
2246 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2247 "remove_wr_from_timeout_list: %p", (void *)tw);
2248
2249 if (hdl->rp_timeout_list) {
2250 if (hdl->rp_timeout_list == tw) {
2251 hdl->rp_timeout_list = tw->wr_timeout_next;
2252 tw->wr_timeout_next = NULL;
2253 ret = 1;
2254 } else {
2255 prev = hdl->rp_timeout_list;
2256 next = prev->wr_timeout_next;
2257
2258 while (next && (next != tw)) {
2259 prev = next;
2260 next = next->wr_timeout_next;
2261 }
2262
2263 if (next == tw) {
2264 prev->wr_timeout_next = next->wr_timeout_next;
2265 tw->wr_timeout_next = NULL;
2266 ret = 1;
2267 }
2268 }
2269 }
2270
2271 /* debug only */
2272 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
2273 "remove_wr_from_timeout_list: %p, on the list:%d",
2274 (void *)tw, ret);
2275 }
2276
2277 /* start timer on a rpipe */
2278 void
wusb_wa_start_xfer_timer(wusb_wa_rpipe_hdl_t * hdl)2279 wusb_wa_start_xfer_timer(wusb_wa_rpipe_hdl_t *hdl)
2280 {
2281 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
2282 "wusb_wa_start_xfer_timer: rpipe hdl = 0x%p", (void *)hdl);
2283
2284 ASSERT(mutex_owned(&hdl->rp_mutex));
2285
2286 /*
2287 * wr_timeout is in Seconds
2288 */
2289 /*
2290 * Start the rpipe's timer only if currently timer is not
2291 * running and if there are transfers on the rpipe.
2292 * The timer will be per rpipe.
2293 *
2294 * The RPipe's timer expires every 1s. When this timer expires, the
2295 * handler gets called and will decrease every pending transfer
2296 * wrapper's timeout value.
2297 */
2298 if ((!hdl->rp_timer_id) && (hdl->rp_timeout_list)) {
2299 hdl->rp_timer_id = timeout(wusb_wa_xfer_timeout_handler,
2300 (void *)hdl, drv_usectohz(1000000));
2301 }
2302 }
2303
2304 /* transfer timeout handler */
2305 void
wusb_wa_xfer_timeout_handler(void * arg)2306 wusb_wa_xfer_timeout_handler(void *arg)
2307 {
2308 wusb_wa_rpipe_hdl_t *hdl = (wusb_wa_rpipe_hdl_t *)arg;
2309 wusb_wa_trans_wrapper_t *wr = NULL;
2310 wusb_wa_trans_wrapper_t *next = NULL;
2311 wusb_wa_data_t *wa_data = NULL;
2312 int rval;
2313 uint8_t rp_status;
2314 wusb_wa_trans_wrapper_t *expire_list = NULL;
2315
2316 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
2317 "wusb_wa_xfer_timeout_handler: rphdl = 0x%p ", (void *)hdl);
2318
2319 mutex_enter(&hdl->rp_mutex);
2320
2321 /*
2322 * Check whether still timeout handler is valid.
2323 */
2324 if (hdl->rp_timer_id != 0) {
2325
2326 /* Reset the timer id to zero */
2327 hdl->rp_timer_id = 0;
2328 } else {
2329 mutex_exit(&hdl->rp_mutex);
2330
2331 return;
2332 }
2333
2334 /*
2335 * Check each transfer wrapper on this RPipe's timeout queue
2336 * Actually, due to USBA's limitation and queueing, there's only one
2337 * usba_request submitted to HCD at a specific pipe. Hence, only one
2338 * WR can be on this RPipe's list at any moment.
2339 */
2340 wr = hdl->rp_timeout_list;
2341 while (wr) {
2342 next = wr->wr_timeout_next;
2343
2344 USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
2345 "wusb_wa_xfer_timeout_handler: rhdl=0x%p"
2346 " wr=0x%p(to=%d) nxt=0x%p", (void *)hdl, (void *)wr,
2347 wr->wr_timeout, (void *)next);
2348
2349 /*
2350 * 1 second passed. Decrease every transfer wrapper's
2351 * timeout value. If the timeout < 0 (expired), remove this
2352 * wrapper from the timeout list and put it on the
2353 * expire_list.
2354 */
2355 wr->wr_timeout--;
2356 if (wr->wr_timeout <= 0) {
2357 USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
2358 "wusb_wa_xfer_timeout_handler: 0x%p time out",
2359 (void *)wr);
2360
2361 /* remove it from the rpipe's timeout list */
2362 wusb_wa_remove_wr_from_timeout_list(hdl, wr);
2363
2364 /* put it on the expired list */
2365 wr->wr_timeout_next = expire_list;
2366 expire_list = wr;
2367
2368 }
2369
2370 wr = next;
2371 }
2372
2373 /* Restart this RPipe's timer */
2374 wusb_wa_start_xfer_timer(hdl);
2375
2376 /* timeout handling */
2377 wr = expire_list;
2378 while (wr) {
2379 next = wr->wr_timeout_next;
2380
2381 /* other thread shouldn't continue processing it */
2382 wr->wr_state = WR_TIMEOUT;
2383
2384 wa_data = wr->wr_wa_data;
2385
2386 mutex_exit(&hdl->rp_mutex);
2387 rval = wusb_wa_get_rpipe_status(wa_data->wa_dip,
2388 wa_data->wa_default_pipe, hdl->rp_descr.wRPipeIndex,
2389 &rp_status);
2390 mutex_enter(&hdl->rp_mutex);
2391
2392 if (rval != USB_SUCCESS) {
2393 /* reset WA perhaps? */
2394 hdl->rp_state = WA_RPIPE_STATE_ERROR;
2395 hdl->rp_curr_wr = NULL;
2396 mutex_exit(&hdl->rp_mutex);
2397 wr->wr_cb(wa_data, wr, USB_CR_TIMEOUT, 1);
2398 mutex_enter(&hdl->rp_mutex);
2399
2400 USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
2401 "wusb_wa_xfer_timeout_handler: fail to get"
2402 " rpipe status, rval = %d", rval);
2403
2404 goto continuing;
2405 }
2406 USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
2407 "wusb_wa_xfer_timeout_handler: rpstat=0x%02x, wr=0x%p,"
2408 " wr_state=%d", rp_status, (void *)wr, wr->wr_state);
2409
2410 if (!(rp_status & WA_RPIPE_IDLE)) {
2411 /*
2412 * If RP is not idle, then it must be processing this WR.
2413 * Abort this request to make the RPipe idle.
2414 */
2415 USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
2416 "wusb_wa_xfer_timeout_handler: rp not idle");
2417
2418 mutex_exit(&hdl->rp_mutex);
2419 rval = wusb_wa_rpipe_abort(wa_data->wa_dip,
2420 wa_data->wa_default_pipe, hdl);
2421 mutex_enter(&hdl->rp_mutex);
2422
2423 USB_DPRINTF_L3(DPRINT_MASK_WHCDI,
2424 whcdi_log_handle,
2425 "wusb_wa_xfer_timeout_handler: abort rpipe"
2426 " fail rval = %d", rval);
2427
2428 if (rval == 0) {
2429 /*
2430 * wait for the result thread to get
2431 * Aborted result. If this wr hasn't been
2432 * aborted, wait it.
2433 */
2434 if ((wr->wr_has_aborted == 0) &&
2435 (cv_reltimedwait(&wr->wr_cv, &hdl->rp_mutex,
2436 drv_usectohz(100 * 1000), TR_CLOCK_TICK)
2437 >= 0)) {
2438 /* 100ms, random number, long enough? */
2439
2440 /* the result thread has processed it */
2441 goto continuing;
2442 }
2443
2444 USB_DPRINTF_L3(DPRINT_MASK_WHCDI,
2445 whcdi_log_handle,
2446 "wusb_wa_xfer_timeout_handler: result"
2447 " thread can't get the aborted request");
2448 }
2449 }
2450
2451 /*
2452 * 1)The Rpipe is idle, OR,
2453 * 2)rpipe_abort fails, OR,
2454 * 3)The result thread hasn't got an aborted result in 100ms,
2455 * most likely the result is lost. We can not depend on WA to
2456 * return result for this aborted request. The WA seems not
2457 * always returning such result. This will cause some hcdi
2458 * ops hang.
2459 */
2460 hdl->rp_state = WA_RPIPE_STATE_IDLE;
2461 hdl->rp_curr_wr = NULL;
2462
2463 /* release this WR's occupied req */
2464 hdl->rp_avail_reqs += (wr->wr_curr_seg - wr->wr_seg_done);
2465 cv_signal(&hdl->rp_cv);
2466
2467 mutex_exit(&hdl->rp_mutex);
2468
2469 wr->wr_cb(wa_data, wr, USB_CR_TIMEOUT, 0);
2470 mutex_enter(&hdl->rp_mutex);
2471
2472 continuing:
2473 wr = next;
2474 }
2475
2476 mutex_exit(&hdl->rp_mutex);
2477 }
2478
2479 /* stop timer */
2480 void
wusb_wa_stop_xfer_timer(wusb_wa_trans_wrapper_t * wr)2481 wusb_wa_stop_xfer_timer(wusb_wa_trans_wrapper_t *wr)
2482 {
2483 wusb_wa_rpipe_hdl_t *hdl = wr->wr_rp;
2484 timeout_id_t timer_id;
2485
2486 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
2487 "wusb_wa_stop_xfer_timer: wr = 0x%p", (void *)wr);
2488
2489 ASSERT(mutex_owned(&hdl->rp_mutex));
2490
2491 if (hdl->rp_timer_id == 0) {
2492
2493 return;
2494 }
2495
2496 timer_id = hdl->rp_timer_id;
2497 hdl->rp_timer_id = 0;
2498 mutex_exit(&hdl->rp_mutex);
2499
2500 (void) untimeout(timer_id);
2501
2502 mutex_enter(&hdl->rp_mutex);
2503 }
2504
2505
2506 /*
2507 * send transfer request and data to the bulk out pipe
2508 *
2509 * General transfer function for WA transfer, see Section 8.3.3.
2510 */
2511 /* ARGSUSED */
2512 int
wusb_wa_wr_xfer(wusb_wa_data_t * wa_data,wusb_wa_rpipe_hdl_t * hdl,wusb_wa_trans_wrapper_t * wr,usb_flags_t usb_flags)2513 wusb_wa_wr_xfer(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl,
2514 wusb_wa_trans_wrapper_t *wr, usb_flags_t usb_flags)
2515 {
2516 int i, rval;
2517 uint8_t curr_seg;
2518 usb_bulk_req_t *req;
2519
2520 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
2521 "wusb_wa_wr_xfer: wr = 0x%p", (void *)wr);
2522
2523 ASSERT(wr->wr_seg_array != NULL);
2524
2525 ASSERT(mutex_owned(&hdl->rp_mutex));
2526
2527 if (hdl->rp_state == WA_RPIPE_STATE_IDLE) {
2528 hdl->rp_state = WA_RPIPE_STATE_ACTIVE;
2529 hdl->rp_curr_wr = wr;
2530 }
2531 curr_seg = wr->wr_curr_seg;
2532
2533 USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
2534 "wusb_wa_wr_xfer: curr_seg = %d, avail_req = %d", curr_seg,
2535 hdl->rp_avail_reqs);
2536
2537 /*
2538 * For every segment,
2539 * Step 1: contruct a bulk req containing Transfer
2540 * Request(T8-12 and T8-10)
2541 * Step 2: alloc another bulk req if there's any data
2542 * for OUT endpoints.
2543 *
2544 * For IN endpoints, the data is returned in the
2545 * GetResult thread.
2546 * Just throw as many as maximum available requests to the RPipe.
2547 * If the avail_req is zero, wait!
2548 *
2549 * When a request is finished, the avail_req will be increased
2550 * in the result thread.
2551 */
2552 for (i = curr_seg; i < wr->wr_nsegs; i++) {
2553 USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
2554 "wusb_wa_wr_xfer: wr=%p curr_seg = %d, avail_req = %d,"
2555 " dir=%s", (void *)wr, curr_seg, hdl->rp_avail_reqs,
2556 (wr->wr_dir == WA_DIR_IN)?"IN":"OUT");
2557
2558 /* waiting for available requests if wr is still good */
2559 while ((hdl->rp_avail_reqs == 0) && (wr->wr_state == 0)) {
2560 rval = cv_wait_sig(&hdl->rp_cv, &hdl->rp_mutex);
2561 }
2562
2563 if ((wr->wr_curr_seg - wr->wr_seg_done) >= 1) {
2564 /* send only one segment */
2565
2566 break;
2567 }
2568
2569 if (wr->wr_state != 0) {
2570 /* wr transfer error, don't continue */
2571 USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
2572 "wusb_wa_wr_xfer: wr_state!=0(%d)", wr->wr_state);
2573
2574 break;
2575 }
2576
2577 req = wr->wr_seg_array[i].seg_trans_reqp;
2578 ASSERT(req != NULL);
2579
2580 mutex_exit(&hdl->rp_mutex);
2581 /* send ith transfer request */
2582 rval = usb_pipe_bulk_xfer(wa_data->wa_bulkout_ph, req, 0);
2583 mutex_enter(&hdl->rp_mutex);
2584 if (rval != USB_SUCCESS) {
2585 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2586 "wusb_wa_wr_xfer: send transfer request %d failed,"
2587 "rv=%d", i, rval);
2588
2589 wr->wr_seg_array[i].seg_trans_req_state = 0; /* clear */
2590
2591 if (i == 0) {
2592 /* no xfer in processing */
2593 hdl->rp_state = WA_RPIPE_STATE_IDLE;
2594 hdl->rp_curr_wr = NULL;
2595
2596 return (rval);
2597 }
2598 wusb_wa_abort_req(wa_data, wr, wr->wr_id);
2599 wr->wr_state = WR_SEG_REQ_ERR; /* sending tr error */
2600
2601 break;
2602 }
2603 wr->wr_seg_array[i].seg_trans_req_state = 1; /* submitted */
2604
2605 USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
2606 "wusb_wa_wr_xfer: seg(%d) request(0x%p) sent,"
2607 " avail_req = %d", i, (void*)req, hdl->rp_avail_reqs);
2608
2609 hdl->rp_avail_reqs--;
2610
2611 /* Get data in the GetResult thread for IN eps */
2612 if (wr->wr_dir == WA_DIR_IN) {
2613 wr->wr_curr_seg++;
2614
2615 /* only send data for out request */
2616 continue;
2617 }
2618
2619 req = wr->wr_seg_array[i].seg_data_reqp;
2620 if (req == NULL) {
2621 /* no data stage */
2622 wr->wr_curr_seg++;
2623
2624 continue;
2625 }
2626
2627 wr->wr_seg_array[i].seg_data_req_state = 1; /* submitted */
2628 mutex_exit(&hdl->rp_mutex);
2629 /* send ith data asynchronously */
2630 rval = usb_pipe_bulk_xfer(wa_data->wa_bulkout_ph, req, 0);
2631 mutex_enter(&hdl->rp_mutex);
2632 if (rval != USB_SUCCESS) {
2633 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2634 "wusb_wa_wr_xfer: send transfer data %d failed",
2635 i);
2636
2637 wr->wr_seg_array[i].seg_data_req_state = 0; /* clear */
2638
2639 wusb_wa_abort_req(wa_data, wr, wr->wr_id);
2640 wr->wr_state = WR_SEG_DAT_ERR; /* sending data error */
2641
2642 /* not inc rp_avail_reqs until callback */
2643
2644 break;
2645 }
2646
2647 USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
2648 "wusb_wa_wr_xfer: seg(%d) data(0x%p) sent, avail_req = %d",
2649 i, (void*)req, hdl->rp_avail_reqs);
2650
2651 wr->wr_curr_seg++;
2652 }
2653
2654 /* start timer */
2655 wusb_wa_start_xfer_timer(hdl);
2656 /*
2657 * return success even if the xfer is not complete, the callback
2658 * will only continue sending segs when (wr_error_state = 0 &&
2659 * wr_curr_seg < wr_nsegs)
2660 */
2661 return (USB_SUCCESS);
2662 }
2663
2664 /*
2665 * submit wr according to rpipe status
2666 * - check RPipe state
2667 * - call general WA transfer function to do transfer
2668 *
2669 * usba only submits one transfer to the host controller per pipe at a time
2670 * and starts next when the previous one completed. So the hwahc now
2671 * assumes one transfer per rpipe at a time. This won't be necessary to
2672 * change unless the usba scheme is changed.
2673 */
2674 int
wusb_wa_submit_ctrl_wr(wusb_wa_data_t * wa_data,wusb_wa_rpipe_hdl_t * hdl,wusb_wa_trans_wrapper_t * wr,usb_ctrl_req_t * ctrl_reqp,usb_flags_t usb_flags)2675 wusb_wa_submit_ctrl_wr(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl,
2676 wusb_wa_trans_wrapper_t *wr, usb_ctrl_req_t *ctrl_reqp,
2677 usb_flags_t usb_flags)
2678 {
2679 int rval;
2680
2681 mutex_enter(&hdl->rp_mutex);
2682 switch (hdl->rp_state) {
2683 case WA_RPIPE_STATE_IDLE:
2684 rval = wusb_wa_wr_xfer(wa_data, hdl, wr, usb_flags);
2685 break;
2686 case WA_RPIPE_STATE_ACTIVE:
2687 /* only allow one req at a time, this should not happen */
2688 default:
2689 rval = USB_PIPE_ERROR;
2690 break;
2691 }
2692 mutex_exit(&hdl->rp_mutex);
2693
2694 if (rval != USB_SUCCESS) {
2695 if (ctrl_reqp->ctrl_completion_reason == USB_CR_OK) {
2696 ctrl_reqp->ctrl_completion_reason = usba_rval2cr(rval);
2697 }
2698 mutex_enter(&hdl->rp_mutex);
2699 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
2700 "wusb_wa_submit_ctrl_wr:fail, reqp=0x%p, rpstat=%d, rv=%d",
2701 (void*)ctrl_reqp, hdl->rp_state, rval);
2702
2703 mutex_exit(&hdl->rp_mutex);
2704
2705 wusb_wa_free_trans_wrapper(wr);
2706 }
2707
2708 /* In other cases, wr will be freed in callback */
2709 return (rval);
2710 }
2711
2712 /*
2713 * Transfer a control request:
2714 * - allocate a transfer wrapper(TW) for this request
2715 * - submit this TW
2716 */
2717 int
wusb_wa_ctrl_xfer(wusb_wa_data_t * wa_data,wusb_wa_rpipe_hdl_t * hdl,usba_pipe_handle_data_t * ph,usb_ctrl_req_t * ctrl_reqp,usb_flags_t usb_flags)2718 wusb_wa_ctrl_xfer(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl,
2719 usba_pipe_handle_data_t *ph, usb_ctrl_req_t *ctrl_reqp,
2720 usb_flags_t usb_flags)
2721 {
2722 int rval;
2723 wusb_wa_trans_wrapper_t *wr;
2724
2725 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
2726 "wusb_wa_ctrl_xfer: ph = 0x%p reqp = 0x%p",
2727 (void*)ph, (void*)ctrl_reqp);
2728
2729 wr = wusb_wa_alloc_ctrl_resources(wa_data, hdl, ph, ctrl_reqp,
2730 usb_flags);
2731 if (wr == NULL) {
2732 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2733 "wusb_wa_ctrl_req: alloc ctrl resource failed");
2734
2735 return (USB_NO_RESOURCES);
2736 }
2737
2738 rval = wusb_wa_submit_ctrl_wr(wa_data, hdl, wr, ctrl_reqp, usb_flags);
2739 if (rval != USB_SUCCESS) {
2740 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2741 "wusb_wa_submit_ctrl_wr: submit ctrl req failed, rval = %d",
2742 rval);
2743 }
2744
2745 return (rval);
2746 }
2747
2748 /*
2749 * submit wr according to rpipe status
2750 *
2751 * usba only submits one transfer to the host controller per pipe at a time
2752 * and starts next when the previous one completed. So the hwahc now
2753 * assumes one transfer per rpipe at a time. This won't be necessary to
2754 * change unless the usba scheme is changed.
2755 */
2756 int
wusb_wa_submit_bulk_wr(wusb_wa_data_t * wa_data,wusb_wa_rpipe_hdl_t * hdl,wusb_wa_trans_wrapper_t * wr,usb_bulk_req_t * bulk_reqp,usb_flags_t usb_flags)2757 wusb_wa_submit_bulk_wr(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl,
2758 wusb_wa_trans_wrapper_t *wr, usb_bulk_req_t *bulk_reqp,
2759 usb_flags_t usb_flags)
2760 {
2761 int rval;
2762
2763 mutex_enter(&hdl->rp_mutex);
2764 switch (hdl->rp_state) {
2765 case WA_RPIPE_STATE_IDLE:
2766 rval = wusb_wa_wr_xfer(wa_data, hdl, wr, usb_flags);
2767 break;
2768 case WA_RPIPE_STATE_ACTIVE:
2769 /* only allow one req at a time, this should not happen */
2770 default:
2771 rval = USB_PIPE_ERROR;
2772 break;
2773 }
2774 mutex_exit(&hdl->rp_mutex);
2775
2776 if (rval != USB_SUCCESS) {
2777 if (bulk_reqp->bulk_completion_reason == USB_CR_OK) {
2778 bulk_reqp->bulk_completion_reason = usba_rval2cr(rval);
2779 }
2780 wusb_wa_free_trans_wrapper(wr);
2781 }
2782
2783 /* In other cases, wr will be freed in callback */
2784 return (rval);
2785 }
2786
2787 /*
2788 * WA general bulk transfer
2789 * - allocate bulk resources
2790 * - submit the bulk request
2791 */
2792 int
wusb_wa_bulk_xfer(wusb_wa_data_t * wa_data,wusb_wa_rpipe_hdl_t * hdl,usba_pipe_handle_data_t * ph,usb_bulk_req_t * bulk_reqp,usb_flags_t usb_flags)2793 wusb_wa_bulk_xfer(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl,
2794 usba_pipe_handle_data_t *ph, usb_bulk_req_t *bulk_reqp,
2795 usb_flags_t usb_flags)
2796 {
2797 int rval;
2798 wusb_wa_trans_wrapper_t *wr;
2799
2800 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
2801 "wusb_wa_bulk_xfer: ph = 0x%p reqp = 0x%p",
2802 (void *)ph, (void *)bulk_reqp);
2803
2804 wr = wusb_wa_alloc_bulk_resources(wa_data, hdl, ph, bulk_reqp,
2805 usb_flags);
2806 if (wr == NULL) {
2807 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2808 "wusb_wa_bulk_xfer: alloc bulk resource failed");
2809
2810 return (USB_NO_RESOURCES);
2811 }
2812
2813 rval = wusb_wa_submit_bulk_wr(wa_data, hdl, wr, bulk_reqp,
2814 usb_flags);
2815 if (rval != USB_SUCCESS) {
2816 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2817 "wusb_wa_bulk_req: submit bulk req failed, rval = %d",
2818 rval);
2819 }
2820
2821 return (rval);
2822 }
2823
2824 /*
2825 * submit wr according to rpipe status
2826 *
2827 * usba only submits one transfer to the host controller per pipe at a time
2828 * and starts next when the previous one completed. So the hwahc now
2829 * assumes one transfer per rpipe at a time. This won't be necessary to
2830 * change unless the usba scheme is changed.
2831 */
2832 int
wusb_wa_submit_intr_wr(wusb_wa_data_t * wa_data,wusb_wa_rpipe_hdl_t * hdl,wusb_wa_trans_wrapper_t * wr,usb_intr_req_t * intr_reqp,usb_flags_t usb_flags)2833 wusb_wa_submit_intr_wr(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl,
2834 wusb_wa_trans_wrapper_t *wr, usb_intr_req_t *intr_reqp,
2835 usb_flags_t usb_flags)
2836 {
2837 int rval;
2838
2839 mutex_enter(&hdl->rp_mutex);
2840 switch (hdl->rp_state) {
2841 case WA_RPIPE_STATE_IDLE:
2842 rval = wusb_wa_wr_xfer(wa_data, hdl, wr, usb_flags);
2843 break;
2844 case WA_RPIPE_STATE_ACTIVE:
2845 /* only allow one req at a time, this should not happen */
2846 default:
2847 rval = USB_PIPE_ERROR;
2848 break;
2849 }
2850 mutex_exit(&hdl->rp_mutex);
2851
2852 if (rval != USB_SUCCESS) {
2853 if (intr_reqp->intr_completion_reason == USB_CR_OK) {
2854 intr_reqp->intr_completion_reason = usba_rval2cr(rval);
2855 }
2856 wusb_wa_free_trans_wrapper(wr);
2857 }
2858
2859 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
2860 "wusb_wa_submit_intr_wr: submit intr req, rval = %d", rval);
2861
2862 /* In other cases, wr will be freed in callback */
2863 return (rval);
2864 }
2865
2866 /*
2867 * do intr xfer
2868 *
2869 * Now only one time intr transfer is supported. intr polling is not
2870 * supported.
2871 */
2872 int
wusb_wa_intr_xfer(wusb_wa_data_t * wa_data,wusb_wa_rpipe_hdl_t * hdl,usba_pipe_handle_data_t * ph,usb_intr_req_t * intr_reqp,usb_flags_t usb_flags)2873 wusb_wa_intr_xfer(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl,
2874 usba_pipe_handle_data_t *ph, usb_intr_req_t *intr_reqp,
2875 usb_flags_t usb_flags)
2876 {
2877 int rval;
2878 wusb_wa_trans_wrapper_t *wr;
2879
2880 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
2881 "wusb_wa_intr_xfer: ph = 0x%p reqp = 0x%p",
2882 (void *)ph, (void *)intr_reqp);
2883
2884 wr = wusb_wa_alloc_intr_resources(wa_data, hdl, ph, intr_reqp,
2885 usb_flags);
2886 if (wr == NULL) {
2887 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2888 "wusb_wa_intr_req: alloc intr resource failed");
2889
2890 return (USB_NO_RESOURCES);
2891 }
2892
2893 rval = wusb_wa_submit_intr_wr(wa_data, hdl, wr, intr_reqp,
2894 usb_flags);
2895 if (rval != USB_SUCCESS) {
2896 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2897 "wusb_wa_intr_req: submit intr req failed, rval = %d",
2898 rval);
2899
2900 return (rval);
2901 }
2902
2903 /*
2904 * have successfully duplicate and queue one more request on
2905 * the pipe. Increase the pipe request count.
2906 */
2907 if ((ph->p_ep.bEndpointAddress & USB_EP_DIR_MASK) == USB_EP_DIR_IN) {
2908 mutex_enter(&ph->p_mutex);
2909
2910 /*
2911 * this count will be decremented by usba_req_normal_cb
2912 * or usba_req_exc_cb (called by hcdi_do_cb <-- usba_hcdi_cb)
2913 */
2914 ph->p_req_count++;
2915
2916 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2917 "wusb_wa_intr_req: p_req_cnt = %d", ph->p_req_count);
2918
2919 mutex_exit(&ph->p_mutex);
2920 }
2921
2922 return (rval);
2923 }
2924
2925 /*
2926 * For an IN transfer request, receive transfer data on bulk-in ept
2927 * The bulk_req has been allocated when allocating transfer resources
2928 */
2929 int
wusb_wa_get_data(wusb_wa_data_t * wa_data,wusb_wa_seg_t * seg,uint32_t len)2930 wusb_wa_get_data(wusb_wa_data_t *wa_data, wusb_wa_seg_t *seg, uint32_t len)
2931 {
2932 usb_bulk_req_t *req;
2933 int rval;
2934
2935 if (len == 0) {
2936
2937 return (USB_SUCCESS);
2938 }
2939
2940 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2941 "wusb_wa_get_data: get data for wr: 0x%p", (void *)seg->seg_wr);
2942
2943 req = seg->seg_data_reqp;
2944 ASSERT(req != NULL);
2945
2946 /* adjust bulk in length to actual length */
2947 req->bulk_len = len;
2948 rval = usb_pipe_bulk_xfer(wa_data->wa_bulkin_ph, req,
2949 USB_FLAGS_SLEEP);
2950
2951 return (rval);
2952 }
2953
2954 /*
2955 * to retrieve a transfer_wrapper by dwTransferID
2956 *
2957 * Though to search a list looks not so efficient, we have to give up
2958 * id32_lookup(). When a transfer segment is throwed to HWA device, we
2959 * can't anticipate when the result will be returned, even if we try to
2960 * abort it. If we have freed the transfer wrapper due to timeout, then
2961 * after a moment, that TW's segment is accomplished by hardware. If
2962 * id32_lookup() is used to look up corresponding TW, we'll get an invalid
2963 * address. Unfortunately, id32_lookup() can't judge validity of its
2964 * returned address.
2965 */
2966 wusb_wa_trans_wrapper_t *
wusb_wa_retrieve_wr(wusb_wa_data_t * wa_data,uint32_t id)2967 wusb_wa_retrieve_wr(wusb_wa_data_t *wa_data, uint32_t id)
2968 {
2969 wusb_wa_rpipe_hdl_t *rph;
2970 uint16_t i;
2971 wusb_wa_trans_wrapper_t *tw;
2972
2973 for (i = 0; i < wa_data->wa_num_rpipes; i++) {
2974 rph = &wa_data->wa_rpipe_hdl[i];
2975
2976 mutex_enter(&rph->rp_mutex);
2977 /* all outstanding TWs are put on the timeout list */
2978 tw = rph->rp_timeout_list;
2979
2980 while (tw) {
2981 if (tw->wr_id == id) {
2982 mutex_exit(&rph->rp_mutex);
2983 return (tw);
2984 }
2985 tw = tw->wr_timeout_next;
2986 }
2987 mutex_exit(&rph->rp_mutex);
2988 }
2989
2990 return (NULL);
2991 }
2992
2993 /* endlessly wait for transfer result on bulk-in ept and handle the result */
2994 int
wusb_wa_get_xfer_result(wusb_wa_data_t * wa_data)2995 wusb_wa_get_xfer_result(wusb_wa_data_t *wa_data)
2996 {
2997 usb_bulk_req_t *req;
2998 int rval;
2999 mblk_t *data;
3000 uint8_t *p;
3001 wa_xfer_result_t result;
3002 wusb_wa_trans_wrapper_t *wr;
3003 wusb_wa_seg_t *seg;
3004 uint8_t status;
3005 uint_t len;
3006 uint8_t lastseg = 0;
3007 usb_cr_t cr;
3008 uint32_t act_len;
3009 wusb_wa_rpipe_hdl_t *hdl;
3010
3011 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3012 "wusb_wa_get_xfer_result: started, wa=0x%p", (void*)wa_data);
3013
3014 /* grab lock before accessing wa_data */
3015 mutex_enter(&wa_data->wa_mutex);
3016
3017 len = wa_data->wa_bulkin_ept.wMaxPacketSize;
3018
3019 req = usb_alloc_bulk_req(wa_data->wa_dip, len,
3020 USB_FLAGS_NOSLEEP);
3021 if (req == NULL) {
3022 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
3023 "wusb_wa_get_xfer_result: alloc bulk req failed");
3024
3025 mutex_exit(&wa_data->wa_mutex);
3026
3027 return (USB_NO_RESOURCES);
3028 }
3029
3030 req->bulk_len = len;
3031 req->bulk_timeout = 0;
3032 req->bulk_attributes = USB_ATTRS_SHORT_XFER_OK |
3033 USB_ATTRS_AUTOCLEARING;
3034
3035 mutex_exit(&wa_data->wa_mutex);
3036
3037 /* Get the Transfer Result head, see Table 8-14 */
3038 rval = usb_pipe_bulk_xfer(wa_data->wa_bulkin_ph, req,
3039 USB_FLAGS_SLEEP);
3040 if ((rval != USB_SUCCESS) || (req->bulk_data == NULL)) {
3041 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
3042 "wusb_wa_get_xfer_result: bulk xfer failed or "
3043 "null data returned, rval=%d, req->bulk_data = %p",
3044 rval, (void*)req->bulk_data);
3045 usb_free_bulk_req(req);
3046
3047 return (rval);
3048 }
3049
3050 data = req->bulk_data;
3051 p = data->b_rptr;
3052
3053 USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
3054 "wusb_wa_get_xfer_result: received data len = %d",
3055 (int)MBLKL(data));
3056
3057 if ((MBLKL(data) != WA_XFER_RESULT_LEN) ||
3058 (p[1] != WA_RESULT_TYPE_TRANSFER)) {
3059 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
3060 "wusb_wa_get_xfer_result: invalid xfer result, "
3061 "len = %d, p0 = 0x%x, p1 = 0x%x, p6 = 0x%x",
3062 (int)MBLKL(data), p[0], p[1], p[6]);
3063
3064 usb_free_bulk_req(req);
3065
3066 return (USB_SUCCESS); /* don't stop this thread */
3067 }
3068
3069 /* Transfer result. Section 8.3.3.4 */
3070 (void) usb_parse_data("ccllccl", p, WA_XFER_RESULT_LEN, &result,
3071 sizeof (wa_xfer_result_t));
3072
3073
3074 USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
3075 "wusb_wa_get_xfer_result: id = 0x%x len = 0x%x nseg = 0x%02x"
3076 " status = 0x%02x(0x%02x)", result.dwTransferID,
3077 result.dwTransferLength, result.bTransferSegment,
3078 result.bTransferStatus, p[11]&0x0f);
3079
3080 req->bulk_data = NULL; /* don't free it. we still need it */
3081 usb_free_bulk_req(req);
3082
3083 status = result.bTransferStatus;
3084 if ((status & 0x3f) == WA_STS_NOT_FOUND) {
3085 freemsg(data);
3086 /*
3087 * The result is just ignored since the transfer request
3088 * has completed
3089 */
3090 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
3091 "wusb_wa_get_xfer_result: TransferID not found");
3092
3093 return (USB_SUCCESS);
3094 }
3095
3096 mutex_enter(&wa_data->wa_mutex);
3097 wr = wusb_wa_retrieve_wr(wa_data, result.dwTransferID);
3098 if ((wr == NULL)) {
3099 /* this id's corresponding WR may have been freed by timeout handler */
3100 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
3101 "wusb_wa_get_xfer_result: wr == deadbeef or NULL");
3102
3103 mutex_exit(&wa_data->wa_mutex);
3104 freemsg(data);
3105
3106 return (USB_SUCCESS);
3107 }
3108
3109 /* bit 7 is last segment flag */
3110 if ((result.bTransferSegment & 0x7f) >= wr->wr_nsegs) {
3111 USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
3112 "wusb_wa_get_xfer_result: error - "
3113 " bTransferSegment(%d) > segment coutnts(%d)",
3114 (result.bTransferSegment & 0x7f), wr->wr_nsegs);
3115
3116 goto err;
3117 }
3118
3119 lastseg = result.bTransferSegment & 0x80;
3120 hdl = wr->wr_rp;
3121
3122 mutex_enter(&hdl->rp_mutex);
3123 seg = &wr->wr_seg_array[result.bTransferSegment & 0x7f];
3124 seg->seg_status = result.bTransferStatus;
3125 act_len = seg->seg_actual_len = result.dwTransferLength;
3126
3127 /*
3128 * if this is the last segment, we should not continue.
3129 * IMPT: we expect the WA deliver result sequentially.
3130 */
3131 seg->seg_done = (result.bTransferSegment) & 0x80;
3132
3133 wr->wr_seg_done++;
3134 hdl->rp_avail_reqs++;
3135 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
3136 "wusb_wa_get_xfer_result: wr = %p, rp=%p, avail_req=%d", (void*)wr,
3137 (void*)wr->wr_rp, hdl->rp_avail_reqs);
3138
3139 cv_broadcast(&hdl->rp_cv);
3140
3141 if (status & 0x40) {
3142 status = 0; /* ignore warning, see Tab8-15 */
3143 }
3144 seg->seg_status = status;
3145
3146 /* Error bit set */
3147 if (status & 0x80) {
3148 /* don't change timeout error */
3149 if (wr->wr_state != WR_TIMEOUT) {
3150 wr->wr_state = WR_XFER_ERR;
3151 }
3152
3153 /*
3154 * The timeout handler is waiting, but the result thread will
3155 * process this wr.
3156 */
3157 if ((wr->wr_state == WR_TIMEOUT) &&
3158 (status & 0x3F) == WA_STS_ABORTED) {
3159 wr->wr_has_aborted = 1;
3160 cv_signal(&wr->wr_cv); /* to inform timeout hdler */
3161 }
3162
3163 mutex_exit(&hdl->rp_mutex);
3164 /* seg error, don't proceed with this WR */
3165 goto err;
3166 }
3167
3168 USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
3169 "wusb_wa_get_xfer_result: status = 0x%02x dir=%s",
3170 status, (wr->wr_dir == WA_DIR_IN)?"IN":"OUT");
3171
3172 /*
3173 * for an IN endpoint and data length > 0 and no error, read in
3174 * the real data. Otherwise, for OUT EP, or data length = 0, or
3175 * segment error, don't read.
3176 */
3177 if ((wr->wr_dir == WA_DIR_IN) &&
3178 (act_len > 0) &&
3179 ((status & 0x3F) == 0)) { /* if segment error, don't read */
3180 /* receive data */
3181 mutex_exit(&hdl->rp_mutex);
3182 mutex_exit(&wa_data->wa_mutex);
3183 rval = wusb_wa_get_data(wa_data, seg, act_len);
3184 mutex_enter(&wa_data->wa_mutex);
3185 mutex_enter(&hdl->rp_mutex);
3186 if (rval != USB_SUCCESS) {
3187 USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
3188 "wusb_wa_get_xfer_result: can't get seg data:%d",
3189 rval);
3190
3191 mutex_exit(&hdl->rp_mutex);
3192
3193 goto err;
3194 }
3195
3196 USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
3197 "wusb_wa_get_xfer_result: get (%dB) data for IN ep",
3198 act_len);
3199 }
3200
3201 mutex_exit(&hdl->rp_mutex);
3202
3203 mutex_exit(&wa_data->wa_mutex);
3204
3205 /* check if the whole transfer has completed */
3206 wusb_wa_check_req_done(wa_data, wr, lastseg);
3207
3208 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3209 "wusb_wa_get_xfer_result: ended");
3210
3211 freemsg(data);
3212
3213 return (USB_SUCCESS);
3214
3215 err:
3216 mutex_exit(&wa_data->wa_mutex);
3217
3218 mutex_enter(&hdl->rp_mutex);
3219 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3220 "wusb_wa_get_xfer_result: segment(%02x) error, abort wr 0x%p,"
3221 "wr_state=%d", result.bTransferSegment, (void*)wr, wr->wr_state);
3222
3223 /* if it's timeout, just return the TIMEOUT error */
3224 if (wr->wr_state == WR_TIMEOUT) {
3225 cr = USB_CR_TIMEOUT;
3226 } else {
3227 cr = wusb_wa_sts2cr(status);
3228 }
3229
3230 mutex_exit(&hdl->rp_mutex);
3231
3232 wusb_wa_handle_error(wa_data, wr, cr);
3233
3234 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3235 "wusb_wa_get_xfer_result: error end, cr=%d",
3236 cr);
3237
3238 freemsg(data);
3239
3240 return (USB_SUCCESS);
3241 }
3242
3243
3244 static void
wusb_wa_handle_error(wusb_wa_data_t * wa_data,wusb_wa_trans_wrapper_t * wr,usb_cr_t cr)3245 wusb_wa_handle_error(wusb_wa_data_t *wa_data, wusb_wa_trans_wrapper_t *wr,
3246 usb_cr_t cr)
3247 {
3248 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3249 "wusb_wa_handle_error: start");
3250
3251 mutex_enter(&wr->wr_rp->rp_mutex);
3252 if (wr->wr_seg_done != wr->wr_curr_seg) {
3253 /* still segments pending, abort them */
3254 USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
3255 "wusb_wa_handle_error: segment err, abort other segs");
3256
3257 wusb_wa_abort_req(wa_data, wr, wr->wr_id);
3258 }
3259
3260 wusb_wa_stop_xfer_timer(wr);
3261 wr->wr_rp->rp_state = WA_RPIPE_STATE_IDLE;
3262 wr->wr_rp->rp_curr_wr = NULL;
3263 mutex_exit(&wr->wr_rp->rp_mutex);
3264
3265 wr->wr_cb(wa_data, wr, cr, 1);
3266
3267 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3268 "wusb_wa_handle_error: error end, cr=%d",
3269 cr);
3270 }
3271
3272 /*
3273 * Check if current request is done, if yes, do callback and move on to
3274 * next request; if there is any uncleared error, do callback to cleanup
3275 * the pipe
3276 */
3277 void
wusb_wa_check_req_done(wusb_wa_data_t * wa_data,wusb_wa_trans_wrapper_t * wr,uint8_t lastseg)3278 wusb_wa_check_req_done(wusb_wa_data_t *wa_data,
3279 wusb_wa_trans_wrapper_t *wr, uint8_t lastseg)
3280 {
3281 wusb_wa_rpipe_hdl_t *hdl = wr->wr_rp;
3282 wusb_wa_seg_t *seg;
3283 int i, rval;
3284 usb_cr_t cr;
3285
3286 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3287 "wusb_wa_check_req_done: wr = 0x%p, lastseg=%02x",
3288 (void*)wr, lastseg);
3289
3290 mutex_enter(&hdl->rp_mutex);
3291 /* not done: submitted segs not finished and lastseg not set */
3292 if ((wr->wr_seg_done != wr->wr_curr_seg) && (!lastseg)) {
3293 mutex_exit(&hdl->rp_mutex);
3294
3295 return;
3296 }
3297
3298 if (wr->wr_state != 0) { /* abort somewhere */
3299 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3300 "wusb_wa_check_req_done: tw(%p) aborted somewhere",
3301 (void*)wr);
3302 cr = USB_CR_UNSPECIFIED_ERR;
3303
3304 goto reset;
3305 }
3306
3307 /* check if there is any error */
3308 for (i = 0; i < wr->wr_curr_seg; i++) {
3309 seg = &wr->wr_seg_array[i];
3310 if (seg->seg_status != WA_STS_SUCCESS) {
3311 /* what about short xfer? need to fix */
3312 cr = wusb_wa_sts2cr(seg->seg_status);
3313 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3314 "wusb_wa_check_req_done: seg fail, status=%02x",
3315 seg->seg_status);
3316
3317 goto reset;
3318 }
3319
3320 if (seg->seg_done == 0x80) {
3321 /* device has told this is the last segment, we're done */
3322 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3323 "wusb_wa_check_req_done: last seg");
3324
3325 goto done;
3326 }
3327 }
3328
3329 /* check if current request has completed */
3330 /*
3331 * Transfer another segment.
3332 *
3333 */
3334 if (wr->wr_curr_seg < wr->wr_nsegs) {
3335 /* send the remained segments */
3336 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3337 "wusb_wa_check_req_done: req not completed, restart");
3338
3339 rval = wusb_wa_wr_xfer(wa_data, hdl, wr, wr->wr_flags);
3340 if (rval != USB_SUCCESS) {
3341 cr = usba_rval2cr(rval);
3342
3343 goto reset;
3344 }
3345
3346 mutex_exit(&hdl->rp_mutex);
3347
3348 return;
3349 }
3350
3351 done:
3352 wusb_wa_stop_xfer_timer(wr);
3353
3354 /* release the occupied requests */
3355 hdl->rp_avail_reqs += (wr->wr_curr_seg - wr->wr_seg_done);
3356 cv_signal(&hdl->rp_cv);
3357
3358 hdl->rp_state = WA_RPIPE_STATE_IDLE;
3359 hdl->rp_curr_wr = NULL;
3360 wr->wr_state = WR_FINISHED;
3361 mutex_exit(&hdl->rp_mutex);
3362
3363 wr->wr_cb(wa_data, wr, USB_CR_OK, 0);
3364
3365 /* Need to move on to next request? usba will do this */
3366 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3367 "wusb_wa_check_req_done: ended");
3368
3369 return;
3370
3371 reset:
3372 wusb_wa_stop_xfer_timer(wr);
3373
3374 /* not necessary to reset the RPipe */
3375 hdl->rp_state = WA_RPIPE_STATE_IDLE;
3376 hdl->rp_curr_wr = NULL;
3377
3378 hdl->rp_avail_reqs += (wr->wr_curr_seg - wr->wr_seg_done);
3379 cv_signal(&hdl->rp_cv);
3380
3381 /* if it's timeout, just return the TIMEOUT error */
3382 if (wr->wr_state == WR_TIMEOUT)
3383 cr = USB_CR_TIMEOUT;
3384
3385 mutex_exit(&hdl->rp_mutex);
3386
3387 wr->wr_cb(wa_data, wr, cr, 1);
3388 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3389 "wusb_wa_check_req_done: reset end");
3390 }
3391
3392 /*
3393 * callback for ctrl transfer
3394 *
3395 * reset_flag: not support yet
3396 */
3397 void
wusb_wa_handle_ctrl(wusb_wa_data_t * wa_data,wusb_wa_trans_wrapper_t * wr,usb_cr_t cr,uint_t reset_flag)3398 wusb_wa_handle_ctrl(wusb_wa_data_t *wa_data, wusb_wa_trans_wrapper_t *wr,
3399 usb_cr_t cr, uint_t reset_flag)
3400 {
3401 usb_ctrl_req_t *req;
3402 usb_bulk_req_t *bulk_req;
3403 mblk_t *data, *bulk_data;
3404 int i;
3405 size_t len;
3406 wusb_wa_seg_t *seg;
3407
3408 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3409 "wusb_wa_handle_ctrl: wr = 0x%p, cr = 0x%x, flag=%d",
3410 (void*)wr, cr, reset_flag);
3411
3412 req = (usb_ctrl_req_t *)wr->wr_reqp;
3413
3414 if ((wr->wr_dir == WA_DIR_OUT) || (cr != USB_CR_OK)) {
3415
3416 /* do callback */
3417 wusb_wa_callback(wa_data, wr->wr_ph, wr, cr);
3418
3419 return;
3420 }
3421
3422 mutex_enter(&wr->wr_rp->rp_mutex);
3423 data = req->ctrl_data;
3424 for (i = 0; i < wr->wr_nsegs; i++) {
3425 seg = &wr->wr_seg_array[i];
3426 /* copy received data to original req buffer */
3427 bulk_req = (usb_bulk_req_t *)
3428 wr->wr_seg_array[i].seg_data_reqp;
3429 bulk_data = bulk_req->bulk_data;
3430 len = MBLKL(bulk_data);
3431 bcopy(bulk_data->b_rptr, data->b_wptr, len);
3432 data->b_wptr += len;
3433 if (len < wr->wr_seg_array[i].seg_len) {
3434 /* short xfer */
3435 break;
3436 }
3437
3438 if (seg->seg_done == 0x80) {
3439 /* last segment, finish */
3440 break;
3441 }
3442 }
3443
3444 mutex_exit(&wr->wr_rp->rp_mutex);
3445 /* do callback */
3446 wusb_wa_callback(wa_data, wr->wr_ph, wr, cr);
3447 }
3448
3449 /*
3450 * callback for bulk transfer
3451 *
3452 * reset_flag: not support yet
3453 */
3454 void
wusb_wa_handle_bulk(wusb_wa_data_t * wa_data,wusb_wa_trans_wrapper_t * wr,usb_cr_t cr,uint_t reset_flag)3455 wusb_wa_handle_bulk(wusb_wa_data_t *wa_data, wusb_wa_trans_wrapper_t *wr,
3456 usb_cr_t cr, uint_t reset_flag)
3457 {
3458 usb_bulk_req_t *req;
3459 usb_bulk_req_t *bulk_req;
3460 mblk_t *data, *bulk_data;
3461 int i;
3462 size_t len;
3463 wusb_wa_seg_t *seg;
3464
3465 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3466 "wusb_wa_handle_bulk: wr = 0x%p, cr = 0x%x, flag=%d",
3467 (void*)wr, cr, reset_flag);
3468
3469 req = (usb_bulk_req_t *)wr->wr_reqp;
3470
3471 if ((wr->wr_dir == WA_DIR_OUT) || (cr != USB_CR_OK)) {
3472 /* do callback */
3473 wusb_wa_callback(wa_data, wr->wr_ph, wr, cr);
3474
3475 return;
3476 }
3477
3478 mutex_enter(&wr->wr_rp->rp_mutex);
3479 data = req->bulk_data;
3480 for (i = 0; i < wr->wr_nsegs; i++) {
3481 seg = &wr->wr_seg_array[i];
3482 /* copy received data to original req buffer */
3483 bulk_req = (usb_bulk_req_t *)
3484 wr->wr_seg_array[i].seg_data_reqp;
3485 bulk_data = bulk_req->bulk_data;
3486 len = MBLKL(bulk_data);
3487 bcopy(bulk_data->b_rptr, data->b_wptr, len);
3488 data->b_wptr += len;
3489 if (len < wr->wr_seg_array[i].seg_len) {
3490 /* short xfer */
3491 break;
3492 }
3493
3494 if (seg->seg_done == 0x80) {
3495 /* last segment, finish */
3496 break;
3497 }
3498 }
3499
3500 mutex_exit(&wr->wr_rp->rp_mutex);
3501 /* do callback */
3502 wusb_wa_callback(wa_data, wr->wr_ph, wr, cr);
3503 }
3504
3505 int
wa_submit_periodic_req(wusb_wa_data_t * wa_data,usba_pipe_handle_data_t * ph)3506 wa_submit_periodic_req(wusb_wa_data_t *wa_data, usba_pipe_handle_data_t *ph)
3507 {
3508 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3509 "wa_submit_periodic_req: wa_data=0x%p, ph=0x%p",
3510 (void*)wa_data, (void*)ph);
3511
3512 return (wa_data->pipe_periodic_req(wa_data, ph));
3513 }
3514
3515 /*
3516 * callback for intr transfer
3517 *
3518 * reset_flag: not support yet
3519 */
3520 void
wusb_wa_handle_intr(wusb_wa_data_t * wa_data,wusb_wa_trans_wrapper_t * wr,usb_cr_t cr,uint_t reset_flag)3521 wusb_wa_handle_intr(wusb_wa_data_t *wa_data, wusb_wa_trans_wrapper_t *wr,
3522 usb_cr_t cr, uint_t reset_flag)
3523 {
3524 usb_intr_req_t *req;
3525 usb_req_attrs_t attrs;
3526 usba_pipe_handle_data_t *ph = wr->wr_ph;
3527 usb_bulk_req_t *bulk_req;
3528 mblk_t *data, *bulk_data;
3529 int i;
3530 size_t len;
3531 int rval;
3532 wusb_wa_seg_t *seg;
3533
3534 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3535 "wusb_wa_handle_intr: wr = 0x%p, cr = 0x%x, flag=%d",
3536 (void*)wr, cr, reset_flag);
3537
3538 req = (usb_intr_req_t *)wr->wr_reqp;
3539 attrs = req->intr_attributes;
3540
3541 if ((wr->wr_dir == WA_DIR_OUT) || (cr != USB_CR_OK)) {
3542 /* do callback */
3543 wusb_wa_callback(wa_data, wr->wr_ph, wr, cr);
3544
3545 return;
3546 }
3547
3548 mutex_enter(&wr->wr_rp->rp_mutex);
3549 /* copy data to client's buffer */
3550 data = req->intr_data;
3551 for (i = 0; i < wr->wr_nsegs; i++) {
3552 seg = &wr->wr_seg_array[i];
3553 /* copy received data to original req buffer */
3554 bulk_req = (usb_bulk_req_t *)
3555 wr->wr_seg_array[i].seg_data_reqp;
3556 bulk_data = bulk_req->bulk_data;
3557 len = MBLKL(bulk_data);
3558 bcopy(bulk_data->b_rptr, data->b_wptr, len);
3559 data->b_wptr += len;
3560 if (len < wr->wr_seg_array[i].seg_len) {
3561 /* short xfer */
3562 break;
3563 }
3564
3565 if (seg->seg_done & 0x80) {
3566
3567 break;
3568 }
3569 }
3570
3571 if (attrs & USB_ATTRS_ONE_XFER) {
3572 /* client requires ONE_XFER request, return */
3573 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3574 "wusb_wa_handle_intr: ONE_XFER set");
3575
3576 mutex_exit(&wr->wr_rp->rp_mutex);
3577 goto finish;
3578 }
3579
3580 /* polling mode */
3581 mutex_exit(&wr->wr_rp->rp_mutex);
3582 rval = wa_submit_periodic_req(wa_data, ph);
3583 if (rval != USB_SUCCESS) {
3584 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3585 "wusb_wa_handle_intr: polling, fail to resubmit req");
3586
3587 goto finish;
3588 }
3589
3590 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3591 "wusb_wa_handle_intr: polling, resubmit request, rv=%d", rval);
3592
3593 finish:
3594 /* do callback */
3595 wusb_wa_callback(wa_data, wr->wr_ph, wr, cr);
3596
3597 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3598 "wusb_wa_handle_intr: end");
3599 }
3600
3601 /*
3602 * free transfer wrapper
3603 * call host controller driver callback for completion handling
3604 *
3605 * This callback will call WA's specific callback function.
3606 * The callback functions should call usba_hcdi_cb() to pass request
3607 * back to client driver.
3608 */
3609 void
wusb_wa_callback(wusb_wa_data_t * wa_data,usba_pipe_handle_data_t * ph,wusb_wa_trans_wrapper_t * wr,usb_cr_t cr)3610 wusb_wa_callback(wusb_wa_data_t *wa_data, usba_pipe_handle_data_t *ph,
3611 wusb_wa_trans_wrapper_t *wr, usb_cr_t cr)
3612 {
3613 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3614 "wusb_wa_callback: wr=0x%p, cr=0x%x, ph=0x%p, req = 0x%p",
3615 (void*)wr, cr, (void*)ph, (void*)((wr == NULL)?0:wr->wr_reqp));
3616
3617 if (cr == USB_CR_FLUSHED) {
3618 /*
3619 * the wr is aborted. mark the rpipe as error,
3620 * so that the periodic xfer callbacks will not submit
3621 * further requests.
3622 */
3623 mutex_enter(&wr->wr_rp->rp_mutex);
3624 wr->wr_rp->rp_state = WA_RPIPE_STATE_ERROR;
3625 mutex_exit(&wr->wr_rp->rp_mutex);
3626 }
3627
3628 wa_data->rpipe_xfer_cb(wa_data->wa_dip, ph, wr, cr);
3629
3630 /*
3631 * need to consider carefully when to free wrapper
3632 * if the rpipe is reset, what to do with current wr in processing?
3633 */
3634 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3635 "wusb_wa_callback: hwahc callback finish for wr= 0x%p, free it",
3636 (void*)wr);
3637
3638 wusb_wa_free_trans_wrapper(wr);
3639 }
3640
3641 static struct {
3642 uint8_t status;
3643 usb_cr_t cr;
3644 } sts2cr[] = {
3645 {WA_STS_SUCCESS, USB_CR_OK},
3646 {WA_STS_HALTED, USB_CR_STALL},
3647 {WA_STS_DATA_BUFFER_ERROR, USB_CR_DATA_OVERRUN},
3648 {WA_STS_BABBLE, USB_CR_DATA_UNDERRUN},
3649 {WA_STS_NOT_FOUND, USB_CR_NOT_ACCESSED},
3650 {WA_STS_INSUFFICIENT_RESOURCE, USB_CR_NO_RESOURCES},
3651 {0x80 | WA_STS_TRANSACTION_ERROR, USB_CR_STALL},
3652 {0x40 | WA_STS_TRANSACTION_ERROR, USB_CR_OK},
3653 {WA_STS_ABORTED, USB_CR_FLUSHED},
3654 {WA_STS_RPIPE_NOT_READY, USB_CR_DEV_NOT_RESP},
3655 {WA_STS_INVALID_REQ_FORMAT, USB_CR_CRC},
3656 {WA_STS_UNEXPECTED_SEGMENT_NUM, USB_CR_UNEXP_PID},
3657 {WA_STS_RPIPE_TYPE_MISMATCH, USB_CR_NOT_SUPPORTED},
3658 {WA_STS_PACKET_DISCARDED, USB_CR_PID_CHECKFAILURE},
3659 {0xff, 0} /* end */
3660 };
3661
3662 /* translate transfer status to USB completion reason */
3663 usb_cr_t
wusb_wa_sts2cr(uint8_t rawstatus)3664 wusb_wa_sts2cr(uint8_t rawstatus)
3665 {
3666 int i;
3667 uint8_t status;
3668
3669 /* cares about bits5:0 in WUSB 1.0 */
3670 if ((rawstatus & 0x1f) == WA_STS_TRANSACTION_ERROR) {
3671 status = rawstatus;
3672 } else {
3673 status = rawstatus & 0x1f;
3674 }
3675
3676 for (i = 0; sts2cr[i].status != 0xff; i++) {
3677 if (sts2cr[i].status == status) {
3678
3679 return (sts2cr[i].cr);
3680 }
3681 }
3682
3683 return (USB_CR_UNSPECIFIED_ERR);
3684 }
3685