内核是 Linux-2.6.22.6
内核中usb设备驱动程序的框架
用户空间
App ..........................................................
usb设备驱动程序
内核空间 ...................................................
usb核心层
..................................................
usb总线驱动程序
................................................................
硬件 usb主机控制器
..................................
UHCI OHCI EHCI
.................................................................
USB设备
从这样分层结构我们可以看出usb核心层起着非常重要的作用,一方面为usb设备驱动程序提供接口,另一方面也为usb总线驱动程序提供接口,其中usb总线驱动程序是直接与硬件打交道的,它提供对硬件操作的读写函数,但是他不知道数据的具体意义,usb设备驱动程序知道数据的具体意义。
usb总线驱动程序框架分析:
static int __init usb_init(void)
retval = bus_register(&usb_bus_type);//usb总线注册
kset_register(&bus->devices);//在/sys/bus/usb/目录下创建 devices
kset_register(&bus->drivers);//在/sys/bus/usb/目录下创建 drivers
klist_init(&bus->klist_devices, klist_devices_get, klist_devices_put);//这个是初始化devices链表
klist_init(&bus->klist_drivers, NULL, NULL);初始化driver链表
retval = usb_host_init();
usb_host_class = class_create(THIS_MODULE, "usb_host");//这个创建了一个 usb_host类②
int usb_major_init(void)
error = register_chrdev(USB_MAJOR, "usb", &usb_fops); //这个创建了一个usb_fops ①
retval = usb_register(&usbfs_driver); //usb驱动的注册
retval = usb_hub_init(); //初始化一个usb hub
usb_register(&hub_driver) //将hub.c下的hub_driver加入到 usb总线下的驱动链表里面
new_driver->drvwrap.driver.bus = &usb_bus_type; //指定增加驱动的类型
new_driver->drvwrap.driver.probe = usb_probe_interface;
retval = driver_register(&new_driver->drvwrap.driver); //这里注册的是 hub_driver->drvwrap.driver
bus_add_driver(drv);
error = driver_attach(drv);
bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
while ((dev = next_device(&i)) && !error) 这里是一个循环 遍历总线上的所有设备
error = fn(dev, data);
fn =__driver_attach
driver_probe_device(drv, dev);
if (drv->bus->match && !drv->bus->match(dev, drv))
ret = dev->bus->probe(dev); //先使用总线的probe函数
如果失败
在使用ret = drv->probe(dev);//driver的probe函数 而由上面的分析可知 drv->probe =usb_probe_interface;
分析usb_probe_interface
struct usb_driver *driver = to_usb_driver(dev->driver);
struct usb_interface *intf = to_usb_interface(dev);
struct usb_device * udev = interface_to_usbdev(intf);
id = usb_match_id(intf, driver->id_table); //这个是匹配接口与驱动的id_table
if(id)
{
error = driver->probe(intf, id);//这里面就调用了 usb_driver的probe函数 (这里会调用到我们自己编写的usb设备驱动程序)也有可能调用到hub的probe函数
}
现在来分析hub的probe函数
hub_configure(hub, endpoint)
hub->buffer = usb_buffer_alloc(hdev, sizeof(*hub->buffer), GFP_KERNEL,&hub->buffer_dma);//目的
pipe = usb_rcvintpipe(hdev, endpoint->bEndpointAddress); //源
maxp = usb_maxpacket(hdev, pipe, usb_pipeout(pipe));//长度
hub->urb = usb_alloc_urb(0, GFP_KERNEL);//分配一个urb
usb_fill_int_urb(hub->urb, hdev, pipe, *hub->buffer, maxp, hub_irq,
hub, endpoint->bInterval);
hub->urb->transfer_dma = hub->buffer_dma;
hub->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; //上面是填充这个urb
hub_activate(hub);
status = usb_submit_urb(hub->urb, GFP_NOIO); 提交这个urb
static DECLARE_WAIT_QUEUE_HEAD(khubd_wait);//定义一个等待队列
由于刚开始的时候假设usb设备还没有,,,,因此 hub的probe函数还不会执行 一次执行下面的操作
khubd_task= kthread_run(hub_thread, NULL, "khubd"); //在这里开启一个hub_thread线程
hub_thread
hub_events(); //这个函数是至关重要的,,,,,它涉及到usb设备描述符的获取操作
while(1)//这是一个循环 就是一直在这里循环检测 如果有了usb设备的插入 就会调用usb_driver的probe函数 提交urb 然后退出循环 ,线程进入休眠状态
{
for (i = 1; i <= hub->descriptor->bNbrPorts; i++) {
hub_port_connect_change(hub, i,portstatus, portchange);
udev = usb_alloc_dev(hdev, hdev->bus, port1); //分配一个usb_device结构体
choose_address(udev); //
devnum = find_next_zero_bit(bus->devmap.devicemap, 128,bus->devnum_next); //选择一个空的设备usb号
hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
hub_set_address//设置设备号
usb_get_device_descriptor(udev, 8);//获得设备描述符
usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE);//再次获得整个设备的描述符
status = usb_new_device(udev);
usb_get_configuration(udev);//获得usb设备的配置描述符,接口描述符,端点描述符
udev->dev.devt = MKDEV(USB_DEVICE_MAJOR, (((udev->bus->busnum-1) * 128) + (udev->devnum-1)));
device_add(&udev->dev);③
error = bus_add_device(dev) //将usb_device设备添加到usb总线旗下的设备链表里面
bus_attach_device(dev);
ret = device_attach(dev);//这个就会被调用
ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
__device_attach
if (drv->bus->match && !drv->bus->match(dev, drv))//调用bus的match函数
ret = really_probe(dev, drv);
ret = dev->bus->probe(dev);//首先调用bus的probe函数
ret = drv->probe(dev);//在调用drv的probe函数
向下最终就会调用到 usb_driver里面的probe函数 当然也会调用到我们自己编写的usb设备驱动程序
}
}
wait_event_interruptible(khubd_wait,!list_empty(&hub_event_list) ||kthread_should_stop()) //将当前进程休眠
下面分析休眠唤醒
唤醒情况①
在hub的probe函数中 我们已经提交了一个urb 他的回调函数为
static void hub_irq(struct urb *urb)
kick_khubd(hub);
if (list_empty(&hub->event_list)) {
list_add_tail(&hub->event_list, &hub_event_list);
wake_up(&khubd_wait);}//在这里休眠被唤醒了 (当urb提交成功并且有数据传过来的时候,就会唤醒这个队列 )
唤醒情况②
void usb_kick_khubd(struct usb_device *hdev)
kick_khubd(hdev_to_hub(hdev));
|