1.5. Other functions

There are the following other functions:

Data Structures

USB-Module will try to store its dynamic data structures inside a dynamic area called "USB". This dynamic area can be used by other USB related programs like USB Host controller drivers and USB device drivers too. If a dynamic area is not available USB-Module will claim its data space from RMA.

USB dynamic area is handled in such a way that an application which wants to use the area must first enumerate all dynamic areas and looking for one called "USB". If this can be found the application can use it directly else it must establish the area. The dynamic area itself is a piece of public address space. Its maximal size is determined by the value of the environment variable "USB$size_dynamic_area" added by a constant of 1024 bytes for internal handling purposes. The area is only containing a single heap section preceeded by some additional information. Therefore programs must use RISCOS internal heap manipulation functions.

Table 1.8. USB dynamic area

OffsetDescription
0x00Offset from the beginning of the dynamic area to the heap in Bytes (8 in the moment).
0x04Number of applications using this USB dynamic area
0x08RISCOS Heap with maximal size of "USB$size_dynamic_area" bytes.

The first application which has generated the area has to fill the offset and to set the number of using applications to 0. It also must establish the heap. Each application using the area (incl. the first one) has to increase the number of using applications by one during program installation. If an application quits which is using the USB dynamic area it has to reduce the number of using applications by one. If the number becomes zero it may remove the area.

Data Structures of application to USB Module communication

There are two fundamental data structures used at the communications between the programs and the USB module:

Data buffer structure

Because access to data buffers must be done by the programs on the host, the USB-Module and the USB host controller driver (incl. the USB Hardware in some cases) it is stored in memory with public adddress range like RMA or dynamic areas. It must be therefore allocated/released by special functions. Data buffers are generally owned by one program. The control is passed on to other parts of the USB software. Note that these software is only allowed to change the content of the data buffer but it is never allowed to release the buffer. A data buffer must always been passed back to the program which has allocated it.

To allow the usage of existing data structures inside RISCOS like buffers programs can declare a particular piece of memory from the public address space as an USB data buffer. There are two ways to generate such a buffer. You can use the normal functions and passing them the address of the beginning of the memory of the buffer. In this case only the additional information will be allocated from the memory by the USB_BufferMalloc function. Of course it will calculate the total size of the buffer space as a multiple of the data payload size of the related pipe. You must keep care that the buffer you passed to the function is large enough or you must change the size value. In the other case your application can generate a buffer of the format described below completely itself. However take care that the size is always a multiple of the data pay load size of the pipe you want to use. Of course you can change the buffer address inside the USB buffer structure as you like from request to request for eg implenting a device FS.

The waiting information is included into the buffer structure even the programs shall not try to access it directly but shall always use the according functions. This saves an acknowledgement from the program to the USB module that it has evaluated the result of a request.

Buffer reading

The number of bytes in the buffer which are really used should be set to the number of bytes which you are expecting to recieve. An error will be generated if you will recieve less or more bytes and an according flag has been set. If you are not expecting a fixed size so set this value to zero. It will be left unchanged during the whole transfer. So you are able to compare the recieved bytes inside the actual position with the expected size. A zero length buffer can be generated by setting the USB_TRANSACTION_EXACT_SIZE flag at request generating. The actual transfer position will be reset to zero automatically if request is started. At the end of the transfer it will pointing exactly one byte behind the recieved data. After the transfer has been done you can evaluate the data buffer content.

Buffer writing

Fill the data into the buffer and set the number of bytes which are really used with the according size. The actual transfer position will be reset to zero automatically if request is started. Note that this value remains unchanged after the transfer has been done. It is granted that actual transfer position is pointing directly to the beginning of the data which has not been sent if an error occurred. A zero length buffer can be generated by setting the number of bytes which are really used to zero and setting the USB_TRANSACTION_EXACT_SIZE flag at request generating.

Table 1.9. Format of data buffer structure

