是一种时尚.我常常对自己说,如果哪一天我没有闯红灯,那么由此可以推导出来,这一天我一定没有出门.同 样,在usb 的世界中,设备也总是那么的不守规矩,我们必须要设计一个东西出来管理来控制所有的usb 设 备的通信,这样,主机控制器就横空出世了. 那么设备和主机控制器的分工又是如何呢?硬件实现上我们就不说了,说点具体的,Linux 中,设备驱动 程序只要为每一次请求准备一个urb 结构体变量,把它填充好,(就是说赋上该赋的值)然后它调用usb core 提供的函数,把这个urb 传递给host controller,host controller 就会把各个设备驱动程序所提交的urb 统一规划,去执行每一个操作.而这期间,usb 设备驱动程序通常会进入睡眠,而一旦host controller 把urb 要做的事情给做完了,它会调用一个函数去唤醒usb 设备驱动程序,然后usb 设备驱动程序就可以继续往 下 走了.这又好比我们学校里的师生关系.考试的时候,我们只管把试卷填好,然后我们交给老师,然后老师拿去 批改试卷,这期间我们除了等待别无选择,等待老师改完了试卷,告诉了我们分数,我们又继续我们的生活.当 然了,如果成绩不好,也许有些人的生活就不会继续了,在复旦,我们可以选择去曾经的绝情谷上吊,可以选择 去第四教学楼顶层跳下来,在交大,则可以去跳思源湖.同样,usb 设备驱动程序也是如此,如果urb 提交给 usb host 了,但是最终却没有成功执行,那么也许该usb 设备驱动程序的生命也就提前结束.不过这都是后 话,现在只要有个感性认识即可,稍后看到了就能更深刻的体会了,这种岗位分工的方式给我们编写设备驱动 程序带来了巨大的方便. 心锁 如果大家没意见的话,我们继续usb_stor_acquire_resources 函数. 761 至764 行,这没啥好说的吧.就是刚才urb 申请了之后判断是否申请成功了,如果指针为NULL 那么 就是失败了.直接返回-ENOMEM.别往下了. 767 行,哦,又一个家伙闪亮登场了,dev_semaphore,这是一个信号量,在storage_probe 的最初始阶 段我们曾经见过,当时有这么一句话,这就是调用一个宏init_MUTEX 来初始化一个信号量, 943 init_MUTEX(&(us->dev_semaphore)); 我们当时说了,等到用的时候再讲.不过现在的确是到用的时候了,不过,我还不想讲.曾经我天真的以为, 只要学了谭浩强的那本C 程序设计,即便不能写代码,也应该能够看懂代码.然而,后来我发现事实并非如此, 世界没错,我错了. 70 首先,什么是信号量?毕业的时候,校园招聘中常常笔试面试会考信号量,会考死锁,不过通常考的会比较 简单,更多的情况是考察一些基本概念,印象中曾经在Sun 中国工程研究院的面试中被问起过,当然也有比 较复杂一点的,要求结合具体的问题对某种算法进行合理性分析,比如Intel 某年在上海交大的笔试题,考到 了经典的哲学家进餐问题,不过幸运的是这种变态的笔试题我没遇上,我进Intel 的时候只被问起解释冒泡 排序法... 我们整个故事中有两个信号量,它们都是us 的成员,一个是这个dev_semaphore,另一个是sema,在 定义struct us_data 的时候我们已经看到过, 111 struct semaphore dev_semaphore; /* protect pusb_dev */ 156 struct semaphore sema; /* to sleep thread on */ sema 也同样是在storage_probe 的一开始就做了初始化, 944 init_MUTEX_LOCKED(&(us->sema)); 设备驱动中最难的部分在于三个方面,一个是涉及到内存管理的代码,一个是涉及到进程管理的代码,另一 个就是信号量和互斥锁或者别的锁的代码.这些部分如果不合理将容易导致系统崩溃,而信号量最容易导致 的就是死锁. 网名为卖血上网的哥们说话了,那么到底什么是信号量?或者什么是互斥锁?
先说互斥锁.它诞生于这样一个背景.这个世界上,有些东西只能属于某一个人,或者说在一个时间里只能 属于一个人,这你承认吧,比如一个女孩的心.当你要追求一个女孩时,你首先会去了解其人是否名花有主,若 是否,你才会去追求,若已然有主,那么你只能放弃,或者准确的说,你只能等待.当然你可以很激昂的说,如果 等待可以换来奇迹的话,我宁愿等下去,哪怕一年,抑或一生!然而,她爱的是他,终究不是你,所以你伤悲,流 泪, 却打不开她心中那把锁.这里你应该就能感觉到什么是互斥锁了,一个女孩如果心有所属,那么对你来说,就 仿佛已有人在你之前给她上了一把锁,而钥匙,不在你这里. 那么你问代码中为什么要锁?Ok,我告诉你,如果你正在操作一个队列,比如一个队列一百个元素,你想把 第七十个读出来,于是你去遍历这个队列,可是如果没有锁,那么可能你遍历的时候别人也可以操作这个队 列, 比如你马上就要找到第七十个了,可是,可是,注意了,可是,这个时候,说不定哪位哥们儿缺德,把第七十个数 给删除了,那你不是白忙活了?所以,怎么办?设一个锁,每个人要想操作这个队列就得先获得这把锁,而一旦 你获得了这把锁,你在操作这把锁期间,别人就不能操作,因为他要操作他就得先获得锁,而这个时候锁在你 这里,所以他只能等待,等你结束了,释放了锁,他才可以去操作.那么互斥锁指的就是这种情况,一个资源只 能同时被一个进程操作,互斥的字面意思也正是如此.互相排斥,就像爱情是自私的一样. 那什么是信号量?信号量和互斥锁略有不同.它允许一个时间里有几个进程同时访问一段资源.到底允许 几个可以设定,这称为设定信号量的初值,如设定为1,那就说明是同一时间只有一个进程可以访问,那么这 就是互斥锁了,不过有的时候一个资源确实可以让几个进程访问,特别是读访问,你想一个文件可以被两个进 程同时读,这不要紧吧,各读各的,谁也影响不了谁,只要大家都不写就是了.设定信号量的初值,比如设定5, 那么就是说,同一时间你就让最多5 个进程同时去读这个文件.每个进程获取了信号量就把信号量的值减 一, 到第六个进程了,它去判断,发现值已经等于0 了,于是它不能访问了,只能等待,等待别的进程释放锁. 71 不过也许,一把钥匙只能开一把锁,更能代表爱情的专一.所以实际上,Linux 内核代码中锁用得更多,而初 值不为1 的信号量用得相对来说不多.比如我们刚才看到的这两个信号量,都是属于当作互斥锁在用.因为 他 们的初值一个被设置成了1(init_MUTEX),一个被设置成了0(init_MUTEX_LOCKED).设置成一很好理 解,就是一把互斥锁,只能容许一个进程去获得它,设置成0 呢,就表示这把锁已经被锁住了,得有进程释放它 才可以.我们这里767 行这句down(&us->dev_semaphore)和up(&us->dev_semaphore)是一对, 一个是获得锁,一个是释放锁.它们就是为了保护中间那段代码.我刚才说我不想讲这段代码,的确,现在讲为 什么这里要用锁还为时过早,整个故事中us->dev_semaphore 出现的次数不是很多,但是我们必须对整 个代码都熟悉了才可能理解为什么要用这把锁,因为这些代码都是环环相扣的,不能孤立来看.所以,我们将 在故事的收尾阶段来一次性来以高屋建瓴的方式看每一处down(&us->dev_semaphore)和 up(&us->dev_semaphore)的使用原因.接下来我们看到了这把锁的时候,也将一并跳过不提.到最后再 来看.需要说的是这里down 和up 这两个函数的作用分别就是去获得锁和释放锁.对于down 来说,它每 次 判断一下信号量的值是否大于0,若是,就进入下面的代码,同时将信号量的值减一,若否,就等待,或者说专业 一点,进入睡眠.对于down(),我们小时候那部的歌词很形象的描述了其行为, 男:挥剑问情,如果问是有情,也愿以身相许,以身相殉; 女:挥剑问情,如果问是无情,又怕回首别是一种伤心. 不过,我们这里看到了两把锁,除了us->dev_semaphore 以外,另一个是us->sema,现在还没有使用 它,但是我们可以先说一下,us->sema 在整个故事中出现的次数不多,总共只有三次.加上这里提到的这句 初始化为0 的语句,一个出现了四次.所以我们在遇到它的时候不需要跳过,会详细的讲.因为很容易理解它 为什么会用在那里.请你记住,这个信号量或者说这把锁是被初始化为0了,不是1,它一开始就处于锁住的状
- Page 1 and 2:
摘要 ............................
- Page 3 and 4:
迷雾重重的Bulk 传输(二)....
- Page 5 and 6:
引子 也许是在复旦养成了
- Page 7 and 8:
usb.h datafab.h dpcm.h initializers
- Page 9 and 10:
的Linux 内核划分为许许多
- Page 11 and 12:
目录下执行make 了.Ok,make 之
- Page 13 and 14:
只 是一个usb 接口.这些口
- Page 15 and 16:
中也定义了这么一些数据
- Page 17 and 18:
511 * @driver: the driver model cor
- Page 19 and 20:
233 .owner = THIS_MODULE, 234 .name
- Page 21 and 22: 91 * construct these entries. Each
- Page 23 and 24: 324 struct usb_host_config *actconf
- Page 25 and 26: 22 88 * @class_dev: driver model's
- Page 27 and 28: 必须给各个地方取名,完了
- Page 29 and 30: 26 136 trans_cmnd transport; /* tra
- Page 31 and 32: 944 init_MUTEX_LOCKED(&(us->sema));
- Page 33 and 34: 147 #if !defined(CONFIG_BLK_DEV_UB)
- Page 35 and 36: 124 #define USB_DEVICE_ID_MATCH_DEV
- Page 37 and 38: intf 来代替. us 之所以重要,
- Page 39 and 40: 睡眠,那就得用GPF_ATOMIC,这
- Page 41 and 42: 504 if (msg >= 0 && !(unusual_dev->
- Page 43 and 44: 179 } 180 181 static struct us_unus
- Page 45 and 46: 711 /* Submitted by Hartmut Wahl */
- Page 47 and 48: 3. useProtocol 为US_SC_DEVICE, use
- Page 49 and 50: Bus 004 Device 001: ID 0000:0000 Bu
- Page 51 and 52: 993 result = get_pipes(us); 994 if
- Page 53 and 54: 631 us->transport_reset = usb_stor_
- Page 55 and 56: 659 us->max_lun = 0; 660 break; 661
- Page 57 and 58: 740 /* Calculate and store the pipe
- Page 59 and 60: storage 会有两个bulk 端点,用
- Page 61 and 62: 比如说,复旦大学,有一个主
- Page 63 and 64: 1079 #define PIPE_ISOCHRONOUS 0 108
- Page 65 and 66: 782 us->unusual_dev->initFunction(u
- Page 67 and 68: 630 * each frame is in the fields o
- Page 69 and 70: 716 * Bulk URBs may 717 * use the U
- Page 71: 802 int number_of_packets; /* (in)
- Page 75 and 76: 920 US_DEBUGP("GetMaxLUN command re
- Page 77 and 78: 148 /* set up data structures for t
- Page 79 and 80: 90 * @wValue: matches the USB wValu
- Page 81 and 82: 830 void *transfer_buffer, 831 int
- Page 83 and 84: 25 { 26 x->done = 0; 27 init_waitqu
- Page 85 and 86: 都会过期,我开始怀疑,在这
- Page 87 and 88: 是实际长度,要么就是不成
- Page 89 and 90: 87 258 行,usb_pipeendpoint,定义
- Page 91 and 92: 对爱你的人掘了一条无法
- Page 93 and 94: Type: Direct-Access ANSI SCSI revis
- Page 95 and 96: 416 /* 417 * this defines our host
- Page 97 and 98: 69 * Ioctl interface 70 * 71 * Stat
- Page 99 and 100: 155 * "is this a new device" checks
- Page 101 and 102: 241 char *proc_name; 242 243 /* 244
- Page 103 and 104: 328 * True if the low-level driver
- Page 105 and 106: 可以看到这个函数的参数
- Page 107 and 108: 451 short unsigned int max_sectors;
- Page 109 and 110: 地 说明了为啥咱们要显式
- Page 111 and 112: usb_stor_acquire_resources()函数
- Page 113 and 114: 341 } 342 343 /* reject if target !
- Page 115 and 116: 内核的核心位置,kernel/exit.c
- Page 117 and 118: 1023 dissociate_dev(us); 1024 retur
- Page 119 and 120: 917 行,再次判断设备有没有
- Page 121 and 122: 181 182 /* fail the command if we a
- Page 123 and 124:
83 struct timer_list eh_timeout; /*
- Page 125 and 126:
123 两个scsi_done,一个是struct
- Page 127 and 128:
56 jiffie count on our counter, the
- Page 129 and 130:
中 看到如下的定义: UNUSUAL_
- Page 131 and 132:
269 memcpy(data+16, us->unusual_dev
- Page 133 and 134:
一切准备好了之后,我们就
- Page 135 and 136:
238 (sg->offset + *offset) & (PAGE_
- Page 137 and 138:
所以对于那些不能相应INQUI
- Page 139 and 140:
239 行对unsigned int sglen 赋值
- Page 141 and 142:
请求,所以这里就判断abort
- Page 143 and 144:
112 case GPCMD_READ_HEADER: what =
- Page 145 and 146:
到北京,每每只有在夜深人
- Page 147 and 148:
580 /* 581 * If we have a failure,
- Page 149 and 150:
666 memcpy(srb->cmnd, old_cmnd, MAX
- Page 151 and 152:
950 struct bulk_cb_wrap *bcb = (str
- Page 153 and 154:
1034 /* get the status again */ 103
- Page 155 and 156:
426 /* store the actual length of t
- Page 157 and 158:
后她会给host 返回一个CSW.CB
- Page 159 and 160:
296 } 297 298 US_DEBUGP("-- transfe
- Page 161 and 162:
491 * scatter-gather or not, and ac
- Page 163 and 164:
迷雾重重的 Bulk 传输(五) us
- Page 165 and 166:
然后把她赋给了result.而us->
- Page 167 and 168:
而bcs->Status,标志命令执行
- Page 169 and 170:
就必须设置US_FL_IGNORE_RESIDUE
- Page 171 and 172:
485 }; 486 这是一个字符数组
- Page 173 and 174:
srb->sense_buffer 里边的东西.S
- Page 175 and 176:
一个类似的函数,名叫usb_sto
- Page 177 and 178:
这种命令应该由mid level 来
- Page 179 and 180:
Disk /dev/sda: 146.1 GB, 1461631057
- Page 181 and 182:
through to the most significant bit
- Page 183 and 184:
1192 USB_TYPE_CLASS | USB_RECIP_INT
- Page 185 and 186:
315 行,scsi_report_device_reset(),
- Page 187 and 188:
285 US_DEBUGP("No reset during disc
- Page 189 and 190:
229 /* Wait for the aborted command
- Page 191 and 192:
两个函数中需要判断它,一
- Page 193 and 194:
associate_dev()相对应.我们来
- Page 195 and 196:
束for 死循环,从而usb_stor_con
- Page 197 and 198:
317 for (i = 1; i < us->host->max_i