免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2226 | 回复: 0
打印 上一主题 下一主题

linux2.6内核USB2.0驱动移植(ISP1160/01) [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-11-30 20:38 |只看该作者 |倒序浏览

USB2.0驱动移植
开发环境:
硬件:UP-NETARM2410-S嵌入式实验平台
软件:PC机操作系统REDHAT LINUX 9.0+MINICOM+ARMV4L-UNKNOWN-LI
NUX开发环境
编译器版本:arm-linux-gcc 3.4.6
内核版本:linux 2.6.18
采用的是usb2.0 主控制芯片为ISP1160/01
一、加载驱动支持:
在linux2.6.12以上的版本 已经加入了ISP116X芯片的支持我们可以在kernel的menuconfig中添加该驱动:

这里我为了方便调试采用的 是模块加载的方式.用户可根据自己的实际需要来进行设置!
二、驱动特点
下面介绍该驱动都支持那些功能:
       该驱动经过了一系列的软硬件测试支持USB 闪存、鼠标、键盘、网卡等设备;
       支持挂起续传等操作,支持唤醒功能(例如:移动鼠标等)
       经过大小端模式设置
       可编程I/O寻址模式(不支持DMA模式)
       不支持同步传输模式,例如:USB的视频、音频设备就不支持,还在对此驱动做改进!

三、注册platform 设备驱动

1、进入arch/arm/mach-s3c2410/mach-smdk2410.c文件中注册该设备:
添加如下内容:
/* I use bank 3 and EINT0 for isp116x */
#define USB_IO_PHYS 0x18000000
/* Platform delay */
static void isp116x_pfm_delay(struct device *dev, int delay)
{
/* On this platform, we work with 200MHz clock, giving
5 ns per instruction. The cycle below involves 2
instructions and we lose 2 more instruction times due
to pipeline flush at jump. I.e., we consume 20 ns
per cycle.
*/
int cyc = delay / 20;
__asm__ volatile ("0:\n"
"     subs  %0, %1, #1\n"
"     bge   0b\n"
:"=r" (cyc)
:"0"(cyc)
);
}
/* Define chip configuration */
static struct isp116x_platform_data isp116x_pfm_data = {
.sel15Kres = 1,
.remote_wakeup_enable = 1,
.no_power_switching = 1,
// .reset = isp116x_pfm_reset,
.delay = isp116x_pfm_delay,
};
/* Define chip address and IRQ line */
static struct resource isp116x_pfm_resources[] = {
[0] = {   /// data (A0 = 0)
  .start = USB_IO_PHYS,
  .end = USB_IO_PHYS + 1,
  .flags = IORESOURCE_MEM,
},
[1] = {   /// addr (A0 = 1)
  .start = USB_IO_PHYS + 2,
  .end = USB_IO_PHYS + 3,
  .flags = IORESOURCE_MEM,
},
[2] = {
  .start = IRQ_EINT0,
  .end = IRQ_EINT0,
  .flags = IORESOURCE_IRQ,
},
};
static struct platform_device isp116x_pfm_usbhost_device = {
.name = "isp116x-hcd",
.num_resources = ARRAY_SIZE(isp116x_pfm_resources),
.resource = isp116x_pfm_resources,
.dev.platform_data = &isp116x_pfm_data,
};
//add end
2、然后在结构体中添加:&s3c_device_export_usb
////////////////////////////////////////////////////
static struct platform_device *smdk2410_devices[] __initdata = {
    ...
    ...
    &s3c_device_export_usb, //add by lyj 20070911
};

3、这里要说明几点:
1)、我是用的是s3c2410的bank3地址空间,在isp116x_pfm_resources【】结构体中注册时使用的是实际的物理地址;
2)、注册该设备时,首先要定义可用于访问的寄存器地址.中断号等资源(resource)。然后将这些资源(resource) 作为 platform 的dev .通过platform_add_devices函数将你定义的paltform_device变量注册到系统的dev里面.。或者你可以象我这样将你需要的驱动添加:
static struct platform_device *smdk2410_devices[] __initdata = {
    ...    ...
    &s3c_device_export_usb, //add by lyj 20070911
};
3)、这里有条关键的语句:
.name = "isp116x-hcd",
它和驱动程序中的&s3c_device_sdi,里的device的name是一致的(drivers/usb/host/isp116x-hcd.c)
static struct platform_driver isp116x_driver = {
        .probe = isp116x_probe,
        .remove = isp116x_remove,
        .suspend = isp116x_suspend,
        .resume = isp116x_resume,
        .driver = {
                   .name = "isp116x-hcd",
                   },
};

4)、我们继续讨论该驱动是如何加载的:
在驱动isp116x-hcd.c中:
static int __init isp116x_init(void)
{
        if (usb_disabled())
                return -ENODEV;

        INFO("driver %s, %s\n", hcd_name, DRIVER_VERSION);
        return platform_driver_register(&isp116x_driver);
}
用platform_driver_register向系统注册这个驱动程序.而这个函数会在isp116x_driver的信息里提取name为搜索内容,搜索系统注册的device中有没有这个platform_device。 如果有注册,那么接着会执行platform_driver 里probe函数.即isp116x_probe函数 。
在probe函数里,用的最多和刚才platform_device有关的语句就是platform_get_resource,这条语句用于获取platform_device里的resource资料.例如映射的IO地址,中断等。

