Linux内核中usb设备侧驱动程序分成3个层次:UDC驱动程序、Gadget API和Gadget驱动程序。UDC驱动程序(USB控制器)直接访问硬件,控制USB设备和主机间的底层通信,向上层提供与硬件相关操作的回调函数。Gadget API是UDC驱动程序回调函数的简单包装,这部分程序内核都已经写好。Gadget驱动程序具体控制USB设备功能的实现,使设备表现出“U盘”、“虚拟串口”等特性。
简单看个usb 虚拟串口例子
Overview
--------
The gadget serial driver is a Linux USB gadget driver, a USB device
side driver. It runs on a Linux system that has USB device side
hardware; for example, a PDA, an embedded Linux system, or a PC
with a USB development card.
The gadget serial driver talks over USB to either a CDC ACM driver
or a generic USB serial driver running on a host PC.
Host
--------------------------------------
| Host-Side CDC ACM USB Host |
| Operating | or | Controller | USB
| System | Generic USB | Driver |--------
| (Linux or | Serial | and | |
| Windows) Driver USB Stack | |
-------------------------------------- |
|
|
|
Gadget |
-------------------------------------- |
| Gadget USB Periph. | |
| Device-Side | Gadget | Controller | |
| Linux | Serial | Driver |--------
| Operating | Driver | and |
| System USB Stack |
--------------------------------------
On the device-side Linux system, the gadget serial driver looks
like a serial device.
On the host-side system, the gadget serial device looks like a
CDC ACM compliant class device or a simple vendor specific device
with bulk in and bulk out endpoints, and it is treated similarly
to other serial devices.
The host side driver can potentially be any ACM compliant driver
or any driver that can talk to a device with a simple bulk in/out
interface. Gadget serial has been tested with the Linux ACM driver,
the Windows usbser.sys ACM driver, and the Linux USB generic serial
driver.
With the gadget serial driver and the host side ACM or generic
serial driver running, you should be able to communicate between
the host and the gadget side systems as if they were connected by a
serial cable.
The gadget serial driver only provides simple unreliable data
communication. It does not yet handle flow control or many other
features of normal serial devices.
内核版本:3.15 硬件:ATMEL SAMA5D3 编译环境:ubuntu 12.04
1、配置内核
这里之所以都选择为模块的形式,是为了调试方便,有些模块,比如U盘加载时还需要提供介质,就是说加载模块时还需要参数,否则加载不上
Device Drivers --->
[*] USB support --->
<*> USB Gadget Support --->
<M> USB Gadget Drivers
< > USB functions configurable through configfs
< > Gadget Zero (DEVELOPMENT)
< > Ethernet Gadget (with CDC Ethernet support)
< > Network Control Model (NCM) support
< > Gadget Filesystem
< > Function Filesystem
< > Mass Storage Gadget
< > USB Gadget Target Fabric Module
<M> Serial Gadget (with CDC ACM and CDC OBEX support)
< > Printer Gadget
保存退出,编译内核。在drivers/usb/gadget目录下会生成以下驱动文件
-rw-rw-r-- 1 a_tu a_tu 9710 3月 5 15:14 ./g_serial.ko
-rw-rw-r-- 1 a_tu a_tu 49319 3月 5 15:14 ./libcomposite.ko
-rw-rw-r-- 1 a_tu a_tu 11473 3月 5 15:14 ./usb_f_acm.ko
-rw-rw-r-- 1 a_tu a_tu 9485 3月 5 15:14 ./usb_f_obex.ko
-rw-rw-r-- 1 a_tu a_tu 8011 3月 5 15:14 ./usb_f_serial.ko
-rw-rw-r-- 1 a_tu a_tu 15970 3月 5 15:14 ./u_serial.ko
2、操作开发板
把编译好的内核烧入开发板,加载生成的驱动文件,注意加载顺序,否则会出现错误。
insmod u_serial.ko
insmod libcomposite.ko
insmod usb_f_serial.ko
insmod usb_f_obex.ko
insmod usb_f_acm.ko
insmod g_serial.ko
出现内核信息如下:
[ 27.310000] --------file=composite.c-------usb_composite_probe------1830
[ 27.320000] ------------402
[ 27.320000] -----usb_gadget_probe_driver------411
[ 27.330000] -------udc_bind_to_driver-----342
[ 27.330000] g_serial gadget: Gadget Serial v2.4
[ 27.340000] g_serial gadget: g_serial ready
[ 18.960000] g_serial gadget: high-speed config #2: CDC ACM config
说明加载成功。
此时你打开设备管理器会发现多了一个串口设备,
ELMO GMAS(COM10)
Win7操作系统可以自动加载基于udc标准的serial驱动。
对于WinXP操作系统,要使用ACM串口,需要WindowsXP机器上有gserial.inf和usbser.sys这两个文件,其中gserial.inf的配置如下:
[Version]
Signature='$Windows NT$'
Class=Ports
ClassGuid={4D36E978-E325-11CE-BFC1-08002BE10318}
Provider=%LINUX%
DriverVer=08/17/2004,0.0.2.0
; Copyright (C) 2004 Al Borchers (alborchers@steinerpoint.com)
[Manufacturer]
%LINUX%=GSerialDeviceList
[GSerialDeviceList]
%GSERIAL%=GSerialInstall, USB\VID_0525&PID_A4A7
[DestinationDirs]
DefaultDestDir=10,System32\Drivers
[GSerialInstall]
CopyFiles=GSerialCopyFiles
AddReg=GSerialAddReg
[GSerialCopyFiles]
usbser.sys
[GSerialAddReg]
HKR,,DevLoader,,*ntkern
HKR,,NTMPDriver,,usbser.sys
HKR,,EnumPropPages32,,'MsPorts.dll,SerialPortPropPageProvider'
[GSerialInstall.Services]
AddService = usbser,0x0002,GSerialService
[GSerialService]
DisplayName = %GSERIAL_DISPLAY_NAME%
ServiceType = 1 ; SERVICE_KERNEL_DRIVER
StartType = 3 ; SERVICE_DEMAND_START
ErrorControl = 1 ; SERVICE_ERROR_NORMAL
ServiceBinary = %10%\System32\Drivers\usbser.sys
LoadOrderGroup = Base
[Strings]
LINUX = 'Linux'
GSERIAL = 'Gadget Serial'
GSERIAL_DISPLAY_NAME = 'USB Gadget Serial Driver'
安装成功后,在设备管理器中可以看到 “Gadget Serial (COM11) '这个端口。
开发板的/dev/下会出现/dev/ttyGS0这个设备。当然如果你怕这个设备重名,可以更改这个设备节点。操作如下:
cat /proc/devices
Character devices:
1 mem
2 pty
3 ttyp
4 /dev/vc/0
4 tty
4 ttyS
5 /dev/tty
5 /dev/console
5 /dev/ptmx
7 vcs
10 misc
13 input
90 mtd
128 ptm
136 pts
153 spi
251 ttyGS
mknod /dev/usb_serial c 254 0
以后可以直接按照串口通讯的方式打开该节点 /dev/usb_serial ,进行数据读写操作。
3、通信测试
开发板上执行命令 cat /dev/usb_serial(当然你也可以编写程序,打开设备读写),这里只是简单的测试设备通信是否正常 ,pc机上打开串口调试助手,打开com10,通过字符串输入框发送数据。此时发现开发板没有收到数据,而串口助手却收到自己发送的数据。这让我很是纳闷,折腾了2天,终于睡醒了。
又测试了另一通路:开发板给pc发。echo 12345 > /dev/usb_serial
这是完全正常的,通过串口助手收到的数据来看。每次收到的数据都有换行现象,会不会是数据没有从缓冲区中刷出来?我就换了数据格式,发送简单文件
111111111111111111
222222222222222222
222222222222222222
444444444444444444
此时开发板收到数据
# cat /dev/usb_serial
111111111111111111
222222222222222222
222222222222222222
444444444444444444
原来真的是 "\n" 在作怪!!!,如果你的文件只有一行,且没有换行。那么你的开发板是收不到数据的,这些数据并没有丢失,而是存储在串口的缓冲区中,直到遇到 "\n",才会把数据一股脑发出来。
至此测试完毕。
本人水平有限,文章仅代表个人观点,如有错误,请指正!!!