您的位置:首页 > 运维架构 > Linux

读Linux那些事儿之我是U盘笔记(三)

2011-04-21 08:53 239 查看
10、 互斥锁:一个女孩如果心有所属,那么对你来说,就 仿佛已有人在你之前给她上了一把锁,而钥匙,不在你这里.(很形象哦)
互斥锁指的就是一个资源只能同时被一个进程操作,互斥的字面意思也正是如此.互相排斥,就像爱情是自私的一样
down和up这两个函数的作用分别就是去获得锁和释放锁.对于down来说,它每次判断一下信号量的值是否大于0,若是,就进入下面的代码,同时将信号量的值减一,若否,就等待,或者说专业一点,进入睡眠.
11、 作为设备驱动程序,只需要提交一个urb就可以了,剩下的事情usb core 会去处理,有了结果它会通知我们.而提交urb,usb core为我们准备了一个函数,usb_submit_urb()不管我们使用什么传输方式,我们都只要调用这个函数即可,在此之前,我们需要做的只是准备好这么一个urb,把urb中各相关的成员填充好,然后就ok了.而这usb_stor_msg_common正是这样做的.而显然,不同的传输方式其填写urb的方式也不同.
12、 URB_NO_SETUP_DMA_MAP表明:如果使用DMA传输,则urb中setup_dma指针所指向的缓冲区是DMA缓冲区,而不是setup_packet所指向的缓冲区接下来再或上URB_NO_TRANSFER_DMA_MAP则表明,如果本urb有一个DMA缓冲区需要传输,则该缓冲区是transfer_dma指针所指向的那个缓冲区,而不是transfer_buffer指针所指向的那一个缓冲区.换句话说,如果没设置这两个DMA的flag,那么usb core就会使用setup_packet和transfer_buffer作为数据传输的缓冲区,然后下面两行就是把us 的iobuf_dma和 cr_dma赋给了 urb的transfer_dma和setup_dma.;
注释表明,只要transfer_buffer被赋了值,那就假设有DMA缓冲区需要传输,于是就去设URB_NO_TRANSFER_DMA_MAP.
13、 usb_submit_urb:
这个函数参数一个是提交的urb,另外一个是GFP_NOIO,意思就是不能在申请内存的时候进行IO操作,目的是为了杜绝嵌套死循环;
14、 定时器
用init_timer()函数和add_timer()函数来真正实现设置闹钟init_timer()是初始化,然后
设置好之后调用add_timer 才能让闹钟生效
Jiffies:Linux内核中赫赫有名的全局变量,表示当前时间
HZ: 1秒
同步调用: 函数执行过程中可以进入睡眠,满足一定条件再醒来继续执行(usb_kill_urb)
异步调用:异步调用则不会睡眠(usb_unlink_urb)
定时器常规用法:
189 /* submit the timeout timer, if a timeout was requested */
struct timer_list to_timer;
190 if (timeout > 0)
{
191 init_timer(&to_timer);
192 to_timer.expires = jiffies + timeout;
193 to_timer.function = timeout_handler;
194 to_timer.data = (unsigned long) us;
195 add_timer(&to_timer);
}
202 /* clean up the timeout timer */
203 if (timeout > 0)
204 del_timer_sync(&to_time) //删除定时器
解释:在add_timer()之前,为to_timer.expires赋值为jiffies+timeout,to_timer.function赋值为timeout_handler,to_timer.data赋值为us.并利用us中的flag标志,这表示,超时时间点为当前时间加上一个timeout,(jiffies:Linux内核中赫赫有名的全局变量,表示当前时间),timeout咱们前面调用usb_stor_msg_common的时候给设置成了HZ,也就是1秒.当时间到了之后,timeout_handler函数会被执行,而us作为参数传递给她.;
15、 completion机制
completion是Linux中同步机制的一个很重要的结构体;
用法:首先我们要用init_completion初始化一个struct completion的结构体变量,然后调用wait_for_completion()这样当前进程就会进入睡眠,处于一种等待状态,而另一个进程可能会去做某事,当它做完了某件事情之后,它会调用complete()函数,一旦它调用这个complete函数,那么刚才睡眠的这个进程就会被唤醒.这样就实现了一种同步机制,或者叫等待机制
代码用法如下:
struct completion urb_done;
/* set up data structures for the wakeup system */
init_completion(&urb_done);
设置定时器后
198 /* wait for the completion of the URB */
199 wait_for_completion(&urb_done);
使进程休眠
最后用completion();函数去唤醒,这个函数在usb_fill_control_urb()中的入参里面可以看到;还记得在调用usb_fill_control_urb()填充 urb的时候咱们设置了一个urb->complete指针吗?当时咱们就看到了,urb->complete=usb_stor_blocking_completion,这相当于向usb host controller driver传达了一个信息.所以,当urb传输完成了之后,usb host controller会唤醒她,但不会直接唤醒她,而是通过执行之前设定的urb的 complete函数指针所指向的函数;
16、 usb_stor_clear_halt函数讲解
Halt是endpoint的feature; CLEAR FEATURE那是所有的usb设备都通用的,因为它是usb spec所规定的
实际上usb spec 规定了,对于设备的bulk端点,每当设备在reset 之后,需要清除halt这个feature然后端点才能正常工作;
注释里说得很清楚,有些变态的设备,它就是不跟你按常理出牌,人家能正常响应GetMaxLUN这个request,它偏要耍个性,就是不认spec,你发送GetMaxLUN请求过来,它不予回复,它出现STALL的特点,
什么是STALL?
其实就是Halt,端点挂起,或者通俗一点理解,就是死机了.所以,毫无疑问,我们要把这个halt给清掉,否则设别没有办法工作了.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  linux 职场 usb 休闲 driver