USB硬盘驱动框架

25 篇文章 0 订阅
13 篇文章 0 订阅

                                                                       USB硬盘驱动框架

前言:

USB驱动在LINUX中占有重要地位,因此了解USB框架是十分必要的,下面以USB硬盘为例了解整个USB驱动的结构。

DAVINCI USB驱动的框架图:

USB-CORE

HCDMUSB CONTROLLER

LOW-LEVEL DRIVER

引言:首先make menuconfig选中usb supportCONFIG_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__initcallinclude/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在initdo_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口的有没有设备接入,一个while1)搞定简单吧老谭的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

它用的IDUSB_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

URBUSB-core的主要传输单位,像netpacket一样

注意了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 controllersubmit方法:我们用的DAVINCI usb-controller

plat_uds.cDAVINCI 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") USBclock在这里申请还记得在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就知道了,这就是热插拔。。。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值