Chinaunix首页 | 论坛 | 博客
  • 博客访问: 154724
  • 博文数量: 49
  • 博客积分: 45
  • 博客等级: 民兵
  • 技术积分: 545
  • 用 户 组: 普通用户
  • 注册时间: 2012-07-23 13:22
文章分类
文章存档

2017年(5)

2016年(18)

2015年(18)

2014年(8)

我的朋友

分类: Android平台

2015-03-17 21:56:48

kernel_init    do_one_initcall     ehci_hcd_init     

 

Ehci-hcd.c (drivers\usb\host) :

 

#ifdef PLATFORM_DRIVER

retval = platform_driver_register(&PLATFORM_DRIVER);

if (retval < 0)

goto clean0;

#endif

 

#ifdef CONFIG_USB_EHCI_S5P

#include "ehci-s5p.c"

#define PLATFORM_DRIVER s5p_ehci_driver

#endif

 

static struct platform_driver s5p_ehci_driver = {

.probe = s5p_ehci_probe,

.remove = __devexit_p(s5p_ehci_remove),

.shutdown = s5p_ehci_shutdown,

.driver = {

.name = "s5p-ehci",

.owner = THIS_MODULE,

.pm = &s5p_ehci_pm_ops,

}

};

 

Devs.c (arch\arm\plat-samsung)

 

struct platform_device s5p_device_ehci = {

.name = "s5p-ehci",

.id = -1,

.num_resources = ARRAY_SIZE(s5p_ehci_resource),

.resource = s5p_ehci_resource,

.dev = {

.dma_mask = &samsung_device_dma_mask,

.coherent_dma_mask = DMA_BIT_MASK(32),

}

};

 

s5p_ehci_probe     

 

重点说probe 函数,一路走下来就是拿资源,这些资源拿到后就做架构相关的一些初始化,比如中断,时钟,IO memory 

 

说一下io memory 吧,就是控制器寄存器的地址:

hcd->regs = ioremap(res->start, resource_size(res));

 

Devs.c (arch\arm\plat-samsung)

 

