分类: LINUX
2011-02-16 10:56:27
1. 在USB设备组织结构中,从上到下分为设备(device)、配置(config)、接口(interface)和端点(endpoint)四个层次。
2. 设备地代表了一个插入的USB设备,在内核使用数据结构 struct usb_device来描述。
3. 一个USB设备可以有多个配置,并可在它们之间转换以改变设备的状态。比如一个设备可以通过下载固件(firmware)的方式改变设备的使用状态(我感觉类似FP那么USB设备就要切换配置,来完成这个工作。一个时刻只能有一个配置可以被激活。Linux使用结构 struct usb_host_config 来描述USB配置。
4. 一个USB接口代表一个基本功能,每个USB驱动控制一个接口。所以一个物理上的硬件设备可能需要一个以上的驱动程序。
5. 端点可被看作一个单向的管道。4 种不同类型:控制(CONTROL)传输、批量(BULK)传输(U盘)、中断(INTERRUPT)传输(定时轮询如小数据量:鼠标键盘)、等时(ISOCHRONOUS)传输(类似UDP 不可靠大量数据的轮询:音频和视频设备)。
6. USB枚举过程:由USB内核完成
1、第一次GetDescriptor :确定缺省管道控制断点的每次数据包大小(只确认前8字节)
2、SetAddress
3、再次发送GetDescriptor 根据描述符确定驱动程序
4、GetConfiguration,读取多个配置
5、SetConfiguration,确定需要使用的配置
7. USB 设备驱动代码通过urb和所有的 USB 设备通讯。
一个 urb 的典型生命循环如下:
(1)被创建;struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags);
(2)被分配给一个特定 USB 设备的特定端点;
static inline void usb_fill_XXX_urb(struct urb *urb,
struct usb_device *dev,
unsigned int pipe,
void *transfer_buffer,
int buffer_length,
usb_complete_t complete_fn,
void *context,
int interval);
XXX 为int中断,bulk批量,control控制 等时传输没有初始化函数,只能手动初始化。
(3)被提交给 USB 核心;
int usb_submit_urb(struct urb *urb, gfp_t mem_flags);
(4)被 USB 核心提交给特定设备的特定 USB 主机控制器驱动;
(5)被 USB 主机控制器驱动处理, 并传送到设备;
(6)以上操作完成后,USB主机控制器驱动通知 USB 设备驱动;
执行结束处理例程。()使用 void usb_kill_urb(struct urb *urb) 和
Int usb_unlink_usb(struct urb *urb) 取消一个已经提交的URB
(7)urb的注销;void usb_free_urb(struct urb *urb);
1. 驱动程序把驱动对象注册到 USB 子系统中,之后使用供应商(idVendor)和设备(idProduct)标识来判断对应的硬件是否已经安装.struct usb_device_id 结构提供了这个驱动支持的不同类型 USB 设备的列表. USB 核心通过此列表用来决定设备对应的驱动,热插拔脚本也通过此列表来决定当特定设备被插入系统时,应该自动加载的驱动.
2. 开发步骤:
1 初始化厂商ID和设备ID :usb_device_id skel_table[ ]
2 注册设备ID, 到usb核:MODULE_DEVICE_TABLE(usb, skel_table)
3 声明USB设备拥有资源的结构体
这个结构体的名字有开发人员自定义,它描述的是该驱动拥有的所有资源及状态:
struct usb_skel {
struct usb_device *udev; /* the usb device for this device */ 该设备的usb_device 指针 制造商 ID 产品ID等等
struct usb_interface *interface; /* the interface for this device */ 接口
struct semaphore limit_sem; /* limiting the number of writes in progress */ 数据共享 ->竞态/并发 信号量 防止竞态发生
struct usb_anchor submitted;/* in case we need to retract our submissions *
unsigned char *bulk_in_buffer;/* the buffer to receive data */ 接送数据缓冲
size_t bulk_in_size; /* the size of the receive buffer */ 接受缓冲大小
__u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */
__u8 bulk_out_endpointAddr; /* the address of the bulk out endpoint */ 批量输入、输出 8位 端点 地址
int errors; /* the last request tanked */
int open_count; /* count the number of openers */
spinlock_t err_lock; /* lock for errors */
struct kref kref; //内核引用的计数器
struct mutex io_mutex;/* synchronize I/O with disconnect */ 同步 IO
};
4 static int skel_probe(struct usb_interface *interface, const struct usb_device_id *id) 需要完成的(在设备被插入时调用):1.在堆上声明一个usb_skl 的结构体,初始化各配置参数;2.从传入的interface中提取端点信息保存到usb_skl 结构体中;3.使用usb_set_intfdata(interface, dev)将usb_skl结构体中的各种信息保存到interface 中,方便以后访问。4.注册该设备到USB核心;
5 static void Skel_disconnect(struct usb_interface *interface)(设备被拔出时调用)。 1.usb_setintfdata(interface, NULL)清除interface 中保存的设备信息。2.注销USB设备3.清除usb_skel结构体中的信息。
6 声明一个usb_device 变量skel_driver初始化其.name .probe .disconnect 和.id_table
7 Open 通过1.interface = usb_find_interface(&skel_driver, subminor); 获取interface 信息;2.通过dev = usb_get_intfdata(interface);获取usb_skel 结构体。3.判断设备是否已经被打开,打开:retval = usb_autopm_get_interface(interface);未被:file->private_data = dev;
8 Read 1.通过dev = (struct usb_skel *)file->private_data; 获取usb_skel结构体;2.通过 retval=usb_bulk_msg(dev->udev,usb_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr),dev->bulk_in_buffer,min(dev->bulk_in_size, count), &bytes_read, 10000);向读入的端点发送读数据请求 把数据读入dev->bulk_in_buffer 中;3.复制数据到用户空间;copy_to_user
9 Write 1.设定实际要写入的个数size_t writesize = min(count, (size_t)MAX_TRANSFER);2.获取usb_skel dev = (struct usb_skel *)file->private_data; 3.创建urb 结构urb = usb_alloc_urb(0, GFP_KERNEL); 4.为urb包含的数据分配DMA空间 buf = usb_buffer_alloc(dev->udev, writesize, GFP_KERNEL, &urb->transfer_dma); 5.将用户空间的数据 复制进内核 copy_from_user(buf, user_buffer, writesize);6.封装urb为bulk_urb 注册回调函数(1) usb_fill_bulk_urb(urb,dev->udev,usb_sndbulkpipe(dev->udev,dev->bulk_out_endpointAddr),buf, writesize,skel_write_bulk_callback,dev);(2)urb->transfer_flags|=URB_NO_TRANSFER_DMA_MAP;(3)usb_anchor_urb(urb, &dev->submitted); 7.将urb提交到USB中心retval = usb_submit_urb(urb, GFP_KERNEL); 8.释放urb usb_free_urb(urb);
10 Write_callback 1.判断返回状态;2.释放urb的buf,usb_buffer_free(urb->dev, urb->transfer_buffer_length,urb->transfer_buffer, urb->transfer_dma);
11 通过各种usbclass来匹配不同的USB设备。