USB驱动移植教程一.USB驱动框架在Linux系统中,提供了主机侧和设备侧视角的USB驱动框架,这里,仅仅讲解主机侧角度看到的USB驱动框架。从主机侧的角度而言,需要编写的USB驱动程序包括主机控制器驱动和设备驱动两类。USB主机控制器驱动程序控制插入其中的USB设备,而USB设备驱动程序控制该设备如何作为设备与主机通信。在USB主机控制器驱动和USB设备驱动之间还有一层叫USB核心层。USB核心负责USB驱动管理和协议处理工作,它通过定义一些数据结构、宏和功能函数,向上为USB设备驱动提供编程接口,向下为USB主机控制器驱动提供编程接口;通过全局变量维护整个系统的USB设备信息,完成设备热插拔控制、总线数据传输控制等。说了那么多,无图无真相啊~~LinuxUSB主机侧驱动总体框架二.USB驱动移植步骤1.S5PV210主机控制驱动的移植USB主机控制器有3种规范,UHCI(UniversalHostControllerInterface),这种规范主要是Intel、Via芯片公司提供支持PC主板的;OHCI(OpenHostControllerInterface),这种规范是微软提出来的,主要应用在非PC系统上的嵌入式领域上的USB芯片;EHCI(EnhancedHostControllerInterface),这种后来为提高USB速度而提出的规范,它支持最高速度为480Mbps。在《S5PV210_UM_REV1.1》手册上搜索OHCI关键词,会发现下面一段话这表明S5PV210这款CPU支持一个USB主机接口,同时支持EHCI和OHCI这两种规范,支持USB1.1和USB2.0规范,支持最高的外设传输速率为480Mbps。注意了,它并不支持USB3.0规范的USB设备,所以做测试的时候,千万不要拿USB3.0规范的USB设备去测试。2.1移植ohci-s5p驱动打开内核目录:driversusbhost,发现Linux系统提供了大量的主机控制器驱动,找遍所有平台,都没有找到ohci-s5p.c源码。很遗憾,3.8的内核没有提供S5PV210的USBHOST控制器驱动程序。最好验证有没有提供的办法就是,烧写网蜂提供的第二版的uImage进去,然后找个U盘、或者鼠标插入Webee210开发板的USBHOST接口,看看串口有没有打印什么信息,结果是不会有任何反应的。既然没有提供,这就需要我们自己来编写了,这下不好办了吧?不用紧张,仔细再找找,还是能发现一些类似的源码,可供我们移植的。我们发现,内核虽然没有提供ohci-s5p.c源码,但是有提供ehci-s5p.c源码,还有ohci相关的其他平台的源码,比如ohci-s3c2410.c、ohci-exynos.c供我们移植参考。2.1.1ohci-s5p.c程序内核既然没有ohci-s5p.c,那我们使用其他平台的ohci源码,这里我们拷贝driversusbhost目录下的ohci-exynos.c为ohci-s5p.c。然后将所有exynos字符串替换成s5p,由于有些地方是exynos4,所以还需要将s5p4替换为s5p。最后还需要修改一下头文件,将#includelinux/platform_data/usb-exynos.h改为:#includelinux/platform_data/usb-ohci-s5p.h2.2usb-ohci-s5p.h程序打开内核目录includelinuxplatform_data,然后拷贝usb-exynos.h为usb-ohci-s5p.h。将所有的exynos4字符串替换为s5p,将EXYNOS替换为S5P。最后添加平台数据:staticstructs5p_ohci_platdatas5p_ohci_platdata;为了以后支持EHCI还添加echi的平台数据,最后usb-ohci-s5p.h修改为:#ifndef__MACH_S5P_OHCI_H#define__MACH_S5P_OHCI_H/**************AddbyWebee*******************/#ifdefCONFIG_S5P_DEV_USB_EHCIstaticstructs5p_ehci_platdatas5p_ehci_platdata;#endifstaticstructs5p_ohci_platdatas5p_ohci_platdata;/**************AddbyWebee*******************/structs5p_ohci_platdata{int(*phy_init)(structplatform_device*pdev,inttype);int(*phy_exit)(structplatform_device*pdev,inttype);};externvoids5p_ohci_set_platdata(structs5p_ohci_platdata*pd);#endif/*__MACH_S5P_OHCI_H*/2.3添加s5p_ohci_driver到ohci_hcd.c打开driversusbhostohci-hcd.c,在CONFIG_USB_OHCI_EXYNOS前面添加如下代码:#ifdefCONFIG_USB_OHCI_S5P#includeohci-s5p.c#definePLATFORM_DRIVERs5p_ohci_driver#endif因为S5PV210USBHOST控制器驱动由driversusbhostohci-hcd.c(支持各种SoC下的主机控制器驱动的通用部分)和driversusbhostohci-s5p.c共同完成。2.4添加平台设备前面我们移植ohci-s5p.c主要是围绕platform_driver来编程的,这又回到了平台驱动设备模型了。还记得我们移植gpio-key驱动了吗?里面就添加了平台设备来支持平台驱动。今天,我们同样需要添加平台设备来支持s5p_ohci_driver这个平台驱动。怎么添加呢?参考别人怎么写!打开archarmplat-samsungdevs.c,找到s5p_device_ehci这个平台设备,模仿它来修改。打开archarmmach-s5pv210mach-smdkv210.c,在smdkv210_devices[]前,添加如下代码:#includelinux/ioport.h#includelinux/platform_device.h#includelinux/dma-mapping.h#includelinux/platform_data/usb-ehci-s5p.h#includelinux/platform_data/usb-ohci-s5p.h#includelinux/platform_data/usb-ohci-s5p.hstaticstructresources5p_ohci_resource[]={[0]=DEFINE_RES_MEM(0xEC300000,SZ_256),[1]=DEFINE_RES_IRQ(S5P_IRQ_VIC1(23)),};staticu64samsung_device_dma_mask=DMA_BIT_MASK(32);structplatform_devices5p_device_ohci={.name=s5p-ohci,.id=-1,.num_resources=ARRAY_SIZE(s5p_ohci_resource),.resource=s5p_ohci_resource,.dev={.dma_mask=&samsung_device_dma_mask,.coherent_dma_mask=DMA_BIT_MASK(32),}};void__inits5p_ohci_set_platdata(structs5p_ohci_platdata*pd){structs5p_ohci_platdata*npd;npd=s3c_set_platdata(pd,sizeof(structs5p_ohci_platdata),&s5p_device_ohci);if(!npd-phy_init)npd-phy_init=s5p_usb_phy_init;if(!npd-phy_exit)npd-phy_exit=s5p_usb_phy_exit;}怎么确定s5p_ohci_resource里面的内存地址呢?这自然要回到《S5PV210_UM_REV1.1》手册了,在USBHOST这章的寄存器介绍里面有这么一段描述:而IRQ的确定,则是找到下面这段话。/*参考archarmmach-s5pc100includemachirqs.h*/#defineIRQ_UHOSTS5P_IRQ_VIC1(23)然后将定义设置好的s5p_device_ohci添加到smdkv210_devices[],如:staticstructplatform_device*smdkv210_devices[]__initdata={&s5p_device_ohci,/*AddbyWebee*/……&webee210_button_device,/*AddbyWebee*/};最后,在smdkv210_machine_init函数中添加平台数据的设置函数。#ifdefCONFIG_S5P_DEV_USB_OHCIs5p_ohci_set_platdata(&s5p_ohci_platdata);#endif2.5修改Kconfig2.5.1移植driversusbhost目录下的Kconfig打开driversusbhost目录下的Kconfig,在USB_OHCI_EXYNOS前面添加USB_OHCI_S5P的配置支持。修改后如下:#AddbyWebeeconfigUSB_OHCI_S5PbooleanOHCIsupportforSamsungS5PSoCSeriesdependsonUSB_OHCI_HCD&&PLAT_S5PselectS5P_DEV_USB_OHCIhelpEnablesupportfortheSamsungS5PSOC'son-chipOHCIcontroller.#AddbyWebee2.5.2移植archarmplat-samsung目录下的Kconfig打开archarmplat-samsung目录下的Kconfig,在S5P_DEV_USB_EHCI后面添加S5P_DEV_USB_OHCI的配置支持,修改后如下:#AddbyWebeeconfigS5P_DEV_USB_OHCIboolhelpCompileinplatformdevicedefinitionforUSBOHCI#AddbyWebee2.5.3移植driversusb目录下的Kconfig在内核目录下输入makemenuconfig配置内核时,搜索S5P_DEV_USB_OHCI发现如下现象,它表明S5P_DEV_USB_OHCI的配置需要先将PLAT_S5P配置上。搜索:先按‘/’打开driversusb目录下的Kconfig,在USB_ARCH_HAS_OHCI模块下添加如下内容:defaultyifPLAT_S5P2.6创建setup-usb-phy.c文件在archarmmach-s5pv210目录下创建setup-usb-phy.c文件,为什么要创建这么一个文件呢?还记得前面在smdkv210_machine_init()函数里添加过s5p_ohci_set_platdata(&s5p_ohci_platdata);这个函数吗?其中就会去设置s5p_ohci_platdata里的phy_init、phy_exit这两个成员函数。那么就需要实现,s5p_usb_phy_init函数和s5p_usb_phy_exit函数。最后将setup-usb-phy.