Linux _USB 驱动
作者:互联网
需要的宏如下:
struct usb_device_id usbmouse_id_table[] = USB_INTERFACE_INFO(cl, sc, pr);
USB_INTERFACE_INFO()设置usb_driver 驱动的id_table成员
cl:接口类:由于我们USB鼠标为HID类 所以填入0x03 也就是USB_INTERFACE_CLASS_HID
sc: 接口自雷为启动设备 填入USB_INTERFACE_SUBCLASS_BOOT
pr: 接口协议为鼠标协议 填入USB_INTERFACE_PROTOCOL_MOUSE
struct usb_device *dev = interface_to_usbdev(intf);
通过usb_interface 接口获取usb_device 设备,为后面设置usb数据传输用。
应该是当usb插入的时候,内核驱动内核会把子usb的信息查询出来 然后给usb device结构体
pipe = usb_rcvintpipe(dev, endpoint)
创建一个接受(rcv)中断(int)类型的断点管道(pipe)用个来断点和数据缓冲区之间的链接,鼠标为接收中断类型。
dev: usb_device
endpoint:为端点描述符的成员 endpoint->bEndpointAddress
对于控制类型的断点管道使用:usb_sndctrlpipe()/usb_rcvctrlpipe()
对于实时类型的额断点管道使用:usb_sndisocpipe/usb_rcvisocpipe()
对于批量类型的端点管道使用:usb_sndbulkpipe()/usb_rcvbulkpipe()
2 我们需要用到的函数如下:
usb_deregister(struct usb_driver *driver)
注册一个usb_driver 驱动,然后内核会通过usb_drvier 的成员id_table 函数匹配一个usb的设备 匹配成功就会调用usb_driver 的成员的.probe 函数。
usb_deregister(struct usb_driver *driver)
注销一个usb_driver 驱动在出口函数中写。
*usb_buffer_alloc(struct usb_device *dev, size_t size, gfp_t mem_flags, dma_addr_t *dma)
分配一个usb缓冲区 该缓冲区的物理地址会与虚拟地址的数据一致,分配成功返回一个char型的缓冲区虚拟地址 //这里应该是选用了类似于DMA的设计思路
*Dev:usb_device 设备结构体
size:分配的缓冲区大小这里填端点描述符的成员 endPoint->wMaxPacketSize //端点能够接受的最大的长度
mem_flags: 分配内存的参数 这里填的是GFP_ATOMIC 表示不休眠。
dma:分配成功则会返回一个dma缓冲物理地址。
void usb_buffer_free(struct usb_device *dev,size_t size,void *addr,dma_addr_t dma);
注销分配的usb缓冲区 在usb driver的disconnect成员函数中使用
addr 要注销的缓冲区虚拟地址
dma:要注销的DMA缓冲区虚拟地址。
urb的知识:
urb的全称是 usb request block USB传输数据的时候 就是打包成urb结构体来传输的
函数:
struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags);
ISO_packets 表示iso 类型的包的个数,这里我么不是iso类型的包 直接填写0
mem_flags:分配内存的参数这里填入GFP_KERNEL正常分配
URB的结构体如下:
1 struct urb 2 { 3 ... ... 4 struct usb_device *dev; //指向usb设备 5 struct usb_host_endpoint *ep; //指向端点的数据结构 6 unsigned int pipe; //指向端点管道(pipe), 本节的pipe通过usb_rcvintpipe()宏获取 7 8 int status; //状态,当status==0,表示数据被成功地收到/发送 9 10 unsigned int transfer_flags; //传输状态 11 ... ... 12 /*以下两个缓冲区通过usb_buffer_alloc ()函数获取 */ 13 //urb结构体默认的transfer_flags是URB_NO_SETUP_DMA_MAP ,也就是说没有提供DMA的缓冲区 14 //就会使用transfer_buffer虚拟地址缓冲区来当缓冲区 15 //当支持DMA缓冲区时,就需要手动设置transfer_flags =URB_NO_TRANSFER_DMA_MAP,并手动设置transfer_dma等于获取到的DMA物理地址 16 17 void *transfer_buffer; //虚拟缓冲区 18 dma_addr_t transfer_dma; //DMA物理缓冲区 19 ... ... 20 };
void usb_free_urb(struct urb *urb)
释放申请的urb 在usb_driver 的disconnect成员函数中使用。
static inline void usb_fill_int_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);
此函数是初始化中断型端点的urb数据结构体(其中函数名里面的int的含义是int型)
针对批量性的端点的urb使用usb_fill_bulk_urb
针对控制性的端点的urb使用usb_fill_control_urb
针对实时性端点的urb需要手动初始化
urb:指向初始化的urb
dev 指向要传输的usb设备
pipe:要传输的端点管道,本届的pipe通过usb_rcvintpipe()宏获取
transfer_buffer 指向要传输的数据的虚拟地址缓冲区
buffer_length:数据大小 这里填写端点描述符的成员endpoint->wMaxPacketS //端点最大包长
complete_fn: 数据传输完之后产生的中断函数(其实这里是一个回调函数 表示如果USB的数据被接受之后如何利用这些数据 此函数并非硬件中断函数)
context: 回房子urb->context 结构成员中 用来给中断函数用 本章节不需要。
interval:间隔时间 表示间隔多少时间赌一次数据 填入endpoint->binterval 即可
int usb_submit_urb(struct urb *urb, gfp_t mem_flags);
提交urb到内核初始化urb和中断函数退出时都要提交依稀高速内核初始化的内存的缓存等。
void usb_kill_urb(struct urb *urb)
释放urb的内存 在disconnect函数中使用
程序思想 步骤如下:
1. 首先定义 usb_driver 结构体
2. input_dev 指针结构体
3. 虚拟地址缓存区 地址
4. DMA 地址缓存区 地址
通过usb_register()函数注册usb_driver结构体
在usb_driver的probe函数中
1. 分配一个input_dev 结构体
2. 设置input_dev 支持L S 回车 3个事件
3. 注册input_dev
4 设置usb数据传输
1. 通过usb_rcvintpipe()创建一个接收中断类型的端点管道,用来连接端点和数据缓冲区之间的链接
2. 通过usb_buffer_alloc 申请USB缓冲区
3. 申请并且初始化urb 结构体urb用来传输数据
4. 因为我们2440支持DMA 所以要告诉urb结构体使用DMA缓冲区的地址
5. 使用usb_sumbit_urb 提交urb
在鼠标中断函数中:
1. 判断缓存区数据是否改变 如果改变上传鼠标事件
2. 使用usb_submit_urb()提交urb
在usb_driverde disconnect 函数中
通过usb kill urb 杀掉提交到内核中的urb
释放urb
释放USB缓冲区
注销input device 释放input_device
在出口函数中
通过usb_deregister函数注销usb_driver 结构体
标签:usb,urb,函数,driver,struct,Linux,缓冲区,驱动,USB 来源: https://www.cnblogs.com/shwzh1990/p/14003225.html