static struct resource s5p_ehci_resource[] = {

[0] = DEFINE_RES_MEM(S5P_PA_EHCI, SZ_256),

 

#define S5P_PA_EHCI EXYNOS4_PA_EHCI

 

Map.h (arch\arm\mach-exynos\include\mach)

 

#define EXYNOS4_PA_EHCI 0x12580000

 

注意下合格map.h文件,是记录所有芯片控制器地址的地方,如果你有什么模块的代码找不到,可以通过这里的寄存器去反推,比如时钟是0x1003_0000 ,在这里也能找到对应宏定义:

#define EXYNOS4_PA_CMU 0x10030000 

 

回到s5p_ehci_probe 函数,接下来有一个:

pdata->phy_init(pdev, S5P_USB_PHY_HOST);

 

这是USB phy 初始化的地方,这个指针函数怎么找?搜pdata对应的数据结构: s5p_ehci_platdata  即可。

你会看到在板级文件 Mach-smdk4x12.c (arch\arm\mach-exynos) 这里面会有这个:

 

static struct s5p_ehci_platdata smdk4x12_ehci_pdata;

 

static void __init smdk4x12_ehci_init(void)

{

struct s5p_ehci_platdata *pdata = &smdk4x12_ehci_pdata;

 

s5p_ehci_set_platdata(pdata); //这个函数里就是填充phy_init 指针函数的地方

}

 

然后你会发现phy_init 指针就指向exynos4412_usb_phy1_init

 

这个函数就是板级的USB EHCI控制器初始化,关于时序可以参考EHCI spec文档:

ehci-specification-for-usb  4.1 Host Controller Initialization 

 

然后,我们继续往下走,仍然在这个probe 函数中init还有收尾工作。

 

err = usb_add_hcd(hcd, irq, IRQF_SHARED);

这个函数里面关注三个行为:hcd->driver->reset hcd->driver->start  register_root_hub

 

hcd->driver->reset

hcd->driver->start

 

这两个函数定义在Ehci-s5p.c (drivers\usb\host) 文件:

 

static const struct hc_driver s5p_ehci_hc_driver = {

.description = hcd_name,

.product_desc = "S5P EHCI Host Controller",

.hcd_priv_size = sizeof(struct ehci_hcd),

 

.irq = ehci_irq,

.flags = HCD_MEMORY | HCD_USB2,

 

.reset = ehci_init,

.start = ehci_run,

.stop = ehci_stop,

.shutdown = ehci_shutdown,

 

register_root_hub

顾名思义就是注册root  hub 的,所有USB控制器都有一个root hub 

在这个函数里会调用到:usb_new_device 

 

然后在usb_new_device 

有这么一句:

err = usb_enumerate_device(udev); /* Read descriptors */

 

新设备的枚举就从这里展开了,这是hub,相对host而言也是被当做一个设备,其他设备也一样。

 

其他设备的枚举从哪里开始呢?

 

Hub.c (drivers\usb\core)

 

int usb_hub_init(void)

{

if (usb_register(&hub_driver) < 0) {

printk(KERN_ERR "%s: can't register hub driver\n",

usbcore_name);

return -1;

}

 

khubd_task = kthread_run(hub_thread, NULL, "khubd");

 

 

USB 的驱动有两条主线,分为两条线程:1,由kernel_init线程发起,注册ehci 控制器的驱动,初始化各个port. 

2,由hub_thread线程发起,检查root hub 上的各个port 发现新设备注册,并把设备归并到USB 总线上,如果新设备是hub 继续扫描该hub的各个port ,以此递归。

参考博客:http://blog.chinaunix.net/uid-20564848-id-73840.html

 

hub_port_init()这个函数的基本思想就是做初始化,首先是把一个设备reset,然后是分配地址.在然后是获得设备描述符.


对于第一个线程参考如下调用栈即可明白:

[    1.885000] [] (ehci_hub_control+0x40/0xb9c) from [] (usb_hcd_submit_urb+0x2d0/0x674)

[    1.895000] [] (usb_hcd_submit_urb+0x2d0/0x674) from [] (usb_start_wait_urb+0x44/0xcc)

[    1.905000] [] (usb_start_wait_urb+0x44/0xcc) from [] (usb_control_msg+0xc8/0xfc)

[    1.915000] [] (usb_control_msg+0xc8/0xfc) from [] (hub_probe+0x234/0x6a4)

[    1.925000] [] (hub_probe+0x234/0x6a4) from [] (usb_probe_interface+0x11c/0x1f8)

[    1.935000] [] (usb_probe_interface+0x11c/0x1f8) from [] (driver_probe_device+0x9c/0x214)

[    1.945000] [] (driver_probe_device+0x9c/0x214) from [] (bus_for_each_drv+0x64/0x8c)

[    1.950000] [] (bus_for_each_drv+0x64/0x8c) from [] (device_attach+0x94/0xb8)

[    1.960000] [] (device_attach+0x94/0xb8) from [] (bus_probe_device+0x84/0xa8)

[    1.970000] [] (bus_probe_device+0x84/0xa8) from [] (device_add+0x498/0x568)

[    1.980000] [] (device_add+0x498/0x568) from [] (usb_set_configuration+0x42c/0x6a4)

[    1.990000] [] (usb_set_configuration+0x42c/0x6a4) from [] (generic_probe+0x44/0x94)

[    1.995000] [] (generic_probe+0x44/0x94) from [] (usb_probe_device+0x14/0x18)

[    2.005000] [] (usb_probe_device+0x14/0x18) from [] (driver_probe_device+0x9c/0x214)

[    2.015000] [] (driver_probe_device+0x9c/0x214) from [] (bus_for_each_drv+0x64/0x8c)

[    2.025000] [] (bus_for_each_drv+0x64/0x8c) from [] (device_attach+0x94/0xb8)

[    2.035000] [] (device_attach+0x94/0xb8) from [] (bus_probe_device+0x84/0xa8)

[    2.045000] [] (bus_probe_device+0x84/0xa8) from [] (device_add+0x498/0x568)

[    2.050000] [] (device_add+0x498/0x568) from [] (usb_new_device+0x13c/0x220)

[    2.060000] [] (usb_new_device+0x13c/0x220) from [] (usb_add_hcd+0x3fc/0x5e4)

[    2.070000] [] (usb_add_hcd+0x3fc/0x5e4) from [] (s5p_ehci_probe+0x1fc/0x288)

[    2.080000] [] (s5p_ehci_probe+0x1fc/0x288) from [] (platform_drv_probe+0x14/0x18)

[    2.090000] [] (platform_drv_probe+0x14/0x18) from [] (driver_probe_device+0x9c/0x214)

[    2.095000] [] (driver_probe_device+0x9c/0x214) from [] (__driver_attach+0x8c/0x90)

[    2.105000] [] (__driver_attach+0x8c/0x90) from [] (bus_for_each_dev+0x58/0x80)

[    2.115000] [] (bus_for_each_dev+0x58/0x80) from [] (bus_add_driver+0x180/0x248)

[    2.125000] [] (bus_add_driver+0x180/0x248) from [] (driver_register+0x78/0x12c)

[    2.135000] [] (driver_register+0x78/0x12c) from [] (ehci_hcd_init+0x58/0x88)

[    2.145000] [] (ehci_hcd_init+0x58/0x88) from [] (do_one_initcall+0x30/0x174)

[    2.150000] [] (do_one_initcall+0x30/0x174) from [] (kernel_init+0xfc/0x1c8)

[    2.160000] [] (kernel_init+0xfc/0x1c8) from [] (kernel_thread_exit+0x0/0x8)

 

===================================

Ehci qh URB

 

 

[    3.580000] ///////qh and urb /////

[    3.580000] [] (unwind_backtrace+0x0/0xf0) from [] (ehci_qh_alloc+0x98/0xd4)

[    3.580000] [] (ehci_qh_alloc+0x98/0xd4) from [] (qh_append_tds+0x160/0x4e8)

[    3.580000] [] (qh_append_tds+0x160/0x4e8) from [] (ehci_urb_enqueue+0x108/0xd9c)

[    3.580000] [] (ehci_urb_enqueue+0x108/0xd9c) from [] (usb_hcd_submit_urb+0xa4/0x674)

[    3.580000] [] (usb_hcd_submit_urb+0xa4/0x674) from [] (usb_start_wait_urb+0x44/0xcc)

[    3.580000] [] (usb_start_wait_urb+0x44/0xcc) from [] (usb_control_msg+0xc8/0xfc)

[    3.580000] [] (usb_control_msg+0xc8/0xfc) from [] (hub_port_init+0x6d8/0x958)

[    3.580000] [] (hub_port_init+0x6d8/0x958) from [] (hub_thread+0x774/0x10a4)

[    3.580000] [] (hub_thread+0x774/0x10a4) from [] (kthread+0x8c/0x98)

[    3.580000] [] (kthread+0x8c/0x98) from [] (kernel_thread_exit+0x0/0x8)

 

 

[    1.780000] ///////qh and urb /////

[    1.785000] [] (unwind_backtrace+0x0/0xf0) from [] (ehci_qh_alloc+0x98/0xd4)

[    1.795000] [] (ehci_qh_alloc+0x98/0xd4) from [] (ehci_init+0x110/0x46c)

[    1.805000] [] (ehci_init+0x110/0x46c) from [] (usb_add_hcd+0x18c/0x5e4)

[    1.810000] [] (usb_add_hcd+0x18c/0x5e4) from [] (s5p_ehci_probe+0x1fc/0x288)

[    1.820000] [] (s5p_ehci_probe+0x1fc/0x288) from [] (platform_drv_probe+0x14/0x18)

[    1.830000] [] (platform_drv_probe+0x14/0x18) from [] (driver_probe_device+0x9c/0x214)

[    1.840000] [] (driver_probe_device+0x9c/0x214) from [] (__driver_attach+0x8c/0x90)

[    1.850000] [] (__driver_attach+0x8c/0x90) from [] (bus_for_each_dev+0x58/0x80)

[    1.855000] [] (bus_for_each_dev+0x58/0x80) from [] (bus_add_driver+0x180/0x248)

[    1.865000] [] (bus_add_driver+0x180/0x248) from [] (driver_register+0x78/0x12c)

[    1.875000] [] (driver_register+0x78/0x12c) from [] (ehci_hcd_init+0x58/0x88)

[    1.885000] [] (ehci_hcd_init+0x58/0x88) from [] (do_one_initcall+0x30/0x174)

[    1.895000] [] (do_one_initcall+0x30/0x174) from [] (kernel_init+0xfc/0x1c8)

[    1.900000] [] (kernel_init+0xfc/0x1c8) from [] (kernel_thread_exit+0x0/0x8)

[    1.910000] liucong ehci_readl :regs :0xdfcd0010 vaule:0x80b00

 

URB 的来历:

 

usb_control_msg  -》 usb_internal_control_msg  urb = usb_alloc_urb(0, GFP_NOIO); 

 

然后

 

关于usb_control_msg 的说明更多可以参考:http://blog.chinaunix.net/uid-20564848-id-73840.html

 

 

在函数 qh_append_tds qh = (struct ehci_qh *) *ptr; URB 制造得到qh

 

 

DMA 池申请qh 使用的内存:

 

ehci_mem_init    函数中:

    

/* QHs for control/bulk/intr transfers */

ehci->qh_pool = dma_pool_create ("ehci_qh",

ehci_to_hcd(ehci)->self.controller,

sizeof(struct ehci_qh_hw),

32 /* byte alignment (for hw parts) */,

4096 /* can't cross 4K */);

 

关于DMA 参考链接:

 

 

usb ehci adress222:0xc3f4f940  value:0xc3f4f802

usb ehci adress222:0xc3f4f944  value:0xa000

usb ehci adress222:0xc3f4f948  value:0x0

usb ehci adress222:0xc3f4f94c  value:0x1

usb ehci adress222:0xc3f4f950  value:0x1

usb ehci adress222:0xc3f4f954  value:0x1

usb ehci adress222:0xc3f4f958  value:0x40

 

1111adress:0xc3f4f940 value:0xc3f4f942

1111adress:0xc3f4f944 value:0x8000

1111adress:0xc3f4f948 value:0x0

1111adress:0xc3f4f94c value:0x1

1111adress:0xc3f4f950 value:0x1

1111adress:0xc3f4f954 value:0x1

1111adress:0xc3f4f958 value:0x40

 

 

 

 

ehci_init  : 

 

ehci_mem_init  : ehci->async = ehci_qh_alloc (ehci, flags);  第一个ehci_qh

 

hci_qh_alloc : qh->hw = (struct ehci_qh_hw *) dma_pool_alloc(ehci->qh_pool, flags, &dma); 

qh->qh_dma = dma;

 

 

 

usb_control_msg 参数详解:

 

result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),

USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,

(type << 8) + index, 0, buf, size,

USB_CTRL_GET_TIMEOUT);

 

1)第一个参数,是usb_device ,是说它属于哪一个设备,这个它就是描述符,这个函数在内核有一段英文解释:

 * Gets a USB descriptor.  Convenience functions exist to simplify

 * getting some types of descriptors.  Use

 * usb_get_string() or usb_string() for USB_DT_STRING.

 * Device (USB_DT_DEVICE) and configuration descriptors (USB_DT_CONFIG)

 * are part of the device structure.

