On Wed, Sep 19, 2001 at 03:42:18PM -0700, jt wrote:
>
> I did a quick read in the source to see if I could implement
> ZERO_PACKET. Well, let's just say that it's not as simple as I
> tought. TD are done multiple of 4096, which doesn't fit with the code
> I see in usb-uhci which have TD multiple of 64 (so you just need to
> add an empty TD at the end). There must be some black magic there.
Well, I'm totally stupid, the TD size doesn't matter. Just add
a TD at the end and don't worry, be happy.
Patch attached. I don't know if the OHCI interface provide
other way to do that more efficiently, but it works. Tested with my
usual array of benchamrks and it's solid.
Enjoy...
Jean
P.S. : Currently the irda-usb driver in the kernel can work only with
usb-uhci, so if this patch could go in the kernel...
diff -u -p linux/drivers/usb/usb-ohci.u1.c linux/drivers/usb/usb-ohci.c
--- linux/drivers/usb/usb-ohci.u1.c Wed Sep 19 15:10:01 2001
+++ linux/drivers/usb/usb-ohci.c Wed Sep 19 16:05:14 2001
@@ -12,6 +12,7 @@
*
* History:
*
+ * 2001/09/19 USB_ZERO_PACKET support (Jean Tourrilhes)
* 2001/07/17 power management and pmac cleanup (Benjamin Herrenschmidt)
* 2001/03/24 td/ed hashing to remove bus_to_virt (Steve Longerbeam);
pci_map_single (db)
@@ -537,6 +538,7 @@ static int sohci_submit_urb (urb_t * urb
ed_t * ed;
urb_priv_t * urb_priv;
unsigned int pipe = urb->pipe;
+ int pipe_mtu = usb_maxpacket (urb->dev, pipe, usb_pipeout (pipe));
int i, size = 0;
unsigned long flags;
int bustime = 0;
@@ -579,6 +581,13 @@ static int sohci_submit_urb (urb_t * urb
switch (usb_pipetype (pipe)) {
case PIPE_BULK: /* one TD for every 4096 Byte */
size = (urb->transfer_buffer_length - 1) / 4096 + 1;
+
+ /* If the transfer size is multiple of the pipe mtu,
+ * we may need an extra TD to create a empty frame
+ * Jean II */
+ if((urb->transfer_flags & USB_ZERO_PACKET) &&
+ ((urb->transfer_buffer_length % pipe_mtu) == 0))
+ size++;
break;
case PIPE_ISOCHRONOUS: /* number of packets from URB */
size = urb->number_of_packets;
@@ -1338,6 +1347,8 @@ static void td_submit_urb (urb_t * urb)
ohci_t * ohci = (ohci_t *) urb->dev->bus->hcpriv;
dma_addr_t data;
int data_len = urb->transfer_buffer_length;
+ unsigned int pipe = urb->pipe;
+ int pipe_mtu = usb_maxpacket (urb->dev, pipe, usb_pipeout (pipe));
int cnt = 0;
__u32 info = 0;
unsigned int toggle = 0;
@@ -1374,6 +1385,17 @@ static void td_submit_urb (urb_t * urb)
TD_CC | TD_DP_OUT : TD_CC | TD_R | TD_DP_IN ;
td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), data,
data_len, urb, cnt);
cnt++;
+
+ /* If the transfer size is multiple of the pipe mtu,
+ * we may need an extra TD to create a empty frame
+ * Note : another way to check this condition is
+ * to test if(urb_priv->length > cnt) - Jean II */
+ if((urb->transfer_flags & USB_ZERO_PACKET) &&
+ ((urb->transfer_buffer_length % pipe_mtu) == 0)) {
+ td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), data
++ data_len, 0, urb, cnt);
+ cnt++;
+ }
+
if (!ohci->sleeping)
writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start
bulk list */
break;