显示标签为“Linux驱动”的博文。显示所有博文
显示标签为“Linux驱动”的博文。显示所有博文

2007年5月7日星期一

I2C Drivers

I2C Drivers, Part I

Created 2003-12-01 02:00

The I2C bus helps you monitor the health of your system. Here's how to develop a driver that will get you all the hardware info you need to know.

In the June and August 2003 issues of Linux Journal, my column covered the Linux kernel driver model, and the I2C subsystem was used as an example. This month, we discuss what the I2C subsystem does and how to write a driver for it.

I2C is the name for a two-wire serial bus protocol originally developed by Phillips. It commonly is used in embedded systems so different components can communicate; PC motherboards use I2C to talk to different sensor chips. Those sensors typically report back fan speeds, processor temperatures and a whole raft of system hardware information. The protocol also is used in some RAM chips to report information about the DIMM itself back to the operating system.

The I2C kernel code has lived outside of the main kernel tree for much of its development life-it originally was written back in the 2.0 days. The 2.4 kernel contains a bit of I2C support, mainly for some video drivers. With the 2.6 kernel, a large portion of the I2C code has made it into the main kernel tree, thanks to the effort of a number of kernel developers who changed the interfaces to be more acceptable to the kernel community. A few drivers still live only in the external CVS tree and have not been moved into the main kernel.org tree, but it is only a matter of time before they, too, are ported.

The I2C kernel code is broken up into a number of logical pieces: the I2C core, I2C bus drivers, I2C algorithm drivers and I2C chip drivers. We ignore how the I2C core operates in this article and focus instead on how to write a bus and algorithm driver. In Part II, we will cover how to write an I2C chip driver.

I2C Bus Drivers

An I2C bus driver is described by a struct named i2c_adapter, which is defined in the include/linux/i2c.h file. Only the following fields need to be set up by the bus driver:

  • struct module *owner; -set to the value (THIS_MODULE) that allows the proper module reference counting.

  • unsigned int class; -the type of I2C class devices that this driver supports. Usually this is set to the value I2C_ADAP_CLASS_SMBUS.

  • struct i2c_algorithm *algo; -a pointer to the struct i2c_algorithm structure that describes the way data is transferred through this I2C bus controller. More information on this structure is provided below.

  • char name[I2C_NAME_SIZE]; -set to a descriptive name of the I2C bus driver. This value shows up in the sysfs filename associated with this I2C adapter.

The code below comes from an example I2C adapter driver called tiny_i2c_adap.c, available from the Linux Journal FTP site [ftp.ssc.com/pub/lj/listings/issue116/7136.tgz [1]] and shows how the struct i2c_adapter is set up:


static struct i2c_adapter tiny_adapter = {
.owner = THIS_MODULE,
.class = I2C_ADAP_CLASS_SMBUS,
.algo = &tiny_algorithm,
.name = "tiny adapter",
};


To register this I2C adapter, the driver calls the function i2c_add_adapter with a pointer to the struct i2c_adapter:


retval = i2c_add_adapter(&tiny_adapter);


If the I2C adapter lives on a type of device that has a struct device associated with it, such as a PCI or USB device, then before the call to i2c_add_adapter, the adapter device's parent pointer should be set to that device. This pointer configuration can be seen in the following line from the drivers/i2c/busses/i2c-piix4.c driver:


/* set up sysfs linkage to our parent device */
piix4_adapter.dev.parent = &dev->dev;


If this parent pointer is not set up, the I2C adapter is positioned on the legacy bus and shows up in the sysfs tree at /sys/devices/legacy. Here is what happens to our example driver when it is registered:

$ tree /sys/devices/legacy/
/sys/devices/legacy/
|-- detach_state
|-- floppy0
| |-- detach_state
| `-- power
| `-- state
|-- i2c-0
| |-- detach_state
| |-- name
| `-- power
| `-- state
`-- power
`-- state

As discussed in the previous kernel driver model columns, the I2C adapter also shows up in the /sys/class/i2c-adapter directory:

$ tree /sys/class/i2c-adapter/
/sys/class/i2c-adapter/
`-- i2c-0
|-- device -> ../../../devices/legacy/i2c-0
`-- driver -> ../../../bus/i2c/drivers/i2c_adapter

To unregister an I2C adapter, the driver should call the function i2c_del_adapter with a pointer to the struct i2c_adapter, like this:


i2c_del_adapter(&tiny_adapter);


I2C Algorithm Drivers

An I2C algorithm is used by the I2C bus driver to talk to the I2C bus. Most I2C bus drivers define their own I2C algorithms and use them, as they are tied closely to how the bus driver talks to that specific type of hardware. For some classes of I2C bus drivers, a number of I2C algorithm drivers already have been written. Examples of these are ITE adapters found in drivers/i2c/i2c-algo-ite.c, IBM PPC 405 adapters found in drivers/i2c/i2c-algo-ibm_ocp.c and a generic I2C bit shift algorithm found in drivers/i2c/i2c-algo-bit.c. All of these already written algorithms have their own functions with which an I2C bus driver needs to register to use. For more information on these, please see all of the drivers/i2c/i2c-algo-*.c files in the kernel tree.

For our example driver, we are going to create our own I2C algorithm driver. An algorithm driver is defined by a struct i2c_algorithm structure and is defined in the include/linux/i2c.h file. Here is a description of some of the commonly used fields:

  • char name[32];: the name of the algorithm.

  • unsigned int id;: description of the type of algorithm this structure defines. These different types are defined in the include/linux/i2c-id.h file and start with the characters I2C_ALGO_.

  • int (*master_xfer)(struct i2c_adapter *adap,struct i2c_msg msgs[], int num);: a function pointer to be set if this algorithm driver can do I2C direct-level accesses. If it is set, this function is called whenever an I2C chip driver wants to communicate with the chip device. If it is set to NULL, the smbus_xfer function is used instead.

  • int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr, unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data *data);: a function pointer to be set if this algorithm driver can do SMB bus accesses. Most PCI-based I2C bus drivers are able to do this, and they should set this function pointer. If it is set, this function is called whenever an I2C chip driver wants to communicate with the chip device. If it is set to NULL, the master_xfer function is used instead.

  • u32 (*functionality) (struct i2c_adapter *);: a function pointer called by the I2C core to determine what kind of reads and writes the I2C adapter driver can do.

In our example I2C adapter driver, the i2c_adapter structure referenced the tiny_algorithm variable. That structure is defined as the following:


static struct i2c_algorithm tiny_algorithm = {
.name = "tiny algorithm",
.id = I2C_ALGO_SMBUS,
.smbus_xfer = tiny_access,
.functionality = tiny_func,
};


The tiny_func function is small and tells the I2C core what types of I2C messages this algorithm can support. For this driver, we want to be able to support a few different I2C message types:


static u32 tiny_func(struct i2c_adapter *adapter)
{
return I2C_FUNC_SMBUS_QUICK |
I2C_FUNC_SMBUS_BYTE |
I2C_FUNC_SMBUS_BYTE_DATA |
I2C_FUNC_SMBUS_WORD_DATA |
I2C_FUNC_SMBUS_BLOCK_DATA;
}


All of the different I2C message types are defined in include/linux/i2c.h and start with the characters I2C_FUNC_.

The tiny_access function is called when an I2C client driver wants to talk to the I2C bus. Our example function is quite simple; it merely logs all of the requests the I2C chip driver makes to the syslog and reports success back to the caller. This log allows you to see all of the different addresses and data types that an I2C chip driver may request. The implementation looks like: Garrick, please kern the double underscores in the code below.


static s32 tiny_access(struct i2c_adapter *adap,
u16 addr,
unsigned short flags,
char read_write,
u8 command,
int size,
union i2c_smbus_data *data)
{
int i, len;
dev_info(&adap->dev, "%s was called with the "
"following parameters:\n",
__FUNCTION__);
dev_info(&adap->dev, "addr = %.4x\n", addr);
dev_info(&adap->dev, "flags = %.4x\n", flags);
dev_info(&adap->dev, "read_write = %s\n",
read_write == I2C_SMBUS_WRITE ?
"write" : "read");
dev_info(&adap->dev, "command = %d\n",
command);
switch (size) {
case I2C_SMBUS_PROC_CALL:
dev_info(&adap->dev,
"size = I2C_SMBUS_PROC_CALL\n");
break;
case I2C_SMBUS_QUICK:
dev_info(&adap->dev,
"size = I2C_SMBUS_QUICK\n");
break;
case I2C_SMBUS_BYTE:
dev_info(&adap->dev,
"size = I2C_SMBUS_BYTE\n");
break;
case I2C_SMBUS_BYTE_DATA:
dev_info(&adap->dev,
"size = I2C_SMBUS_BYTE_DATA\n");
if (read_write == I2C_SMBUS_WRITE)
dev_info(&adap->dev,
"data = %.2x\n", data->byte);
break;
case I2C_SMBUS_WORD_DATA:
dev_info(&adap->dev,
"size = I2C_SMBUS_WORD_DATA\n");
if (read_write == I2C_SMBUS_WRITE)
dev_info(&adap->dev,
"data = %.4x\n", data->word);
break;
case I2C_SMBUS_BLOCK_DATA:
dev_info(&adap->dev,
"size = I2C_SMBUS_BLOCK_DATA\n");
if (read_write == I2C_SMBUS_WRITE) {
dev_info(&adap->dev, "data = %.4x\n",
data->word);
len = data->block[0];
if (len < 0)
len = 0;
if (len > 32)
len = 32;
for (i = 1; i <= len; i++)
dev_info(&adap->dev,
"data->block[%d] = %x\n",
i, data->block[i]);
}
break;
}
return 0;
}


