上一节勉勉强强把struct urb这个中心给说完,接着看那三个基本点。
第一个基本点,usb_alloc_urb函数,创建urb的专用函数,为一个urb申请内存并做初始化,在drviers/usb/core/urb.c里定义:
/**
-
usb_alloc_urb - creates a new urb for a USB driver to use
-
@iso_packets: number of iso packets for this urb
-
@mem_flags: the type of memory to allocate, see kmalloc() for a list of
-
valid options for this.
-
Creates an urb for the USB driver to use, initializes a few internal
-
structures, incrementes the usage counter, and returns a pointer to it.
-
If no memory is available, NULL is returned.
-
If the driver want to use this urb for interrupt, control, or bulk
-
endpoints, pass ‘0’ as the number of iso packets.
-
The driver must call usb_free_urb() when it is finished with the urb.
*/
struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags)
{
struct urb *urb;urb = kmalloc(sizeof(struct urb) +
iso_packets * sizeof(struct usb_iso_packet_descriptor),
mem_flags);
if (!urb) {
err(“alloc_urb: kmalloc failed”);
return NULL;
}
usb_init_urb(urb);
return urb;
}
这函数只做了两件事情,拿kmalloc来为urb申请内存,然后调用usb_init_urb进行初始化。usb_init_urb函数的作用就是初始化urb的引用计数,并用memset顺便把这里给urb申请的内存清零。没什么说的了么?usb_alloc_urb说:别看我简单,我也是很有内涵的。
先看第一个问题,它的第一个参数iso_packets,表示的是struct urb结构最后那个变长数组iso_frame_desc的元素数目,也就是应该与number_of_packets的值相同,所以对于控制/中断/批量传输,这个参数都应该为0。这也算是给咱们示范了下变长数组咋个用法,内核里到处都是C的示范工程。
第二个问题是参数mem_flags的类型gfp_t,早几个版本的内核,这里还是int,当然这里变成gfp_t是因为kmalloc参数里的那个标志参数的类型从int变成gfp_t了,你要用kmalloc来申请内存,就得遵守它的规则。咱们来调查一下它的背景。它在include/linux/types.h里定义。
typedef unsigned bitwise gfp_t;
很显然,要了解gfp_t,关键是要了解__bitwise__,它也在types.h里定义:
#ifdef __CHECKER__
#define __bitwise__ __attribute__((bitwise))
#else
#define __bitwise__
#endif
bitwise__的含义又取决于是否定义了__CHECKER,如果没有定义__CHECKER__,那__bitwise__就啥也不是。哪里定义了__CHECKER__?咱们不找,因为内核代码里就没有哪个地方定义了__CHECKER__,它是有关Sparse工具的,内核编译时的参数决定了是不是使用Sparse工具来做类型检查。那Sparse又是什么?它是一种静态分析工具(static analysis tool), 用于在linux内核源代码中发现各种类型的漏洞,一直都是比较神秘的角色,最初由Linus Torvalds写的,后来linus没有继续维护,直到去年的冬天,它才又有了新的维护者Josh Triplett。有关Sparse再多的东东,咱们还是各自去研究吧,这里不多说了。
可能还会有第三个问题,usb_alloc_urb也没做多少事啊,它做的那些咱们自己很容易就能做了,为什么还说驱动里一定要使用它来创建urb那?按照C++的说法,它就是urb的构造函数,构造函数是创建对象的唯一方式。它将创建urb的工作给包装了,咱们只管调用就是了,孙子兵法里有,以不变应万变。
对应的,当然还会有个析构函数,销毁urb的,也在urb.c里定义。usb_free_urb只调用kref_put将urb的引用计数减一,减了之后如果变为0,也就是没人再用它了,就调用urb_destroy将它销毁掉。
接着看第二个基本点,usb_fill_control_urb函数,初始化刚才创建的控制urb,你要想使用urb进行usb传输,不是光为它申请点内存就够的,你得为它初始化。它是在include/linux/usb.h里定义的内联函数:
static inline void usb_fill_control_urb (struct urb *urb,
struct usb_device *dev,
unsigned int pipe,
unsigned char *setup_packet,
void *transfer_buffer,
int buffer_length,
usb_complete_t complete_fn,
void *context)
{
spin_lock_init(&urb->lock);
urb->dev = dev;
urb->pipe = pipe;
urb->setup_packet = setup_packet;
urb->transfer_buffer = transfer_buffer;
urb->transfer_buffer_length = buffer_length