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

时间:2021-03-24 14:34:55

 

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给清掉,否则设别没有办法工作了.

本文出自 “专注嵌入式多媒体技术” 博客,请务必保留此出处http://zyg0227.blog.51cto.com/1043164/550307