Now that the tiny_i2c_adap driver is built and loaded, what can it do? On its own, it cannot do anything. An I2C bus driver needs an I2C client driver in order to do anything besides sit in the sysfs tree. So, if the lm75 I2C client driver is loaded, it tries to use the tiny_i2c_adap driver to find the chip for which it was written: Garrick, please use a small font so these lines don't have to break.

$ modprobe lm75
$ tree /sys/bus/i2c/
/sys/bus/i2c/
|-- devices
| |-- 0-0048 -> ../../../devices/legacy/i2c-0/0-0048
| |-- 0-0049 -> ../../../devices/legacy/i2c-0/0-0049
| |-- 0-004a -> ../../../devices/legacy/i2c-0/0-004a
| |-- 0-004b -> ../../../devices/legacy/i2c-0/0-004b
| |-- 0-004c -> ../../../devices/legacy/i2c-0/0-004c
| |-- 0-004d -> ../../../devices/legacy/i2c-0/0-004d
| |-- 0-004e -> ../../../devices/legacy/i2c-0/0-004e
| `-- 0-004f -> ../../../devices/legacy/i2c-0/0-004f
`-- drivers
|-- i2c_adapter
`-- lm75
|-- 0-0048 -> ../../../../devices/legacy/i2c-0/0-0048
|-- 0-0049 -> ../../../../devices/legacy/i2c-0/0-0049
|-- 0-004a -> ../../../../devices/legacy/i2c-0/0-004a
|-- 0-004b -> ../../../../devices/legacy/i2c-0/0-004b
|-- 0-004c -> ../../../../devices/legacy/i2c-0/0-004c
|-- 0-004d -> ../../../../devices/legacy/i2c-0/0-004d
|-- 0-004e -> ../../../../devices/legacy/i2c-0/0-004e
`-- 0-004f -> ../../../../devices/legacy/i2c-0/0-004f


Because the tiny_i2c_adap driver responds with a success to every read and write request it is asked to accomplish, the lm75 I2C chip driver thinks it has found an lm75 chip at every known possible I2C address for this chip. This abundance of addresses is why I2C devices 0-0048 through 0-004f have been created. If we look at the directory for one of these devices, the sensor files for this chip driver are shown:

$ tree /sys/devices/legacy/i2c-0/0-0048/
/sys/devices/legacy/i2c-0/0-0048/
|-- detach_state
|-- name
|-- power
| `-- state
|-- temp_input
|-- temp_max
`-- temp_min


The detach_state file and power directory is created by the kernel driver core and is used for power management. It is not created by the lm75 driver. The functions of the other files in this directory are described below.

If we ask the lm75 driver for the current value of temp_max, we receive the following:

$ cat /sys/devices/legacy/i2c-0/0-0048/temp_max
1000


To get that value, the lm75 driver asked the tiny_i2c_adap driver to read some addresses on the I2C bus. This request is shown in the syslog: Garrick, please use a really small font so this will fit without breaking the lines.

$ dmesg
i2c_adapter i2c-0: tiny_access was called with the following parameters:
i2c_adapter i2c-0: addr = 0048
i2c_adapter i2c-0: flags = 0000
i2c_adapter i2c-0: read_write = read
i2c_adapter i2c-0: command = 0
i2c_adapter i2c-0: size = I2C_SMBUS_WORD_DATA
i2c_adapter i2c-0: tiny_access was called with the following parameters:
i2c_adapter i2c-0: addr = 0048
i2c_adapter i2c-0: flags = 0000
i2c_adapter i2c-0: read_write = read
i2c_adapter i2c-0: command = 3
i2c_adapter i2c-0: size = I2C_SMBUS_WORD_DATA
i2c_adapter i2c-0: tiny_access was called with the following parameters:
i2c_adapter i2c-0: addr = 0048
i2c_adapter i2c-0: flags = 0000
i2c_adapter i2c-0: read_write = read
i2c_adapter i2c-0: command = 2
i2c_adapter i2c-0: size = I2C_SMBUS_WORD_DATA


The log file shows that the tiny_access function was called three times. The first command wanted to read a word of data from register 0 out of the device with the address 0048. The second and third reads asked for register 3 and register 2 from the same device. The commands match up with the following code from the drivers/i2c/chips/lm75.c file in the lm75_update_client function:


data->temp_input = lm75_read_value(client,
LM75_REG_TEMP);
data->temp_max = lm75_read_value(client,
LM75_REG_TEMP_OS);
data->temp_hyst = lm75_read_value(client,
LM75_REG_TEMP_HYST);


The lm75_read_value function in that same file contains the following code:


/* All registers are word-sized, except for the
configuration register. LM75 uses a high-byte
first convention, which is exactly opposite to
the usual practice. */
static int lm75_read_value(struct i2c_client
*client, u8 reg)
{
if (reg == LM75_REG_CONF)
return i2c_smbus_read_byte_data(client,
reg);
else
return swap_bytes(
i2c_smbus_read_word_data(client,
reg));
}


Therefore, when the lm75 driver wants to read the value of the max temperature, it calls the lm75_read_value function with the register number, which then calls the I2C core function i2c_smbus_read_word_data. That I2C core function looks up on which I2C bus the client device is, and then it calls the I2C algorithm associated with that specific I2C bus to do the data transfer. This is the method, then, by which our tiny_i2c_adap driver is asked to complete the transfer.

If this same sysfs file is written to, the lm75 driver asks the tiny_i2c_adap driver to write some data to a specific address on the I2C bus in the same way the read was requested. This request also is shown in the syslog: Garrick, again, use small font below.

$ echo 300 > /sys/devices/legacy/i2c-0/0-0048/temp_max
$ dmesg
i2c_adapter i2c-0: tiny_access was called with the following parameters:
i2c_adapter i2c-0: addr = 0048
i2c_adapter i2c-0: flags = 0000
i2c_adapter i2c-0: read_write = write
i2c_adapter i2c-0: command = 3
i2c_adapter i2c-0: size = I2C_SMBUS_WORD_DATA
i2c_adapter i2c-0: data = 8000


Conclusion

This month we covered the basics of the I2C driver subsystem and explained how to write a simple I2C bus and I2C algorithm driver that work with any existing I2C client driver. The complete driver, dmn-09-i2c-adap.c, is available from the Linux Journal FTP site at ftp.ssc.com/pub/lj/listings/issue116/7136.tgz [2]. In Part II, we will cover how to write an I2C chip driver.

Greg Kroah-Hartman currently is the Linux kernel maintainer for a variety of different driver subsystems. He works for IBM, doing Linux kernel-related things and can be reached at greg@kroah.com [3]. 7136aa.tif


2007年5月5日星期六

Linux and USB 2.0

Linux and USB 2.0

Last Update: 29 November 2004

This is a short writeup explaining what USB 2.0 changed and what's going on with it in Linux. It starts by talking about user visible changes (including usbfs information) followed by driver-visible ones. Finally it summarizes the current state of Linux USB 2.0 driver support in recent 2.4 and 2.6 kernels. If you want assistance getting this working on your hardware, try the linux-usb-users (or linux-usb-devel) mailing lists at http://www.linux-usb.org.

If you're a 2.4 user, use 2.4.22 or newer kernels. Newer kernels (including 2.6.x ones) have updates which seem to resolve the worst problems reported. The driver version string should be no older than June 2003. (VT6202 problems may still remain, especially on 2.4 kernels.)

Some older Linux distributions ship 2.4.18 kernels with EHCI code based on much older code, similar to what was in 2.5.2; the newer code supports more hardware, fixes bugs, is smaller, and has other goodness. If you're building a distribution, avoid using such old code; in particular, 2.4 versions of the EHCI driver are no longer being kept current.

