Linux那些事儿 之 戏说USB(26)设备的生命线(五)

原创 2007年10月12日 16:11:00
人的一生就象在拉屎,有时你已经很努力了可出来的只是一个屁。
看这内核代码也一个样,已经很努力了,俺的葱葱玉指都磨出茧子了,才勉勉强强把struct urb这个中心给说完,下面接着看那三个基本点。看之前,再猜个谜语,蜘蛛侠是什么颜色的?
第一个基本点,usb_alloc_urb函数,创建urb的专用函数,为一个urb申请内存并做初始化,在drviers/usb/core/urb.c里定义。
40 /**
41 * usb_alloc_urb - creates a new urb for a USB driver to use
42 * @iso_packets: number of iso packets for this urb
43 * @mem_flags: the type of memory to allocate, see kmalloc() for a list of
44 *      valid options for this.
45 *
46 * Creates an urb for the USB driver to use, initializes a few internal
47 * structures, incrementes the usage counter, and returns a pointer to it.
48 *
49 * If no memory is available, NULL is returned.
50 *
51 * If the driver want to use this urb for interrupt, control, or bulk
52 * endpoints, pass '' as the number of iso packets.
53 *
54 * The driver must call usb_free_urb() when it is finished with the urb.
55 */
56 struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags)
57 {
58         struct urb *urb;
60         urb = kmalloc(sizeof(struct urb) +
61                 iso_packets * sizeof(struct usb_iso_packet_descriptor),
62                 mem_flags);
63         if (!urb) {
64                 err("alloc_urb: kmalloc failed");
65                 return NULL;
66         }
67         usb_init_urb(urb);
68         return urb;
69 }
这函数长的很让人提神,是个亲民的角色。它只做了两件事情,拿kmalloc来为urb申请内存,然后调用usb_init_urb进行初始化。usb_init_urb函数在前面说struct 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来申请内存,就得遵守它的规则。不过这里要说的不是kmalloc,而是gfp_t,它在江湖上也没出现多久,名号还没打出来,很多人不了解,咱们来调查一下它的背景。它在include/linux/types.h里定义
193 typedef unsigned __bitwise__ gfp_t;
很显然,要了解gfp_t,关键是要了解__bitwise__,它也在types.h里定义
170 #ifdef __CHECKER__
171 #define __bitwise__ __attribute__((bitwise))
172 #else
174 #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的构造函数,构造函数是创建对象的唯一方式,你抬杠说C++里面儿使用位拷贝去复制一个简单对象给新对象就没使用构造函数,那是你不知道,C++的ARM里将这时的构造函数称为trivial copy constructor。再说,现在它做这些事儿,以后还是做这些么?它将创建urb的工作给包装了,咱们只管调用就是了,孙子兵法里有,以不变应万变。
对应的,当然还会有个析构函数,销毁urb的,也在urb.c里定义
71 /**
72 * usb_free_urb - frees the memory used by a urb when all users of it are finished
73 * @urb: pointer to the urb to free, may be NULL
74 *
75 * Must be called when a user of a urb is finished with it. When the last user
76 * of the urb calls this function, the memory of the urb is freed.
77 *
78 * Note: The transfer buffer associated with the urb is not freed, that must be
79 * done elsewhere.
80 */
81 void usb_free_urb(struct urb *urb)
82 {
83         if (urb)
84                 kref_put(&urb->kref, urb_destroy);
85 }
usb_free_urb更潇洒,只调用kref_put将urb的引用计数减一,减了之后如果变为0,也就是没人再用它了,就调用urb_destroy将它销毁掉。
接着看第二个基本点,usb_fill_control_urb函数,初始化刚才创建的控制urb,你要想使用urb进行usb传输,不是光为它申请点内存就够的,你得为它初始化,充实点实实在在的内容,这个和女星要出名快,也要填充点内容的道理是一样的。它是在include/linux/usb.h里定义的内联函数
1161 /**
1162 * usb_fill_control_urb - initializes a control urb
1163 * @urb: pointer to the urb to initialize.
1164 * @dev: pointer to the struct usb_device for this urb.
1165 * @pipe: the endpoint pipe
1166 * @setup_packet: pointer to the setup_packet buffer
1167 * @transfer_buffer: pointer to the transfer buffer
1168 * @buffer_length: length of the transfer buffer
1169 * @complete_fn: pointer to the usb_complete_t function
1170 * @context: what to set the urb context to.
1171 *
1172 * Initializes a control urb with the proper information needed to submit
1173 * it to a device.
1174 */
1175 static inline void usb_fill_control_urb (struct urb *urb,
1176                                          struct usb_device *dev,
1177                                          unsigned int pipe,
1178                                          unsigned char *setup_packet,
1179                                          void *transfer_buffer,
1180                                          int buffer_length,
1181                                          usb_complete_t complete_fn,
1182                                          void *context)
1184         spin_lock_init(&urb->lock);
1185         urb->dev = dev;
1186         urb->pipe = pipe;
1187         urb->setup_packet = setup_packet;
1188         urb->transfer_buffer = transfer_buffer;
1189         urb->transfer_buffer_length = buffer_length;
1190         urb->complete = complete_fn;
1191         urb->context = context;
这个函数长的就让人兴奋,纯粹是来增长咱们自信的,自信多一分,成功就多十分,你就能搞懂内核,你就能成为一个成功的男人。这个函数基本上都是赋值语句,把你在参数里指定的值充实给刚刚创建的urburb的元素有很多,这里只是填充了一部分,剩下那些不是控制传输管不着的,就是自有安排可以不用去管的。
你想想,一个struct urb结构要应付四种传输类型,每种传输类型总会有点自己特别的要求,总会有些元素专属于某种传输类型,而其它传输类型不用管的。如果按C++的做法,这称不上是一个好的设计思想,应该有个基类urb,里面放点儿四种传输类型公用的,比如pipetransfer_buffer等,再搞几个子类,control_urbbulk_urb等等,专门应付具体的传输类型,如果不用什么虚函数,实际的时间空间消耗也不会增加什么。但是实在没必要这么搞,这年头儿内核的结构已经够多了,你创建什么类型的urb,就填充相关的一些字段好了,况且写usb core的哥们儿已经给咱们提供了不同传输类型的初始化函数,就像上面的usb_fill_control_urb,对于批量传输有usb_fill_bulk_urb,对于中断传输有usb_fill_int_urb,一般来说这也就够了,下面就看看usb_fill_control_urb函数的这俩孪生兄弟。
1194 /**
1195 * usb_fill_bulk_urb - macro to help initialize a bulk urb
1196 * @urb: pointer to the urb to initialize.
1197 * @dev: pointer to the struct usb_device for this urb.
1198 * @pipe: the endpoint pipe
1199 * @transfer_buffer: pointer to the transfer buffer
1200 * @buffer_length: length of the transfer buffer
1201 * @complete_fn: pointer to the usb_complete_t function
1202 * @context: what to set the urb context to.
1203 *
1204 * Initializes a bulk urb with the proper information needed to submit it
1205 * to a device.
1206 */
1207 static inline void usb_fill_bulk_urb (struct urb *urb,
1208                                       struct usb_device *dev,
1209                                       unsigned int pipe,
1210                                       void *transfer_buffer,
1211                                       int buffer_length,
1212                                       usb_complete_t complete_fn,
1213                                       void *context)
1215         spin_lock_init(&urb->lock);
1216         urb->dev = dev;
1217         urb->pipe = pipe;
1218         urb->transfer_buffer = transfer_buffer;
1219         urb->transfer_buffer_length = buffer_length;
1220         urb->complete = complete_fn;
1221         urb->context = context;
1224 /**
1225 * usb_fill_int_urb - macro to help initialize a interrupt urb
1226 * @urb: pointer to the urb to initialize.
1227 * @dev: pointer to the struct usb_device for this urb.
1228 * @pipe: the endpoint pipe
1229 * @transfer_buffer: pointer to the transfer buffer
1230 * @buffer_length: length of the transfer buffer
1231 * @complete_fn: pointer to the usb_complete_t function
1232 * @context: what to set the urb context to.
1233 * @interval: what to set the urb interval to, encoded like
1234 *      the endpoint descriptor's bInterval value.
1235 *
1236 * Initializes a interrupt urb with the proper information needed to submit
1237 * it to a device.
1238 * Note that high speed interrupt endpoints use a logarithmic encoding of
1239 * the endpoint interval, and express polling intervals in microframes
1240 * (eight per millisecond) rather than in frames (one per millisecond).
1241 */
1242 static inline void usb_fill_int_urb (struct urb *urb,
1243                                      struct usb_device *dev,
1244                                      unsigned int pipe,
1245                                      void *transfer_buffer,
1246                                      int buffer_length,
1247                                      usb_complete_t complete_fn,
1248                                      void *context,
1249                                      int interval)
1251         spin_lock_init(&urb->lock);
1252         urb->dev = dev;
1253         urb->pipe = pipe;
1254         urb->transfer_buffer = transfer_buffer;
1255         urb->transfer_buffer_length = buffer_length;
1256         urb->complete = complete_fn;
1257         urb->context = context;
1258         if (dev->speed == USB_SPEED_HIGH)
1259                 urb->interval = 1 << (interval - 1);
1260         else
1261                 urb->interval = interval;
1262         urb->start_frame = -1;
负责批量传输的usb_fill_bulk_urb和负责控制传输的usb_fill_control_urb的相比,只是少初始化了一个setup_packet,因为批量传输里没有Setup包的概念,中断传输里也没有,所以usb_fill_int_urb里也没有初始化setup_packet这一说。不过usb_fill_int_urb比那两个还是多了点儿内容的,因为它有个interval,比控制传输和批量传输多了个表达自己期望的权利,1258行还做了次判断,如果是高速就怎么怎么着,否则又怎么怎么着,主要是高速和低速/全速的间隔时间单位不一样,低速/全速的单位为帧,高速的单位为微帧,还要经过2的(bInterval-1)次方这么算一下。至于1262行start_frame,它是给等时传输用的,这里自然就设置为-1,关于为什么既然start_frame是等时传输用的这里还要设置那么一下,你往后看吧,现在我也不知道。
作为一个共产主义接班人,我们很快就能发现usb_fill_control_urb的孪生兄弟里,少了等时传输对应的那个初始化函数,三缺一啊,在哪里都会是个遗憾。不是不想有,而是没办法,对于等时传输,urb里是可以指定进行多次传输的,你必须一个一个的对那个变长数组iso_frame_desc里的内容进行初始化,没人帮得了你。难道你能想出一个办法搞出一个适用于各种情况等时传输的初始化函数?我是不能。如果想不出来,使用urb进行等时传输的时候,还是老老实实的对里面相关的字段一个一个的填内容吧。如果想找个例子旁观一下别人是咋初始化的,可以去找个摄像头驱动,或者其它usb音视频设备的驱动看看,内核里也有一些的。
现在,你应该还记得咱们是因为要设置设备的地址,让设备进入Address状态,调用了usb_control_msg,才走到这里遇到usb_fill_control_urb的,参数里的setup_packet就是之前创建和赋好值的struct usb_ctrlrequest结构体,设备的地址已经在struct usb_ctrlrequest结构体wValue字段里了,这次控制传输并没有DATA transaction阶段,也并不需要urb提供什么transfer_buffer缓冲区,所以transfer_buffer应该传递一个NULL,当然transfer_buffer_length也就为0了,有意思的是这时候传递进来的结束处理函数usb_api_blocking_completion,可以看一下当这次控制传输已经完成,设备地址已经设置好后,接着做了些什么,它的定义在drivers/usb/core/message.c里
21 static void usb_api_blocking_completion(struct urb *urb)
22 {
23         complete((struct completion *)urb->context);
24 }
这个函数更简洁,就那么一句,没有前面说的释放urb,也没有重新提交它,本来就想设置个地址就完事儿了,没必要再将它提交给HCD,你就是再提交多少次,设置多少次,也只能有一个地址,usb的世界里不提倡囤积居奇,不鼓励一人多个Address去炒。那在这仅仅一句里面都做了些什么?你接着往下看。
然后就是第三个基本点,usb_start_wait_urb函数,将前面历经千辛万苦创建和初始化的urb提交给咱们的usb core,让它移交给特定的主机控制器驱动进行处理,然后望眼欲穿的等待HCD回馈的结果,如果等待的时间超过了预期的限度,它不会再等,不会去变成望夫石。它在message.c里定义
27 /*
28 * Starts urb and waits for completion or timeout. Note that this call
29 * is NOT interruptible. Many device driver i/o requests should be
30 * interruptible and therefore these drivers should implement their
31 * own interruptible routines.
32 */
33 static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length)
34 {
35         struct completion done;
36         unsigned long expire;
37         int status;
39         init_completion(&done);        
40         urb->context = &done;
41        urb->actual_length = 0;
42         status = usb_submit_urb(urb, GFP_NOIO);
43         if (unlikely(status))
44                 goto out;
46         expire = timeout ? msecs_to_jiffies(timeout) : MAX_SCHEDULE_TIMEOUT;
47         if (!wait_for_completion_timeout(&done, expire)) {
49                 dev_dbg(&urb->dev->dev,
50                         "%s timed out on ep%d%s len=%d/%d/n",
51                         current->comm,
52                         usb_pipeendpoint(urb->pipe),
53                         usb_pipein(urb->pipe) ? "in" : "out",
54                         urb->actual_length,
55                         urb->transfer_buffer_length);
57                 usb_kill_urb(urb);
58                 status = urb->status == -ENOENT ? -ETIMEDOUT : urb->status;
59         } else
60                 status = urb->status;
62         if (actual_length)
63                 *actual_length = urb->actual_length;
65         usb_free_urb(urb);
66         return status;
67 }
35行,定义了一个struct completion结构体。completion是内核里一个比较简单的同步机制,一个线程可以通过它来通知另外一个线程某件事情已经做完了。你使用某个下载软件去下载A片,然后撇一边儿不管就去忙着聊QQ泡mm了,下载完了那个软件会通知你,然后你想怎么做就怎么做,自个看也成,不怕被扁和正在聊的mm一块看也成,没人会去管你。怎么?你的那个软件下载完了也没通知你?那就紧赶的换个别的吧,写那个软件的也太没职业道德了,该做的事情不做。completion机制也同样是这么回事儿,你的代码执行到某个地方,需要再忙点儿其它的,就新开个线程,让它去忙活,然后自个接着忙自己的,想知道那边儿忙活的结果了,就停在某个地方等着,那边儿忙活完了会通知一下已经有结果了,于是你的代码又可以继续往下走。
completion机制围绕struct completion结构去实现,有两种使用方式,一种是通过DECLARE_COMPLETION宏在编译时就创建好struct completion的结构体,另外一种就是上面的形式,运行时才创建的,先在35行定义一个struct completion结构体,然后在39行使用init_completion去初始化。光是创建struct completion的结构体没用,关键的是如何通知任务已经完成了,和怎么去等候完成的好消息。片子下载完了可能会用声音、对话框等多种方式来通知你,同样这里用来通知已经完成了的函数也不只一个,
      void complete(struct completion *c);
      void complete_all(struct completion *c);
