在我看来,roothub的功能主要有两个:一是感应设备的插拔,在一个是对新插入的设备进行配置。
root hub 是怎么感应到设备的插拔的?
这里开始分析root hub的驱动。之前已经提到过每个host controller都集成有一个root hub。通过看2440的datasheet中的host controller部分,我们可以看到root hub是有相应的物理电路的,并不是host controller虚拟了一个root hub。2440的root hub共有两个port,但是在mini2440上面只连了一个host的接口。
从旁边的图上可以看出,DN0和DP0是第一个host port的引脚。DN1和DP1是第二个host port的引脚,但是这两个引脚是和udc 的引脚PDN0\PDP0复用的,在mini2440中这个复用的引脚用作了udc的port。但是这里有个问题,是怎么设定这两个复用的引脚的功能的?
root hub的一个很重要的功能就是检测到设备的插拔,有usb device插入时,对设备进行一定部分的初始化。但是有一个需要注意的是,读写usb device,并不需要通过usb root hub,都是hcd直接读写寄存器进行的,不需要通过root hub的传递。root hub对插入的设备进行读写也是通过submit urb来实现的。
先看root hub的表示。与root hub相关的结构体有两个usb_hub和hub_driver。
struct usb_hub {
struct device *intfdev; /* the "interface" device */
struct usb_device *hdev;
struct kref kref;
struct urb *urb; /* for interrupt polling pipe */
/* buffer for urb ... with extra space in case of babble */
char (*buffer)[8];
dma_addr_t buffer_dma; /* DMA address for buffer */
union {
struct usb_hub_status hub;
struct usb_port_status port;
} *status; /* buffer for status reports */
struct mutex status_mutex; /* for the status buffer */
int error; /* last reported error */
int nerrors; /* track consecutive errors */
struct list_head event_list; /* hubs w/data or errs ready */
unsigned long event_bits[1]; /* status change bitmask */
unsigned long change_bits[1]; /* ports with logical connect
status change */
unsigned long busy_bits[1]; /* ports being reset or
resumed */
#if USB_MAXCHILDREN > 31 /* 8*sizeof(unsigned long) - 1 */
#error event_bits[] is too short!
#endif
struct usb_hub_descriptor *descriptor; /* class descriptor */
struct usb_tt tt; /* Transaction Translator */
unsigned mA_per_port; /* current for each child */
unsigned limited_power:1;
unsigned quiescing:1;
unsigned disconnected:1;
unsigned has_indicators:1;
u8 indicator[USB_MAXCHILDREN];
struct delayed_work leds;
struct delayed_work init_work;
void **port_owners;
};
在内核中实现了专门针对usb hub的驱动,叫hub_driver。
static struct usb_driver hub_driver = {
.name = "hub",
.probe = hub_probe,
.disconnect = hub_disconnect,
.suspend = hub_suspend,
.resume = hub_resume,
.reset_resume = hub_reset_resume,
.pre_reset = hub_pre_reset,
.post_reset = hub_post_reset,
.ioctl = hub_ioctl,
.id_table = hub_id_table,
.supports_autosuspend = 1,
};
之前在hcd的初始化驱动中有register_root_hub,这个函数经过device_add等一系列调用,最终会调用到usb hub的probe函数,即hub_probe。(调用到hub_probe时候,可以看到这个函数参数就已经变成了usb_interface,这个过程还需要以后的分析)。
static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
struct usb_host_interface *desc;
struct usb_endpoint_descriptor *endpoint;
struct usb_device *hdev;
struct usb_hub *hub;
desc = intf->cur_altsetting;
hdev = interface_to_usbdev(intf);
endpoint = &desc->endpoint[0].desc;
/* We found a hub */
dev_info (&intf->dev, "USB hub found\n");
hub = kzalloc(sizeof(*hub), GFP_KERNEL);
if (!hub) {
dev_dbg (&intf->dev, "couldn't kmalloc hub struct\n");
return -ENOMEM;
}
kref_i