PositionData typeDescription
0x00unsigned longPointer to begin of buffer data. If data is included in this structure it will point behind the waiting structure else it must point to the piece of memory which is used as data buffer.
0x04unsigned longAllocated data buffer size in Bytes. If the offset is added to this value you are getting the whole size of the buffer structure.
0x08unsigned longNumber of Bytes in the buffer which are really used for data in the moment.
0x0Cunsigned longActual position of data transfer.
0x10unsigned longNumber of the frame in which the transaction has been completed. Must be filled by the USB host controller driver.
0x14unsigned longData toggle as the transaction has been completed. Must be filled by the USB host controller driver.
0x18various. Size may vary from version to versionWaiting structure. Exact structure see below.
... At later version here there may be additional information located.
(0x18 + Size of Waiting Structure) word allocated data of arbitrary size word aligned. Only if data buffer memory is hold inside this buffer. Not used if this memory is located elsewhere.

Waiting mode structure

Programs should only set the size (sizeof(waiting) in C), the waiting mode and additional parameters belonging to this mode. All other operations are done internally the USB-module. Note that a copy of your waiting structure is placed inside one buffer of a request. The setting of the size is needed to grant future compatibility. If an application mallocs a new buffer for USB requests the size of the waiting structure is automatically initialized.

Table 1.10. Format of Waiting structure

PositionData typeDescription
0x00intSize of this structure (actual 0x3C Bytes).
0x04intWaiting Mode
0x08intResult
0x0CintFlag that shows that no result has been recieved. That means that the waiting is still going on.

Table 1.11. additional data for WAITING_TYPE_MESSAGE

PositionData typeDescription
0x10PointerPointer to WIMP message block located in common address space.
0x14intDestination task handle
0x18intIcon handle

Table 1.12. Additional data for WAITING_TYPE_SWI

PositionData typeDescription
0x10intNumber of the SWI to call
0x14-0x3CintAn array of 10 register values passed to the SWI call.

Table 1.13. Additional data for WAITING_TYPE_APCS

PositionData typeDescription
0x10PointerPointer to APCS-Function located in common address space.
0x14-0x24intAn array of 4 register values passed to the APCS function call.

Waiting Constants

Please note that in all modes except WAITING_TYPE_RETURN the calling program is only informed that a request has been finished. It will be not informed whether the operation has been successful. It has to use USB_RequestGetState to get this information.

Table 1.14. Constants used for USB waiting modes

DefinitionValueDescription
WAITING_TYPE_RETURN0Returns immediately. Program must check the state of the request periodically by calling USB_RequestGetState
WAITING_TYPE_LOOP1Loops internally until the request has been finished.
WAITING_TYPE_POLL2Waits until the request has been finished. WIMP is polled so other none interrupt driven tasks can use the CPU. This is only implemented for usage together with task windows.
WAITING_TYPE_MESSAGE3Returns immediately. If request is finished a message using the values inside the waiting structure is sent. This will be done by calling Wimp_SendMessage. A user message without a reply will be generated. Destination task and icon handle will be taken from waiting structure. The message block will be also taken from the location stored inside the waiting parameters. This means that a program will have to fill this block located inside a part of common address space before launching an operation which will make usage of the waiting structure. The program must fill the message block in according with general WIMP restritction to such blocks.
WAITING_TYPE_SWI4Returns immediately. If request is finished the SWI declared inside the waiting structure is launched. This is done by using the C-Function _kernel_swi. The SWI number is taken from the waiting structure. Also registers 0 to 9 are passed to this function. However results of the function call are dropped.
WAITING_TYPE_APCS5Returns immediately. If request is finished a function which has been declared inside the waiting structure is called. The function must be located elsewhere in common address space. It must accord to ARM Procedure Call Standard (APCS). In fact call is done by calling a C-Function of the type int function(int, int, int, int). The 4 parameters are filled from the waiting structure. The result of the function is dropped. At Assembler side registers 0-3 will be filled according APCS.

Data Structures of USB Module to USB host controller driver communication

There are two data structures used by the commnunication between USB Module and USB host controller driver:

There is one structure in which the USB host controller driver tells some properties of its own to the USB Module:

