【驱动】USB驱动·入门【转】

转自:http://www.cnblogs.com/lcw/p/3159371.html

Preface

   USB是目前最流行的系统总线之一。随着计算机周围硬件的不断扩展,各种设备使用不同的总线接口,导致计算机外部总线种类繁多,管理困难。USB总线正是因此而诞生的。

USB总线提供了所有外部设备的统一连接方式,并且支持热插拔,方便了厂商开发设备和用户使用设备。

USB遵循原则

   USB的设计目标是对现有的PC机体系进行扩充,但是目前不仅是PC机,许多的嵌入式系统都开始支持USB总线和接口标准。USB设计主要遵循下面几个原则:

易于扩充外部设备:USB支持一个接口最多127个设备。

灵活的传输协议: 支持同步和异步数据传输。

设备兼容性好: 可以兼容不同类型的设备。

接口标准统一:不同的设备之间使用相同的设备接口。

USB体系概述

   USB接口标准支持主机和外部设备之间进行数据传输。

   在USB体系结构中,主机预定了各种类型外部设备使用的总线带宽。当外部设备和主机在运行时,USB总线允许添加、设置、使用和拆除外设。

   在USB体系结构中,一个USB系统可以分成USB互联、USB设备和USB主机三个部分。

   USB互联是USB设备和USB主机之间进行连接通信的操作,主要包括:

总线拓扑结构:USB主机和USB设备之间的连接方式。

数据流模式:描述USB通信系统中数据如何从产生方传递到使用方。

USB调度:USB总线是一个共享连接,对可以使用的连接进行了调试以支持同步数据传输,并且避免优先级判定的开销。

   USB的物理连接是一个有层次的星形结构。

   在一个节点上连接多个设备需要使用 USB集线器(USB HUB)。

   USB体系结构规定,在一个 USB系统中,只有唯一的一个主机。USB和主机系统的接口称做主机控制器,主机控制器由主机控制器芯片、固件程序和软件共同实现的。

   USB设备包括USB集线器和功能器件。其中USB集线器的作用是扩展总线端点,向总线提供更多的连接点;功能器件是用户使用的外部设备,如键盘,鼠标等。

   USB设备需要支持 USB总线协议,对主机的操作提供反馈并且提供设备性能的描述信息。

USB体系工作流程

   USB总线采用轮询方式控制,主机控制设置初始化所有的数据传输。

   USB总线每次执行传输动作最多可以传输三个数据包。每次开始传输时,主机控制器发送一个描述符描述传输动作的种类和方向,这个数据包称作标志数据包(Token Packet)。USB设备收到主机发送的标志数据包后解析出数据自己的数据。

   USB数据传输的方向只有两种:主机到设备或者设备到主机。

   在一个数据传输开始时,由标志包标示数据的传输方向,然后发送端开始发送包含信息的数据。接收端发送一个握手的数据包表明数据是否传送成功。

   在主机和设备之间的USB数据传输可以看做一个通道。USB数据传输有流和消息两种通道。消息是有格式的数据,而流是没有数据格式的。

   USB有一个缺省的控制消息通道,在设备启动的时候被创建,因此设备的设置查询和输入控制信息都可以使用缺省消息控制通道完成。

USB驱动程序框架

   Linux内核提供了完整的USB驱动程序框架。

   USB总线采用树形结构,在一条总线上只能有唯一的主机设备。

   Linux内核从主机和设备两个角度观察USB总线结构。

Linux内核USB驱动框架

   左侧是主机驱动结构。

   主机驱动的最底层是 USB主机控制器,提供了 OHCI/EHCI/UHCI这3种类型的总线控制功能。

   在USB控制器的上一层是主机控制器的驱动,分别对应OHCI/EHCI/UHCI这3种类型的总线接口。

   USB核心部分连接了 USB控制器驱动和设备驱动,是两者之间的转换接口。

   USB设备驱动层提供了各种设备的驱动程序。

   所有类型的 USB设备都是用相同的电气接口,使用的传输协议也基本相同。

   向用户提供某种特定类型的 USB设备时,需要处理 USB总线协议。内核完成所有的 USB总线协议处理,并且向用户提供编程接口。

   右侧是设备驱动结构。

   与USB主机类似,USB设备提供了相同的层次结构与之对应。但是在 USB设备一侧使用名为 Gadget API的结构作为核心。

   Gadget API是 Linux内核实现的对应 USB设备的核心结构。Gadget API屏蔽了 USB设备控制器的细节,控制具体的 USB设备实现。

