分类: LINUX
2013-03-23 11:45:34
原文地址:2440 USB Gadget 存储设备的调试(解决写问题) 作者:三点水兽
众所周知,USB Gadget 的源代码,在 内核目录 driver->usb->gadget 目录下,gadget 能实现的功能有很多,可以让嵌入式设备,在PC 上实现一个存储磁盘,虚拟成一个网络设备还有, zero 设备,今天,我主要记录一下,自己,在调试SD 卡过程,碰到的问题,哎,发现,自己弄这个arm 开发板,一路碰到的都是很经典的问题,先讲一下,自己碰到的问题吧。
linux
,对gadget的支持,已经,有方案了,自己用的是2440,自然,选中内核的选项,就可以把2440 的udc ,编译进内核了,但是,都必须是
模块的形式,编译,才行,找到Device drivers–>USb support –>
[*]File-backed Storage gadget testing version , 直接编译
sudo make ,这样它就会把模块也编译出来。
插入相应的模块
insmod /etc/modules/s3c2410_udc.ko
insmod /etc/modules/g_file_storage.ko file=/dev/sdcard stall=0 removable=1
这里的驱动,涉及的文件是s3c2410_udc.c 和 file_storage.c
接上USB 线以后,就可以,识别成存储器,但是 这样的做法,只能,拷贝小文件,大文件往往会出各种问题,
别想了,问题没出在file_storage.c,这是Linux内核社区写的 ,肯定是棒子给的文件有问题,
自己的不是大牛,这两文件的分析,就算了,主要,还是讲一下,自己无所不能的搜索技术,google ,找答案,
嘿嘿,自己的问题,网上的哥们分析,还真不少,但大部分,都是,讲协议的,什么协议? 这个都是内核里写好的
看大牛的分析,还不如拿着RFC,看源代码,总的来说是不管的事。 突然google 发力,追踪到了这里 ,
网上牛人真多啊, 这种微妙的东西都能发现,他妈的是吃什么长大的,总之一个字,就是牛。
以防链接消失,我把关键复制下来,
tengel,我是这样加的again:
static int s3c2410_udc_read_fifo(struct s3c2410_ep *ep, struct s3c2410_request *req) {
u8 *buf;
u32 ep_csr;
unsigned bufferspace;
int is_last = 1;
unsigned avail;
int fifo_count = 0;
u32 idx;
int fifo_reg;
int again_num = 0;
struct timeval time;
idx = ep->bEndpointAddress & 0x7F;
switch (idx) {
default:
idx = 0;
case 0:
fifo_reg = S3C2410_UDC_EP0_FIFO_REG;
break;
case 1:
fifo_reg = S3C2410_UDC_EP1_FIFO_REG;
break;
case 2:
fifo_reg = S3C2410_UDC_EP2_FIFO_REG;
break;
case 3:
fifo_reg = S3C2410_UDC_EP3_FIFO_REG;
break;
case 4:
fifo_reg = S3C2410_UDC_EP4_FIFO_REG;
break;
}
if (!req->req.length) {
return 1;
}
do_gettimeofday(&time);
if(( time.tv_sec – o_tick ) >= 10){
dprintk(DEBUG_WATCH, “last data, actual:%d, length:%d, count:%d\n”, o_actual, o_length, o_x_count);
}
o_tick = time.tv_sec;
again:
buf = req->req.buf + req->req.actual;
bufferspace = req->req.length – req->req.actual;
if (!bufferspace) {
dprintk(DEBUG_WATCH/*DEBUG_NORMAL*/, “%s: buffer full!\n”, __func__);
return -1;
}
udc_write(idx, S3C2410_UDC_INDEX_REG);
fifo_count = s3c2410_udc_fifo_count_out();
//dprintk(DEBUG_WATCH/*DEBUG_VERBOSE*/, “%s fifo count : %d\n”, __func__, fifo_count);
if (fifo_count > ep->ep.maxpacket) {
avail = ep->ep.maxpacket;
}
else {
avail = fifo_count;
}
fifo_count = s3c2410_udc_read_packet(fifo_reg, buf, req, avail);
// checking this with ep0 is not accurate as we already read a control request
if (idx != 0 && fifo_count < ep->ep.maxpacket) {
is_last = 1;
// overflowed this request? flush extra data
if (fifo_count != avail) {
req->req.status = -EOVERFLOW;
}
}
else {
is_last = (req->req.length <= req->req.actual) ? 1 : 0;
}
udc_write(idx, S3C2410_UDC_INDEX_REG);
fifo_count = s3c2410_udc_fifo_count_out();
// Only ep0 debug messages are interesting
if (idx == 0) {
dprintk(DEBUG_WATCH/*DEBUG_VERBOSE*/, “%s fifo count : %d [last %d]\n”, __func__, fifo_count,is_last);
}
if (is_last) {
if (idx == 0) {
s3c2410_udc_set_ep0_de_out(base_addr);
ep->dev->ep0state = EP0_IDLE;
}
else {
udc_write(idx, S3C2410_UDC_INDEX_REG);
ep_csr = udc_read(S3C2410_UDC_OUT_CSR1_REG);
udc_write(idx, S3C2410_UDC_INDEX_REG);
udc_write(ep_csr & ~S3C2410_UDC_OCSR1_PKTRDY, S3C2410_UDC_OUT_CSR1_REG);
s3c2410_udc_done(ep, req, 0);
}
}
else {
if (idx == 0) {
s3c2410_udc_clear_ep0_opr(base_addr);
}
else {
udc_write(idx, S3C2410_UDC_INDEX_REG);
ep_csr = udc_read(S3C2410_UDC_OUT_CSR1_REG);
udc_write(idx, S3C2410_UDC_INDEX_REG);
udc_write(ep_csr & ~S3C2410_UDC_OCSR1_PKTRDY, S3C2410_UDC_OUT_CSR1_REG);
}
}
}
/**/
//udc_write(idx, S3C2410_UDC_INDEX_REG);
fifo_count = s3c2410_udc_fifo_count_out();
if( (( EP_FIFO_SIZE == fifo_count) || ((req->req.length – req->req.actual) == fifo_count) )
&& (!is_last)
){
dprintk(DEBUG_NORMAL, “goto again”);
goto again;
}
return is_last;
}
分析这位仁兄的做法,对照,内核代码,发现,这哥们就是,把数据多读了几遍,哎,在这,我又得概叹几句了,
“为什么国人这么聪明,还得用棒子设计的CPU呢?”,真想不通。
瞬间,改过以后,就好使多了。
转载: