不说没用的
直接上两个重要的数据结构:
第一个:
struct xhci_ctrl {
#ifdef CONFIG_DM_USB
struct udevice *dev;
#endif
struct xhci_hccr *hccr; /* R/O registers, not need for volatile */
struct xhci_hcor *hcor;
struct xhci_doorbell_array *dba;
struct xhci_run_regs *run_regs;
struct xhci_device_context_array *dcbaa \
__attribute__ ((aligned(ARCH_DMA_MINALIGN)));
struct xhci_ring *event_ring;
struct xhci_ring *cmd_ring;
struct xhci_ring *transfer_ring;
struct xhci_segment *seg;
struct xhci_intr_reg *ir_set;
struct xhci_erst erst;
struct xhci_erst_entry entry[ERST_NUM_SEGS];
struct xhci_virt_device *devs[MAX_HC_SLOTS];
int rootdev;
};
没有研究DM(driver model)的代码,而且,本人感觉,将LINUX中本来就不完善的DRIVER MODE搬到U-BOOT中,就是浪费自己与他人的时间与精力,把一件原本就需要简单,明了的事情,弄得复杂。
其实,除了rootdev这个成员,前面的这些成员,只要是熟悉XHCI的工程师,都应该非常快地知道代表了什么意思,
寄存器组,设备CONTEXT组,event, command rinng以及transfer ring.
ERST: event ring segment table
devs是该USB HOST下面的设备实例
rootdev是需要绕一绕才知道起什么作用的,看俺的前一篇吧。
第二个:
struct usb_device {
int devnum; /* Device number on USB bus */
int speed; /* full/low/high */
char mf[32]; /* manufacturer */
char prod[32]; /* product */
char serial[32]; /* serial number */
/* Maximum packet size; one of: PACKET_SIZE_* */
int maxpacketsize;
/* one bit for each endpoint ([0] = IN, [1] = OUT) */
unsigned int toggle[2];
/* endpoint halts; one bit per endpoint # & direction;
* [0] = IN, [1] = OUT
*/
unsigned int halted[2];
int epmaxpacketin[16]; /* INput endpoint specific maximums */
int epmaxpacketout[16]; /* OUTput endpoint specific maximums */
int configno; /* selected config number */
/* Device Descriptor */
struct usb_device_descriptor descriptor
__attribute__((aligned(ARCH_DMA_MINALIGN)));
struct usb_config config; /* config descriptor */
int have_langid; /* whether string_langid is valid yet */
int string_langid; /* language ID for strings */
int (*irq_handle)(struct usb_device *dev);
unsigned long irq_status;
int irq_act_len; /* transfered bytes */
void *privptr;
/*
* Child devices - if this is a hub device
* Each instance needs its own set of data structures.
*/
unsigned long status;
unsigned long int_pending; /* 1 bit per ep, used by int_queue */
int act_len; /* transfered bytes */
int maxchild; /* Number of ports if hub */
int portnr; /* Port number, 1=first */
#ifndef CONFIG_DM_USB
/* parent hub, or NULL if this is the root hub */
struct usb_device *parent;
struct usb_device *children[USB_MAXCHILDREN];
void *controller; /* hardware controller private data */
#endif
/* slot_id - for xHCI enabled devices */
unsigned int slot_id;
#ifdef CONFIG_DM_USB
struct udevice *dev; /* Pointer to associated device */
struct udevice *controller_dev; /* Pointer to associated controller */
#endif
};
devnum其实,就是一组设备的编号,初始化的时候,从1到max
但是,为了将ROOT HUB也当作一个HUB来用,这里就得结合rootdev一起看代码,否则,保证让你看得云里雾里,也搞不清楚rootdev的作用。
usb_device这个数据结构基本贯穿了整个U-BOOT中USB子系统。
有一些成员,一看就知道,不多解释了。
主要解说几个影响代码执行流程的地方:
1. devnum见前文
2. struct usb_device *parent;上一级HUB的指针,ROOT HUB设置为NULL
3. struct usb_device *children[USB_MAXCHILDREN]; HUB下面的设备指针
4. controller, 指向struct xhci_ctrl 的实例
5. unsigned int slot_id;, 每个设备对应一个SLOT。
6. int maxchild; /* Number of ports if hub */, HUB所包含的DS PORT的个数
7. int portnr; /* Port number, 1=first */, 设备所连接接的HUB的DS PORT的编号, 即使是ROOT HUB,也有对应的PORT NUMBER
usb_hub_port_connect_change函数中有一段代码:
是在检测到HUB DS PORT下面有设备连上后,调用该函数。
其中,代码如下:
struct usb_device *usb; <--------------------------------------------------------------为检测到的新设备,准备一个数据结构实例
ret = usb_alloc_new_device(dev->controller, &usb);
if (ret) {
printf("cannot create new device: ret=%d", ret);
return ret;
}
dev->children[port] = usb; <--------------------------------------------------------------将HUB与USB DEV的上下游关系建立
usb->speed = speed;
usb->parent = dev; <-------------------------------------------------------------- 建立HUB与USB DEV的上下游关系
usb->portnr = port + 1; <--------------------------------------------------------------设置该USB DEV对应的上游HUB的DS PORT NUMBER
/* Run it through the hoops (find a driver, etc) */
ret = usb_new_device(usb);
if (ret < 0) {
/* Woops, disable the port */
usb_free_device(dev->controller);
dev->children[port] = NULL;
}
大家可以发现,该代码的设备检测是深度优先。