linux usb-skeleton,Linux USB驱动程序(4)----usb-skeleton.c分析
发布日期:2021-06-24 12:34:37 浏览次数:2 分类:技术文章

本文共 6198 字,大约阅读时间需要 20 分钟。

usb_driver里面最重要的3个要素都说完了,接下来就是skel_class了。

第一步,看其结构体定义

/*

* usb class driver info in order to get a minor number from the usb core,

* and to have the device registered with the driver core

*/

static struct usb_class_driver skel_class = {

.name ="skel%d",

.fops =&skel_fops,

.minor_base =USB_SKEL_MINOR_BASE,

};

Name就是驱动名字了,fops就是这个驱动的文件操作结构体了,minor_base表示次设备的基础设备号,也就是192.比如我使用的时候,产生的文件/dev/skel0 ,主设备号是180,次设备号就是192了。

第二步,就是看skel_fops了,定义如下

static const struct file_operations skel_fops = {

.owner =THIS_MODULE,

.read =skel_read,

.write =skel_write,

.open =skel_open,

.release =skel_release,

.flush =skel_flush,

};

由于只是一个象征性的骨架程序,因此其open函数比较简单,如下

static int skel_open(struct inode *inode, struct file *file)

{

struct usb_skel *dev;

struct usb_interface *interface;

int subminor;

int retval = 0;

subminor = iminor(inode);//得到需要打开设备的次设备号

interface = usb_find_interface(&skel_driver, subminor); //通过skel_driver及次设备号找到USB接口指针

if (!interface) {//没找到返回错误

err ("%s - error, can't find device for minor %d",

__func__, subminor);

retval = -ENODEV;

goto exit;

}

dev = usb_get_intfdata(interface);//找到则得到其私有保存数据

if (!dev) {

retval = -ENODEV;

goto exit;

}

/* increment our usage count for the device */

kref_get(&dev->kref);//增加设备的引用计数

/* lock the device to allow correctly handling errors

* in resumption */

mutex_lock(&dev->io_mutex);

if (!dev->open_count++) {

retval = usb_autopm_get_interface(interface);

if (retval) {

dev->open_count--;

mutex_unlock(&dev->io_mutex);

kref_put(&dev->kref, skel_delete);

goto exit;

}

} /* else { //uncomment this block if you want exclusive open

retval = -EBUSY;

dev->open_count--;

mutex_unlock(&dev->io_mutex);

kref_put(&dev->kref, skel_delete);

goto exit;

} */

/* prevent the device from being autosuspended */

/* save our object in the file's private structure */

file->private_data = dev;//接口数据保存在file的私有数据里

mutex_unlock(&dev->io_mutex);

exit:

return retval;

}

对应的release()函数也就是减少在open()中增加的引用计数,如下

static int skel_release(struct inode *inode, struct file *file)

{

struct usb_skel *dev;

dev = (struct usb_skel *)file->private_data;

if (dev == NULL)

return -ENODEV;

/* allow the device to be autosuspended */

mutex_lock(&dev->io_mutex);

if (!--dev->open_count && dev->interface)

usb_autopm_put_interface(dev->interface);

mutex_unlock(&dev->io_mutex);

/* decrement the count on our device */

kref_put(&dev->kref, skel_delete);

return 0;

}

接下来要分析的是读写函数,在访问USB设备时,贯穿于其中的是urb结构体。先看读函数

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

{

struct usb_skel *dev;

int retval;

int bytes_read;

dev = (struct usb_skel *)file->private_data; //得到usb_skel指针

mutex_lock(&dev->io_mutex);

if (!dev->interface) {/* disconnect() was called */

retval = -ENODEV;

goto exit;

}

/* do a blocking bulk read to get data from the device */

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

/* if the read was successful, copy the data to userspace */

if (!retval) {//若读成功,则将数据复制到用户空间

if (copy_to_user(buffer, dev->bulk_in_buffer, bytes_read))

retval = -EFAULT;

else

retval = bytes_read;

}

exit:

mutex_unlock(&dev->io_mutex);

return retval;

}