设备

   每个 USB设备提供了不同级别的配置信息。

   一个 USB设备可以包含一个或多个配置,不同的配置使设备表现出不同的特点。其中,设备的配置是通过接口组成的。

   Linux内核定义了 USB设备描述结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//源定义在Usb_ch9.h
/* USB_DT_DEVICE: Device descriptor */
struct usb_device_descriptor {
    __u8  bLength;  //设备描述符长度
    __u8  bDescriptorType;  //设备类型
    __le16 bcdUSB;  // USB版本号(使用 BCD编码)
    __u8  bDeviceClass; //  USB设备类型
    __u8  bDeviceSubClass;  //  USB设备子类型
    __u8  bDeviceProtocol;  //  USB设备协议号
    __u8  bMaxPacketSize0;  //传输数据的最大包长
    __le16 idVendor;    //厂商编号
    __le16 idProduct;   //产品编号
    __le16 bcdDevice;   //设备出厂号
    __u8  iManufacturer;    //厂商字符串索引
    __u8  iProduct; //产品字符串索引
    __u8  iSerialNumber;    //产品序列号索引
    __u8  bNumConfigurations;   //最大的配置数量
} __attribute__ ((packed));

   从 usb_device_descrptor结构定义看出,一个设备描述定义了与 USB设备有关的所有信息。

接口

   在 USB体系中,接口是由多个端点组成的。

   一个接口代表一个基本的功能,是 USB设备驱动程序控制的对象。

   一个 USB设备最少有一个接口,功能复杂的 USB设备可以有多个接口。接口描述定义如下:Usb

1
2
3
4
5
6
7
8
9
10
11
12
13
//源定义在 Usb_ch9.h
/* USB_DT_INTERFACE: Interface descriptor */
struct usb_interface_descriptor {
    __u8  bLength;  //描述符长度
    __u8  bDescriptorType;  //描述符类型
    __u8  bInterfaceNumber; //接口编号
    __u8  bAlternateSetting;    //备用接口编号
    __u8  bNumEndpoints;    //端点数量
    __u8  bInterfaceClass;  //接口类型
    __u8  bInterfaceSubClass;   //接口子类型
    __u8  bInterfaceProtocol;   //接口使用的协议
    __u8  iInterface;   //接口索引字符串数值
} __attribute__ ((packed));

端点

   端点是 USB总线通信的基本形式,每个 USB设备接口可以认为是端点的集合。

   主机只能通过端点与设备通信。

   USB体系结构规定每个端点都有一个唯一的地址,由设备地址和端点号决定端点地址。

   端点还包括了与主机通信用到的属性,如传输方式、总线访问频率、带宽和端点号等。

   端点的通信是单向的,通过端点传输的数据只能是从主机到设备或者从设备到主机。

   端点的定义描述如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
/* USB_DT_ENDPOINT: Endpoint descriptor */
struct usb_endpoint_descriptor {
    __u8  bLength;  //描述符长度
    __u8  bDescriptorType;  //描述符类型
    __u8  bEndpointAddress; //端点地址
    __u8  bmAttributes; //端点属性
    __le16 wMaxPacketSize;  //端点接收的最大数据包长度
    __u8  bInterval;
    /* NOTE:  these two are _only_ in audio endpoints. */
    /* use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. */
    __u8  bRefresh;
    __u8  bSynchAddress;
} __attribute__ ((packed));

配置

   配置是一个接口的集合。

   Linux内核配置的定义如下:

1
2
3
4
5
6
7
8
9
10
struct usb_config_descriptor {
    __u8  bLength;  //描述符长度
    __u8  bDescriptorType;  //描述符类型
    __le16 wTotalLength;    //配置返回数据长度
    __u8  bNumInterfaces;   //最大接口数
    __u8  bConfigurationValue;  //配置参数值
    __u8  iConfiguration;   //配置描述字符串索引
    __u8  bmAttributes; //供电模式
    __u8  bMaxPower;    //接口的最大电流
} __attribute__ ((packed));

主机驱动结构

   USB主机控制器有三种类型:

OHCI,英文全称是Open Host Controller Interface。OHCI是用于SiS和Ali芯片组的USB控制器。

