DAVINCI USB驱动的框架图:

DAVINCI USB驱动的框架图:

USB-CORE
HCD(MUSB CONTROLLER)
LOW-LEVEL DRIVER




引言:首先make menuconfig选中usb support(CONFIG_USB)
在driver/usb/makefie里定义:
obj-$(CONFIG_USB)                += core/
找到driver/usb /core/makefie里定义:
usbcore-objs        := usb.o hub.o hcd.o urb.o message.o \
                        config.o file.o buffer.o sysfs.o
obj-$(CONFIG_USB)        += usbcore.o
usb.c这就是USB 总线驱动的核心文件,那现在打开driver/usb/core/usb.c看看usb总线是如何初始化的 

subsys_initcall(usb_init);
我们知道subsys_initcall是子系统的初始化,关于subsys__initcall在include/linux/init.h里定义如下:
#define subsys_initcall(fn)                __define_initcall("4",fn)
而__define_initcall在
#define __define_initcall(level,fn) \
        static initcall_t __initcall_##fn __attribute_used__ \
        __attribute__((__section__(".initcall" level ".init"))) = fn
相当于".initcall"4 ".init"
.initcall4.init在vmlinux.lds
__initcall_start = .;
                        *(.initcall1.init)
                        *(.initcall2.init)
                        *(.initcall3.init)
                        *(.initcall4.init)
                        *(.initcall5.init)
                        *(.initcall6.init)
                        *(.initcall7.init)
                __initcall_end = .;
把函数放到段地址里遍历段时就调用函数了 妙招!
__initcall_start在init里do_initcalls引用的-_-
for (call = &__initcall_start; call < &__initcall_end; call++)
{
}
废话不说了,回到usb_init里
最重要的是:
bus_register
usb_host_init
usb_hub_init
driver_register(&usb_generic_driver);

这。。。。。。。

subsys_initcall(musb_init); davinci usb-controller 的初始化,
主要是这步driver_register(&musb_driver); usb-controller的核心了

static struct device_driver musb_driver = {
        .name = (char *)musb_driver_name,
        .bus = &platform_bus_type,
        .owner = THIS_MODULE,
        .probe = musb_probe,
        .remove = __exit_p(musb_remove),
        .shutdown = musb_shutdown,
        .suspend = musb_suspend,
        .resume = musb_resume,
};
又回到linux驱动的框架了 哈 熟吧
最终还是会去做musb_probe,目标只有一个,在musb_probe里会musb_init_controller,当然只有初始化了才能用controller终于找到组织了。下面来看看musb_init_controller

。。。。。。。。。。。。。。。。。。。。。。。。

。。。。。。。。。。。。。。。。。。。。。。。。

提到HUB了,在usb_init core 早为我们准备了usb_hub_init();这样通过kernel_thread创建一个守护进程khubd轮询USB口的有没有设备接入,一个while(1)搞定简单吧老谭的C有用了,
调用 hub_port_connect_change处理

1        USB硬盘的识别:
接入USB硬盘hub_events就开始工作了,hub_port_connect_change发现有设备连上USB口于是就有了后来的事
usb_new_device
device_add
bus_add_device
device_attach

。。。。。。。。。。。。。。。。。。。。。。。。。

。。。。。。。。。。。。。。。。。。。。。。。。。
storage_probe,USB Mass Storage device? 调用usb_stor_scan_thread  创建守护进程(usb-stor-scan) 
storage_probe在usb_stor_init引用:
usb_register(&usb_storage_driver)

struct usb_driver usb_storage_driver = {
        .owner =        THIS_MODULE,
        .name =                "usb-storage",
        .probe =        storage_probe,
        .disconnect =        storage_disconnect,
        .id_table =        storage_usb_ids,
};
usb_register是usb 设备驱动向usb core层注册

struct usb_driver {
        struct module *owner;
        const char *name;
        int (*probe) (struct usb_interface *intf,
                      const struct usb_device_id *id);
        void (*disconnect) (struct usb_interface *intf);
        int (*ioctl) (struct usb_interface *intf, unsigned int code, void *buf);
        int (*suspend) (struct usb_interface *intf, u32 state);
        int (*resume) (struct usb_interface *intf);
        const struct usb_device_id *id_table;
        struct device_driver driver;
};
usb_driver是usb -core的驱动struct device_driver driver在这哈 linux驱动框架是不是很熟啊 ,对 这就是封装 。。。C++
回首usb core原来帮你做了这么多事

scsi_scan_host到SCSI层了!又看到scsi_scan_channel了
scsi设备都是挂到某个伦上的 比如:Attached scsi disk sda at scsi11, channel 0, id 0, lun 0  因为SCSI controller是数据结构LINUX 内核SCSI  core虚拟的



2  USB        硬盘数据传输:
在storage_probe时调用result = usb_stor_acquire_resources(us); 在此函数里创建的usb_stor_control_thread守护进程(usb-storage),在传输数据时用的是us->proto_handler(us->srb, us)决定用的是哪种协议的传输方式SCSI用的是usb_stor_transparent_scsi_command在(get_protocol里定义的),
说到get_protocol主要是得到一些设备信息比如:vender protocol manfatuer等
它用的ID是USB_PROBE是传入的。
get_transport决定用的是哪种的传输模式:硬盘是存储设备用的是BULK的方式,当然USB  core里也定义了(Bulk,Control传输模式因设备类型而异)。

