First iteration of the documentation that describes how to write drivers that use the USB module.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@21162 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Niels Sascha Reedijk
2007-05-17 16:08:33 +00:00
parent fa48b9d885
commit 0d975479fb
2 changed files with 1055 additions and 495 deletions
+205 -13
View File
@@ -81,9 +81,11 @@
\param device A unique id that identifies this USB device. \param device A unique id that identifies this USB device.
\param[in] cookie You can store a pointer to an object in this variable. \param[in] cookie You can store a pointer to an object in this variable.
When the device is removed, this cookie will be provided to you. When the device is removed, this cookie will be provided to you.
\return You should return \c B_OK in case of success. If you return an error \return You should return \c B_OK in case of success. The USB stack will then
value, the \a device id will become invalid and you will not be notified if request the kernel to republish your device names, so that the new device
this device is removed. will be shown in the \c /dev tree. If you return an error value, the
\a device id will become invalid and you will not be notified if this
device is removed.
\see device_removed() \see device_removed()
*/ */
@@ -148,14 +150,147 @@
///// usb_endpoint_info ///// ///// usb_endpoint_info /////
/*!
\struct usb_endpoint_info
\brief Container for endpoint descriptors and their Haiku USB stack
identifiers.
*/
/*!
\var usb_endpoint_descriptor *usb_endpoint_info::descr
\brief Pointer to the descriptor of the endpoint.
*/
/*!
\var usb_pipe usb_endpoint_info::handle
\brief Handle to use when using the stack to transfer data to and from this
endpoint.
*/
///// usb_interface_info ///// ///// usb_interface_info /////
/*!
\struct usb_interface_info
\brief Container for interface descriptors and their Haiku USB stack
identifiers.
*/
//! @{
/*!
\var usb_interface_descriptor *usb_interface_info::descr
\brief Pointer to the descriptor of the interface.
*/
/*!
\var usb_interface usb_interface_info::handle
\brief Handle to use when using the stack to manipulate this interface.
*/
//! @}
/*!
\name Endpoints
*/
//! @{
/*!
\var size_t usb_interface_info::endpoint_count
\brief The number of endpoints in this interface.
*/
/*!
\var usb_endpoint_info *usb_interface_info::endpoint
\brief An array of endpoints that are associated to this interface.
*/
//! @}
/*!
\name Unparsed descriptors
*/
//! @{
/*!
\var size_t usb_interface_info::generic_count
\brief The number of unparsed descriptors in this interface.
*/
/*!
\var usb_descriptor **usb_interface_info::generic
\brief Unparsed descriptors in this interface.
*/
//! @}
///// usb_interface_list ///// ///// usb_interface_list /////
/*!
\struct usb_interface_list
\brief List of interfaces available to a configuration.
*/
/*!
\var size_t usb_interface_list::alt_count
\brief Number of available interfaces.
*/
/*!
\var usb_interface_info *usb_interface_list::alt
\brief Array of available interfaces.
*/
/*!
\var usb_interface_info *usb_interface_list::active
\brief Pointer to active interface.
*/
///// usb_configuration_info ///// ///// usb_configuration_info /////
/*!
\struct usb_configuration_info
\brief Container for a specific configuration descriptor of a device.
*/
/*!
\var usb_configuration_descriptor *usb_configuration_info::descr
\brief The configuration descriptor.
*/
/*!
\var size_t usb_configuration_info::interface_count
\brief The number of interfaces in this configuration.
*/
/*!
\var usb_interface_list *usb_configuration_info::interface
\brief The list of interfaces available to this configuration.
*/
///// usb_iso_packet_descriptor ///// ///// usb_iso_packet_descriptor /////
/*!
\struct usb_iso_packet_descriptor
\brief The descriptor for data packets of isochronous transfers.
*/
/*!
\var int16 usb_iso_packet_descriptor::req_len
\brief Length of the request.
*/
/*!
\var int16 usb_iso_packet_descriptor::act_len
\brief The USB stack writes the actual transferred length in this variable.
*/
/*!
\var status_t usb_iso_packet_descriptor::status
\brief The status of the transfer.
*/
///// usb_callback_func ///// ///// usb_callback_func /////
/*! /*!
@@ -163,7 +298,51 @@
\brief Callback function for asynchronous transfers. \brief Callback function for asynchronous transfers.
\param cookie The cookie you supplied when you queued the transfer. \param cookie The cookie you supplied when you queued the transfer.
\param status The status of the transfer (whether it succeeded or not). \param status The status of the transfer. This is one of the following:
<table>
<tr>
<td><em>B_OK</em></td><td>Transfer succeeded.</td>
</tr>
<tr>
<td><em>B_CANCELED</em></td><td>Transfer cancelled by the user via a
usb_module_info::cancel_queued_transfers() call.</td>
</tr>
<tr>
<td><em>B_DEV_MULTIPLE_ERRORS</em></td><td>More than one of the errors
below. Unfortunately, the stack cannot give you more information.</td>
</tr>
<tr>
<td><em>B_DEV_STALLED</em></td><td>The endpoint is stalled. You can use
usb_module_info::clear_feature() method with the associated pipe and
the USB_FEATURE_ENDPOINT_HALT arguments.</td>
</tr>
<tr>
<td><em>B_DEV_DATA_OVERRUN</em></td><td>Incoming transfer: more data
flowing in than the size of the buffer.</td>
</tr>
<tr>
<td><em>B_DEV_DATA_UNDERRUN</em></td><td>Outgoing transfer: more data
flowing out than the endpoint accepts.</td>
</tr>
<tr>
<td><em>B_DEV_CRC_ERROR</em></td><td>The internal data consistency
checks of the USB protocol failed. You are best to retry. If you keep
on getting this error, there might be something wrong with the
device.</td>
</tr>
<tr>
<td><em>B_DEV_UNEXPECTED_PID</em></td><td>Internal error. You should
retry your transfer.</td>
</tr>
<tr>
<td><em>B_DEV_FIFO_OVERRUN</em></td><td>Internal error. You should
retry your transfer.</td>
</tr>
<tr>
<td><em>B_DEV_FIFO_UNDERRUN</em></td><td>Internal error. You should
retry your transfer.</td>
</tr>
</table>
\param data The provided buffer. \param data The provided buffer.
\param actualLength The amount of bytes read or written during the transfer. \param actualLength The amount of bytes read or written during the transfer.
*/ */
@@ -204,8 +383,7 @@
the amount of objects in the next parameter. the amount of objects in the next parameter.
\param supportDescriptorCount The number of objects in the array supplied in \param supportDescriptorCount The number of objects in the array supplied in
the previous parameter. the previous parameter.
\param optionalRepublishDriverName Undocumented parameter. It is safe to \param optionalRepublishDriverName Unused parameter. You should pass \c NULL.
pass \c NULL.
\retval B_OK The driver is registered. You can now call install_notify() \retval B_OK The driver is registered. You can now call install_notify()
\retval B_BAD_VALUE You passed \c NULL as \a driverName. \retval B_BAD_VALUE You passed \c NULL as \a driverName.
\retval B_ERROR General internal error in the USB stack. You may retry the \retval B_ERROR General internal error in the USB stack. You may retry the
@@ -391,7 +569,7 @@
value won't tell you if the transfer actually succeeded. value won't tell you if the transfer actually succeeded.
\retval B_OK The interrupt transfer is queued. \retval B_OK The interrupt transfer is queued.
\retval B_NO_MEMORY Error allocating objects. \retval B_NO_MEMORY Error allocating objects.
\retval B_DEV_INVALID_PIPE The \a pipe is invalid. \retval B_DEV_INVALID_PIPE The \a pipe is not a valid interrupt pipe.
*/ */
/*! /*!
@@ -435,7 +613,7 @@
value won't tell you if the transfer actually succeeded. value won't tell you if the transfer actually succeeded.
\retval B_OK The control transfer is queued. \retval B_OK The control transfer is queued.
\retval B_NO_MEMORY Error allocating objects. \retval B_NO_MEMORY Error allocating objects.
\retval B_DEV_INVALID_PIPE The \a callback is invalid. \retval B_DEV_INVALID_PIPE The \a device argument is invalid.
*/ */
/*! /*!
@@ -458,14 +636,21 @@
/*! /*!
\fn status_t (*usb_module_info::cancel_queued_transfers)(usb_pipe pipe) \fn status_t (*usb_module_info::cancel_queued_transfers)(usb_pipe pipe)
\brief Cancel pending transfers. Not Implemented. \brief Cancel pending transfers on a pipe.
Call this method to cancel pending transfers in a \a pipe. All the pending transfers will be cancelled. The stack will perform the
callback on all of them that are cancelled.
\warning This is currently not implemented! \attention There might be transfers that are being executed the moment you
call this method. These will be executed, and their callbacks will be
performed. Make sure you don't delete any buffers that could still be used
by these transfers.
\param pipe The id of the pipe to clear. The method will always return \param pipe The id of the pipe to clear.
\c B_ERROR.
\retval B_OK All the pending transfers on this pipe are deleted.
\retval B_DEV_INVALID_PIPE The supplied usb_id is not a valid pipe.
\retval "other errors" There was an error clearing the pipe.
*/ */
/*! /*!
@@ -475,3 +660,10 @@
This method is used to give lowlevel commands to the Stack. There are This method is used to give lowlevel commands to the Stack. There are
currently no uses documented. currently no uses documented.
*/ */
///// B_USB_MODULE_NAME /////
/*!
\def B_USB_MODULE_NAME
\brief The identifier string for the USB Stack interface module.
*/
+374 -6
View File
@@ -9,10 +9,378 @@
/*! /*!
\page usb_modules Writing drivers for USB devices \page usb_modules Writing drivers for USB devices
This page will describe how the Haiku USB stack is structured. The introduction of USB standardized the way many devices connected to a
whole range of different computers and operating systems. It introduced a
standard that was capable of getting rid of all the legacy systems, such as
the LPT, the PS/2 and serial ports. The plug and play nature of the standard
were revolutional at the time of it's introduction, and it changed the way
in which operating systems interacted with devices.
With the grand standard that USB has become, Haiku has an implementation
of it. It supports both the USB 1.1 and USB 2.0 specifications, and when
Haiku R1 is released, it will support the three host controller standards:
UHCI, OHCI and EHCI. The modularized design of Haiku's USB stack also paves
the way for easy implementation of any future specifications, such as
Wireless USB.
\section usb_modules_scope The Scope of this Document
This document is written for driver developers that need to interact with
USB devices. The USB specification standardizes the communication between
the host controller and the devices, and how devices should transfer data,
but it does not prescribe a standard environment that Operating Systems
should provide to the driver interfaces. As such, every operating system has
it's own interface for drivers, and so does Haiku.
This document will point driver developers to relevant parts of the USB
module API and give a general impression of the workings of the USB stack.
This document will not give information on the basics of writing drivers, or
on how to use modules. Have a look elsewhere in this documentation for that.
This document also asumes a basic knowledge of the USB specification, and on
how you are supposed to interact with devices. See \ref usb_modules_resources
for tutorials on the web if you are looking for a basic introduction on
communication with the USB protocol.
\section usb_modules_structure Structure of the Stack
This section will outline how Haiku's USB stack is structured, and how you
can interact with this stack.
The goal of the USB stack is to provide a few basic features for drivers
interacting with USB devices. It is important that the stack maintains a
continually updated device grid, so that the driver modules are always
aware of the latest status. The stack should also facilitate communication
between drivers and the devices, by abstracting the actual transfering of
bits via the host controller hardware in the computer. The stack therefore
should implement a inituitive interface to give driver developers access to
all features and possibilities the USB specification offers, and at the same
time it should abstract many of the small requirements and peculiarities of
that specification.
The stack internally can be divided into two parts. The first part is the
core module. This module, called \c usb_busmanager, performs all the
operations required by the USB specification. For example, it performs the
necessary lowlevel initialization when new devices are connected, or all the
requirements when it comes to performing transfers. The core module also
is the module that provides the abstractions to driver developers. The other
part of the USB stack are the individual modules that control the different
host controllers. Haiku supports the three types in existence: UHCI, OHCI
and EHCI. These modules perform the communication between the core module
and the hardware. As driver developer, you won't have to interact with these
modules: the core module provides all the abstractions you need.
Thus, as a driver developer you are interfacing with the \c usb_busmanager
module. On Haiku, this module implements two API's. The \c v2 API, identical
to the API offered by BeOS R5, can be found in the \c USB2.h file. However,
for new drivers, or for ports, the recomended API is the \c v3 API, defined
in the USB3.h file. This API is identical to the one provided by Zeta. The
\c v2 API should be considered to be deprecated.
\section usb_modules_registration Initial Steps: Driver Registration
In order to be able to start using the USB stack to communicate with your
devices, you will need to perform some actions. This section will outline
those actions and will point you to their appropriate locations.
\note The code examples are based on the \c usb_hid driver written by
Jerome Duval. Have a look at this driver for a complete working example.
The following example gives an overview of the requirements to open the
USB module, and to start your driver registration in order to receive
connect and disconnect events.
\code
// Global variables and constants
usb_module_info *gUsb;
const char *kDriverName = "usb_hid";
static usb_support_descriptor sSupportedDevices[1] = {
{ USB_HID_DEVICE_CLASS, 0, 0, 0, 0 },
};
// Prototype for the hooks that are called when devices are added or removed
static status_t hid_device_added(const usb_device *dev, void **cookie);
static status_t hid_device_removed(void *cookie);
static usb_notify_hooks sNotifyHooks = {
hid_device_added,
hid_device_removed
};
// Driver initialization, called by the kernel when the driver is loaded
status_t
init_driver(void)
{
if (get_module(B_USB_MODULE_NAME, (module_info **)&gUsb) != B_OK)
return B_ERROR;
gUsb->register_driver(kDriverName, sSupportedDevices,
1, NULL);
gUsb->install_notify(kDriverName, &sNotifyHooks);
return B_OK;
}
\endcode
Basically, this boils down to three steps. The first step is to acquire the
usb_module_info module. This struct contains a set of function pointers that
you use to communicate with the stack. You can retrieve it like you would
retrieve any other module.
As soon as you have done that you can start registering your driver in the
stack. What you do is you pass a unique identifier to identify your driver,
zero or more \link usb_support_descriptor support descriptors \endlink
to provide the stack with information on which devices you support, and the
number of support descriptors you provided. The stack is very flexible with
what patterns it accepts, so even the most complex driver will be able to
pass it's credentials. Have a look at the \c usb_support_descriptor struct
and the \c usb_module_info::register_driver() call for all the details.
The last step in initialization is to provide the stack with notification
hooks. These are functions in your driver that the stack should call as soon
as a device is attached or removed. Please perform this call after your
internal driver data structures are initialized, because as soon as you
perform this call, the usb stack will start searching for already attached
devices that match the credentials. Have a look at
\c usb_module_info::install_notify() and the structure \c usb_notify_hooks
for the details on the signatures of your hooks.
\section usb_modules_changes Handling Device Changes
The USB stack will notify you of device connects and disconnects when they
occur. You will receive notifications as soon as you have supplied the hooks
to the stack, using \c usb_module_info::install_notify() . This section will
explain some of the details when it comes to handling device changes.
When a device is added, your supplied usb_notify_hooks::device_added() hook
will be called if its credentials matches one of your support descriptors.
Because the stack runs through all the registered drivers, it could be that
two or more drivers operate on the same device. The stack does not provide
a locking mechanism to prevent two conflicting drivers to get in each others
way. It is up to the device maker to have supplied such a mechanism.
\note In reality, it is very likely that your device will match at least one
other driver, because Haiku supplies the \c usb_raw driver. This driver
provides userland access to the usb devices and therefore it has a blank
support descriptor that matches everything. The \c usb_raw driver will
not conflict with your device interaction though (except when there is an
userland application that tries to meddle with your device).
If your driver is willing to accept the supplied device, and your
device_added() hook returns B_OK, the USB stack will ask the kernel to reload
your published devices, so that your device is visible in userspace in the
\c /dev tree.
The other event that the stack reports, device disconnection, should be
handled by your \c usb_notify_hooks::device_removed() hook. Because "plug and
play" also means "unplug and leave", you should make sure your driver is
capable of cleaning up in the likely event that the user removes their
device, even during transfers. In your hook function, you have the ability to
do clean up whatever there is to clean up, however, make sure that you cancel
all the pending transfers. Use the usb_module_info::cancel_queued_transfers()
call for that end. Also, don't forget to free the cookie you supplied in your
device_added() hook.
\section usb_modules_standard Standard USB Operations
One of the many conveniences of the Haiku USB API is the fact that many of
the standard operations can be performed by simple function calls. As such,
you won't have to build many of the standard requests the USB specification
defines by hand. This section will outline all the different conveniences and
will point you to where to look if you do need something more advanced.
\subsection usb_modules_standard_descriptors Configurations, Interfaces and Descriptors
Many standard USB operations have to do with configurations, interfaces and
descriptors. All these operations are accessible by convenience functions.
The device descriptor is one of the first things you will be interested in if
you want to check out a device. The device descriptor can be retrieved quite
easily using the \c usb_module_info::get_device_descriptor() call. The
retrieved descriptor complies to the one dictated by the USB standard.
Also important are configurations. Since every device has at least one
configuration, you should be able to retrieve and manipulate configurations.
You can use \c usb_module_info::get_nth_configuration() to get them. To set
a configuration, you should use \c usb_module_info::set_configuration(). To
get the active configuration, use \c usb_module_info::get_configuration().
\attention By default, Haiku's stack will set the configuration at offset
zero, which is according to the standard, the default configuration.
Do not rely on that if you first get the device, that the currently active
configuration is the default configuration though. Another driver might
have manipulated this device already.
Every configuration has associated interfaces. To make life easier, the stack
automatically gets the interface descriptors (and their associated
endpoints), and stores them in the \c usb_configuration_info structure. This
structure has a member called \link usb_configuration_info::interface
\c interface \endlink which is of the type \c usb_interface_list. That object
containts all the interfaces, including a pointer to the interface that is
currently active. Each interface is described as a \c usb_interface_info,
which is a container for the interface, its associated endpoints and any
unparsed descriptors. In order to change the active interface, you can use
the stack's \c usb_module_info::set_alt_interface() call.
Endpoints, the basic units with which you can communicate, are stored as
\c usb_endpoint_info structures. Each of these structures carries the actual
endpoint descriptor, and the accompanying usb_pipe handle that you can use to
actually send and receive data.
The last point of interest are descriptors. As you have seen, Haiku caches
all the relevant descriptors itself, however, you might want to retrieve any
other type of descriptor that could be relevant for your device. The
convenience function to use in such a case is the
\c usb_module_info::get_descriptor() call. This function takes all the
parameters needed to build the actual descriptor, and performs the request
over the default control pipe.
\subsection usb_modules_standard_features Features
Another one of the building blocks of USB are features. Every device should
provide for a number of standard features, but the USB specification also
leaves the option to using custom device specific features. Feature requests
can be performed on devices, interfaces and pipes (which are tied to
endpoints).
To set a feature, you can use the \c usb_module_info::set_feature() call. To
clear a feature, use the \c usb_module_info::clear_feature() call. One of the
most used feature calls is the call to clear a \c USB_FEATURE_ENDPOINT_HALT .
\subsection usb_modules_standard_other Other Standard Calls
To get the status of a device, an interface or an endpoint, you can use the
\c usb_module_info::get_status() call.
If you are using isochronous transfers, you can use the
\c usb_module_info::set_pipe_policy() to set the properties of the
isochronous pipe.
\section usb_modules_transfers Data Transfers
Transfering data is one of the basic building blocks of the USB protocol.
This section will demonstrate how to perform transfers via the four different
protocols the USB stack offers.
But first it is essential to show how to perform the transfers using the
\c usb_module_info interface. The interface provides five \c queue_*
functions, with the asterix being one of the following: \c bulk, \c bulk_v
(bulk transfers using a vector), \c interrupt, \c isochronous or \c request
(over the standard control pipe). These five functions work asynchronously,
which means that your driver is called back from a different thread when your
transfer is finished.
The five functions share some arguments. The first argument is always the
pipe that is associated with the endpoint (except for control transfers,
these only work on the device in general). All of the functions accept a data
buffer, and the length of that buffer. All of the functions require a
\c #usb_callback_func, a function in your driver that can be called in case a
transfer is finished. The functions also require a cookie that is provided to
the callback function.
The working order is as follows: first you queue a transfer, then you handle
the result in the callback function when it's done. The callback function
will be called with a \a status argument, in which you can check whether or
not the transfer actually succeeded. See this \link #usb_callback_func
description \endlink for how your callback function should behave and what
kind of status there might have been.
Finally, before going into the different transfer types, a note on buffer
ownership. The usb stack keeps the internal buffers tidy, but the buffer you
provide to the \c queue_* functions are yours. You are responsible for
allocating and freeing them, and you may do with them whatever you like,
\e except between queueing your transfer and the callback. During that period
you should consider the USB stack the owner of the buffer.
\subsection usb_modules_transfers_control Control Requests
Control requests are done over the device wide control pipe which is provided
by every device. Haiku's stack has two functions that you can use to perform
custom requests (opposed to many of the \ref usb_modules_standard
"standard operations"). Control transfers are the only transfers that you can
perform synchronously as well as asynchronously. The functions you can use
are \c usb_module_info::send_request() for synchronous requests and
\c usb_module_info::queue_request() for asynchronous requests.
Many of the constants that you should use when performing can be found in
the USB_spec.h file which is automatically included if you include the main
USB header. Have a look of how to use these constants in the following
example:
\code
// Send a request that is defined by the standard of this class. We retrieve
// a report from the device on one of its interfaces.
// This request is specified by the HID specification.
status = usb->send_request(dev,
USB_REQTYPE_INTERFACE_IN | USB_REQTYPE_CLASS,
USB_REQUEST_HID_GET_REPORT,
0x0100 | report_id, interfaceNumber, device->total_report_size,
device->buffer, device->total_report_size, &actual);
\endcode
\warning Both the \link usb_module_info::send_request() \a send_request()
\endlink and \link usb_module_info::queue_request() \a queue_request()
\endlink functions can be used to perform standard usb requests. Avoid
low-level operations, because the stack needs to keep its internal
data structures consistent. If you need to perform one of the
\ref usb_modules_standard "standard operations", use the provided
convenience functions.
\subsection usb_modules_transfers_interrupt Interrupt
Interrupt transfers apply to endpoints that receive data, or that can be
polled in several instances of time. The intervals are determined by the
endpoint descriptor.
To schedule a transfer, use usb_module_info::queue_interrupt(). You only have
to supply a buffer, the stack schedule the transfer in such a way that it
will be performed within a certain timeframe. To create a continuous
interrupt system, you should queue the next transfer in the callback function
of the previous. The stack will make sure that the new transfer will be
performed exactly after the required interval.
\subsection usb_modules_transfers_bulk Bulk
Bulk transfers are very similar to control transfers. They will be performed
as soon as possible without stalling other transfers, and they transfer data.
Bulk transfers are designed to transfer up to large amounts of data as
efficiently as possible. Performing bulk transfers isn't difficult, you
merely supply a buffer and the endpoint that should execute the request, and
you're set.
Bulk transfers come in two flavours. The first is
usb_module_info::queue_bulk(), which takes a standard data buffer. The second
flavour is the usb_module_info::queue_bulk_v() function, which is designed to
operate on (an array of) POSIX vectors. These functions only differ in the
buffer they accept, they function in exactly the same way.
\subsection usb_modules_transfers_isochronous Isochronous
Isochronous transfers are not implemented on Haiku yet. As soon as they are,
this section should contain information on how to queue them.
\section usb_modules_cleanup Cleaning Up
This section describes how to gracefully leave the stack after your driver is
requested to shut down.
There are truely only two simple actions to perform. The first is to
uninstall your notification hooks, using
\c usb_module_info::uninstall_notify(). The second action is to 'put' the
module.
\code
void
uninit_driver(void)
{
usb->uninstall_notify(kDriverName);
put_module(B_USB_MODULE_NAME);
}
\endcode
\section usb_modules_resources More Resources
This section should list more resources on the web.
*/ */