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

还东国的博客

行之苟有恒,久久自芬芳

 
 
 

日志

 
 

LINUX驱动学习——内核USB驱动编写三USB驱动的开发PROBE函数  

2012-12-13 20:49:41|  分类: USB系列 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
 

LINUX驱动学习——内核USB驱动编写三USB驱动的开发PROBE函数

PROBE函数在上文中进行了简单的引入,看一下这个函数传入的两个参数:

1、struct usb_interface *interface

2、const struct usb_device_id *id

第一个参数是一个USB的接口类型数据结构,而第二个则是一个设备ID,而后者中就包含PID和VID的参数。前面的十余行代码主要是初始化的,不详细说,看下面这行:

dev->udev = usb_get_dev(interface_to_usbdev(interface));

这个函数和usb_put_dev一起进行内核引用计数的作用,跳进去你看,其实代码很简单,不过一定要和本模块的kref区分开来,二者并不是一回事。

接下来:

         iface_desc = interface->cur_altsetting;

         for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {

                   endpoint = &iface_desc->endpoint[i].desc;

 

                   if (!dev->bulk_in_endpointAddr &&

                       usb_endpoint_is_bulk_in(endpoint)) {

                            /* we found a bulk in endpoint */

                            buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);

                            dev->bulk_in_size = buffer_size;

                            dev->bulk_in_endpointAddr = endpoint->bEndpointAddress;

                            dev->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);

                            if (!dev->bulk_in_buffer) {

                                     err("Could not allocate bulk_in_buffer");

                                     goto error;

                            }

                            dev->bulk_in_urb = usb_alloc_urb(0, GFP_KERNEL);

                            if (!dev->bulk_in_urb) {

                                     err("Could not allocate bulk_in_urb");

                                     goto error;

                            }

                   }

 

                   if (!dev->bulk_out_endpointAddr &&

                       usb_endpoint_is_bulk_out(endpoint)) {

                            /* we found a bulk out endpoint */

                            dev->bulk_out_endpointAddr = endpoint->bEndpointAddress;

                   }

         }

外面的大循环很明显是对接口(前面不是讲过:接口是端点的集合)的所有端点进行遍历,并将其注册到dev,而它的定义很清楚是:usb_skel类型的。下来还有两个比较重要的函数:

         /* save our data pointer in this interface device */

         usb_set_intfdata(interface, dev);

         /* we can register the device now, as it is ready */

         retval = usb_register_dev(interface, &skel_class);

先看第一个:

这个用来把usb_skel数据结构,也就是前面遍历注册的dev注册到内核中去,其实就是挂到链表上,大家有兴趣可以自己跟进去看。这里面的dev有很多的地方想用,可是这个变量是一个局部的变量,所以只有把他注册到接口上去,而接口是所有的地方都可以访问得到的。

而第二个函数呢,则是把&skel_class注册到方才的接口上去,并为其分配主次设备号,大家都知道,USB的逻辑设备,诸如鼠标键盘之类的东西,其一一对应着一个接口,前面讲过,一般情况下,一个驱动只控制一个接口,好,那么看一下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,

};

/**

 * struct usb_class_driver - identifies a USB driver that wants to use the USB major number

 * @name: the usb class device name for this driver.  Will show up in sysfs.

 * @devnode: Callback to provide a naming hint for a possible

 *     device node to create.

 * @fops: pointer to the struct file_operations of this driver.

 * @minor_base: the start of the minor range for this driver.

 *

 * This structure is used for the usb_register_dev() and

 * usb_unregister_dev() functions, to consolidate a number of the

 * parameters used for them.

 */

struct usb_class_driver {

         char *name;

         char *(*devnode)(struct device *dev, mode_t *mode);

         const struct file_operations *fops;

         int minor_base;

};

其中的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,

};

LINUX的USB设备一般是操作接口,而一个USB设备是可以有多个接口的,因此上面的操作,每次为一个逻辑设备申请一个次设备号,也就是说,上面列举的USB的鼠标和键盘等设备分别对应着一个次设备ID

既然每一个接口可以对应一个逻辑设备,那么每一个操作设备的数据结构,都有可能不同。所以每个接口都要挂一个自己的文件操作数据结构。(LINUX下一切都是文件),而在这个操作数据结构中,最重要的就是五个函数了,这个正常的情况下是需要大家自己来完成的。

这样,probe这个函数基本就介绍过了,余下的是一些错误处理和模块计数的动作,就不再细说,今天就先到这里。

说是有雪,不知道下不下,早回家吧。

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

历史上的今天

在LOFTER的更多文章

评论

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

页脚

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