一次传输从usb_stor_transparent_scsi_command开始:。。。首先usb_stor_invoke_transport                 temp_result = us->transport(us->srb, us);还记得吗这就是前面get_transport里定义好的传输模式,哈USB就是这样的
主要提到usb_stor_bulk_transfer_buf和usb_stor_bulk_transfer_sg,前者调用usb_stor_msg_common里面status = usb_submit_urb(us->current_urb, GFP_NOIO);提交URB,
URB是USB-core的主要传输单位,像net的packet一样
注意了op->submit_urb (urb, mem_flags)用到的是struct usb_operations        *op是
struct usb_operations {
        int (*allocate)(struct usb_device *);
        int (*deallocate)(struct usb_device *);
        int (*get_frame_number) (struct usb_device *usb_dev);
        int (*submit_urb) (struct urb *urb, int mem_flags);
        int (*unlink_urb) (struct urb *urb, int status);

        /* allocate dma-consistent buffer for URB_DMA_NOMAPPING */
        void *(*buffer_alloc)(struct usb_bus *bus, size_t size,
                        int mem_flags,
                        dma_addr_t *dma);
        void (*buffer_free)(struct usb_bus *bus, size_t size,
                        void *addr, dma_addr_t dma);

        void (*disable)(struct usb_device *udev, int bEndpointAddress);

        /* global suspend/resume of bus */
        int (*hub_suspend)(struct usb_bus *);
        int (*hub_resume)(struct usb_bus *);
};
调用的是musb_submit_urb而这是哪来的的呢?
哈 具体的USB controller的submit方法:我们用的DAVINCI usb-controller
在plat_uds.c里DAVINCI usb-controller device-driver初始化函数musb_init 
driver_register(&musb_driver);
定义如下:
static struct device_driver musb_driver = {
        .name = (char *)musb_driver_name,
        .bus = &platform_bus_type,
        .owner = THIS_MODULE,
        .probe = musb_probe,
        .remove = __exit_p(musb_remove),
        .shutdown = musb_shutdown,
        .suspend = musb_suspend,
        .resume = musb_resume,
};
还记得LINUX 驱动框架吗? Driver 的probe必然会去找设备
musb_init_controller这时才登场
bus = usb_alloc_bus(&musb_host_bus_ops)里bus->op = op;连上了
musb_init_controller除了这还做了:比如 platform_get_irq(pdev, 1)为MUSB申请中断 为何是platform呢? USB-controller无家可归的娃啊
musb_platform_init又是另一个比较重要的函数
clkp = clk_get (NULL, "USBCLK") USB的clock在这里申请还记得在CONTROLLER会检查 没时钟怎行
musb->isr = davinci_interrupt 中断处理函数
davinci usb controller通过中断来检测硬盘寄存器复位USB controller
回到usb_stor_bulk_transfer_sg里Transfer an entire SCSI command's worth of data payload over the bulk 这就是scsi协议用到的



2        USB硬盘的移除:
简单的可以说是USB热插拔的实现了,当USB口的设备拔出时,USB是如何知道的呢?还记得前面提到的hub_port_connect_change 吗?对USB有守护进程这个宝
void usb_disconnect(struct usb_device **pdev)
{
}
原因是这样的慢慢说来,当USB口的设备拔出时,从硬件上看是一个叫MUSB中断(中断号是12),davinci 的驱动就跳到中断处理函数davinci_interrupt里查状态寄存器的位变化,代码如下:
        tmp = musb_readl(tibase, DAVINCI_USB_INT_SRC_MASKED_REG);
        musb_writel(tibase, DAVINCI_USB_INT_SRC_CLR_REG, tmp);

        musb->int_rx = (tmp & DAVINCI_USB_RXINT_MASK)
            >> DAVINCI_USB_RXINT_SHIFT;
        musb->int_tx = (tmp & DAVINCI_USB_TXINT_MASK)
            >> DAVINCI_USB_TXINT_SHIFT;
        musb->int_usb = (tmp & DAVINCI_USB_USBINT_MASK)
            >> DAVINCI_USB_USBINT_SHIFT;

续。。。。。。
        if (musb->int_tx || musb->int_rx || musb->int_usb)
                retval |= musb_interrupt(musb);
这不进到usb-conroller中断处理函数里去le。后面的故事更精彩
然后起一个定时器去查询hub的状态(?。。。。。),同时 hub会向usbcontroller发送Change Bitmap的消息(硬件上做的东东),那么usb控制器就接受这个urb 处理完后调用那个hub_irq处理函数,在它那里再去kick_khubd里做了这一关键的一步,看下
static void kick_khubd(struct usb_hub *hub)
{
        unsigned long        flags;

        spin_lock_irqsave(&hub_event_lock, flags);
        if (list_empty(&hub->event_list)) {
                list_add_tail(&hub->event_list, &hub_event_list);
                wake_up(&khubd_wait);
        }
        spin_unlock_irqrestore(&hub_event_lock, flags);
}
把事件加到event链表里,这样hub_events就知道了,这就是热插拔。。。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值