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 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 * Copyright 2019 Joyent, Inc.
25 */
26
27
28 /*
29 * USBA: Solaris USB Architecture support
30 *
31 * functions that deal with allocation/free/data_xfers
32 * for the control/bulk/interrupt/isoch pipes:
33 * usb_alloc_ctrl_req()
34 * usb_free_ctrl_req()
35 * usb_pipe_ctrl_xfer()
36 * usb_pipe_sync_ctrl_xfer()
37 * usb_pipe_ctrl_xfer_wait()
38 *
39 * usb_alloc_bulk_req()
40 * usb_free_bulk_req()
41 * usb_pipe_bulk_xfer()
42 * usb_pipe_bulk_transfer_size()
43 *
44 * usb_alloc_intr_req()
45 * usb_free_intr_req()
46 * usb_pipe_intr_xfer()
47 * usb_pipe_stop_intr_polling()
48 *
49 * usb_alloc_isoc_req()
50 * usb_free_isoc_req()
51 * usb_get_current_frame_number()
52 * usb_get_max_isoc_pkts()
53 * usb_pipe_isoc_xfer()
54 * usb_pipe_stop_isoc_polling()
55 *
56 * XXX to do:
57 * update return values where needed
58 * keep track of requests not freed
59 *
60 */
61 #define USBA_FRAMEWORK
62 #include <sys/usb/usba/usba_impl.h>
63 #include <sys/usb/usba/hcdi_impl.h>
64 #include <sys/strsubr.h>
65 #include <sys/strsun.h>
66
67 /* prototypes */
68 static int usba_flags_attr_check(usba_pipe_handle_data_t *,
69 usb_req_attrs_t attrs, usb_flags_t);
70 static int _usba_check_req(usba_pipe_handle_data_t *, usb_opaque_t,
71 usb_flags_t, uchar_t);
72
73 /*
74 * usba_check_req:
75 * check pipe, request structure for validity
76 *
77 * Arguments:
78 * ph - pipe handle pointer
79 * req - opaque request pointer
80 * flags - usb flags
81 *
82 * Returns:
83 * USB_SUCCESS - valid request
84 * USB_INVALID_REQUEST - request contains some invalid values
85 * USB_PIPE_ERROR - pipe is in error state
86 * USB_INVALID_CONTEXT - sleep in interrupt context
87 * USB_INVALID_PIPE - zero pipe or wrong pipe
88 */
89 static int
usba_check_req(usba_pipe_handle_data_t * ph_data,usb_opaque_t req,usb_flags_t flags,uchar_t pipe_type)90 usba_check_req(usba_pipe_handle_data_t *ph_data, usb_opaque_t req,
91 usb_flags_t flags, uchar_t pipe_type)
92 {
93 int rval = _usba_check_req(ph_data, req, flags, pipe_type);
94
95 if (rval != USB_SUCCESS) {
96 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
97 "usba_check_req: ph_data=0x%p req=0x%p flags=0%x rval=%d",
98 (void *)ph_data, (void *)req, flags, rval);
99 }
100
101 return (rval);
102 }
103
104
105 static int
_usba_check_req(usba_pipe_handle_data_t * ph_data,usb_opaque_t req,usb_flags_t flags,uchar_t pipe_type)106 _usba_check_req(usba_pipe_handle_data_t *ph_data, usb_opaque_t req,
107 usb_flags_t flags, uchar_t pipe_type)
108 {
109 usb_ctrl_req_t *ctrl_req = (usb_ctrl_req_t *)req;
110 usb_bulk_req_t *bulk_req = (usb_bulk_req_t *)req;
111 usb_intr_req_t *intr_req = (usb_intr_req_t *)req;
112 usb_isoc_req_t *isoc_req = (usb_isoc_req_t *)req;
113 usba_req_wrapper_t *wrp = USBA_REQ2WRP(req);
114 mblk_t *data;
115 usb_cr_t *cr;
116 usb_req_attrs_t attrs;
117 usb_opaque_t cb = NULL, exc_cb = NULL;
118 uint_t timeout = 0;
119 uchar_t direction = ph_data->p_ep.bEndpointAddress &
120 USB_EP_DIR_MASK;
121 uchar_t ep_attrs = ph_data->p_ep.bmAttributes &
122 USB_EP_ATTR_MASK;
123 int n;
124
125 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
126 "usba_check_req: ph_data=0x%p req=0x%p flags=0x%x",
127 (void *)ph_data, (void *)req, flags);
128
129 if (req == NULL) {
130
131 return (USB_INVALID_ARGS);
132 }
133
134 /* set completion reason first so it specifies an error */
135 switch (ep_attrs) {
136 case USB_EP_ATTR_CONTROL:
137 cr = &ctrl_req->ctrl_completion_reason;
138 break;
139 case USB_EP_ATTR_BULK:
140 cr = &bulk_req->bulk_completion_reason;
141 break;
142 case USB_EP_ATTR_INTR:
143 cr = &intr_req->intr_completion_reason;
144 break;
145 case USB_EP_ATTR_ISOCH:
146 cr = &isoc_req->isoc_completion_reason;
147 break;
148 default:
149 return (USB_INVALID_REQUEST);
150 }
151
152 *cr = USB_CR_UNSPECIFIED_ERR;
153
154 if (servicing_interrupt() && (flags & USB_FLAGS_SLEEP)) {
155
156 return (USB_INVALID_CONTEXT);
157 }
158
159 if (pipe_type != ep_attrs) {
160
161 return (USB_INVALID_PIPE);
162 }
163
164 /* we must have usba_device and default ph to do autoclearing */
165 ASSERT(ph_data->p_usba_device);
166
167 if (ph_data->p_usba_device->usb_ph_list[0].usba_ph_data == NULL) {
168
169 return (USB_INVALID_PIPE);
170 }
171
172 /* check if this is a valid request packet, ie. not freed */
173 if (usba_check_in_list(&(ph_data->p_usba_device->usb_allocated),
174 &wrp->wr_allocated_list) != USB_SUCCESS) {
175
176 return (USB_INVALID_REQUEST);
177 }
178
179 /* copy over some members for easy checking later */
180 switch (ep_attrs) {
181 case USB_EP_ATTR_CONTROL:
182 ctrl_req->ctrl_cb_flags = USB_CB_NO_INFO;
183 data = ctrl_req->ctrl_data;
184 attrs = ctrl_req->ctrl_attributes;
185 timeout = ctrl_req->ctrl_timeout;
186 cb = (usb_opaque_t)ctrl_req->ctrl_cb;
187 exc_cb = (usb_opaque_t)ctrl_req->ctrl_exc_cb;
188 if (flags & USB_FLAGS_SLEEP) {
189 flags |= USBA_WRP_FLAGS_WAIT;
190 }
191 /* force auto clearing on the default pipe */
192 if (USBA_IS_DEFAULT_PIPE(ph_data)) {
193 attrs |= USB_ATTRS_AUTOCLEARING;
194 }
195 break;
196 case USB_EP_ATTR_BULK:
197 bulk_req->bulk_cb_flags = USB_CB_NO_INFO;
198 data = bulk_req->bulk_data;
199 attrs = bulk_req->bulk_attributes;
200 timeout = bulk_req->bulk_timeout;
201 cb = (usb_opaque_t)bulk_req->bulk_cb;
202 exc_cb = (usb_opaque_t)bulk_req->bulk_exc_cb;
203 if (flags & USB_FLAGS_SLEEP) {
204 flags |= USBA_WRP_FLAGS_WAIT;
205 }
206 break;
207 case USB_EP_ATTR_INTR:
208 intr_req->intr_cb_flags = USB_CB_NO_INFO;
209 data = intr_req->intr_data;
210 attrs = intr_req->intr_attributes;
211 timeout = intr_req->intr_timeout;
212 cb = (usb_opaque_t)intr_req->intr_cb;
213 exc_cb = (usb_opaque_t)intr_req->intr_exc_cb;
214 if ((flags & USB_FLAGS_SLEEP) &&
215 (attrs & USB_ATTRS_ONE_XFER)) {
216 flags |= USBA_WRP_FLAGS_WAIT;
217 }
218 break;
219 case USB_EP_ATTR_ISOCH:
220 isoc_req->isoc_cb_flags = USB_CB_NO_INFO;
221 data = isoc_req->isoc_data;
222 attrs = isoc_req->isoc_attributes;
223 cb = (usb_opaque_t)isoc_req->isoc_cb;
224 exc_cb = (usb_opaque_t)isoc_req->isoc_exc_cb;
225 break;
226 default:
227 return (USB_INVALID_REQUEST);
228 }
229
230 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
231 "usba_check_req: attrs = 0x%x flags=0x%x", attrs, flags);
232
233 /* check flags and attr combinations */
234 if (usba_flags_attr_check(ph_data, attrs, flags) !=
235 USB_SUCCESS) {
236
237 return (USB_INVALID_REQUEST);
238 }
239
240 /* if no sleep, there must be callback ptrs */
241 if ((flags & USB_FLAGS_SLEEP) == 0) {
242 if (cb == NULL || exc_cb == NULL) {
243
244 return (USB_INVALID_REQUEST);
245 }
246 }
247
248 switch (ep_attrs) {
249 case USB_EP_ATTR_CONTROL:
250 if (ctrl_req->ctrl_wLength && (data == NULL)) {
251
252 return (USB_INVALID_REQUEST);
253 }
254 break;
255 case USB_EP_ATTR_BULK:
256 if ((bulk_req->bulk_len) && (data == NULL)) {
257
258 return (USB_INVALID_REQUEST);
259 }
260 break;
261 case USB_EP_ATTR_INTR:
262 if (direction == USB_EP_DIR_OUT) {
263 if (intr_req->intr_len && data == NULL) {
264
265 return (USB_INVALID_REQUEST);
266 }
267 }
268
269 if (direction == USB_EP_DIR_IN) {
270 if (!(intr_req->intr_attributes & USB_ATTRS_ONE_XFER)) {
271 if (cb == NULL || exc_cb == NULL) {
272
273 return (USB_INVALID_REQUEST);
274 }
275 }
276 if (data != NULL) {
277
278 return (USB_INVALID_REQUEST);
279 }
280 if (!(intr_req->intr_attributes & USB_ATTRS_ONE_XFER) &&
281 (timeout > 0)) {
282
283 return (USB_INVALID_REQUEST);
284 }
285 }
286 break;
287 case USB_EP_ATTR_ISOCH:
288 if (direction == USB_EP_DIR_IN) {
289 if (cb == NULL || exc_cb == NULL) {
290
291 return (USB_INVALID_REQUEST);
292 }
293 }
294
295 if (data == NULL) {
296
297 return (USB_INVALID_REQUEST);
298 }
299
300 /*
301 * Since ehci/ohci/uhci use (data->b_wptr - data->b_rptr) as
302 * real isoc_pkts_length, it should be checked.
303 */
304 if (direction == USB_EP_DIR_OUT) {
305 if (MBLKL(data) <= 0) {
306
307 return (USB_INVALID_REQUEST);
308 }
309 }
310
311 /* special isoc checks */
312 if ((isoc_req->isoc_pkts_count == 0) ||
313 (isoc_req->isoc_pkt_descr == NULL)) {
314
315 return (USB_INVALID_REQUEST);
316 }
317
318 /* check attributes for conflicts, one must be specified */
319 if (!((isoc_req->isoc_attributes &
320 USB_ATTRS_ISOC_START_FRAME) ||
321 (isoc_req->isoc_attributes & USB_ATTRS_ISOC_XFER_ASAP))) {
322
323 return (USB_NO_FRAME_NUMBER);
324 }
325
326 /* both may not be specified */
327 if ((isoc_req->isoc_attributes &
328 (USB_ATTRS_ISOC_START_FRAME | USB_ATTRS_ISOC_XFER_ASAP)) ==
329 (USB_ATTRS_ISOC_START_FRAME | USB_ATTRS_ISOC_XFER_ASAP)) {
330
331 return (USB_NO_FRAME_NUMBER);
332 }
333
334 /* no start frame may be specified for ASAP attribute */
335 if (((isoc_req->isoc_attributes & USB_ATTRS_ISOC_XFER_ASAP)) &&
336 isoc_req->isoc_frame_no) {
337
338 return (USB_INVALID_REQUEST);
339 }
340
341 /* start frame must be specified for START FRAME attribute */
342 if (((isoc_req->isoc_attributes &
343 USB_ATTRS_ISOC_START_FRAME)) &&
344 (isoc_req->isoc_frame_no == 0)) {
345
346 return (USB_NO_FRAME_NUMBER);
347 }
348
349 /* each packet must have initialized pkt length */
350 for (n = 0; n < isoc_req->isoc_pkts_count; n++) {
351 if (isoc_req->isoc_pkt_descr[n].isoc_pkt_length == 0) {
352
353 return (USB_INVALID_REQUEST);
354 }
355 }
356 break;
357 }
358
359 /* save pipe_handle/attrs/timeout/usb_flags */
360 wrp->wr_ph_data = ph_data;
361 wrp->wr_usb_flags = flags;
362 wrp->wr_attrs = attrs;
363
364 /* zero some fields in case the request is reused */
365 wrp->wr_done = B_FALSE;
366 wrp->wr_cr = USB_CR_OK;
367
368 /* this request looks good */
369 *cr = USB_CR_OK;
370
371 return (USB_SUCCESS);
372 }
373
374
375 /*
376 * Table of invalid flags and attributes values. See "usbai.h"
377 * for a complete table on valid usb_req_attrs_t
378 */
379 #define X ((uint_t)(-1))
380 #define OUT USB_EP_DIR_OUT
381 #define IN USB_EP_DIR_IN
382
383 struct flags_attr {
384 uint_t ep_dir;
385 uint_t ep_attr;
386 uint_t usb_flags; /* usb_flags SLEEP or none */
387 uint_t attrs;
388 } usb_invalid_flags_attrs[] = {
389 { OUT, USB_EP_ATTR_BULK, X, USB_ATTRS_SHORT_XFER_OK },
390 { OUT, USB_EP_ATTR_INTR, X, USB_ATTRS_SHORT_XFER_OK },
391 { OUT, USB_EP_ATTR_ISOCH, X, USB_ATTRS_SHORT_XFER_OK },
392
393 { X, USB_EP_ATTR_CONTROL, X, USB_ATTRS_ISOC_START_FRAME },
394 { X, USB_EP_ATTR_BULK, X, USB_ATTRS_ISOC_START_FRAME },
395 { X, USB_EP_ATTR_INTR, X, USB_ATTRS_ISOC_START_FRAME },
396
397 { X, USB_EP_ATTR_CONTROL, X, USB_ATTRS_ISOC_XFER_ASAP },
398 { X, USB_EP_ATTR_INTR, X, USB_ATTRS_ISOC_XFER_ASAP },
399 { OUT, USB_EP_ATTR_INTR, X, USB_ATTRS_ONE_XFER },
400 { X, USB_EP_ATTR_BULK, X, USB_ATTRS_ISOC_XFER_ASAP },
401
402 { X, USB_EP_ATTR_CONTROL, X, USB_ATTRS_ONE_XFER },
403 { X, USB_EP_ATTR_BULK, X, USB_ATTRS_ONE_XFER },
404 { X, USB_EP_ATTR_ISOCH, X, USB_ATTRS_ONE_XFER },
405 };
406
407 #define N_INVALID_FLAGS_ATTRS (sizeof (usb_invalid_flags_attrs))/ \
408 sizeof (struct flags_attr)
409
410 /*
411 * function to check flags and attribute combinations for a particular pipe
412 * Arguments:
413 * ph - pipe handle pointer
414 * attrs - attributes of the request
415 * flags - usb_flags
416 */
417 static int
usba_flags_attr_check(usba_pipe_handle_data_t * ph_data,usb_req_attrs_t attrs,usb_flags_t flags)418 usba_flags_attr_check(usba_pipe_handle_data_t *ph_data,
419 usb_req_attrs_t attrs,
420 usb_flags_t flags)
421 {
422 uchar_t i;
423 uchar_t ep_dir = ph_data->p_ep.bEndpointAddress & USB_EP_DIR_MASK;
424 uchar_t ep_attr = ph_data->p_ep.bmAttributes & USB_EP_ATTR_MASK;
425
426 flags &= USB_FLAGS_SLEEP; /* ignore other flags */
427
428 /*
429 * Do some attributes validation checks here.
430 */
431 for (i = 0; i < N_INVALID_FLAGS_ATTRS; i++) {
432 if (((ep_dir == usb_invalid_flags_attrs[i].ep_dir) ||
433 (usb_invalid_flags_attrs[i].ep_dir == X)) &&
434 ((ep_attr == usb_invalid_flags_attrs[i].ep_attr) ||
435 (usb_invalid_flags_attrs[i].ep_attr == X)) &&
436 ((flags & usb_invalid_flags_attrs[i].usb_flags) ||
437 (usb_invalid_flags_attrs[i].usb_flags == X)) &&
438 ((attrs & usb_invalid_flags_attrs[i].attrs) ||
439 (usb_invalid_flags_attrs[i].attrs == X))) {
440 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
441 "invalid (%d) : flags = 0x%x, attrs = 0x%x",
442 i, flags, attrs);
443
444 return (USB_INVALID_REQUEST);
445 }
446 }
447
448 return (USB_SUCCESS);
449 }
450
451
452 /*
453 * usba_rval2cr:
454 * convert rval to meaningful completion reason
455 * XXX extend completion reasons to get better mapping
456 */
457 static struct {
458 int rval;
459 usb_cr_t cr;
460 } rval2cr[] = {
461 {USB_SUCCESS, USB_CR_OK},
462 {USB_FAILURE, USB_CR_UNSPECIFIED_ERR},
463 {USB_NO_RESOURCES, USB_CR_NO_RESOURCES},
464 {USB_NO_BANDWIDTH, USB_CR_NO_RESOURCES},
465 {USB_NOT_SUPPORTED, USB_CR_UNSPECIFIED_ERR},
466 {USB_PIPE_ERROR, USB_CR_UNSPECIFIED_ERR},
467 {USB_INVALID_PIPE, USB_CR_UNSPECIFIED_ERR},
468 {USB_NO_FRAME_NUMBER, USB_CR_UNSPECIFIED_ERR},
469 {USB_INVALID_START_FRAME, USB_CR_UNSPECIFIED_ERR},
470 {USB_HC_HARDWARE_ERROR, USB_CR_UNSPECIFIED_ERR},
471 {USB_INVALID_REQUEST, USB_CR_UNSPECIFIED_ERR},
472 {USB_INVALID_CONTEXT, USB_CR_UNSPECIFIED_ERR},
473 {USB_INVALID_VERSION, USB_CR_UNSPECIFIED_ERR},
474 {USB_INVALID_ARGS, USB_CR_UNSPECIFIED_ERR},
475 {USB_INVALID_PERM, USB_CR_UNSPECIFIED_ERR},
476 {USB_BUSY, USB_CR_UNSPECIFIED_ERR},
477 {0xffff, 0}
478 };
479
480 usb_cr_t
usba_rval2cr(int rval)481 usba_rval2cr(int rval)
482 {
483 int i;
484
485 for (i = 0; rval2cr[i].rval != 0xffff; i++) {
486 if (rval2cr[i].rval == rval) {
487
488 return (rval2cr[i].cr);
489 }
490 }
491
492 return (USB_CR_UNSPECIFIED_ERR);
493 }
494
495
496 /*
497 * usba_start_next_req:
498 * Arguments:
499 * ph_data - pointer to pipe handle
500 *
501 * Currently, only ctrl/bulk requests can be queued
502 */
503 void
usba_start_next_req(usba_pipe_handle_data_t * ph_data)504 usba_start_next_req(usba_pipe_handle_data_t *ph_data)
505 {
506 usb_ctrl_req_t *ctrl_req;
507 usb_bulk_req_t *bulk_req;
508 usba_req_wrapper_t *wrp;
509 uchar_t ep_attrs = ph_data->p_ep.bmAttributes &
510 USB_EP_ATTR_MASK;
511 int rval;
512 usb_pipe_state_t state;
513
514 mutex_enter(&ph_data->p_mutex);
515 switch (ep_attrs) {
516 case USB_EP_ATTR_CONTROL:
517 case USB_EP_ATTR_BULK:
518 switch (usba_get_ph_state(ph_data)) {
519 case USB_PIPE_STATE_IDLE:
520 case USB_PIPE_STATE_CLOSING:
521
522 break;
523
524 default:
525 mutex_exit(&ph_data->p_mutex);
526
527 return;
528 }
529
530 break;
531 case USB_EP_ATTR_ISOCH:
532 case USB_EP_ATTR_INTR:
533 default:
534 mutex_exit(&ph_data->p_mutex);
535
536 return;
537 }
538
539 while ((wrp = (usba_req_wrapper_t *)
540 usba_rm_first_pvt_from_list(&ph_data->p_queue)) != NULL) {
541
542 /* only submit to HCD when idle/active */
543
544 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
545 "usba_start_next_req: ph_data=0x%p state=%d",
546 (void *)ph_data, usba_get_ph_state(ph_data));
547
548 if (ep_attrs == USB_EP_ATTR_CONTROL) {
549 ph_data->p_active_cntrl_req_wrp = (usb_opaque_t)wrp;
550 }
551
552 if ((state = usba_get_ph_state(ph_data)) ==
553 USB_PIPE_STATE_IDLE) {
554 usba_pipe_new_state(ph_data, USB_PIPE_STATE_ACTIVE);
555
556 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
557 "starting req = 0x%p",
558 (void *)USBA_WRP2CTRL_REQ(wrp));
559
560 switch (ep_attrs) {
561 case USB_EP_ATTR_CONTROL:
562 mutex_exit(&ph_data->p_mutex);
563 ctrl_req = USBA_WRP2CTRL_REQ(wrp);
564 /* submit to hcd */
565 rval = ph_data->p_usba_device->usb_hcdi_ops->
566 usba_hcdi_pipe_ctrl_xfer(ph_data,
567 ctrl_req, wrp->wr_usb_flags);
568 mutex_enter(&ph_data->p_mutex);
569 break;
570 case USB_EP_ATTR_BULK:
571 mutex_exit(&ph_data->p_mutex);
572 bulk_req = USBA_WRP2BULK_REQ(wrp);
573 /* submit to hcd */
574 rval = ph_data->p_usba_device->usb_hcdi_ops->
575 usba_hcdi_pipe_bulk_xfer(ph_data,
576 bulk_req, wrp->wr_usb_flags);
577 mutex_enter(&ph_data->p_mutex);
578 break;
579 default:
580 /* there shouldn't be any requests */
581 rval = USB_FAILURE;
582 break;
583 }
584
585 if (rval != USB_SUCCESS) {
586 mutex_exit(&ph_data->p_mutex);
587 usba_do_req_exc_cb(wrp,
588 usba_rval2cr(rval),
589 USB_CB_SUBMIT_FAILED);
590 mutex_enter(&ph_data->p_mutex);
591 }
592 /* we are done */
593 break;
594
595 } else {
596 mutex_exit(&ph_data->p_mutex);
597 switch (state) {
598 case USB_PIPE_STATE_CLOSING:
599 usba_do_req_exc_cb(wrp, USB_CR_PIPE_CLOSING, 0);
600 break;
601 case USB_PIPE_STATE_ERROR:
602 default:
603 usba_do_req_exc_cb(wrp, USB_CR_FLUSHED, 0);
604 break;
605 }
606 mutex_enter(&ph_data->p_mutex);
607 }
608 }
609
610 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
611 "usba_start_next_req done: ph_data=0x%p state=%d", (void *)ph_data,
612 usba_get_ph_state(ph_data));
613
614 mutex_exit(&ph_data->p_mutex);
615 }
616
617
618 /*
619 * usba_req_wrapper_alloc:
620 * Allocate + Initialize a usba_req_wrapper_t
621 *
622 * Arguments:
623 * dip - dev_info_t of the client driver
624 * req_len - sizeof request
625 * flags -
626 * USB_FLAGS_SLEEP - Sleep if resources are not available
627 * no USB_FLAGS_SLEEP - Don't Sleep if resources are not available
628 *
629 * Return Values:
630 * pointer to usba_req_wrapper_t on success; NULL on failure.
631 *
632 */
633 static usba_req_wrapper_t *
usba_req_wrapper_alloc(dev_info_t * dip,size_t req_len,usb_flags_t flags)634 usba_req_wrapper_alloc(dev_info_t *dip,
635 size_t req_len,
636 usb_flags_t flags)
637 {
638 int kmflag;
639 usba_device_t *usba_device = usba_get_usba_device(dip);
640 usba_req_wrapper_t *wrp;
641 size_t wr_length = sizeof (usba_req_wrapper_t) + req_len;
642 ddi_iblock_cookie_t iblock_cookie =
643 usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip)->
644 hcdi_iblock_cookie;
645
646 if (servicing_interrupt() && (flags & USB_FLAGS_SLEEP)) {
647
648 return (NULL);
649 }
650
651 kmflag = (flags & USB_FLAGS_SLEEP) ? KM_SLEEP : KM_NOSLEEP;
652
653 /* Allocate the usb_{c/b/i/i}_req + usba_req_wrapper_t structure */
654 if ((wrp = kmem_zalloc(wr_length, kmflag)) != NULL) {
655 wrp->wr_length = wr_length;
656 wrp->wr_dip = dip;
657 wrp->wr_req = (usb_opaque_t)USBA_SETREQ_ADDR(wrp);
658 cv_init(&wrp->wr_cv, NULL, CV_DRIVER, NULL);
659
660 /* initialize mutex for the queue */
661 usba_init_list(&wrp->wr_queue, (usb_opaque_t)wrp,
662 iblock_cookie);
663 usba_init_list(&wrp->wr_allocated_list, (usb_opaque_t)wrp,
664 iblock_cookie);
665
666 usba_add_to_list(&usba_device->usb_allocated,
667 &wrp->wr_allocated_list);
668
669 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
670 "usba_req_wrapper_alloc: wrp = 0x%p", (void *)wrp);
671 }
672
673 return (wrp);
674 }
675
676
677 /*
678 * usba_req_wrapper_free:
679 * Frees a usba_req_wrapper_t. Get rid of lists if any.
680 *
681 * Arguments:
682 * wrp: request wrapper structure
683 */
684 void
usba_req_wrapper_free(usba_req_wrapper_t * wrp)685 usba_req_wrapper_free(usba_req_wrapper_t *wrp)
686 {
687 usba_device_t *usba_device;
688 usba_pipe_handle_data_t *ph_data;
689
690 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
691 "usba_req_wrapper_free: wrp=0x%p", (void *)wrp);
692
693 if (wrp) {
694 /* remove from queues */
695 ph_data = USBA_WRP2PH_DATA(wrp);
696 if (ph_data) {
697 (void) usba_rm_from_list(&ph_data->p_queue,
698 &wrp->wr_queue);
699 }
700 usba_device = usba_get_usba_device(wrp->wr_dip);
701 if (usba_rm_from_list(&usba_device->usb_allocated,
702 &wrp->wr_allocated_list) != USB_SUCCESS) {
703 cmn_err(CE_PANIC,
704 "usba_req_wrapper_free: data corruption");
705 }
706 usba_destroy_list(&wrp->wr_queue);
707 usba_destroy_list(&wrp->wr_allocated_list);
708 cv_destroy(&wrp->wr_cv);
709 kmem_free(wrp, wrp->wr_length);
710 }
711 }
712
713
714 /*
715 * usba_check_intr_context
716 * Set USB_CB_INTR_CONTEXT callback flag if executing in interrupt context
717 */
718 usb_cb_flags_t
usba_check_intr_context(usb_cb_flags_t cb_flags)719 usba_check_intr_context(usb_cb_flags_t cb_flags)
720 {
721 if (servicing_interrupt() != 0) {
722 cb_flags |= USB_CB_INTR_CONTEXT;
723 }
724
725 return (cb_flags);
726 }
727
728
729 /*
730 * usba_req_normal_cb:
731 * perform normal callback depending on request type
732 */
733 void
usba_req_normal_cb(usba_req_wrapper_t * req_wrp)734 usba_req_normal_cb(usba_req_wrapper_t *req_wrp)
735 {
736 usba_pipe_handle_data_t *ph_data = req_wrp->wr_ph_data;
737 usb_pipe_handle_t pipe_handle;
738 uint_t direction = ph_data->p_ep.bEndpointAddress &
739 USB_EP_DIR_MASK;
740 usb_pipe_state_t pipe_state;
741
742 pipe_handle = usba_get_pipe_handle(ph_data);
743
744 mutex_enter(&ph_data->p_mutex);
745 ASSERT(ph_data->p_req_count >= 0);
746 pipe_state = usba_get_ph_state(ph_data);
747
748 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
749 "usba_req_normal_cb: "
750 "ph_data=0x%p state=%d wrp=0x%p ref=%d req=%d",
751 (void *)ph_data, pipe_state, (void *)req_wrp,
752 usba_get_ph_ref_count(ph_data), ph_data->p_req_count);
753
754 ASSERT((pipe_state == USB_PIPE_STATE_ACTIVE) ||
755 (pipe_state == USB_PIPE_STATE_CLOSING));
756
757 /* set done to indicate that we will do callback or cv_signal */
758 ASSERT(req_wrp->wr_done == B_FALSE);
759 req_wrp->wr_done = B_TRUE;
760
761 /* update the pipe state */
762 switch (req_wrp->wr_ph_data->p_ep.bmAttributes &
763 USB_EP_ATTR_MASK) {
764 case USB_EP_ATTR_CONTROL:
765 case USB_EP_ATTR_BULK:
766 usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE);
767 break;
768 case USB_EP_ATTR_INTR:
769 if ((direction == USB_EP_DIR_IN) &&
770 (USBA_WRP2INTR_REQ(req_wrp)->intr_attributes &
771 USB_ATTRS_ONE_XFER)) {
772 usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE);
773 } else if ((direction == USB_EP_DIR_OUT) &&
774 (ph_data->p_req_count == 0)) {
775 usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE);
776 }
777 break;
778 case USB_EP_ATTR_ISOCH:
779 if ((ph_data->p_req_count == 0) &&
780 (direction == USB_EP_DIR_OUT)) {
781 usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE);
782 }
783 break;
784 }
785
786
787 /* now complete the request */
788 if (req_wrp->wr_usb_flags & USBA_WRP_FLAGS_WAIT) {
789 ph_data->p_active_cntrl_req_wrp = NULL;
790 cv_signal(&req_wrp->wr_cv);
791 mutex_exit(&ph_data->p_mutex);
792 } else {
793 mutex_exit(&ph_data->p_mutex);
794
795 /* This sets USB_CB_INTR_CONTEXT as needed. */
796 usba_req_set_cb_flags(req_wrp, USB_CB_NO_INFO);
797
798 switch (req_wrp->wr_ph_data->p_ep.bmAttributes &
799 USB_EP_ATTR_MASK) {
800 case USB_EP_ATTR_CONTROL:
801 USBA_WRP2CTRL_REQ(req_wrp)->ctrl_cb(pipe_handle,
802 USBA_WRP2CTRL_REQ(req_wrp));
803 mutex_enter(&ph_data->p_mutex);
804 ph_data->p_active_cntrl_req_wrp = NULL;
805 mutex_exit(&ph_data->p_mutex);
806 break;
807 case USB_EP_ATTR_INTR:
808 USBA_WRP2INTR_REQ(req_wrp)->intr_cb(pipe_handle,
809 USBA_WRP2INTR_REQ(req_wrp));
810 break;
811 case USB_EP_ATTR_BULK:
812 USBA_WRP2BULK_REQ(req_wrp)->bulk_cb(pipe_handle,
813 USBA_WRP2BULK_REQ(req_wrp));
814 break;
815 case USB_EP_ATTR_ISOCH:
816 USBA_WRP2ISOC_REQ(req_wrp)->isoc_cb(pipe_handle,
817 USBA_WRP2ISOC_REQ(req_wrp));
818 break;
819 }
820 }
821
822 /* we are done with this request */
823 mutex_enter(&ph_data->p_mutex);
824 ph_data->p_req_count--;
825 ASSERT(ph_data->p_req_count >= 0);
826 mutex_exit(&ph_data->p_mutex);
827 }
828
829
830 /*
831 * usba_req_exc_cb:
832 * perform exception cb depending on request type.
833 * ensure the completion reason is non zero
834 */
835 void
usba_req_exc_cb(usba_req_wrapper_t * req_wrp,usb_cr_t cr,usb_cb_flags_t cb_flags)836 usba_req_exc_cb(usba_req_wrapper_t *req_wrp, usb_cr_t cr,
837 usb_cb_flags_t cb_flags)
838 {
839 usba_pipe_handle_data_t *ph_data = req_wrp->wr_ph_data;
840 usb_pipe_handle_t pipe_handle = usba_get_pipe_handle(ph_data);
841
842 mutex_enter(&req_wrp->wr_ph_data->p_mutex);
843 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
844 "usba_req_exc_cb: %s%d: ph_data=0x%p (ep%x) state=%d wrp=0x%p "
845 "ref=%d reqcnt=%d cr=%d",
846 ddi_driver_name(req_wrp->wr_dip),
847 ddi_get_instance(req_wrp->wr_dip),
848 (void *)ph_data, ph_data->p_ep.bEndpointAddress,
849 usba_get_ph_state(ph_data), (void *)req_wrp,
850 usba_get_ph_ref_count(ph_data), ph_data->p_req_count,
851 req_wrp->wr_cr);
852
853 ASSERT(req_wrp->wr_ph_data->p_req_count >= 0);
854
855 usba_req_set_cb_flags(req_wrp, cb_flags);
856
857 /* if there was no CR set already, set it now */
858 if (req_wrp->wr_cr == USB_CR_OK) {
859 req_wrp->wr_cr = (cr != USB_CR_OK) ?
860 cr : USB_CR_UNSPECIFIED_ERR;
861 }
862
863 ASSERT(req_wrp->wr_done == B_FALSE);
864 req_wrp->wr_done = B_TRUE;
865
866 switch (req_wrp->wr_ph_data->p_ep.bmAttributes &
867 USB_EP_ATTR_MASK) {
868 case USB_EP_ATTR_CONTROL:
869 if (USBA_WRP2CTRL_REQ(req_wrp)->
870 ctrl_completion_reason == USB_CR_OK) {
871 USBA_WRP2CTRL_REQ(req_wrp)->
872 ctrl_completion_reason = req_wrp->wr_cr;
873 }
874 break;
875 case USB_EP_ATTR_INTR:
876 if (USBA_WRP2INTR_REQ(req_wrp)->
877 intr_completion_reason == USB_CR_OK) {
878 USBA_WRP2INTR_REQ(req_wrp)->
879 intr_completion_reason = req_wrp->wr_cr;
880 }
881 break;
882 case USB_EP_ATTR_BULK:
883 if (USBA_WRP2BULK_REQ(req_wrp)->
884 bulk_completion_reason == USB_CR_OK) {
885 USBA_WRP2BULK_REQ(req_wrp)->
886 bulk_completion_reason = req_wrp->wr_cr;
887 }
888 break;
889 case USB_EP_ATTR_ISOCH:
890 if (USBA_WRP2ISOC_REQ(req_wrp)->
891 isoc_completion_reason == USB_CR_OK) {
892 USBA_WRP2ISOC_REQ(req_wrp)->
893 isoc_completion_reason = req_wrp->wr_cr;
894 }
895 break;
896 }
897
898 if (req_wrp->wr_usb_flags & USBA_WRP_FLAGS_WAIT) {
899 cv_signal(&req_wrp->wr_cv);
900 if (ph_data->p_active_cntrl_req_wrp == (usb_opaque_t)req_wrp) {
901 ph_data->p_active_cntrl_req_wrp = NULL;
902 }
903 mutex_exit(&ph_data->p_mutex);
904 } else {
905 mutex_exit(&ph_data->p_mutex);
906 switch (req_wrp->wr_ph_data->p_ep.bmAttributes &
907 USB_EP_ATTR_MASK) {
908 case USB_EP_ATTR_CONTROL:
909 USBA_WRP2CTRL_REQ(req_wrp)->ctrl_exc_cb(pipe_handle,
910 USBA_WRP2CTRL_REQ(req_wrp));
911 mutex_enter(&ph_data->p_mutex);
912 if (ph_data->p_active_cntrl_req_wrp ==
913 (usb_opaque_t)req_wrp) {
914 ph_data->p_active_cntrl_req_wrp = NULL;
915 }
916 mutex_exit(&ph_data->p_mutex);
917 break;
918 case USB_EP_ATTR_INTR:
919 USBA_WRP2INTR_REQ(req_wrp)->intr_exc_cb(pipe_handle,
920 USBA_WRP2INTR_REQ(req_wrp));
921 break;
922 case USB_EP_ATTR_BULK:
923 USBA_WRP2BULK_REQ(req_wrp)->bulk_exc_cb(pipe_handle,
924 USBA_WRP2BULK_REQ(req_wrp));
925 break;
926 case USB_EP_ATTR_ISOCH:
927 USBA_WRP2ISOC_REQ(req_wrp)->isoc_exc_cb(pipe_handle,
928 USBA_WRP2ISOC_REQ(req_wrp));
929 break;
930 }
931 }
932
933 /* we are done with this request */
934 mutex_enter(&ph_data->p_mutex);
935 ph_data->p_req_count--;
936 ASSERT(ph_data->p_req_count >= 0);
937 mutex_exit(&ph_data->p_mutex);
938 }
939
940
941 /*
942 * usba_do_req_exc_cb:
943 * called when flushing requests. rather than calling usba_req_exc_cb()
944 * directly, this function uses usba_hcdi_cb() which ensures callback
945 * order is preserved
946 */
947 void
usba_do_req_exc_cb(usba_req_wrapper_t * req_wrp,usb_cr_t cr,usb_cb_flags_t cb_flags)948 usba_do_req_exc_cb(usba_req_wrapper_t *req_wrp, usb_cr_t cr,
949 usb_cb_flags_t cb_flags)
950 {
951 req_wrp->wr_cb_flags |= cb_flags;
952 usba_hcdi_cb(req_wrp->wr_ph_data, req_wrp->wr_req, cr);
953 }
954
955
956 /*
957 * usba_req_set_cb_flags:
958 * This function sets the request's callback flags to those stored in the
959 * request wrapper ORed with those received as an argument. Additionally
960 * USB_CB_INTR_CONTEXT is set if called from interrupt context.
961 *
962 * NOTE: The xfer may have succeeded, which client driver can determine
963 * by looking at usb_cr_t
964 */
965 void
usba_req_set_cb_flags(usba_req_wrapper_t * req_wrp,usb_cb_flags_t cb_flags)966 usba_req_set_cb_flags(usba_req_wrapper_t *req_wrp,
967 usb_cb_flags_t cb_flags)
968 {
969 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
970 "usba_req_set_cb_flags: wrp=0x%p cb-flags=0x%x",
971 (void *)req_wrp, cb_flags);
972
973 cb_flags |= req_wrp->wr_cb_flags;
974 cb_flags = usba_check_intr_context(cb_flags);
975
976 /* do the callback under taskq context */
977 switch (req_wrp->wr_ph_data->p_ep.bmAttributes &
978 USB_EP_ATTR_MASK) {
979 case USB_EP_ATTR_CONTROL:
980 USBA_WRP2CTRL_REQ(req_wrp)->ctrl_cb_flags |= cb_flags;
981 break;
982 case USB_EP_ATTR_INTR:
983 USBA_WRP2INTR_REQ(req_wrp)->intr_cb_flags |= cb_flags;
984 break;
985 case USB_EP_ATTR_BULK:
986 USBA_WRP2BULK_REQ(req_wrp)->bulk_cb_flags |= cb_flags;
987 break;
988 case USB_EP_ATTR_ISOCH:
989 USBA_WRP2ISOC_REQ(req_wrp)->isoc_cb_flags |= cb_flags;
990 break;
991 }
992 }
993
994
995 /*
996 * usba_pipe_sync_wait:
997 * wait for the request to finish.
998 * usba_hcdi_cb() does a cv_signal thru a soft intr
999 *
1000 * Arguments:
1001 * ph_data - pointer to pipe handle data
1002 * wrp - pointer to usba_req_wrapper_structure.
1003 *
1004 * Return Values:
1005 * USB_SUCCESS - request successfully executed
1006 * USB_FAILURE - request failed
1007 */
1008 static int
usba_pipe_sync_wait(usba_pipe_handle_data_t * ph_data,usba_req_wrapper_t * wrp)1009 usba_pipe_sync_wait(usba_pipe_handle_data_t *ph_data,
1010 usba_req_wrapper_t *wrp)
1011 {
1012 ASSERT(wrp->wr_usb_flags & USB_FLAGS_SLEEP);
1013 ASSERT(ph_data == wrp->wr_ph_data);
1014
1015 mutex_enter(&ph_data->p_mutex);
1016 while (wrp->wr_done != B_TRUE) {
1017 cv_wait(&wrp->wr_cv, &ph_data->p_mutex);
1018 }
1019
1020 mutex_exit(&ph_data->p_mutex);
1021
1022 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1023 "usba_pipe_sync_wait: ph_data=0x%p cr=0x%x", (void *)ph_data,
1024 wrp->wr_cr);
1025
1026 /* XXX return something better than USB_FAILURE?? */
1027
1028 return (wrp->wr_cr == USB_CR_OK ? USB_SUCCESS : USB_FAILURE);
1029 }
1030
1031
1032 /*
1033 * Allocate usb control request and a USB request wrapper
1034 *
1035 * Arguments:
1036 * dip - dev_info_t of the client driver
1037 * len - length of "data" for this control request
1038 * flags:
1039 * USB_FLAGS_SLEEP - Sleep if resources are not available
1040 * no USB_FLAGS_SLEEP - Don't Sleep if resources are not available
1041 *
1042 * Return Values: usb_ctrl_req_t on success, NULL on failure
1043 */
1044 usb_ctrl_req_t *
usb_alloc_ctrl_req(dev_info_t * dip,size_t len,usb_flags_t flags)1045 usb_alloc_ctrl_req(dev_info_t *dip,
1046 size_t len,
1047 usb_flags_t flags)
1048 {
1049 usb_ctrl_req_t *ctrl_req = NULL;
1050 usba_req_wrapper_t *wrp;
1051
1052 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1053 "usb_alloc_ctrl_req: dip=0x%p, wlen=0x%lx, flags=0x%x",
1054 (void *)dip, len, flags);
1055
1056 /* Allocate + Initialize the usba_req_wrapper_t structure */
1057 if (dip &&
1058 ((wrp = usba_req_wrapper_alloc(dip, sizeof (*ctrl_req), flags)) !=
1059 NULL)) {
1060 ctrl_req = USBA_WRP2CTRL_REQ(wrp);
1061
1062 /* Allocate the usb_ctrl_req data mblk */
1063 if (len) {
1064 if (flags & USB_FLAGS_SLEEP) {
1065 ctrl_req->ctrl_data = allocb_wait(len, BPRI_LO,
1066 STR_NOSIG, NULL);
1067 } else if ((ctrl_req->ctrl_data =
1068 allocb(len, BPRI_HI)) == NULL) {
1069 usba_req_wrapper_free(wrp);
1070 ctrl_req = NULL;
1071 }
1072 }
1073 }
1074
1075 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1076 "usb_alloc_ctrl_req: ctrl_req = 0x%p", (void *)ctrl_req);
1077
1078 return (ctrl_req);
1079 }
1080
1081
1082 /*
1083 * usb_free_ctrl_req:
1084 * free USB control request + wrapper
1085 *
1086 * Arguments:
1087 * req - pointer to usb_ctrl_req_t
1088 */
1089 void
usb_free_ctrl_req(usb_ctrl_req_t * req)1090 usb_free_ctrl_req(usb_ctrl_req_t *req)
1091 {
1092 if (req) {
1093 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1094 "usb_free_ctrl_req: req = 0x%p", (void *)req);
1095
1096 if (req->ctrl_data) {
1097 freemsg(req->ctrl_data);
1098 }
1099 usba_req_wrapper_free(USBA_REQ2WRP(req));
1100 }
1101 }
1102
1103
1104 /*
1105 * Client driver calls this function to issue the control
1106 * request to the USBA
1107 *
1108 * Arguments:
1109 * pipe_handle: control pipe pipehandle (obtained via usb_pipe_open()
1110 * req: control request
1111 * usb_flags:
1112 * USB_FLAGS_SLEEP - wait for the request to complete
1113 *
1114 * Return Values:
1115 * USB_SUCCESS - request successfully executed
1116 * USB_FAILURE - request failed
1117 */
1118 int
usb_pipe_ctrl_xfer(usb_pipe_handle_t pipe_handle,usb_ctrl_req_t * req,usb_flags_t usb_flags)1119 usb_pipe_ctrl_xfer(usb_pipe_handle_t pipe_handle,
1120 usb_ctrl_req_t *req,
1121 usb_flags_t usb_flags)
1122 {
1123 int rval;
1124 usba_req_wrapper_t *wrp = USBA_REQ2WRP(req);
1125 usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle);
1126 usba_device_t *usba_device;
1127 usb_flags_t wrp_usb_flags;
1128 usb_pipe_state_t pipe_state;
1129
1130 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1131 "usb_pipe_ctrl_xfer: req=0x%p, wrp=0x%p\n\t"
1132 "setup = 0x%x 0x%x 0x%x 0x%x 0x%x uf=0x%x",
1133 (void *)req, (void *)wrp, req->ctrl_bmRequestType,
1134 req->ctrl_bRequest, req->ctrl_wValue, req->ctrl_wIndex,
1135 req->ctrl_wLength, usb_flags);
1136
1137 if (ph_data == NULL) {
1138
1139 return (USB_INVALID_PIPE);
1140 }
1141
1142 mutex_enter(&ph_data->p_mutex);
1143 usba_device = ph_data->p_usba_device;
1144
1145 if ((rval = usba_check_req(ph_data, (usb_opaque_t)req, usb_flags,
1146 USB_EP_ATTR_CONTROL)) != USB_SUCCESS) {
1147 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
1148 "request rejected: rval=%d", rval);
1149 mutex_exit(&ph_data->p_mutex);
1150
1151 usba_release_ph_data(ph_data->p_ph_impl);
1152
1153 return (rval);
1154 }
1155
1156 ASSERT(ph_data == wrp->wr_ph_data);
1157
1158 /* we accepted the request, so increment the req count */
1159 ph_data->p_req_count++;
1160
1161 wrp_usb_flags = wrp->wr_usb_flags;
1162
1163 /* Get the current bulk pipe state */
1164 pipe_state = usba_get_ph_state(ph_data);
1165
1166 /*
1167 * if this is for the default pipe, and the pipe is in error,
1168 * just queue the request. autoclearing will start this request
1169 *
1170 * if there is already an active request in the queue
1171 * then just add this request to the queue.
1172 */
1173 switch (pipe_state) {
1174 case USB_PIPE_STATE_IDLE:
1175 if (ph_data->p_queue.next ||
1176 ph_data->p_active_cntrl_req_wrp) {
1177 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1178 "usb_pipe_ctrl_xfer: queue request 0x%p",
1179 (void *)req);
1180
1181 usba_add_to_list(&ph_data->p_queue, &wrp->wr_queue);
1182 rval = USB_SUCCESS;
1183 mutex_exit(&ph_data->p_mutex);
1184 } else {
1185 usba_pipe_new_state(ph_data, USB_PIPE_STATE_ACTIVE);
1186 ph_data->p_active_cntrl_req_wrp = (usb_opaque_t)wrp;
1187 mutex_exit(&ph_data->p_mutex);
1188
1189 /* issue the request to HCD */
1190 rval = usba_device->usb_hcdi_ops->
1191 usba_hcdi_pipe_ctrl_xfer(ph_data, req, usb_flags);
1192 }
1193 break;
1194 case USB_PIPE_STATE_ACTIVE:
1195 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1196 "usb_pipe_ctrl_xfer: queue request 0x%p", (void *)req);
1197
1198 usba_add_to_list(&ph_data->p_queue, &wrp->wr_queue);
1199 rval = USB_SUCCESS;
1200 mutex_exit(&ph_data->p_mutex);
1201 break;
1202 case USB_PIPE_STATE_ERROR:
1203 if (USBA_IS_DEFAULT_PIPE(ph_data)) {
1204 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1205 "usb_pipe_ctrl_xfer: queue request 0x%p on "
1206 "pending def pipe error", (void *)req);
1207
1208 usba_add_to_list(&ph_data->p_queue, &wrp->wr_queue);
1209 rval = USB_SUCCESS;
1210 } else {
1211 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1212 "usb_pipe_ctrl_xfer: pipe is in error state ");
1213
1214 rval = USB_PIPE_ERROR;
1215 }
1216 mutex_exit(&ph_data->p_mutex);
1217 break;
1218 default:
1219 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1220 "usb_pipe_ctrl_xfer: pipe state %d", pipe_state);
1221
1222 rval = USB_PIPE_ERROR;
1223 mutex_exit(&ph_data->p_mutex);
1224 break;
1225 }
1226
1227 /* if there has been a failure, decrement req count */
1228 if (rval != USB_SUCCESS) {
1229 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
1230 "usb_pipe_ctrl_xfer: hcd failed req 0x%p", (void *)req);
1231
1232 if (req->ctrl_completion_reason == USB_CR_OK) {
1233 req->ctrl_completion_reason = usba_rval2cr(rval);
1234 }
1235 mutex_enter(&ph_data->p_mutex);
1236 ASSERT(wrp->wr_done == B_FALSE);
1237 ph_data->p_req_count--;
1238 ASSERT(ph_data->p_req_count >= 0);
1239 ph_data->p_active_cntrl_req_wrp = NULL;
1240 if ((ph_data->p_req_count == 0) &&
1241 (usba_get_ph_state(ph_data) == USB_PIPE_STATE_ACTIVE)) {
1242 usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE);
1243 }
1244 mutex_exit(&ph_data->p_mutex);
1245
1246 /* if success and sleep specified, wait for completion */
1247 } else if (wrp_usb_flags & USBA_WRP_FLAGS_WAIT) {
1248 rval = usba_pipe_sync_wait(ph_data, wrp);
1249 }
1250
1251 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1252 "usb_pipe_ctrl_xfer: rval=0x%x", rval);
1253
1254 usba_release_ph_data(ph_data->p_ph_impl);
1255
1256 return (rval);
1257 }
1258
1259
1260 /*
1261 * usb_pipe_sync_ctrl_xfer():
1262 * for simple synchronous control transactions this wrapper function
1263 * will perform the allocation, xfer, and deallocation
1264 * USB_ATTRS_AUTOCLEARING will be enabled
1265 *
1266 * Arguments:
1267 * dip - pointer to clients devinfo
1268 * pipe_handle - control pipe pipehandle (obtained via usb_pipe_open()
1269 * bmRequestType - characteristics of request
1270 * bRequest - specific request
1271 * wValue - varies according to request
1272 * wIndex - index or offset
1273 * wLength - number of bytes to xfer
1274 * data - pointer to pointer to data and may be NULL if
1275 * wLength is 0
1276 * attrs - required request attributes
1277 * completion_reason - completion status
1278 * cb_flags - request completions flags
1279 * flags - none
1280 *
1281 * Return Values:
1282 * USB_SUCCESS - request successfully executed
1283 * USB_* - request failed
1284 *
1285 * Notes:
1286 * - in the case of failure, the client should check completion_reason and
1287 * and cb_flags and determine further recovery action
1288 * - the client should check data and if non-zero, free the data on
1289 * completion
1290 */
1291 int
usb_pipe_sync_ctrl_xfer(dev_info_t * dip,usb_pipe_handle_t pipe_handle,uchar_t bmRequestType,uchar_t bRequest,uint16_t wValue,uint16_t wIndex,uint16_t wLength,mblk_t ** data,usb_req_attrs_t attributes,usb_cr_t * completion_reason,usb_cb_flags_t * cb_flags,usb_flags_t flags)1292 usb_pipe_sync_ctrl_xfer(dev_info_t *dip,
1293 usb_pipe_handle_t pipe_handle,
1294 uchar_t bmRequestType,
1295 uchar_t bRequest,
1296 uint16_t wValue,
1297 uint16_t wIndex,
1298 uint16_t wLength,
1299 mblk_t **data,
1300 usb_req_attrs_t attributes,
1301 usb_cr_t *completion_reason,
1302 usb_cb_flags_t *cb_flags,
1303 usb_flags_t flags)
1304 {
1305 usba_pipe_handle_data_t *ph_data;
1306 int rval;
1307 usb_ctrl_req_t *ctrl_req;
1308 size_t length;
1309 #ifdef DEBUG
1310 #define BUFSIZE 256
1311 char *buf = kmem_alloc(BUFSIZE, KM_SLEEP);
1312 #endif
1313
1314 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1315 "usb_pipe_sync_ctrl_xfer: ph=0x%p\n\t"
1316 "setup = 0x%x 0x%x 0x%x 0x%x 0x%x uf = 0x%x", (void *)pipe_handle,
1317 bmRequestType, bRequest, wValue, wIndex, wLength, flags);
1318
1319 if ((ph_data = usba_hold_ph_data(pipe_handle)) == NULL) {
1320 rval = USB_INVALID_PIPE;
1321
1322 goto done;
1323 }
1324 if (servicing_interrupt()) {
1325 rval = USB_INVALID_CONTEXT;
1326
1327 goto done;
1328 }
1329 if (dip == NULL) {
1330 rval = USB_INVALID_ARGS;
1331
1332 goto done;
1333 }
1334
1335 length = ((data) && (*data)) ? 0: wLength;
1336
1337 ctrl_req = usb_alloc_ctrl_req(dip,
1338 length, flags | USB_FLAGS_SLEEP);
1339
1340 /* Initialize the ctrl_req structure */
1341 ctrl_req->ctrl_bmRequestType = bmRequestType;
1342 ctrl_req->ctrl_bRequest = bRequest;
1343 ctrl_req->ctrl_wValue = wValue;
1344 ctrl_req->ctrl_wIndex = wIndex;
1345 ctrl_req->ctrl_wLength = wLength;
1346 ctrl_req->ctrl_data = ctrl_req->ctrl_data ?
1347 ctrl_req->ctrl_data : ((data) ? *data : NULL);
1348 ctrl_req->ctrl_timeout = USB_PIPE_TIMEOUT;
1349 ctrl_req->ctrl_attributes = attributes | USB_ATTRS_AUTOCLEARING;
1350
1351 /* Issue control xfer to the HCD */
1352 rval = usb_pipe_ctrl_xfer(pipe_handle, ctrl_req,
1353 flags | USB_FLAGS_SLEEP);
1354
1355 #ifdef DEBUG
1356 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1357 "req=0x%p, cr=%s cb_flags=%s data=0x%p rval=%s",
1358 (void *)ctrl_req, usb_str_cr(ctrl_req->ctrl_completion_reason),
1359 usb_str_cb_flags(ctrl_req->ctrl_cb_flags, buf, BUFSIZE),
1360 (void *)ctrl_req->ctrl_data, usb_str_rval(rval));
1361 #endif
1362
1363 /* copy back ctrl_req values */
1364 if (data) {
1365 *data = ctrl_req->ctrl_data;
1366 }
1367 if (completion_reason) {
1368 *completion_reason = ctrl_req->ctrl_completion_reason;
1369 }
1370 if (cb_flags) {
1371 *cb_flags = ctrl_req->ctrl_cb_flags;
1372 }
1373
1374 /* Free up the control request now */
1375 ctrl_req->ctrl_data = NULL; /* leave to client to free */
1376 usb_free_ctrl_req(ctrl_req);
1377
1378 done:
1379 #ifdef DEBUG
1380 kmem_free(buf, BUFSIZE);
1381 #endif
1382 if (ph_data) {
1383 usba_release_ph_data(ph_data->p_ph_impl);
1384 }
1385
1386 return (rval);
1387 }
1388
1389
1390 /*
1391 * usb_pipe_ctrl_xfer_wait():
1392 * Easy-to-use wrapper around usb_pipe_sync_ctrl_xfer.
1393 *
1394 * ARGUMENTS:
1395 * pipe_handle - control pipe pipehandle (obtained via usb_pipe_open())
1396 * setup - setup descriptor params, attributes
1397 * data - pointer to pointer to data and may be NULL when
1398 * wLength is 0
1399 * completion_reason - completion status.
1400 * cb_flags - request completions flags.
1401 * flags - none.
1402 *
1403 * RETURN VALUES:
1404 * USB_SUCCESS - request successfully executed.
1405 * USB_* - failure
1406 */
1407 int
usb_pipe_ctrl_xfer_wait(usb_pipe_handle_t pipe_handle,usb_ctrl_setup_t * setup,mblk_t ** data,usb_cr_t * completion_reason,usb_cb_flags_t * cb_flags,usb_flags_t flags)1408 usb_pipe_ctrl_xfer_wait(
1409 usb_pipe_handle_t pipe_handle,
1410 usb_ctrl_setup_t *setup,
1411 mblk_t **data,
1412 usb_cr_t *completion_reason,
1413 usb_cb_flags_t *cb_flags,
1414 usb_flags_t flags)
1415 {
1416 return (usb_pipe_sync_ctrl_xfer(
1417 usba_get_dip(pipe_handle),
1418 pipe_handle,
1419 setup->bmRequestType,
1420 setup->bRequest,
1421 setup->wValue,
1422 setup->wIndex,
1423 setup->wLength,
1424 data,
1425 setup->attrs,
1426 completion_reason,
1427 cb_flags,
1428 flags));
1429 }
1430
1431
1432 /*
1433 * usb_alloc_bulk_req:
1434 * Allocate a usb bulk request + usba_req_wrapper_t
1435 *
1436 * Arguments:
1437 * dip - dev_info_t of the client driver
1438 * len - length of "data" for this bulk request
1439 * flags:
1440 * USB_FLAGS_SLEEP - Sleep if resources are not available
1441 *
1442 * Return Values:
1443 * usb_bulk_req_t on success, NULL on failure
1444 */
1445 usb_bulk_req_t *
usb_alloc_bulk_req(dev_info_t * dip,size_t len,usb_flags_t flags)1446 usb_alloc_bulk_req(dev_info_t *dip,
1447 size_t len,
1448 usb_flags_t flags)
1449 {
1450 usb_bulk_req_t *bulk_req = NULL;
1451 usba_req_wrapper_t *wrp;
1452
1453 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1454 "usb_alloc_bulk_req: dip=0x%p wlen=0x%lx flags=0x%x",
1455 (void *)dip, len, flags);
1456
1457 /* Allocate + Initialize the usba_req_wrapper_t structure */
1458 if (dip &&
1459 ((wrp = usba_req_wrapper_alloc(dip, sizeof (*bulk_req), flags)) !=
1460 NULL)) {
1461 bulk_req = USBA_WRP2BULK_REQ(wrp);
1462
1463 /* Allocate the usb_bulk_req data mblk */
1464 if (len) {
1465 if (flags & USB_FLAGS_SLEEP) {
1466 bulk_req->bulk_data = allocb_wait(len,
1467 BPRI_LO, STR_NOSIG, NULL);
1468 } else if ((bulk_req->bulk_data =
1469 allocb(len, BPRI_HI)) == NULL) {
1470 usba_req_wrapper_free(wrp);
1471 bulk_req = NULL;
1472 }
1473 }
1474
1475 }
1476
1477 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1478 "usb_alloc_bulk_req: bulk_req = 0x%p", (void *)bulk_req);
1479
1480 return (bulk_req);
1481 }
1482
1483
1484 /*
1485 * usb_free_bulk_req:
1486 * free USB bulk request + wrapper
1487 *
1488 * Arguments:
1489 * req - pointer to usb_bulk_req_t
1490 */
1491 void
usb_free_bulk_req(usb_bulk_req_t * req)1492 usb_free_bulk_req(usb_bulk_req_t *req)
1493 {
1494 if (req) {
1495 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1496 "usb_free_bulk_req: req=0x%p", (void *)req);
1497
1498 if (req->bulk_data) {
1499 freemsg(req->bulk_data);
1500 }
1501 usba_req_wrapper_free(USBA_REQ2WRP(req));
1502 }
1503 }
1504
1505
1506 /*
1507 * Client driver calls this function to issue the bulk xfer to the USBA
1508 *
1509 * Arguments:-
1510 * pipe_handle - bulk pipe handle (obtained via usb_pipe_open()
1511 * req - bulk data xfer request (IN or OUT)
1512 * usb_flags - USB_FLAGS_SLEEP - wait for the request to complete
1513 *
1514 * Return Values:
1515 * USB_SUCCESS - success
1516 * USB_FAILURE - unspecified failure
1517 */
1518 int
usb_pipe_bulk_xfer(usb_pipe_handle_t pipe_handle,usb_bulk_req_t * req,usb_flags_t usb_flags)1519 usb_pipe_bulk_xfer(usb_pipe_handle_t pipe_handle,
1520 usb_bulk_req_t *req,
1521 usb_flags_t usb_flags)
1522 {
1523 int rval;
1524 usba_req_wrapper_t *wrp = USBA_REQ2WRP(req);
1525 usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle);
1526 usba_device_t *usba_device;
1527 usb_flags_t wrp_usb_flags;
1528 usb_pipe_state_t pipe_state;
1529
1530 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1531 "usb_pipe_bulk_xfer: req=0x%p uf=0x%x", (void *)req, usb_flags);
1532
1533 if (ph_data == NULL) {
1534
1535 return (USB_INVALID_PIPE);
1536 }
1537
1538 mutex_enter(&ph_data->p_mutex);
1539 usba_device = ph_data->p_usba_device;
1540
1541 if ((rval = usba_check_req(ph_data, (usb_opaque_t)req, usb_flags,
1542 USB_EP_ATTR_BULK)) != USB_SUCCESS) {
1543 mutex_exit(&ph_data->p_mutex);
1544
1545 usba_release_ph_data(ph_data->p_ph_impl);
1546
1547 return (rval);
1548 }
1549
1550 /* we accepted the request */
1551 ph_data->p_req_count++;
1552 wrp_usb_flags = wrp->wr_usb_flags;
1553
1554 /* Get the current bulk pipe state */
1555 pipe_state = usba_get_ph_state(ph_data);
1556
1557 /*
1558 * if there is already an active request in the queue
1559 * then just add this request to the queue.
1560 */
1561 switch (pipe_state) {
1562 case USB_PIPE_STATE_IDLE:
1563 if (ph_data->p_queue.next) {
1564 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1565 "usb_pipe_bulk_xfer: queue request 0x%p",
1566 (void *)req);
1567
1568 usba_add_to_list(&ph_data->p_queue, &wrp->wr_queue);
1569 rval = USB_SUCCESS;
1570 mutex_exit(&ph_data->p_mutex);
1571 } else {
1572 usba_pipe_new_state(ph_data, USB_PIPE_STATE_ACTIVE);
1573 mutex_exit(&ph_data->p_mutex);
1574
1575 /* issue the request to HCD */
1576 rval = usba_device->usb_hcdi_ops->
1577 usba_hcdi_pipe_bulk_xfer(ph_data, req, usb_flags);
1578 }
1579 break;
1580 case USB_PIPE_STATE_ACTIVE:
1581 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1582 "usb_pipe_bulk_xfer: queue request 0x%p", (void *)req);
1583
1584 usba_add_to_list(&ph_data->p_queue, &wrp->wr_queue);
1585 rval = USB_SUCCESS;
1586 mutex_exit(&ph_data->p_mutex);
1587 break;
1588 default:
1589 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1590 "usb_pipe_bulk_xfer: pipe state %d", pipe_state);
1591
1592 rval = USB_PIPE_ERROR;
1593 mutex_exit(&ph_data->p_mutex);
1594 break;
1595 }
1596
1597 if (rval != USB_SUCCESS) {
1598 if (req->bulk_completion_reason == USB_CR_OK) {
1599 req->bulk_completion_reason = usba_rval2cr(rval);
1600 }
1601 mutex_enter(&ph_data->p_mutex);
1602 ASSERT(wrp->wr_done == B_FALSE);
1603 ph_data->p_req_count--;
1604 ASSERT(ph_data->p_req_count >= 0);
1605 if ((ph_data->p_req_count == 0) &&
1606 (usba_get_ph_state(ph_data) == USB_PIPE_STATE_ACTIVE)) {
1607 usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE);
1608 }
1609 mutex_exit(&ph_data->p_mutex);
1610 } else if (wrp_usb_flags & USBA_WRP_FLAGS_WAIT) {
1611 rval = usba_pipe_sync_wait(ph_data, wrp);
1612 }
1613
1614 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1615 "usb_pipe_bulk_xfer: rval=%d", rval);
1616
1617 usba_release_ph_data(ph_data->p_ph_impl);
1618
1619 return (rval);
1620 }
1621
1622
1623 /*
1624 * usb_pipe_bulk_transfer_size:
1625 * - request HCD to return bulk max transfer data size
1626 *
1627 * Arguments:
1628 * dip - pointer to dev_info_t
1629 * size - pointer to bulk_transfer_size
1630 *
1631 * Return Values:
1632 * USB_SUCCESS - request successfully executed
1633 * USB_FAILURE - request failed
1634 */
1635 int
usb_pipe_bulk_transfer_size(dev_info_t * dip,size_t * size)1636 usb_pipe_bulk_transfer_size(dev_info_t *dip,
1637 size_t *size)
1638 {
1639 return (usb_pipe_get_max_bulk_transfer_size(dip, size));
1640 }
1641
1642
1643 int
usb_pipe_get_max_bulk_transfer_size(dev_info_t * dip,size_t * size)1644 usb_pipe_get_max_bulk_transfer_size(dev_info_t *dip,
1645 size_t *size)
1646 {
1647 usba_device_t *usba_device;
1648
1649 if ((dip == NULL) || (size == NULL)) {
1650
1651 return (USB_INVALID_ARGS);
1652 }
1653 usba_device = usba_get_usba_device(dip);
1654
1655 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1656 "usb_pipe_bulk_transfer_size: usba_device=0x%p",
1657 (void *)usba_device);
1658
1659 if ((usba_device) &&
1660 (usba_device->usb_hcdi_ops->usba_hcdi_bulk_transfer_size)) {
1661
1662 return (usba_device->usb_hcdi_ops->
1663 usba_hcdi_bulk_transfer_size(usba_device, size));
1664 } else {
1665 *size = 0;
1666
1667 return (USB_FAILURE);
1668 }
1669 }
1670
1671
1672 /*
1673 * usb_alloc_intr_req:
1674 * Allocate usb interrupt request
1675 *
1676 * Arguments:
1677 * dip - dev_info_t of the client driver
1678 * len - length of "data" for this interrupt request
1679 * flags -
1680 * USB_FLAGS_SLEEP - Sleep if resources are not available
1681 *
1682 * Return Values:
1683 * usb_intr_req_t on success, NULL on failure
1684 */
1685 usb_intr_req_t *
usb_alloc_intr_req(dev_info_t * dip,size_t len,usb_flags_t flags)1686 usb_alloc_intr_req(dev_info_t *dip,
1687 size_t len,
1688 usb_flags_t flags)
1689 {
1690 usb_intr_req_t *intr_req = NULL;
1691 usba_req_wrapper_t *wrp;
1692
1693 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1694 "usb_alloc_intr_req: dip=0x%p, len=0x%lx, flags=0x%x",
1695 (void *)dip, len, flags);
1696
1697 /* Allocate + Initialize the usba_req_wrapper_t structure */
1698 if ((dip &&
1699 (wrp = usba_req_wrapper_alloc(dip, sizeof (*intr_req), flags)) !=
1700 NULL)) {
1701 intr_req = (usb_intr_req_t *)USBA_WRP2INTR_REQ(wrp);
1702
1703 /* Allocate the usb_intr_req data mblk */
1704 if (len) {
1705 if (flags & USB_FLAGS_SLEEP) {
1706 intr_req->intr_data = allocb_wait(len, BPRI_LO,
1707 STR_NOSIG, NULL);
1708 } else if ((intr_req->intr_data =
1709 allocb(len, BPRI_HI)) == NULL) {
1710 usba_req_wrapper_free(wrp);
1711 intr_req = NULL;
1712 }
1713 }
1714 }
1715
1716 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1717 "usb_alloc_intr_req: intr_req=0x%p", (void *)intr_req);
1718
1719 return (intr_req);
1720 }
1721
1722
1723 /*
1724 * usba_hcdi_dup_intr_req:
1725 * create duplicate of interrupt request
1726 *
1727 * Arguments:
1728 * dip - devinfo pointer
1729 * reqp - original requestp pointer
1730 * len - length of "data" for this interrupt request
1731 * flags -
1732 * USB_FLAGS_SLEEP - Sleep if resources are not available
1733 *
1734 * Return Values:
1735 * usb_intr_req_t on success, NULL on failure
1736 */
1737 usb_intr_req_t *
usba_hcdi_dup_intr_req(dev_info_t * dip,usb_intr_req_t * reqp,size_t len,usb_flags_t flags)1738 usba_hcdi_dup_intr_req(
1739 dev_info_t *dip,
1740 usb_intr_req_t *reqp,
1741 size_t len,
1742 usb_flags_t flags)
1743 {
1744 usb_intr_req_t *intr_reqp = NULL;
1745 usba_req_wrapper_t *intr_wrp, *req_wrp;
1746
1747 if (reqp == NULL) {
1748
1749 return (NULL);
1750 }
1751
1752 req_wrp = USBA_REQ2WRP(reqp);
1753
1754 if (((intr_reqp = usb_alloc_intr_req(dip, len, flags)) != NULL)) {
1755 intr_reqp->intr_client_private = reqp->intr_client_private;
1756 intr_reqp->intr_timeout = reqp->intr_timeout;
1757 intr_reqp->intr_attributes = reqp->intr_attributes;
1758 intr_reqp->intr_len = reqp->intr_len;
1759 intr_reqp->intr_cb = reqp->intr_cb;
1760 intr_reqp->intr_exc_cb = reqp->intr_exc_cb;
1761
1762 intr_wrp = USBA_REQ2WRP(intr_reqp);
1763 intr_wrp->wr_dip = req_wrp->wr_dip;
1764 intr_wrp->wr_ph_data = req_wrp->wr_ph_data;
1765 intr_wrp->wr_attrs = req_wrp->wr_attrs;
1766 intr_wrp->wr_usb_flags = req_wrp->wr_usb_flags;
1767 }
1768
1769 return (intr_reqp);
1770 }
1771
1772
1773 /*
1774 * usb_free_intr_req:
1775 * free USB intr request + wrapper
1776 *
1777 * Arguments:
1778 * req - pointer to usb_intr_req_t
1779 */
1780 void
usb_free_intr_req(usb_intr_req_t * req)1781 usb_free_intr_req(usb_intr_req_t *req)
1782 {
1783 if (req) {
1784 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1785 "usb_free_intr_req: req = 0x%p", (void *)req);
1786
1787 if (req->intr_data) {
1788 freemsg(req->intr_data);
1789 }
1790
1791 usba_req_wrapper_free(USBA_REQ2WRP(req));
1792 }
1793 }
1794
1795
1796 /*
1797 * Client driver calls this function to issue the intr xfer to the USBA
1798 *
1799 * Arguments:-
1800 * pipe_handle - intr pipe handle (obtained via usb_pipe_open()
1801 * req - intr data xfer request (IN or OUT)
1802 * flags -
1803 * USB_FLAGS_SLEEP - wait for the request to complete
1804 * Return Values
1805 * USB_SUCCESS - success
1806 * USB_FAILURE - unspecified failure
1807 */
1808 int
usb_pipe_intr_xfer(usb_pipe_handle_t pipe_handle,usb_intr_req_t * req,usb_flags_t usb_flags)1809 usb_pipe_intr_xfer(usb_pipe_handle_t pipe_handle,
1810 usb_intr_req_t *req,
1811 usb_flags_t usb_flags)
1812 {
1813 int rval;
1814 usba_req_wrapper_t *wrp = USBA_REQ2WRP(req);
1815 usba_ph_impl_t *ph_impl = (usba_ph_impl_t *)pipe_handle;
1816 usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle);
1817 usba_device_t *usba_device;
1818 uchar_t direction;
1819 usb_flags_t wrp_usb_flags;
1820 usb_pipe_state_t pipe_state;
1821
1822 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1823 "usb_pipe_intr_req: req=0x%p uf=0x%x",
1824 (void *)req, usb_flags);
1825
1826 if (ph_data == NULL) {
1827
1828 return (USB_INVALID_PIPE);
1829 }
1830 usba_device = ph_data->p_usba_device;
1831 direction = ph_data->p_ep.bEndpointAddress & USB_EP_DIR_MASK;
1832
1833 mutex_enter(&ph_data->p_mutex);
1834 if ((rval = usba_check_req(ph_data, (usb_opaque_t)req, usb_flags,
1835 USB_EP_ATTR_INTR)) != USB_SUCCESS) {
1836 mutex_exit(&ph_data->p_mutex);
1837
1838 usba_release_ph_data(ph_data->p_ph_impl);
1839
1840 return (rval);
1841 }
1842
1843 /* Get the current interrupt pipe state */
1844 pipe_state = usba_get_ph_state(ph_data);
1845
1846 switch (pipe_state) {
1847 case USB_PIPE_STATE_IDLE:
1848 /*
1849 * if the pipe state is in middle of transition,
1850 * i.e. stop polling is in progress, fail any
1851 * attempt to do a start polling
1852 */
1853 mutex_enter(&ph_impl->usba_ph_mutex);
1854 if (ph_impl->usba_ph_state_changing > 0) {
1855 mutex_exit(&ph_impl->usba_ph_mutex);
1856
1857 mutex_exit(&ph_data->p_mutex);
1858 usba_release_ph_data(ph_data->p_ph_impl);
1859
1860 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
1861 "usb_pipe_intr_req: fail request - "
1862 "stop polling in progress");
1863
1864 return (USB_FAILURE);
1865 } else {
1866 mutex_exit(&ph_impl->usba_ph_mutex);
1867 usba_pipe_new_state(ph_data, USB_PIPE_STATE_ACTIVE);
1868 }
1869
1870 break;
1871 case USB_PIPE_STATE_ACTIVE:
1872 /*
1873 * If this is interrupt IN pipe and if we are
1874 * already polling, return failure.
1875 */
1876 if (direction == USB_EP_DIR_IN) {
1877 USB_DPRINTF_L4(DPRINT_MASK_USBAI,
1878 usbai_log_handle,
1879 "usb_pipe_intr_req: already polling");
1880
1881 mutex_exit(&ph_data->p_mutex);
1882 usba_release_ph_data(ph_data->p_ph_impl);
1883
1884 return (USB_FAILURE);
1885 }
1886
1887 break;
1888 default:
1889 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1890 "usb_pipe_intr_req: pipe state %d", pipe_state);
1891
1892 mutex_exit(&ph_data->p_mutex);
1893 usba_release_ph_data(ph_data->p_ph_impl);
1894
1895 return (USB_PIPE_ERROR);
1896 }
1897
1898 /* we accept the request */
1899 wrp_usb_flags = wrp->wr_usb_flags;
1900 ph_data->p_req_count++;
1901
1902 mutex_exit(&ph_data->p_mutex);
1903
1904 /* issue the request out */
1905 if ((rval = usba_device->usb_hcdi_ops->usba_hcdi_pipe_intr_xfer(ph_data,
1906 req, usb_flags)) != USB_SUCCESS) {
1907
1908 /* the request failed, decrement the ref_count */
1909 if (req->intr_completion_reason == USB_CR_OK) {
1910 req->intr_completion_reason = usba_rval2cr(rval);
1911 }
1912 mutex_enter(&ph_data->p_mutex);
1913 ASSERT(wrp->wr_done == B_FALSE);
1914 ph_data->p_req_count--;
1915 ASSERT(ph_data->p_req_count >= 0);
1916 if ((ph_data->p_req_count == 0) &&
1917 (usba_get_ph_state(ph_data) == USB_PIPE_STATE_ACTIVE)) {
1918 usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE);
1919 }
1920 mutex_exit(&ph_data->p_mutex);
1921
1922 /* if sleep specified, wait for completion */
1923 } else if (wrp_usb_flags & USBA_WRP_FLAGS_WAIT) {
1924 rval = usba_pipe_sync_wait(ph_data, wrp);
1925 }
1926
1927 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1928 "usb_pipe_intr_req: rval=0x%x", rval);
1929
1930 usba_release_ph_data(ph_data->p_ph_impl);
1931
1932 return (rval);
1933 }
1934
1935
1936 /*
1937 * usba_pipe_sync_stop_intr_polling:
1938 * - set up for sync transport, if necessary
1939 * - request HCD to stop polling
1940 * - wait for draining of all callbacks
1941 */
1942 /*ARGSUSED*/
1943 static int
usba_pipe_sync_stop_intr_polling(dev_info_t * dip,usba_ph_impl_t * ph_impl,usba_pipe_async_req_t * request,usb_flags_t flags)1944 usba_pipe_sync_stop_intr_polling(dev_info_t *dip,
1945 usba_ph_impl_t *ph_impl,
1946 usba_pipe_async_req_t *request,
1947 usb_flags_t flags)
1948 {
1949 int rval;
1950 usba_pipe_handle_data_t *ph_data;
1951 usba_device_t *usba_device;
1952
1953 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1954 "usba_pipe_sync_stop_intr_polling: flags=0x%x", flags);
1955
1956 ph_data = usba_get_ph_data((usb_pipe_handle_t)ph_impl);
1957 if (ph_data == NULL) {
1958 usba_release_ph_data(ph_impl);
1959 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
1960 "usba_pipe_sync_stop_intr_polling: pipe closed");
1961
1962 return (USB_INVALID_PIPE);
1963 }
1964
1965 usba_device = ph_data->p_usba_device;
1966
1967 mutex_enter(&ph_data->p_mutex);
1968
1969 if (usba_get_ph_state(ph_data) == USB_PIPE_STATE_ERROR) {
1970 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
1971 "usba_pipe_sync_stop_intr_polling: pipe error");
1972 mutex_exit(&ph_data->p_mutex);
1973
1974 usba_release_ph_data(ph_impl);
1975
1976 return (USB_PIPE_ERROR);
1977 }
1978
1979 if (usba_get_ph_state(ph_data) == USB_PIPE_STATE_IDLE) {
1980 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
1981 "usba_pipe_sync_stop_intr_polling: already idle");
1982 mutex_exit(&ph_data->p_mutex);
1983
1984 usba_release_ph_data(ph_impl);
1985
1986 return (USB_SUCCESS);
1987 }
1988 mutex_exit(&ph_data->p_mutex);
1989
1990 mutex_enter(&ph_impl->usba_ph_mutex);
1991 ph_impl->usba_ph_state_changing++;
1992 mutex_exit(&ph_impl->usba_ph_mutex);
1993
1994 flags |= USB_FLAGS_SLEEP;
1995
1996 for (;;) {
1997 rval = usba_device->usb_hcdi_ops->
1998 usba_hcdi_pipe_stop_intr_polling(ph_data, flags);
1999
2000 /*
2001 * The host controller has stopped polling of the endpoint.
2002 * Now, drain the callbacks if there are any on the callback
2003 * queue.
2004 */
2005 if (rval == USB_SUCCESS) {
2006 mutex_enter(&ph_data->p_mutex);
2007
2008 /*
2009 * there is a tiny window that the client driver
2010 * may still have restarted the polling and we
2011 * have to let the stop polling win)
2012 */
2013 rval = usba_drain_cbs(ph_data, 0,
2014 USB_CR_STOPPED_POLLING);
2015 mutex_exit(&ph_data->p_mutex);
2016 if (rval != USB_SUCCESS) {
2017
2018 continue;
2019 }
2020 }
2021
2022 break;
2023 }
2024
2025 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
2026 "usba_pipe_sync_stop_intr_polling: rval=0x%x", rval);
2027
2028 mutex_enter(&ph_impl->usba_ph_mutex);
2029 ph_impl->usba_ph_state_changing--;
2030 mutex_exit(&ph_impl->usba_ph_mutex);
2031
2032 usba_release_ph_data(ph_impl);
2033
2034 return (rval);
2035 }
2036
2037
2038 /*
2039 * dummy callback function for stop polling
2040 */
2041 static void
usba_dummy_callback(usb_pipe_handle_t ph,usb_opaque_t arg,int rval,usb_cb_flags_t flags)2042 usba_dummy_callback(
2043 usb_pipe_handle_t ph,
2044 usb_opaque_t arg,
2045 int rval,
2046 usb_cb_flags_t flags)
2047 {
2048 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
2049 "usba_dummy_callback: "
2050 "ph=0x%p rval=0x%x flags=0x%x cb_arg=0x%p",
2051 (void *)ph, rval, flags, (void *)arg);
2052 }
2053
2054
2055 /*
2056 * usb_pipe_stop_intr_polling:
2057 * stop polling for interrupt pipe IN data
2058 * The HCD doesn't do a usba_hcdi_cb().
2059 * It just returns success/failure
2060 * Arguments:
2061 * pipe_handle - pipe handle
2062 * flags -
2063 * USB_FLAGS_SLEEP: wait for completion
2064 */
2065 void
usb_pipe_stop_intr_polling(usb_pipe_handle_t pipe_handle,usb_flags_t flags)2066 usb_pipe_stop_intr_polling(usb_pipe_handle_t pipe_handle,
2067 usb_flags_t flags)
2068 {
2069 usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle);
2070
2071 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
2072 "usba_pipe_stop_intr_polling: flags=0x%x", flags);
2073
2074 if (ph_data == NULL) {
2075 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
2076 "usba_pipe_stop_intr_polling: pipe closed");
2077
2078 return;
2079 }
2080
2081 if ((ph_data->p_ep.bmAttributes &
2082 USB_EP_ATTR_MASK) != USB_EP_ATTR_INTR) {
2083 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
2084 "usba_pipe_stop_intr_polling: wrong pipe type");
2085
2086 usba_release_ph_data(ph_data->p_ph_impl);
2087
2088 return;
2089 }
2090
2091 if ((ph_data->p_ep.bEndpointAddress & USB_EP_DIR_IN) == 0) {
2092 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
2093 "usba_pipe_stop_intr_polling: wrong pipe direction");
2094
2095 usba_release_ph_data(ph_data->p_ph_impl);
2096
2097 return;
2098 }
2099
2100 if (servicing_interrupt() && (flags & USB_FLAGS_SLEEP)) {
2101 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
2102 "usba_pipe_stop_intr_polling: invalid context");
2103
2104 usba_release_ph_data(ph_data->p_ph_impl);
2105
2106 return;
2107 }
2108
2109 (void) usba_pipe_setup_func_call(ph_data->p_dip,
2110 usba_pipe_sync_stop_intr_polling,
2111 (usba_ph_impl_t *)pipe_handle, (usb_opaque_t)flags,
2112 flags, usba_dummy_callback, NULL);
2113 }
2114
2115
2116 /*
2117 * usb_alloc_isoc_req:
2118 * - Allocate usb isochronous resources that includes usb isochronous
2119 * request and array of packet descriptor structures and wrapper.
2120 *
2121 * Arguments:
2122 * dip - dev_info_t of the client driver
2123 * isoc_pkts_count - number of isoc_pkt_descr_t's
2124 * len - length of "data" for this isochronous request
2125 * flags -
2126 * USB_FLAGS_SLEEP - Sleep if resources are not available
2127 * no USB_FLAGS_SLEEP - Don't Sleep if resources are not available
2128 *
2129 * Return Values:
2130 * usb_isoc_req_t on success, NULL on failure
2131 */
2132 /*ARGSUSED*/
2133 usb_isoc_req_t *
usb_alloc_isoc_req(dev_info_t * dip,uint_t isoc_pkts_count,size_t len,usb_flags_t flags)2134 usb_alloc_isoc_req(dev_info_t *dip,
2135 uint_t isoc_pkts_count,
2136 size_t len,
2137 usb_flags_t flags)
2138 {
2139 usb_isoc_req_t *isoc_req = NULL;
2140 usba_req_wrapper_t *wrp;
2141 size_t length = sizeof (*isoc_req) +
2142 (sizeof (usb_isoc_pkt_descr_t) * isoc_pkts_count);
2143
2144 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
2145 "usb_alloc_isoc_req: dip=0x%p pkt_cnt=%d len=%lu flags=0x%x",
2146 (void *)dip, isoc_pkts_count, len, flags);
2147
2148 /* client needs to set isoc_pks_count */
2149 if (dip && isoc_pkts_count) {
2150 /* Allocate + Initialize the usba_req_wrapper_t structure */
2151 if ((wrp = usba_req_wrapper_alloc(dip, length, flags)) !=
2152 NULL) {
2153 isoc_req = (usb_isoc_req_t *)USBA_WRP2ISOC_REQ(wrp);
2154
2155 /* Allocate the usb_isoc_req data mblk */
2156 if (len) {
2157 if ((isoc_req->isoc_data =
2158 allocb(len, BPRI_HI)) == NULL) {
2159 usba_req_wrapper_free(wrp);
2160 isoc_req = NULL;
2161 }
2162 }
2163 }
2164 }
2165
2166 if (isoc_req) {
2167 isoc_req->isoc_pkt_descr = (usb_isoc_pkt_descr_t *)
2168 (((intptr_t)isoc_req) + (sizeof (usb_isoc_req_t)));
2169
2170 /* Initialize all the fields of usb isochronous request */
2171 isoc_req->isoc_pkts_count = (ushort_t)isoc_pkts_count;
2172 }
2173
2174 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
2175 "usb_alloc_isoc_req: isoc_req = 0x%p", (void *)isoc_req);
2176
2177 return (isoc_req);
2178 }
2179
2180
2181 /*
2182 * usba_hcdi_dup_isoc_req:
2183 * create duplicate of isoc request
2184 *
2185 * Arguments:
2186 * dip - devinfo pointer
2187 * reqp - original request pointer
2188 * len - length of "data" for this isoc request
2189 * flags -
2190 * USB_FLAGS_SLEEP - Sleep if resources are not available
2191 *
2192 * Return Values:
2193 * usb_isoc_req_t on success, NULL on failure
2194 */
2195 usb_isoc_req_t *
usba_hcdi_dup_isoc_req(dev_info_t * dip,usb_isoc_req_t * reqp,usb_flags_t flags)2196 usba_hcdi_dup_isoc_req(
2197 dev_info_t *dip,
2198 usb_isoc_req_t *reqp,
2199 usb_flags_t flags)
2200 {
2201 usb_isoc_req_t *isoc_reqp = NULL;
2202 usba_req_wrapper_t *isoc_wrp, *req_wrp;
2203 ushort_t count;
2204 ushort_t isoc_pkts_count;
2205 size_t length;
2206
2207 if (reqp == NULL) {
2208
2209 return (isoc_reqp);
2210 }
2211
2212 isoc_pkts_count = reqp->isoc_pkts_count;
2213
2214 /* calculate total data length required in original request */
2215 for (count = length = 0; count < isoc_pkts_count; count++) {
2216 length += reqp->isoc_pkt_descr[count].isoc_pkt_length;
2217 }
2218
2219 req_wrp = USBA_REQ2WRP(reqp);
2220
2221 if (((isoc_reqp = usb_alloc_isoc_req(dip,
2222 isoc_pkts_count, length, flags)) != NULL)) {
2223 isoc_reqp->isoc_frame_no = reqp->isoc_frame_no;
2224 isoc_reqp->isoc_pkts_count = reqp->isoc_pkts_count;
2225 isoc_reqp->isoc_pkts_length = reqp->isoc_pkts_length;
2226 isoc_reqp->isoc_attributes = reqp->isoc_attributes;
2227 isoc_reqp->isoc_client_private = reqp->isoc_client_private;
2228 isoc_reqp->isoc_cb = reqp->isoc_cb;
2229 isoc_reqp->isoc_exc_cb = reqp->isoc_exc_cb;
2230
2231 isoc_wrp = USBA_REQ2WRP(isoc_reqp);
2232 isoc_wrp->wr_dip = req_wrp->wr_dip;
2233 isoc_wrp->wr_ph_data = req_wrp->wr_ph_data;
2234 isoc_wrp->wr_attrs = req_wrp->wr_attrs;
2235 isoc_wrp->wr_usb_flags = req_wrp->wr_usb_flags;
2236
2237 for (count = 0; count < isoc_pkts_count; count++) {
2238 isoc_reqp->isoc_pkt_descr[count].isoc_pkt_length =
2239 reqp->isoc_pkt_descr[count].isoc_pkt_length;
2240 }
2241 }
2242
2243 return (isoc_reqp);
2244 }
2245
2246
2247 /*
2248 * usb_free_isoc_req:
2249 * - Deallocate usb isochronous resources that includes usb isochronous
2250 * request and array of packet descriptor strcutures.
2251 *
2252 * Arguments:
2253 * req - pointer to usb_isoc_req_t
2254 */
2255 void
usb_free_isoc_req(usb_isoc_req_t * req)2256 usb_free_isoc_req(usb_isoc_req_t *req)
2257 {
2258 if (req) {
2259 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
2260 "usb_free_isoc_req: req=0x%p", (void *)req);
2261
2262 if (req->isoc_data) {
2263 freemsg(req->isoc_data);
2264 }
2265
2266 usba_req_wrapper_free(USBA_REQ2WRP(req));
2267 }
2268 }
2269
2270
2271 /*
2272 * usb_get_current_frame_number:
2273 * - request HCD to return current usb frame number
2274 *
2275 * Arguments:
2276 * dip - pointer to dev_info_t
2277 *
2278 * Return Values:
2279 * current_frame_number - request successfully executed
2280 * 0 - request failed
2281 */
2282 usb_frame_number_t
usb_get_current_frame_number(dev_info_t * dip)2283 usb_get_current_frame_number(dev_info_t *dip)
2284 {
2285 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
2286 "usb_get_current_frame_number: dip=0x%p", (void *)dip);
2287
2288 if (dip) {
2289 usba_device_t *usba_device = usba_get_usba_device(dip);
2290 usb_frame_number_t frame_number;
2291
2292 if (usba_device->usb_hcdi_ops->
2293 usba_hcdi_get_current_frame_number) {
2294
2295 if (usba_device->usb_hcdi_ops->
2296 usba_hcdi_get_current_frame_number(usba_device,
2297 &frame_number) == USB_SUCCESS) {
2298
2299 return (frame_number);
2300 }
2301 }
2302 }
2303
2304 return (0);
2305 }
2306
2307
2308 /*
2309 * usb_get_max_isoc_pkts:
2310 * - request HCD to return maximum isochronous packets per request
2311 *
2312 * Arguments:
2313 * dip - pointer to dev_info_t
2314 *
2315 * Return Values:
2316 * isoc_pkt - request successfully executed
2317 * 0 - request failed
2318 */
2319 uint_t
usb_get_max_isoc_pkts(dev_info_t * dip)2320 usb_get_max_isoc_pkts(dev_info_t *dip)
2321 {
2322 return (usb_get_max_pkts_per_isoc_request(dip));
2323 }
2324
2325
2326 uint_t
usb_get_max_pkts_per_isoc_request(dev_info_t * dip)2327 usb_get_max_pkts_per_isoc_request(dev_info_t *dip)
2328 {
2329 if (dip) {
2330 usba_device_t *usba_device = usba_get_usba_device(dip);
2331 uint_t max_isoc_pkts_per_request;
2332
2333 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
2334 "usb_get_max_isoc_pkts: usba_device=0x%p",
2335 (void *)usba_device);
2336
2337 if (usba_device->usb_hcdi_ops->usba_hcdi_get_max_isoc_pkts) {
2338
2339 if (usba_device->usb_hcdi_ops->
2340 usba_hcdi_get_max_isoc_pkts(usba_device,
2341 &max_isoc_pkts_per_request) == USB_SUCCESS) {
2342
2343 return (max_isoc_pkts_per_request);
2344 }
2345 }
2346 }
2347
2348 return (0);
2349 }
2350
2351
2352 /*
2353 * usb_pipe_isoc_xfer:
2354 * - check for pipe stalled
2355 * - request HCD to transport isoc data asynchronously
2356 *
2357 * Arguments:
2358 * pipe_handle - isoc pipe pipehandle (obtained via usb_pipe_open())
2359 * req - isochronous request
2360 *
2361 * Return Values:
2362 * USB_SUCCESS - request successfully executed
2363 * USB_FAILURE - request failed
2364 */
2365 int
usb_pipe_isoc_xfer(usb_pipe_handle_t pipe_handle,usb_isoc_req_t * req,usb_flags_t flags)2366 usb_pipe_isoc_xfer(usb_pipe_handle_t pipe_handle,
2367 usb_isoc_req_t *req,
2368 usb_flags_t flags)
2369 {
2370 int rval;
2371 usba_req_wrapper_t *wrp = USBA_REQ2WRP(req);
2372 usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle);
2373 usba_device_t *usba_device;
2374 uchar_t direction;
2375 usb_pipe_state_t pipe_state;
2376
2377 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
2378 "usb_pipe_isoc_xfer: flags=0x%x", flags);
2379
2380 if (ph_data == NULL) {
2381
2382 return (USB_INVALID_PIPE);
2383 }
2384
2385 usba_device = ph_data->p_usba_device;
2386 direction = ph_data->p_ep.bEndpointAddress & USB_EP_DIR_MASK;
2387
2388 mutex_enter(&ph_data->p_mutex);
2389 if ((rval = usba_check_req(ph_data, (usb_opaque_t)req, flags,
2390 USB_EP_ATTR_ISOCH)) != USB_SUCCESS) {
2391 mutex_exit(&ph_data->p_mutex);
2392
2393 usba_release_ph_data(ph_data->p_ph_impl);
2394
2395 return (rval);
2396 }
2397
2398 req->isoc_error_count = 0;
2399
2400 /* Get the current isoch pipe state */
2401 pipe_state = usba_get_ph_state(ph_data);
2402
2403 switch (pipe_state) {
2404 case USB_PIPE_STATE_IDLE:
2405 usba_pipe_new_state(ph_data, USB_PIPE_STATE_ACTIVE);
2406 break;
2407 case USB_PIPE_STATE_ACTIVE:
2408 if (direction == USB_EP_DIR_IN) {
2409 USB_DPRINTF_L4(DPRINT_MASK_USBAI,
2410 usbai_log_handle,
2411 "usb_pipe_isoc_req: already polling");
2412
2413 mutex_exit(&ph_data->p_mutex);
2414 usba_release_ph_data(ph_data->p_ph_impl);
2415
2416 return (USB_FAILURE);
2417 }
2418 break;
2419 default:
2420 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
2421 "usb_pipe_isoc_req: pipe state %d", pipe_state);
2422
2423 mutex_exit(&ph_data->p_mutex);
2424 usba_release_ph_data(ph_data->p_ph_impl);
2425
2426 return (USB_PIPE_ERROR);
2427 }
2428
2429 /* we accept the request */
2430 ph_data->p_req_count++;
2431 mutex_exit(&ph_data->p_mutex);
2432
2433 if ((rval = usba_device->usb_hcdi_ops->usba_hcdi_pipe_isoc_xfer(
2434 ph_data, req, flags)) != USB_SUCCESS) {
2435 if (req->isoc_completion_reason == USB_CR_OK) {
2436 req->isoc_completion_reason = usba_rval2cr(rval);
2437 }
2438 mutex_enter(&ph_data->p_mutex);
2439 ASSERT(wrp->wr_done == B_FALSE);
2440 ph_data->p_req_count--;
2441 if ((ph_data->p_req_count == 0) &&
2442 (usba_get_ph_state(ph_data) == USB_PIPE_STATE_ACTIVE)) {
2443 usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE);
2444 }
2445 mutex_exit(&ph_data->p_mutex);
2446 }
2447
2448 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
2449 "usb_pipe_isoc_req: rval=%x", rval);
2450
2451 usba_release_ph_data(ph_data->p_ph_impl);
2452
2453 return (rval);
2454 }
2455
2456
2457 /*
2458 * usba_pipe_sync_stop_isoc_polling:
2459 * - set up for sync transport, if necessary
2460 * - request HCD to stop polling
2461 * - wait for draining of all callbacks
2462 *
2463 * Arguments:
2464 * dip - dev_info pointer
2465 * pipe_handle - pointer to pipe handle
2466 * flags - USB_FLAGS_SLEEP: wait for completion
2467 */
2468 /*ARGSUSED*/
2469 static int
usba_pipe_sync_stop_isoc_polling(dev_info_t * dip,usba_ph_impl_t * ph_impl,usba_pipe_async_req_t * request,usb_flags_t flags)2470 usba_pipe_sync_stop_isoc_polling(dev_info_t *dip,
2471 usba_ph_impl_t *ph_impl,
2472 usba_pipe_async_req_t *request,
2473 usb_flags_t flags)
2474 {
2475 int rval;
2476 usba_pipe_handle_data_t *ph_data = usba_get_ph_data(
2477 (usb_pipe_handle_t)ph_impl);
2478 usba_device_t *usba_device;
2479
2480 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
2481 "usba_pipe_sync_stop_isoc_polling: uf=0x%x", flags);
2482
2483 if (ph_data == NULL) {
2484 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
2485 "usba_pipe_stop_isoc_polling: pipe closed");
2486
2487 return (USB_INVALID_PIPE);
2488 }
2489
2490 usba_device = ph_data->p_usba_device;
2491
2492 mutex_enter(&ph_data->p_mutex);
2493
2494 if (usba_get_ph_state(ph_data) == USB_PIPE_STATE_ERROR) {
2495 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
2496 "usba_pipe_sync_stop_isoc_polling: pipe error");
2497 mutex_exit(&ph_data->p_mutex);
2498
2499 usba_release_ph_data(ph_impl);
2500
2501 return (USB_PIPE_ERROR);
2502 }
2503
2504 if (usba_get_ph_state(ph_data) == USB_PIPE_STATE_IDLE) {
2505 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
2506 "usba_pipe_sync_stop_isoc_polling: already stopped");
2507 mutex_exit(&ph_data->p_mutex);
2508
2509 usba_release_ph_data(ph_impl);
2510
2511 return (USB_SUCCESS);
2512 }
2513
2514
2515 mutex_exit(&ph_data->p_mutex);
2516
2517 flags |= USB_FLAGS_SLEEP;
2518
2519 for (;;) {
2520 rval = usba_device->usb_hcdi_ops->
2521 usba_hcdi_pipe_stop_isoc_polling(ph_data, flags);
2522
2523 /*
2524 * The host controller has stopped polling of the endpoint.
2525 * Now, drain the callbacks if there are any on the callback
2526 * queue.
2527 */
2528 if (rval == USB_SUCCESS) {
2529 mutex_enter(&ph_data->p_mutex);
2530
2531 /*
2532 * there is a tiny window that the client driver
2533 * may still have restarted the polling and we
2534 * let the stop polling win
2535 */
2536 rval = usba_drain_cbs(ph_data, 0,
2537 USB_CR_STOPPED_POLLING);
2538 mutex_exit(&ph_data->p_mutex);
2539 if (rval != USB_SUCCESS) {
2540
2541 continue;
2542 }
2543 }
2544
2545 break;
2546 }
2547
2548 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
2549 "usba_pipe_sync_stop_isoc_polling: rval=0x%x", rval);
2550
2551 usba_release_ph_data(ph_impl);
2552
2553 return (rval);
2554 }
2555
2556
2557 /*
2558 * usb_pipe_stop_isoc_polling:
2559 * stop polling for isoc IN data
2560 *
2561 * Arguments:
2562 * pipe_handle - pipe handle
2563 * flags -
2564 * USB_FLAGS_SLEEP: wait for completion
2565 */
2566 void
usb_pipe_stop_isoc_polling(usb_pipe_handle_t pipe_handle,usb_flags_t flags)2567 usb_pipe_stop_isoc_polling(usb_pipe_handle_t pipe_handle,
2568 usb_flags_t flags)
2569 {
2570 usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle);
2571
2572 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
2573 "usba_pipe_stop_isoc_polling: uf=0x%x", flags);
2574
2575 if (ph_data == NULL) {
2576 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
2577 "usba_pipe_stop_isoc_polling: pipe closed");
2578
2579 return;
2580 }
2581
2582 if ((ph_data->p_ep.bmAttributes & USB_EP_ATTR_MASK) !=
2583 USB_EP_ATTR_ISOCH) {
2584 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
2585 "usba_pipe_stop_isoc_polling: wrong pipe type");
2586
2587 usba_release_ph_data(ph_data->p_ph_impl);
2588
2589 return;
2590 }
2591 if ((ph_data->p_ep.bEndpointAddress & USB_EP_DIR_IN) == 0) {
2592 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
2593 "usba_pipe_stop_isoc_polling: wrong pipe direction");
2594
2595 usba_release_ph_data(ph_data->p_ph_impl);
2596
2597 return;
2598 }
2599
2600 if (servicing_interrupt() && (flags & USB_FLAGS_SLEEP)) {
2601 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
2602 "usba_pipe_stop_intr_polling: invalid context");
2603
2604 usba_release_ph_data(ph_data->p_ph_impl);
2605
2606 return;
2607 }
2608
2609 (void) usba_pipe_setup_func_call(ph_data->p_dip,
2610 usba_pipe_sync_stop_isoc_polling,
2611 (usba_ph_impl_t *)pipe_handle, (usb_opaque_t)flags,
2612 flags, usba_dummy_callback, NULL);
2613 }
2614