There is one value which is directly under the control of the USB host controller driver inside a structure which is USB Modul internal inside the other cases:

Data buffer structure

The scheme of the Data Buffer structure has been already described above. Pointers to data buffers are passed to an USB host controller driver inside the transactions. Information inside a data buffer tells the USB host controller driver how much bytes must transferred from or to an endpoint and where the data is or can be stored. Please note that a data buffer can be the same as passed from client application to the USB module but it may vary in special cases. It is granted by the USB module that the storage of the buffers passed to an USB host controller driver will be always a multiple of the data pay load size of the according pipe. The sizes of the data to transfer will also fit into these size. That means that the USB host controller driver can directly split up the buffer data into USB packages. the driver must not worry about USB size restrictions (like 0 length packages, even of course it must transmit or recieve such packages). This will be handled inside the USB module.

Transaction structure

Transactions tell the USB host controller driver what transfer of which type must be done with which device and endpoint. Transactions are generated from requests which are generated by the client applications.

A request can consist of several transactions. This is the case at control transactions at which first a special block (Setup) is transmitted before doing the transfer. Think also of the special case where a size of data exactly fits into the transaction size but no data is following so a transfer of zero data length must be transmitted. At receiving data, there is no proper working possibility to recognize such a situation. Transactions of zero length must be passed to client function. Inside transaction data of zero length may be represented by a NULL pointer to the buffer or by a buffer with zero bytes used. USB host controller driver must be prepared to handle both cases.

To link transactions which are belonging logically together there is a pointer to the following transaction. Only the first transaction of such a transaction chain belonging to one request can be detected as pending. The USB host controller driver can obtain them by calling USB_RequestGetPending. The following transaction will blocking any other transactions pending at an endpoint from being queued into the pending list of transactions which the controller can get. Therefore if the USB host controller driver gets such a first transaction he must get all the other transactions belonging to the same request by calling USB_TransactionGetPending. Because an endpoint may be dropped the USB host controller must be prepared that this following transactions are not available anymore. This can be detected if a NULL pointer is returned.

If an error is occurring in one transaction inside USB host controller driver the following transactions of this request must be acknowledged one after the other with the same error message as sent to the first transaction where the error occurred.

A transaction is passed on from stage to stage through the USB-Module and the USB host controller driver. Every stage can place its own information inside it. Therefore it is a flexible but directly allocated structure. This allows a fast unique memory allocation inside the USB Module and passing on a request structure only by pointer. The transactions are allocated from memory with public address range like RMA or dynamic areas.

Table 1.15. Transaction container structure

PositionData typeDescription
0x00unsigned longTotal size of the structure
0x04unsigned longNumber of offsets
0x08Array of unsigned longList of offsets from structure start to the begining of the substructures.
...  

Table 1.16. transaction structure

PositionData typeDescription
Off1 USB-Module general transaction information
Off1 + 0x00PointerPointer to USB host controller structure
Off1 + 0x04PointerPointer to USB device structure
Off1 + 0x08unsigned longNumber of USB device for usage at bus addressing
Off1 + 0x0Cunsigned longDevice speed
Off1 + 0x10PointerPointer to USB endpoint structure.
Off1 + 0x14unsigned longNumber of endpoint for usage at bus addressing including direction information which must be masked out by USB host controller driver.
Off1 + 0x18unsigned longUSB transfer type
Off1 + 0x1Cunsigned longmaximal data size of this pipe
Off1 + 0x20unsigned long

Tranasction code Table 1.17, “USB transaction codes”

Off1 + 0x24PointerPointer to data buffer used for I/O operation (may include waiting information!) or may be zero to represent transaction of zero data length.
Off1 + 0x28PointerPointer to next transaction belonging to the same request or zero if last transaction of a request.
Off1 + 0x2CPointerPointer to waiting structure which must be informed about the result. If there is no such structure pointer must be set to zero. Note that this structure is laying inside a buffer but it is not necessary that it lays inside the buffer which is used at this transaction.
Off1 + 0x30unsigned long

Table 1.18, “Additional transaction information”