You should probably know that "USB" is an abbreviation of the Universal Serial Bus, which is widely used for peripherals in modern desktop systems. (It's not "universal" in the sense that you'd want it instead of HyperTransport!) PCs typically support one or more USB controllers (one per "USB bus") each of which can support up to 127 different USB peripherals. "Legacy free" PCs omit non-USB peripheral support (like RS-232 serial lines, and PS/2 ports). Partially excepting the new USB 2.0 "OTG" support, USB is asymmetric. For example, its cabling is always asymmetric (even with OTG), so you can't hook things up incorrectly. USB supports "hotplugging" for all its peripherals, which means that you don't have to configure them by hand and that peripherals may rely on power delivered through USB. Both those features help reduce end-user setup and configuration problems, which was a major goal for USB technology.


OS-Neutral Changes in USB 2.0

Today, most USB peripherals and hosts support USB version 1.1, which supported two device speeds: low speed at 1.5 Mbit/sec, and full speed at 12 Mbit/sec. USB 2.0 is appearing in current product designs, and one of its main features is adding a new speed: high speed, at 480 Mbit/sec.

To put it another way: USB 1.1 was OK for low speed devices like mice and keyboards, and even for medium speed ones like Ethernet (10 Mbit/sec) adapters, or consumer electronics gadgets that only exchange a few megabytes of data (like many digital still cameras and MP3 players). USB 2.0 "full speed" or "low speed" is effectively just the familiar old "USB 1.1". You need USB 2.0 high speed to get reasonable speed for multiple large transfers as with some PC peripherals like disk drives (including MP3 jukeboxes :) or high resolution webcams (USB video), or get concurrent use from a bunch of 100BaseT networking adapters.

OK, it's faster! ... but what else will a Linux user notice about USB 2.0? We'll go from the outside in: starting from what you'll see with product boxes, and then working toward what you'll see with normal Linux user mode tools. (More technical details are in later sections.) One thing you won't notice is designed-in compatibility problems. Apart from some constraints on how you set up high speed devices, all your USB 1.1 hardware works just fine with USB 2.0 systems.

Updated USB Logos

One thing that you should watch for, and use to your advantage, is a new testing and branding program. Earlier USB peripherals sometimes had compatibility problems, and the tighter electrical requirements of USB 2.0 could have aggravated that issue. Instead, there are new USB 2.0 logos and a testing program that must be passed before peripherals are allowed to use them. That is, this isn't purely a marketing gimmick, there's actually some value wrapped up in this logo. Here are the new and old USB logos:

New USB 2.0 Logo
high speed labeled by the top stripe ... the two-color version highlights that in red, sometimes it's one-color.
Old USB 1.1 Logo (no compatibility testing done)

Be cautious about "high speed" peripherals that for any reason don't display that new logo. Those devices may not work very well, and it'll be your fault for encouraging vendors that sell nonconformant devices.

Hubs and Cabling

One big win for the USB 2.0 upgrade is that cables don't need to change. With the possible exception of some low quality cables that may not even handle USB 1.1 very well, you can keep using your existing USB cables. There was no need to switch to optical signal transmission, or anything similarly incompatible. There are new "Mini-B" cables, that can help eliminate the need for proprietary connectors on many small USB peripherals. (Think of a camera, cell phone, or PDA; classic B sockets take up way too much space.) However, some people report they need to avoid using long USB cables. If you're using long cables and having problems enumerating, try using shorter cables.

USB 2.0 hubs are special. Not only do they support high speed devices (older USB 1.1 hubs can't), but also because they all include "transaction translator" support that helps prevent full and low speed devices from wasting most of the USB bandwidth. See the later section on backwards compatibility for information about how this impacts end users with high speed buses whose devices may not all operate at high speed.

USB "On-The-Go" (OTG)

There is also a supplement to USB 2.0 called USB "On-The-Go" (OTG) which supports point-to-point peer style hookups for USB devices that are often used without a PC host. Few end-user OTG products exist yet; newer embedded Linux systems can be used to implement them. OTG relies heavily on those new USB "Mini" connectors, and supports low power operation (battery friendly). It also defines a modified USB 2.0 logo:

USB OTG Logo
full-speed version
(without high speed top stripe)

The key change in OTG is defining a new "Dual-Role" type of peripheral, which can become a low-power USB host when you connect it to another peripheral. Most OTG-capable peripherals will have special Mini-AB sockets (new in OTG). Because of how the USB "mini" plugs and jacks work, Mini-AB sockets accept either the Mini-B peripheral jack at one end of a USB cable or the (new in OTG) Mini-A host jack at its other end. Use the peripheral end, and they start out as a peripheral. Use the host end, and they start out like a USB host ... so that you could print directly from your camera or phone, hook a keyboard up to your PDA, or swap songs with your friend's MP3 player. If you connect two different dual-role devices, the "wrong" one may be initialized as the host. In that case, the optional OTG Host Negotiation Protocol (HNP) lets devices switch roles between "host" and "device" instead of forcing users to switch the cable around.

Host Controllers and Backwards Compatibility

You can connect USB 2.0 peripherals to USB 1.1 hosts and hubs, and they should work just fine ... but at 12 Mbit/sec, not at 480 Mbit/sec.

To get "high speed" behavior you'll need an updated host controller. It must support "USB 2.0 high speed", through the "EHCI" standard. Today you can get those as PCI cards, usually with a three or five port controller from NEC, or sometimes a four port one from Philips or VIA. More importantly, essentially all current generation PC motherboard silicon includes an EHCI controller built in. Linux users have reported success on most of these, with chips from ALI, Intel, NVidia, SiS, VIA, and others. (That's in alphabetical order; I'm not intending to slight any vendors.) See the section on Linux support (later) for more specific information.

You may also need newer hubs with USB 2.0 support. Probably the most important aspect of such hubs is how they support trees of devices that mix both high speed and full (or low) speed devices. The short version of the story is that to get high speed transfers out of a high-speed capable device, you must hook it up through an EHCI controller (that's using an EHCI driver!), and any hubs between the host and the device must only be USB 2.0 hubs.

That is, a tree of USB devices can start out with a high speed root hub, but if you plug in any USB 1.1 hubs to that tree, USB devices on branches below that hub will only operate at slower full/low (USB 1.1) speeds ... even if it's a USB 2.0 device. For now the lesson is that if you want to use a device at high speed, double check it after cabling things up. You can do this with "usbfs".


Changes Visible to Linux Users

Beyond those general issues, Linux users will notice a few changes if they poke around through what the kernel tells them about their hardware.

"usbfs" and /proc/bus/usb/devices

You may know "usbfs" through its original, and somewhat confusing name, of "usbdevfs". The name changed because it was completely unrelated to "devfs".

If you use "usbfs" (perhaps through scripts like usbtree or tools like usbview) you will notice a few minor changes. Most notably, the USB version for some devices will be "2.0", and those devices will report their speed as "480Mb/s" when they're running at high speed. (In compatibility mode, at full speed, they'll say "12Mb/s".) Here's what usbtree shows for some full speed devices hooked up to an USB 2.0 controller. Several are connected through a USB 2.0 hub, and there's a USB 1.1 hub (with no devices) hooked up to another root hub port.

/:  Bus 03.Port 1: Dev 1, Class=root_hub, Driver=ohci-hcd/2p, 12M
/: Bus 02.Port 1: Dev 1, Class=root_hub, Driver=ohci-hcd/3p, 12M
|__ Port 1: Dev 2, If 0, Class=hub, Driver=hub/4p, 12M
/: Bus 01.Port 1: Dev 1, Class=root_hub, Driver=ehci-hcd/5p, 480M
|__ Port 2: Dev 2, If 0, Class=hub, Driver=hub/4p, 480M
|__ Port 1: Dev 3, If 0, Class=>ifc, Driver=pegasus, 12M
|__ Port 4: Dev 8, If 0, Class=hub, Driver=hub/3p, 12M
|__ Port 1: Dev 9, If 0, Class=HID, Driver=hid, 12M

Some of the endpoint descriptors may change. Maximum packet sizes can be bigger, and polling intervals for periodic transfers will sometimes be measured in microseconds (like 250us), not milliseconds (like 2ms), and you may even see NAK rates for bulk endpoints. For example, this descriptor is for one USB 2.0 CD-RW when it's running at high speed:

T:  Bus=01 Lev=01 Prnt=01 Port=01 Cnt=01 Dev#=  2 Spd=480 MxCh= 0
D: Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs= 1
P: Vendor=05ab ProdID=0060 Rev= 2.10
S: Manufacturer=In-System Design
S: Product=USB Storage Adapter
S: SerialNumber=2201010A0247C8AB
C:* #Ifs= 1 Cfg#= 2 Atr=c0 MxPwr= 98mA
I: If#= 0 Alt= 0 #EPs= 3 Cls=08(stor.) Sub=06 Prot=50 Driver=usb-storage
E: Ad=01(O) Atr=02(Bulk) MxPS= 512 Ivl=125us
E: Ad=82(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
E: Ad=83(I) Atr=03(Int.) MxPS= 2 Ivl=32ms

Here's the descriptor for the same CD-RW when there's no EHCI driver, so it's running at full speed (may not be a good idea to burn CDs at this speed though):

T:  Bus=02 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#=  2 Spd=12  MxCh= 0
D: Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs= 1
P: Vendor=05ab ProdID=0060 Rev= 2.10
S: Manufacturer=In-System Design
S: Product=USB Storage Adapter
S: SerialNumber=2201010A0247C8AB
C:* #Ifs= 1 Cfg#= 2 Atr=c0 MxPwr= 98mA
I: If#= 0 Alt= 0 #EPs= 3 Cls=08(stor.) Sub=06 Prot=50 Driver=usb-storage
E: Ad=01(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms
E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms
E: Ad=83(I) Atr=03(Int.) MxPS= 2 Ivl=32ms

Other than that "480Mb/s" speed rating, most of that per-device usbfs information will only be interesting to folk working with device drivers. That "480Mb/s" in the descriptor for your device will be a sign that you've cabled it up correctly (so it runs at high speed). But there are also differences you may notice if you look at the root hub support for each of your systems USB busses.

USB 1.1 "Companion Controllers"

Perhaps the most curious thing is that when you plug in a full (or low) speed device to a connector on your high speed USB controller, it will be connecting to a different bus than when you plug in a high speed device to that same USB "A" socket on your PC! In the CD-RW example above, the bus number changed. Sometimes the port number will also change. (OK, so maybe you wouldn't have noticed.)

That's because of how the controllers work. Here's how /proc/bus/usb/devices looks on one system with a five port NEC EHCI based controller, and nothing hooked up to it. I added some whitespace and highlighting so you can see what's going on a bit better:

T:  Bus=03 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#=  1 Spd=12  MxCh= 3
B: Alloc= 0/900 us ( 0%), #Int= 0, #Iso= 0
D: Ver= 1.10 Cls=09(hub ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1
P: Vendor=0000 ProdID=0000 Rev= 2.05
S: Manufacturer=Linux 2.5.8 ohci-hcd
S: Product=NEC Corporation USB
S: SerialNumber=00:0b.0
C:* #Ifs= 1 Cfg#= 1 Atr=40 MxPwr= 0mA
I: If#= 0 Alt= 0 #EPs= 1 Cls=09(hub ) Sub=00 Prot=00 Driver=hub
E: Ad=81(I) Atr=03(Int.) MxPS= 2 Ivl=255ms

T: Bus=02 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#= 1 Spd=12 MxCh= 2
B: Alloc= 0/900 us ( 0%), #Int= 0, #Iso= 0
D: Ver= 1.10 Cls=09(hub ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1
P: Vendor=0000 ProdID=0000 Rev= 2.05
S: Manufacturer=Linux 2.5.8 ohci-hcd
S: Product=NEC Corporation USB (#2)
S: SerialNumber=00:0b.1
C:* #Ifs= 1 Cfg#= 1 Atr=40 MxPwr= 0mA
I: If#= 0 Alt= 0 #EPs= 1 Cls=09(hub ) Sub=00 Prot=00 Driver=hub
E: Ad=81(I) Atr=03(Int.) MxPS= 2 Ivl=255ms

T: Bus=01 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#= 1 Spd=480 MxCh= 5
B: Alloc= 0/800 us ( 0%), #Int= 0, #Iso= 0
D: Ver= 2.00 Cls=09(hub ) Sub=00 Prot=01 MxPS= 8 #Cfgs= 1
P: Vendor=0000 ProdID=0000 Rev= 2.05
S: Manufacturer=Linux 2.5.8 ehci-hcd
S: Product=NEC Corporation USB 2.0
S: SerialNumber=00:0b.2
C:* #Ifs= 1 Cfg#= 1 Atr=40 MxPwr= 0mA
I: If#= 0 Alt= 0 #EPs= 1 Cls=09(hub ) Sub=00 Prot=00 Driver=hub
E: Ad=81(I) Atr=03(Int.) MxPS= 2 Ivl=256ms

Yes, three USB buses on one controller card! (The PCI card is 00:0b but each bus has a different PCI function number.) And it looks like there's a total of ten ports (sum the "MxCh" entries saying how many children the root hubs have), not five ... how can that be?

The answer is that the two OHCI "companion controllers" are used along with the EHCI controller, and a silicon switch connects each port to only one controller at a time. When an EHCI driver runs, all ports start out connected to EHCI. When EHCI detects a full or low speed device on a port, that port is switched over to one of the companion controllers. High speed devices it keeps for itself ... so each port seems to connect to either EHCI or its companion controller (never both!) based on whether it runs at high speed or not. If there's no EHCI driver there to handle high speed devices, then everything gets treated as full or low speed since the switch won't connect things to the EHCI controller. (Companion controllers won't necessarily be OHCI; some are UHCI.)

So to fully use a USB 2.0 host controller you must still use an OHCI or UHCI host controller driver, as you've likely been doing already. And if that's the only driver you have, you can still use hardware that includes USB 2.0 support ... it just won't be as fast until you upgrade to an OS version with USB 2.0 support. In the big picture that's a great migration story for the core USB 2.0 technology: the hardware can upgrade, and the software follows later when it's convenient for end users. (Much like most vendors' stories for migrating from one generation of CPU, or instruction set, to the next one.)

The USB Host controllers in many embedded systems would rather not spend silicon for companion controllers, so some of them avoid this by embedding a transaction translator into the controller's root hub. That's not standardized, but Linux already supports one such product (from ARC).


USB 2.0 Hubs have "Transaction Translators" (TTs)

OK, this section talks about what makes USB 2.0 tricky. And it's not all that user visible, so you can safely skip reading it if you're one of the many Linux users who just wants a top quality OS (or a Free one) and aren't very concerned about all the underlying technology. If you want to skip this, remember just this one thing: hubs with more than one TT may support more active low and full speed devices, especially more webcams or audio devices.

If you're writing a device driver, you may want to know about this, since it can affect how you write your driver. At this writing, not all transaction translator features are used by Linux. Also, since those code paths aren't used much yet, a number of shortcuts have been taken, which limit throughput. (A mostly-functional patch is available for 2.6.10, removing those shortcuts.)

Split Transactions

USB 2.0 gets some of its backward compatibility through a technique called split transactions that's used in many other buses. Many disk interface technologies, for example, support concurrent requests to different devices (like USB does), and split their requests into a "start" phase, disconnecting, and reconnecting later for a "complete" phase. That lets the bus be used for other purposes while some slow I/O completes ... like a disk drive seeking and reading several sectors, or (in the USB case) like a 1.5 MBit/sec mouse delivering its motion event.

In the case of a USB 2.0 host talking to a USB 1.1 device, it does so either through a companion controller (so it's really acting as a USB 1.1 host), or through a transaction translator in a USB 2.0 hub. The host talks to the translator at high speed, and then the translator performs the full or low speed I/O to that USB 1.1 device. It buffers data in either direction as required, and later sends the results back to the host at high speed. A hub can have just one translator, or one per port. With just one translator, a hub can only use as much bandwidth as a USB 1.1 host can. With more translators, each port can use that much bandwidth.

So for example, each of the ports on the hub might have a full speed webcam, each of which is using ten megabits per second of I/O at the same time. With less capable hubs, only one port on that hub might be able to operate at that speed at a time, supporting only the bandwidth of a USB 1.1 bus.

Using Transaction Translators

From the perspective of a Linux USB 2.0 host, there are two ways it talks to USB 1.1 devices through transaction translators. Some requests do this almost transparently, like control requests and (full speed only) bulk data transfer. In those cases, the host must tell the EHCI controller that it's talking through a transaction translator, and maybe be ready to recover from some errors, but for most purposes there's control and bulk requests are completely "hands off". That means many USB 1.1 device drivers will continue to work just fine through a USB 2.0 hub ... many network adapters, modems, digital still cameras, MP3 players, disk drives, and similar devices won't need anything more.

Then there are the requests that need a lot of hands-on attention: periodic transfers like interrupt and (full speed only) isochronous ones. Because these are all reserved-bandwidth transacton types, they can't be automated as readily as control and bulk (which can opportunistically make progress whenever periodic transfers aren't active). The result is a lot of hub-related complexity in the EHCI driver, making sure that the periodic transfers are safely scheduled and that transaction translators don't get overcommited. Periodic transfers are already the most complex type in USB (though their API got simpler in the Linux kernel 2.6 series), so to some extent it's just one more consideration when scheduling,

For example, suppost a USB 1.1 periodic transfer is to be worked on every eight frames (milliseconds). That's going to go through a specific transaction translator; the transfer needs a time when that translator isn't in use, and when there's also bus bandwidth. The EHCI driver needs to schedule a "start split" (a bit in an 's-mask') sometime in one microframe, and a "complete split" (bits in a 'c-mask') in some later microframe, and ensure that between the start and completion no other request uses that translator. Isochronous transfers can be bigger, and are managed by EHCI using a different type of data structure, but in both cases you can see that there's a fair amount of housekeeping involved in tracking what requests are active.


Driver-Visible Changes in USB 2.0

The most visible change was the addition of "high speed" devices and transfers. In a Linux USB device driver, you can tell if the device is high speed (and thus whether its transfers will be at high speed!) by testing whether dev->speed == USB_SPEED_HIGH. You've been able to do that since about the 2.4.10 kernel, but you probably didn't have high speed devices to work with then.

The rules for full and low speed transfers have not changed, but some rules changed for high speed transfers. (You may have noticed some of those changes when comparing the high speed and full speed usbfs information shown above for the CD-RW.) In a few cases drivers need to have code that knows which rules apply, but mostly the changes will be transparent to correctly written drivers. Those changes include:

  • Maximum packet sizes for control transfers are fixed at 64 bytes, and for bulk transfers they are fixed at 512 bytes. For full and low speed, those limits are smaller and can also vary between devices. Don't hard-wire maxpacket sizes in drivers that will handle high speed devices (and their full-speed modes).
  • Maximum packet sizes for interrupt transfers can now be up to 1024 bytes. (For full and low speed, those limits are much smaller.) Likewise for ISO transfers (which previously had a curious 1023 byte limit).
  • There are now eight "microframes" per frame. A useful number to keep in mind is that thirteen bulk packets of 512 bytes each can be exchanged in one microframe. (At full speed, nineteen bulk packets of 64 packets could be exchanged in one frame. High speed transfers can be more than forty times faster than full speed ones!) For devices that can operate at high speed, drivers need to queue more data, both with bigger per-urb buffers and multiple urbs, to get the most benefit from that higher speed.
  • Periodic transfers can only reserve up to eighty percent of the USB bandwidth (per microframe). In USB 1.1, up to ninety percent was available.
  • Periodic transfer periods are measured in microframes, not frames. Both ISO and interrupt transfer intervals now use a log2 encoding, where previously only ISO transfers used that encoding. (Interrupt transfers can now have larger or smaller periods.) Drivers will need to interpret endpoint->bInterval differently for high speed devices, and also set urb->interval accordingly. Use usb_fill_int_urb() correctly, so this is done for you.
  • Periodic transfers can support a "high bandwidth" mode, where up to 3 packets (3KB at most) per microframe can be transferred. This shows up in a new field in endpoint descriptors. Drivers will need to interpret usb_maxpacket() differently for high speed, since that holds the new bit field as well as the original one. (With USB 1.1 devices, periodic transfers only involve one packet each period.)
  • EHCI provides less detailed error indicators than OHCI or UHCI. This means that drivers for USB 1.1 devices should retest for good behavior while connecting through a transaction translator in a USB 2.0 hub. Try things like unplugging devices while they're actively in use. It's likely they'll see EPIPE (endpoint stall) errors in some cases where previously they saw ETIMEDOUT (ohci) or EILSEQ (uhci). Unlike true endpoint stalls, usb_clear_halt() won't be able to talk to the device. (Your driver does have code to recover correctly from halted endpoints, doesn't it? It should!)

There are also protocol changes that should be invisible to most device drivers ... except in some cases for the host or device controller drivers, or the hub driver:

  • There's a new "other speed configuration" descriptor for devices that can work at both full and high speed. When a device is working at full speed, it would usually have different descriptors for high speed operation ... see the CD-RW example above. You don't need to re-enumerate at the other speed to see those descriptors.
  • "Split transactions" use a new feature of USB 2.0 hubs, the "transaction translator, which makes more efficient use of USB bandwidth. (All transactions run at high speed. Hubs build in buffering and logic for full or low speed speed operations.)
  • NYET transactions on the wire, used to detect that split transactions are not yet complete.
  • PING transactions on the wire help flow control to high speed bulk or control endpoints.
  • DATA2 and MDATA transactions on the wire are used with isochronous transfers.
  • The hub descriptor defines a few new fields, and uses the protocol number to say whether each port has its own transaction translator.

USB "Gadget" API; and OTG

As Linux gets embedded more widely inside USB peripherals (not just USB hosts), the USB "function" or "target" drivers have been getting more attention. The original Linux-USB programming interface had only a host side model: one master talking to many targets (like a web client talking to many servers). It didn't support the drivers running inside USB devices.

A peripheral side Linux-USB gadget API is now standard with 2.4 and 2.6 kernels. That framework currently supports at least a dozen different types of USB peripheral controller hardware under Linux. While it resembles the original host-side programming interfaces (at least in terms of submitting asynchronous requests, and in terms of shared core data structures), it must treat USB busses very differently from a host side API. That's because implementing the target function only involves responding to a single USB Host (like a web server only responding to one client at a time). Also, target side drivers can never initiate control requests, they can only respond to them.

Once Linux supported both "host" and "gadget" USB APIs (at all device speeds), it clearly had almost every programming interface needed to implement OTG compliant devices. Courtesy of Texas Instruments, Linux 2.6.9 kernels include an implementtion of OTG on Linux; that first implementation supports TI's OMAP processors, used in wireless devices.


Linux Status

People have been using USB 2.0 with usb-storage devices from Linux hosts since June 2001. But it was only towards the end of that year, a short while before Linus created the 2.5 development branch, that other USB 2.0 devices (notably, hubs) began to be available. So while some changes for USB 2.0 were rolling into 2.4 kernels through the year 2001, largely done by about 2.4.10, the most tricky stuff (the ehci-hcd driver) stayed separate until the 2.5 kernel branched. All current Linux distributions include EHCI support, and the end-user bug reports have been helping to stabilize that driver.

Host Controller Driver Support

At this writing the "ehci-hcd" driver is not as well proven as the OHCI or UHCI drivers, so parts of it (especially those parts interacting with USB 2.0 hubs and transaction translators) are still experimental, but it's just fine for many purposes, including espcially providing quick access to high speed disks. (Where "quick" often means up to 30 MByte/second, with off-the-shelf hardware.)

  • The Linux 2.6 kernel has the most up-to-date USB 2.0 support, as well as quite a number of other USB updates and cleanups.
  • The 2.4.19 kernel was the first to bundle a 2.4 based version of the ehci-hcd driver, but avoid using anything older than 2.4.22. Expect any 2.4 version to be less current than the 2.5 version; it's also not being updated to match 2.6 any more.
  • Older Linux distributions include a 2.4.18 based version that's much like the original 2.5 patch, though more recent distributions (including RedHat 9) match a good 2.4.21-pre level.

In terms of functionality, the latest driver:

  • Supports all four USB transfer types at high speed: control, bulk, interrupt, and isochronous. However, scheduling for interrupt transfers currently takes shortcuts which prevent them from using much bandwidth. (Or handling certain system configurations. However, a patch for 2.6.10 is being tested which removes those shortcuts.) And nobody's really done much yet with the isochronous code, although kernel 2.6.2 (or 2.4.25) and later has a rewritten version that handles high bandwidth, and is a lot more capable.
  • Has partial support for split transactions (full and low speed transfers) through USB 2.0 hubs:
    • Control and bulk transfers work, though older versions may not recover from some errors appropriately. That means: that while you should be able to use many USB 1.1 devices like disks and still cameras through such hubs, you might also run into some failure modes that can't yet be recovered. (And some device drivers might also need updates to handle new failure modes, as noted above.)
    • Full and low speed interrupt transactions work, taking the same scheduling shortcuts as high speed interrupt transfers take. So most keyboards and mice should work on USB 2.0 hubs, if you're using one of the more recent kernels. (Some serial port and Bluetooth adapters aren't compatible with those shortcuts though.)
    • Full speed isochronous transfers work somewhat through USB 2.0 hubs, in current 2.6 kernels. But they're not robust yet; for example, USB speakers will sometimes work, but there may also be an audible buzz in addition to (or instead of!) the desired sound. Eventually of course a dozen USB 1.1 webcams will easily coexist at full data rate on a single USB 2.0 bus, using USB 2.0 hubs.
  • The current kernels support BIOS handshaking (transferring "ownership" of EHCI from BIOS/SMM to Linux, as is done for OHCI or UHCI). That depends on EHCI hardware features that took time to become generally available with BIOS implementation support. Recently some BIOS versions have appeared which don't seeem to cooperate fully with Linux (mis-implementing that handshake).
  • Works with a variety of EHCI silicon implementations. NEC led the market by over a year, but now implementations from Intel, NVidia, Philips, VIA, SiS, ALI, Genesys, and others work with Linux.
  • Should tolerate more abuse on CardBus adapters. Before the 2.5.29 kernel, you needed to manually "rmmod" ehci-hcd (and often ohci-hcd) to cope with a sequencing bug in the CardBus shutdown.

You'll find that most PCI USB 2.0 add-in cards (and CardBus/PCMCIA ones) use the NEC silicon or the VT62x2, though there are other vendors. (Including ALI.) The cards that do both USB 2.0 and FireWire have for some reason been a problem for many people, even those without built-in PCI bridges. Avoid the VT6202 cards; but VT6212 should be OK.

Some folk have problems with the CardBus versions, because Linux hasn't always managed to get the IRQs assigned correctly on their particular laptop make/model. (IRQs are a general problem, BIOS and ACPI problems abound.) Once such BIOS/PCI level problems get resolved, the ehci-hcd driver works with those CardBus configurations too. It may be very important to use an external power supply for the CardBus adapter. (It seems like CardBus can't supply all of the power needed by bus-powered USB devices, without help: half an Ampere from each port. With longer USB cables, you may also need more power to drive the signals correctly.)

If you're using a CardBus adapter with an older driver version, you may need to manually remove the driver (with rmmod) before a CardBus eject (including cardctl eject) or system shutdown; the CardBus shutdown doesn't shut down drivers when it should, so that's the only "clean shutdown" solution..

See the linux/Documentation/usb/ehci.txt file in your Linux kernel source distribution for some more information. As always with drivers still in development, if you have any problems, try the latest code (preferably in the 2.5 kernel, otherwise in the latest 2.4 code) to see if the problem has been fixed yet. And if not, report problems to the linux-usb-devel mailing list.

Device Driver Support

High speed storage devices, and to some extent hubs, seem to be the most USB 2.0 devices so far. High speed scanners and printers are available, and there are early reports of success using them.

Most full and Low speed (USB 1.1) devices will work when connected to USB 2.0 root hubs, using their current drivers, since they'll be handled by the companion controllers. Many of them should also work when connected to USB 2.0 external hubs, subject to the restrictions desribed earlier. (Which, for the latest code, amounts to no webcam or audio support yet.)

Device Driver Comments
USB 2.0 hubs hub (usbcore) USB 2.0 hubs work, but haven't been widely stressed (especially in terms of faults happening during transaction translation). The hubs with Cypress hub chips have multiple transaction translators; get that kind if you're using many full speed audio or video devices.
Disks, CD-RW, USB-FLASH, etc usb-storage Linux USB 2.0 support seems to work pretty well for the usb-storage devices that now exist, though it's slower on 2.4 since the usb-storage driver does not queue its USB requests. (Where "slower" still tops 10 MByte/sec on most hardware.) Starting with about 2.5.45, storage uses the new usb_sg_submit() call to queue all I/Os in a scatterlist at once, so nothing should be in the way of letting your hardware achieve 20+ MByte/sec (except maybe bugs that aren't yet fixed, or slow disks).
BackPack USB Drives usb-storage Micro-Solutions has provided software to set up their devices with hotplugging, so that you can easily connect theeir drives to Linux. Available in several formats, including RPM.
Archos MP3 Jukebox usb-storage Older kernels may need a tweak to usb-storage error handling, or a workaround: start the Archos and let it boot up before you load or hotplug the usb-storage module..
ASIX AX88172 (10/100 Ethernet Adapter) usbnet A variety of products, including the D-Link DUB-E100, Hawking UF200, and Netgear FA120 all use this technology. Running at high speed, all of them should give much better throughput than similar full-speed products. This driver is merged into usbnet in 2.4 and 2.6 kernels.
ALI M5632 Host-to-Host Link usbnet Adapter cables based on this chip are available from several different vendors, and can provide good throughput to another Linux system.
IOGear Host-to-Host Link usbnet (patch needed) Press Release
Orange iBOT2 WebCam ovfx2, evolved from ov511 This is the first USB 2.0 webcam announced.
Cypress EZ-USB FX2 custom ... depends on what your firmware makes it do These are 8051 microcontrollers with support for high speed transfers, designed for use inside USB devices and with custom firmware. The fxload software lets you download that firmware. For the start of one interesting Linux-based example (hosted at sf.net), see the SR-1 software radio.
NetChip 2280 custom ... depends on what your firmware makes it do These are PCI based controllers with support for high speed transfers, designed for use inside USB devices and with custom firmware. Linux-USB gadget support is available, so you can implement that firmware under Linux. One such driver implemens a network interface, and others are under development.

Regardless of what type of high speed device you use, USB hotplugging works the same as it always has on Linux.

User mode device drivers should be able to use the usbfs APIs as usual. They may be able to tell that they're talking to USB 2.0 devices by details in the device descriptors (such as 512 byte bulk packets); the Java USB APIs expose such information more directly. The libusb APIs (in C) don't yet.


References

2007年5月3日星期四

linux下USB器件驱动程序相关

今天上网,查找USB驱动相关的问题时找到一个好网站(www.linux-usb.org),若要做linux下的USB 驱动,到这个网站可以找到很多好东西。今天匆匆看了一下,了解了linux的USB从设备(器件)驱动的一些知识,记录如下。

一. USB盘的实现

linux下U盘的实现其实很简单,基于一个g_file_storage的模块,使用文件或其他块设备(如MTD设备)作为U盘的存储器即可,不用自己编写驱动程序。以文件为例的具体步骤如下所示:

· 创建文件存储器

[root@localhost data]# dd bs=1M count=64 if=/dev/zero of=/root/data/backing_file

· 用fdisk对该文件存储器分区,可以不做,但有的版本的windows会不认这个U盘

[root@localhost data]# fdisk file=/root/data/backing_file

· 格式化该文件存储器上的分区,若未使用fdisk,则如下操作

[root@localhost data]# mkdosfs /root/data/backing_file

· 加载文件存储器,实现U盘

[root@localhost data]# modprobe g_file_storage file=/root/data/backing_file

简单的几步操作完成后,将你的目标板通过USB线作为从设备连接到PC上,在PC端即可见到这个U盘。使用fdisk对文件存储器分区后的格式化步骤参考文章www.linux-usb.org/gadget/file_storage.html。

二. USB网卡的实现

linux下的从设备网卡的实现是基于g_ether的模块,加载该模块即可作为一个ethernet网络设备连接到PC主机。

三. USB串口的实现

linux下的从设备USB串口模块实现了从设备端的USB转串口,g_serial使得运行嵌入式linux的小机作为一个串口设备通过USB连接到PC主机,PC主机可以使用MINICOM等登录到linux小机上。



由上面这些可以看到,linux对USB从设备(器件)的支持还是比较完善的,使用也比较方便。另外,linux还支持用户空间的对USB器件的直接驱动,如设置USB器件的配置,接口,端点,直接读写USB器件的端点来接收和发送数据,即用户空间的驱动,性能和内核的驱动几乎没什么差别。和当年在windows下编写USB驱动比起来,要好用多了。

有空再看看linux下USB多接口是如何实现的。



参考文档

Linux的USB从设备(器件)驱动API www.linux-usb.org/gadget

http://blog.csdn.net/flyfish30/archive/2006/12/15/1444829.aspx

2007年4月29日星期日

实例解读 linux 网卡驱动

在此仅仅讨论网络设备驱动的一般写法,有关硬件部分的相关代码由于硬件规格不同,予以省略。有什么地方错误,或补充,欢迎大家提出。

1, 驱动模块的加载和卸载

如果网络设备(包括wireless)是PCI规范的,则先是向内核注册该PCI设备(pci_register_driver),然后由pci_driver数据结构中的probe函数指针所指向的侦测函数来初始化该PCI设备,并且同时注册和初始化该网络设备。

如果网络设备(包括wireless)是PCMCIA规范的,则先是向内核注册该PCMCIA设备 (register_pccard_driver),然后driver_info_t数据结构中的attach函数指针所指向的侦测函数来初始化该 PCMCIA设备,并且同时注册和初始化该网络设备。

static int __init tg3_init(void)
{
//先注册成PCI设备,并初始化,如果是其他的ESIA,PCMCIA,用其他函数
return pci_module_init(&tg3_driver);
}

static void __exit tg3_cleanup(void)
{
pci_unregister_driver(&tg3_driver);//注销PCI设备
}

module_init(tg3_init); //驱动模块的加载
module_exit(tg3_cleanup); //驱动模块的卸载

申明为PCI设备:
static struct pci_driver tg3_driver = {
.name = DRV_MODULE_NAME,
.id_table = tg3_pci_tbl, //此驱动所支持的网卡系列,vendor_id, device_id
.probe = tg3_init_one, //初始化网络设备的回调函数
.remove = __devexit_p(tg3_remove_one), //注销网络设备的回调函数
.suspend = tg3_suspend, //设备挂起函数
.resume = tg3_resume //设备恢复函数
};


2,PCI设备探测函数probe,初始化网络设备
static int __devinit tg3_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{

//初始化设备,使I/O,memory可用,唤醒设备
pci_enable_device(pdev);

//申请内存空间,配置网卡的I/O,memory资源
pci_request_regions(pdev, DRV_MODULE_NAME);
pci_set_master(pdev);

//设置DMA属性
pci_set_dma_mask(pdev, (u64) 0xffffffffffffffff);

//网卡 I/O,memory资源的启始地址
tg3reg_base = pci_resource_start(pdev, 0);

//网卡I/O,memory资源的大小
tg3reg_len = pci_resource_len(pdev, 0);

//分配并设置网络设备
dev = alloc_etherdev(sizeof(*tp));

//申明为内核设备模块
SET_MODULE_OWNER(dev);

//初始化私有结构中的各成员值
tp = dev->priv;
tp->pdev = pdev;
tp->dev = dev;
……
//锁的初始化
spin_lock_init(&tp->lock);

//映射I/O,memory地址到私有域中的寄存器结构
tp->regs = (unsigned long) ioremap(tg3reg_base, tg3reg_len);
dev->irq = pdev->irq;

//网络设备回调函数赋值
dev->open = tg3_open;
dev->stop = tg3_close;
dev->get_stats = tg3_get_stats;
dev->set_multicast_list = tg3_set_rx_mode;
dev->set_mac_address = tg3_set_mac_addr;
dev->do_ioctl = tg3_ioctl;
dev->tx_timeout = tg3_tx_timeout;
dev->hard_start_xmit= tg3_start_xmit;

//网卡的MAC地址赋值dev->addr
tg3_get_device_address(tp);

//注册网络设备
register_netdev(dev);

//把网络设备指针地址放入PCI设备中的设备指针中
pci_set_drvdata(pdev, dev);
}

3,注销网络设备
static void __devexit tg3_remove_one(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
//注销网络设备
unregister_netdev(dev);
//取消地址映射
iounmap((void *) ((struct tg3 *)(dev->priv))->regs);
//释放网络设备
kfree(dev);
//释放PCI资源
pci_release_regions(pdev);
//停用PCI设备
pci_disable_device(pdev);
//PCI设备中的设备指针赋空
pci_set_drvdata(pdev, NULL);
}


4,打开网络设备
static int tg3_open(struct net_device *dev)
{
//分配一个中断
request_irq(dev->irq, tg3_interrupt, SA_SHIRQ, dev->name, dev);

/* int request_irq(unsigned int irq,
void (*handler)(int irq, void *dev_id, struct pt_regs *regs),
unsigned long irqflags,
const char * devname,
void *dev_id);

irq是要申请的硬件中断号。在Intel平台,范围0--15。
handler是向系统登记的中断处理函数。这是一个回调函数,中断发生时,系统调用这个函数,传入的参数包括硬件中断号,device id,寄存器值。
dev_id就是下面的request_irq时传递给系统的参数dev_id。
irqflags 是中断处理的一些属性。比较重要的有 SA_INTERRUPT,标明中断处理程序是快速处理程序(设置SA_INTERRUPT)还是慢速处理程序(不设置SA_INTERRUPT)。快速处理程序被调用时屏蔽所有中断。慢速处理程序不屏蔽。还有一个SA_SHIRQ属性,设置了以后运行多个设备共享中断。dev_id在中断共享时会用到。一般设置为这个设备的device结构本身或者NULL。中断处理程序可以用dev_id找到相应的控制这个中断的设备,或者用rq2dev_map找到中断对应的设备。*/


//初始化硬件
tg3_init_hw(tp);


//初始化收包和发包的缓冲区
tg3_init_rings(tp);

//初始化定时器
init_timer(&tp->timer);
tp->timer.expires = jiffies + tp->timer_offset;
tp->timer.data = (unsigned long) tp;
tp->timer.function = tg3_timer; //超时回调函数
add_timer(&tp->timer);

//允许网卡开始传输包
netif_start_queue(dev);
}


5,关闭网络设备
static int tg3_close(struct net_device *dev)
{
//停止网卡传输包
netif_stop_queue(dev);
netif_carrier_off(tp->dev);
//去除定时器
del_timer_sync(&tp->timer);
//释放收包和发包的缓冲区
tg3_free_rings(tp);
//释放中断
free_irq(dev->irq, dev);
}


6,硬件处理数据包发送
static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
len = (skb->len - skb->data_len);
//以DMA方式向网卡物理设备传输包。如果是wireless的话,需要根据802.11协议及硬件的规范从新填充
//硬件帧头,然后提交给硬件发送。
mapping = pci_map_single(tp->pdev, skb->data, len, PCI_DMA_TODEVICE);
tp->tx_buffers[entry].skb = skb;
pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, mapping);
//硬件发送
tg3_set_txd(tp, entry, mapping, len, base_flags, mss_and_is_end);
//记录发包开始时间
dev->trans_start = jiffies;
}


7,中断处理收包,发包
static void tg3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
//如果要收包
tg3_rx(tp);
//如果要发包
tg3_tx(tp);
}


8,发包
static void tg3_tx(struct tg3 *tp)
{
struct tx_ring_info *ri = &tp->tx_buffers[sw_idx];
struct sk_buff *skb = ri->skb;
//以DMA方式向网卡传输包完毕
pci_unmap_single(tp->pdev, pci_unmap_addr(ri, mapping),
(skb->len - skb->data_len), PCI_DMA_TODEVICE);
ri->skb = NULL;
dev_kfree_skb_irq(skb);
}


9,收包
static int tg3_rx(struct tg3 *tp, int budget)
{
struct sk_buff *copy_skb;
//分配一个包
copy_skb = dev_alloc_skb(len + 2);
copy_skb->dev = tp->dev;
//修改包头空间
skb_reserve(copy_skb, 2);
//加入数据到包中
skb_put(copy_skb, len);
//以DMA方式从网卡传输回数据
pci_dma_sync_single(tp->pdev, dma_addr, len, PCI_DMA_FROMDEVICE);
memcpy(copy_skb->data, skb->data, len);
skb = copy_skb;
//解析包的协议
skb->protocol = eth_type_trans(skb, tp->dev);
//把包送到协议层
netif_rx(skb);
//记录收包时间
tp->dev->last_rx = jiffies;
}


10, 读取包的网卡收发包的状态,统计数据
static struct net_device_stats *tg3_get_stats(struct net_device *dev)
{
//从硬件相关的寄存器读取数据,累加
//stats->rx_packets, stats->tx_packets, stats->rx_bytes, stats->tx_bytes等
}


11, 用户的ioctl命令系统调用
static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
struct mii_ioctl_data *data = (struct mii_ioctl_data *)&ifr->ifr_data;
switch(cmd) {
//ethtool程序命令的调用
case SIOCETHTOOL:
return tg3_ethtool_ioctl(dev, (void *) ifr->ifr_data);
//mii程序命令的调用
case SIOCGMIIREG: {
err = tg3_readphy(tp, data->reg_num & 0x1f, &mii_regval)
data->val_out = mii_regval;
return err;
}
……
}
}



12, PCI设备的挂起和恢复函数
static int tg3_suspend(struct pci_dev *pdev, u32 state)
{
//停用网卡的中断寄存器
tg3_disable_ints(tp);
//停止网卡收发包
netif_device_detach(dev);
//停止网卡某些硬件,fireware的一些功能
tg3_halt(tp);
//设置网卡的电源状态
tg3_set_power_state(tp, state);
}

static int tg3_resume(struct pci_dev *pdev)
{
//恢复网卡电源
tg3_set_power_state(tp, 0);
//允许网卡收发包
netif_device_attach(dev);
//初始化收发包的缓冲区
tg3_init_rings(tp);
//初始化网卡硬件
tg3_init_hw(tp);
//打开网卡中断寄存器
tg3_enable_ints(tp);
}



13,参数设置
在驱动程序里还提供一些方法供系统对设备的参数进行设置和读取信息。一般只有超级用户(root)权限才能对设备参数进行设置。设置方法有:

tg3_set_mac_addr (dev->set_mac_address)
当用户调用ioctl类型为SIOCSIFHWADDR时是要设置这个设备的mac地址。一般对mac地址的设置没有太大意义的。

dev->set_config()
当用户调用ioctl时类型为SIOCSIFMAP时,系统会调用驱动程序的set_config方法
用户会传递一个ifmap结构包含需要的I/O、中断等参数。

总结:

所有的Linux网络驱动程序遵循通用的接口。
设计时采用的是面向对象的方法。一个设备就是一个对象(net_device 结构),它内部有自己的数据和方法。一个网络设备最基本的方法有初始化,发送和接收。

Linux网络驱动程序的体系结构可以划分为四层:
网络协议接口,网络设备接口,设备驱动功能,网络设备和网络媒介层

网络驱动程序,最主要的工作就是完成设备驱动功能层。
在Linux中所有网络设备都抽象为一个接口,这个接口提供了对所有网络设备的操作集合。
由数据结构struct net_device来表示网络设备在内核中的运行情况,即网络设备接口。
它既包括纯软件网络设备接口,如环路(Loopback),也包括硬件网络设备接口,如以太网卡。

而由以dev_base为头指针的设备链表来集体管理所有网络设备,该设备链表中的每个元素代表一个网络设备接口。数据结构 net_device中有很多供系统访问和协议层调用的设备方法,包括初始化,打开和关闭网络设备的open和stop函数,处理数据包发送的 hard_start_xmit函数,以及中断处理函数等。

网络设备在Linux里做专门的处理。Linux的网络系统主要是基于BSD unix的socket机制。在系统和驱动程序之间定义有专门的数据结构(sk_buff)进行数据的传递。系统里支持对发送数据和接收数据的缓存,提供流量控制机制,提供对多协议的支持。

2007年4月28日星期六

Linux系统下USB摄像头驱动开发

http://blog.csdn.net/fengyv/archive/2006/05/22/749761.aspx

一、 Linux系统中的USB摄像头驱动程序
USB摄像头以其良好的性能和低廉的价格得到广泛应用。同时因其灵活、方便的特性,易于集成到嵌入式系统中。但是如果使用现有的符合Video for Linux标准的驱动程序配合通用应用程序,难以充分利用USB带宽,帧速不高,不易满足实时监控等要求。本文首先介绍在Linux系统下USB摄像头驱动编制的一般方法,然后说明在此基础上如何提高帧速。
USB设备驱动程序完全符合通用设备驱动的准则,不同的是内核提供了一些特别的API函数,方便驱动注册、销毁自己,例如usb_reSister()和usb_dereSister();2.4版的内核还提供了对于hotplug的支持。
1.1 USB摄像头驱动的一般编写方法
摄像头属于视频类设备。在目前的Linux核心中,视频部分的标准是Video for Linux(简称V4L)。这个标准其实定义了一套接口,内核、驱动、应用程序以这个接口为标准进行交流。目前的V4L涵盖了视、音频流捕捉及处理等内容,USB摄像头也属于它支持的范畴。
因此,USB摄像头的驱动应当与内核提供的视频驱动挂钩。即首先在驱动中声明一个video_device结构,并为其指定文件操作函数指针数组.fops,向系统注册。在应用程序发出文件操作的相关命令时,核心根据这些指针调用相应函数,并将该结构作为参数传递给它们。这样,就完成了驱动和核心之间的通信。例如:

static struct video_device vdev_template={……};
//声明video_device,指出挂接驱动
static struct file_operations ov511_fops={……};
//声明本驱动的文件操作函数指针
struct video_device*vdev=video_devdata(file);
//从文件指针中提取出video_device结构

在video_device结构中,有一个私有指针priv,可以将它指向一块保留内存。在这块内存中,保存着本驱动、本设备的相关初始化信息。这块内存的申请、初始化、指针指向等工作都是在USB驱动的枚举函数.probe中完成。这样,在枚举函数将控制权返还给系统后,因为内核不销毁保留内存,所以驱动仍然保留着自己的信息。这点与Windows系统中WDM驱动有异曲同工之处。当然,在驱动卸载函数中,应当将申请的各块内存全部释放。
1.2 使用双URB轮流通信
众所周知,USBl.1总线标准定义了控制、中断、批量、等时等四种管道。对于时间性极强但是准确度要求不高的视频捕捉应用来说,摄像头应当使用等时传输方式。为了尽可能快地得到图像数据,应当在URB中指定USB_ISO_ASAP标志。

urb->transfer_flags=USB_ISO_ASAP;//尽可能快地发出本URB

Linux系统中任何USB传输都通过URB实现。为提高速度,可以考虑扩大URB的缓冲,这样可以降低每个USB事务中握手信息所占比例,提高有效数据的传输速度。但是受限于总线带宽和具体的USB设备芯片,单纯扩大URB的缓冲不能无限制地解决问题。具体分析一下USB传输在操作系统中的实现:每次传输都要包括URB的建立、发出、回收、数据整理等阶段,这些时间不产生有效数据。因此可以建立两个URB,在等待一个URB被回收时,也就是图像正在被传感器采集时,处理、初始化另一个URB,并在回收后立刻将其发出。两个URB交替使用,大大减少了额外时间。工作流程如图1所示。
这个过程是在URB的完成例程中实现的,有两点需要注意:首先处理再次初始化的代码时间不能长,否则会造成完成例程的重人,如果确实来不及,可以在完成例程中设定标志,例如“数据采集好”旗语,由应用程序使用阻塞ioctl()来查询该旗语并做处理;其次由于CPU可能会在完成例程中停留较长时间,系统负担较大,可以在.open函数中初始化两个URB并将其发出,有限度地减轻系统负担。
1.3 使用双帧缓冲提高效率
Linux系统中,文件操作通常是由read、write等系统调用来完成。这些系统调用在驱动中的解决方法就是用copy_to_user()、copy_from_user()等函数在核态、户态内存空间中互相拷贝。但是对于大批量的图像数据,采用拷贝的方法显然会增加时间开销,因此用内存映射的方法解决。首先使用vmalloc()申请足够大的核态内存,将其作为图像数据缓冲空间,两个URB带回的图像数据在这里暂存;然后使用remap_page_range()函数将其逐页映射到用户空间中。户态的图像处理程序使用mmap()函数,直接读写核态图像缓冲内存,大大减少额外开销。
图像数据的处理可能要花费比较长的时间,不同的算法对于数据保留时间的要求也不一样。因此可以申请两帧图像缓冲,在处理一帧图像的同时,将两个URB带回的数据全部填充到另一帧缓冲中,这样可以免去时间冲突上的麻烦。
值得注意的是:这种方法要求时刻持有当前帧的序号、每一帧的起始地址等信息,不能将两帧图像混淆。这些信息可以保存在保留内存中,当前帧的数据整理、序号改变在URB完成例程中实现。
二、 V4L标准的改进
V4L标准目前已经发展到第二版V4L2,其基本思路与V4L相同。
2.1 标准分析
根据V4L标准,户态程序在需要一帧图像时,CPU的走向如图2。CPU按照123456的顺序完成一个循环。在这里,有一个细节被忽略:在完成例程中,也就是图2中步骤6,该URB被立刻发出,但是由于这时用户程序正在阻塞等待,没办法再次提出获得图像的申请,因此在判断有无新请求时,判断的结果必然是当前无请求,导致下一个URB带回的数据被驱动丢弃;由于核态、户态的切换需要一定的时间,加上户态多进程同步等开销,等到应用程序能够再次发出获得一副图像的申请时,已经有不止一个URB带回的数据被丢弃掉,这些URB包含的数据正好是新一帧图像的开始部分。因此驱动必须等到再下一帧图像才能保存数据、缓冲。这样凭白损失了一帧图像,帧速最少下降一半。
2.2 改进思路:不间断采集
为了解决这个问题,可以改进V4L标准作,使其增加新的功能:通过新的参数,让ioetl()函数通知驱动不间断采集、缓冲图像数据,轮流保存在两帧缓冲区中,并在一帧图像采集好后,设定“图像采集好”旗语。户态程序只需要发出一次“获得图像”请求,就可以通过阻塞等待该旗语,不断获得图像。在采集结束后,再次通过新的参数,让驱动停止缓冲即可。CPU工作流程图如图3。
注意到图2、图3,两种“判断有无新请求”的不同,即可发现新方法假定一直有请求,因此不丢弃每个URB带回的数据,轮流保存在两个帧缓冲内。
V4L已经作为约定俗成的标准被内核支持,因此如果使用全新的参数,工作量将相当巨大,并且不能和现有的应用程序兼容。考虑到现有的图像采集应用程序使用VIDIOCMCAPTURE作为参数,并提供帧序号,要求驱动将图像保存到指定序号的帧缓冲内。由于驱动通常仅仅提供几帧缓冲,因此该序号不会大于某个数字,如10。因此可以继续使用VIDIOCMCAPTURE参数,搭配较大的序号来表示新增的功能,例如用10000和10001来分别表示开始和停止缓冲图像数据的要求。驱动在收到VIDIOCMCAPTURE要求后,检查这个序号。如果小于10000,则按照正常的方法处理,否则按照改进方法。这种思路可以有效解决兼容性问题。
2.3 实验结果
在赛扬366、USBl.1接口的计算机平台上,采用上述不间断采集改进V4L标准,配合双URB、双帧缓冲等方法后,帧速提高两倍有余,有效数据传输速度达960KB/s,接近等时传输方式下USB总线的带宽极限。 推荐阅读:《rh9实现视频的捕获》,该文档中有详细的代码