Linux设备驱动开发---USB主机(控制器)与设备驱动(二)

一、Linux USB驱动层次

USB主机(控制器)与设备驱动(一)

二、USB主机(控制器)驱动

USB主机(控制器)与设备驱动(一)

三、USB设备驱动

NOTE:请注意,这里的USB设备驱动指从主机侧角度如何访问插入的USB设备。
		而不是USB设备本身内部运行的固件程序(设备用户固件)!!!

3.1 usb_driver

3.1.1 usb_driver结构体

File path:include/linux/usb.h

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 (*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_driver 的注册和注销:
	usb_register(driver);						/*注册*/
	void usb_deregister(struct usb_driver *);	/*注销*/
	或直接使用下面宏:
	module_usb_driver(xxx_driver);			    /*包含了注册和注销函数*/

3.1.2 usb_device_id

usb_device_id结构体:包含USB设备的制造商ID、产品ID、产品版本、设备类、接口类等信息。
struct usb_device_id {
	/* 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_t	driver_info
		__attribute__((aligned(sizeof(kernel_ulong_t))));
};

相关宏:
	USB_DEVICE(vendor, product);
		#define USB_DEVICE(vend, prod) \
			.match_flags = USB_DEVICE_ID_MATCH_DEVICE, \
			.idVendor = (vend), \
			.idProduct = (prod)
实例:static const struct usb_device_id xxx_table[] = {
			{ USB_DEVICE(USB_XXX_VENDOR_ID, USB_XXX_PRODUCT_ID) },
			{ }					/* Terminating entry */
		};	
NOTE:
1)与PCI设备驱动相似,USB设备驱动的主体工作仍是设备本身(字符设备/tty设备/块设备等)驱动程序;
2)usb_driver与"platform_driver"类似,起到“牵线”的作用。usb_driver本身只是起到了找到USB设备、管理USB设备连接和断开的作用;
3)USB设备挂或不挂在USB总线的区别:
	---驱动结构完全相同。区别在于设备通信时,挂在USB总线时贯穿始终的是URB(USB请求块),而不是对I/O内存和I/O端口的访问。

3.2 USB请求块(URB)

NOTE:URB类似网络设备驱动里的"sk_buff",是USB设备通信的基本载体和核心数据结构。

3.2.1 urb结构体

File path:include/linux/usb.h

struct urb {
	/* private: 仅usb核心和主机控制器访问的字段 */
	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: 驱动可以使用的字段 */
	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 */
};

NOTE:
当transfer_flags被置为URB_NO_TRANSFER_DMA_MAP时,USB核心将使用transfer_dma指向的缓冲区,而非transfer_buffer指向的;
当transfer_flags被置URB_SETUP_MAP_SINGLE时,USB核心将使用setup_dma指向的缓冲区,而非setup_packet指向的。

3.2.2 urb处理流程

NOTE:USB设备的每个endpoint都会处理一个urb队列。
在队列被清空前,一个urb的典型生命周期如下:
1)由一个USB设备驱动创建;
struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags);
	/* 如果分配成功,该函数返回一个urb 结构体指针,否则返回0。*/
	/* iso_packets:urb 应当包含的等时数据包的数目;mem_flags 参数是分配内存的标志。*/
	/* 反函数:void usb_free_urb(struct urb *urb);---释放由usb_alloc_urb()分配的urb 结构体*/
2)初始化,被安排给USB设备的特定endpoint;
中断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: 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);
控制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);
等时(isochronous)urb: 该urb没有像中断、控制和批量urb的初始化函数,只能手动初始化urb。
/* pipe参数:这个urb要被发送到的USB设备的特定端点。
	对于中断urb里的pipe由usb_sndintpipe(dev, endpoint)或usb_rcvintpipe(dev, endpoint)创建;
	对于批量urb里的pipe由usb_sndbulkpipe(dev, endpoint)或usb_rcvbulkpipe(dev, endpoint)创建;
	对于控制urb里的pipe由usb_sndctrlpipe(dev, endpoint)或usb_rcvctrlpipe(dev, endpoint)创建;
	对于等时urb里的pipe由usb_sndisocpipe(dev, endpoint)或usb_rcvisocpipe(dev, endpoint)创建;
*/
/*  urb参数:指向要被初始化的urb的指针;
*	dev参数:指向这个urb要被发送到的USB设备;
*	transfer_buffer参数:指向发送数据或接收数据的缓冲区的指针,不能是静态缓冲区,必须使用kmalloc()来分配;
*	buffer_length参数:transfer_buffer指针所指向缓冲区的大小;
*	complete_fn参数:指向当这个urb完成时被调用的完成处理函数;
*	context参数:完成处理函数的“上下文”;
*	interval参数: 这个urb应当被调度的间隔;
*	setup_packet参数:指向即将被发送到端点的设置数据包;
*/
3)由USB设备驱动提交给USB核心;
int usb_submit_urb(struct urb *urb, gfp_t mem_flags);
	/*  urb参数:指向urb的指针;
	 *	mem_flags:告知USB核心如何在此时分配内存缓冲区;与传递给kmalloc()函数参数的意义相同。
	 */