Off1 + 0x34unsigned longFrame start number. Transaction must not be processed before the USB frame number has reached this value. Only set at the first transaction of a request.
Off1 + 0x38unsigned longFrame repeat. Needed at interrupt transfer if NAK is recieved to calculate the next retry by an USB Host controller.
Off1 + 0x3Cunsigned intStorage element position inside storage of running transaction list. This allows a fast removal from this list (internal usage only).

Table 1.17. USB transaction codes

DefinitionValueDescription
USB_TRANSACTION_CODE_OUT0x01Host to function transaction
USB_TRANSACTION_CODE_IN0x09Function to host transaction
USB_TRANSACTION_CODE_SETUP0x0DHost to function transaction for SETUP to a control pipe.

Table 1.18. Additional transaction information

BitDefinitionValueDescription
0USB_TRANSACTION_EXACT_SIZE0
  • Reading: You can recieve an arbitrary amount of bytes.

  • Writing: No zero length package is generated automatically.

1

Note that the term of exact buffer size is used in different (and in my opinion confusing way) inside the USB specification so use this flag exactly as described in the sense at here.

  • Reading: You must recieve exactly the number of bytes in data buffer or an error is generated.

  • Writing: It is checked whether number of bytes matches data payload size. If this the case a zero length package is generated automatically.

This flag is also used to show zero length buffers to the USB module.

1USB_TRANSACTION_FRAME_START0>No frame start number is given
1Frame start number is given and the transaction must not be processed before this frame number is reached.
2USB_TRANSACTION_SETUP_EVAL0Setup buffer is not evaluated by the USB module.
1

Setup buffer is evaluated by the USB module. Only three USB standard requests are influencing USB-Module internal data structures and are therefore evaluated after the request has been successfuly acknowledged by the device. Note that configuration and interface settings are managed by service calls by the according part of software.

  • CLEAR_FEATURE ENDPOINT_HALT. Will remove the halt on the according pipe of the device.

  • SET_FEATURE ENDPOINT_HALT. Will halt the according pipe of the device.

  • SET ADDRESS. The new device address should have been reserved by USB_GetDeviceAddress and must be still unused. If the address has not been already reserved it will be reserved at this moment. If this request fails the address is freed automatically (even request is aborted by program). At the succesfull end device structure will be allocated to new address automatically. Also the old device number will be freed automatically.

This Flag is not evaluated in the actual version of the USB module. Programs are responsible for keeping the structures at the right state. So this flag must be set to zero.

3USB_TRANSACTION_STATUS_STAGE0Normal that means no status stage behaviour.
1At pipes of Control transfer type a transaction containing sending or recieving of a zero length package as Status Stage is generated automatically after the last normal transfer. This option is needed because the direction of this transaction is opposite to the normal data transfer direction given inside the last setup buffer. If a buffer of zero length is given this is interpreted automatically as such a status package if this bit is set and no additional transaction is generated which would be the case if buffer is not zero length. Note that a zero length buffer size must be shown by setting used size of buffer to zero and setting the USB_TRANSACTION_EXACT_SIZE flag.
30USB_TRANSACTION_REQUEST_FIRST0Transaction is not the first in a request. This blocks any other transaction at this endpoint to be notified as pending until it is removed from the pending queue by using a special function.
1Transaction is the first one in a request.
31USB_TRANSACTION_CANCELLED0All informations inside transaction are valid.
1

Transaction has been cancelled. Stop the processing of the transaction and its following transactions belonging to the same request immediately.

Note that some information inside the transaction may be invalid. However the validity of the most pointer references is granted by reference chains.

If there are sublayers each sublayer must provide a host controller installation function. This function must contain a pointer to an array. The first element of the array must give the number of substructures (that means the number of the remaining array elements). The remaining elements are giving information about one substructure. Bit 0-23 of an element must contain the size of each substructure. Bits 24-31 must contain a unique tag of the substructure (described below). Every sublayer expands this list by its own substructures at the beginning of the array (that means after the first element which must be increased by the number of the additional substructures). Afterwards the installation function of the layer above is called. The top installation function mallocs total storage even this layer is using only a part of it. It calculates the offsets of the substructures. Note that every substructure will be word aligned! Functions will return the list of substructures from top layer to their caller so that this caller can determine by the tags on which substructures the substructures used by itself are located. The control over this array is passed to the caller. The last caller has to clear the array from memory.

