modelsim 发表于 2013-2-22 16:36:39

悬赏千元人民币,找linux下USB驱动的一个Bug

本帖最后由 modelsim 于 2013-2-22 16:49 编辑

公司之前开发的一款基于2440的手持设备,要求通过USB连线PC机能读到设备版本号,并要能向手持linux设备的某个指定目录(驱动中定死的目录)中传输文件,现基本功能已完成,发现向手持设备中写入文件时有时会发生数据丢失的情况,进而引起内核发生崩溃的情况。请求大侠帮组寻找bug,如能解决,赏金千元人民币。如果您已经开发过这种驱动,功能满足要求,我也可以千元购买您的驱动源码!有兴趣的可联系我,我把源码发给您帮助寻找bug,邮箱modelsim_tyc@163.com注意t前有下划线,QQ791563787,联系时请注明“关于驱动”。
内核版本linux-2.6.29.4
目前采用USB gadget zero 设备驱动方式

cloudborn123 发表于 2013-2-22 23:49:16

有意思!底层驱动难调!

bbstr 发表于 2013-2-24 18:34:04

哪里难调?用心搞必能出成果

wye11083 发表于 2013-2-24 19:07:04

建议LZ先把2440的主频降下来,再测试。看上去像是文件系统驱动出问题了,写文件失败,然后挂掉。

modelsim 发表于 2013-2-25 12:21:29

wye11083 发表于 2013-2-24 19:07 static/image/common/back.gif
建议LZ先把2440的主频降下来,再测试。看上去像是文件系统驱动出问题了,写文件失败,然后挂掉。 ...

您好,我觉得应该不是主频的问题,我把2440板上的SD卡作为U盘,通过复制直接可以传入,文件不出丝毫问题,速度也比较快
但是我通过公司之前写的g_zero.ko驱动,把带SD卡得2440板作为一个设备,向该SD卡的目录中直接写入文件,不仅慢而且还容易出问题
具体为何不把SD卡当U盘来用是由于特定需求所致。基本可以确定应该是驱动的问题,但我对驱动又不熟,不知道如何去解决这个问题

modelsim 发表于 2013-2-25 12:29:33

bbstr 发表于 2013-2-24 18:34 static/image/common/back.gif
哪里难调?用心搞必能出成果

您有兴趣搞一搞?

wye11083 发表于 2013-2-25 13:07:22

modelsim 发表于 2013-2-25 12:21 static/image/common/back.gif
您好,我觉得应该不是主频的问题,我把2440板上的SD卡作为U盘,通过复制直接可以传入,文件不出丝毫问题 ...

那是你公司里的人写的驱动有问题了。你不用他的驱动不得了,就算当成U盘来用,由于不是真实的U盘,稳定性是有保障的。

winterw 发表于 2013-2-25 13:17:20

是否与写入的文件大小有关?

winterw 发表于 2013-2-25 13:19:18

如果将文件内容不写入sd卡而写入ram也会出现问题吗?

modelsim 发表于 2013-2-25 16:31:22

winterw 发表于 2013-2-25 13:19 static/image/common/back.gif
如果将文件内容不写入sd卡而写入ram也会出现问题吗?

没用进行写入ram测试

modelsim 发表于 2013-2-25 16:32:36

wye11083 发表于 2013-2-25 13:07 static/image/common/back.gif
那是你公司里的人写的驱动有问题了。你不用他的驱动不得了,就算当成U盘来用,由于不是真实的U盘,稳定性 ...

我要是会搞这个驱动就不用在这问了,linux太庞大了,找bug我都不知道从哪下手,项目需要不可以当U盘来用,没办法

wye11083 发表于 2013-2-25 18:05:19

你可以完全复制U盘驱动的框架,然后把读写硬件换成你自己的代码,这样对错误处理就控制得比较到位了。从ioctl_read/write开始入手。具体怎么弄的我也不太清楚,流程大概是驱动载入时把自己的接口指针传给内核,内核生成一张映射表,调用哪个操作,就从映射表里找对应的接口指针,然后跳到接口里运行。如果内核出现错误,则说明驱动程序错误处理没写好。

bbstr 发表于 2013-3-1 09:18:36

