driver/usb/host/ohci-s3c2410.c
static struct platform_driver ohci_hcd_s3c2410_driver
注册usb_device_driver
static int __init usb_init(void)
usb_register_device_driver(&usb_generic_driver, THIS_MODULE)/*注册usb_device_driver 到内核中*/
当找到usb总线上有匹配的usb_device就会调用generic_probe
generic_probe
usb_set_configuration
ret = device_add (&intf->dev);/*将每个USB接口注册到内核*/
struct usb_device_driver usb_generic_driver
driver/usb/host/ohci-hcd.c
注册USB平台驱动
ohci_hcd_mod_init
#define PLATFORM_DRIVER ohci_hcd_s3c2410_driver
platform_driver_register(&PLATFORM_DRIVER);
usb_hcd_s3c2410_probe(&ohci_s3c2410_hc_driver, pdev)
hcd = usb_create_hcd(driver, &dev->dev, "s3c24xx")
usb_add_hcd(hcd, dev->resource[1].start, IRQF_DISABLED)
hcd_buffer_create(hcd)
usb_register_bus(&hcd->self)
usb_alloc_dev(NULL, &hcd->self, 0)
register_root_hub(hcd)
usb_new_device (usb_dev)
device_add(&udev->dev)/*将usb_device添加到usb总线的klist_devices链表上,以便于usb_register_device_driver注册usb_device_driver的时候匹配该设备*/
S3C2410 HUB初始化
usb_hub_init
usb_register(&hub_driver)/*该过程匹配USB总线上的USB HUB接口设备,通过usb_probe_interface进行匹配,若匹配则调用hub_probe*/
hub_probe
hub_configure
usb_fill_int_urb(hub->urb, hdev, pipe, *hub->buffer, maxp, hub_irq, hub, endpoint->bInterval);/*填充urb->complete = hub_irq*/
hub_activate(hub);
usb_submit_urb
khubd_task = kthread_run(hub_thread, NULL, "khubd");/*建立内核线程*/
list_empty(&hub_event_list)/*若hub_event_list链表为空,则该线程休眠,知道urb_irq检测到hub接口状态发生变化,将该事件添加到hub_event_list链表,然后唤醒该线程*/
创建HCD
usb_create_hcd
init_timer(&hcd->rh_timer);
hcd->rh_timer.function = rh_timer_func;
hcd->rh_timer.data = (unsigned long) hcd;
static void rh_timer_func (unsigned long _hcd)
usb_hcd_poll_rh_status
mod_timer (&hcd->rh_timer, jiffies + msecs_to_jiffies(250));
usb_submit_urb(struct urb *urb, gfp_t mem_flags)
status = hcd->driver->urb_enqueue (hcd, ep, urb, mem_flags);
finish_urb (struct ohci_hcd *ohci, struct urb *urb)
usb_hcd_giveback_urb (ohci_to_hcd(ohci), urb);
urb->complete (urb);/*调用注册的HUB_IRQ*/
1.中断类型的端口用于监控 root hub上是否有设备插入,root hub通过两种方式来监控是否有设备插入:
1.一种是通过中断方式,使能相应中断,当状态发生变化时产生中断,然后运行中断服务程序获取取状态寄存器信息;
2.一种是定时轮询方式,当定时时间到了运行定时器程时指定的定时器rh_timer的function函数rh_timer_func。
问:为什么要两种方式?
答:个人认为如果只使用中断方式的话,当插入USB的设备的时候,只会发生一次中断,若此次的中断丢失的话那么系统永远无法感知有USB设备的接入,但是定时器的可以定时的轮训该USB设备接入状态,可以避免这种情况的发生
一、中断方式:
usb_hcd_s3c2410_probe
usb_add_hcd(hcd, dev->resource[1].start, IRQF_DISABLED);
request_irq(irqnum, &usb_hcd_irq, irqflags,hcd->irq_descr, hcd))/*usb_hcd_irq会调用hcd->driver->irq (hcd) = ohci_irq*/
ohci_irq
usb_hcd_poll_rh_status(hcd);
二、定时器方式:
usb_hcd_s3c2410_probe
usb_add_hcd(hcd, dev->resource[1].start, IRQF_DISABLED)
hcd->driver->start(hcd)/*调用ohci_s3c2410_hc_driver中的ohci_s3c2410_start,该函数*/
ohci_s3c2410_start (struct usb_hcd *hcd)
ohci_run (ohci)
hcd->poll_rh = 1;
hcd->uses_new_polling = 1;
if (hcd->uses_new_polling && hcd->poll_rh)
usb_hcd_poll_rh_status(hcd);/*进行一次USB HUB接口状态的检查,该函数中启动定时器链表rh_timer,当定时器超时的时候,调用超时函数rh_timer_func*/
static void rh_timer_func (unsigned long _hcd)
{
usb_hcd_poll_rh_status((struct usb_hcd *) _hcd);
} /*usb_hcd_poll_rh_status函数中会再次修改rh_timer,添加到内核定时器链表,定时器的周期为250ms*/
不管是通过中断方式还是通过定时轮询方式 ,最终都是通过调用usb_hcd_poll_rh_status来实现的root hub状态查
接下来分析usb_hcd_poll_rh_status函数
usb_hcd_poll_rh_status
length = hcd->driver->hub_status_data(hcd, buffer)
if (length > 0)
usb_hcd_giveback_urb (hcd, urb)
urb->complete (urb)/*该函数即为usb_fill_int_urb填充的hub_irq*/
kick_khubd(hub);/*当urb->status=0是说明urb传输完成,此时需要唤醒内核线程hub_thread*/
list_add_tail(&hub->event_list, &hub_event_list)
wake_up(&khubd_wait)
接着分析线程hub_thread
for (i = 1; i <= hub->descriptor->bNbrPorts; i++)
hub_port_status/*获取HUB接口状态*/
connect_change = 1/*当接口状态发生改变时,connect_change设为1*/
if(connect_change)
hub_port_connect_change(hub, i, portstatus, portchange)
udev = usb_alloc_dev(hdev, hdev->bus, port1)
dev->dev.bus = &usb_bus_type;
dev->dev.type = &usb_device_type;
struct usb_device *udev/*创建一个usb_device设备*/
choose_address(udev)/*给USB分配地址,最大为127*/
hub_port_init(hub, udev, port1, i)
hub_set_address
retval = usb_get_device_descriptor(udev, 8)/*因为不确定USB设备的能够支持的最大传输大小,先读取8字节,第8个字节为bMaxPacketSize0*/
i = udev->descriptor.bMaxPacketSize0 == 0xff?512 : udev->descriptor.bMaxPacketSize0;
udev->ep0.desc.wMaxPacketSize = cpu_to_le16(i);/*设置UDEV的描述符wMaxPacketSize = bMaxPacketSize0*/
retval = usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE)/*将USB设备中的设备描述、配置描述符、接口描述符、端点描述符一次性全部读出来进行分析*/
usb_new_device(udev)
device_add(&udev->dev)/*将该设备添加到usb_bus_type类型的总线上,匹配成功的话,将调用需要我们写的usb_driver->probe*/
举例usb_driver:
驱动编写者需要添加自己usb_driver,如usbmouse_as_key.c
static struct usb_driver usbmouse_as_key_driver
usb_register(&usbmouse_as_key_driver)/*若匹配的过程是设备接口,则调用usbmouse_as_key_driver的probe函数*/
usbmouse_as_key_probe
input_register_device(uk_dev);
usb_fill_int_urb(uk_urb, dev, pipe, usb_buf, len, usbmouse_as_key_irq, NULL, endpoint->bInterval)
usb_submit_urb
久爱不腻 于 2014-07-29 15:25:08发表:
太深奥了吧
linux08071151 于 2014-07-20 11:33:56发表:
[i=s] 本帖最后由 linux08071151 于 2014-7-20 11:38 编辑 [/i]
上面说的为什么使用两种方式查询HUB接口状态分析的有误,现在更正下。使用定时器查询的主要原因是USB没有中断USB控制器的能力,所以当USB设备接入之后,获取USB输入的信息是无法通过中断方式来获取,只能通过定时器定时轮训获取。当USB设备未插入时,定时器rh_timer会停止,直到USB插入之后,再次开启定时查询USB设备输入的信息
huiteng 于 2014-07-19 08:49:00发表:
深奥啊