Table 1.19. Transaction sublayer tags

ValueUsed for
0x01000000transaction information (will be used by nearly every layer)
0x02000000used internally by the USB Module for USB Standard Request evaluation
0x03000000- 0x0E000000reserved for USB Module
0x0F000000Information of level 2 concept (will be used by level 2 routines and USB host controller driver)
0x10000000USB host controller driver specific information
0x11000000 - 0x3X000000can be used by USB host controller drivers in an arbitrary way.
0x40000000 - 0xXX000000reserved for future expansion

USB host controller driver property structure

The USB host controller driver property structure contains USB host controller driver properties which are needed at various parts of the USB Module. These properties must be held inside the USB host controller driver. If USB host controller driver is registered he must pass a pointer to this structure. Because some data must be evaluated if other applications are active this structure including the data structures to which it holds pointer must be located in a public memory address range like RMA or Dynamic areas. Note that some properties can be changed by the USB host controller driver during operation.

Table 1.20. Format of USB host controller driver property structure

PositionData typeDescription
0x00unsigned longSize of the structure in bytes including this field (0x1C). This is used to enable running of newer USB-module Version with older USB host controller drivers if this structure should be expanded.
0x04unsigned longMinimal speed
0x08unsigned longMaximal speed
0x0Cunsigned longGives the maximal number that can be used for frame repeat values. (255 at USB 1.1)
0x10unsigned longMaximal number of transfer types supported (4 at USB 1.1)
0x14Pointer to unsigned longPointer to table which gives the maximal number of running requests of a transfer type until that the controller wants to be notified about pending requests.
0x18unsigned longFrame Mask Number

Bus capacity calculation

If a pipe is opened USB specification requires a check whether the bus capacity needed for this pipe is available. You can define this in a more common way and say that a check is required whether your computer systen can handle the new pipe. That means that you must include the I/O capacity and processing power capactities of your machine. This may vary from machine to machine from time to time and from controller to controller. There are Service calls which are broadcast by various applications and which must be claimed by the according applications if the required capacity is available. The USB Hub class driver is maintining the power capacities. Because these are changed if the configuration of a device is changed the requests to claim or release a power capacity are generated by SetDevConf. USB transfer capacity is handled by the USB host controller drivers. The request of claiming or releasing transfer capacity may be generated by SetDevConf or the USB module itself if a pipe is opened (for the first time at shared pipes) or closed or the endpoint is deregistered.

Maximal running requests to note

For transfer type the host controller determines how much requests can running for an endpoint before he don't want to be notified about pending requests. If controllers are doing all management itself they should set this value to maximum. Normally a value of 1 or 2 (one transaction running, one in preparation) will be used. Information is hold inside an array of 4 byte words (unsigend long) elements and controls pending requests speed up handling.

Frame number mask

Frame number mask is used to generate a concept to determine the frame from which on a transaction can be sent. At USB 1.1 the frame number is 11 Bit long. Specification allows the USB-Driver to handle larger frame numbers where it must be cutted to 11 Bit at the Bus. However it will come the point where a maximum frame number is reached and you must reset number to zero. On the other side you are having absolutely frame numbers which are telling how long to have to wait until sending this transaction. Similar situation occurs if you have to determine the next frame number of an interrupt transfer transaction. On one side you have to sort transactions, but if becoming greater then the maximal value simple sorting will fail because you new frame number is lower then the actual one. Therefore the frame number mask is used.

External incoming frame number values are always masked with frame number mask (frame start at usb_request_start, usb_frame_sync_number). One exception is made at usb_request_get_pending. Here a value of 0xFFFFFFFF is allowed to fetch all requests regardsless of the frame number.

