一、前言

本篇博客仅对ECHI主机控制器驱动的注册部分进行简要叙述,后面再对一些重要的接口进行分析讲解。

二、USB

1、概述

USB(Universal Serial Bus)即“通用外部总线”,在各种场所已经大量使用。它的接口简单(只有5v电源和地、两根数据线D+和D-),可以外接硬盘、键盘、鼠标、打印机等多种设备。

USB总线规范有1.1版和2.0版。USB1.1支持两种传输速率:低速1.5Mbit/s,全速12Mbit/s,对于鼠标、键盘、CD-ROM等设备,这样的速率够了。但是在访问硬盘、摄像机时,还是稍显不足、为此,USB2.0提供了一种更高的传输速率:高速,他可以达到480Mbit/s。USB2.0向下兼容USB1.1,可以将遵循USB1.1规范的设备连接到USB2.0控制器上,也可以把USB2.0的设备连接到USB1.1控制器上。

2、硬件拓扑结构

图 - USB硬件拓扑结构

USB主机控制器(USB Host Controller)通过跟集线器与其他USB设备相连。集线器也属于USB设备,通过它可以在一个USB接口上扩展出多个接口。除根集线器外。可以层叠5个集线器,每条USB电缆的最大长度是5m,所以USB总线的最大距离为30m。一条USB总线上可以外接127个设备,包括根集线器和其他集线器。整个结构图是一个星状结构,一条USB总线上所有设备共享一条通往主机的数据通道,同一时刻只能有一个设备与主机通信。

3、主机控制器

USB主机控制器分为3种:UHCI、OHCI和EHCI。其中HCI表示“Host Controller Interface”。UHCI、OHCI属于USB1.1的主机控制器规范,而EHCI属于USB2.0的主机控制器规范。UHCI(即Universal HCI),它是由Inrel公司制定的标准,它的硬件所做的事情比较少,这使得软件比较复杂。与之相对的是OHCI(即Open HCI),塔友Compaq、Microsoft和National Semiconductor联合制定,在硬件方面它具备更多的智能,使得软件相对简单,因此,我们公司用的就是OHCI。

三、源码分析

USB驱动路径:kernel/driver/usb/。

ECHI驱动文件路径:kernel/driver/usb/host/echi-hcd.c。

虽然对于大型的驱动模块从框架切入能更好的理解代码,但我目前的基础知识还比较薄弱,所以还是依旧从驱动入口看起。

#ifdef CONFIG_USB_EHCI_HCD_PLATFORM
#include "ehci-platform.c"
#define PLATFORM_DRIVER     ehci_platform_driver
#endifstatic int __init ehci_hcd_init(void)
{int retval = 0;if (usb_disabled())return -ENODEV;printk(KERN_INFO "%s: " DRIVER_DESC "\n", hcd_name);//设置usb_hcds_loaded的第USB_EHCI_LOADED位为1//作用通过下面的打印就能知道:它能让ehci主机控制器驱动先于uhci和ohciset_bit(USB_EHCI_LOADED, &usb_hcds_loaded);if (test_bit(USB_UHCI_LOADED, &usb_hcds_loaded) || test_bit(USB_OHCI_LOADED, &usb_hcds_loaded))printk(KERN_WARNING "Warning! ehci_hcd should always be loaded before uhci_hcd and ohci_hcd, not after\n");#ifdef PLATFORM_DRIVERretval = platform_driver_register(&PLATFORM_DRIVER);if (retval < 0)goto clean0;
#endifreturn retval;#ifdef PLATFORM_DRIVERplatform_driver_unregister(&PLATFORM_DRIVER);
clean0:
#endifclear_bit(USB_EHCI_LOADED, &usb_hcds_loaded);return retval;
}static void __exit ehci_hcd_cleanup(void)
{
#ifdef PLATFORM_DRIVERplatform_driver_unregister(&PLATFORM_DRIVER);
#endifclear_bit(USB_EHCI_LOADED, &usb_hcds_loaded);
}module_init(ehci_hcd_init);
module_exit(ehci_hcd_cleanup);MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_AUTHOR (DRIVER_AUTHOR);
MODULE_LICENSE ("GPL");

以上代码是我经过删减剩下的。

在echi-hcd的模块入口和出口函数有许多的宏控,而我留下了我目前所学习的平台(sunplus 8368u)相关的代码。

在init函数中做的事情相对较少,就是进行位设置、位检测和平台驱动注册。

位设置和位检测中的USB_*_LOADED被定义在kernel/include/linux/usb/hcd.h,值为0、1、2。

平台驱动注册所用的平台驱动结构体PLATFORM_DRIVER,可以看到上述代码最上方的define,显然,这个结构体在同级目录下的ehci-platform.c文件中。

