分类: 嵌入式
2012-06-20 11:02:21
我负责的是usb的读写函数和disconnect模块,就是断开函数。在usb设备驱动中,读写函数最基本的功能就是数据的传输。而Linux usb子系统的最常用的数据传输结构叫usb request block,即urb,这个结构包含了用于启动任何usb传输类型的所有参数。在操作系统与设备之间传送数据这里,有个很好的比喻说把数据看成货物的话,urb就是运载货物的汽车,至于道路嘛,则是usb的bus驱动负责,而这个汽车可以运载各个类型的数据。所有的传输请求都会发送给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函数中,把该结构体存入file的private-data中,以便read,write等函数调用
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,如果kref为0,则调用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函数中,把该结构体存入file的private-data中,以便read,write等函数调用
if (count == 0)检查所写的数据不为0
goto exit;
if (down_interruptible(&dev->limit_sem)) 如果down_interruptible得返回值不为0,则说明它被中断了(limit-sem在usb-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); 一旦urb被USB驱动程序正确地创建和初始化后,就可以利用usb-submit-urb将urb递交到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 无效的中断间隔