当前位置:   article > 正文

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

xhci_hcd

一、Linux USB驱动层次

1、USB驱动(主机侧)

NOTE:在Linux 系统中,USB驱动可以从两个角度去观察,一个角度是主机侧,一个角度是设备侧。
  • 1
从主机侧角度看,USB驱动从底到上依次是:
USB主机控制器硬件层 --> USB主机控制器驱动层 --> USB核心层 --> USB设备驱动层
  • 1
  • 2

usb驱动层次

USB主机控制器驱动层:控制插入的USB设备;
USB核心层:负责USB驱动管理和协议处理。
			---定义一些数据结构、宏和功能函数,分别向上层(USB设备驱动层)和下层(USB主机控制器驱动层)	提供编程接口;
			---通过全局变量维护整个系统的USB信息;
			---完成设备热拔插控制、总线数据传输控制等;
USB设备驱动层:控制USB设备和主机的通信;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

2、USB的逻辑组合(4个层次)

usb逻辑层次

设备(device):包含一个/多个配置。
  • 1
		设备描述符:struct usb_device_descriptor {
							__u8  bLength;
							__u8  bDescriptorType;
		
							__le16 bcdUSB;
							__u8  bDeviceClass;
							__u8  bDeviceSubClass;
							__u8  bDeviceProtocol;
							__u8  bMaxPacketSize0;
							__le16 idVendor;
							__le16 idProduct;
							__le16 bcdDevice;
							__u8  iManufacturer;
							__u8  iProduct;
							__u8  iSerialNumber;
							__u8  bNumConfigurations;
						} __attribute__ ((packed));
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
配置(config):不同的配置使设备表现出不同的功能组合。
			---每个配置可以有多个接口,可由多个接口组成。
  • 1
  • 2
		配置描述符:struct usb_config_descriptor {
							__u8  bLength;
							__u8  bDescriptorType;
		
							__le16 wTotalLength;
							__u8  bNumInterfaces;
							__u8  bConfigurationValue;
							__u8  iConfiguration;
							__u8  bmAttributes;
							__u8  bMaxPower;
						} __attribute__ ((packed));
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
接口(interface):代表一个基本功能,是USB 设备驱动程序控制的对象。
				  ---配置中的所有接口可以同时有效,并可被不同的驱动程序连接。
				  ---接口可以有备用接口,以提供不同质量的服务参数。
				  ---接口是端点的汇集。
  • 1
  • 2
  • 3
  • 4
		接口描述符:struct usb_interface_descriptor {
								__u8  bLength;
								__u8  bDescriptorType;
		
								__u8  bInterfaceNumber;
								__u8  bAlternateSetting;
								__u8  bNumEndpoints;
								__u8  bInterfaceClass;
								__u8  bInterfaceSubClass;
								__u8  bInterfaceProtocol;
								__u8  iInterface;
							} __attribute__ ((packed));
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
端点(endpoint):USB通信的基本形式(主机只能通过端点与设备进行通信,以使用设备的功能)。
				  ---USB系统中每一个端点都有惟一的地址,由设备地址和端点号给出的。
				  ---每个端点的属性包含传输方式、总线访问频率、带宽、端点号和数据包的最大容量等。
				  ---每个USB 端点只能在一个方向承载数据,或主机到设备(输出端点),或设备到主机(输入端点)。
				  ---端点0(控制端点,用于设备初始化参数),只要设备连接到USB并且上电端点0就可以被访问。
  • 1
  • 2
  • 3
  • 4
  • 5
		端点描述符: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));
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

实例:在linux机器上插入U盘/读卡器,利用lsusb -v命令查看设备详细信息:
descriptor

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

1、主机控制器规格

OHCI:Open Host Controller Interface.
UHCI:Universal Host Controller Interface. 
EHCI:Enhance(增强型),主要用于USB2.0,兼容OHCI和UHCI;
xHCI:eXtensible(可扩展的),主要用于USB3.0,兼容EHCI、UHCI及OHCI;
  • 1
  • 2
  • 3
  • 4

2、主机控制器的相关结构

usb_hcd结构体:描述USB主机控制器驱动。
  • 1
		struct usb_hcd {
				/* housekeeping */
				struct usb_bus		self;		/* hcd is-a bus */
				struct kref		kref;			/* reference counter */
			
				const char		*product_desc;	/* product/vendor string */
				int			speed;				/* Speed for this roothub.
			
				char			irq_descr[24];	/* driver + bus # */
			
				struct timer_list	rh_timer;	/* drives root-hub polling */
				struct urb		*status_urb;	/* the current status urb */
			
				/*
				 * hardware info/state
				 */
				const struct hc_driver	*driver;	/* hw-specific hooks(特定硬件的钩子函数) */
			
				/*
				 * OTG and some Host controllers need software interaction with phys;
				 * other external phys should be software-transparent
				 */
				struct usb_phy		*usb_phy;
				struct phy		*phy;
				...
				...
			
				int			state;
			#	define	__ACTIVE		0x01
			#	define	__SUSPEND		0x04
			#	define	__TRANSIENT		0x80
				...
			
				/* The HC driver's private data is stored at the end of
				 * this structure.
				 */
				unsigned long hcd_priv[0]
						__attribute__ ((aligned(sizeof(s64))));
			};
  • 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
hc_driver结构体:用于操作主机控制器。
  • 1
		struct hc_driver {
				const char	*description;	/* "ehci-hcd" etc */
				const char	*product_desc;	/* product/vendor string */
				size_t		hcd_priv_size;	/* size of private data */

				/* irq handler */
				irqreturn_t	(*irq) (struct usb_hcd *hcd);

				int	flags;
			#define	HCD_MEMORY	0x0001		/* HC regs use memory (else I/O) */
				...

				/* called to init HCD and root hub */
				int	(*reset) (struct usb_hcd *hcd);
				int	(*start) (struct usb_hcd *hcd);

				/* NOTE:  these suspend/resume calls relate to the HC as
				 * a whole, not just the root hub; they're for PCI bus glue.
				 */
				/* called after suspending the hub, before entering D3 etc */
				int	(*pci_suspend)(struct usb_hcd *hcd, bool do_wakeup);

				/* called after entering D0 (etc), before resuming the hub */
				int	(*pci_resume)(struct usb_hcd *hcd, bool hibernated);

				/* cleanly make HCD stop writing memory and doing I/O */
				void	(*stop) (struct usb_hcd *hcd);

				/* shutdown HCD */
				void	(*shutdown) (struct usb_hcd *hcd);

				/* return current frame number */
				int	(*get_frame_number) (struct usb_hcd *hcd);

				/* manage i/o requests, device state */
				int	(*urb_enqueue)(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags);
				int	(*urb_dequeue)(struct usb_hcd *hcd, struct urb *urb, int status);
				...
				...
			};
  • 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
hcd的创建、添加和移除:
	struct usb_hcd *usb_create_hcd(const struct hc_driver *driver, struct device *dev, const char *bus_name);
	int usb_add_hcd(struct usb_hcd *hcd, unsigned int irqnum, unsigned long irqflags);
	void usb_remove_hcd(struct usb_hcd *hcd);
  • 1
  • 2
  • 3
  • 4
xhci主机控制器
	1)xhci_hcd结构体:drivers/usb/host/xhci.h
			struct xhci_hcd {
				struct usb_hcd *main_hcd;
				struct usb_hcd *shared_hcd;
				/* glue to PCI and HCD framework */
				struct xhci_cap_regs __iomem *cap_regs;
				struct xhci_op_regs __iomem *op_regs;
				struct xhci_run_regs __iomem *run_regs;
				struct xhci_doorbell_array __iomem *dba;
				/* Our HCD's current interrupter register set */
				struct	xhci_intr_reg __iomem *ir_set;
		
				/* Cached register copies of read-only HC data */
				__u32		hcs_params1;
				...
		
				spinlock_t	lock;
		
				/* packed release number */
				u8		sbrn;
				u16		hci_version;
				...
				...
				...
			};
	2)usb_hcd和xhci_hcd的相互转换:
		struct xhci_hcd *hcd_to_xhci(struct usb_hcd *hcd);
		struct usb_hcd *xhci_to_hcd(struct xhci_hcd *xhci);
	3)xHCI主机控制器的初始化:
		int xhci_init(struct usb_hcd *hcd);
	4)xHCI主机控制器的开启、停止、复位:
		int xhci_start(struct xhci_hcd *xhci);
		void xhci_stop(struct usb_hcd *hcd);
		int xhci_reset(struct xhci_hcd *xhci);
  • 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

3、实例:xHCI主机控制器驱动

xHCI主机控制器驱动 drivers/usb/host/xhci.c
		static const struct hc_driver xhci_hc_driver = {
				.description =		"xhci-hcd",
				.product_desc =		"xHCI Host Controller",
				.hcd_priv_size =	sizeof(struct xhci_hcd),
	
				/*
				 * generic hardware linkage
				 */
				.irq =			xhci_irq,
				.flags =		HCD_MEMORY | HCD_USB3 | HCD_SHARED,
	
				/*
				 * basic lifecycle operations
				 */
				.reset =		NULL, /* set in xhci_init_driver() */
				.start =		xhci_run,
				.stop =			xhci_stop,
				.shutdown =		xhci_shutdown,
	
				/*
				 * managing i/o requests and associated device resources
				 */
				.urb_enqueue =		xhci_urb_enqueue,
				.urb_dequeue =		xhci_urb_dequeue,
				.alloc_dev =		xhci_alloc_dev,
				.free_dev =		xhci_free_dev,
				...
				...
	
				/*
				 * scheduling support
				 */
				.get_frame_number =	xhci_get_frame,
	
				/*
				 * root hub support
				 */
				.hub_control =		xhci_hub_control,
				.hub_status_data =	xhci_hub_status_data,
				.bus_suspend =		xhci_bus_suspend,
				.bus_resume =		xhci_bus_resume,
	
				/*
				 * call back when device connected and addressed
				 */
				.update_device =        xhci_update_device,
				.set_usb2_hw_lpm =	xhci_set_usb2_hardware_lpm,
				.enable_usb3_lpm_timeout =	xhci_enable_usb3_lpm_timeout,
				.disable_usb3_lpm_timeout =	xhci_disable_usb3_lpm_timeout,
				.find_raw_port_number =	xhci_find_raw_port_number,
				.submit_single_step_set_feature	= xhci_submit_single_step_set_feature,
			};
			
			int xhci_run(struct usb_hcd *hcd)
			{
				u32 temp;
				u64 temp_64;
				int ret;
				struct xhci_hcd *xhci = hcd_to_xhci(hcd);

				/* Start the xHCI host controller running only after the USB 2.0 roothub
				 * is setup.
				 */

				hcd->uses_new_polling = 1;
				if (!usb_hcd_is_primary_hcd(hcd))
					return xhci_run_finished(xhci);

				xhci_dbg_trace(xhci, trace_xhci_dbg_init, "xhci_run");

				ret = xhci_try_enable_msi(hcd);
				...
				...
				temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
				temp_64 &= ~ERST_PTR_MASK;
				...
				temp = readl(&xhci->ir_set->irq_control);
				temp &= ~ER_IRQ_INTERVAL_MASK;
				/*
				 * the increment interval is 8 times as much as that defined
				 * in xHCI spec on MTK's controller
				 */
				temp |= (u32) ((xhci->quirks & XHCI_MTK_HOST) ? 20 : 160);
				writel(temp, &xhci->ir_set->irq_control);

				/* Set the HCD state before we enable the irqs */
				temp = readl(&xhci->op_regs->command);
				temp |= (CMD_EIE);
				...
				writel(temp, &xhci->op_regs->command);

				temp = readl(&xhci->ir_set->irq_pending);
				...
				writel(ER_IRQ_ENABLE(temp), &xhci->ir_set->irq_pending);
				xhci_print_ir_set(xhci, 0);

				if (xhci->quirks & XHCI_NEC_HOST) {
					struct xhci_command *command;
					command = xhci_alloc_command(xhci, false, false, GFP_KERNEL);
					...
					xhci_queue_vendor_command(xhci, command, 0, 0, 0,
							TRB_TYPE(TRB_NEC_GET_FW));
				}
				...
				return 0;
			}
  • 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
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107

三、USB设备驱动(详解)

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

四、实例

4.1 USB串口驱动:drivers/usb/serial/usb-serial.c
  • 1
4.2 USB键盘驱动:drivers/hid/usbhid/usbkbd.c
  • 1
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/246841?site
推荐阅读
相关标签
  

闽ICP备14008679号