对于大多数实际应用来说, 可以把USB总线当作一种高速串行端口考虑。如此在某些类型的嵌入式设备和应用中对它进行原型模拟是有意义的。StrongARM处理器的Linux内核提供现成的USB设备驱动专工于此,称作usb-char。
在希望与USB主机通信时,Linux USB设备应用程序只是打开对其usb-char设备节点(字符型,最大10,最小240)的连接,然后开始读写数据即可。read()和 write()操作将一直返回错误值直到USB主机连上为止。一旦连接建立和枚举完成,便开始通信,就像USB是一种点对点串行端口一样。
由于这种USB数据传递方法十分直接且实用,因此usb-char设备得到高效使用。它还为其它USB通信方法的实现提供了重要的参照基准。usb-char的实际动作从usbc_open()功能开始,部分内容示于列表1中。
static int usbc_open(struct inode *pInode, struct file *pFile)
{
int retval = 0;
/* start usb core */
sa1100_usb_open(_sb-char?;
/* allocate memory for in-transit USB packets */
tx_buf = (char*) kmalloc(TX_PACKET_SIZE, GFP_KERNEL | GFP_DMA);
packet_buffer = (char*) kmalloc(RX_PACKET_SIZE, GFP_KERNEL | GFP_DMA);
/* allocate memory for the receive buffer; the contents of this
buffer are provided during read() */
rx_ring.buf = (char*) kmalloc(RBUF_SIZE, GFP_KERNEL);
/* set up USB descriptors */
twiddle_descriptors();
/* enable USB i/o */
sa1100_usb_start();
/* set up to receive a packet */
kick_start_rx();
return 0;
列表1:打开USB上的串行连接
twiddle_descriptors ()功能建立起设备的USB描述符。在描述符全部建起后,准备从USB主机枚举并接收一个数据帧。kick_start_rx()所需的代码大多数情况下只是一种对sa1100_usb_recv() 的调用以建立回调而已。当USB主机发送数据包时,设备的内核通过回调调用rx_done_callback_packet_buffer()函数,把数据包的内容移入usb-char 设备点上由read()返回的FIFO队列。
主机
对于运行Linux的USB主机,usb-char相应的USB主机模块称为usbserial模块。大多数Linux版本都包括Usbserial模块,尽管通常不是自动装入。在USB与设备的连接建立之前,usbserial 由modprobe 或 insmod载入。
一旦USB设备开始枚举,主机上的应用程序便用usbserial设备点(字符型,最大188,最小0以上)之一与设备进行通信。这些节点通常命名为/dev/ttyUSBn。Usbserial模块在内核报文日志记录中报告它把哪个节点指定给USB设备使用:
usbserial.c: 通用转换器删除;
usbserial.c: 通用转换器当前连到ttyUSB0上。连接建立后,USB主机上的应用程序便通过读写指定的节点与USB设备进行通信。
Linux 主机上usbserial模块的一种替代选择是一种称作libusb(libusb.sourceforge.net)的库。这种库使用低层内核系统调用进行USB数据传输,而不是通过usbserial模块,在某种程度上跨Linux内核版本建立和使用时更方便。Libusb库还提供大量有用的调试功能,这一点在对运行在USB链路上的复杂通信协议进行除错时有帮助。用libusb与采用usb-char的USB设备进行通信时,Linux主机应用程序使用usb_open()函数建立与该设备的连接。然后应用程序使用usb_bulk_read()和usb_bulk_write()与设备交换数据。