complete只通知一个等候的线程,complete_all可以通知所有等候的线程,大家都一个宿舍的好兄弟,你总不好意思自己藏着好东西,不让大家欣赏吧,所以可能会有多个人来等着片子下完。
你不可能会毫无限度的等下去,21世纪最缺的是什么?耐心,凡事都有个限度,即使片子再精彩,多会儿下不完也不等它了,当然会有比我还穷极无聊的人愿意一直在那里等着,毕竟林子大了什么鸟儿都有,或者说正等着那,一个ppmm过来打断你,你赶着花前月下去了,也不会去继续等了。所以针对不同的情况,等候的方式就有好几种,都在kernel/sched.c里定义
      void wait_for_completion(struct completion *c);
      unsigned long wait_for_completion_timeout(struct completion *x, unsigned long timeout);
      int wait_for_completion_interruptible(struct completion *x);
      unsigned long wait_for_completion_interruptible_timeout(struct completion *x, unsigned long timeout);
上面47行使用的就是wait_for_completion_timeout,设定一个时间限度,然后在那里候着,直到得到通知,或者超过时间。既然有等的一方,也总得有通知的一方吧,不然岂不是每次都超时?写代码的哥们儿没这么变态,记得上面刚出现过的那个结束处理函数usb_api_blocking_completion不?不是吧,被窝都热乎着就不认人了啊,它里面唯一的一句complete就是用来通知这里的47行的。有疑问的话看40行,将刚刚初始过的struct completion结构体done的地址赋值给了urb,47行等的就是这个done。再看42行,usb_submit_urb函数将这个控制urb提交给usb core,它是异步的,也就是说提交了之后不会等到传输完成了才返回。->context((struct completion *)urb->context)
现在就比较清晰了,usb_start_wait_urb函数将urb提交给usb core去处理后,就停在47行等候usb core和HCD的处理结果,而这个urb代表的控制传输完成之后会调用结束处理函数usb_api_blocking_completion,从而调用complete来通知usb_start_wait_urb说不用再等了,传输已经完成了,当然还有种可能是usb_start_wait_urb已经等的超过了时间限度仍然没有接到通知,不管是哪种情况,usb_start_wait_urb都可以不用再等,继续往下走了。
下边儿挨个说一下,42行,提交urb,并返回一个值表示是否提交成功了,显然,成功的可能性要远远大于失败的可能性,不然就是或者写代码的哥们儿有问题,或者就是我有问题,所以接下来的判断加上了unlikely,如果你真的那么衰,遇上了小概率事件,那也就没必要在47行等通知了,直接到后边儿去吧。
46行,计算超时值。超时值在参数里不是已经给了么,还计算什么?没错,你是在参数里是指定了自己能够忍受的最大时间限度,不过那是以ms为单位的,作为一个平头小百姓,咱们的时间概念里也只有分钟啊妙啊毫秒啊什么的,不过作为一个要在linux里混的平头小百姓,咱们的时间概念里必须得加上一个号称jiffy的东东,因为函数wait_for_completion_timeout里的超时参数是必须以jiffy为单位的。
jiffy,金山词霸告诉我们,是瞬间,短暂的时间跨度,短暂到什么程度?linux里它表示的是两次时钟中断的间隔,时钟中断是由定时器周期性产生的,关于这个周期,内核里有个巨直白巨形象的变量来描述,就是HZ,它是个体系结构相关的常数。内核里还提供了专门的计数器来记录从系统引导开始所度过的jiffy值,每次时钟中断发生时,这个计数器就增加1。
既然你指定的时间和wait_for_completion_timeout需要的时间单位不一致,就需要转换一下,msecs_to_jiffies函数可以完成这个工作,它将ms值转化为相应的jiffy值。这一行里还剩个MAX_SCHEDULE_TIMEOUT比较陌生,在include/linux/sched.h里它被定义为LONG_MAX,最大的长整型值,我知道你会好奇这个LONG_MAX是怎么来的,好奇就说出来嘛,好奇又不会真的害死猫,我也很好奇,所以咱们到生它养它的include/linux/kernel.h里看看
23 #define INT_MAX         ((int)(~0U>>1))
24 #define INT_MIN         (-INT_MAX - 1)
25 #define UINT_MAX        (~0U)
26 #define LONG_MAX        ((long)(~0UL>>1))
27 #define LONG_MIN        (-LONG_MAX - 1)
28 #define ULONG_MAX       (~0UL)
29 #define LLONG_MAX       ((long long)(~0ULL>>1))
30 #define LLONG_MIN       (-LLONG_MAX - 1)
31 #define ULLONG_MAX      (~0ULL)
各种整型数的最大值最小值都在这里了,俺现在替谭浩强再普及点基础知识,‘~’是按位取反,‘UL’是无符号长整型,那么‘ULL’就是64位的无符号长整型,‘<<’左移运算的话就是直接一股脑的把所有位往左边儿移若干位,‘>>’右移运算比较容易搞混,主要是牵涉到怎么去补缺,有关空缺儿的事情在哪里都会比较的复杂,勾心斗角阶级斗争的根源,在C里主要就是无符号整数和有符号整数的之间的冲突,在你补管三七二十一一直往右移多少位之后,空出来的那些空缺,对于无符号整数得补0,对于有符号的,得补上符号位。
还是拿LONG_MAX来说事儿,上边定义为((long)(~0UL>>1)),0UL按位取反之后全为1的无符号长整型,向右移1位,左边儿空出来的那个补0,这个数对于无符号的long来说不算什么,但是再经过long这么强制转化一下变为有符号的长整型,它就是老大了。每个老大的成长过程都是一部血泪史,都要历经很多曲折。
现在你可以很明白的知道写代码的哥们儿在46行都做了些什么,你指定的超时时间被转化为相应的jiffy值,或者直接被设定为最大的long值。
47行,等待通知,我们需要知道的是怎么去判断等待的结果,也就是wait_for_completion_timeout的返回值代表什么意思?一般来说,一个函数返回了0代表了好消息,一切顺利,如果你这么想那可就错了。wait_for_completion_timeout返回0恰恰表示的是坏消息,表示直到超过了自己的忍耐的极限仍没有接到任何的回馈,而返回了一个大于0的值则表示接到通知了,那边儿不管是完成了还是出错了总归是告诉这边儿不用再等了,这个值具体的含义就是距你设定的时限提前了多少时间。为什么会这样?你去看看wait_for_completion_timeout的定义就知道了,我就不贴了,它是通过schedule_timeout来实现超时的,schedule_timeout的返回值就是这么个意思。
那么现在就很明显了,如果超时了,就打印一些调试信息提醒一下,然后调用usb_kill_urb终止这个urb,再将返回值设定一下。如果收到了通知,就简单了,直接设定了返回值,就接着往下走。
62行,actual_length是用来记录实际传输的数据长度的,是上头儿的上头儿usb_control_msg需要的。不要给我说这个值urb里本来就有保存,何必再多次一举找个地儿去放,没看接下来的65行就用usb_free_urb把这个urb给销毁了啊,到那时花非花树非树,urb也已经不是urb,哪里还去找这个值。actual_length是从上头儿那里传递过来的一个指针,写内核的哥们儿教导我们,遇到指针一定要小心再小心啊,同志们。所以这里要先判断一下actual_length是不是空的。
 
现在,只剩一个usb_submit_urb在刚才被有意无意的飘过了,咱们下面说。
 
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/fudan_abc/article/details/1822034

Linux驱动之USB设备驱动

-
  • 1970年01月01日 08:00

USB 驱动程序开发之几个重要函数分析

  下面介绍的函数都出自以下的Linux源码文件:driver/usb/core/message.c  该文件内包含许多关于同步信息处理的函数,具体内容在文件中都有注释介绍,该处我只选择在USB驱动程...
  • WInScar
  • WInScar
  • 2011-04-09 23:50:00
  • 2697

Linux USB设备驱动程序设计 和 USB下载线驱动设计

Linux USB设备驱动程序设计 和 USB下载线驱动设计
  • qq_36016407
  • qq_36016407
  • 2017-09-07 21:41:19
  • 293

urb分析,usb_fill_bulk_urb函数理解

usb request block,简称urb。事实上,可以打一个这样的比喻,usb总线就像一条高速公路,货物、人流之类的可以看成是系统与设备交互的数据,而urb就可以看成是汽车。在一开始对USB规范...
  • liangxiaozhang
  • liangxiaozhang
  • 2012-12-19 15:25:25
  • 2524

usb中urb相关接口函数

一. 简介              usb总线是一种轮询式总线,协议规定所有的数据传输都必须由主机发起,usb主机与设备之间是通过管道(pipe)传输的,管道两边分别对应主机中的数据缓冲区和设备侧...
  • fanqipin
  • fanqipin
  • 2012-12-05 17:46:02
  • 4464