这段说明很清楚的说明了,设备描述符和配置描述符是usb_device这个结构体的一部分,他们获取后会被放在usb_device这个结构体里。至于具体是设备描述符还是配置描述符等,看参数5才能知道。

 

2)第二个参数,是一个pipe,它融合了端点号,设备号,USB数据流方向三个信息。内核里这个数据的实现定义如下:

#define usb_rcvctrlpipe(dev, endpoint) \

((PIPE_CONTROL << 30) | __create_pipe(dev, endpoint) | USB_DIR_IN)

 

__create_pipe 函数实现如下:

static inline unsigned int __create_pipe(struct usb_device *dev,

unsigned int endpoint)

{

return (dev->devnum << 8) | (endpoint << 15);

}

 

由这个宏的名字也可知道,顾名思义receive  control  pipe ,接收,控制,管道(管道)。 

 

3)第三个参数,USB 标准命令的序号,不同的序号表示不同的意义,这个USB_REQ_GET_DESCRIPTOR =0x06就是拿描述符的意思,分为如下类:

A:[To Device]获取设备描述符:

*.描述当前USB协议的版本号.设备端点0FIFO大小.USB设备的ID号等.

B:[To Configuration]获取配置描述符:

*.描述USB设备接口个数及是否有自供电能力等.