static const struct platform_device_id ehci_platform_table[] = {{"ehci-platform", 0},{}
};static struct platform_driver ehci_platform_driver = {.id_table = ehci_platform_table,.probe = ehci_platform_probe,.remove = __devexit_p(ehci_platform_remove),
#ifdef CONFIG_PM_WARP.resume = sp_ehci_fb_resume,.suspend = sp_ehci_fb_suspend,
#endif.shutdown = usb_hcd_platform_shutdown,.driver = {.owner = THIS_MODULE,.name = "ehci-platform",
#ifndef CONFIG_PM_WARP.pm = &ehci_platform_pm_ops,
#endif}
};

平台设备一般通过.driver.name进行匹配,匹配成功之后则进入probe函数。

static int __devinit ehci_platform_probe(struct platform_device *dev)
{struct usb_hcd *hcd;struct resource *res_mem;int irq;int err = -ENOMEM;struct ehci_hcd_sp *ehci_sp;BUG_ON(!dev->dev.platform_data);if (usb_disabled())return -ENODEV;/* 获取中断号 */irq = platform_get_irq(dev, 0);if (irq < 0) {pr_err("no irq provieded");return irq;}/* 获取平台设备资源 */res_mem = platform_get_resource(dev, IORESOURCE_MEM, 0);if (!res_mem) {pr_err("no memory recourse provieded");return -ENXIO;}/* 创建和初始化一个hcd结构体 *///usb_hcd主要描述主机控制器相关信息//hc_driver结构体类型内主要是控制主机的钩子函数hcd = usb_create_hcd(&ehci_platform_hc_driver, &dev->dev, dev_name(&dev->dev));if (!hcd)return -ENOMEM;hcd->rsrc_start = res_mem->start;hcd->rsrc_len = resource_size(res_mem);//从rsrc_start地址开始申请一个rsrc_len长度的内存,用于后面做io映射if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {pr_err("controller already in use");err = -EBUSY;goto err_put_hcd;}//io映射:映射实际io物理地址到虚拟内存hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);if (!hcd->regs)goto err_release_region;tasklet_init(&hcd->host_irq_tasklet, ehci_irq_tasklet, (unsigned long)hcd);err = usb_add_hcd(hcd, irq, IRQ_TYPE_LEVEL_HIGH);if (err)goto err_iounmap;platform_set_drvdata(dev, hcd);/****************************************************/ehci_sp = (struct ehci_hcd_sp *)hcd_to_ehci(hcd);//创建sys调试节点if (dev->id < 3) {device_create_file(&dev->dev, &dev_attr_usb_role_switch);device_create_file(&dev->dev, &dev_attr_usb_ctrl_reset);}device_create_file(&dev->dev, &dev_attr_usb_speed_switch);device_create_file(&dev->dev, &dev_attr_usb_uphy_swing);device_create_file(&dev->dev, &dev_attr_usb_disconnect_level);device_create_file(&dev->dev, &dev_attr_usb_rx_sqct_level);device_create_file(&dev->dev, &dev_attr_usb_rx_clk_invert);ehci_sp->flag = 0;printk("flag ***%p %p %d %d %p\n", hcd, hcd->hcd_priv, sizeof(struct ehci_hcd_sp), hcd->driver->hcd_priv_size, &ehci_sp->flag);/* ohci reset uphy notifier */ehci_sp->ehci_notifier.notifier_call = ehci_notifier_call;usb_register_notify(&ehci_sp->ehci_notifier);init_waitqueue_head(&hcd->reset_queue);hcd->ptr_flag = &ehci_sp->flag;ehci_sp->reset_thread = kthread_create(ehci_reset_thread,hcd_to_ehci(hcd),"ehci_reset_wait_event");if (IS_ERR(ehci_sp->reset_thread)) {pr_err("Create EHCI(%d) reset thread fail!\n", dev->id);return err;}/* Tell the thread to start working */wake_up_process(ehci_sp->reset_thread);return err;err_iounmap:iounmap(hcd->regs);
err_release_region:release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
err_put_hcd:usb_put_hcd(hcd);return err;
}

probe函数我们先关注两个结构体,第三行的hcd和31行的ehci_platform_hc_driver。

hcd的类型为“struct usb_hcd *hcd”,这个结构体主要用来描述主机控制器的相关信息,定义位置在kernel/include/linux/usb/hcd.h。

ehci_platform_hc_driver的类型为“struct hc_driver”,这个结构体则是一些控制usb主机控制器的回调函数。

以下是echi_hcd驱动的hc_driver。

static const struct hc_driver ehci_platform_hc_driver = {.description = hcd_name,.product_desc = "Generic Platform EHCI Controller",//私有数据大小.hcd_priv_size = sizeof(struct ehci_hcd_sp),//中断处理函数.irq = ehci_irq,.flags = HCD_MEMORY | HCD_USB2 | HCD_BH,//复位、开始、停止、关闭函数.reset = ehci_platform_reset,.start = ehci_run,.stop = ehci_stop,.shutdown = ehci_shutdown,//usb logo test support.usb_logo_test = ehci_usb_logo_test,.urb_enqueue = ehci_urb_enqueue,.urb_dequeue = ehci_urb_dequeue,.endpoint_disable = ehci_endpoint_disable,.endpoint_reset = ehci_endpoint_reset,.get_frame_number = ehci_get_frame,.hub_status_data = ehci_hub_status_data,.hub_control = ehci_hub_control,
#if defined(CONFIG_PM).bus_suspend = ehci_bus_suspend,.bus_resume = ehci_bus_resume,
#endif.relinquish_port = ehci_relinquish_port,.port_handed_over = ehci_port_handed_over,.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,.get_port_status_from_register = ehci_get_port_status_from_register,
};

