From owner-p4-projects@FreeBSD.ORG Thu Aug 7 13:41:29 2008 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 2EF7E1065674; Thu, 7 Aug 2008 13:41:29 +0000 (UTC) Delivered-To: perforce@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id CE2541065673 for ; Thu, 7 Aug 2008 13:41:28 +0000 (UTC) (envelope-from hselasky@FreeBSD.org) Received: from repoman.freebsd.org (repoman.freebsd.org [IPv6:2001:4f8:fff6::29]) by mx1.freebsd.org (Postfix) with ESMTP id BAE5B8FC0A for ; Thu, 7 Aug 2008 13:41:28 +0000 (UTC) (envelope-from hselasky@FreeBSD.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.14.2/8.14.2) with ESMTP id m77DfSIH051429 for ; Thu, 7 Aug 2008 13:41:28 GMT (envelope-from hselasky@FreeBSD.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.14.2/8.14.1/Submit) id m77DfSI3051427 for perforce@freebsd.org; Thu, 7 Aug 2008 13:41:28 GMT (envelope-from hselasky@FreeBSD.org) Date: Thu, 7 Aug 2008 13:41:28 GMT Message-Id: <200808071341.m77DfSI3051427@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to hselasky@FreeBSD.org using -f From: Hans Petter Selasky To: Perforce Change Reviews Cc: Subject: PERFORCE change 146837 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 07 Aug 2008 13:41:29 -0000 http://perforce.freebsd.org/chv.cgi?CH=146837 Change 146837 by hselasky@hselasky_laptop001 on 2008/08/07 13:41:14 Fixes and improvements to the Linux USB compat layer. Has been tested and found to work. Affected files ... .. //depot/projects/usb/src/sys/dev/usb2/core/usb2_compat_linux.c#8 edit Differences ... ==== //depot/projects/usb/src/sys/dev/usb2/core/usb2_compat_linux.c#8 (text+ko) ==== @@ -28,6 +28,9 @@ #include #include #include +#include + +#define USB_DEBUG_VAR usb2_debug #include #include @@ -38,6 +41,8 @@ #include #include #include +#include +#include struct usb_linux_softc { LIST_ENTRY(usb_linux_softc) sc_attached_list; @@ -62,12 +67,13 @@ static usb_complete_t usb_linux_wait_complete; static uint16_t usb_max_isoc_frames(struct usb_device *dev); -static int usb_start_wait_urb(struct urb *urb, uint32_t timeout, uint32_t *p_actlen); +static int usb_start_wait_urb(struct urb *urb, uint32_t timeout, uint16_t *p_actlen); static const struct usb_device_id *usb_linux_lookup_id(const struct usb_device_id *id, struct usb2_attach_arg *uaa); static struct usb_driver *usb_linux_get_usb_driver(struct usb_linux_softc *sc); static struct usb_device *usb_linux_create_usb_device(struct usb2_device *udev, device_t dev); static void usb_linux_cleanup_interface(struct usb_device *dev, struct usb_interface *iface); static void usb_linux_complete(struct usb2_xfer *xfer); +static int usb_unlink_urb_sub(struct urb *urb, uint8_t drain); /*------------------------------------------------------------------------* * FreeBSD USB interface @@ -437,12 +443,35 @@ * * This function is used to stop an URB after that it is been * submitted, but before the "complete" callback has been called. On - * FreeBSD this function is always non-blocking, and will always call - * the "complete" callback with an error before it returns. *------------------------------------------------------------------------*/ int usb_unlink_urb(struct urb *urb) { + return (usb_unlink_urb_sub(urb, 0)); +} + +static void +usb_unlink_bsd(struct usb2_xfer *xfer, + struct urb *urb, uint8_t drain) +{ + if (xfer && + usb2_transfer_pending(xfer) && + (xfer->priv_fifo == (void *)urb)) { + if (drain) { + mtx_unlock(&Giant); + usb2_transfer_drain(xfer); + mtx_lock(&Giant); + } else { + usb2_transfer_stop(xfer); + } + usb2_transfer_start(xfer); + } + return; +} + +static int +usb_unlink_urb_sub(struct urb *urb, uint8_t drain) +{ struct usb_host_endpoint *uhe; uint16_t x; @@ -479,17 +508,8 @@ * If so, re-start that transfer, which will lead to the * termination of that URB: */ - - if (uhe->bsd_xfer[0] && - (uhe->bsd_xfer[0]->priv_fifo == (void *)urb)) { - usb2_transfer_stop(uhe->bsd_xfer[0]); - usb2_transfer_start(uhe->bsd_xfer[0]); - } - if (uhe->bsd_xfer[1] && - (uhe->bsd_xfer[1]->priv_fifo == (void *)urb)) { - usb2_transfer_stop(uhe->bsd_xfer[1]); - usb2_transfer_start(uhe->bsd_xfer[1]); - } + usb_unlink_bsd(uhe->bsd_xfer[0], urb, drain); + usb_unlink_bsd(uhe->bsd_xfer[1], urb, drain); } return (0); } @@ -539,7 +559,7 @@ * Linux USB transfers. *------------------------------------------------------------------------*/ static int -usb_start_wait_urb(struct urb *urb, uint32_t timeout, uint32_t *p_actlen) +usb_start_wait_urb(struct urb *urb, uint32_t timeout, uint16_t *p_actlen) { int err; @@ -564,8 +584,6 @@ urb->transfer_flags |= URB_IS_SLEEPING; usb2_cv_wait(&(urb->cv_wait), &Giant); urb->transfer_flags &= ~URB_IS_SLEEPING; - if (err) - goto done; } err = urb->status; @@ -596,48 +614,51 @@ int usb_control_msg(struct usb_device *dev, struct usb_host_endpoint *uhe, uint8_t request, uint8_t requesttype, - uint16_t value, uint16_t index, void *data, uint16_t size, uint32_t timeout) + uint16_t value, uint16_t index, void *data, + uint16_t size, uint32_t timeout) { + struct usb2_device_request req; struct urb *urb; - struct usb2_device_request *req; - struct usb_host_endpoint *uhe_write; - struct usb_host_endpoint *uhe_read; - uint32_t actlen; int err; + uint16_t actlen; uint8_t type; uint8_t addr; + req.bmRequestType = requesttype; + req.bRequest = request; + USETW(req.wValue, value); + USETW(req.wIndex, index); + USETW(req.wLength, size); + if (uhe == NULL) { return (-EINVAL); } type = (uhe->desc.bmAttributes & UE_XFERTYPE); addr = (uhe->desc.bEndpointAddress & UE_ADDR); - /* - * The FreeBSD USB stack supports standard control transfers on - * control endpoints only. For the other two endpoint types we need - * special handling. Check the endpoint type: - */ - if (type == UE_CONTROL) { - uhe_write = NULL; - uhe_read = NULL; - } else { - if (type == UE_ISOCHRONOUS) { - return (-EINVAL); - } - uhe_write = usb_find_host_endpoint(dev, type, addr | UE_DIR_OUT); - if (uhe_write == NULL) { - return (-EINVAL); - } - if (requesttype & UT_READ) { - uhe_read = usb_find_host_endpoint(dev, type, addr | UE_DIR_IN); - if (uhe_read == NULL) { - return (-EINVAL); - } + if (type != UE_CONTROL) { + return (-EINVAL); + } + if (addr == 0) { + /* + * The FreeBSD USB stack supports standard control + * transfers on control endpoint zero: + */ + err = usb2_do_request_flags(dev->bsd_udev, + &Giant, &req, data, USB_SHORT_XFER_OK, + &actlen, timeout); + if (err) { + err = -EPIPE; } else { - uhe_read = NULL; + err = actlen; } + return (err); } + if (dev->bsd_udev->flags.usb2_mode != USB_MODE_HOST) { + /* not supported */ + return (-EINVAL); + } + err = usb_setup_endpoint(dev, uhe, 1 /* dummy */ ); /* * NOTE: we need to allocate real memory here so that we don't @@ -650,58 +671,21 @@ return (-ENOMEM); urb->dev = dev; + urb->pipe = uhe; - req = (void *)(urb->setup_packet); + bcopy(&req, urb->setup_packet, sizeof(req)); - req->bmRequestType = requesttype; - req->bRequest = request; - USETW(req->wValue, value); - USETW(req->wIndex, index); - USETW(req->wLength, size); - - if (size && (req->bmRequestType & UT_WRITE)) { + if (size && (!(req.bmRequestType & UT_READ))) { /* move the data to a real buffer */ - bcopy(data, req + 1, size); + bcopy(data, USB_ADD_BYTES(urb->setup_packet, + sizeof(req)), size); } - if (type == UE_CONTROL) { - urb->pipe = uhe; - err = usb_start_wait_urb(urb, timeout, &actlen); - } else { - urb->pipe = uhe_write; - urb->transfer_buffer = urb->setup_packet; - urb->transfer_buffer_length = sizeof(*req); + err = usb_start_wait_urb(urb, timeout, &actlen); - err = usb_start_wait_urb(urb, 1000, &actlen); - if (err) { - goto done; - } - if (actlen < sizeof(*req)) { - err = -EPIPE; - actlen = 0; - goto done; - } - if (size) { - if (req->bmRequestType & UT_READ) { - urb->pipe = uhe_read; - } - urb->transfer_buffer = req + 1; - urb->transfer_buffer_length = size; - - err = usb_start_wait_urb(urb, timeout, &actlen); - if (err) { - goto done; - } - } - } - -done: - if (req->bmRequestType & UT_READ) { - if (actlen < size) { - /* we don't like returning random data */ - bzero(((uint8_t *)data) + actlen, size - actlen); - } + if (req.bmRequestType & UT_READ) { if (actlen) { - bcopy(req + 1, data, actlen); + bcopy(USB_ADD_BYTES(urb->setup_packet, + sizeof(req)), data, actlen); } } usb_free_urb(urb); @@ -751,7 +735,8 @@ * size on "wMaxPacketSize". *------------------------------------------------------------------------*/ int -usb_setup_endpoint(struct usb_device *dev, struct usb_host_endpoint *uhe, uint32_t bufsize) +usb_setup_endpoint(struct usb_device *dev, + struct usb_host_endpoint *uhe, uint32_t bufsize) { struct usb2_config cfg[2]; uint8_t type = uhe->desc.bmAttributes & UE_XFERTYPE; @@ -962,12 +947,6 @@ sizeof(p_ud->descriptor)); bcopy(udev->default_pipe.edesc, &(p_ud->ep0.desc), sizeof(p_ud->ep0.desc)); - - if (usb_setup_endpoint(p_ud, &(p_ud->ep0), 1024 /* bytes */ )) { - usb_linux_free_device(p_ud); - p_ud = NULL; - goto done; - } } } done: @@ -1007,7 +986,6 @@ urb->setup_packet = (void *)(urb + 1); urb->transfer_buffer = (void *)(urb->setup_packet + sizeof(struct usb2_device_request)); - urb->transfer_buffer_length = mem_flags; } else { urb->number_of_packets = iso_packets; } @@ -1058,7 +1036,6 @@ for (uhe = uhi->endpoint; uhe != uhe_end; uhe++) { - ea = uhe->desc.bEndpointAddress; at = uhe->desc.bmAttributes; @@ -1264,9 +1241,9 @@ void usb_kill_urb(struct urb *urb) { - int err; - - err = usb_unlink_urb(urb); + if (usb_unlink_urb_sub(urb, 1)) { + /* ignore */ + } return; } @@ -1362,6 +1339,8 @@ struct usb_host_endpoint *uhe = xfer->priv_sc; struct usb_iso_packet_descriptor *uipd; + DPRINTF("\n"); + switch (USB_GET_STATE(xfer)) { case USB_ST_TRANSFERRED: @@ -1423,12 +1402,13 @@ TAILQ_REMOVE(&(uhe->bsd_urb_list), urb, bsd_urb_list); urb->bsd_urb_list.tqe_prev = NULL; - x = usb_max_isoc_frames(urb->dev); + x = xfer->max_frame_count; if (urb->number_of_packets > x) { /* XXX simply truncate the transfer */ urb->number_of_packets = x; } } else { + DPRINTF("Already got a transfer\n"); /* already got a transfer (should not happen) */ urb = xfer->priv_fifo; @@ -1525,19 +1505,17 @@ }; struct urb *urb = xfer->priv_fifo; struct usb_host_endpoint *uhe = xfer->priv_sc; + uint8_t *ptr; uint32_t max_bulk = xfer->max_data_length; uint8_t data_frame = xfer->flags_int.control_xfr ? 1 : 0; + DPRINTF("\n"); + switch (USB_GET_STATE(xfer)) { case USB_ST_TRANSFERRED: if (xfer->flags_int.control_xfr) { - /* sanity check - should not happen */ - - if (xfer->aframes < xfer->nframes) { - goto tr_error; - } /* don't transfer the setup packet again: */ xfer->frlengths[0] = 0; @@ -1562,7 +1540,6 @@ urb->status = 0; } } else { - /* check remainder */ if (urb->bsd_length_rem > 0) { goto setup_bulk; @@ -1576,7 +1553,6 @@ case USB_ST_SETUP: tr_setup: - /* get next transfer */ urb = TAILQ_FIRST(&(uhe->bsd_urb_list)); if (urb == NULL) { @@ -1607,18 +1583,21 @@ xfer->frlengths[0] = REQ_SIZE; - /* setup data transfer direction */ + ptr = urb->setup_packet; - urb->bsd_isread = (((uint8_t *)(urb->setup_packet))[0] & UT_READ) ? 1 : 0; + /* setup data transfer direction and length */ + urb->bsd_isread = (ptr[0] & UT_READ) ? 1 : 0; + urb->bsd_length_rem = ptr[6] | (ptr[7] << 8); } else { /* setup data transfer direction */ - urb->bsd_isread = (uhe->desc.bEndpointAddress & UE_DIR_IN) ? 1 : 0; + urb->bsd_length_rem = urb->transfer_buffer_length; + urb->bsd_isread = (uhe->desc.bEndpointAddress & + UE_DIR_IN) ? 1 : 0; } - urb->bsd_length_rem = urb->transfer_buffer_length; urb->bsd_data_ptr = urb->transfer_buffer; urb->actual_length = 0; @@ -1658,7 +1637,6 @@ return; default: -tr_error: if (xfer->error == USB_ERR_CANCELLED) { urb->status = -ECONNRESET; } else { @@ -1676,6 +1654,5 @@ return; } goto tr_setup; - } }