Table of Contents
Drivers manipulate data within the USB system using a simple data buffer structure known as a USB Request Buffer(URB). URBs are used in much the same way as MBufs are used in the RISC OS networking system.
URBs are allocated by the USB system from a central memory pool which can be accessed in all contexts within RISC OS (I.E. RMA or Dynamic area). URBs may also use storage provided by the driver which must also be in memory available from all contexts.
URBs are managed by the USB core. Drivers can use the API to obtain and release a URB.
A URB is allocated by calling usb_buffer_malloc(USBLib_AllocURB (SWI &56340)) with a pipe reference and the required data size. The returned URB may only be used for one outstanding transaction at a time.
The driver is responsible for freeing any allocated URBs once finished with. Any URBs which are not freed will not be released and the memory they occupy will be lost until the USB system is completely restarted. Freeing URBs is accomplished by calling usb_buffer_free(USBLib_FreeURB (SWI &56340)).
A URB is passed to a transaction either as the source or destination for transfered data depending on the pipe direction and type of transaction requested.
A URB may only be used by one outstanding transaction at a time. However, a URB may be reused in another transaction once any outstanding transaction is completed. Hence, a URB may be claimed once at the beginning of a series of transactions and freed once they are all complete.
A driver may vary the amount of data transfered, in each transaction of a series, by changing the used size field to indicate the amount of data to receive or transmit before starting the next transaction.
The used size field indicates the number of bytes to transfer in transactions from host to device transfers. Used size is used to limit the amount of data to be transfered from a device to host, note that the transaction may complete having transfered fewer bytes than this value and the actual_position field should be used to find the actual number of bytes transfered.
See Chapter 8 for more details on transactions and their interaction with URBs.
Example 6.1. Use of URBs with a control transaction
This example shows
The allocation of two URBs
Data manipulation in a URB (zeroing space for reception of data)
URB use with a control transaction
URB freeing
Please note this example performs no error checking, real code would of course need to check the return and error codes from each call.
int result; extern waiting* msgwait; usb_io_buffer* msgbuf; usb_io_buffer* databuf; /* allocate a URB for a control message */ msgbuf = usb_buffer_malloc(control_pipe,/* pipe reference */ USB_STRUCT_SETUP_BUFFER_SIZE,/* buffer length */ 0,/* no external storage */ &result); /* result pointer */ /* allocate a 64byte data URB */ databuf = usb_buffer_malloc(control_pipe, 64, 0, &result); /* clear data buffer within URB */ memset(databuf->pointer_to_data, 0, len); databuf->size = len; /* code would change URB data buffer if data was to be transfered from host to device*/ /* sends a control messgage */ msgwait = usblib_ctrl_msg(control_pipe, databuf, msgbuf, &wait, requtype, req, val, index); /* code would examine URB data buffer if data was transfered from device to host */ /* free URB */ usb_buffer_free(databuf); usb_buffer_free(msgbuf); |
A URB contains four main fields which the driver can manipulate and read when performing transactions. The structure does contain additional fields for use by the USB system these are detailed in the host controller writing book.
Direct manipulation of the fields when not using the C api is discouraged, instead two library calls have been provided, one to examine the URB fields (USBLib_URBInfo (SWI &56340)) and one to set the URB fields (USBLib_SetURB (SWI &56340))
The four fields of interest are shown in the (incomplete) structure definition below (the definition drivers should use is in Section 4.12). The offsets and specific values can be found in Table A.10.
struct usb_io_buffer_s { void *pointer_to_data; unsigned long size; unsigned long used_size; unsigned long actual_position; }; |
pointer_to_data is the pointer to the actual allocated storage the URB refers to. |
size is the size of the allocated storage and hence the maximum amount of data that can be held in a URB. |
used_size is the amount of data to transfer in a transaction. I.e. the amount of data to transfer from host to device or the maximum amount of data to transfer device to host. |
actual_position is the amount of data actually transfered in a transaction. I.e. the amount of data in the buffer that was actually transfered from the device to the host which may be less than the used_size value set if the device doesn't transfer the full amount of data requested. |