UHCI,英文全称是Universal Host Controller Interface。UHCI用于Intel和AMD芯片组的USB控制器。UHCI类型的控制器比OHCI控制器硬件结构要简单,但是需要额外的驱动支持,因此从理论上说速度要慢。

EHCI,USB2.0规范提出的一种控制器标准,可以兼容UHCI和OHCI。

USB主机控制器驱动

   Linux内核使用 usb_hcd结构描述 USB主机控制器驱动。

   usb_hcd结构描述了 USB主机控制器的硬件信息、状态和操作函数。定义如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
//源定义在Hcd.h
struct usb_hcd {    /* usb_bus.hcpriv points to this */
    /*
     * housekeeping //控制器基本信息
     */
    struct usb_bus      self;       /* hcd is-a bus */
    const char      *product_desc;  /* product/vendor string */ //厂商名称字符串
    char            irq_descr[24];  /* driver + bus # */    //驱动和总线类型
    struct timer_list   rh_timer;   /* drives root-hub polling */   //根 hub轮询时间间隔
    struct urb      *status_urb;    /* the current status urb */    //当前 urb状态
    /*
     * hardware info/state  //硬件信息和状态
     */
    const struct hc_driver  *driver;    /* hw-specific hooks */ //控制器驱动使用的回调函数
    /* Flags that need to be manipulated atomically */
    unsigned long       flags;
#define HCD_FLAG_HW_ACCESSIBLE  0x00000001
#define HCD_FLAG_SAW_IRQ    0x00000002
    unsigned        rh_registered:1;/* is root hub registered? */   //是否注册根 hub
    /* The next flag is a stopgap, to be removed when all the HCDs
     * support the new root-hub polling mechanism. */
    unsigned        uses_new_polling:1; //是否允许轮询根 hub状态
    unsigned        poll_rh:1;  /* poll for rh status? */
    unsigned        poll_pending:1; /* status has changed? */   //状态是否改变
    int         irq;        /* irq allocated */ //控制器的中断请求号
    void __iomem        *regs;      /* device memory/io */  //控制器使用的内存和 I/O
    u64         rsrc_start; /* memory/io resource start */  //控制器使用的内存和 I/O起始地址
    u64         rsrc_len;   /* memory/io resource length */ //控制器使用的内存和 I/O资源长度
    unsigned        power_budget;   /* in mA, 0 = no limit */
#define HCD_BUFFER_POOLS    4
    struct dma_pool     *pool [HCD_BUFFER_POOLS];
    int         state;
#   define  __ACTIVE        0x01
#   define  __SUSPEND       0x04
#   define  __TRANSIENT     0x80
#   define  HC_STATE_HALT       0
#   define  HC_STATE_RUNNING    (__ACTIVE)
#   define  HC_STATE_QUIESCING  (__SUSPEND|__TRANSIENT|__ACTIVE)
#   define  HC_STATE_RESUMING   (__SUSPEND|__TRANSIENT)
#   define  HC_STATE_SUSPENDED  (__SUSPEND)
#define HC_IS_RUNNING(state) ((state) & __ACTIVE)
#define HC_IS_SUSPENDED(state) ((state) & __SUSPEND)
    /* more shared queuing code would be good; it should support
     * smarter scheduling, handle transaction translators, etc;
     * input size of periodic table to an interrupt scheduler.
     * (ohci 32, uhci 1024, ehci 256/512/1024).
     */
    /* The HC driver's private data is stored at the end of
     * this structure.
     */
    unsigned long hcd_priv[0]
            __attribute__ ((aligned (sizeof(unsigned long))));
};

OHCI控制器驱动

   usb_hcd结构可以理解为一个通用的 USB控制器描述结构,OHCI主机控制器是 usb_hcd结构的具体实现。

   内核使用 ohci_hcd结构描述 OHCI主机控制器,定义如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
