USB驱动----USB总线驱动程序

来源:互联网 发布:武术 知乎 编辑:程序博客网 时间:2024/03/28 17:21

usb总线驱动程序的作用
1. 识别设备

1.1 分配地址
1.2 并告诉USB设备(set address)
1.3 发出命令获取描述符
设备描述符的信息在 linux-2.6.22.6\include\linux\usb\Ch9.h

2 找到并安装对应的设备驱动

3 提供USB读写函数(不了解数据含义)

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

这里写图片描述

接上:

usb 1-1: new full speed USB device using s3c2410-ohci and address 2usb 1-1: configuration #1 chosen from 1 choice

断开:

usb 1-1: USB disconnect, address 2

再接上

usb 1-1: new full speed USB device using s3c2410-ohci and address 3usb 1-1: configuration #1 chosen from 1 choice

在内核目录(/work/system/linux-2.6.22.6/drivers)搜索

grep “USB device using ” * -nR

这里写图片描述
结果:

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

通过hub.c的2186行 ,可以一步步找到总线驱动的编程思路:

 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; //看结构图004           choose_address(udev)  //选择地址,也就是给新的设备分配编号(地址)           hub_port_init //打印usb 1-1: new full speed USB device using s3c2410-ohci and address 2              hub_set_address //把地址告诉USB设备              usb_get_device_descriptor(udev, 8 )// 获得设备描述符,8字节的含义包括usb_device_descriptor前八个描述              retval = usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE);//再次获得设备描述符              usb_new_device(udev) //新建一个USB设备                  err - usb_get_configuration(udev);//把所有的描述符都读出来                  usb_parse_configuration //解析                  device_add//把device放入 usb_bus_type的dev链表,                            //从usb_bus_type的driver链表里取出usb _driver                            //把usb_interface和driver的id_tabe比较                            //如果能匹配,调用usb _driver的probe

整体思路:

                 usb_bus_type                 / -------------\            usb_new_device(udev)   usb_register              /                  \   usb_interface                 usb _driver                                      id_tabe                                      probe

说明:

给新设备分配地址