C:[To Interface]获取接口描述符:

*.描述端点0以外的物理端点个数等信息.

D:[To Endpoint]获取端点描述符:

 *.描述端点0各端点的传输类型和最大信息包大小和端点的传输方向(IN/OUT).


4)第四个参数,详细解释如下:

- RequestTypeD7D6D5D4D3D2D1D0

 D7=0主机到设备, =1设备到主机;

 D6D5 =00标准请求命令, 01 类请求命令,10用户定义的命令,11保留值

 D4D3D2D1D0= 0表示接收者为设备,1表示接收者为接口,2表示接收者为端点,3表示接收者为其他,其他值保留。


这里是USB_DIR_IN,也就是D7位是1D6-D0都是0,那么就是表明:一,要设备发数据到主机,二,是标准请求命令,三,当前包的接收者位设备。


5)第五个参数,一共16位,融合了描述符的类型(设备描述符还是配置描述符等),描述符的编号两个字段的信息,这里(type << 8) + index,这两个字段信息分别占高8位和低八位。


6)第六个参数,是接口号的信息,因为这个是usb_control_msg是在拿描述符的函数usb_get_descriptor中被调度的,这种控制信息都是跟端点0沟通的,而端点0必然在接口0,所以这个值被写死为0


7)第七个参数,它指向了一块内存,这块内存在这里被初始化为描述符的类型,设备发送的描述符的信息就放在这块内存中。


8)第八个参数,对应第七个参数,表明这块内存的大小。


9)第九个参数,表明主机发送此控制信息,到接收这个控制信息完毕,最多等待的时间,超出此时限还没收到传输完成信号,会报错。



USB 设备的各种状态:

enum usb_device_state {

/* NOTATTACHED isn't in the USB spec, and this state acts

 * the same as ATTACHED ... but it's clearer this way.

 */

USB_STATE_NOTATTACHED = 0,


/* chapter 9 and authentication (wireless) device states */

USB_STATE_ATTACHED,

USB_STATE_POWERED, /* wired */

USB_STATE_RECONNECTING, /* auth */

USB_STATE_UNAUTHENTICATED, /* auth */

USB_STATE_DEFAULT, /* limited function */

USB_STATE_ADDRESS,

USB_STATE_CONFIGURED, /* most functions */


USB_STATE_SUSPENDED


/* NOTE:  there are actually four different SUSPENDED

 * states, returning to POWERED, DEFAULT, ADDRESS, or

 * CONFIGURED respectively when SOF tokens flow again.

 * At this level there's no difference between L1 and L2

 * suspend states.  (L2 being original USB 1.1 suspend.)

 */

};



USB host controller 的各种状态:


# define HC_STATE_HALT 0

# define HC_STATE_RUNNING (__ACTIVE)

# define HC_STATE_QUIESCING (__SUSPEND|__TRANSIENT|__ACTIVE)

# define HC_STATE_RESUMING (__SUSPEND|__TRANSIENT)

# define HC_STATE_SUSPENDED (__SUSPEND)

 

 

HC 初始化完毕,使能HC  ,开始注册root_hub 的行为在函数:usb_add_hcd中,代码如下:

hcd->state = HC_STATE_RUNNING;

retval = hcd->driver->start(hcd);

if (retval < 0) {

dev_err(hcd->self.controller, "startup error %d\n", retval);

goto err_hcd_driver_start;

}

 

/* starting here, usbcore will pay attention to this root hub */

rhdev->bus_mA = min(500u, hcd->power_budget);

if ((retval = register_root_hub(hcd)) != 0)

goto err_register_root_hub;

 

 

 

===============================

 

/* usb 2.0 root hub device descriptor */

static const u8 usb2_rh_dev_descriptor [18] = {

0x12,       /*  __u8  bLength; */

0x01,       /*  __u8  bDescriptorType; Device */

0x00, 0x02, /*  __le16 bcdUSB; v2.0 */

 

0x09,     /*  __u8  bDeviceClass; HUB_CLASSCODE */

0x00,     /*  __u8  bDeviceSubClass; */

0x00,       /*  __u8  bDeviceProtocol; [ usb 2.0 no TT ] */

0x40,       /*  __u8  bMaxPacketSize0; 64 Bytes */

 

0x6b, 0x1d, /*  __le16 idVendor; Linux Foundation 0x1d6b */

0x02, 0x00, /*  __le16 idProduct; device 0x0002 */

KERNEL_VER, KERNEL_REL, /*  __le16 bcdDevice */

 

0x03,       /*  __u8  iManufacturer; */

0x02,       /*  __u8  iProduct; */

0x01,       /*  __u8  iSerialNumber; */

0x01        /*  __u8  bNumConfigurations; */

};

======================

static const u8 hs_rh_config_descriptor [] = {

 

/* one configuration */

0x09,       /*  __u8  bLength; */

0x02,       /*  __u8  bDescriptorType; Configuration */

0x19, 0x00, /*  __le16 wTotalLength; */

0x01,       /*  __u8  bNumInterfaces; (1) */

0x01,       /*  __u8  bConfigurationValue; */

0x00,       /*  __u8  iConfiguration; */

0xc0,       /*  __u8  bmAttributes; 

 Bit 7: must be set,

     6: Self-powered,

     5: Remote wakeup,

     4..0: resvd */

0x00,       /*  __u8  MaxPower; */

};

 

 

 

 

 

 

 

 

阅读(2309) | 评论(0) | 转发(0) |
0

上一篇:DMA 相关问题 汇总

下一篇:GIC 调试总结

给主人留下些什么吧!~~