分类: 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] [
[ 1.895000] [
[ 1.905000] [
[ 1.915000] [
[ 1.925000] [
[ 1.935000] [
[ 1.945000] [
[ 1.950000] [
[ 1.960000] [
[ 1.970000] [
[ 1.980000] [
[ 1.990000] [
[ 1.995000] [
[ 2.005000] [
[ 2.015000] [
[ 2.025000] [
[ 2.035000] [
[ 2.045000] [
[ 2.050000] [
[ 2.060000] [
[ 2.070000] [
[ 2.080000] [
[ 2.090000] [
[ 2.095000] [
[ 2.105000] [
[ 2.115000] [
[ 2.125000] [
[ 2.135000] [
[ 2.145000] [
[ 2.150000] [
[ 2.160000] [
===================================
Ehci 的qh 与URB:
[ 3.580000] ///////qh and urb /////
[ 3.580000] [
[ 3.580000] [
[ 3.580000] [
[ 3.580000] [
[ 3.580000] [
[ 3.580000] [
[ 3.580000] [
[ 3.580000] [
[ 3.580000] [
[ 3.580000] [
[ 1.780000] ///////qh and urb /////
[ 1.785000] [
[ 1.795000] [
[ 1.805000] [
[ 1.810000] [
[ 1.820000] [
[ 1.830000] [
[ 1.840000] [
[ 1.850000] [
[ 1.855000] [
[ 1.865000] [
[ 1.875000] [
[ 1.885000] [
[ 1.895000] [
[ 1.900000] [
[ 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协议的版本号.设备端点0的FIFO大小.USB设备的ID号等.
B:[To Configuration]获取配置描述符:
*.描述USB设备接口个数及是否有自供电能力等.
C:[To Interface]获取接口描述符:
*.描述端点0以外的物理端点个数等信息.
D:[To Endpoint]获取端点描述符:
*.描述端点0各端点的传输类型和最大信息包大小和端点的传输方向(IN/OUT).
4)第四个参数,详细解释如下:
- RequestType:D7D6D5D4D3D2D1D0
D7=0主机到设备, =1设备到主机;
D6D5 =00标准请求命令, 01 类请求命令,10用户定义的命令,11保留值
D4D3D2D1D0= 0表示接收者为设备,1表示接收者为接口,2表示接收者为端点,3表示接收者为其他,其他值保留。
这里是USB_DIR_IN,也就是D7位是1,D6-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; */
};