static void choose_address(struct usb_device *udev){    int     devnum;    struct usb_bus  *bus = udev->bus;    /* If khubd ever becomes multithreaded, this will need a lock */    /* Try to allocate the next devnum beginning at bus->devnum_next. */    devnum = find_next_zero_bit(bus->devmap.devicemap, 128,            bus->devnum_next); //找下一个零位,一直找到第128个,插入USB设备分配地址2,下一个分配地址3...    if (devnum >= 128)        devnum = find_next_zero_bit(bus->devmap.devicemap, 128, 1);//如果大于128,从头开始    bus->devnum_next = ( devnum >= 127 ? 1 : devnum + 1);    if (devnum < 128) {        set_bit(devnum, bus->devmap.devicemap);        udev->devnum = devnum;    }}

新建一个usb驱动

int usb_new_device(struct usb_device *udev){    int err;    /* Determine quirks */    usb_detect_quirks(udev);    err = usb_get_configuration(udev);//获得它的配置    if (err < 0) {        dev_err(&udev->dev, "can't read configurations, error %d\n",            err);        goto fail;    }

接口描述符

   struct usb_interface_descriptor {      __u8  bLength;//设备描述符的字节数大小,为0x12      __u8  bDescriptorType;//描述符类型编号,为0x01       __u8  bInterfaceNumber;//接口的编号       __u8  bAlternateSetting;//备用的接口描述符编号       __u8  bNumEndpoints;//该接口使用端点数,不包括端点0      __u8  bInterfaceClass;//接口类型       __u8  bInterfaceSubClass;//接口子类型      __u8  bInterfaceProtocol;//接口所遵循的协议       __u8  iInterface;//描述该接口的字符串索引值  } __attribute__ ((packed));  

怎样写usb设备驱动程序?

①分配/设置 USB_driver结构体
.id_tabe //支持哪些设备
.probe
.disconnect
②注册

现在使用USB鼠标用作按键 ,写一个简单usb框架:
左 :L 右:S 中:回车
① 分配input_dev
② 设置
③ 注册
④ 硬件操作
这4步在 probe 实现。

先参考内核中的usbmouse.c(drivers\hid\usbhid\usbmouse.c)

#include <linux/kernel.h>#include <linux/slab.h>#include <linux/module.h>#include <linux/init.h>#include <linux/usb/input.h>#include <linux/hid.h>

第一步:

static int usbmouse_as_key_init(void){    /* 注册 */    usb_register(&usbmouse_as_key_driver);    return 0;}static void usbmouse_as_key_exit(void){  /* 注销 */    usb_deregister(&usbmouse_as_key_driver);    }module_init(usbmouse_as_key_init);module_exit(usbmouse_as_key_exit);

第二部:

/* 分配/设置usb_driver */static struct usb_driver usbmouse_as_key_driver = {    .name       = "usbmouse_as_key_", //设备名称    .probe      = usbmouse_as_key_probe,    .disconnect = usbmouse_as_key_disconnect,    .id_table   = usbmouse_as_key_id_table,//支持的设备};

然后填充:

static struct usb_device_id usbmouse_as_key_id_table [] = {    { USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,        USB_INTERFACE_PROTOCOL_MOUSE) },        /*支持某一款USB_DEVICE,在usb.h中的USB_DEVICE(vend,prod)*/    //{USB_DEVICE(0x1234,0x5678)},     { } /* Terminating entry */  };
static int usbmouse_as_key_probe(struct usb_interface *intf, const struct usb_device_id *id){    printk("found usbmouse!\n");    return 0;}
static void usbmouse_as_key_disconnect(struct usb_interface *intf){    printk("disconnect usbmouse!\n");}

分析:

 .id_table  = usbmouse_as_key_id_table,//支持的设备

在usbmouse.c函数中去usb_mouse_id_table的定义

static struct usb_device_id usb_mouse_id_table [] = {    { USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,        USB_INTERFACE_PROTOCOL_MOUSE) },    { } /* Terminating entry */};

去宏 USB_INTERFACE_INFO

#define USB_INTERFACE_INFO(cl,sc,pr) \    .match_flags = USB_DEVICE_ID_MATCH_INT_INFO, .bInterfaceClass = (cl), \    .bInterfaceSubClass = (sc), .bInterfaceProtocol = (pr)/*  match_flags匹配设备描述符的哪一项,INT_INFO是接口信息,cl是类,sc是子类,pr是协议。  所以,usb_mouse_id_table中,只要接口设备描述符的类是HID,子类是BOOT,协议是MOUSE 就可以支持*/

这样就实现了一个usb驱动的框架构建。

测试:
1.make menuconfig 去掉原来的usb鼠标驱动
(cd /work/system/linux-2.6.22.6)

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

2.make uImage 并使用新的内核启动

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

4.编译USB驱动程序,拷贝到/work/nfs_root/first_fs

5.使用新的uImage启动开发板

nfs 30000000 192.168.1.102:/work/nfs_root/uImage_nohid
bootm 30000000

mount -t nfs -o nolock,vers=2 192.168.1.102:/work/nfs_root/first_fs /mnt
cd /mnt
开发板,安装驱动 insmod usbmouse_as_key.ko

插拔鼠标可以看到如下结果:
这里写图片描述

参考usbmouse.c的usb_mouse_probe,通过usb_interface(设备接口)找到
struct usb_device *dev = interface_to_usbdev(intf);
查看usb_device结构体的设备描述符

struct usb_device_descriptor {      __u8  bLength;//设备描述符的字节数大小,为0x12       __u8  bDescriptorType;//描述符类型编号,为0x01       __le16 bcdUSB;//USB版本号       __u8  bDeviceClass;//USB分配的设备类代码,0x01~0xfe为标准设备类,0xff为厂商自定义类型       //0x00不是在设备描述符中定义的,如HID       __u8  bDeviceSubClass;//usb分配的子类代码,同上,值由USB规定和分配的      __u8  bDeviceProtocol;//USB分配的设备协议代码,同上       __u8  bMaxPacketSize0;//端点0的最大包的大小       __le16 idVendor;//厂商编号       __le16 idProduct;//产品编号       __le16 bcdDevice;//设备出厂编号      __u8  iManufacturer;//描述厂商字符串的索引       __u8  iProduct;//描述产品字符串的索引      __u8  iSerialNumber;//描述设备序列号字符串的索引       __u8  bNumConfigurations;//可能的配置数量  } __attribute__ ((packed)); 

在usb驱动程序的 usbmouse_as_key_probe 添加如下

 static int usbmouse_as_key_probe(struct usb_interface *intf, const struct usb_device_id *id){    struct usb_device *dev = interface_to_usbdev(intf);    printk("bcdUSB = %x\n", dev->descriptor.bcdUSB);// dev->descriptor.bcdUSB,dev结构体里面的设备描述符    printk("VID    = 0x%x\n", dev->descriptor.idVendor);    printk("PID    = 0x%x\n", dev->descriptor.idProduct);}

测试结果:

这里写图片描述

这里写图片描述

原创粉丝点击