四、加载驱动并调试
加载之后重新编译内核,并编译模块isp116x-hcd.ko,成功之后重新烧写内核并下载驱动
加载驱动后提示信息如下:
[/mnt/yaffs/usb2.0]insmod isp116x-hcd.ko
Using isp116x-hcd.ko
116x: driver isp116x-hcd, 03 Nov 2005
isp116x-hcd isp116x-hcd: ISP116x Host Controller
isp116x-hcd isp116x-hcd: new USB bus registered, assigned bus number 2
isp116x-hcd isp116x-hcd: irq 16, io base 0x18000002
usb usb2: Product: ISP116x Host Controller
usb usb2: Manufacturer: Linux 2.6.18 isp116x-hcd
usb usb2: SerialNumber: isp116x-hcd
usb usb2: configuration #1 chosen from 1 choice
hub 2-0:1.0: USB hub found
hub 2-0:1.0: 2 ports detected
插上USB摄像提示信息:
[/mnt/yaffs/usb2.0]usb 2-2: new full speed USB device using isp116x-hcd and address 2
usb 2-2: Product: PC Camera
usb 2-2: Manufacturer: Vimicro Corp.
usb 2-2: configuration #1 chosen from 1 choice

经过USB2.0存储盘测试,读写速度明显要快!

不过该驱动有几个问题需要大家明白:
1、不支持ISO(同步传输),如果您的需求要求支持ISO那么你需要改写驱动,加入ISO功能支持,或者使用isp176x芯片,目前该芯片的驱动支持ISO功能。
2、这里摘录了原文:
Known bugs
Kernel 2.6.13 - There is a one, related to power switching of ports. Apply the following
patch
to fix it. Also, this patch converts the driver to a new platform code interface, reducing the amount of the platform support code needed for the driver. If you'll use the unpatched driver from 2.6.13 then see a
separate page
about setting up its platform support code.
该驱动有一个关于电源管理的漏洞,可以通过下载补丁来解决:
http://www.artecdesign.ee/~ok/isp116x/isp116x-fix-2.6.13.patch.bz2


参考文档:
http://www.artecdesign.ee/~ok/isp116x/
http://www.mail-archive.com/linux-usb-devel@lists.sourceforge.net/msg44127.html
http://www.artecdesign.ee/~ok/isp116x/isp116x-pre-2.6.13.html
http://www.linux-usb.org/FAQ.html#ts6
附录:
关于platform_device相关问题:
首先你需要为SOC的各个功能部分定义他的一些资源.例如可用于访问的寄存器地址.中断号,DMA什么的。然后将这些资源(resource) 作为 platform 的dev .通过platform_add_devices函数将你定义的paltform_device变量注册到系统的dev里面.。或者你可以象我这样将你需要的驱动添加:
static struct platform_device *smdk2410_devices[] __initdata = {
&s3c_device_usb,
&s3c_device_lcd,
&s3c_device_bl,
&s3c_device_wdt,
&s3c_device_i2c,
&s3c_device_iis,
&s3c_device_sdi,
&s3c_device_adc,
&s3c_device_nand,
&s3c_device_usbgadget,
&s3c_device_ts,
&s3c_device_buttons,
&s3c_device_rtc,
&s3c_device_spi0,
&s3c_device_timer1,//add by cefanty for battery charging
};
这样你的硬件的信息和资源就会注册到系统中.
说了半天,这回该说这有什么用了。
你编写的驱动或者移植别人的驱动,一般在驱动里有这样的代码,例如:
static struct platform_driver s3c2410sdi_driver =
{
.probe          = s3c2410sdi_probe,
.remove         = s3c2410sdi_remove,
.suspend= s3c2410mci_suspend,
.resume= s3c2410mci_resume,
.driver={
.name= "s3c2410-sdi",
.bus    = &platform_bus_type,
.owner= THIS_MODULE,
},
};
看到 .name= "s3c2410-sdi",这条关键的语句没有??,它和我在上面注册的&s3c_device_sdi,里的device的名称是一致的.我这里展开我的s3c_device_sdi,的内容
:
/* SDI */
static struct resource s3c_sdi_resource[] = {
[0] = {
.start = S3C2410_PA_SDI,
.end   = S3C2410_PA_SDI + S3C24XX_SZ_SDI - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_SDI,
.end   = IRQ_SDI,
.flags = IORESOURCE_IRQ,
},
[2] = {
.start = 3,
.end  = 3,
.flags = IORESOURCE_DMA,
}
};
struct platform_device s3c_device_sdi = {
.name  = "s3c2410-sdi",
.id  = -1,
.num_resources  = ARRAY_SIZE(s3c_sdi_resource),
.resource  = s3c_sdi_resource,
};
在驱动程序里的init代码大致如下:
static int __init s3c2410sdi_init(void)
{
return platform_driver_register(&s3c2410sdi_driver);
}
用platform_driver_register向系统注册这个驱动程序.而这个函数会在s3c2410sdi_driver的信息里提取name为搜索内容,搜索系统注册的device中有没有这个platform_device。 如果有注册,那么接着会执行platform_driver 里probe函数.在这里显然是s3c2410sdi_probe函数  在probe函数里,用的最多和刚才platform_device有关的语句是platform_get_resource,这条语句用于获取platform_device里的resource资料.例如映射的IO地址,中断等.剩下等得就是ioremap,和 request_irq等的事情了


本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u2/65122/showart_1673207.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP