2440 Gadget移植手册
1. Gadget可以将开发板上的存储设备作为U盘挂载到Windows下,该技术主要用于MP3等带有存储文件功能的电子产品和U盘等。
2. 2.6.22之前的版本默认没有s3c2410_udc的驱动文件(笔者自己的内核代码里没有,而使用较新的内核版本里2.6.32.2带有),所以对于2.6.22需要将找到对应的udc驱动文件。如下操作:
l 将s3c2410的UDC驱动s3c2410_udc.c s3c2410_udc.h放到source根目录下driver/usb/gadget/下
l 修改对应的gadget Kconfig文件和Makefile文件:
在Kconfig增加下面内核选项,使其出现在Menuconfig选项内:
config USB_GADGET_S3C2410
boolean "S3C2410 USB Device Controller"
depends on ARCH_S3C2410
help
Michael Tang add for s3c2440 processor.
config USB_S3C2410
tristate
depends on USB_GADGET_S3C2410
default USB_GADGET
select USB_GADGET_SELECTED
config USB_S3C2410_DEBUG
boolean "S3C2410 udc debug messages"
depends on USB_GADGET_S3C2410
l 修改Makefile文件,使其可以编译进内核:
增加:
obj-$(CONFIG_USB_S3C2410) += s3c2410_udc.o
3. 将udc驱动编译进内核:
Device Drivers -à
<*> USB Gadget Support --->
USB Peripheral Controller (S3C2410 USB Device Controller) --->
S3C2410 USB Device Controller
<M> USB Gadget Drivers
<M> File-backed Storage Gadget
由于linux2.6.32将平台相关代码的目录结构进行了调整,所以如果是2.6.22的内核应该将上述头文件改为:
删除下面的头文件引用:
#include <linux/gpio.h>
#include <linux/usb/gadget.h>
#include <mach/irqs.h>
#include <mach/hardware.h>
#include <plat/regs-udc.h>
#include <plat/udc.h>
在893行,删除头文件
#include <mach/regs-irq.h>
增加下面头文件引用:
#include <linux/usb_gadget.h>
#include <asm/arch-s3c2410/regs-udc.h>
#include <asm/arch/regs-gpio.h>
#include <asm/arch-s3c2410/gpio.h>
#include <asm/arch/regs-clock.h>
#include <asm/arch-s3c2410/udc.h>
#include <asm/delay.h>
#include <asm/arch-s3c2410/regs-irq.h>
如果上述头文件找不到,去smdk2410相关目录里去找(find命令),然后cp到arch/arm/mach-s3c2440/中。
4. 修改arch/arm/mach-s3c2440/mach-smdk2440.c文件,增加开发板相关的代码,修改该文件使之可以在系统启动时被加载。
增加下面的头文件
#include <mach/regs-gpio.h>
#include <mach/regs-clock.h>
#include <mach/gpio-fns.h>
#include <plat/udc.h>
#include <asm/delay.h>
5. 增加下面代码用于UDC使能操作,加粗部分要根据自己的开发板的使能引脚进行设置。
static void smdk2410_udc_pullup(enum s3c2410_udc_cmd_e cmd)
{
u8 *s3c2410_pullup_info[] = {
" ",
"Pull-up enable",
"Pull-up disable",
"UDC reset, in case of"
};
printk("smdk2410_udc: %s\n",s3c2410_pullup_info[cmd]);
s3c2410_gpio_cfgpin(S3C2410_GPG(12), (1<<24));
switch (cmd)
{
case S3C2410_UDC_P_ENABLE :
s3c2410_gpio_setpin(S3C2410_GPG(12), 1); //set gpg9 output HIGH
break;
case S3C2410_UDC_P_DISABLE :
s3c2410_gpio_setpin(S3C2410_GPG(12), 0); //set gpg9 output LOW
break;
case S3C2410_UDC_P_RESET :
//FIXME!!!
break;
default:
break;
}
}
static struct s3c2410_udc_mach_info smdk2410_udc_cfg __initdata = {
.udc_command = smdk2410_udc_pullup,
};
在开发板初始化函数smdk2440_machine_init内增加下面代码
// 增加下面的宏
#define S3C2410_PLLCON_MDIVSHIFT 12
#define S3C2410_PLLCON_PDIVSHIFT 4
#define S3C2410_PLLCON_SDIVSHIFT 0
static void __init smdk2440_machine_init(void)
{
s3c24xx_fb_set_platdata(&smdk2440_fb_info);
s3c_i2c0_set_platdata(NULL);
/* Michael Tang add start */
s3c24xx_udc_set_platdata(&smdk2410_udc_cfg); /* 初始化*/
printk("=====MT===== Run to here [smdk2440_machine_init]");
s3c2410_modify_misccr(S3C2410_MISCCR_USBHOST |
S3C2410_MISCCR_USBSUSPND0 |
S3C2410_MISCCR_USBSUSPND1, 0x0);
/* 设置USB时钟 */
u32 upll_value = (
0x78 << S3C2410_PLLCON_MDIVSHIFT)
| (0x02 << S3C2410_PLLCON_PDIVSHIFT)
| (0x03 << S3C2410_PLLCON_SDIVSHIFT);
while (upll_value != readl(S3C2410_UPLLCON)) {
writel(upll_value, S3C2410_UPLLCON);
udelay(20);
}
/* Michael Tang add end */
platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices));
….
在平台设备注册结构体数组里加入usbgadget的平台设备注册结构体
static struct platform_device *smdk2440_devices[] __initdata = {
&s3c_device_usb,
&s3c_device_lcd,
&s3c_device_wdt,
&s3c_device_i2c0,
&s3c_device_iis,
// Michael Tang add
&s3c_device_usbgadget,
// Michael Tang add
};
6. 在source根目录下执行make uImage,会生成对应的映像文件,不过,UDC驱动的文件传输需要使用到file_storge.c驱动,不过该驱动文件有点问题,如果不修改,传输速度很慢,在传输过程还还会不停的重启gadget,修改如下:
修改drivers/usb/gadget/file_storage.c
在static int fsg_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)函数中
删除: fsg->ep0req->zero = rc < w_length;
增加: fsg->ep0req->zero = rc < w_length \
&& (rc % gadget->ep0->maxpacket) == 0;
修改drivers/usb/gadget/s3c2410_udc.c
在static void s3c2410_udc_handle_ep(struct s3c2410_ep *ep)函数中
struct s3c2410_request *req;
int is_in = ep->bEndpointAddress & USB_DIR_IN;
u32 ep_csr1;
u32 idx;
增加: handle_ep_again:
……
if ((ep_csr1 & S3C2410_UDC_OCSR1_PKTRDY) && req) {
s3c2410_udc_read_fifo(ep,req);
增加: if (s3c2410_udc_fifo_count_out())
goto handle_ep_again;
}
7. 执行make modules,生成g_file_storage.ko,将内核烧入后,执行:
insmod g_file_storage.ko file=/dev/mtdblock2 stall=0 removable=1
插入usb device接口,然后在windows下可以被识别了,执行文件写入和读出速度都还可以。
附件:修正文件传输速度慢的patch代码:
1----------------------------------------------------------------------------------
--- a/drivers/usb/gadget/file_storage.c 2008-09-01 11:13:03.000000000 -0400
+++ b/drivers/usb/gadget/file_storage.c 2008-09-01 11:16:41.000000000 -0400
@@ -1463,7 +1463,8 @@
if (rc >= 0 && rc != DELAYED_STATUS) {
rc = min(rc, w_length);
fsg->ep0req->length = rc;
- fsg->ep0req->zero = rc < w_length;
+ fsg->ep0req->zero = rc < w_length
+ && (rc % gadget->ep0->maxpacket) == 0;
fsg->ep0req_name = (ctrl->bRequestType & USB_DIR_IN ?
"ep0-in" : "ep0-out");
rc = ep0_queue(fsg);
2------------------------------------------------------------------------
Index: linux-2.6.28.8/drivers/usb/gadget/s3c2410_udc.c
===================================================================
--- linux-2.6.28.8.orig/drivers/usb/gadget/s3c2410_udc.c 2009-03-17 21:14:28.000000000 +0100
+++ linux-2.6.28.8/drivers/usb/gadget/s3c2410_udc.c 2009-03-17 21:14:46.000000000 +0100
@@ -843,6 +843,7 @@
u32 ep_csr1;
u32 idx;
+handle_ep_again:
if (likely (!list_empty(&ep->queue)))
req = list_entry(ep->queue.next,
struct s3c2410_request, queue);
@@ -882,6 +883,8 @@
if ((ep_csr1 & S3C2410_UDC_OCSR1_PKTRDY) && req) {
s3c2410_udc_read_fifo(ep,req);
+ if (s3c2410_udc_fifo_count_out())
+ goto handle_ep_again;
}
}
}
文章评论(0条评论)
登录后参与讨论