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