External outgoing frame number values as used inside transactions will be always in the range of the frame number mask.

The behaviour of inserting new request is as follows. At first a new frame start must be calculated. This done without using the mask because all values are stored masked by the mask. So a linear value is range is valid. After all calculations are done the calculated value is masked by the frame number mask. The calculated number may be overwritten by a given frame number if this is in a valid range (from actual frame up to frame number mask/2 more). The insertion is started at the end of list of pending request because this will be the most likely case. However due to interrupt transactions and unordered starting of requests new request may need to be placed prior to in the list. Therefore the list is scanned to front while the frame number of the new request is smaller than the frame number of the actual list element. However to avoid placing the new element before requests which have been delayed because of not working driver polling another comparism of actual list element is made to a so called reference frame value whether the actual list element is bigger than this reference frame value. The reference value is the either the actual frame number or the frame number of the last element inside the list if the actual frame number is less or equal than frame number mask/2 and the frame number of the last element inside the list is greater than frame number mask/2.

Removing a request is done as follows. The list of pending requests of the transaction type is checked wether the frame number of the first element inside it is either between the actual frame number minus frame number mask/2 and the actual frame number if the actual frame number is greater than frame number mask/2 or in the case that the actual frame number is less or equal the actual frame number if the frame number of the first list element is less than the actual frame number or is greater than actual frame number plus frame number mask/2.

This concept may fail if there is a very long time no USB host controller driver activity. But that should not happen however.

Pipe structure

Pipe structure is in the moment identical to endpoint structure but this may change in later releases. Pipe structure is not public whith one exception. Each Pipe has one Data Toggle field which allows the USB Host controller driver to keep the actual Data toggle state for a pipe. A SETUP transaction must reset Data toggle state to 0. A status stage transaction will set it always to 1. Isochronous transactions are always done with a data toggle of 0.

Table 1.21. Format of pipe structure (public parts)

PositionData typeDescription
0x00unsigned longData toggle value (0 or 1).

This field must be handled by the USB Host controller driver because it may keep more than one transaction of a pipe and handle the results in its own way. On the other hand clearing the pipe reset by the UBS Module resets the pipe to 0. Therefore following scheme must be used. At dropping the USB Module will first mark all running transactions as cancelled before it will then reset the according pipe data toggle to 0. The USB Hub controller driver must keep a copy of the data toggle value. Afterwards it must check whether transaction has been cancelled. If this is the case it must reject it. Else the transaction must be processed. The local copy of the data toggle must be manipulated and rewritten at the end of the transfer. If USB Module recieves a cancelled transaction back by USB_TransactionResult it will automatically reset data toggle to 0.

USB Hub driver module

This function will be normally used by the USB Hub driver module

The normal way is that the USB-Hub module detects a new device. It will examine this device by using the default device address and the default pipe. It will then call this function to get a number for this device or using a fix device number. Afterwards it will set the address of the new device by by using the default device address and the default pipe. Afterwards it will establish a new default pipe for the new device address. Then the new device is ready for usage.

This chapter is not finished at the moment.

Service Call Concept

The USB-System is using a single Service Call &80c00. R0 contains the task of the call and determines the meaning of the other registers.

This chapter is not finished at the moment.

Errors

The error handling of USB-Module is in the moment different to ususal RISCOS Error handling. It is more a C-like handling because its returns the errors in Form of a result code. This way has been choosen because the USB modules will be used by other applications and these have to cope with the errors. The most errors will contain information which is only for this application of any interest but not for the usual endusers. However the application may take the error code passed back by the USB module and launch them in an RISCOS conform way if they are thinking the information is for interest to the user or if they want to implement a RISCOS conform error handling to applications which are using themselves. Therefore a RISCOS Error chunk (&819b00) has been allocated for USB-Module. If all is well USB-Module will return error code 0. Note that if pointers are passed back as a result of a function a NULL pointer always shows that the function failed. At such functions the address of a word which keeps an additional error code information can be passed too.

For specific codes see Table A.1, “Error codes used by the USB system”.