Date: Tue, 25 Dec 2007 19:45:22 GMT From: Hans Petter Selasky <hselasky@FreeBSD.org> To: Perforce Change Reviews <perforce@FreeBSD.org> Subject: PERFORCE change 131607 for review Message-ID: <200712251945.lBPJjMbg026803@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=131607 Change 131607 by hselasky@hselasky_laptop001 on 2007/12/25 19:45:00 Fixes for USB Device Side Mode. Affected files ... .. //depot/projects/usb/src/sys/dev/usb/usb_transfer.c#87 edit Differences ... ==== //depot/projects/usb/src/sys/dev/usb/usb_transfer.c#87 (text+ko) ==== @@ -1214,7 +1214,6 @@ } else { mtx_unlock(info->usb_mtx); } - } } } @@ -1500,7 +1499,6 @@ /* * This is not a valid operation! */ - PRINTFN(-1, ("Invalid parameter " "combination\n")); goto error; @@ -2756,6 +2754,7 @@ /* handle the request */ err = usbd_handle_request(xfer); + if (err) { if (err == USBD_BAD_CONTEXT) { /* * Currently we get a "start" context by @@ -2765,12 +2764,11 @@ USB_BUS_EXPLORE_TREE); return; } - if ((!xfer->flags_int.control_act) || err) { /* * If no control transfer is active, * receive the next SETUP message: */ - goto tr_start; + goto tr_restart; } usbd_start_hardware(xfer); return; @@ -2778,24 +2776,18 @@ default: if (xfer->error != USBD_CANCELLED) { /* should not happen - try stalling */ - err = USBD_STALLED; - goto tr_start; + goto tr_restart; } break; } return; -tr_start: +tr_restart: xfer->frlengths[0] = sizeof(usb_device_request_t); xfer->nframes = 1; xfer->flags.manual_status = 1; xfer->flags.force_short_xfer = 0; - xfer->flags.short_xfer_ok = 0; - if (err) { - xfer->flags.stall_pipe = 1; - } else { - xfer->flags.stall_pipe = 0; - } + xfer->flags.stall_pipe = 1; /* cancel previous transfer, if any */ usbd_start_hardware(xfer); return; } @@ -2821,64 +2813,20 @@ } if (usbd_set_config_index(xfer->udev, conf_no, 0)) { + PRINTFN(0, ("set config %d failed\n", conf_no)); mtx_lock(xfer->priv_mtx); return (USBD_STALLED); } if (usbd_probe_and_attach(xfer->udev, USB_IFACE_INDEX_ANY)) { - mtx_lock(xfer->priv_mtx); - return (USBD_STALLED); - } - mtx_lock(xfer->priv_mtx); - - return (0); -} - -/*------------------------------------------------------------------------* - * usbd_handle_set_alt_setting - *------------------------------------------------------------------------*/ -static usbd_status_t -usbd_handle_set_alt_setting(struct usbd_xfer *xfer, - uint8_t iface_index, uint8_t alt_index) -{ - if (iface_index >= USB_MAX_INTERFACES) { - return (USBD_STALLED); - } - mtx_unlock(xfer->priv_mtx); - - usbd_detach_device(xfer->udev, iface_index, 1); - - if (usbd_set_alt_interface_index(xfer->udev, - iface_index, alt_index)) { - mtx_lock(xfer->priv_mtx); - return (USBD_STALLED); - } - if (usbd_probe_and_attach(xfer->udev, iface_index)) { + PRINTFN(0, ("probe and attach failed\n")); mtx_lock(xfer->priv_mtx); return (USBD_STALLED); } mtx_lock(xfer->priv_mtx); - return (0); } /*------------------------------------------------------------------------* - * usbd_handle_get_alt_setting - *------------------------------------------------------------------------*/ -static usbd_status_t -usbd_handle_get_alt_setting(struct usbd_xfer *xfer, - uint8_t iface_index, uint8_t *ptr) -{ - struct usbd_interface *iface; - - iface = usbd_get_iface(xfer->udev, iface_index); - if (iface) { - *ptr = iface->alt_index; - return (0); - } - return (USBD_STALLED); -} - -/*------------------------------------------------------------------------* * usbd_handle_set_stall_sub * * This function is used to make a BULK or INTERRUPT endpoint @@ -3005,24 +2953,33 @@ /*------------------------------------------------------------------------* * usbd_handle_request + * + * Returns: + * 0: Ready to start hardware + * USBD_BAD_CONTEXT: Need to switch context + * Else: Stall current transfer, if any *------------------------------------------------------------------------*/ static usbd_status_t usbd_handle_request(struct usbd_xfer *xfer) { +/* + * USB handle request states + * + * Typical state sequence: + * + * ST_DATA [ -> ST_CONTEXT_START ] -> ST_POST_STATUS + */ enum { ST_DATA, ST_CONTEXT_START, ST_POST_STATUS, }; - - /* - * State sequence: - * - * ST_DATA [ -> ST_CONTEXT_START ] -> ST_POST_STATUS - */ usb_device_request_t req; struct usbd_device *udev; - const void *ptr; + struct usbd_interface *iface; + const void *src_zcopy; /* zero-copy source pointer */ + const void *src_mcopy; /* non zero-copy source pointer */ + int error; uint16_t off; /* data offset */ uint16_t rem; /* data remainder */ uint16_t max_len; /* max fragment length */ @@ -3041,15 +2998,17 @@ switch (USBD_GET_STATE(xfer)) { case USBD_ST_SETUP: + state = ST_CONTEXT_START; + if (!xfer->flags_int.control_act) { /* nothing to do */ - return (0); + goto tr_stalled; } + if (xfer->flags_int.context != USBD_CONTEXT_START) { - /* wrong context */ + /* wrong context - should not happen */ goto tr_bad_context; } - state = ST_CONTEXT_START; break; default: /* USBD_ST_TRANSFERRED */ @@ -3085,7 +3044,8 @@ /* set some defaults */ max_len = 0; - ptr = &temp; + src_zcopy = NULL; + src_mcopy = NULL; udev = xfer->udev; /* get some request fields decoded */ @@ -3093,9 +3053,9 @@ wValue = UGETW(req.wValue); wIndex = UGETW(req.wIndex); - PRINTFN(2, ("req 0x%02x 0x%02x 0x%04x 0x%04x " - "off=0x%x rem=0x%x\n", req.bmRequestType, - req.bRequest, wValue, wIndex, off, rem)); + PRINTFN(0, ("req 0x%02x 0x%02x 0x%04x 0x%04x " + "off=0x%x rem=0x%x, state=%d\n", req.bmRequestType, + req.bRequest, wValue, wIndex, off, rem, state)); /* demultiplex the control request */ @@ -3130,7 +3090,7 @@ case UT_WRITE_ENDPOINT: switch (req.bRequest) { case UR_CLEAR_FEATURE: - switch (UGETW(req.wValue)) { + switch (wValue) { case UF_ENDPOINT_HALT: goto tr_handle_clear_halt; case UF_DEVICE_REMOTE_WAKEUP: @@ -3141,7 +3101,7 @@ break; case UR_SET_FEATURE: - switch (UGETW(req.wValue)) { + switch (wValue) { case UF_ENDPOINT_HALT: goto tr_handle_set_halt; case UF_DEVICE_REMOTE_WAKEUP: @@ -3163,60 +3123,35 @@ goto tr_stalled; } break; - - case UT_WRITE_INTERFACE: - switch (req.bRequest) { - case UR_SET_INTERFACE: - goto tr_handle_set_interface; - default: - goto tr_stalled; - } - break; - - case UT_READ_INTERFACE: - switch (req.bRequest) { - case UR_GET_INTERFACE: - goto tr_handle_get_interface; - default: - goto tr_stalled; + default: + if ((req.bmRequestType & 0x1F) == UT_INTERFACE) { + if (state == ST_DATA) { + goto tr_bad_context; + } + goto tr_handle_iface_request; } - break; - - case UT_WRITE_CLASS_INTERFACE: - case UT_WRITE_VENDOR_INTERFACE: - /* XXX forward */ - break; - - case UT_READ_CLASS_INTERFACE: - case UT_READ_VENDOR_INTERFACE: - /* XXX forward */ - break; - default: goto tr_stalled; } goto tr_valid; tr_handle_get_descriptor: - usbd_temp_get_desc(udev, &req, &ptr, &max_len); - if (ptr == NULL) { + usbd_temp_get_desc(udev, &req, &src_zcopy, &max_len); + if (src_zcopy == NULL) { goto tr_stalled; } - /* use zero copy */ - usbd_set_frame_data(xfer, USBD_ADD_BYTES(ptr, off), 1); - ptr = NULL; - /* adjust maximum length according to offset */ - max_len -= off; goto tr_valid; tr_handle_get_config: + temp.buf[0] = udev->curr_config_no; + src_mcopy = temp.buf; max_len = 1; - temp.buf[0] = udev->curr_config_no; goto tr_valid; tr_handle_get_status: - max_len = sizeof(temp.wStatus); /* XXX FIXME */ USETW(temp.wStatus, UDS_SELF_POWERED); + src_mcopy = temp.wStatus; + max_len = sizeof(temp.wStatus); goto tr_valid; tr_handle_set_address: @@ -3238,7 +3173,7 @@ if (state == ST_DATA) { goto tr_bad_context; } else if (state == ST_CONTEXT_START) { - if (usbd_handle_set_config(xfer, wValue)) { + if (usbd_handle_set_config(xfer, req.wValue[0])) { goto tr_stalled; } } @@ -3246,7 +3181,7 @@ tr_handle_clear_halt: if (state == ST_DATA) { - if (usbd_handle_set_stall(xfer, wIndex, 0)) { + if (usbd_handle_set_stall(xfer, req.wIndex[0], 0)) { goto tr_stalled; } } @@ -3264,7 +3199,7 @@ tr_handle_set_halt: if (state == ST_DATA) { - if (usbd_handle_set_stall(xfer, wIndex, 1)) { + if (usbd_handle_set_stall(xfer, req.wIndex[0], 1)) { goto tr_stalled; } } @@ -3282,32 +3217,80 @@ tr_handle_get_ep_status: if (state == ST_DATA) { + temp.wStatus[0] = + usbd_handle_get_stall(udev, req.wIndex[0]); + temp.wStatus[1] = 0; + src_mcopy = temp.wStatus; max_len = sizeof(temp.wStatus); - temp.wStatus[0] = usbd_handle_get_stall(udev, req.wIndex[0]); - temp.wStatus[1] = 0; } goto tr_valid; -tr_handle_set_interface: - if (state == ST_DATA) { - goto tr_bad_context; - } else if (state == ST_CONTEXT_START) { - if (usbd_handle_set_alt_setting(xfer, wIndex - 1, wValue)) { +tr_handle_iface_request: + iface = usbd_get_iface(udev, req.wIndex[0]); + if (iface == NULL) { + goto tr_stalled; + } + if (iface->subdev == NULL) { + goto tr_handle_iface_request_builtin; + } + if (device_is_attached(iface->subdev) == 0) { + goto tr_handle_iface_request_builtin; + } + mtx_unlock(xfer->priv_mtx); + + /* We use "USBD_ADD_BYTES" to de-const the src_zcopy */ + + error = USB_HANDLE_REQUEST(iface->subdev, + &req, USBD_ADD_BYTES(&src_zcopy, 0), &max_len, + off, (state == ST_POST_STATUS)); + + mtx_lock(xfer->priv_mtx); + + if (error == 0) { + /* negativly adjust pointer and length */ + src_zcopy = ((const uint8_t *)src_zcopy) - off; + max_len += off; + goto tr_valid; + } else if (error == ENOTTY) { + goto tr_stalled; + } + goto tr_handle_iface_request_builtin; + +tr_handle_iface_request_builtin: + switch (req.bmRequestType) { + case UT_WRITE_INTERFACE: + switch (req.bRequest) { + case UR_SET_INTERFACE: + if (iface->alt_index != req.wValue[0]) { + goto tr_stalled; + } + break; + default: goto tr_stalled; } - } - goto tr_valid; + break; + + case UT_READ_INTERFACE: + switch (req.bRequest) { + case UR_GET_INTERFACE: + src_mcopy = &(iface->alt_index); + max_len = 1; + break; -tr_handle_get_interface: - if (state == ST_DATA) { - if (usbd_handle_get_alt_setting(xfer, wIndex, temp.buf)) { + default: goto tr_stalled; } - max_len = 1; + break; } goto tr_valid; tr_valid: + if (state == ST_POST_STATUS) { + goto tr_stalled; + } + /* subtract offset from length */ + + max_len -= off; /* Compute the real maximum data length */ @@ -3340,8 +3323,13 @@ xfer->nframes = max_len ? 2 : 1; } if (max_len > 0) { - if (ptr) { - usbd_copy_in(xfer->frbuffers + 1, 0, ptr, max_len); + if (src_mcopy) { + src_mcopy = USBD_ADD_BYTES(src_mcopy, off); + usbd_copy_in(xfer->frbuffers + 1, 0, + src_mcopy, max_len); + } else { + usbd_set_frame_data(xfer, + USBD_ADD_BYTES(src_zcopy, off), 1); } xfer->frlengths[1] = max_len; } else { @@ -3350,12 +3338,16 @@ xfer->frlengths[1] = 0; } xfer->flags.stall_pipe = 0; /* do not stall pipe */ + PRINTFN(0, ("success\n")); return (0); /* success */ tr_stalled: + PRINTFN(0, ("%s\n", (state == ST_POST_STATUS) ? + "complete" : "stalled")); return (USBD_STALLED); tr_bad_context: + PRINTFN(0, ("bad context\n")); return (USBD_BAD_CONTEXT); } @@ -3367,7 +3359,7 @@ .bufsize = 1024, /* bytes */ .mh.flags = {.proxy_buffer = 1,.short_xfer_ok = 1,}, .mh.callback = &usbd_do_request_callback, - .md.flags = {.proxy_buffer = 1,.short_xfer_ok = 1,}, + .md.flags = {.proxy_buffer = 1,.short_xfer_ok = 0,}, .md.callback = &usbd_handle_request_callback, }, };
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200712251945.lBPJjMbg026803>