struct ohci_hcd {
    spinlock_t      lock;
    /*
     * I/O memory used to communicate with the HC (dma-consistent)  //用于 HC通信的 I/O内存地址
     */
    struct ohci_regs __iomem *regs;
    /*
     * main memory used to communicate with the HC (dma-consistent)。    //用于 HC 通告的主内存地址
     * hcd adds to schedule for a live hc any time, but removals finish
     * only at the start of the next frame.
     */
    struct ohci_hcca    *hcca;
    dma_addr_t      hcca_dma;
    struct ed       *ed_rm_list;        /* to be removed */ //将被移除列表
    struct ed       *ed_bulktail;       /* last in bulk list */ //列表最后一项
    struct ed       *ed_controltail;    /* last in ctrl list */ //控制列表最后一项
    struct ed       *periodic [NUM_INTS];   /* shadow int_table */
    /*
     * OTG controllers and transceivers need software interaction;
     * other external transceivers should be software-transparent
     */
    struct otg_transceiver  *transceiver;
    /*
     * memory management for queue data structures  //内存管理队列使用的数据结构
     */
    struct dma_pool     *td_cache;
    struct dma_pool     *ed_cache;
    struct td       *td_hash [TD_HASH_SIZE];
    struct list_head    pending;
    /*
     * driver state
     */
    int         num_ports;
    int         load [NUM_INTS];
    u32             hc_control; /* copy of hc control reg */    // HC控制寄存器复制
    unsigned long       next_statechange;   /* suspend/resume */    //挂起 恢复
    u32         fminterval;     /* saved register */    //保存的寄存器
    struct notifier_block   reboot_notifier;
    unsigned long       flags;      /* for HC bugs */
#define OHCI_QUIRK_AMD756   0x01            /* erratum #4 */
#define OHCI_QUIRK_SUPERIO  0x02            /* natsemi */
#define OHCI_QUIRK_INITRESET    0x04            /* SiS, OPTi, ... */
#define OHCI_BIG_ENDIAN     0x08            /* big endian HC */
#define OHCI_QUIRK_ZFMICRO  0x10            /* Compaq ZFMicro chipset*/
    // there are also chip quirks/bugs in init logic    //芯片的初始化逻辑里也同样会有怪异的 Bug
};
   OHCI主机控制器是嵌入式系统最常用的一种 USB主机控制器。

设备驱动结构

   USB协议规定了许多种USB设备类型。Linux内核实现了音频设备、通信设备、人机接口、存储设备、电源设备、打印设备等几种USB设备类。

基本概念

   Linux内核实现的 USB设备驱动都是针对通用的设备类型设计的。

   只要 USB存储设备是按照标准的 USB存储设备规范实现的,就可以直接被内核 USB存储设备驱动。如果一个 USB设备是非标准的,则需要编写对应设备的驱动程序。

设备驱动结构

   内核使用 usb_driver结构体描述 USB设备驱动,定义如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
struct usb_driver {
    const char *name;
    int (*probe) (struct usb_interface *intf,
              const struct usb_device_id *id);  //探测函数
    void (*disconnect) (struct usb_interface *intf);    //断开连接函数
    int (*ioctl) (struct usb_interface *intf, unsigned int code,
            void *buf); // I/O控制函数
    int (*suspend) (struct usb_interface *intf, pm_message_t message);  //挂起函数
    int (*resume) (struct usb_interface *intf); //恢复函数
    void (*pre_reset) (struct usb_interface *intf);
    void (*post_reset) (struct usb_interface *intf);
    const struct usb_device_id *id_table;
    struct usb_dynids dynids;
    struct device_driver driver;
    unsigned int no_dynamic_id:1;
};
实现一个 USB设备的驱动主要是实现 probe()和 disconnect()函数接口。

probe()函数在插入 USB设备的时候被调用,disconnect()函数在拔出 USB设备的时候被调用。

USB请求块

   USB请求块(USB request block,urb)的功能类似于网络设备中的 sk_buff,用于描述 USB设备与主机通信的基本数据结构。

   urb结构在内核中定义如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
//源定义在 Usb.h
struct urb
{
    /* private: usb core and host controller only fields in the urb */
    struct kref kref;       /* reference count of the URB */    // urb引用计数
    spinlock_t lock;        /* lock for the URB */  // urb锁
    void *hcpriv;           /* private data for host controller */  //主机控制器私有数据
    int bandwidth;          /* bandwidth for INT/ISO request */ //请求带宽
    atomic_t use_count;     /* concurrent submissions counter */    //并发传输计数
    u8 reject;          /* submissions will fail */ //传输即将失败标志
    /* public: documented fields in the urb that can be used by drivers */  //公有数据,可以被驱动使用
    struct list_head urb_list;  /* list head for use by the urb's   //链表头
                     * current owner */
    struct usb_device *dev;     /* (in) pointer to associated device */ //关联的 USB设备
    unsigned int pipe;      /* (in) pipe information */ //管道信息
    int status;         /* (return) non-ISO status */   //当前信息
    unsigned int transfer_flags;    /* (in) URB_SHORT_NOT_OK | ...*/
    void *transfer_buffer;      /* (in) associated data buffer */   //数据缓冲区
    dma_addr_t transfer_dma;    /* (in) dma addr for transfer_buffer */ //DMA使用的缓冲区
    int transfer_buffer_length; /* (in) data buffer length */   //缓冲区大小
    int actual_length;      /* (return) actual transfer length */   //实际接收或发送数据的长度
    unsigned char *setup_packet;    /* (in) setup packet (control only) */
    dma_addr_t setup_dma;       /* (in) dma addr for setup_packet */    //设置数据包缓冲区
    int start_frame;        /* (modify) start frame (ISO) */    //等时传输中返回初始帧
    int number_of_packets;      /* (in) number of ISO packets */    //等时传输中缓冲区数据
    int interval;           /* (modify) transfer interval   //轮询的时间间隔
                     * (INT/ISO) */
    int error_count;        /* (return) number of ISO errors */ //出错次数
    void *context;          /* (in) context for completion */
    usb_complete_t complete;    /* (in) completion routine */
    struct usb_iso_packet_descriptor iso_frame_desc[0];
                    /* (in) ISO ONLY */
};
   内核提供了一组函数 urb类型的结构变量。urb的使用流程如下:

创建 urb。在使用之前,USB设备驱动需要调用 usb_alloc_urb()函数创建一个 urb;内核还提供释放 urb的函数,在不使用 urb的时候(退出驱动种马或者挂起驱动),需要使用 usb_free_urb()函数释放 urb。

初始化 urb。设置 USB设备的端点。使用内核提供的 usb_init_urb()函数设置 urb初始结构。

提交 urb到 USB核心。在分配并设置 urb完毕后,使用 urb_submit_urb()函数把新的 urb提交到 USB核心。

USB驱动程序框架

   Linux内核代码driver/usb/usb-skeleton.c文件是一个标准的USB设备驱动程序。

   编写一个USB设备的驱动可以参考usb-skeleton.c文件,实际上,可以直接修改该文件驱动新的USB设备。

基本数据结构

   usb-skel设备使用自定义结构 usb_skel记录设备驱动用到的所有描述符,该结构定义如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/* Structure to hold all of our device specific stuff */
struct usb_skel {
    struct usb_device * udev;           /* the usb device for this device */
        // USB设备描述符
    struct usb_interface *  interface;      /* the interface for this device */
        // USB接口描述符
    struct semaphore    limit_sem;      /* limiting the number of writes in progress */
        // 互斥信号量
    unsigned char *     bulk_in_buffer;     /* the buffer to receive data */
        // 数据接收缓冲区
    size_t          bulk_in_size;       /* the size of the receive buffer */
        // 数据接收缓冲区大小
    __u8            bulk_in_endpointAddr;   /* the address of the bulk in endpoint */
        // 入端点地址
    __u8            bulk_out_endpointAddr;  /* the address of the bulk out endpoint */
        // 出端点地址
    struct kref     kref;
};
   usb-skel设备驱动把 usb_skel结构存放在了 urb结构的 context指针里。通过 urb,设备的所有操作函数都可以访问到 usb_skel结构。

   其中,limit_sem成员是一个信号量,当多个 usb-skel类型的设备存在于系统中的时候,需要控制设备之间的数据同步。

驱动程序初始化和注销

   与其他所有的 Linux设备驱动程序一样,usb-skel驱动使用 module_init()宏设置初始化函数,使用 module_exit()宏设置注销函数。

   usb-skel驱动的初始化函数是 usb_skel_init()函数,定义如下:

1
2
3
4
5
6
7
8
9
static int __init usb_skel_init(void)
{
    int result;
    /* register this driver with the USB subsystem */
    result = usb_register(&skel_driver);    //注册 USB设备驱动
    if (result)
        err("usb_register failed. Error number %d", result);
    return result;
}
   usb_skel_init()函数调用内核提供的 usb_register()函数注册了一个 usb_driver类型的结构变量,该变量定义如下:

1
2
3
4
5
6
static struct usb_driver skel_driver = {
    .name =     "skeleton", // USB设备名称
    .probe =    skel_probe, // USB设备初始化函数
    .disconnect =   skel_disconnect,    // USB设备注销函数
    .id_table = skel_table, // USB设备 ID映射表
};
   skel_driver结构变量中,定义了 usb-skel设备的名、设备初始化函数、设备注销函数和 USB ID映射表。

   其中 usb-skel设备的 USB ID映射表定义如下:

1
2
3
4
5
/* table of devices that work with this driver */
static struct usb_device_id skel_table [] = {
    { USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) },
    { }                 /* Terminating entry */
};
   skel_table中只有一项,定义了一个默认的 usb-skel设备的 ID,其中,USB_SKEL_VENDOR_ID是 USB设备的厂商 ID,USB_SKEL_PRODUCT_ID是 USB设备 ID。

设备初始化

   从 skel_driver结构可以知道 usb-skel设备的初始化函数是 skel_probe()函数。

设备初始化主要是探测设备类型,分配 USB设备用到的 urb资源,注册 USB设备操作函数等。

skel_class结构变量记录了 usb-skel设备信息,定义如下:

1
2
3
4
5
6
7
8
9
/*
 * usb class driver info in order to get a minor number from the usb core,
 * and to have the device registered with the driver core
 */
static struct usb_class_driver skel_class = {
    .name =     "skel%d",   //设备名称
    .fops =     &skel_fops, //设备操作函数
    .minor_base =   USB_SKEL_MINOR_BASE,
};
   name变量使用 %d通配符表示一个整形变量,当一个 usb-skel类型的设备连接到 USB总线后会按照子设备编号自动设置设备名称。

   fops是设备操作函数结构变量,定义如下:

1
2
3
4
5
6
7
static struct file_operations skel_fops = {
    .owner =    THIS_MODULE,
    .read =     skel_read,  //读操作
    .write =    skel_write, //写操作
    .open =     skel_open,  //打开操作
    .release =  skel_release,   //关闭操作
};
   skel_ops定义了 usb-skel设备的操作函数。当在 usb-skel设备上发生相关事件时,USB文件系统会调用对应的函数处理。

设备注销

   skel_disconnect()函数在注销设备的时候被调用,定义如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
static void skel_disconnect(struct usb_interface *interface)
{
    struct usb_skel *dev;
    int minor = interface->minor;
    /* prevent skel_open() from racing skel_disconnect() */
    lock_kernel();  //在操作之前加锁
    dev = usb_get_intfdata(interface);  //获得 USB设备接口描述
    usb_set_intfdata(interface, NULL);  //设置 USB设备接口描述无效
    /* give back our minor */
    usb_deregister_dev(interface, &skel_class); //注销 USB设备操作供述
    unlock_kernel();    //操作完毕解锁
    /* decrement our usage count */
    kref_put(&dev->kref, skel_delete);   //减小引用计数
    info("USB Skeleton #%d now disconnected", minor);
}
static struct usb_driver skel_driver = {
    .name =     "skeleton", // USB设备名称
    .probe =    skel_probe, // USB设备初始化函数
    .disconnect =   skel_disconnect,    // USB设备注销函数
    .id_table = skel_table, // USB设备 ID映射表
};
   skel_disconnect()函数释放 usb-skel设备用到的资源。

   首先获取 USB设备接口描述,之后设置为无效;然后调用 usb_deregister_dev()函数注销 USB设备的操作描述符,注销操作本身需要加锁;注销设备描述符后,更新内核对 usb-skel设备的引用计数。

 

时间: 2024-11-05 18:46:04

【驱动】USB驱动·入门【转】的相关文章

【驱动】USB驱动实例·串口驱动·键盘驱动【转】

转自:http://www.cnblogs.com/lcw/p/3159370.html Preface USB体系支持多种类型的设备. 在 Linux内核,所有的USB设备都使用 usb_driver结构描述. 对于不同类型的 USB设备,内核使用传统的设备驱动模型建立设备驱动描述,然后映射到 USB设备驱动,最终完成特定类型的 USB设备驱动 USB驱动·入门:http://infohacker.blog.51cto.com/6751239/1226257 USB串口驱动 USB串口驱动关键

win7电脑如何卸载USB驱动?

  USB驱动出现故障的后果是很严重的,也许很多朋友还没有意识到,USB接口在咱们日常生活中已经扮演了非常重要的角色.例如很多朋友喜欢用电脑直接给手机充电,如果USB接口无法使用的话,那么充电就无法进行;很多朋友工作上都需要使用U盘,使用U盘也需要使用USB接口.当然,还有其他的情况,咱们这里就不一一举例了,下面,小编就来讲述一下,ghost win7电脑如何快速的卸载USB驱动. 1.首先,咱们返回到桌面界面,然后找到桌面的计算机图标,右键点击该图标,选择下滑菜单中的属性选项. 2.在属性窗口

驱动人生安装USB驱动教程

  为了保障移动设备在电脑上能够正常运行,第一次接入某台电脑时都需要安装一个驱动,手机需要安装手机驱动,U盘需要安装USB驱动等等. 当你将U盘或手机等移动设备连接到电脑时你会发现电脑的右下角工具栏里会出现"正在安装驱动程序,请稍等--"此时,电脑正在为你的设备自动安装驱动程序,一般情况下,数十秒即可成功安装驱动程序. 但有时候移动设备插入电脑的usb接口后,却显示"未成功安装驱动程序",这时候就需要手动安装驱动程序了. 由于USB驱动都是自动安装,所以在出现问题时

USB驱动如何卸载?

  右键我的电脑(计算机),选择属性,在弹出来的窗口里选择左上角的"设备管理器",然后继续在弹出来的窗口里选择"通用串行总线控制器"点击下,最后选择你想要卸载的USB驱动右键点击卸载就OK了!

VxWorks下USB驱动总结2

3:USBD驱动详解 这一部分将要描述USBD(USB Host Driver)的典型应用.例如初始化,client注册,动态连接注册,设备配置,数据传输,同时还探讨了USBD内部设计的关键特性.这部分是VxWorks下USB驱动的核心.   1 初始化USBD:分为两步 (1)必须至少调用一次函数usbdInitialize().在一个给定的系统中,usbdlnifialize()初始化内部USBD数据结构,并依次调用其它USB驱动栈模块的入口.usbdinitialize()可以在启动时调用

linux-LINUX内核usb驱动,如何知道数据正在USB接口上传输(包括读写)?

问题描述 LINUX内核usb驱动,如何知道数据正在USB接口上传输(包括读写)? 开始数据传输必调用的内核函数是哪个? 数据传输结束必调用的内核函数是哪个? 另外我想在开始和结束的时候做标记,吐一个信息到/tmp/dataTransferSymbol; 或者吐到系统日志也行,设备运行过程中使用dmesg能看到数据传输标志,怎么实现呢? 请高手赐教.谢谢.

WinCE USB驱动开发经验谈

WinCE USB驱动开发经验谈 随着USB2.0设备的不断增加,USB设备驱动开发在嵌入式开发中变的越来越重要.Windows CE支持USB 2.0更是对这一波新技术浪潮产生巨大的推动.近期我负责一个这样的项目,在WinCE下开发USB接口的外围设备驱动.当时做这个项目花费了我相当多的时间和精力,错走许多冤枉路使我精疲力尽. 项目需求是在已调好的ARM9板子上开发USB WiFi无线网卡的驱动程序,具体要求是驱动程序平台是WinCE,CPU类型支持ARM构架,要能比较方便地移植到X86:驱动

WinXP下USB驱动开发(八)

3.3.2.8.    即插即用(PNP) 即插即用(Plug and Play -- PnP)管理器使用主功能码为IRP_MJ_PNP的IRP与设备驱动程序交换信息和请求.这种类型的请求是新引入到Windows 2000和WDM中的,在以前版本的Windows NT中,大部分检测和配置设备的工作由设备驱动程序自己做.而WDM驱动程序可以让PnP管理器做这个工作.为了与PnP管理器协同工作,驱动程序开发者需要了解一些相关的IRP. 在WDM中,PnP请求扮演了两个角色.在第一个角色中,这些请求指

内核-关于Android的USB驱动

问题描述 关于Android的USB驱动 我手头上有一个CH341 USB转串口芯片的外设,我在官网找到它的Linux USB驱动源码,官方说明是这样的"软件简介: USB转串口CH340/CH341的虚拟串口驱动程序",文件夹里有 3个文件 我是想能不能把这个驱动加载进Android手机的内核中,以供应用层操作(其实我就是想把这个外设插入Android手机中使用). --不知道这个思路对不对 --这想法能否实现?不知道对Android手机硬件有无要求 --是通过刷内核的方式么? --