NOTE:
	a)该函数在原子上下文和进程上下文中都可以被调用;
	b)mem_flags变量则需跟据调用环境进行相应的设置。根据实际情况选择GFP_ATOMIC、GFP_NOIO或GFP_ KERNEL ;
	c)该函数调用成功后,返回0,控制权交给USB核心。否则返回错误号。
4)提交到由USB核心指定的USB主机控制器驱动;
5)被USB主机控制器处理,进行一次到USB设备的传送;
NOTE:第4和第5步是由USB核心和USB主机控制器完成。不受USB设备驱动的控制。
6)当urb完成,USB主机控制器驱动通知USB设备驱动。
NOTE:下面3种情况,urb将结束。
	a) urb 被成功发送给设备,并且设备返回正确的确认。
	b) 发送数据到设备或从设备接收数据时发生了错误(urb->status 将记录错误值)。
	c) 设备驱动通过usb_unlink_urb()或usb_kill_urb()将urb从USB核心“去除连接”。
NOTE:当urb生命结束时,可以通过urb结构体的status成员可以获知其原因:
	a) urb->status = 0,表示传输成功;
	b) urb->status = -ENOENT或-ECONNRESET,分别表示被usb_kill_urb()杀死、被usb_unlink_urb()杀死;
	c) urb->status = -ENODEV或-EXDEV,分别表示USB设备已被移除、等时传输仅完成了一部分等。
	d) urb->status = -EPROTO,表示传输中发生了bitstuff错误或者硬件未能及时收到响应数据包。

3.2.3 简单的批量与控制URB

NOTE:如果USB驱动程序只是从USB设备上接收或向USB设备发送一些简单的数据,
	  此时,没有必要将上述urb处理流程走一遍,而可以使用下面两个更简单的函数:
int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, 
			int *actual_length, int timeout);	/* 调用成功返回值0,失败则返回错误号 */	
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);	/* 调用成功返回发送到设备或从设备接收到的字节数;失败则返回负的错误值 */
/* usb_dev参数:批量/控制消息被发送到的USB设备;
 * pipe参数:批量/控制消息被发送到的USB设备的特定端点;
 * data参数:指向要发送或接收的数据缓冲区的指针;
 * len参数: data参数所指缓冲区的长度;
 * actual_length参数:批量消息返回实际发送或接收的字节数;
 * timeout参数:    发送超时,以jiffies为单位,0表示永远等待。
 下面专属usb_control_msg的参数:
 *	 request参数:控制消息的USB请求值;
 *	 requesttype参数:控制消息的USB请求类型;
 *	 value参数:控制消息的USB消息值;
 *	 index参数:控制消息的USB消息索引值;
 *	 size参数: data参数所指向的缓冲区的大小;
 参数request、requesttype、value 和index 与USB规范中定义的USB控制消息直接对应。
*/
注意事项:
1)由于上述两函数是同步的,故不能在中断上下文和持有自旋锁的情况下使用。使用要特别慎重!
2) 两函数也不能被任何其他函数取消!		

3.3 probe和disconnect函数

3.3.1 probe

USB设备驱动usb_driver结构体的probe函数中,应完成如下工作:
a) 探测设备的端点地址、缓冲区大小;
b) 初始化任何可能用于控制USB设备的数据结构;
c) 把已初始化数据结构的指针保存到接口设备中;
	void usb_set_intfdata(struct usb_interface *intf, void *data);
d) 注册USB设备。
	int usb_register_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;
		};
		/*对于字符设备,上述结构体的fops成员指向改字符设备的成员函数;
		 *而其他设备,该成员指向对应设备的注册函数。
		 */			

3.3.2 disconnect

USB设备驱动usb_driver结构体的disconnect函数中,应完成如下工作:
a) 释放所有为设备分配的资源;
b) 设置接口设备的数据指针为NULL;	
c) 注销USB设备;
	void usb_deregister_dev(struct usb_interface *intf, struct usb_class_driver *class_driver); 

3.4 USB骨架程序(详解)

USB主机(控制器)与设备驱动(三)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值