zoukankan      html  css  js  c++  java
  • USB设备驱动

    架构

     

       

    USB的硬件识别原理

       

    基本概念

    ①如何区分不同的USB设备?

    每个USB设备接入PC时,USB总线驱动程序都会给它分配一个编号(地址);

    接在USB总线上的每一个USB设备都有自己的编号(地址);

    PC机想访问某个USB设备时,发出的命令都含有对应的编号(地址);

    新接入的USB设备的设备编号(地址)是0,在未分配新编号之前,PC机使用0编号与其通信;

       

    USB为主从结构

    USB主机发起通信,从机处于"绝对被动"地位("通知"主机接收数据的能力都没有);

       

    USB传输类型

    控制传输

    数据可靠

    实时

    USB识别过程

    批量传输

    数据可靠

    非实时

    U

    "中断"传输

    数据可靠

    实时

    鼠标

    实时传输

    数据不可靠

    实时

    USB摄像头

       

    USB传输对象:端点(endpoint)

    端点0:

    传输类型:控制传输; 传输方向:双向(输出和输入);

    除了端点0外,其它端点都是单向传输的,只支持一种传输方向;

       

    ⑤术语里,程序的输入(IN)、输出(OUT)都是基于USB主机的立场说的;

    例如:鼠标。鼠标作为从设备,由主机读取鼠标的数据,对主机来说,鼠标对应的端点为输入端点。

        

    设备描述符

       

    程序框架实现分析

    ①把USB设备接到开发板上,看输出信息:

    usb 1-1: new full speed USB device using s3c2410-ohci and address 2

    usb 1-1: configuration #1 chosen from 1 choice

    scsi0 : SCSI emulation for USB Mass Storage devices

    scsi 0:0:0:0: Direct-Access HTC Android Phone 0100 PQ: 0 ANSI: 2

    sd 0:0:0:0: [sda] Attached SCSI removable disk

       

    ②拔掉

    usb 1-1: USB disconnect, address 2

       

    ③再接上:

    usb 1-1: new full speed USB device using s3c2410-ohci and address 3

    usb 1-1: configuration #1 chosen from 1 choice

    scsi1 : SCSI emulation for USB Mass Storage devices

    scsi 1:0:0:0: Direct-Access HTC Android Phone 0100 PQ: 0 ANSI: 2

    sd 1:0:0:0: [sda] Attached SCSI removable disk

       

    ④在内核目录下搜:

    grep "USB device using" * -nR

    drivers/usb/core/hub.c:2186: "%s %s speed %sUSB device using %s and address %d ",

       

    hub_irq

    kick_khubd

    hub_thread

    hub_events

    hub_port_connect_change

       

    udev = usb_alloc_dev(hdev, hdev->bus, port1);

    dev->dev.bus = &usb_bus_type;

       

    choose_address(udev); // 给新设备分配编号(地址)

       

       

    hub_port_init // usb 1-1: new full speed USB device using s3c2410-ohci and address 3

       

    hub_set_address // 把编号(地址)告诉USB设备

       

    usb_get_device_descriptor(udev, 8); // 获取设备描述符

    retval = usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE);

       

    usb_new_device(udev)

    err = usb_get_configuration(udev); // 把所有的描述符都读出来,并解析

    usb_parse_configuration

       

    device_add // 把device放入usb_bus_type的dev链表,

    // 从usb_bus_type的driver链表里取出usb_driver

    // 把usb_interface和usb_driver的id_table比较

    // 如果能匹配,调用usb_driver的probe

       

    驱动程序

    1 /*
    2 * 参考:.linux-2.6.22.6drivershidusbhidusbmouse.c
    3 * USB鼠标用作按键输入:
    4 * 左键:L;右键:S;中键:ENTER
    5 */
    6 #include <linux/kernel.h>
    7 #include <linux/slab.h>
    8 #include <linux/module.h>
    9 #include <linux/init.h>
    10 #include <linux/usb/input.h>
    11 #include <linux/hid.h>
    12
    13 static struct input_dev *uk_dev;
    14
    15 static int usb_bufLen;
    16 static char *usb_buf;
    17 static dma_addr_t usb_buf_phy;
    18 static struct urb *uk_urb;
    19
    20 static void usbMouseAsKey_irq(struct urb *urb)
    21 {
    22 #if 0
    23         /* test: 测试鼠标数据含义 */
    24         int i;
    25         static int cnt = 0;
    26
    27         for (i=0; i<usb_bufLen; i++)
    28         {
    29                 printk("%02x ", usb_buf[i]);
    30         }
    31         printk(" ");
    32 #else
    33         /*
    34          * usb鼠标数据含义:
    35          * data[0]: bit0-左键
    36          *          bit1-右键
    37          *          bit2-中键
    38          */
    39          static unsigned char pre_val;
    40
    41          if ((pre_val&(1<<0)) != (usb_buf[0]&(1<<0)))
    42          {
    43                 //左键发生了变化
    44                 input_event(uk_dev, EV_KEY, KEY_L, (usb_buf[0]&(1<<0))?1:0);
    45                 input_sync(uk_dev);
    46          }
    47
    48          if ((pre_val&(1<<1)) != (usb_buf[0]&(1<<1)))
    49          {
    50                 //右键发生了变化
    51                 input_event(uk_dev, EV_KEY, KEY_S, (usb_buf[0]&(1<<1))?1:0);
    52                 input_sync(uk_dev);
    53          }
    54
    55          if ((pre_val&(1<<2)) != (usb_buf[0]&(1<<2)))
    56          {
    57                 //中键发生了变化
    58                 input_event(uk_dev, EV_KEY, KEY_ENTER, (usb_buf[0]&(1<<2))?1:0);
    59                 input_sync(uk_dev);
    60          }
    61
    62         pre_val = usb_buf[0];
    63 #endif
    64         /* 重新提交urb */
    65         usb_submit_urb(uk_urb, GFP_KERNEL);
    66 }
    67
    68
    69 static int usbMouseAsKey_probe(struct usb_interface *intf, const struct usb_device_id *id)
    70 {
    71         /* test:打印usb设备厂家相关信息(当鼠标接到windows下,设备管理器可看到这些信息) */
    72         //struct usb_device *dev = interface_to_usbdev(intf);
    73
    74         //printk("found usb mouse ");
    75         //printk("bcdUSB = 0x%x ", dev->descriptor.bcdUSB);
    76         //printk("VID = 0x%x ", dev->descriptor.idVendor);        //供应商id
    77         //printk("PID = 0x%x ", dev->descriptor.idProduct);        //产品id
    78         /******** test end ********/
    79
    80         struct usb_device *dev = interface_to_usbdev(intf);
    81         struct usb_host_interface *interface;
    82         struct usb_endpoint_descriptor *endpoint;
    83         int pipe, maxp;
    84         
    85
    86         interface = intf->cur_altsetting;
    87         endpoint = &interface->endpoint[0].desc;
    88
    89         /* 3 分配一个input_dev */
    90         uk_dev = input_allocate_device();
    91         /******** 3 end ********/
    92
    93         /* 4 设置 */
    94         //4.1 能产生哪类事件
    95         set_bit(EV_KEY, uk_dev->evbit);
    96         set_bit(EV_REP, uk_dev->evbit);
    97         
    98         //4.2 能产生哪些事件
    99         set_bit(KEY_L, uk_dev->keybit);
    100         set_bit(KEY_S, uk_dev->keybit);
    101         set_bit(KEY_ENTER, uk_dev->keybit);
    102         /******** 4 end ********/
    103
    104         /* 5 注册 */
    105         input_register_device(uk_dev);
    106         /******** 5 end ********/
    107
    108         /* 6 硬件相关操作 */
    109         //数据传输3要素:源、目的、长度
    110         //a、源:usb设备的某个端点
    111         pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
    112         maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
    113
    114         //b、长度
    115         usb_bufLen = endpoint->wMaxPacketSize;
    116
    117         //c、目的
    118         usb_buf = usb_buffer_alloc(dev, 8, GFP_ATOMIC, &usb_buf_phy);
    119
    120         //d、使用3要素
    121         //d.1 分配urb ―― usb请求块:usb request block
    122         uk_urb = usb_alloc_urb(0, GFP_KERNEL);        
    123
    124         //d.2 填充urb
    125         usb_fill_int_urb(uk_urb, dev, pipe, usb_buf, usb_bufLen, usbMouseAsKey_irq, NULL, endpoint->bInterval);        //endpoint->bInterval:主机查询频率
    126         uk_urb->transfer_dma = usb_buf_phy;
    127         uk_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
    128
    129         //d.3 使用urd
    130         usb_submit_urb(uk_urb, GFP_KERNEL);
    131         /******** 6 end ********/
    132         return 0;
    133 }
    134
    135 static void usbMouseAsKey_disconnect(struct usb_interface *intf)
    136 {
    137         //printk("disconnect ");
    138         usb_kill_urb(uk_urb);
    139         usb_free_urb(uk_urb);
    140         usb_buffer_free(interface_to_usbdev(intf), usb_bufLen, usb_buf, usb_buf_phy);
    141         input_unregister_device(uk_dev);
    142         input_free_device(uk_dev);        
    143         return 0;
    144 }
    145
    146
    147 static struct usb_device_id usbMouseAsKey_id_table [] = {
    148         { USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,
    149                 USB_INTERFACE_PROTOCOL_MOUSE) },
    150         { }        /* Terminating entry */
    151 };
    152
    153 /* 2 分配设置一个usb_driver结构体 */
    154 static struct usb_driver usbMouseAsKey_driver = {
    155         .name                = "usbMouseAsKey",
    156         .probe                = usbMouseAsKey_probe,
    157         .disconnect        = usbMouseAsKey_disconnect,
    158         .id_table         = usbMouseAsKey_id_table,
    159 };
    160 /******** 2 end ********/
    161
    162
    163 /* 1 出、入口函数 */
    164 static int usbMouse_asKey_init(void)
    165 {
    166         /* 3 注册usb_driver */
    167         usb_register(&usbMouseAsKey_driver);
    168         /******** end ********/
    169         return 0;
    170 }
    171
    172
    173 static void usbMouse_asKey_exit(void)
    174 {
    175         /* 4 卸载usb_driver */
    176         usb_deregister(&usbMouseAsKey_driver);
    177         /******** end ********/
    178         return;
    179 }
    180
    181
    182 module_init(usbMouse_asKey_init);
    183 module_exit(usbMouse_asKey_exit);
    184 MODULE_LICENSE("GPL");
    185 /******** 1 end ********/

    Makefile

    1 KERN_DIR = /work/system/linux-2.6.22.6
    2
    3 all:
    4         make -C $(KERN_DIR) M=`pwd` modules
    5

    6 clean:
    7         make -C $(KERN_DIR) M=`pwd` modules clean
    8
            rm -rf modules.order

    9
    10 obj-m        += usb_mouseASkey.o

       

       

    调试

    pc-linux:

    cd /work/system/linux-2.6.22.6/

    make menuconfig(屏蔽鼠标驱动)

    make uImage

    cp arch/arm/boot/uImage /work/nfs_root/uImage_nohid

       

    board-uboot:

    nfs 30000000 192.168.0.103:/work/nfs_root/uImage_nohid

    bootm 30000000

       

    board-linux:

    insmod usb_mouseASkey.ko

    接上usb鼠标

    ls /dev/event*

    cat /dev/tty1(hexdump /dev/event*)

    操作鼠标——观察数据

  • 相关阅读:
    复制表结构及数据
    mysql 字段名是关键字 报错
    mysql 截取字符串
    《官方资料》 例如:string 函数 、分组函数
    mysql event 入门
    Spring国际化
    Python学习记录
    精选股文
    为VS定制一个自己的代码生成器
    房产常识
  • 原文地址:https://www.cnblogs.com/lilto/p/11878104.html
Copyright © 2011-2022 走看看