在skel_write()函数中进行的关于urb的操作与前面对urb的描述完全对应,即进行了urb的分配、初始化和提交操作。代码如下:

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

{

struct usb_skel *dev;

int retval = 0;

struct urb *urb = NULL;

char *buf = NULL;

size_t writesize = min(count, (size_t)MAX_TRANSFER);

dev = (struct usb_skel *)file->private_data;

/* verify that we actually have some data to write */

if (count == 0)//验证实际上有数据要写入USB设备

goto exit;

/* limit the number of URBs in flight to stop a user from using up all RAM */

if (down_interruptible(&dev->limit_sem)) { //限制urb的数量,防止一个用户用光所有的RAM

retval = -ERESTARTSYS;

goto exit;

}

spin_lock_irq(&dev->err_lock);

if ((retval = dev->errors) < 0) {

/* any error is reported once */

dev->errors = 0;

/* to preserve notifications about reset */

retval = (retval == -EPIPE) ? retval : -EIO;

}

spin_unlock_irq(&dev->err_lock);

if (retval < 0)

goto error;

/* create a urb, and a buffer for it, and copy the data to the urb */

urb = usb_alloc_urb(0, GFP_KERNEL);//创建urb的缓存区,将数据复制给urb

if (!urb) {

retval = -ENOMEM;

goto error;

}

//申请DMA内存

buf = usb_buffer_alloc(dev->udev, writesize, GFP_KERNEL, &urb->transfer_dma);

if (!buf) {

retval = -ENOMEM;

goto error;

}

if (copy_from_user(buf, user_buffer, writesize)) { //从用户空间复制数据

retval = -EFAULT;

goto error;

}

/* this lock makes sure we don't submit URBs to gone devices */

mutex_lock(&dev->io_mutex);

if (!dev->interface) {/* disconnect() was called */

mutex_unlock(&dev->io_mutex);

retval = -ENODEV;

goto error;

}

/* initialize the urb properly */ //初始化urb

usb_fill_bulk_urb(urb, dev->udev,

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

buf, writesize, skel_write_bulk_callback, dev);

urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;

usb_anchor_urb(urb, &dev->submitted);//

/* send the data out the bulk port */

retval = usb_submit_urb(urb, GFP_KERNEL);

mutex_unlock(&dev->io_mutex);

if (retval) {

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

goto error_unanchor;

}

/* release our reference to this urb, the USB core will eventually free it entirely */

usb_free_urb(urb);

return writesize;

error_unanchor:

usb_unanchor_urb(urb);

error:

if (urb) {

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

usb_free_urb(urb);

}

up(&dev->limit_sem);

exit:

return retval;

}

写函数发起的urb结束后,其完成函数skel_write_bulk_callback()将被调用,它会进行urb->status的判断,如下所示:

static void skel_write_bulk_callback(struct urb *urb)

{

struct usb_skel *dev;

dev = urb->context;

/* sync/async unlink faults aren't errors */ //去除链路故障

if (urb->status) {

if(!(urb->status == -ENOENT ||

urb->status == -ECONNRESET ||

urb->status == -ESHUTDOWN))

err("%s - nonzero write bulk status received: %d",

__func__, urb->status);

spin_lock(&dev->err_lock);

dev->errors = urb->status;

spin_unlock(&dev->err_lock);

}

/* free up our allocated buffer */释放被分配的内存

usb_buffer_free(urb->dev, urb->transfer_buffer_length,

urb->transfer_buffer, urb->transfer_dma);

up(&dev->limit_sem);

}

到这里,整个程序就分析完了。大部分工作内核都帮你做了,USB驱动程序就是这么简单,呵呵。

转载地址:https://blog.csdn.net/weixin_32767591/article/details/116923630 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:工作站Linux双显卡BIOS设置,在BIOS Setup里面设置双显卡机型的双显卡模式
下一篇:linux线程调度与rtos,实时Linux和RTOS的基本特性及技术进行比较

发表评论

最新留言

初次前来,多多关照!
[***.217.46.12]2024年04月27日 03时19分16秒