Chinaunix首页 | 论坛 | 博客
  • 博客访问: 456762
  • 博文数量: 73
  • 博客积分: 3593
  • 博客等级: 中校
  • 技术积分: 912
  • 用 户 组: 普通用户
  • 注册时间: 2009-10-14 11:32
文章分类

全部博文(73)

文章存档

2013年(2)

2012年(20)

2011年(25)

2010年(12)

2009年(14)

分类: 嵌入式

2012-06-20 11:02:21

最后决定不删了,辛辛苦苦加的备注,留着纪念吧 (2010-07-20 21:42:16)

我负责的是usb的读写函数和disconnect模块,就是断开函数。在usb设备驱动中,读写函数最基本的功能就是数据的传输。而Linux usb子系统的最常用的数据传输结构叫usb request block,即urb,这个结构包含了用于启动任何usb传输类型的所有参数。在操作系统与设备之间传送数据这里,有个很好的比喻说把数据看成货物的话,urb就是运载货物的汽车,至于道路嘛,则是usbbus驱动负责,而这个汽车可以运载各个类型的数据。所有的传输请求都会发送给usb内核而且通过回调函数告知回调完成。我们都知道这个驱动程序是在usb骨架基础上完成的,所以在读写包括其他函数中都大量的调用了骨架中带的函数,比如我们这个程序中的read函数,它没有使用urb来完成数据传输,而是选择调用usb-bulk-msg这个接口函数来读取设备数据的。如果该接口函数调用成功,返回值为0,否则返回一个负的错误值。而在下面用到的调用函数,大多都是调用函数成功,返回值为0的。那我们具体看read函数:

 static ssize_t skel_read(struct file *file, char *buffer, size_t count, loff_t *ppos)

定义函数,函数名,函数参数。

{struct usb_skel *dev;指向包含设备所有信息的结构体usb-skel的指针dev

int retval = 0;变量初始值为0

int bytes_read;定义变量

dev = (struct usb_skel *)file->private_data;open函数中,把该结构体存入fileprivate-data中,以便readwrite等函数调用

mutex_lock(&dev->io_mutex);互斥信号量锁定,当它在使用这个资源时,其他程序不能访问该资源

    if (!dev->interface) 检查接口是否存在,如果不存在就表明设备已断开,并返回一个-ENODEV给用户程序

{       retval = -ENODEV;

        goto exit;

    }

 

    从设备中读取批量数据。

    retval = usb_bulk_msg(dev->udev,

                  usb_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr),

                  dev->bulk_in_buffer,

                  min(dev->bulk_in_size, count),

                  &bytes_read, 10000); 调用usb-bulk-msg接口函数

   if (!retval) 如果函数调用成功,返回值为0。即retval值为0,!retval值非零

 {

    if (copy_to_user(buffer, dev->bulk_in_buffer, bytes_read)) 由于内核空间与用户空间的内存不能直接互访,因此借助函数,从内核空间复制数据到用户空间,调用成功返回值为0

            retval = -EFAULT;

        else

            retval = bytes_read;

    }

 

exit:

    mutex_unlock(&dev->io_mutex);释放io

    return retval;返回函数值

}

再简单说下ddisconnect函数,当usb设备断开时,调用断开函数清理和设备相关的资源。

static void skel_disconnect(struct usb_interface *interface)定义函数,参数

{struct usb_skel *dev;指针

    int minor = interface->minor;定义变量

dev = usb_get_intfdata(interface);调用usb_get_intfdata函数获取端点数据

    usb_set_intfdata(interface, NULL); 通过usb-set-intfdata释放usb-skel结构体

    usb_deregister_dev(interface, &skel_class); 如果已经在探测函数中调用了注册函数为该usb设备分配了一个次设备号的话,必须调用usb-deregister-dev函数来把次设备号交还给usb核心

    mutex_lock(&dev->io_mutex);防止更多的io访问

    dev->interface = NULL; 设置struct usb-interface结构体的数据指针为null,即设置接口设备的数据指针为空   

mutex_unlock(&dev->io_mutex);释放io

usb_kill_anchored_urbs(&dev->submitted);处理urb

    kref_put(&dev->kref, skel_delete);使用kref-put递减kref,如果kref0,则调用skel-delete释放kref

info("USB Myusb #%d now disconnected", minor);通知系统,usb已经完全断开

}

最后说一下write函数,用于向设备写数据

static ssize_t skel_write(struct file *file, const char *user_buffer, size_t count, loff_t *ppos)

{   printk(KERN_ALERT "Write\n");

    struct usb_skel *dev;定义指针

    int retval = 0;定义变量

    struct urb *urb = NULL;定义结构体指针并初始化为空

    char *buf = NULL;char型指针buf为空

    size_t writesize = min(count, (size_t)MAX_TRANSFER);    最大可写尺寸

dev = (struct usb_skel *)file->private_data; open函数中,把该结构体存入fileprivate-data中,以便readwrite等函数调用

    if (count == 0)检查所写的数据不为0

        goto exit;

    if (down_interruptible(&dev->limit_sem)) 如果down_interruptible得返回值不为0,则说明它被中断了(limit-semusb-skel结构体中定义),这里是为了限制urb传输的数量

{       retval = -ERESTARTSYS;

        goto exit;

    }

spin_lock_irq(&dev->err_lock); spin_lock_irq函数禁止CPU的本地中断,再调用spin_lock获得自旋锁

    if ((retval = dev->errors) < 0) 任何错误只能报错一次

{     dev->errors = 0;

        retval = (retval == -EPIPE) ? retval : -EIO; 维护协议的恢复

    }

    spin_unlock_irq(&dev->err_lock); spin_unlock_irq函数首先调用spin_unlock释放自旋锁,再打开CPU的本地中断

    if (retval < 0)

        goto error;

    urb = usb_alloc_urb(0, GFP_KERNEL); usb-alloc-urb函数创建一个urb,并且给它分配一个缓存,创建成功返回值为0

if (!urb) {

        retval = -ENOMEM;

        goto error;

    }

    buf = usb_buffer_alloc(dev->udev, writesize, GFP_KERNEL, &urb->transfer_dma);  usb-buffer-alloc创建一个DMA缓冲区缓冲传递给驱动程序的数据,成功返回0

    if (!buf) {

        retval = -ENOMEM;

        goto error;

    }

if (copy_from_user(buf, user_buffer, writesize))从用户空间复制到内核空间中的缓冲区,成功返回0

 {   retval = -EFAULT;

        goto error;}

mutex_lock(&dev->io_mutex);互斥锁

    if (!dev->interface) 判断接口是否断开,保证不给已断开的USB发送URB

{       mutex_unlock(&dev->io_mutex);释放互斥锁

        retval = -ENODEV;

        goto error;}

    usb_fill_bulk_urb(urb, dev->udev,

              usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr),

              buf, writesize, skel_write_bulk_callback, dev);用来正确初始化即将被发送到usb设备的中断端点的urb,使用了回调函数skel_write_bulk_callback用来通知驱动

    urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;设置传输标志

    usb_anchor_urb(urb, &dev->submitted);

 

    retval = usb_submit_urb(urb, GFP_KERNEL); 一旦urbUSB驱动程序正确地创建和初始化后,就可以利用usb-submit-urburb递交到USB核心以发送到USB设备了,提交成功返回值为0

    mutex_unlock(&dev->io_mutex);释放io

    if (retval)

 {err("%s - failed submitting write urb, error %d", __func__, retval);报错

        goto error_unanchor;

}

    usb_free_urb(urb);释放我们对这个urb的作用,usb内核将最终完全的释放它

return writesize;

error_unanchor:

    usb_unanchor_urb(urb);

error:

    if (urb) 拿到urb控制权后,检查它是不是出错了,用不用重新释放或提交

 {

        usb_buffer_free(dev->udev, writesize, buf, urb->transfer_dma);

        usb_free_urb(urb);

}

    up(&dev->limit_sem);

exit:

    return retval;

}

-ENOMEM        内存不足

-ENODEV        没有设备可用

-EPIPE         端点停止

-EAGAIN        排队等候同步传输的太多

-EFBIG         请求ISO frame的太多

-EINVAL        无效的中断间隔

阅读(1416) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~