0d975479fb
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@21162 a95241bf-73f2-0310-859d-f6bbb57e9c96
387 lines
20 KiB
Plaintext
387 lines
20 KiB
Plaintext
/*
|
|
* Copyright 2007, Haiku, Inc. All Rights Reserved.
|
|
* Distributed under the terms of the MIT License.
|
|
*
|
|
* Documentation by:
|
|
* Niels Sascha Reedijk <niels.reedijk@gmail.com>
|
|
*/
|
|
|
|
/*!
|
|
\page usb_modules Writing drivers for USB devices
|
|
|
|
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.
|
|
*/
|