Linux驱动开发之USB驱动深入学习(三)——USB2.0ECHI驱动注册相关推荐

  1. linux内核单步调试,Linux内核驱动开发之KGDB单步调试内核(kgdboc方式)

    如何单步调试Linux内核一直困扰着linux驱动开发人员,内核有其代码量大.逻辑复杂.与硬件交互的特性.因此,有着不同于应用程序的调试方法,据统计Linux内核开 Linux内核驱动开发之KGDB原 ...

  2. Android驱动开发之Hello实例(基于高通msm8909)

    点击打开链接 Android驱动开发之Hello实例: 驱动部分 modified:   kernel/arch/arm/configs/msm8909-1gb_w100_hd720p-perf_de ...

  3. Android驱动开发之Hello实例

    Android驱动开发之Hello实例: 驱动部分 modified:   kernel/arch/arm/configs/msm8909-1gb_w100_hd720p-perf_defconfig ...

  4. 10 怎么写USB驱动,Cadence USB 2.0 Controller和PHY IP驱动移植

    怎么写USB驱动,Cadence USB 2.0 Controller和PHY IP驱动移植 作者 将狼才鲸 日期 2022-03-26 本子文档所属的上级文档(Gitee仓库): 才鲸 / 嵌入式知 ...

  5. (0045) iOS 开发之MBProgressHUD 源码学习

    (0045) iOS 开发之MBProgressHUD 源码学习 第一部分:学习所得和分析线程 1.  学习到了kvo 的使用 和屏幕方向的旋转判断. 2. 如果调起这个 HUD 的方法不是在主线程调 ...

  6. 安卓开发之Handler、HandlerThread学习篇

    安卓开发之Handler.HandlerThread学习心得篇           开篇说明:本文采用的都是最基础最简单的例子,目的只有一个:希望大家将学习的焦点放在Handler的理解和使用上,我不 ...

  7. 【转载】Android逆向开发之smali语言的学习

    Android逆向开发之smali语言的学习 该文转载自乱码三千 – 分享实用IT技术 smali和java基本数据类型对比 smali java B byte S short I int J lon ...

  8. Swift Web 开发之 Vapor - 模版 Leaf(三)

    模版引擎,对现在的 Web 开发极为重要,几乎所有主流 Web 框架都会支持一种或多种模版引擎,模版引擎可以分离用户界面和业务逻辑,工作原理主要是一种翻译,后端对特定的标记.语法.变量等渲染后再输送给 ...

  9. Linux驱动开发之PCIe Host驱动

    作者 QQ群:852283276 微信:arm80x86 微信公众号:青儿创客基地 B站:主页 https://space.bilibili.com/208826118 参考 PCI Utilitie ...

最新文章

  1. log4j:WARN Error initializing output writer. log4j:WARN Unsupported encoding?
  2. NLP命名实体识别(NER)代码实践
  3. 半导体到底靠什么导电?
  4. 社会大学的作业,活动篇
  5. HTML常见小问题2
  6. 五种网络管理技巧优化网络办公环境
  7. pctfree pctused详解
  8. SpringBoot 自带工具类~AopUtils
  9. 这家总资产排名第一的银行,为什么叫“小”摩?
  10. ADS2015 for linux 安装教程
  11. python程序实现rep后剪枝算法
  12. 【中医学】8 中药-1
  13. 12306订票候补是个坑_12306网上订票候补是什么意思
  14. Android studio添加依赖是什么意思以及添加依赖的方法
  15. 电信物联网平台,java后台对接电信北向应用,订阅平台消息
  16. 有哪些比较好的企业内部管理软件?公认的5个高效管理软件介绍
  17. Python中的微型巨人-Flask
  18. 解析FPS,刷新率,垂直同步
  19. FPN与DSSD的对比
  20. 通俗理解 三次握手四次挥手(老友依恋式)

热门文章

  1. Python使用ffmpeg批量去水印
  2. 博图买什么样配置的笔记本_博图买什么样配置的笔记本_西门子PLC编程软件-博图软件用什么配置的电脑最好?......
  3. 慢启动和拥塞避免算法
  4. 5G科普——5G接入网
  5. Opencascade源码学习之模型算法_TKO模块文件介绍
  6. STM32 低功耗设计
  7. arduino花盆含水量_Arduino教程┃模拟土壤湿度传感器的介绍
  8. MVC 网上零食销售系统的设计与实现java jsp 程序设计 课程设计 毕业设计-附源码02139
  9. Windows Server 2019不重装进行分盘
  10. 自写的C语言矩阵简易运算库