• 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");



                
                
                
                
                
                
                
                
                
                
                
                
                
                
                
                
                
                
                
                
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
       

  • 相关阅读:
    P1541
    P1004
    P1006
    高精度
    数组
    递归
    顺序结构
    循环结构
    变量
    分支结构
  • 原文地址:https://www.cnblogs.com/wanghuaijun/p/9218988.html
Copyright © 2020-2023  润新知