提一个建议,驱动框架确实很庞大,但是debug这个bug,和你是否了解这个usb的框架在最初的调试阶段影响不大,你可以加一些log在驱动里,看看正在的时候和出问题的时候,一般是在什么文件里显现出来的,然后再来提问题,便于对usb模块驱动熟悉的人给你提供帮助

modelsim 发表于 2013-3-1 10:18:10

本帖最后由 modelsim 于 2013-3-1 10:30 编辑

bbstr 发表于 2013-3-1 09:18 static/image/common/back.gif
提一个建议,驱动框架确实很庞大,但是debug这个bug,和你是否了解这个usb的框架在最初的调试阶段影响不大 ...

现在bug发生的情况已经找到,当上位机通过驱动向下位机发送的字节数正好是64的倍数的时候bug就出现了,下位机收到的数据为0字节
比如说发送一个1.txt 内容为”1111111111111111111111111111111111111111111111111111111111111111“,64个1,下位机收到的字节数就为0了
如果是63或者65个1,下位机就能正常收到

下面是当上位机发送65个字节时,驱动中打印出的信息
actual = 5
g_filename = 1.txt
actual = 65

下面是当上位机发送64个字节时,驱动中打印出的信息
actual = 5
g_filename = 1.txt
这里少了一句actual = 64

打印信息是在以下代码中完成的
static int check_read_data(struct f_sourcesink *ss, struct usb_request *req)
{
        u8        *buf = req->buf;
        struct usb_rw_dev *usb_rw = the_usb_ops;
/*/
        for (i = 0; i < req->actual; i++, buf++)
                printk("buf[%d] = %c\n",i,buf);
/*/

        printk("actual = %d\n",req->actual);
        if(usb_rw->tranffilename)
        {
                usb_rw->tranffilename = false;
                spin_lock(&usb_rw->lock);
                memcpy(g_usbfilename,buf,req->actual);
                spin_unlock(&usb_rw->lock);
                printk("g_filename = %s\n",g_usbfilename);
                wakeup_thread(usb_rw);
        }
        else if(usb_rw->writefilenum)
        {
                if(usb_hcd == 0)
                {
                        printk("usb ohci_hcd error!\n");
                        return 0;
                }
                spin_lock(&usb_rw->lock);
                memcpy(usb_rw->outf->wbuffer,buf,req->actual);
                usb_rw->outf->wbuffersize = req->actual;
                usb_rw->outf->flag = 1;
                usb_rw->data_from_host_count++;
                spin_unlock(&usb_rw->lock);
                if(usb_rw->data_from_host_count >= max_buffer)
                        usb_rw->data_from_host_count = 0;
        }
        return 0;
}

下面是代码修改部分的一个diff文件

请有经验的坛友们帮我看看,不胜感激

fengyuganyu 发表于 2013-3-1 10:45:35

modelsim 发表于 2013-3-1 10:18 static/image/common/back.gif
现在bug发生的情况已经找到,当上位机通过驱动向下位机发送的字节数正好是64的倍数的时候bug就出现了,下 ...

我觉得是你们 gadt驱动中的 读取数据出问题了,你们在读取数据时的状态错误了

monkerman 发表于 2013-3-1 11:19:14

我觉得是你指针越界操作造成的内核崩溃. 可能是哪个边界没有处理好.

绿茶山人 发表于 2013-3-1 11:20:13

modelsim 发表于 2013-3-1 10:18 static/image/common/back.gif
现在bug发生的情况已经找到,当上位机通过驱动向下位机发送的字节数正好是64的倍数的时候bug就出现了,下 ...

我看了你的diff文件,把605行和616行的w_length > 64改为w_length > 63试一试。

绿茶山人 发表于 2013-3-1 11:28:32

modelsim 发表于 2013-3-1 10:18 static/image/common/back.gif
现在bug发生的情况已经找到,当上位机通过驱动向下位机发送的字节数正好是64的倍数的时候bug就出现了,下 ...

还有427,479两行的63值得关注,你可以再检查一下

杨大侠 发表于 2013-3-1 12:18:25

绿茶山人 发表于 2013-3-1 11:20 static/image/common/back.gif
我看了你的diff文件,把605行和616行的w_length > 64改为w_length > 63试一试。

对,可以试下这个。

modelsim 发表于 2013-3-1 13:18:00

本帖最后由 modelsim 于 2013-3-1 13:32 编辑

