在pxa310 中 查看host目录下的Makefile
是要编译出一个名为”ohci_hcd”的模块
对OHCI主控器进行编程要容易得多。控制器假设有一组端点(endpoint)可用,并知道帧中不同传输类型的调度优先级和排序。主控器使用的主要数据结构是端点描述符(ED),它上面连接着一个传输描述符(TD)的队列。 ED包含端点所允许的最大的包大小,控制器硬件完成包的分割。每次传输后都会更新指向数据缓冲区的指针,当起始和终止指针相等时,TD就退归到完成队列(done-queue)。四种类型的端点各有其自己的队列。控制和大块(bulk)端点分别在它们自己的队列排队。中断ED在树中排队,在树中的深度定义了它们运行的频度。
帧列表 中断 同步(isochronous) 控制大块(bulk)
主控器在每帧中运行的调度看起来如下。控制器首先运行非周期性控制和大块队列,最长可到HC驱动程序设置的一个时间限制。然后以帧编号低5位作为中断ED树上深度为0的那一层中的索引,运行那个帧编号的中断传输。在这个树的末尾,同步ED被连接,并随后被遍历。同步TD包含了传输应当运行其中的第一个帧的帧编号。所有周期性的传输运行过以后,控制和大块队列再次被遍历。中断服务例程会被周期性地调用,来处理完成的队列,为每个传输调用回调,并重新调度中断和同步端点。
更详尽的描述请看 OHCI specification。服务层,即中间层,提供了以可控的方式对设备进行访问,并维护着由不同驱动程序和服务层所使用的资源。此层处理下面几方面:
设备配置信息
与设备进行通信的管道
探测和连接设备,以及从设备分离(detach)。
ohci_hcd_mod_init
现在看一下HCD的probe 是如何发生的?
还是从源头说起吧
在arch/arm/march-pxa/generic.c 中有如下代码
在pxa_init 中注册了一系列的device
其中有这样一个device
static struct platform_device ohci_hcd_pxa_device = {
.name = "pxa3xx-ohci",
.id = -1,
.dev = {
.platform_data = &pxa_ohci_info,
.dma_mask = &ohci_hcd_pxa_dmamask,
.coherent_dma_mask = 0xffffffff,
},
.num_resources = ARRAY_SIZE(pxa3xx_ohci_resources),
.resource = pxa3xx_ohci_resources,
};
注意这个device的名字pxa3xx-ohci
以后还有一个同样名字的driver
platform_device 在device的基础上封装了资源和ID
struct platform_device {
const char * name;
u32 id;
struct device dev;
u32 num_resources;
struct resource * resource;
};
看看这个HCD 拥有的资源
static struct resource pxa3xx_ohci_resources[] = {
{
.start= 0x4C000000,
.end= 0x4C000fff,
.flags= IORESOURCE_MEM,
}, {
.start= IRQ_USBH1,
.end= IRQ_USBH1,
.flags= IORESOURCE_IRQ,
},
};
内存4K ,中断号 为 3
再来看一下driver 这一边
static struct platform_driver ohci_hcd_pxa3xx_driver = {
.probe = ohci_hcd_pxa3xx_drv_probe,
.remove = ohci_hcd_pxa3xx_drv_remove,
.shutdown = usb_hcd_platform_shutdown,
#ifdef CONFIG_PM
.suspend = ohci_hcd_pxa3xx_drv_suspend,
.resume = ohci_hcd_pxa3xx_drv_resume,
#endif
.driver = {
.name = "pxa3xx-ohci",
},
};
看看match 的时候 发生了什么事情?
static int ohci_hcd_pxa3xx_drv_probe(struct platform_device *pdev)
{
int ret;
pr_debug ("In ohci_hcd_pxa3xx_drv_probe");
if (usb_disabled())
return -ENODEV;
ret = usb_hcd_pxa3xx_probe(&ohci_pxa3xx_hc_driver, pdev);
return ret;
}
usb_hcd_pxa3xx_probe
1 创建usb_hcd !
2 在hcd 中有
struct usb_bus self; /* hcd is-a bus */
这样一个结构体
现在对这个usb_bus进行初始化
将usb_devmap 设置为0 ,这个结构体就是4个int的数组
其他的一些就不说了
这样就完成了usb_bus 的初始化
将内存资源给hcd,
Hcd 请求后,重新映射,这个就是映射过来的寄存器地址
哈哈!
设备的平台数据
struct pxaohci_platform_data {
int (*init)(struct device *);
void (*exit)(struct device *);
int port_mode;
#define PMM_NPS_MODE 1
#define PMM_GLOBAL_MODE 2
#define PMM_PERPORT_MODE 3
int power_budget;
};
启动hc
设置hc的内存管理模式
初始化ohci