]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/dev/usb/usb_handle_request.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / sys / dev / usb / usb_handle_request.c
1 /* $FreeBSD$ */
2 /*-
3  * Copyright (c) 2008 Hans Petter Selasky. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26
27 #include <sys/stdint.h>
28 #include <sys/stddef.h>
29 #include <sys/param.h>
30 #include <sys/queue.h>
31 #include <sys/types.h>
32 #include <sys/systm.h>
33 #include <sys/kernel.h>
34 #include <sys/bus.h>
35 #include <sys/module.h>
36 #include <sys/lock.h>
37 #include <sys/mutex.h>
38 #include <sys/condvar.h>
39 #include <sys/sysctl.h>
40 #include <sys/sx.h>
41 #include <sys/unistd.h>
42 #include <sys/callout.h>
43 #include <sys/malloc.h>
44 #include <sys/priv.h>
45
46 #include <dev/usb/usb.h>
47 #include <dev/usb/usbdi.h>
48 #include <dev/usb/usbdi_util.h>
49 #include "usb_if.h"
50
51 #define USB_DEBUG_VAR usb_debug
52
53 #include <dev/usb/usb_core.h>
54 #include <dev/usb/usb_process.h>
55 #include <dev/usb/usb_busdma.h>
56 #include <dev/usb/usb_transfer.h>
57 #include <dev/usb/usb_device.h>
58 #include <dev/usb/usb_debug.h>
59 #include <dev/usb/usb_dynamic.h>
60 #include <dev/usb/usb_hub.h>
61
62 #include <dev/usb/usb_controller.h>
63 #include <dev/usb/usb_bus.h>
64
65 /* function prototypes */
66
67 static uint8_t usb_handle_get_stall(struct usb_device *, uint8_t);
68 static usb_error_t       usb_handle_remote_wakeup(struct usb_xfer *, uint8_t);
69 static usb_error_t       usb_handle_request(struct usb_xfer *);
70 static usb_error_t       usb_handle_set_config(struct usb_xfer *, uint8_t);
71 static usb_error_t       usb_handle_set_stall(struct usb_xfer *, uint8_t,
72                             uint8_t);
73 static usb_error_t       usb_handle_iface_request(struct usb_xfer *, void **,
74                             uint16_t *, struct usb_device_request, uint16_t,
75                             uint8_t);
76
77 /*------------------------------------------------------------------------*
78  *      usb_handle_request_callback
79  *
80  * This function is the USB callback for generic USB Device control
81  * transfers.
82  *------------------------------------------------------------------------*/
83 void
84 usb_handle_request_callback(struct usb_xfer *xfer, usb_error_t error)
85 {
86         usb_error_t err;
87
88         /* check the current transfer state */
89
90         switch (USB_GET_STATE(xfer)) {
91         case USB_ST_SETUP:
92         case USB_ST_TRANSFERRED:
93
94                 /* handle the request */
95                 err = usb_handle_request(xfer);
96
97                 if (err) {
98
99                         if (err == USB_ERR_BAD_CONTEXT) {
100                                 /* we need to re-setup the control transfer */
101                                 usb_needs_explore(xfer->xroot->bus, 0);
102                                 break;
103                         }
104                         goto tr_restart;
105                 }
106                 usbd_transfer_submit(xfer);
107                 break;
108
109         default:
110                 /* check if a control transfer is active */
111                 if (xfer->flags_int.control_rem != 0xFFFF) {
112                         /* handle the request */
113                         err = usb_handle_request(xfer);
114                 }
115                 if (xfer->error != USB_ERR_CANCELLED) {
116                         /* should not happen - try stalling */
117                         goto tr_restart;
118                 }
119                 break;
120         }
121         return;
122
123 tr_restart:
124         /*
125          * If a control transfer is active, stall it, and wait for the
126          * next control transfer.
127          */
128         usbd_xfer_set_frame_len(xfer, 0, sizeof(struct usb_device_request));
129         xfer->nframes = 1;
130         xfer->flags.manual_status = 1;
131         xfer->flags.force_short_xfer = 0;
132         usbd_xfer_set_stall(xfer);      /* cancel previous transfer, if any */
133         usbd_transfer_submit(xfer);
134 }
135
136 /*------------------------------------------------------------------------*
137  *      usb_handle_set_config
138  *
139  * Returns:
140  *    0: Success
141  * Else: Failure
142  *------------------------------------------------------------------------*/
143 static usb_error_t
144 usb_handle_set_config(struct usb_xfer *xfer, uint8_t conf_no)
145 {
146         struct usb_device *udev = xfer->xroot->udev;
147         usb_error_t err = 0;
148         uint8_t do_unlock;
149
150         /*
151          * We need to protect against other threads doing probe and
152          * attach:
153          */
154         USB_XFER_UNLOCK(xfer);
155
156         /* Prevent re-enumeration */
157         do_unlock = usbd_enum_lock(udev);
158
159         if (conf_no == USB_UNCONFIG_NO) {
160                 conf_no = USB_UNCONFIG_INDEX;
161         } else {
162                 /*
163                  * The relationship between config number and config index
164                  * is very simple in our case:
165                  */
166                 conf_no--;
167         }
168
169         if (usbd_set_config_index(udev, conf_no)) {
170                 DPRINTF("set config %d failed\n", conf_no);
171                 err = USB_ERR_STALLED;
172                 goto done;
173         }
174         if (usb_probe_and_attach(udev, USB_IFACE_INDEX_ANY)) {
175                 DPRINTF("probe and attach failed\n");
176                 err = USB_ERR_STALLED;
177                 goto done;
178         }
179 done:
180         if (do_unlock)
181                 usbd_enum_unlock(udev);
182         USB_XFER_LOCK(xfer);
183         return (err);
184 }
185
186 static usb_error_t
187 usb_check_alt_setting(struct usb_device *udev, 
188      struct usb_interface *iface, uint8_t alt_index)
189 {
190         uint8_t do_unlock;
191         usb_error_t err = 0;
192
193         /* Prevent re-enumeration */
194         do_unlock = usbd_enum_lock(udev);
195
196         if (alt_index >= usbd_get_no_alts(udev->cdesc, iface->idesc))
197                 err = USB_ERR_INVAL;
198
199         if (do_unlock)
200                 usbd_enum_unlock(udev);
201
202         return (err);
203 }
204
205 /*------------------------------------------------------------------------*
206  *      usb_handle_iface_request
207  *
208  * Returns:
209  *    0: Success
210  * Else: Failure
211  *------------------------------------------------------------------------*/
212 static usb_error_t
213 usb_handle_iface_request(struct usb_xfer *xfer,
214     void **ppdata, uint16_t *plen,
215     struct usb_device_request req, uint16_t off, uint8_t state)
216 {
217         struct usb_interface *iface;
218         struct usb_interface *iface_parent;     /* parent interface */
219         struct usb_device *udev = xfer->xroot->udev;
220         int error;
221         uint8_t iface_index;
222         uint8_t temp_state;
223         uint8_t do_unlock;
224
225         if ((req.bmRequestType & 0x1F) == UT_INTERFACE) {
226                 iface_index = req.wIndex[0];    /* unicast */
227         } else {
228                 iface_index = 0;        /* broadcast */
229         }
230
231         /*
232          * We need to protect against other threads doing probe and
233          * attach:
234          */
235         USB_XFER_UNLOCK(xfer);
236
237         /* Prevent re-enumeration */
238         do_unlock = usbd_enum_lock(udev);
239
240         error = ENXIO;
241
242 tr_repeat:
243         iface = usbd_get_iface(udev, iface_index);
244         if ((iface == NULL) ||
245             (iface->idesc == NULL)) {
246                 /* end of interfaces non-existing interface */
247                 goto tr_stalled;
248         }
249         /* set initial state */
250
251         temp_state = state;
252
253         /* forward request to interface, if any */
254
255         if ((error != 0) &&
256             (error != ENOTTY) &&
257             (iface->subdev != NULL) &&
258             device_is_attached(iface->subdev)) {
259 #if 0
260                 DEVMETHOD(usb_handle_request, NULL);    /* dummy */
261 #endif
262                 error = USB_HANDLE_REQUEST(iface->subdev,
263                     &req, ppdata, plen,
264                     off, &temp_state);
265         }
266         iface_parent = usbd_get_iface(udev, iface->parent_iface_index);
267
268         if ((iface_parent == NULL) ||
269             (iface_parent->idesc == NULL)) {
270                 /* non-existing interface */
271                 iface_parent = NULL;
272         }
273         /* forward request to parent interface, if any */
274
275         if ((error != 0) &&
276             (error != ENOTTY) &&
277             (iface_parent != NULL) &&
278             (iface_parent->subdev != NULL) &&
279             ((req.bmRequestType & 0x1F) == UT_INTERFACE) &&
280             (iface_parent->subdev != iface->subdev) &&
281             device_is_attached(iface_parent->subdev)) {
282                 error = USB_HANDLE_REQUEST(iface_parent->subdev,
283                     &req, ppdata, plen, off, &temp_state);
284         }
285         if (error == 0) {
286                 /* negativly adjust pointer and length */
287                 *ppdata = ((uint8_t *)(*ppdata)) - off;
288                 *plen += off;
289
290                 if ((state == USB_HR_NOT_COMPLETE) &&
291                     (temp_state == USB_HR_COMPLETE_OK))
292                         goto tr_short;
293                 else
294                         goto tr_valid;
295         } else if (error == ENOTTY) {
296                 goto tr_stalled;
297         }
298         if ((req.bmRequestType & 0x1F) != UT_INTERFACE) {
299                 iface_index++;          /* iterate */
300                 goto tr_repeat;
301         }
302         if (state != USB_HR_NOT_COMPLETE) {
303                 /* we are complete */
304                 goto tr_valid;
305         }
306         switch (req.bmRequestType) {
307         case UT_WRITE_INTERFACE:
308                 switch (req.bRequest) {
309                 case UR_SET_INTERFACE:
310                         /*
311                          * We assume that the endpoints are the same
312                          * accross the alternate settings.
313                          *
314                          * Reset the endpoints, because re-attaching
315                          * only a part of the device is not possible.
316                          */
317                         error = usb_check_alt_setting(udev,
318                             iface, req.wValue[0]);
319                         if (error) {
320                                 DPRINTF("alt setting does not exist %s\n",
321                                     usbd_errstr(error));
322                                 goto tr_stalled;
323                         }
324                         error = usb_reset_iface_endpoints(udev, iface_index);
325                         if (error) {
326                                 DPRINTF("alt setting failed %s\n",
327                                     usbd_errstr(error));
328                                 goto tr_stalled;
329                         }
330                         /* update the current alternate setting */
331                         iface->alt_index = req.wValue[0];
332                         break;
333
334                 default:
335                         goto tr_stalled;
336                 }
337                 break;
338
339         case UT_READ_INTERFACE:
340                 switch (req.bRequest) {
341                 case UR_GET_INTERFACE:
342                         *ppdata = &iface->alt_index;
343                         *plen = 1;
344                         break;
345
346                 default:
347                         goto tr_stalled;
348                 }
349                 break;
350         default:
351                 goto tr_stalled;
352         }
353 tr_valid:
354         if (do_unlock)
355                 usbd_enum_unlock(udev);
356         USB_XFER_LOCK(xfer);
357         return (0);
358
359 tr_short:
360         if (do_unlock)
361                 usbd_enum_unlock(udev);
362         USB_XFER_LOCK(xfer);
363         return (USB_ERR_SHORT_XFER);
364
365 tr_stalled:
366         if (do_unlock)
367                 usbd_enum_unlock(udev);
368         USB_XFER_LOCK(xfer);
369         return (USB_ERR_STALLED);
370 }
371
372 /*------------------------------------------------------------------------*
373  *      usb_handle_stall
374  *
375  * Returns:
376  *    0: Success
377  * Else: Failure
378  *------------------------------------------------------------------------*/
379 static usb_error_t
380 usb_handle_set_stall(struct usb_xfer *xfer, uint8_t ep, uint8_t do_stall)
381 {
382         struct usb_device *udev = xfer->xroot->udev;
383         usb_error_t err;
384
385         USB_XFER_UNLOCK(xfer);
386         err = usbd_set_endpoint_stall(udev,
387             usbd_get_ep_by_addr(udev, ep), do_stall);
388         USB_XFER_LOCK(xfer);
389         return (err);
390 }
391
392 /*------------------------------------------------------------------------*
393  *      usb_handle_get_stall
394  *
395  * Returns:
396  *    0: Success
397  * Else: Failure
398  *------------------------------------------------------------------------*/
399 static uint8_t
400 usb_handle_get_stall(struct usb_device *udev, uint8_t ea_val)
401 {
402         struct usb_endpoint *ep;
403         uint8_t halted;
404
405         ep = usbd_get_ep_by_addr(udev, ea_val);
406         if (ep == NULL) {
407                 /* nothing to do */
408                 return (0);
409         }
410         USB_BUS_LOCK(udev->bus);
411         halted = ep->is_stalled;
412         USB_BUS_UNLOCK(udev->bus);
413
414         return (halted);
415 }
416
417 /*------------------------------------------------------------------------*
418  *      usb_handle_remote_wakeup
419  *
420  * Returns:
421  *    0: Success
422  * Else: Failure
423  *------------------------------------------------------------------------*/
424 static usb_error_t
425 usb_handle_remote_wakeup(struct usb_xfer *xfer, uint8_t is_on)
426 {
427         struct usb_device *udev;
428         struct usb_bus *bus;
429
430         udev = xfer->xroot->udev;
431         bus = udev->bus;
432
433         USB_BUS_LOCK(bus);
434
435         if (is_on) {
436                 udev->flags.remote_wakeup = 1;
437         } else {
438                 udev->flags.remote_wakeup = 0;
439         }
440
441         USB_BUS_UNLOCK(bus);
442
443 #if USB_HAVE_POWERD
444         /* In case we are out of sync, update the power state. */
445         usb_bus_power_update(udev->bus);
446 #endif
447         return (0);                     /* success */
448 }
449
450 /*------------------------------------------------------------------------*
451  *      usb_handle_request
452  *
453  * Internal state sequence:
454  *
455  * USB_HR_NOT_COMPLETE -> USB_HR_COMPLETE_OK v USB_HR_COMPLETE_ERR
456  *
457  * Returns:
458  * 0: Ready to start hardware
459  * Else: Stall current transfer, if any
460  *------------------------------------------------------------------------*/
461 static usb_error_t
462 usb_handle_request(struct usb_xfer *xfer)
463 {
464         struct usb_device_request req;
465         struct usb_device *udev;
466         const void *src_zcopy;          /* zero-copy source pointer */
467         const void *src_mcopy;          /* non zero-copy source pointer */
468         uint16_t off;                   /* data offset */
469         uint16_t rem;                   /* data remainder */
470         uint16_t max_len;               /* max fragment length */
471         uint16_t wValue;
472         uint8_t state;
473         uint8_t is_complete = 1;
474         usb_error_t err;
475         union {
476                 uWord   wStatus;
477                 uint8_t buf[2];
478         }     temp;
479
480         /*
481          * Filter the USB transfer state into
482          * something which we understand:
483          */
484
485         switch (USB_GET_STATE(xfer)) {
486         case USB_ST_SETUP:
487                 state = USB_HR_NOT_COMPLETE;
488
489                 if (!xfer->flags_int.control_act) {
490                         /* nothing to do */
491                         goto tr_stalled;
492                 }
493                 break;
494         case USB_ST_TRANSFERRED:
495                 if (!xfer->flags_int.control_act) {
496                         state = USB_HR_COMPLETE_OK;
497                 } else {
498                         state = USB_HR_NOT_COMPLETE;
499                 }
500                 break;
501         default:
502                 state = USB_HR_COMPLETE_ERR;
503                 break;
504         }
505
506         /* reset frame stuff */
507
508         usbd_xfer_set_frame_len(xfer, 0, 0);
509
510         usbd_xfer_set_frame_offset(xfer, 0, 0);
511         usbd_xfer_set_frame_offset(xfer, sizeof(req), 1);
512
513         /* get the current request, if any */
514
515         usbd_copy_out(xfer->frbuffers, 0, &req, sizeof(req));
516
517         if (xfer->flags_int.control_rem == 0xFFFF) {
518                 /* first time - not initialised */
519                 rem = UGETW(req.wLength);
520                 off = 0;
521         } else {
522                 /* not first time - initialised */
523                 rem = xfer->flags_int.control_rem;
524                 off = UGETW(req.wLength) - rem;
525         }
526
527         /* set some defaults */
528
529         max_len = 0;
530         src_zcopy = NULL;
531         src_mcopy = NULL;
532         udev = xfer->xroot->udev;
533
534         /* get some request fields decoded */
535
536         wValue = UGETW(req.wValue);
537
538         DPRINTF("req 0x%02x 0x%02x 0x%04x 0x%04x "
539             "off=0x%x rem=0x%x, state=%d\n", req.bmRequestType,
540             req.bRequest, wValue, UGETW(req.wIndex), off, rem, state);
541
542         /* demultiplex the control request */
543
544         switch (req.bmRequestType) {
545         case UT_READ_DEVICE:
546                 if (state != USB_HR_NOT_COMPLETE) {
547                         break;
548                 }
549                 switch (req.bRequest) {
550                 case UR_GET_DESCRIPTOR:
551                         goto tr_handle_get_descriptor;
552                 case UR_GET_CONFIG:
553                         goto tr_handle_get_config;
554                 case UR_GET_STATUS:
555                         goto tr_handle_get_status;
556                 default:
557                         goto tr_stalled;
558                 }
559                 break;
560
561         case UT_WRITE_DEVICE:
562                 switch (req.bRequest) {
563                 case UR_SET_ADDRESS:
564                         goto tr_handle_set_address;
565                 case UR_SET_CONFIG:
566                         goto tr_handle_set_config;
567                 case UR_CLEAR_FEATURE:
568                         switch (wValue) {
569                         case UF_DEVICE_REMOTE_WAKEUP:
570                                 goto tr_handle_clear_wakeup;
571                         default:
572                                 goto tr_stalled;
573                         }
574                         break;
575                 case UR_SET_FEATURE:
576                         switch (wValue) {
577                         case UF_DEVICE_REMOTE_WAKEUP:
578                                 goto tr_handle_set_wakeup;
579                         default:
580                                 goto tr_stalled;
581                         }
582                         break;
583                 default:
584                         goto tr_stalled;
585                 }
586                 break;
587
588         case UT_WRITE_ENDPOINT:
589                 switch (req.bRequest) {
590                 case UR_CLEAR_FEATURE:
591                         switch (wValue) {
592                         case UF_ENDPOINT_HALT:
593                                 goto tr_handle_clear_halt;
594                         default:
595                                 goto tr_stalled;
596                         }
597                         break;
598                 case UR_SET_FEATURE:
599                         switch (wValue) {
600                         case UF_ENDPOINT_HALT:
601                                 goto tr_handle_set_halt;
602                         default:
603                                 goto tr_stalled;
604                         }
605                         break;
606                 default:
607                         goto tr_stalled;
608                 }
609                 break;
610
611         case UT_READ_ENDPOINT:
612                 switch (req.bRequest) {
613                 case UR_GET_STATUS:
614                         goto tr_handle_get_ep_status;
615                 default:
616                         goto tr_stalled;
617                 }
618                 break;
619         default:
620                 /* we use "USB_ADD_BYTES" to de-const the src_zcopy */
621                 err = usb_handle_iface_request(xfer,
622                     USB_ADD_BYTES(&src_zcopy, 0),
623                     &max_len, req, off, state);
624                 if (err == 0) {
625                         is_complete = 0;
626                         goto tr_valid;
627                 } else if (err == USB_ERR_SHORT_XFER) {
628                         goto tr_valid;
629                 }
630                 /*
631                  * Reset zero-copy pointer and max length
632                  * variable in case they were unintentionally
633                  * set:
634                  */
635                 src_zcopy = NULL;
636                 max_len = 0;
637
638                 /*
639                  * Check if we have a vendor specific
640                  * descriptor:
641                  */
642                 goto tr_handle_get_descriptor;
643         }
644         goto tr_valid;
645
646 tr_handle_get_descriptor:
647         err = (usb_temp_get_desc_p) (udev, &req, &src_zcopy, &max_len);
648         if (err)
649                 goto tr_stalled;
650         if (src_zcopy == NULL)
651                 goto tr_stalled;
652         goto tr_valid;
653
654 tr_handle_get_config:
655         temp.buf[0] = udev->curr_config_no;
656         src_mcopy = temp.buf;
657         max_len = 1;
658         goto tr_valid;
659
660 tr_handle_get_status:
661
662         wValue = 0;
663
664         USB_BUS_LOCK(udev->bus);
665         if (udev->flags.remote_wakeup) {
666                 wValue |= UDS_REMOTE_WAKEUP;
667         }
668         if (udev->flags.self_powered) {
669                 wValue |= UDS_SELF_POWERED;
670         }
671         USB_BUS_UNLOCK(udev->bus);
672
673         USETW(temp.wStatus, wValue);
674         src_mcopy = temp.wStatus;
675         max_len = sizeof(temp.wStatus);
676         goto tr_valid;
677
678 tr_handle_set_address:
679         if (state == USB_HR_NOT_COMPLETE) {
680                 if (wValue >= 0x80) {
681                         /* invalid value */
682                         goto tr_stalled;
683                 } else if (udev->curr_config_no != 0) {
684                         /* we are configured ! */
685                         goto tr_stalled;
686                 }
687         } else if (state != USB_HR_NOT_COMPLETE) {
688                 udev->address = (wValue & 0x7F);
689                 goto tr_bad_context;
690         }
691         goto tr_valid;
692
693 tr_handle_set_config:
694         if (state == USB_HR_NOT_COMPLETE) {
695                 if (usb_handle_set_config(xfer, req.wValue[0])) {
696                         goto tr_stalled;
697                 }
698         }
699         goto tr_valid;
700
701 tr_handle_clear_halt:
702         if (state == USB_HR_NOT_COMPLETE) {
703                 if (usb_handle_set_stall(xfer, req.wIndex[0], 0)) {
704                         goto tr_stalled;
705                 }
706         }
707         goto tr_valid;
708
709 tr_handle_clear_wakeup:
710         if (state == USB_HR_NOT_COMPLETE) {
711                 if (usb_handle_remote_wakeup(xfer, 0)) {
712                         goto tr_stalled;
713                 }
714         }
715         goto tr_valid;
716
717 tr_handle_set_halt:
718         if (state == USB_HR_NOT_COMPLETE) {
719                 if (usb_handle_set_stall(xfer, req.wIndex[0], 1)) {
720                         goto tr_stalled;
721                 }
722         }
723         goto tr_valid;
724
725 tr_handle_set_wakeup:
726         if (state == USB_HR_NOT_COMPLETE) {
727                 if (usb_handle_remote_wakeup(xfer, 1)) {
728                         goto tr_stalled;
729                 }
730         }
731         goto tr_valid;
732
733 tr_handle_get_ep_status:
734         if (state == USB_HR_NOT_COMPLETE) {
735                 temp.wStatus[0] =
736                     usb_handle_get_stall(udev, req.wIndex[0]);
737                 temp.wStatus[1] = 0;
738                 src_mcopy = temp.wStatus;
739                 max_len = sizeof(temp.wStatus);
740         }
741         goto tr_valid;
742
743 tr_valid:
744         if (state != USB_HR_NOT_COMPLETE) {
745                 goto tr_stalled;
746         }
747         /* subtract offset from length */
748
749         max_len -= off;
750
751         /* Compute the real maximum data length */
752
753         if (max_len > xfer->max_data_length) {
754                 max_len = usbd_xfer_max_len(xfer);
755         }
756         if (max_len > rem) {
757                 max_len = rem;
758         }
759         /*
760          * If the remainder is greater than the maximum data length,
761          * we need to truncate the value for the sake of the
762          * comparison below:
763          */
764         if (rem > xfer->max_data_length) {
765                 rem = usbd_xfer_max_len(xfer);
766         }
767         if ((rem != max_len) && (is_complete != 0)) {
768                 /*
769                  * If we don't transfer the data we can transfer, then
770                  * the transfer is short !
771                  */
772                 xfer->flags.force_short_xfer = 1;
773                 xfer->nframes = 2;
774         } else {
775                 /*
776                  * Default case
777                  */
778                 xfer->flags.force_short_xfer = 0;
779                 xfer->nframes = max_len ? 2 : 1;
780         }
781         if (max_len > 0) {
782                 if (src_mcopy) {
783                         src_mcopy = USB_ADD_BYTES(src_mcopy, off);
784                         usbd_copy_in(xfer->frbuffers + 1, 0,
785                             src_mcopy, max_len);
786                         usbd_xfer_set_frame_len(xfer, 1, max_len);
787                 } else {
788                         usbd_xfer_set_frame_data(xfer, 1,
789                             USB_ADD_BYTES(src_zcopy, off), max_len);
790                 }
791         } else {
792                 /* the end is reached, send status */
793                 xfer->flags.manual_status = 0;
794                 usbd_xfer_set_frame_len(xfer, 1, 0);
795         }
796         DPRINTF("success\n");
797         return (0);                     /* success */
798
799 tr_stalled:
800         DPRINTF("%s\n", (state != USB_HR_NOT_COMPLETE) ?
801             "complete" : "stalled");
802         return (USB_ERR_STALLED);
803
804 tr_bad_context:
805         DPRINTF("bad context\n");
806         return (USB_ERR_BAD_CONTEXT);
807 }