绿茶山人 发表于 2013-3-1 11:28 static/image/common/back.gif
还有427,479两行的63值得关注,你可以再检查一下

这两个是读文件,读完送给上位机,这个功能是正常的,问题主要出在上位机向下位机写数据。谢谢

astankvai 发表于 2013-3-1 13:24:41

用的什么方式?bulk?interrupt?

modelsim 发表于 2013-3-1 13:32:04

astankvai 发表于 2013-3-1 13:24 static/image/common/back.gif
用的什么方式?bulk?interrupt?

用bulk方式

astankvai 发表于 2013-3-1 13:39:22

modelsim 发表于 2013-3-1 13:32 static/image/common/back.gif
用bulk方式

查buffer(端点).一般来说是buffer溢出的可能性比较大。

modelsim 发表于 2013-3-1 20:46:17

astankvai 发表于 2013-3-1 13:39 static/image/common/back.gif
查buffer(端点).一般来说是buffer溢出的可能性比较大。

63字节 65字节都可以 反正不能是64字节应该和是否溢出也没多大关系吧

modelsim 发表于 2013-3-5 11:52:39

modelsim 发表于 2013-3-1 20:46 static/image/common/back.gif
63字节 65字节都可以 反正不能是64字节应该和是否溢出也没多大关系吧

bug好像就在这一块
/*
* return:  0 = still running, 1 = queue empty, negative = errno
*/
static int s3c2410_udc_read_fifo(struct s3c2410_ep *ep,
                 struct s3c2410_request *req)
{
    u8        *buf = NULL;
    u32        ep_csr;
    unsigned    bufferspace;
    int        is_last=1;
    unsigned    avail;
    int        fifo_count = 0;
    u32        idx;
    int        fifo_reg;

    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;

    printk("%s req->req.length : %d\n", "s3c2410_udc_read_fifo", req->req.length);//tyc
    printk("%s req->req.actual : %d\n", "s3c2410_udc_read_fifo", req->req.actual);//tyc

again:

    buf = req->req.buf + req->req.actual;

    bufferspace = req->req.length - req->req.actual;

    if (!bufferspace)

        return -1;



    udc_write(idx, S3C2410_UDC_INDEX_REG);

    fifo_count = s3c2410_udc_fifo_count_out();

    printk("%s fifo_count : %d\n", "s3c2410_udc_fifo_count_out", fifo_count);    //tyc



    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);

    printk("%s fifo_count : %d\n", "s3c2410_udc_read_packet", fifo_count);    //tyc


    // checking this with ep0 is not accurate as we already read a control request

    if (idx != 0 && fifo_count < ep->ep.maxpacket) { //这个地方只能判断当数据小于64字节时认为是最后一包数据,如果最后一包数据恰好是64字节呢

        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;
        printk("%s req->req.length : %d\n", "s3c2410_udc_read_fifo_is_last", req->req.length);//tyc
        printk("%s req->req.actual : %d\n", "s3c2410_udc_read_fifo_is_last", req->req.actual);//tyc  

    }

    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_NORMAL,"%s fifo count : %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) )

        goto again;


    return is_last;
}
请问这段代码,当最后一包数据恰好是64字节的情况如何能确定这就是最后一包数据

Auir 发表于 2013-3-5 12:02:51

个人提一个建议,换个Nandflash试试。用micron的试试。

121854416 发表于 2013-3-5 12:20:10

我遇到过这情况,应该不是驱动的bug,而是文件系统缓存的问题。

yzdel7 发表于 2013-4-10 12:47:47

本帖最后由 yzdel7 于 2013-4-10 13:33 编辑

技术交流谈到钱不合适。

对了,你看看你USB Driver里的相应端点的数据包大小设置的是多少,用BUS Hound等数据跟踪工具抓数据看看。

这里把64个字节全部Print出来,结合抓到的数据试着分析一下。

/*******************************************/
    if (idx != 0 && fifo_count < ep->ep.maxpacket) { //这个地方只能判断当数据小于64字节时认为是最后一包数据,如果最后一包数据恰好是64字节呢

或者根据文件长度和相应端点的缓冲区大小计算数据包数量。
页: [1]
查看完整版本: 悬赏千元人民币,找linux下USB驱动的一个Bug