linux驱动程序设计之USB

来源:互联网 发布:极光大数据 王者荣耀 编辑:程序博客网 时间:2024/05/16 12:35
usb:通用串行总线,是一种外部总线标准,用于规范电脑与外部设备的连接和通讯。

有一个称为主机控制器的设备,该控制器和一个根Hub作为一个整体。这个根Hub下可以接多级的Hub,每个子Hub又可以接子Hub。每个USB设备作为一个节点接在不同级别的Hub上。 每条USB总线上最多可以接127个设备。

常见的USB主控制器规格有:
OHCI:主要是非PC系统上的USB芯片
UHCI:大多是Intel和Via主板上的USB控制器芯片。他们都是由USB1.1规格的。
EHCI:是由Intel等几个厂商研发,兼容OHCIUHCI ,遵循USB2.0规范。

设备逻辑结构:
在USB设备的逻辑组织中,包含设备、配置、接口和端点4个层次。设备通常有一个或多个配置,配置通常有一个或多个接口,接口有零或多个端点。每个USB设备都可以包含一个或多个配置不同的配置使设备表现出不同的功能组合,配置由多个接口组成。在USB协议中,接口代表一个基本的功能,一个功能复杂的USB设备可以具有多个接口,而接口是端点的汇集。
USB设备中设备中的唯一可寻址的部分是设备端点,端点的作用类似于寄存器。每个端点在设备内部有唯一的端点号这个端点号是在设备设计时给定的。主机和设备的通信最终都作用于设备上的各个端点。每个端点所支持的操作都是单向的,要么只读,要么只写。

USB描述:
在每一个USB设备内部,包含了固定格式的数据,通过这些数据,USB主机就可以获取USB设备的类型 、生产厂商等信息。这些固定格式的数据,我们称之为USB描述符。标准的USB数据,我们就称之为USB描述符。标准的USB设备有5 种USB描述符:设备描述符,配置描述符,接口描述符 ,端点描述符, 字符串描述符。

usb描述描述符:

struct usb_device_descriptor { //usb设备描述符结构体
__u8  bLength;         //描述符长度
__u8  bDescriptorType; //描述符编号类型


__le16 bcdUSB;         //usb版本号
__u8  bDeviceClass;    //usb分配的设备类code
__u8  bDeviceSubClass; //usb分配的子设备类code
__u8  bDeviceProtocol; //usb分配的协议code
__u8  bMaxPacketSize0; //endpoint0最大包大小
__le16 idVendor;       //厂商编号
__le16 idProduct;      //产品编号
__le16 bcdDevice;      //设备出厂编号
__u8  iManufacturer;   
__u8  iProduct;        
__u8  iSerialNumber;
__u8  bNumConfigurations;
} __attribute__ ((packed));


struct usb_config_descriptor { //usb配置描述符结构体
__u8  bLength;         //描述符长度
__u8  bDescriptorType; //描述符编号类型


__le16 wTotalLength;
__u8  bNumInterfaces;   //配置所支持的接口数
__u8  bConfigurationValue; //set_Configuration命令所需要的参数
__u8  iConfiguration;
__u8  bmAttributes;
__u8  bMaxPower;
} __attribute__ ((packed));


struct usb_interface_descriptor { //usb接口描述结构体
__u8  bLength;
__u8  bDescriptorType;


__u8  bInterfaceNumber;
__u8  bAlternateSetting;
__u8  bNumEndpoints;
__u8  bInterfaceClass;
__u8  bInterfaceSubClass;
__u8  bInterfaceProtocol;
__u8  iInterface;
} __attribute__ ((packed));

struct usb_endpoint_descriptor {
__u8  bLength;
__u8  bDescriptorType;


__u8  bEndpointAddress; //端点地址:0-3位是端点号,第七位是方向(0输出,1输入)
__u8  bmAttributes;     //端点属性:bit[0:1],00控制,01同步,02批量,03中断
__le16 wMaxPacketSize;  //本端点接收或发送最大信息包的大小
__u8  bInterval;        //轮询数据传送端点的最大时间间隔,
                                //轮询数据传送时间间隔,
                                //批量传送及控制传送忽略,
                                //同步必须为1,
                                //中断传送1-255


/* NOTE:  these two are _only_ in audio endpoints. */
/* use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. */
__u8  bRefresh;
__u8  bSynchAddress;
} __attribute__ ((packed));


struct usb_string_descriptor {
__u8  bLength;
__u8  bDescriptorType;


__le16 wData[1];/* UTF-16LE encoded */
} __attribute__ ((packed));


struct usb_interface { //usb接口
/* array of alternate settings for this interface,
* stored in no particular order */
struct usb_host_interface *altsetting;


struct usb_host_interface *cur_altsetting;/* the currently
* active alternate setting */
unsigned num_altsetting;/* number of alternate settings */


/* If there is an interface association descriptor then it will list
* the associated interfaces */
struct usb_interface_assoc_descriptor *intf_assoc;


int minor; /* minor number this interface is
* bound to */
enum usb_interface_condition condition;/* state of binding */
unsigned sysfs_files_created:1;/* the sysfs attributes exist */
unsigned ep_devs_created:1;/* endpoint "devices" exist */
unsigned unregistering:1;/* unregistration is in progress */
unsigned needs_remote_wakeup:1;/* driver requires remote wakeup */
unsigned needs_altsetting0:1;/* switch to altsetting 0 is pending */
unsigned needs_binding:1;/* needs delayed unbind/rebind */
unsigned resetting_device:1;/* true: bandwidth alloc after reset */
unsigned authorized:1;/* used for interface authorization */


struct device dev;/* interface specific device info */
struct device *usb_dev;
atomic_t pm_usage_cnt;/* usage counter for autosuspend */
struct work_struct reset_ws;/* for resets in atomic context */
};


struct usb_host_endpoint { //usb主机端口
struct usb_endpoint_descriptordesc;
struct usb_ss_ep_comp_descriptorss_ep_comp;
struct usb_ssp_isoc_ep_comp_descriptorssp_isoc_ep_comp;
struct list_headurb_list;
void *hcpriv;
struct ep_device*ep_dev;/* For sysfs info */


unsigned char *extra;   /* Extra descriptors */
int extralen;
int enabled;
int streams;
};


struct usb_host_interface {
struct usb_interface_descriptordesc;


int extralen;
unsigned char *extra;   /* Extra descriptors */


/* array of desc.bNumEndpoints endpoints associated with this
* interface setting.  these will be in no particular order.
*/
struct usb_host_endpoint *endpoint;


char *string; /* iInterface string, if present */
};


struct usb_host_config {
struct usb_config_descriptordesc;


char *string; /* iConfiguration string, if present */


/* List of any Interface Association Descriptors in this
* configuration. */
struct usb_interface_assoc_descriptor *intf_assoc[USB_MAXIADS];


/* the interfaces associated with this configuration,
* stored in no particular order */
struct usb_interface *interface[USB_MAXINTERFACES];


/* Interface information available even when this is not the
* active configuration */
struct usb_interface_cache *intf_cache[USB_MAXINTERFACES];


unsigned char *extra;   /* Extra descriptors */
int extralen;
};


usb驱动结构体


struct usb_driver { //usb驱动结构体
const char *name;


int (*probe) (struct usb_interface *intf,
     const struct usb_device_id *id);


void (*disconnect) (struct usb_interface *intf);


int (*unlocked_ioctl) (struct usb_interface *intf, unsigned int code,
void *buf);


int (*suspend) (struct usb_interface *intf, pm_message_t message);
int (*resume) (struct usb_interface *intf);
int (*reset_resume)(struct usb_interface *intf);


int (*pre_reset)(struct usb_interface *intf);
int (*post_reset)(struct usb_interface *intf);


const struct usb_device_id *id_table; //所支持usb设备的列表


struct usb_dynids dynids;
struct usbdrv_wrap drvwrap;
unsigned int no_dynamic_id:1;
unsigned int supports_autosuspend:1;
unsigned int disable_hub_initiated_lpm:1;
unsigned int soft_unbind:1;
};


usb_driver驱动的注册与注销
int usb_register(struct usb_driver *new_driver); //注册
void usb_deregister(struct usb_driver *driver);  //注销


struct usb_device_id { //usb设备的信息
/* which fields to match against? */
__u16 match_flags; 


/* Used for product specific matches; range is inclusive */
__u16 idVendor;
__u16 idProduct;
__u16 bcdDevice_lo;
__u16 bcdDevice_hi;


/* Used for device class matches */
__u8 bDeviceClass;
__u8 bDeviceSubClass;
__u8 bDeviceProtocol;


/* Used for interface class matches */
__u8 bInterfaceClass;
__u8 bInterfaceSubClass;
__u8 bInterfaceProtocol;


/* Used for vendor-specific interface matches */
__u8 bInterfaceNumber;


/* not matched against */
kernel_ulong_tdriver_info
__attribute__((aligned(sizeof(kernel_ulong_t))));
};


match_flags:


可以通过下面的宏来生成usb_device_id结构体的实例:

①USB_DEVICE(vendor,product)
该宏可以使用制造商ID和产品ID生成usb_device_id的实例,在数组中添加该实例以为着该驱动可以支持与制造商ID、产品ID匹配的设备。

②USB_DEVICE_VER(vendor,product,lo,hi)
该宏可以使用制造商ID、产品ID、产品版本的最大值和最小值生成usb_device_id的实例,在数组中添加该实例以为着该驱动可以支持与制造商ID、产品ID和lo-hi范围内版本的设备。

③USB_DEVICE_INFO(class,subclass,protocol)
该宏用于创建一个匹配设备指定类型的usb_device_id结构体的实例。

④USB_INTERFACE_INFO(class,subclass,protocol)
该宏用于创建一个匹配设接口指定类型的usb_device_id结构体的实例。

当USB核心检测某个设备的属性和某个驱动程序的usb_device_id结构体所带的信息一致时驱动程序中的porbe函数被调用。拔掉设备或卸载驱动时disconnect()函数被调用。usb只是一个总线,usb驱动包含其作为总线上挂接设备的驱动和本身所属的驱动设备类型(如:字符设备、块设备、网络设备、tty设备、input设备)。

usb请求块:

struct urb { //usb请求块
/* private: usb core and host controller only fields in the urb */
struct kref kref;/* reference count of the URB */
void *hcpriv; /* private data for host controller */
atomic_t use_count;/* concurrent submissions counter */
atomic_t reject;/* submissions will fail */
int unlinked; /* unlink error code */


/* 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 list_head anchor_list;/* the URB may be anchored */
struct usb_anchor *anchor;
struct usb_device *dev;/* (in) pointer to associated device */
struct usb_host_endpoint *ep;/* (internal) pointer to endpoint */
unsigned int pipe;/* (in) pipe information */
unsigned int stream_id;/* (in) stream ID */
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 */
struct scatterlist *sg;/* (in) scatter gather buffer list */
int num_mapped_sgs;/* (internal) mapped sg entries */
int num_sgs; /* (in) number of entries in the sg list */
u32 transfer_buffer_length;/* (in) data buffer length */
u32 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 */
};


1)被一个usb设备驱动创建:

①创建urt
struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags);
iso_packets:是这个usb请求块包含的等时数据的数目,若为0则不创建等时数据包。
mem_flags:分配内存的标志
urb不宜静态创建,因为这可能破坏usb核心给urb使用的引用计数器方法
②释放urt
void usb_free_urb(struct urb *urb);

2)初始化,被安排给特定usb设备的特定端点

①中断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_fn,
   void *context,
   int interval)
urb:要将要初始化的urb
dev:urb要发送到的设备
pipe:urb要被发送到设备的特定端点
transfer_buffer:发送缓冲区或接收缓冲区(最好动态分配)
buffer_length:缓冲区的大小
complete_fn:urb完成时的回掉函数
context:完成处理函数的“上下文”
interval:urb应当被调度的时间间隔

pipe使用usb_sndintpipe()或usb_rcvintpipe()创建。

②批量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_fn,
    void *context)

pipe使用usb_sndbulkpipe()或usb_rcvbulkpipe()创建。

③控制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_fn,
void *context)

pipe使用usb_sndctrlpipe()或usb_rcvctrlpipe()创建。

④等时urb
需要手动初始化urb。

3)被usb设备驱动提交给usb核心层
int usb_submit_urb(struct urb *urb, gfp_t mem_flags);
调用成功则把控制权交给usb核心层,成功返回0,失败返回错误号。

4)提交由USB核心指定的USB主机控制器

5)被usb主机控制器处理,进行一次usb传送。
第四和第五步有usb核心层完成,不受usb设备驱动控制。

6)当urb完成,usb主机控制器驱动通知usb设备驱动。
在以下三种情况下,urb将结束,urb回掉函数将被调用,在回掉函数中通过urb->status判断调用是否成功。
①urb被成功发送给设备,并且设备返回正确的确认,此时status为0,以为着urb数据被成功发送或接收。
②如果发送或接收数据发生错误,则urb->status将记录错误值。
③urb被从USB“去除链接”,这发生在驱动通过usb->unlink_urb()或usb_kill_urb()函数取消或urb虽被提交usb设备却被拔出。
usb->unlink_urb()是异步的,完成后调用回掉函数。usb_kill_urb()是同步的,等待完成后返回,一般在disconnect函数中调用。

简单的批量和控制urb
1) usb_bulk_msg()
创建一个USB批量URB并把它发送到特定的设备上,此函数是同步函数,它一直等待urb完成后才返回。
int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe,
void *data, int len, int *actual_length,
int timeout);
data:缓冲区指针
len:缓冲区长度
timeout:超时,为0则永远等待。
成功返回0,失败返回错误代码。

2)usb_control_msg()
它提供给usb控制信息而非批量信息。
int usb_control_msg(struct usb_device *dev, unsigned int pipe,
__u8 request, __u8 requesttype, __u16 value, __u16 index,
void *data, __u16 size, int timeout);
request: usb请求值
requesttype: usb请求类型
value: usb消息值
index: usb消息索引

usb_bulk_msg()和usb_control_msg()是同步的,因此不能在中断上下文和持有互斥锁的情况下使用。该函数也不能被任何其他函数取消。

探测和断开函数
在usb设备驱动usb_driver结构体的probe()函数中,应该完成如下工作:
①探测设备的端点地址、缓冲区大小,初始化任何可能用于控制usb设备的数据结构。
②把已经初始化的数据结构的指针保存到接口设备中。

usb_set_interface()函数可以设置usb_interface的私有数据。
int usb_set_interface(struct usb_device *dev, int ifnum, int alternate);

usb_get_intfdata()函数可以获取usb_interface的私有数据。
void *usb_get_intfdata(struct usb_interface *intf);

③注册USB设备
简单的字符设备注册使用usb_register_dev();
简单的字符设备注销使用usb_deregister_dev();
int usb_register_dev(struct usb_interface *intf,
   struct usb_class_driver *class_driver);

void usb_deregister_dev(struct usb_interface *intf,
      struct usb_class_driver *class_driver);

struct usb_class_driver {
char *name;
char *(*devnode)(struct device *dev, umode_t *mode);
const struct file_operations *fops;
int minor_base;
};

对于其他类型的设备,则调用相应的注册函数。

判断端口是否为输出端口
int usb_endpoint_is_bulk_out(
const struct usb_endpoint_descriptor *epd)

imajor()和iminor()从inode函数中获的主设备号和次设备号。

获得设备接口
struct usb_interface *usb_find_interface(struct usb_driver *drv,int minor);

原创粉丝点击