Writing Device Drivers

Requests

This section discusses request structures and allocating and deallocating different types of requests.

Request Allocation and Deallocation

Requests are implemented as initialized request structures. Each different endpoint type takes a different type of request. Each type of request has a different request structure type. The following table shows the structure type for each type of request. This table also lists the functions to use to allocate and free each type of structure.

Table 20–1 Request Initialization

Pipe or Endpoint Type 

Request Structure 

Request Structure Allocation Function 

Request Structure Free Function 

Control 

usb_ctrl_req_t (see the usb_ctrl_request(9S) man page)

usb_alloc_ctrl_req(9F)

usb_free_ctrl_req(9F)

Bulk 

usb_bulk_req_t (see the usb_bulk_request(9S) man page)

usb_alloc_bulk_req(9F)

usb_free_bulk_req(9F)

Interrupt 

usb_intr_req_t (see the usb_intr_request(9S) man page)

usb_alloc_intr_req(9F)

usb_free_intr_req(9F)

Isochronous 

usb_isoc_req_t (see the usb_isoc_request(9S) man page)

usb_alloc_isoc_req(9F)

usb_free_isoc_req(9F)

The following table lists the transfer functions that you can use for each type of request.

Table 20–2 Request Transfer Setup

Pipe or Endpoint Type 

Transfer Functions 

Control 

usb_pipe_ctrl_xfer(9F), usb_pipe_ctrl_xfer_wait(9F)

Bulk 

usb_pipe_bulk_xfer(9F)

Interrupt 

usb_pipe_intr_xfer(9F), usb_pipe_stop_intr_polling(9F)

Isochronous 

usb_pipe_isoc_xfer(9F), usb_pipe_stop_isoc_polling(9F)

Use the following procedure to allocate and deallocate a request:

  1. Use the appropriate allocation function to allocate a request structure for the type of request you need. The man pages for the request structure allocation functions are listed in Table 20–1.

  2. Initialize any fields you need in the structure. See Request Features and Fields or the appropriate request structure man page for more information. The man pages for the request structures are listed in Table 20–1.

  3. When the data transfer is complete, use the appropriate free function to free the request structure. The man pages for the request structure free functions are listed in Table 20–1.

Request Features and Fields

Data for all requests is passed in message blocks so that the data is handled uniformly whether the driver is a STREAMS, character, or block driver. The message block type, mblk_t, is described in the mblk(9S) man page. The DDI offers several routines for manipulating message blocks. Examples include allocb(9F) and freemsg(9F). To learn about other routines for manipulating message blocks, see the “SEE ALSO” sections of the allocb(9F) and freemsg(9F) man pages. Also see the STREAMS Programming Guide.

The following request fields are included in all transfer types. In each field name, the possible values for xxxx are: ctrl, bulk, intr, or isoc.

xxxx_client_private

This field value is a pointer that is intended for internal data to be passed around the client driver along with the request. This pointer is not used to transfer data to the device. 

xxxx_attributes

This field value is a set of transfer attributes. While this field is common to all request structures, the initialization of this field is somewhat different for each transfer type. See the appropriate request structure man page for more information. These man pages are listed in Table 20–1. See also the usb_request_attributes(9S) man page.

xxxx_cb

This field value is a callback function for normal transfer completion. This function is called when an asynchronous transfer completes without error. 

xxxx_exc_cb

This field value is a callback function for error handling. This function is called only when asynchronous transfers complete with errors. 

xxxx_completion_reason

This field holds the completion status of the transfer itself. If an error occurred, this field shows what went wrong. See the usb_completion_reason(9S) man page for more information. This field is updated by the USBA 2.0 framework.

xxxx_cb_flags

This field lists the recovery actions that were taken by the USBA 2.0 framework before calling the callback handler. The USB_CB_INTR_CONTEXT flag indicates whether a callback is running in interrupt context. See the usb_callback_flags(9S) man page for more information. This field is updated by the USBA 2.0 framework.

The following sections describe the request fields that are different for the four different transfer types. These sections describe how to initialize these structure fields. These sections also describe the restrictions on various combinations of attributes and parameters.

Control Requests

Use control requests to initiate message transfers down a control pipe. You can set up transfers manually, as described below. You can also set up and send synchronous transfers using the usb_pipe_ctrl_xfer_wait(9F) wrapper function.

The client driver must initialize the ctrl_bmRequestType, ctrl_bRequest, ctrl_wValue, ctrl_wIndex, and ctrl_wLength fields as described in the USB 2.0 specification.

The ctrl_data field of the request must be initialized to point to a data buffer. The usb_alloc_ctrl_req(9F) function initializes this field when you pass a positive value as the buffer len. The buffer must, of course, be initialized for any outbound transfers. In all cases, the client driver must free the request when the transfer is complete.

Multiple control requests can be queued. Queued requests can be a combination of synchronous and asynchronous requests.

The ctrl_timeout field defines the maximum wait time for the request to be processed, excluding wait time on the queue. This field applies to both synchronous and asynchronous requests. The ctrl_timeout field is specified in seconds.

The ctrl_exc_cb field accepts the address of a function to call if an exception occurs. The arguments of this exception handler are specified in the usb_ctrl_request(9S) man page. The second argument of the exception handler is the usb_ctrl_req_t structure. Passing the request structure as an argument allows the exception handler to check the ctrl_completion_reason and ctrl_cb_flags fields of the request to determine the best recovery action.

The USB_ATTRS_ONE_XFER and USB_ATTRS_ISOC_* flags are invalid attributes for all control requests. The USB_ATTRS_SHORT_XFER_OK flag is valid only for host-bound requests.

Bulk Requests

Use bulk requests to send data that is not time-critical. Bulk requests can take several USB frames to complete, depending on overall bus load.

All requests must receive an initialized message block. See the mblk(9S) man page for a description of the mblk_t message block type. This message block either supplies the data or stores the data, depending on the transfer direction. Refer to the usb_bulk_request(9S) man page for more details.

The USB_ATTRS_ONE_XFER and USB_ATTRS_ISOC_* flags are invalid attributes for all bulk requests. The USB_ATTRS_SHORT_XFER_OK flag is valid only for host-bound requests.

The usb_pipe_get_max_bulk_transfer_size(9F) function specifies the maximum number of bytes per request. The value retrieved can be the maximum value used in the client driver's minphys(9F) routine.

Multiple bulk requests can be queued.

Interrupt Requests

Interrupt requests typically are for periodic inbound data. Interrupt requests periodically poll the device for data. However, the USBA 2.0 framework supports one-time inbound interrupt data requests, as well as outbound interrupt data requests. All interrupt requests can take advantage of the USB interrupt transfer features of timeliness and retry.

The USB_ATTRS_ISOC_* flags are invalid attributes for all interrupt requests. The USB_ATTRS_SHORT_XFER_OK and USB_ATTRS_ONE_XFER flags are valid only for host-bound requests.

Only one-time polls can be done as synchronous interrupt transfers. Specifying the USB_ATTRS_ONE_XFER attribute in the request results in a one-time poll.

Periodic polling is started as an asynchronous interrupt transfer. An original interrupt request is passed to usb_pipe_intr_xfer(9F). When polling finds new data to return, a new usb_intr_req_t structure is cloned from the original and is populated with an initialized data block. When allocating the request, specify zero for the len argument to the usb_alloc_intr_req(9F) function. The len argument is zero because the USBA 2.0 framework allocates and fills in a new request with each callback. After you allocate the request structure, fill in the intr_len field to specify the number of bytes you want the framework to allocate with each poll. Data beyond intr_len bytes is not returned.

The client driver must free each request it receives. If the message block is sent upstream, decouple the message block from the request before you send the message block upstream. To decouple the message block from the request, set the data pointer of the request to NULL. Setting the data pointer of the request to NULL prevents the message block from being freed when the request is deallocated.

Call the usb_pipe_stop_intr_polling(9F) function to cancel periodic polling. When polling is stopped or the pipe is closed, the original request structure is returned through an exception callback. This returned request structure has its completion reason set to USB_CR_STOPPED_POLLING.

Do not start polling while polling is already in progress. Do not start polling while a call to usb_pipe_stop_intr_polling(9F) is in progress.

Isochronous Requests

Isochronous requests are for streaming, constant-rate, time-relevant data. Retries are not made on errors. Isochronous requests have the following request-specific fields:

isoc_frame_no

Specify this field when the overall transfer must start from a specific frame number. The value of this field must be greater than the current frame number. Use usb_get_current_frame_number(9F) to find the current frame number. Note that the current frame number is a moving target. For low-speed and full-speed buses, the current frame is new each millisecond. For high-speed buses, the current frame is new each 0.125 millisecond. Set the USB_ATTR_ISOC_START_FRAME attribute so that the isoc_frame_no field is recognized.

To ignore this frame number field and start as soon as possible, set the USB_ATTR_ISOC_XFER_ASAP flag.

isoc_pkts_count

This field is the number of packets in the request. This value is bounded by the value returned by the usb_get_max_pkts_per_isoc_request(9F) function and by the size of the isoc_pkt_descr array (see below). The number of bytes transferable with this request is equal to the product of this isoc_pkts_count value and the wMaxPacketSize value of the endpoint.

isoc_pkts_length

This field is the sum of the lengths of all packets of the request. This value is set by the initiator. This value should be set to zero so that the sum of isoc_pkts_length in the isoc_pkt_descr list will be used automatically and no check will be applied to this element.

isoc_error_count

This field is the number of packets that completed with errors. This value is set by the USBA 2.0 framework. 

isoc_pkt_descr

This field points to an array of packet descriptors that define how much data to transfer per packet. For an outgoing request, this value defines a private queue of sub-requests to process. For an incoming request, this value describes how the data arrived in pieces. The client driver allocates these descriptors for outgoing requests. The framework allocates and initializes these descriptors for incoming requests. Descriptors in this array contain framework-initialized fields that hold the number of bytes actually transferred and the status of the transfer. See the usb_isoc_request(9S) man page for more details.

All requests must receive an initialized message block. This message block either supplies the data or stores the data. See the mblk(9S) man page for a description of the mblk_t message block type.

The USB_ATTR_ONE_XFER flag is an illegal attribute because the system decides how to vary the amounts of data through available packets. The USB_ATTR_SHORT_XFER_OK flag is valid only on host-bound data.

The usb_pipe_isoc_xfer(9F) function makes all isochronous transfers asynchronous, regardless of whether the USB_FLAGS_SLEEP flag is set. All isochronous input requests start polling.

Call the usb_pipe_stop_isoc_polling(9F) function to cancel periodic polling. When polling is stopped or the pipe is closed, the original request structure is returned through an exception callback. This returned request structure has its completion reason set to USB_CR_STOPPED_POLLING.

Polling continues until one of the following events occurs: