打印

Linux内核驱动程序整理之三 USB设备驱动程序

[复制链接]
1940|3
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
nello|  楼主 | 2015-12-18 17:21 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
内核是 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));

相关帖子

沙发
zhangbin_abc| | 2015-12-18 17:28 | 只看该作者
楼主您好,我最近在尝试SPI驱动设计,并且要使用微控制器内部的SSP控制器,请问楼主有没有做过这个,很想向您学习一下。

使用特权

评论回复
板凳
阿南| | 2015-12-19 09:57 | 只看该作者
zhangbin_abc 发表于 2015-12-18 17:28
楼主您好,我最近在尝试SPI驱动设计,并且要使用微控制器内部的SSP控制器,请问楼主有没有做过这个,很想向 ...

在Linux下吗?先找一本原理性的书看一下,再看看驱动例子

使用特权

评论回复
地板
mega1702| | 2016-3-28 16:04 | 只看该作者
感谢楼主分享!!!

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

3

主题

5

帖子

2

粉丝