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