zoukankan      html  css  js  c++  java
  • 学习Linux下s3c2440的USB鼠标驱动笔记


    1、ARM-Linux下USB驱动程序开发
    1.1.1、linux下USB配置:
    *********(MassStorage:存储设备)************************************
    -> Device Drivers
    -> SCSI device support(通用设备)
    -> SCSI disk support (磁盘支持)
    -> SCSI device support(设备支持)

    -> Device Drivers
    -> USB support (USB设备)
    -> USB device filesystem (USB设备文件系统)
    -> OHCI HCD support (主要是非PC上的USB芯片)
    -> USB Mass Storage support(USB大容量设备)
    -> USB Monitor (USB 主设备)

    -> File systems
    -> DOS/FAT/NT Filesystems
    -> MSDOS fs support
    -> VFAT (Windows-95) fs support

    -> Partition Types (分区类型)
    -> PC BIOS (MSDOS partition tables) support

    -> Native Language Suppor (本地语言设置)
    -> Simplified Chinese charset (CP936, GB2312)
    -> NLS UTF-8

    make uImage (生成uImage)
    测试 mount /dev/sda1 /mnt/

    *********(HID:人机接口(鼠标、键盘))********************************
    -> Device Drivers
    HID Devices --->
    -> USB Human Interface Device (full HID) support
    USB support --->
    -> Support for Host-side USB
    make uImage (生成uImage)
    测试 cat /dev/mouse1

    *********(RNDIS:网卡)********************************

    -> Device Drivers x
    -> USB support x
    -> USB Gadget Support
    <M> Support for USB Gadgets
    <M> Ethernet Gadget (with CDC Et hernet support) x x
    [*] RNDIS support (EXPERIMENTAL) (NEW)
    编译内核模块

    cp drivers/usb/gadget/_ether.ko /work/nfs_root/first_fs/
    cp /arch/arm/boot/uImage /work/nfs_root/new_uImage

    *********(CDC-ACM:USB虚拟串口)********************************
    (未能识别USB driver)可能是没有配置USB设备

     


    1.2.1、驱动程序编写
    struct usb_driver {
    const char *name; /*USB驱动名字*/
    int (*probe) (struct usb_interface *intf,const struct usb_device_id *id);/*USB core发现该驱动程序能够处理USB接口时,调用*/
    void (*disconnect) (struct usb_interface *intf);/*USB移除的时候调用*/
    const struct usb_device_id *id_table; /*该驱动程序支持哪些设备 idVendor(制造商ID) idProduct(产品id)*/
    };
    1.2.2、linux提供宏来定义 一种 设备 :
    USB_DEVICE(vend,prod)
    vend:USB Vendor ID 制造商ID
    prod:USB Product ID 设备ID

    1.2.3、linux提供宏来定义 一类 设备 :
    USB_INTERFACE_INFO(cl,sc,pr)
    cl:类 blnterfaceClass Value
    sc:子类 blnterfaceSubClass value
    pr:协议 blnterfaceProtocil Value

    1.2.4、USB注册:传入一个参数usb_driver
    static inline int usb_register(struct usb_driver *driver)

    1.2.5、usb_device结构
    int devnum; /* Address on USB bus */
    char devpath [16]; /* Use in messages: /port/port/... */
    enum usb_device_state state; /* configured, not attached, etc */
    enum usb_device_speed speed; /* high/full/low (or error) */
    struct usb_device_descriptor descriptor; /* Descriptor 设备描述符号*/
    struct usb_host_config *config; /* All of the configs */
    struct usb_config_descriptor desc; /*usb配置描述符*/
    struct usb_interface *interface[USB_MAXINTERFACES];
    ruct usb_host_interface *cur_altsetting; /* the currently
    /*USB 接口描述符 一个[配置]包含一个或者多个接口,一个接口包含一个或者多个[设置] */
    struct usb_interface_descriptor desc;
    struct usb_host_endpoint *endpoint; /*USB端点*/
    struct usb_endpoint_descriptor desc;/*USB 端点描述符 */

    1.3.1、URB(usb request block)请求块 ,承载USB之间的数据传输

    ①URB处理流程:
    1、USB设备驱动程序创建并初始化一个访问特点USB设备指定的端点的URB,并提交给USB Core
    2、USB core提交该URB到USB主控制驱动程序
    3、USB主控制器驱动程序根据该URB的描述信息,来访问USB设备
    4、当访问设备结束后,USB主控制器驱动程序通知USB设备驱动(device)程序

    ②创建urb的函数为:
    struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags)
    参数1:iso_packets:urb所含的等时数据包个数
    参数2:mem_flags:内存分配标示

    ③初始化urb函数为:interrupt
    static inline void usb_fill_int_urb (
    struct urb *urb, //要初始化urb指针
    struct usb_device *dev, //usb_device设备
    unsigned int pipe, //要访问的端点所对应的管道,使用usb_sndintpipe()/usb_rcvintpipe()
    void *transfer_buffer, //要传输数据的缓冲区
    int buffer_length, //要传输数据的长度
    usb_complete_t complete_fn, //当完成urb所请求的操作时候调用的回调函数
    void *context, //通常取值为DEV
    int interval //URB被调度的时间间隔
    );
    问:何为管道?
    答:管道:驱动程序的数据缓冲区与一个端点的连接,代表一个在两者之间要移动数据的能力。

    批量urb:使用usb_fill_bulk_urb()
    控制urb: 使用usb_control_urb()
    等时urb没有像中断、控制、批量传输那样有URB初始化函数,我们只有手动初始化urb.

    ④提交URB
    在完成urb的创建和初始化后,URB就可以通过usb_smbmit_urb函数来提交给usb core
    int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
    urb:指向URB的指针
    mem_flags:内存分配标示,用于告知USB core如何分配内存换成区。


    ⑤URB处理 以下三种情况被认为URB处理完成,调用complete_fn函数
    1、URB成功发送给设备,并且设备返回正确,URB->status = 0
    2、如果接收和发送发生错误时候 urb->status = error
    3、urb被取消,就发生在驱动程序通过,usb_unlink_urb() / usb_kill_urb()


    鼠标驱动程序:

      1 #include <linux/kernel.h>
      2 #include <linux/errno.h>
      3 #include <linux/init.h>
      4 #include <linux/slab.h>
      5 #include <linux/module.h>
      6 #include <linux/kref.h>
      7 #include <asm/uaccess.h>
      8 #include <linux/usb.h>
      9 #include <linux/mutex.h>
     10 #include <linux/hid.h>
     11 #include <linux/input.h>
     12 
     13 
     14 /*创建输入设备*/
     15 static struct input_dev *uk_dev;
     16 static int len;
     17 static char *usb_buf;
     18 static dma_addr_t usb_data_dma;
     19 static struct urb *uk_urb;
     20 
     21 
     22 
     23 
     24 //usb支持的设备列表
     25 static struct usb_device_id usbmouse_key_table [] = {
     26     { USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,
     27         USB_INTERFACE_PROTOCOL_MOUSE) },
     28     //{USB_DEVICE(0x1234,0x5678)},
     29     { }    /* Terminating entry */
     30 };
     31 
     32 static void usb_mouse_irq(struct urb *urb)
     33 {
     34     static unsigned char pre_val;
     35 #if 0    
     36     int i;
     37     char b[100];
     38     static int cnt = 0;
     39     printk("data cnt %d: ", ++cnt);
     40     for (i = 0; i < len; i++)
     41     {
     42         printk("%02x   ", usb_buf[i]);
     43     }
     44     printk("
    ");
     45 
     46 
     47 
     48     /* USB鼠标数据含义
     49      * data[1]: bit0-左键, 1-按下, 0-松开
     50      *          bit1-右键, 1-按下, 0-松开
     51      *          bit2-中键, 1-按下, 0-松开 
     52      *
     53      */
     54     // if ((pre_val & (1<<0)) != (usb_buf[1] & (1<<0)))
     55     // {
     56     //     /* 左键发生了变化 */
     57     //     input_event(uk_dev, EV_KEY, KEY_L, (usb_buf[1] & (1<<0)) ? 1 : 0);
     58     //     input_sync(uk_dev);
     59     // }
     60 
     61     // if ((pre_val & (1<<1)) != (usb_buf[1] & (1<<1)))
     62     // {
     63     //     /* 右键发生了变化 */
     64     //     input_event(uk_dev, EV_KEY, KEY_S, (usb_buf[1] & (1<<1)) ? 1 : 0);
     65     //     input_sync(uk_dev);
     66     // }
     67 
     68     // if ((pre_val & (1<<2)) != (usb_buf[1] & (1<<2)))
     69     // {
     70     //     /* 中键发生了变化 */
     71     //     input_event(uk_dev, EV_KEY, KEY_ENTER, (usb_buf[1] & (1<<2)) ? 1 : 0);
     72     //     input_sync(uk_dev);
     73     // }    
     74     
     75     // pre_val = usb_buf[1];
     76     /* 重新提交urb */
     77     usb_submit_urb(uk_urb, GFP_KERNEL);
     78 
     79 #else
     80 
     81     switch (urb->status) {
     82     case 0:            /* success */
     83         break;
     84     case -ECONNRESET:    /* unlink */
     85     case -ENOENT:
     86     case -ESHUTDOWN:
     87         return;
     88     /* -EPIPE:  should clear the halt */
     89     default:        /* error */
     90         goto resubmit;
     91     }
     92 
     93     input_report_key(uk_dev, BTN_LEFT,   usb_buf[1] & 0x01);
     94     input_report_key(uk_dev, BTN_RIGHT,  usb_buf[1] & 0x02);
     95     input_report_key(uk_dev, BTN_MIDDLE, usb_buf[1] & 0x04);
     96     input_report_key(uk_dev, BTN_SIDE,   usb_buf[1] & 0x08);
     97     input_report_key(uk_dev, BTN_EXTRA,  usb_buf[1] & 0x10);
     98 
     99     input_report_rel(uk_dev, REL_X,     usb_buf[3]);
    100     input_report_rel(uk_dev, REL_Y,     usb_buf[4]);
    101     input_report_rel(uk_dev, REL_WHEEL, usb_buf[5]);
    102 
    103     input_sync(uk_dev);
    104 resubmit:
    105      usb_submit_urb (urb, GFP_ATOMIC);
    106 #endif
    107 
    108 
    109 
    110 
    111 }
    112 
    113 static int usbmouse_key_probe(struct usb_interface *intf, const struct usb_device_id *id)
    114 {
    115     struct usb_device *dev = interface_to_usbdev(intf);
    116     struct usb_host_interface *interface;
    117     struct usb_endpoint_descriptor *endpoint;
    118     int pipe;
    119     /*获取当前usb接口的设置*/
    120     interface = intf->cur_altsetting;
    121     endpoint  = &interface->endpoint[0].desc;
    122 
    123     /* a. 分配一个input_dev */
    124     uk_dev = input_allocate_device();
    125     /* b. 设置 */
    126     /* b.1 能产生哪类事件 */
    127      set_bit(EV_KEY, uk_dev->evbit);
    128      set_bit(EV_REL, uk_dev->evbit);
    129     
    130     // /* b.2 能产生这类操作里的哪些事件: L,S,ENTER,LEFTSHIT */
    131     // set_bit(BTN_LEFT, uk_dev->keybit);
    132     // set_bit(BTN_RIGHT, uk_dev->keybit);
    133     // set_bit(BTN_MIDDLE, uk_dev->keybit); 
    134 
    135     // set_bit(REL_X,uk_dev->keybit);
    136     // set_bit(REL_Y,uk_dev->keybit);
    137     // set_bit(REL_WHEEL,uk_dev->keybit);
    138     
    139      uk_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
    140      uk_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
    141      uk_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y);
    142      uk_dev->keybit[LONG(BTN_MOUSE)] |= BIT(BTN_SIDE) | BIT(BTN_EXTRA);
    143      uk_dev->relbit[0] |= BIT(REL_WHEEL);
    144 
    145     /* c. 注册 */
    146     input_register_device(uk_dev);
    147     
    148     /* d. 硬件相关操作 */
    149     /* 数据传输3要素: 源,目的,长度 */
    150     /* 源: USB设备的某个端点 */
    151     pipe = usb_rcvintpipe(dev,endpoint->bEndpointAddress);
    152     /* 长度: */
    153     len =  endpoint->wMaxPacketSize;
    154     /* 目的: */
    155     usb_buf = usb_buffer_alloc(dev,len,GFP_ATOMIC,&usb_data_dma);
    156     /* 使用"3要素" */
    157     /* 分配usb request block */
    158     uk_urb = usb_alloc_urb(0, GFP_KERNEL);
    159 
    160     /* 使用"3要素设置urb" */
    161     usb_fill_int_urb(uk_urb, dev, pipe,usb_buf,len,usb_mouse_irq, NULL, endpoint->bInterval);
    162     uk_urb->transfer_dma = usb_data_dma;
    163     uk_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
    164 
    165     /* 使用URB */
    166     usb_submit_urb(uk_urb, GFP_KERNEL);
    167 
    168 
    169     printk("found usbmouse!
    ");
    170 
    171     printk("bcdUSB = %x
    ", dev->descriptor.bcdUSB);
    172     printk("VID    = 0x%x
    ", dev->descriptor.idVendor);
    173     printk("PID    = 0x%x
    ", dev->descriptor.idProduct);
    174 
    175     return 0;
    176 }
    177 
    178 static void usbmouse_key_disconnect(struct usb_interface *interface)
    179 {
    180     struct usb_device *dev = interface_to_usbdev(interface);
    181 
    182     printk("usbmouse_key_disconnect
    ");
    183     input_unregister_device(uk_dev);
    184     input_free_device(uk_dev);    
    185     usb_buffer_free(dev,len,usb_buf,usb_data_dma);
    186     usb_kill_urb(uk_urb);
    187     usb_free_urb(uk_urb);
    188 
    189 }
    190 
    191 MODULE_DEVICE_TABLE (usb, usbmouse_key_table);
    192 
    193  /*usbmouse_key_probe  usbmouse_key_disconnect  函数指针
    194   *当设备与在id_table 中变量信息匹配时,此函数被调用
    195   */
    196 static struct usb_driver usbmouse_key_driver = {
    197     .name =        "usbmouse_key",
    198     .probe =    usbmouse_key_probe,             
    199     .disconnect =    usbmouse_key_disconnect,
    200     .id_table =    usbmouse_key_table,
    201 
    202 };
    203 
    204 /*
    205  *USB骨架  最基本的usb驱动模板
    206  */
    207 static int __init usb_usbmouse_key_init(void)
    208 {
    209     int result;
    210 
    211     printk("usb_usbmouse_key_init
    ");
    212 
    213     /* register this driver with the USB subsystem */
    214     result = usb_register(&usbmouse_key_driver);
    215     if (result)
    216         err("usb_register failed. Error number %d", result);
    217 
    218     return result;
    219 }
    220 
    221 static void __exit usb_usbmouse_key_exit(void)
    222 {
    223     printk("usb_usbmouse_key_exit
    ");
    224     /* deregister this driver with the USB subsystem */
    225     usb_deregister(&usbmouse_key_driver);
    226 }
    227 
    228 module_init(usb_usbmouse_key_init);
    229 module_exit(usb_usbmouse_key_exit);
    230 MODULE_LICENSE("GPL");
    View Code




  • 相关阅读:
    notion笔记
    PHP性能分析工具xdebug+qcachegrind
    Homebrew1.5之后安装PHP和扩展
    Yii2 创建新项目目录
    MAC的一些实用
    Item2 + zsh
    YII2 RBAC Admin User权限相关
    ITEM 2 MAC OSX 功能略强大的终端
    MAC终端配色Solarized
    微服务 SpringCloud + docker
  • 原文地址:https://www.cnblogs.com/veryStrong/p/6100643.html
Copyright © 2011-2022 走看看