PERFORCE change 146837 for review
Hans Petter Selasky
hselasky at FreeBSD.org
Thu Aug 7 13:41:29 UTC 2008
http://perforce.freebsd.org/chv.cgi?CH=146837
Change 146837 by hselasky at 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 <dev/usb2/include/usb2_mfunc.h>
#include <dev/usb2/include/usb2_standard.h>
#include <dev/usb2/include/usb2_error.h>
+#include <dev/usb2/include/usb2_ioctl.h>
+
+#define USB_DEBUG_VAR usb2_debug
#include <dev/usb2/core/usb2_core.h>
#include <dev/usb2/core/usb2_compat_linux.h>
@@ -38,6 +41,8 @@
#include <dev/usb2/core/usb2_transfer.h>
#include <dev/usb2/core/usb2_parse.h>
#include <dev/usb2/core/usb2_hub.h>
+#include <dev/usb2/core/usb2_request.h>
+#include <dev/usb2/core/usb2_debug.h>
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;
-
}
}
More information about the p4-projects
mailing list