注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

还东国的博客

行之苟有恒,久久自芬芳

 
 
 

日志

 
 

LINUX驱动学习——内核USB驱动编写五USB驱动的数据操作函数写函数  

2012-12-19 21:14:17|  分类: USB系列 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
 

LINUX驱动学习——内核USB驱动编写五USB驱动的数据操作函数写函数

接昨天的上文,老规矩先上函数,虽然这样看上去不厚道,可不上函数,下面讲大家就不知道是在讲哪儿。

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

}

同样,与读函数一样,会有一个写函数的回调处理函数。

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)

                   goto exit;

 

         /*

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

          * RAM

          */

         if (!file->f_flags & O_NONBLOCK) {

                   if (down_interruptible(&dev->limit_sem)) {

                            retval = -ERESTARTSYS;

                            goto exit;

                   }

         } else {

                   if (down_trylock(&dev->limit_sem)) {

                            retval = -EAGAIN;

                            goto exit;

                   }

         }

 

         spin_lock_irq(&dev->err_lock);

         retval = dev->errors;

         if (retval < 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);

         if (!urb) {

                   retval = -ENOMEM;

                   goto error;

         }

 

         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 */

         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 = usb_alloc_urb(0, GFP_KERNEL);buf = usb_buffer_alloc是与读不同的,在昨天的读的函数里,其实是使用的probe函数里分配的urb,而在写的函数里,估计这个urb比较不固定,所以就自己来创建了,同时还得分配缓冲区。而比较有趣的是这个函数:

usb_anchor_urb(urb, &dev->submitted);

大家可以跟进去:

/**

 * usb_anchor_urb - anchors an URB while it is processed

 * @urb: pointer to the urb to anchor

 * @anchor: pointer to the anchor

 *

 * This can be called to have access to URBs which are to be executed

 * without bothering to track them

 */

void usb_anchor_urb(struct urb *urb, struct usb_anchor *anchor)

{

         unsigned long flags;

 

         spin_lock_irqsave(&anchor->lock, flags);

         usb_get_urb(urb);

         list_add_tail(&urb->anchor_list, &anchor->urb_list);

         urb->anchor = anchor;

 

         if (unlikely(anchor->poisoned)) {

                   atomic_inc(&urb->reject);

         }

 

         spin_unlock_irqrestore(&anchor->lock, flags);

}

代码是不是非常简单,锁定当前操作处理的urb,并且将其加入到链表中,当然有一个锁定就会有一个删除(注意删除不是释放urb):

/**

 * usb_unanchor_urb - unanchors an URB

 * @urb: pointer to the urb to anchor

 *

 * Call this to stop the system keeping track of this URB

 */

void usb_unanchor_urb(struct urb *urb)

{

         unsigned long flags;

         struct usb_anchor *anchor;

 

         if (!urb)

                   return;

 

         anchor = urb->anchor;

         if (!anchor)

                   return;

 

         spin_lock_irqsave(&anchor->lock, flags);

         if (unlikely(anchor != urb->anchor)) {

                   /* we've lost the race to another thread */

                   spin_unlock_irqrestore(&anchor->lock, flags);

                   return;

         }

         urb->anchor = NULL;

         list_del(&urb->anchor_list);

         spin_unlock_irqrestore(&anchor->lock, flags);

         usb_put_urb(urb);

         if (list_empty(&anchor->urb_list))

                   wake_up(&anchor->wait);

}

而释放会有相应的free函数来操作。

其它的地方如果注意的话会和读没有什么太大的区别,这里就不再说述。

事情很多,但要一件件的认真干,不要冲动。

  评论这张
 
阅读(875)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017