Linux USB Gadget --mini2440使用与测试
2012-04-15 20:12
423 查看
USB Gadget驱动又称USB器件驱动。主要用于运行linux的嵌入式系统中,使得系统拥有普通USB设备的功能。mini2440具有USB1.1设备控制器,所以可以使用USB Gadget功能。但是linux2.6.32.2内核对于mini2440的支持不是很完全。开启USB Gadget功能之后,不能使得主机发现USB硬件。这个问题主要是USB接口的上拉电阻的问题,mini2440使用GPC5来上拉USB,使得主机集线器发现有USB设备链接从而枚举设备。但是在linux2.6.32.2内核中,没有设置GPC5的代码。所以导致不能使用Gadget功能。解决办法网上也有一些,就是增加额外的模块置位GPC5,但是我认为这样不是最好的办法。认真分析s3c2410_udc.c以及g_zero.c的代码后,发现在注册Gadget功能驱动的时候会调用s3c2410_udc.c提供的usb_gadget_register_driver函数,而这个函数最后会调用s3c2410_udc_enable。这个函数就是使能UDC的。代码如下:
我们发现这个函数除了前面使能中断的操作后,最后有个判断语句,判断udc_info以及udc_info->command是否有值。然后调用udc_command,这个函数的调用参数为S3C2410_UDC_P_ENABLE。很显然这个就是使能UDC的关键操作。我们看一下udc_info又是什么,在s3c2410_udc.c的最开始有这样的定义:
那么这个指针又是什么时候赋值的,是在s3c2410_udc_probe函数中。这就说明在注册s3c2410_udc驱动的时候,由platform总线找到相应的设备匹配后,调用的。如下:
device在系统板级初始化的时候初始化的。也就是板级初始化的时候赋值。但是用Kscope怎么也找不到给他赋值的语句。说明根本就没人给他赋值。所以在注册g_zero功能驱动的时候udc_info是空的,没有执行udc_info->udc_command()。我们要做的就是给usb gadget platform device的platform_data初始化。在mach-mini2440.c中增加如下代码:
这个结构体定义了platform_data的初始值。
修改mini2440_machine_init函数,增加s3c24xx_udc_set_platdata(&s3c2410_udc_cfg);如下
从注释上可以看出调用composite_unbind的前提是要首先保证composite_disconnect被调用。这样才不会出现警告的内核信息。在增加上面的代码后重新编译内核,将USB Gadget设置称为模块。然后make modules 在通过ftp将s3c2410_udc.ko与g_zero.ko传入开发板,先后加载这两个模块。在主机上lsusb会发现出现新设备
Bus 005 Device 023: ID 0525:a4a0 Netchip Technology, Inc. Linux-USB "Gadget Zero"
卸载g_zero.ko后,新设备就会消失。这样基本的USB Gadget驱动功能就开启了。类似的还可以测试其他的USB Gagget。
static void s3c2410_udc_enable(struct s3c2410_udc *dev) { int i; dprintk(DEBUG_NORMAL, "s3c2410_udc_enable called\n"); /* dev->gadget.speed = USB_SPEED_UNKNOWN; */ dev->gadget.speed = USB_SPEED_FULL; /* Set MAXP for all endpoints */ for (i = 0; i < S3C2410_ENDPOINTS; i++) { udc_write(i, S3C2410_UDC_INDEX_REG); udc_write((dev->ep[i].ep.maxpacket & 0x7ff) >> 3, S3C2410_UDC_MAXP_REG); } /* Set default power state */ udc_write(DEFAULT_POWER_STATE, S3C2410_UDC_PWR_REG); /* Enable reset and suspend interrupt interrupts */ udc_write(S3C2410_UDC_USBINT_RESET | S3C2410_UDC_USBINT_SUSPEND, S3C2410_UDC_USB_INT_EN_REG); /* Enable ep0 interrupt */ udc_write(S3C2410_UDC_INT_EP0, S3C2410_UDC_EP_INT_EN_REG); /* time to say "hello, world" */ if (udc_info && udc_info->udc_command) { udc_info->udc_command(S3C2410_UDC_P_ENABLE); } }
我们发现这个函数除了前面使能中断的操作后,最后有个判断语句,判断udc_info以及udc_info->command是否有值。然后调用udc_command,这个函数的调用参数为S3C2410_UDC_P_ENABLE。很显然这个就是使能UDC的关键操作。我们看一下udc_info又是什么,在s3c2410_udc.c的最开始有这样的定义:
static struct s3c2410_udc_mach_info *udc_info;说明这是一个指向s3c2410_udc_mach_info结构的指针。s3c2410_udc_mach_info结构在udc.h中定义:
struct s3c2410_udc_mach_info { void (*udc_command)(enum s3c2410_udc_cmd_e); void (*vbus_draw)(unsigned int ma); unsigned int vbus_pin; unsigned char vbus_pin_inverted; };
那么这个指针又是什么时候赋值的,是在s3c2410_udc_probe函数中。这就说明在注册s3c2410_udc驱动的时候,由platform总线找到相应的设备匹配后,调用的。如下:
udc_info = pdev->dev.platform_data;那么什么又是platfom_data呢,这个又是在什么时候赋值的呢。要理解这个还得需要平台驱动的只是,也就是platform driver的知识。s3c2410的udc驱动是一个platform驱动,所以USB设备控制器是platform device。那么这个platform_data又是在哪赋的值。一般而言platform
device在系统板级初始化的时候初始化的。也就是板级初始化的时候赋值。但是用Kscope怎么也找不到给他赋值的语句。说明根本就没人给他赋值。所以在注册g_zero功能驱动的时候udc_info是空的,没有执行udc_info->udc_command()。我们要做的就是给usb gadget platform device的platform_data初始化。在mach-mini2440.c中增加如下代码:
static void s3c2410_udc_pullup(enum s3c2410_udc_cmd_e cmd) { switch (cmd) { case S3C2410_UDC_P_ENABLE : s3c2410_gpio_cfgpin(S3C2410_GPC(5), S3C2410_GPIO_OUTPUT); //参考评论增加的代码 s3c2410_gpio_setpin(S3C2410_GPC(5), 1); break; case S3C2410_UDC_P_DISABLE : s3c2410_gpio_setpin(S3C2410_GPC(5), 0); break; case S3C2410_UDC_P_RESET : break; default: break; } }这个函数就是udc_info->udc_command()执行的函数,在这里使得GPC5为高电平,使能USB设备。
static struct s3c2410_udc_mach_info s3c2410_udc_cfg __initdata = { .udc_command = s3c2410_udc_pullup, };
这个结构体定义了platform_data的初始值。
修改mini2440_machine_init函数,增加s3c24xx_udc_set_platdata(&s3c2410_udc_cfg);如下
static void __init mini2440_machine_init(void) { #if defined (LCD_WIDTH) s3c24xx_fb_set_platdata(&mini2440_fb_info); #endif s3c_i2c0_set_platdata(NULL); s3c2410_gpio_cfgpin(S3C2410_GPC(0), S3C2410_GPC0_LEND); s3c_device_nand.dev.platform_data = &friendly_arm_nand_info; s3c_device_sdi.dev.platform_data = &mini2440_mmc_cfg; s3c24xx_udc_set_platdata(&s3c2410_udc_cfg); //增加的代码 platform_add_devices(mini2440_devices, ARRAY_SIZE(mini2440_devices)); s3c_pm_init(); }s3c24xx_udc_set_platdata()这个函数定义与devs.c,如下:
void __init s3c24xx_udc_set_platdata(struct s3c2410_udc_mach_info *pd) { struct s3c2410_udc_mach_info *npd; npd = kmalloc(sizeof(*npd), GFP_KERNEL); if (npd) { memcpy(npd, pd, sizeof(*npd)); s3c_device_usbgadget.dev.platform_data = npd; } else { printk(KERN_ERR "no memory for udc platform data\n"); } }最后还要在头文件中包含plat/udc.h。这样我们注册Gadget功能驱动的时候自动使能了USB设备功能。但是在卸载驱动的时候发生了问题,内核打印出一大堆调试信息。问题出在composite.c中的composite_unbind函数中。这个函数开头有一行代码WARN_ON(cdev->config);就是如果cdev-config不为0,那么内核就会打印出调试信息。上面还给了注释
int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) { struct s3c2410_udc *udc = the_controller; if (!udc) return -ENODEV; if (!driver || driver != udc->driver || !driver->unbind) return -EINVAL; dprintk(DEBUG_NORMAL,"usb_gadget_register_driver() '%s'\n", driver->driver.name); driver->disconnect(&udc->gadget); //此处为新加语句,这条语句调用 composite_disconnect,然后使得cdev->config为NULL driver->unbind(&udc->gadget); //这里就是composite_unbind device_del(&udc->gadget.dev); udc->driver = NULL; /* Disable udc */ s3c2410_udc_disable(udc); return 0; }
从注释上可以看出调用composite_unbind的前提是要首先保证composite_disconnect被调用。这样才不会出现警告的内核信息。在增加上面的代码后重新编译内核,将USB Gadget设置称为模块。然后make modules 在通过ftp将s3c2410_udc.ko与g_zero.ko传入开发板,先后加载这两个模块。在主机上lsusb会发现出现新设备
Bus 005 Device 023: ID 0525:a4a0 Netchip Technology, Inc. Linux-USB "Gadget Zero"
卸载g_zero.ko后,新设备就会消失。这样基本的USB Gadget驱动功能就开启了。类似的还可以测试其他的USB Gagget。
相关文章推荐
- Mini2440 USB gadget --使用与测试
- mini2440 usb device controller 驱动的分析--gadget设备(五)--zero和usb-skeleton测试例
- Linux系统中使用 DD 命令测试 USB 和 SSD 硬盘的读写速度
- Linux下USB从(USB gadget) 驱动配置与使用
- Linux下USB从(USB gadget) 驱动配置与使用
- Linux下USB从(USB gadget) 驱动配置与使用
- mini2440 Linux 下的 USB 工具 DNW使用(2440) [转]
- Linux系统中使用 DD 命令测试 USB 和 SSD 硬盘的读写速度
- Linux-USB Gadget : Part 5: 测试 PXA UDC 驱动
- Linux下USB从(USB gadget) 驱动配置与使用
- Linux系统中使用 DD 命令测试 USB 和 SSD 硬盘的读写速度
- linux-2.6.32在mini2440开发板上移植(11)之配置USB外设
- Linux 使用 egrep 和 cut 去 解析 jmeter的 测试 结果 数据
- [linux][command] linux 中的测试硬盘读写速度的命令: time dd 使用介绍
- Linux普通用户使用libusb访问usb设备的方法
- 测试道路之第四周-Linux基础命令使用
- 使用Linux命令行测试网速
- Linux RT(1)-硬实时Linux(RT-Preempt Patch)在PC上的编译、使用和测试
- linux2.6.32.2 mini2440平台移植-- 配置 USB 外设、SD卡移植
- 使用sipp对FreeSwitch进行测试(Linux环境,会议模式)