linux usb驱动

Posted 专注it

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了linux usb驱动相关的知识,希望对你有一定的参考价值。

0.usb协议
    usb的版本:     硬件
        usb 1.0     OHCI        微软                 硬件 > 软件
        usb 1.1     UHCI        intel                软件 > 硬件
        usb 2.0     EHCI        intel
        usb 3.0     XHCI        intel

        12mpbs/s   480mpbs/s   5gbps/s   10gbps/s
        
        
        usb传输类型:
            (0)控制传输:在usb设备插入主机时,主机与usb通信获取usb设备信息进行相关资源分配,配置时;
            (1)中断传输:数据传输量小,响应速度快,usb鼠标;【只是名称为中断,实际上其内部设置会有一个轮询时间,不断的去查询鼠标状态,是否有数据可上报】
            (2)实时传输:数据量大,数据不可靠,其实时性还是比较强,usb摄像头;
            (3)批量传输:数据量大,但是数据可靠,无实时性的限制:u盘;
                
            传输--->事务---->包---->域
            事务:输入(IN)事务处理、输出(OUT)事务处理、设置(SETUP)
            包:USB协议定义在总线上传输的基本单位是包
                1、令牌包阶段:启动一个输入、输出或设置的事务;  start
                2、数据包阶段:按输入、输出发送相应的数据;          data
                3、握手包阶段:返回数据接收情况,在同步传输的IN和OUT事务中没有这个阶段。 ack
            域:同步字域(SYNC)、包标识符域(PID)、数据域、循环冗余校验域(CRC)和包结尾域(EOP),
                
                
            usb端点是usb设备中的数据收发最小单元,usb数据传输的目的地/数据源是端点;
            usb设备中除了端点 0 之外(in+out),其余的端点有且只有一个方向(in/out);
            
            pipe:是usb主机 与 usb设备端点  之间通信的通道;
            
            
            usb设备枚举过程:    
                (1)usb设备 --插入-->  主机  --->硬件  (主机 5v d-(15k--->gnd) d+(15k-->gnd) gnd)
                                                        (设备 5v d-(15k--->vcc) d+(15k-->vcc) gnd)
                (2)usb设备上电:[1]主机供电  [2]外部独立供电
                (3)usb设备reset:usb设备先复位,之后主机才能与设备通信;
                (4)usb设备进入默认状态:主机与设备通信,首先该usb设备使用addr 0,端点0,控制管道与
                                          主机进行通信,usb主机分配新地址;
                (5)usb设备使用新地址:主机通过该新地址与usb设备进行通信,获取设备的相关信息;
                (6)根据获取到的设备信息进行相关配置工作;
                (7)如果有数据与该设备进行交互,则通信,反之挂起设备进入省电模式;
                
                RZ编码(return zero)
                    正电平代表逻辑1,负电平代表逻辑0,每传输完一位数据,信号归0。[自同步]
                NRZ编码(no return zero)
                    正电平代表逻辑1,负电平代表逻辑0,每传输完一位数据,信号不归0。
                NRZI编码(no return zero in)
                    数据为0电平翻转,数据为1电平不翻转。    
1.usb总线
    1.1 传输模式
    1.2 主机规范

2.linux下的usb框架
                           总线:                                         设备                         驱动  
            usb            struct bus_type   usb_bus_type                     struct usb_device              struct usb_driver
            i2c            struct bus_type   i2c_bus_type                     struct i2c_client            struct i2c_driver
            platform    struct bus_type   platform_bus_type                struct platform_device       struct platform_driver
        
                
    1.4 usb设备描述符
        usb设备在逻辑上分成几个层次:
        usb硬件连接:
            [1.5.1]usb设备描述符:设备描述符给出了usb设备的一般信息。
            [1.5.2]配置描述符
                配置描述符给出了usb设备的配置信息,在一个配置下,一个端点不会再接口之间共享,
            除非端点被统一接口的不同配置使用;    
            [1.5.3]接口描述符
            [1.5.4]端点描述符
    1.4 nrzi编码
    
    
    1.0usb总线框架
        app:      open    read     write
                -------------------------------------
        kernel:      
                  usb的设备驱动:struct usb_driver
                            drv_open drv_read drv_write ...
                        ------------------------------
                   usb core:
                        提供结构体 + 注册注销函数  + 传输方法 + 设备识别
                        ------------------------------
                   usb主机控制器驱动:struct hc_driver
                 -------------------------------------
        hardware:
                        usb主机控制器:struct usb_hcd
                        ------------------------------
                         usb的设备:struct usb_device
                --------------------------------------
    2.2 usb驱动    
        (2)总线
        usb.c--->module--->装载
            struct bus_type usb_bus_type = {
                .name =        "usb",
                .match =    usb_device_match,
                .uevent =    usb_uevent,
            };
            
            subsys_initcall(usb_init);
            usb_init
                retval = bus_register(&usb_bus_type);

                
            #define subsys_initcall(fn)     __define_initcall(fn, 4) //__define_initcall(usb_init, 4)
            
            176 #define __define_initcall(usb_init, 4)
            177     static initcall_t __initcall_##usb_init##4 __used                                                                                                                  
            178     __attribute__((__section__(".initcall" #4 ".init"))) = usb_init
            .initcall4.init = usb_init
            
            
            #define module_init(x)  __initcall(x);
                #define __initcall(fn) device_initcall(fn)
                    #define device_initcall(fn)     __define_initcall(fn, 6)
                    
                    
            vmlinux.lds  

        (1)驱动结构体
            struct usb_driver {
                const char *name;/名称
                int (*probe) (struct usb_interface *intf,const struct usb_device_id *id);//设备与驱动匹配上自动执行
                void (*disconnect) (struct usb_interface *intf);//当总线上设备或驱动任意一方移除时,自动执行
                const struct usb_device_id *id_table;//usb驱动所支持的设备列表
            };
            
                (1)生成匹配设备指定<制造商ID + 产品ID>的usb_dev_id
                    USB_DEVICE(vendor , product);
                    /*
                        #define USB_DEVICE(vend, prod)
                        .match_flags = USB_DEVICE_ID_MATCH_DEVICE,
                        .idVendor = (vend),
                        .idProduct = (prod)
                        
                        #define USB_DEVICE_ID_MATCH_DEVICE
                            (USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT)
                    */
                    
                    
                    
                (2) 生成匹配设备指定<制造商ID + 产品ID + 产品版本号最值区间>的usb_dev_id
                    USB_DEVICE_VER(vendor , product , lo ,hi);
                    
                (3)生成匹配设备指定<类 + 子类 + 协议>的usb_dev_id
                    USB_DEVICE_INFO(class , subclass , protocol);
                    
                (4)生成匹配接口指定<类 + 子类 + 协议>的usb_dev_id
                    USB_INTERFACE_INFO(class , subclass , protocol);

                    
            #define usb_register(driver)
                    usb_register_driver(driver, THIS_MODULE, KBUILD_MODNAME)    
                    
            int usb_register(struct usb_driver *new_driver)
            功能:usb_driver的注册
            参数:new_driver:usb_driver的指针对象
            返回值:成功: 0 失败:-ERRNO
            
            void usb_deregister(struct usb_driver *driver)
            功能:usb_driver的注销
            参数:driver:usb_driver的指针对象
            返回值:无
            
            static inline struct usb_device *interface_to_usbdev(struct usb_interface *intf)
            功能:根据struct usb_interface获取struct usb_device
            参数:intf:struct usb_interface
            返回值:成功:struct usb_device指针对象  失败:NULL
            
            想写一个usb鼠标的驱动:/driver/usb/usbmouse.c
            
            流程:
                (0)将该鼠标驱动程序对应的配置项删除
                     Device Drivers  --->
                            HID support  --->
                                 USB HID support  --->  
                                     <*> USB HID transport layer //该项“N”
                                    
                    cp  arch/arm/boot/uImage ~/tftpboot
                    
                (1)模块三要素
                (2)结构体填充
                (3)注册注销
                
                
            
            
        
        (3)设备    
            struct usb_device {
                int        devnum;//当前usb的设备地址编号
                struct usb_bus *bus;//该设备挂载到的usb总线对象
                struct usb_host_endpoint ep0;//usb设备的端点0
                
                struct usb_device_descriptor descriptor;//usb设备描述符---->
                
                struct usb_host_config *config;//usb主机配置【当前usb设备的若干种功能的集合】
                struct usb_host_endpoint *ep_in[16];//usb 设备的输入端点集合
                struct usb_host_endpoint *ep_out[16];////usb 设备的输出端点集合
                struct device dev;//linux设备模型相关的
            };
            
                配置:
                    struct usb_host_config {
                        struct usb_config_descriptor    desc;//配置描述符
                        struct usb_interface *interface[USB_MAXINTERFACES];//接口:具体的功能
                    };
                    
                    接口:
                        struct usb_interface {
                            struct usb_host_interface *altsetting;//未使用的接口
                            struct usb_host_interface *cur_altsetting;//正在使用的接口    
                            unsigned num_altsetting;//当前正在使用的接口的数量    
                            int minor;    //次设备号    
                            struct device dev;    //linux设备模型对象
                        };
                        
                            设置:
                            struct usb_host_interface {
                                struct usb_interface_descriptor    desc;//接口描述符
                                struct usb_host_endpoint *endpoint;  //端点
                            };
                                端点:
                                struct usb_host_endpoint {
                                    struct usb_endpoint_descriptor        desc;
                                };
                        
                lsusb -v:将系统中的所有usb设备的描述信息打印出来
            
创建pipe:            
            1、创建控制pipe(根据传输类型 以及  传输方向(针对于主机而言)的不同而不同  )
                usb_sndctrlpipe(dev, endpoint)
                usb_rcvctrlpipe(dev, endpoint)    
                
            2、创建中断pipe
                usb_sndintpipe(dev, endpoint)    
                usb_rcvintpipe(dev, endpoint)
                
            3、创建批量pipe
                usb_sndbulkpipe(dev, endpoint)
                usb_rcvbulkpipe(dev, endpoint)
                
            4、创建等时pipe
                usb_sndisocpipe(dev, endpoint)
                usb_rcvisocpipe(dev, endpoint)

填充urb:
            (1)使用usb_fill_control_urb函数初始化与控制端点通信的urb。
            void usb_fill_control_urb(struct urb *urb,
                                          struct usb_device *dev,
                                          unsigned int pipe,
                                          unsigned char *setup_packet,
                                          void *transfer_buffer,                       
                                          int buffer_length,
                                          usb_complete_t complete(回调函数),
                                          void *context,
                                          );
            (2)使用usb_fill_int_urb函数初始化与中断端点通信的urb。
                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,
                                          void *context,
                                         int interval
                                          );
            (3)使用usb_fill_int_urb函数初始化与批量端点通信的urb。
                void usb_fill_bulk_urb(      struct urb *urb,
                                          struct usb_device *dev,
                                          unsigned int pipe,
                                          void *transfer_buffer,                       
                                          int buffer_length,
                                          usb_complete_t complete,
                                          void *context,
                                         int interval
                                          )
            (4)等时传输的urb的填充采用固定步骤,具体参考相关数据设置
                
            void *usb_alloc_coherent(struct usb_device *dev, size_t size, gfp_t mem_flags,dma_addr_t *dma)
            功能:给主机接收数据分配相关的地址空间
            参数:dev:struct usb_device 的对象
                  size:分配空间的大小
                  mem_flags:分配空间的标志 GFP_KERNEL
                  dma:该返回值所对应的物理地址
            返回值:成功:分配空间的首地址  失败: NULL
                  
            struct urb *usb_alloc_urb(int iso_packets, int mem_flags);
            功能:分配struct urb结构体
            参数:
                iso_packet:urb包含的同步报文的数目。如果不是同步urb,设置为0,表示不创建等时数据包。
                mem_flags: 内核分配内存的标志类型。
            成功返回:urb的首地址  失败返回:NULL

            释放urb结构体的函数:
            void usb_free_urb(struct urb *urb);

            
            int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
            功能:提交urb
            参数:urb:待提交的urb对象
                  mem_flags:该urb所占内存空间的标志GFP_KERNEL
            返回值:成功:0  失败: -errno
3.usb请求块
    (1)urb结构体:
    (2)urb相关函数
        申请释放urb:
        填充urb:
        填充urb函数中关于pipe参数的设置:    
        提交urb
        取消urb函数        
4.usb骨架程序
    
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/usb.h>
#include <linux/mod_devicetable.h>
#include <linux/hid.h>
#include <linux/input.h>
#include <linux/bitops.h>
#include <linux/gfp.h>
/*
流程:
(1)模块三要素
(2)结构体填充
(3)注册注销
(4)硬件相关的操作
    [4.1]因为usb鼠标属于输入设备,其需要提供上报的数据  经过 usb 数据线 传输出去  故此时需要提供input 的数据
        input_dev申请 + 填充  +  注册  + 注销

    [4.2]usb相关
        [4.2.1]得到通信的端点(usb 设备中)
        [4.2.2]得到pipe (不同的传输类型的管道是不一样的 , 管道有传输方向)
        [4.2.3]主机为了接收端点传进来的数据 需要分配一定的空间
        [4.2.4]urb:申请到urb  +  fill  + submit + 收到urb后再进行相关的数据解析
*/
struct usb_device *usb_key_dev = NULL;
struct input_dev *usb_input_dev = NULL;
char *usb_master_buf = NULL;
dma_addr_t  usb_buf_phy;
struct urb *my_urb = NULL;
int length = 0;

void usb_key_complete(struct urb *urb)
{
    int i = 0;
    for(i = 0; i < length ; i++){
        printk("usb_master_buf[%d]:%d ",i ,usb_master_buf[i] );
    }
    printk(" ");
    usb_submit_urb(my_urb,GFP_KERNEL);
}

int usb_key_probe(struct usb_interface *intf,const struct usb_device_id *id)
{
    int ret = 0;
    int pipe = 0;
    
    struct usb_host_interface *interface;
    struct usb_endpoint_descriptor *endpoint;
    
    usb_key_dev = interface_to_usbdev(intf);
    if(usb_key_dev == NULL){
        printk("%s,%d usb_key_dev fail... ",__func__,__LINE__);
        return -ENOMEM;
    }
    
    interface = intf->cur_altsetting;
    endpoint = &interface->endpoint[0].desc;
    /*input相关*/
    usb_input_dev = input_allocate_device();
    if(usb_input_dev == NULL){
        printk("input_allocate_device ... ");
        return -ENOMEM;
    }
    //type
    set_bit( EV_KEY, usb_input_dev->evbit);
    set_bit( EV_REL, usb_input_dev->evbit);
    //code
    set_bit( KEY_L,usb_input_dev->keybit );
    set_bit( KEY_R,usb_input_dev->keybit );
    set_bit( KEY_ENTER,usb_input_dev->keybit);

    ret = input_register_device(usb_input_dev);
    if(ret < 0){
        printk("input_register_device fail ");
        return -EINVAL;
    }

    /*usb相关  1.  确定数据传输的源  +  目的 + 长度*/
    pipe= usb_rcvintpipe(usb_key_dev, endpoint->bEndpointAddress);
    length = endpoint->wMaxPacketSize;
    usb_master_buf = usb_alloc_coherent(usb_key_dev,length,GFP_KERNEL,&usb_buf_phy);
    if(usb_master_buf == NULL){
        printk("usb_alloc_coherent fail ");
        return -ENOMEM;
    }

    /*usb  数据的传输准备: 分配urb  + 填充urb (跟传输类型相关)+ 提交urb*/
    my_urb = usb_alloc_urb(0,GFP_KERNEL);
    if(my_urb == NULL){
        printk("usb_alloc_urb fail ");
        return -ENOMEM;
    }
    usb_fill_int_urb(my_urb,usb_key_dev,pipe,usb_master_buf,length,usb_key_complete,NULL,endpoint->bInterval);
    my_urb->transfer_dma = usb_master_buf;
    my_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
    
    usb_submit_urb(my_urb,GFP_KERNEL);
    
    printk("%x,%x ",usb_key_dev->descriptor.idVendor,usb_key_dev->descriptor.idProduct);//[   21.545000] 93a,2510
    printk("%s,%d ",__func__,__LINE__);
    return 0;
}
void usb_key_disconnect(struct usb_interface *intf)
{
    usb_kill_urb(my_urb);
    usb_free_urb(my_urb);
    usb_free_coherent(usb_key_dev,length,usb_master_buf,usb_buf_phy);
    input_unregister_device(usb_input_dev);
    input_free_device(usb_input_dev);
    
    printk("%s,%d ",__func__,__LINE__);
}

const struct usb_device_id usb_key_table[] = {
    { USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,
        USB_INTERFACE_PROTOCOL_MOUSE)},
    //{USB_DEVICE(0x93a , 0x2510)},//匹配指定的厂商ID  产品ID为什么没有实现该功能?
};

struct usb_driver usb_key_drv = {
    .name = "usb_key",
      .probe = usb_key_probe,
    .disconnect = usb_key_disconnect,
    .id_table = usb_key_table,
};

static int __init usbkey_init(void)
{
    int ret = 0;
    ret = usb_register(&usb_key_drv);
    if(ret < 0){
        printk("%s,%d usb_register fail ",__func__,__LINE__);
        return -EINVAL;
    }
    printk("%s,%d ",__func__,__LINE__);
    return 0;
}

static void __exit usbkey_exit(void)
{
    usb_deregister(&usb_key_drv);
    printk("%s,%d ",__func__,__LINE__);
}

module_init(usbkey_init);
module_exit(usbkey_exit);
MODULE_LICENSE("GPL");



            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
   




















































































































































































































































































































































































































































































































以上是关于linux usb驱动的主要内容,如果未能解决你的问题,请参考以下文章

linux 如何判断usb驱动是2.0

Linux USB 驱动开发—— 编写USB 驱动程序

如何写一个Android USB接口驱动

Linux USB 驱动开发—— USB 鼠标驱动注解及测试

怎样写linux下的USB设备驱动程序

linux USB设备驱动的问题!