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驱动框架与驱动架构


下一篇:Linux 内核提交和控制一个 urb