USB: how transmit more than wMaxPacketSize of bulk data in one submission ? - Linux

This is a discussion on USB: how transmit more than wMaxPacketSize of bulk data in one submission ? - Linux ; Hi fellows, I'm confused about the different size aspects, when setting up a USB transmission. Here's a brief example of what I want: bulk_size is 512 bytes (USB 2.0) (endpoint->wMaxPacketSize) data size is 1000 bytes From LDD I learnt, that ...

+ Reply to Thread
Results 1 to 14 of 14

Thread: USB: how transmit more than wMaxPacketSize of bulk data in one submission ?

  1. USB: how transmit more than wMaxPacketSize of bulk data in one submission ?

    Hi fellows,

    I'm confused about the different size aspects, when setting up a USB
    transmission. Here's a brief example of what I want:

    bulk_size is 512 bytes (USB 2.0) (endpoint->wMaxPacketSize)
    data size is 1000 bytes

    From LDD I learnt, that it should be possible to set up the URB so that all
    data are delivered in one bunch and the core parts between the submission
    and the completion callback do the division and transmissions in adequate
    blocks.
    So I want to hand over to the URB a buffer containing the 1000 bytes,
    and receive an alertion (completion callback handler), when all 1000 bytes
    are out.

    To transmit 512 bytes, I would do this:
    -------------------------
    urb = usb_alloc_urb(0,GFP_KERNEL);
    buf = usb_buffer_alloc (udev, bulk_size, GFP_KERNEL, &urb->transfer_dma);
    memcpy(buf,data,bulk_size);
    usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(..), buf, bulk_size,
    callback,dev);
    urb->transfer_buffer_length = bulk_size;
    usb_submit_urb(urb, GFP_KERNEL);

    and then, in callback handler (or at least after that):
    usb_buffer_free(udev, bulk_size, buf, urb->transfer_dma);
    usb_free_urb(urb);
    ------------------------------
    Please check the '?'s. What must be filled in? Are my guesses ok?
    urb = usb_alloc_urb(0,GFP_KERNEL);
    buf = usb_buffer_alloc (udev, ?data_size?, GFP_KERNEL, &urb->transfer_dma);
    memcpy(buf,data,?data_size?);
    usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(..), buf, ?data_size?,
    callback,dev);
    urb->transfer_buffer_length = ?bulk_size?;
    usb_submit_urb(urb, GFP_KERNEL);

    and then, in callback handler (or at least after that):
    usb_buffer_free(udev, ?data_size?, buf, urb->transfer_dma);
    usb_free_urb(urb);
    ------------------------------
    What happens after submission?
    First packet goes out. And then?
    Is the second packet (with the rest of the data) automatically set up and
    submitted internally, before the callback handler is launched?
    Or is any further action required from my side?

    I'd appreciate, if anybody could shed some light onto this.
    Bernhard


  2. Re: USB: how transmit more than wMaxPacketSize of bulk data in one submission ?

    Bernhard Holzmayer writes:
    > I'm confused about the different size aspects, when setting up a USB
    > transmission. Here's a brief example of what I want:
    >
    > bulk_size is 512 bytes (USB 2.0) (endpoint->wMaxPacketSize)
    > data size is 1000 bytes
    >
    > From LDD I learnt, that it should be possible to set up the URB so that all
    > data are delivered in one bunch and the core parts between the submission
    > and the completion callback do the division and transmissions in adequate
    > blocks.


    Actually, the hardware (ie the host controller) is supposed to frame
    user data into USB bulk packets.

    [...]

    > Please check the '?'s. What must be filled in? Are my guesses ok?
    > urb = usb_alloc_urb(0,GFP_KERNEL);
    > buf = usb_buffer_alloc (udev, ?data_size?, GFP_KERNEL, &urb->transfer_dma);
    > memcpy(buf,data,?data_size?);
    > usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(..), buf, ?data_size?,
    > callback,dev);
    > urb->transfer_buffer_length = ?bulk_size?;


    This will result in requesting a transfer of 512 octets.

    > What happens after submission?


    The USB spec will tell you this in sufficient detail.

    > First packet goes out. And then?


    If there is is data left in the URB, insofar the host controller knows
    this (which it doesn't, because you lied to him about your intentions),
    the next packet will go out.

  3. Re: USB: how transmit more than wMaxPacketSize of bulk data in one submission ?

    On Wed, 11 Oct 2006 09:05:38 +0200, Bernhard Holzmayer
    wrote:

    >Hi fellows,
    >
    >I'm confused about the different size aspects, when setting up a USB
    >transmission. Here's a brief example of what I want:
    >
    >bulk_size is 512 bytes (USB 2.0) (endpoint->wMaxPacketSize)
    >data size is 1000 bytes
    >
    >From LDD I learnt, that it should be possible to set up the URB so that all
    >data are delivered in one bunch and the core parts between the submission
    >and the completion callback do the division and transmissions in adequate
    >blocks.
    >So I want to hand over to the URB a buffer containing the 1000 bytes,
    >and receive an alertion (completion callback handler), when all 1000 bytes
    >are out.
    >
    >To transmit 512 bytes, I would do this:
    > -------------------------
    >urb = usb_alloc_urb(0,GFP_KERNEL);
    >buf = usb_buffer_alloc (udev, bulk_size, GFP_KERNEL, &urb->transfer_dma);
    >memcpy(buf,data,bulk_size);
    >usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(..), buf, bulk_size,
    >callback,dev);
    >urb->transfer_buffer_length = bulk_size;
    >usb_submit_urb(urb, GFP_KERNEL);
    >
    >and then, in callback handler (or at least after that):
    >usb_buffer_free(udev, bulk_size, buf, urb->transfer_dma);
    >usb_free_urb(urb);
    > ------------------------------
    >Please check the '?'s. What must be filled in? Are my guesses ok?
    >urb = usb_alloc_urb(0,GFP_KERNEL);
    >buf = usb_buffer_alloc (udev, ?data_size?, GFP_KERNEL, &urb->transfer_dma);
    >memcpy(buf,data,?data_size?);
    >usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(..), buf, ?data_size?,
    >callback,dev);
    >urb->transfer_buffer_length = ?bulk_size?;
    >usb_submit_urb(urb, GFP_KERNEL);
    >
    >and then, in callback handler (or at least after that):
    >usb_buffer_free(udev, ?data_size?, buf, urb->transfer_dma);
    >usb_free_urb(urb);
    > ------------------------------
    >What happens after submission?
    >First packet goes out. And then?
    >Is the second packet (with the rest of the data) automatically set up and
    >submitted internally, before the callback handler is launched?
    >Or is any further action required from my side?
    >


    So you are writing a driver, right? My advice is don't. There are good
    userspace tools with none of the agonies of Kernel debugging and
    oopses etc.

    Ok, you really want to do a driver. I hope it is not premature
    optimization, but you really really want to do a driver. In that case
    read LDD3 a couple more times. Try to find an existing kernel driver
    doing something similar to what you want to do, start with that.

    Urbs have a simple rule - one submission one callback. The USB core
    splits the data into as many packets are required. When they are all
    done you get one callback. Checking error statuses are critical in a
    USB driver.

    Luck, Steve

    There is no "x" in my email address.

  4. Re: USB: how transmit more than wMaxPacketSize of bulk data in one submission ?

    Rainer Weikusat wrote:

    > Bernhard Holzmayer writes:
    >> I'm confused about the different size aspects, when setting up a USB
    >> transmission. Here's a brief example of what I want:
    >>
    >> bulk_size is 512 bytes (USB 2.0) (endpoint->wMaxPacketSize)
    >> data size is 1000 bytes
    >>
    >> From LDD I learnt, that it should be possible to set up the URB so that
    >> all data are delivered in one bunch and the core parts between the
    >> submission and the completion callback do the division and transmissions
    >> in adequate blocks.

    >
    > Actually, the hardware (ie the host controller) is supposed to frame
    > user data into USB bulk packets.
    >
    > [...]
    >
    >> Please check the '?'s. What must be filled in? Are my guesses ok?
    >> urb = usb_alloc_urb(0,GFP_KERNEL);
    >> buf = usb_buffer_alloc (udev, ?data_size?, GFP_KERNEL,
    >> &urb->transfer_dma); memcpy(buf,data,?data_size?);
    >> usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(..), buf, ?data_size?,
    >> callback,dev);
    >> urb->transfer_buffer_length = ?bulk_size?;

    >
    > This will result in requesting a transfer of 512 octets.

    Though I filled urb with data_size ?
    >
    >> What happens after submission?

    >
    > The USB spec will tell you this in sufficient detail.

    Depends. My question aimed at the treatment of the URB.
    >
    >> First packet goes out. And then?

    >
    > If there is is data left in the URB, insofar the host controller knows
    > this (which it doesn't, because you lied to him about your intentions),
    > the next packet will go out.

    So what's the solution to tell it the truth?
    urb->transfer_buffer_length = data_size ??

    You see my problem?
    I agree, that it's up to the host-controller to fragment my data.
    But do I have to tell it the packet size for the fragments?
    Sounds silly, but it's not obvious (to me), if data_size>bulk_size

    Bernhard



  5. Re: USB: how transmit more than wMaxPacketSize of bulk data in one submission ?

    Steve Calfee wrote:

    >
    > So you are writing a driver, right? My advice is don't. There are good
    > userspace tools with none of the agonies of Kernel debugging and
    > oopses etc.

    I agree. Did userspace drivers before (libusb) - but isn't acceptable
    here...
    >
    > Ok, you really want to do a driver.

    No: not want - just have to! Self-made hardware needs this driver.
    > I hope it is not premature
    > optimization, but you really really want to do a driver. In that case
    > read LDD3 a couple more times. Try to find an existing kernel driver
    > doing something similar to what you want to do, start with that.

    Good advice. Doing so most of my time... :-)
    >
    > Urbs have a simple rule - one submission one callback.

    All right - I expected this - and seems correct.

    > The USB core
    > splits the data into as many packets are required. When they are all
    > done you get one callback.

    That's my point: since I increased the size of the urb buffer, I don't
    receive a callback anymore. That's why I wanted to make sure that I got
    everything right before taking into account the other end of USB.

    > Checking error statuses are critical in a USB driver.

    I experience this piece of wisdom for some time now ...
    >
    > Luck, Steve
    >




  6. Re: USB: how transmit more than wMaxPacketSize of bulk data in one submission ?

    Bernhard Holzmayer writes:

    [...]

    >>> What happens after submission?

    >>
    >> The USB spec will tell you this in sufficient detail.

    > Depends. My question aimed at the treatment of the URB.


    You have basically two options:

    - read the spec and the source to determine the answer
    yourself

    - just accept reality as it is

    Which, in this case, means that that the transfer_buffer_length is the
    length of the buffer you wish to transfer and that fragmentation,
    insofar needed, is handled by the host controller, and fragmentation,
    insofar introduced by the HCD implementation 'for some reason', is
    handled by the HCD (host controller driver).

  7. Re: USB: how transmit more than wMaxPacketSize of bulk data in one submission ?

    Steve Calfee writes:

    [...]

    > Urbs have a simple rule - one submission one callback. The USB core
    > splits the data into as many packets are required.


    Strictly speaking, this is not true. The 'USB core' splits the data
    into as many 'transfer descriptors' as it desires (exception: UHCI)
    and the host controller handles fragmentation imposed by the USB
    itself.

  8. Re: USB: how transmit more than wMaxPacketSize of bulk data in one submission ?

    On Wed, 11 Oct 2006 09:05:38 +0200, Bernhard Holzmayer
    wrote:

    >Hi fellows,
    >
    >I'm confused about the different size aspects, when setting up a USB
    >transmission. Here's a brief example of what I want:
    >
    >bulk_size is 512 bytes (USB 2.0) (endpoint->wMaxPacketSize)
    >data size is 1000 bytes
    >
    >From LDD I learnt, that it should be possible to set up the URB so that all
    >data are delivered in one bunch and the core parts between the submission
    >and the completion callback do the division and transmissions in adequate
    >blocks.
    >So I want to hand over to the URB a buffer containing the 1000 bytes,
    >and receive an alertion (completion callback handler), when all 1000 bytes
    >are out.
    >
    >To transmit 512 bytes, I would do this:
    > -------------------------
    >urb = usb_alloc_urb(0,GFP_KERNEL);
    >buf = usb_buffer_alloc (udev, bulk_size, GFP_KERNEL, &urb->transfer_dma);
    >memcpy(buf,data,bulk_size);
    >usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(..), buf, bulk_size,
    >callback,dev);
    >urb->transfer_buffer_length = bulk_size;
    >usb_submit_urb(urb, GFP_KERNEL);
    >
    >and then, in callback handler (or at least after that):
    >usb_buffer_free(udev, bulk_size, buf, urb->transfer_dma);
    >usb_free_urb(urb);
    > ------------------------------
    >Please check the '?'s. What must be filled in? Are my guesses ok?
    >urb = usb_alloc_urb(0,GFP_KERNEL);
    >buf = usb_buffer_alloc (udev, ?data_size?, GFP_KERNEL, &urb->transfer_dma);
    >memcpy(buf,data,?data_size?);
    >usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(..), buf, ?data_size?,
    >callback,dev);
    >urb->transfer_buffer_length = ?bulk_size?;
    >usb_submit_urb(urb, GFP_KERNEL);
    >
    >and then, in callback handler (or at least after that):
    >usb_buffer_free(udev, ?data_size?, buf, urb->transfer_dma);
    >usb_free_urb(urb);
    > ------------------------------
    >What happens after submission?
    >First packet goes out. And then?
    >Is the second packet (with the rest of the data) automatically set up and
    >submitted internally, before the callback handler is launched?
    >Or is any further action required from my side?
    >


    So you are writing a driver, right? My advice is don't. There are good
    userspace tools with none of the agonies of Kernel debugging and
    oopses etc.

    Ok, you really want to do a driver. I hope it is not premature
    optimization, but you really really want to do a driver. In that case
    read LDD3 a couple more times. Try to find an existing kernel driver
    doing something similar to what you want to do, start with that.

    Urbs have a simple rule - one submission one callback. The USB core
    splits the data into as many packets are required. When they are all
    done you get one callback. Checking error statuses are critical in a
    USB driver.

    Luck, Steve

    There is no "x" in my email address.

  9. Re: USB: how transmit more than wMaxPacketSize of bulk data in one submission ?

    On Wed, 11 Oct 2006 09:05:38 +0200, Bernhard Holzmayer
    wrote:

    >Hi fellows,
    >
    >I'm confused about the different size aspects, when setting up a USB
    >transmission. Here's a brief example of what I want:
    >
    >bulk_size is 512 bytes (USB 2.0) (endpoint->wMaxPacketSize)
    >data size is 1000 bytes
    >
    >From LDD I learnt, that it should be possible to set up the URB so that all
    >data are delivered in one bunch and the core parts between the submission
    >and the completion callback do the division and transmissions in adequate
    >blocks.
    >So I want to hand over to the URB a buffer containing the 1000 bytes,
    >and receive an alertion (completion callback handler), when all 1000 bytes
    >are out.
    >
    >To transmit 512 bytes, I would do this:
    > -------------------------
    >urb = usb_alloc_urb(0,GFP_KERNEL);
    >buf = usb_buffer_alloc (udev, bulk_size, GFP_KERNEL, &urb->transfer_dma);
    >memcpy(buf,data,bulk_size);
    >usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(..), buf, bulk_size,
    >callback,dev);
    >urb->transfer_buffer_length = bulk_size;
    >usb_submit_urb(urb, GFP_KERNEL);
    >
    >and then, in callback handler (or at least after that):
    >usb_buffer_free(udev, bulk_size, buf, urb->transfer_dma);
    >usb_free_urb(urb);
    > ------------------------------
    >Please check the '?'s. What must be filled in? Are my guesses ok?
    >urb = usb_alloc_urb(0,GFP_KERNEL);
    >buf = usb_buffer_alloc (udev, ?data_size?, GFP_KERNEL, &urb->transfer_dma);
    >memcpy(buf,data,?data_size?);
    >usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(..), buf, ?data_size?,
    >callback,dev);
    >urb->transfer_buffer_length = ?bulk_size?;
    >usb_submit_urb(urb, GFP_KERNEL);
    >
    >and then, in callback handler (or at least after that):
    >usb_buffer_free(udev, ?data_size?, buf, urb->transfer_dma);
    >usb_free_urb(urb);
    > ------------------------------
    >What happens after submission?
    >First packet goes out. And then?
    >Is the second packet (with the rest of the data) automatically set up and
    >submitted internally, before the callback handler is launched?
    >Or is any further action required from my side?
    >


    So you are writing a driver, right? My advice is don't. There are good
    userspace tools with none of the agonies of Kernel debugging and
    oopses etc.

    Ok, you really want to do a driver. I hope it is not premature
    optimization, but you really really want to do a driver. In that case
    read LDD3 a couple more times. Try to find an existing kernel driver
    doing something similar to what you want to do, start with that.

    Urbs have a simple rule - one submission one callback. The USB core
    splits the data into as many packets are required. When they are all
    done you get one callback. Checking error statuses are critical in a
    USB driver.

    Luck, Steve

    There is no "x" in my email address.

  10. Re: USB: how transmit more than wMaxPacketSize of bulk data in one submission ?

    Bernhard Holzmayer wrote:

    >
    > I'm confused about the different size aspects...


    Thank you, fellows, for your response.
    Gave me some additional insight, but could not really help me,
    because my problem was not that of fragmentation etc.

    Instead, I had a silly pointer issue:
    positioning to the end with ptr=ptr+sizeof(*ptr) failed,
    since ptr was of a struct type,
    and I just forgot to cast it like in
    ptr=(type) ((void*)ptr+sizeof(*ptr))
    Caused confusion on USB receiver - and missing callback.

    After that modification, my transmissions work pretty well again,
    independent of their length.

    Silly enough. My confusion came, since I didn't receive the callback
    anymore ...

    Bernhard

  11. Re: USB: how transmit more than wMaxPacketSize of bulk data in one submission ?

    Bernhard Holzmayer writes:

    [...]

    > Instead, I had a silly pointer issue:
    > positioning to the end with ptr=ptr+sizeof(*ptr) failed,
    > since ptr was of a struct type,
    > and I just forgot to cast it like in
    > ptr=(type) ((void*)ptr+sizeof(*ptr))


    According to C, this construct has undefined behaviour (it is a "gcc
    extension") and the correct way would be to use a char * instead.
    But this is pointless, because

    (char *)p + sizeof(*p) == p + 1

    JFTR.

  12. Re: USB: how transmit more than wMaxPacketSize of bulk data in onesubmission ?

    Bernhard Holzmayer wrote:
    > Bernhard Holzmayer wrote:
    >
    >
    >>I'm confused about the different size aspects...

    >
    >
    > Thank you, fellows, for your response.
    > Gave me some additional insight, but could not really help me,
    > because my problem was not that of fragmentation etc.
    >
    > Instead, I had a silly pointer issue:
    > positioning to the end with ptr=ptr+sizeof(*ptr) failed,
    > since ptr was of a struct type,
    > and I just forgot to cast it like in
    > ptr=(type) ((void*)ptr+sizeof(*ptr))
    > Caused confusion on USB receiver - and missing callback.


    What's wrong with a simple 'p++' instead?

    (Please remember that pointer arithmetic is done
    in units of the pointer's target type size).

    --

    Tauno Voipio
    tauno voipio (at) iki fi

  13. Re: USB: how transmit more than wMaxPacketSize of bulk data in one submission ?

    Tauno Voipio writes:
    > Bernhard Holzmayer wrote:
    >> Bernhard Holzmayer wrote:
    >>
    >>>I'm confused about the different size aspects...

    >> Thank you, fellows, for your response.
    >> Gave me some additional insight, but could not really help me,
    >> because my problem was not that of fragmentation etc.
    >> Instead, I had a silly pointer issue: positioning to the end with
    >> ptr=ptr+sizeof(*ptr) failed, since ptr was of a struct type,
    >> and I just forgot to cast it like in
    >> ptr=(type) ((void*)ptr+sizeof(*ptr))
    >> Caused confusion on USB receiver - and missing callback.

    >
    > What's wrong with a simple 'p++' instead?
    >
    > (Please remember that pointer arithmetic is done
    > in units of the pointer's target type size).



    Probably the same that is wrong with letting the hardware
    care about the framing: too simple.


  14. Re: USB: how transmit more than wMaxPacketSize of bulk data in one submission ?

    Sorry, I'm in delay ... but I'll respond just to point a few issues out.

    Rainer Weikusat wrote:

    > Tauno Voipio writes:
    >> Bernhard Holzmayer wrote:
    >>> Bernhard Holzmayer wrote:
    >>>
    >>>>I'm confused about the different size aspects...

    I told you that I've been confused.
    Confusion means that there is a piece of truth in what I can see, but
    there's a fog or cloud which hides it so much that I'm not sure if I'm on
    the right track. This is why I asked for some orientation...

    >>> Thank you, fellows, for your response.
    >>> Gave me some additional insight, but could not really help me,
    >>> because my problem was not that of fragmentation etc.
    >>> Instead, I had a silly pointer issue

    If I had known this before, I wouldn't have asked different questions.

    >>> : positioning to the end with ptr=ptr+sizeof(*ptr) failed,
    >>> since ptr was of a struct type,
    >>> and I just forgot to cast it like in
    >>> ptr=(type) ((void*)ptr+sizeof(*ptr))

    It was not so obvious, because
    a) the pointers deal with opaque types in reality (container lists etc.) and
    the offset has to be calculated at runtime.
    b) the existing code had been successfully tested under different
    circumstances. I didn't expect the adaptation to cause trouble here.
    c) the strange thing was that the device on the other end didn't respond
    properly, so at a certain point the transfer broke. This caused me to look
    into the wrong direction...

    >>> Caused confusion on USB receiver - and missing callback.

    >>
    >> What's wrong with a simple 'p++' instead?

    Nothing. Indeed I'd prefer that, but it may fail or at least become
    unreadable if you have to deal with
    >>
    >> (Please remember that pointer arithmetic is done
    >> in units of the pointer's target type size).

    >
    >
    > Probably the same that is wrong with letting the hardware
    > care about the framing: too simple.
    >

    You may be right. If not the example code had contained a buffer length
    equal to the endpoint's packet size, I'd not have thought about it.
    If not my pointer arithmetic algorithm had been too complex, I'd have seen
    the obvious '+1' issue,
    and so on...

    It has been my experience, that other people tend to see such mistakes
    easier than the developer. That's why I posted here.
    I was quite sure that other USB programmer's would not think so awkward as I
    did.

    Your hints gave me enough reason to trust that piece of URB-procession so
    much, that I started to investigate further around until I found the
    pointer bug. That's what I love about these newsgroups.

    Bernhard



+ Reply to Thread