USB URB

URB定义:usb 请求块(usb request block, urb)是usb设备驱动中用来描述与usb设备通信所用的基本载体和核心数据结构,非常类似于网络设备驱动中的sk_buff结构体,是us...
  • lidaqiang99
  • lidaqiang99
  • 2011-07-07 18:11:10
  • 10488

Linux那些事儿 之 戏说USB(26)设备的生命线(五)

人的一生就象在拉屎,有时你已经很努力了可出来的只是一个屁。看这内核代码也一个样,已经很努力了,俺的葱葱玉指都磨出茧子了,才勉勉强强把struct urb这个中心给说完,下面接着看那三个基本点。看之前,...
  • fudan_abc
  • fudan_abc
  • 2007-10-12 16:11:00
  • 12360

USB驱动函数总结

pipe 管道   管道是USB设备通信的通道,内核中提供了创建管道的宏,从宏中我们可以分析出,管道是一个 int 型的变量,由设备号、端点地址、端点类型组合而成。 usb_[snd|rcv...
  • lizuobin2
  • lizuobin2
  • 2016-11-18 20:46:47
  • 1315

Linux那些事儿 之 戏说USB(22)设备的生命线(五)

下面接着看那三个基本点。 第一个基本点,usb_alloc_urb函数,创建urb的专用函数,为一个urb申请内存并做初始化,在drviers/usb/core/urb.c里定义。 struct ur...
  • zhqh100
  • zhqh100
  • 2015-03-25 19:04:57
  • 740

USB设备被识别流程

USB模块包括usb core,host,hub,device驱动,其中hub会启动一个内核线程名曰:khubd(hub_events一直在查询(hub使用的是中断传输), 当usb 设备连接在 hu...
  • MyArrow
  • MyArrow
  • 2012-12-12 15:31:37
  • 10468
收藏助手
不良信息举报
您举报文章:Linux那些事儿 之 戏说USB(26)设备的生命线(五)
举报原因:
原因补充:

(最多只允许输入30个字)