PERFORCE change 126720 for review
Hans Petter Selasky
hselasky at FreeBSD.org
Sun Sep 23 05:34:32 PDT 2007
http://perforce.freebsd.org/chv.cgi?CH=126720
Change 126720 by hselasky at hselasky_laptop001 on 2007/09/23 12:34:22
FYI; The comments follow the P4 diff from top to bottom.
- the maximum frame size must be read from the USB transfer
- convert kernel USB flags (USBD_XXX) into a bitmap (scripted)
- computing correct buffer sizes have been factored out into
the USB kernel by setting the "proxy_buffer" flag.
- "xfer->actlen < xfer->sumlen" is the new way to check if a
USB transfer is short.
- remove redundant setting of "xfer->length" for ISOC USB transfers.
- proxy buffer data size is now stored in "xfer->max_data_length".
- new mechanism to proxy USB control transfers
Affected files ...
.. //depot/projects/usb/src/sys/dev/usb/usb_compat_linux.c#7 edit
Differences ...
==== //depot/projects/usb/src/sys/dev/usb/usb_compat_linux.c#7 (text+ko) ====
@@ -753,7 +753,6 @@
usb_setup_endpoint(struct usb_device *dev, struct usb_host_endpoint *uhe, uint32_t bufsize)
{
struct usbd_config cfg[2];
- uint16_t mfs = usbd_get_max_frame_size((usb_endpoint_descriptor_t *)&(uhe->desc));
uint8_t type = uhe->desc.bmAttributes & UE_XFERTYPE;
uint8_t addr = uhe->desc.bEndpointAddress;
@@ -784,7 +783,8 @@
cfg[0].callback = &usb_linux_isoc_callback;
cfg[0].bufsize = 0; /* use wMaxPacketSize */
cfg[0].frames = usb_max_isoc_frames(dev);
- cfg[0].flags = (USBD_USE_DMA|USBD_SHORT_XFER_OK);
+ cfg[0].flags.proxy_buffer = 1;
+ cfg[0].flags.short_xfer_ok = 1;
bcopy(cfg + 0, cfg + 1, sizeof(*cfg));
@@ -802,16 +802,6 @@
bufsize = (1 << 22);
}
- /* we need enough room for the control header */
- if (bufsize < sizeof(usb_device_request_t)) {
- bufsize = sizeof(usb_device_request_t);
- }
-
- if (bufsize < mfs) {
- /* we need to be able to hold at least one frame! */
- bufsize = mfs;
- }
-
/* Allocate and setup one generic FreeBSD USB transfer */
cfg[0].type = type;
@@ -819,7 +809,8 @@
cfg[0].direction = addr & (UE_DIR_OUT|UE_DIR_IN);
cfg[0].callback = &usb_linux_non_isoc_callback;
cfg[0].bufsize = bufsize;
- cfg[0].flags = (USBD_USE_DMA|USBD_SHORT_XFER_OK);
+ cfg[0].flags.proxy_buffer = 1;
+ cfg[0].flags.short_xfer_ok = 1;
if (usbd_transfer_setup(dev->bsd_udev, uhe->bsd_iface_index,
uhe->bsd_xfer, cfg, 1, uhe,
@@ -1359,7 +1350,7 @@
urb->actual_length = xfer->actlen;
/* check for short transfer */
- if (xfer->actlen < xfer->length) {
+ if (xfer->actlen < xfer->sumlen) {
/* short transfer */
if (urb->transfer_flags & URB_SHORT_NOT_OK) {
urb->status = -EPIPE; /* XXX should be EREMOTEIO */
@@ -1431,10 +1422,9 @@
}
xfer->priv_fifo = urb;
- xfer->flags &= ~USBD_FORCE_SHORT_XFER;
+ xfer->flags.force_short_xfer = 0;
xfer->timeout = urb->timeout;
xfer->nframes = urb->number_of_packets;
- xfer->length = offset; /* not really used */
usbd_start_hardware(xfer);
return;
}
@@ -1448,10 +1438,13 @@
static void
usb_linux_non_isoc_callback(struct usbd_xfer *xfer)
{
+ enum {
+ REQ_SIZE = sizeof(usb_device_request_t)
+ };
struct urb *urb = xfer->priv_fifo;
struct usb_host_endpoint *uhe = xfer->priv_sc;
- uint32_t max_bulk = (uhe->fbsd_buf_size -
- (uhe->fbsd_buf_size % xfer->max_packet_size));
+ uint32_t max_bulk = xfer->max_data_length;
+ uint8_t data_frame = xfer->flags_int.control_xfr ? 1 : 0;
USBD_CHECK_STATUS(xfer);
@@ -1476,18 +1469,31 @@
tr_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;
+ }
+
if (urb->bsd_isread) {
/* copy in data with regard to the URB */
- usbd_copy_out(&(xfer->buf_data), 0,
- urb->bsd_data_ptr, xfer->actlen);
+ usbd_copy_out(xfer->frbuffers + data_frame, 0,
+ urb->bsd_data_ptr, xfer->frlengths[data_frame]);
}
- urb->bsd_length_rem -= xfer->actlen;
- urb->bsd_data_ptr += xfer->actlen;
- urb->actual_length += xfer->actlen;
+ urb->bsd_length_rem -= xfer->frlengths[data_frame];
+ urb->bsd_data_ptr += xfer->frlengths[data_frame];
+ urb->actual_length += xfer->frlengths[data_frame];
- /* check for short packet */
- if (xfer->actlen < xfer->length) {
+ /* check for short transfer */
+ if (xfer->actlen < xfer->sumlen) {
urb->bsd_length_rem = 0;
/* short transfer */
@@ -1499,7 +1505,7 @@
} else {
/* check remainder */
- if (urb->bsd_length_rem) {
+ if (urb->bsd_length_rem > 0) {
goto setup_bulk;
}
@@ -1507,12 +1513,6 @@
urb->status = 0;
}
- /* check actual length */
- if (urb->actual_length > urb->transfer_buffer_length) {
- /* premature end of a control transfer */
- urb->actual_length = 0;
- }
-
/* call callback */
usb_linux_complete(xfer);
@@ -1529,49 +1529,58 @@
urb->bsd_urb_list.tqe_prev = NULL;
xfer->priv_fifo = urb;
- xfer->flags &= ~USBD_FORCE_SHORT_XFER;
+ xfer->flags.force_short_xfer = 0;
xfer->timeout = urb->timeout;
- if ((uhe->desc.bmAttributes & UE_XFERTYPE) == UE_CONTROL) {
- /* transfer the control header first and then the data,
- * if any, to a control endpoint:
+ if (xfer->flags_int.control_xfr) {
+
+ /*
+ * USB control transfers need special handling.
+ * First copy in the header, then copy in data!
*/
- usbd_copy_in(&(xfer->buf_data), 0,
- urb->setup_packet, sizeof(usb_device_request_t));
- xfer->length = sizeof(usb_device_request_t);
+ usbd_copy_in(xfer->frbuffers + 0, 0,
+ urb->setup_packet, REQ_SIZE);
+
+ xfer->frlengths[0] = REQ_SIZE;
+
+ /* setup data transfer direction */
- urb->bsd_length_rem = xfer->length + urb->transfer_buffer_length;
- urb->bsd_data_ptr = ((uint8_t *)(urb->transfer_buffer)) - xfer->length;
- urb->actual_length = -xfer->length;
urb->bsd_isread = (((uint8_t *)(urb->setup_packet))[0] & UT_READ) ? 1 : 0;
- usbd_start_hardware(xfer);
- return;
+ } 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_data_ptr = urb->transfer_buffer;
urb->actual_length = 0;
- urb->bsd_isread = (uhe->desc.bEndpointAddress & UE_DIR_IN) ? 1 : 0;
setup_bulk:
if (max_bulk > urb->bsd_length_rem) {
max_bulk = urb->bsd_length_rem;
}
- if (max_bulk == urb->bsd_length_rem) {
- if (urb->transfer_flags & URB_ZERO_PACKET) {
- xfer->flags |= USBD_FORCE_SHORT_XFER;
- }
+ /* check if we need to force a short transfer */
+
+ if ((max_bulk == urb->bsd_length_rem) &&
+ (urb->transfer_flags & URB_ZERO_PACKET) &&
+ (!xfer->flags_int.control_xfr)) {
+ xfer->flags.force_short_xfer = 1;
}
+ /* check if we need to copy in data */
+
if (!(urb->bsd_isread)) {
/* copy out data with regard to the URB */
- usbd_copy_in(&(xfer->buf_data), 0,
+ usbd_copy_in(xfer->frbuffers + data_frame, 0,
urb->bsd_data_ptr, max_bulk);
}
- xfer->length = max_bulk;
+ xfer->frlengths[data_frame] = max_bulk;
+ xfer->nframes = data_frame + 1;
usbd_start_hardware(xfer);
return;
}
More information about the p4-projects
mailing list