856 scsi_host_put(us->host); 857 858 /* Free the extra data and the URB */ 859 if (us->extra) 860 kfree(us->extra); 861 if (us->current_urb) 862 usb_free_urb(us->current_urb); 863 864 } 865 866 /* Dissociate from the USB device */ 867 static void dissociate_dev(struct us_data *us) 868 { 869 US_DEBUGP("-- %s\n", __FUNCTION__); 870 871 /* Free the device-related DMA-mapped buffers */ 872 if (us->cr) 873 usb_buffer_free(us->pusb_dev, size<strong>of</strong>(*us->cr), us->cr, 874 us->cr_dma); 875 if (us->iobuf) 876 usb_buffer_free(us->pusb_dev, US_IOBUF_SIZE, us->iobuf, 877 us->iobuf_dma); 878 879 /* Remove our private data from the interface */ 880 usb_set_intfdata(us->pusb_intf, NULL); 881 882 /* Free the structure itself */ 883 kfree(us); 884 } 823 行,判断us 的pid,这个pid 是哪来的?很显然,usb_stor_release_resources 和咱们前面说过的 usb_stor_acquire_resources 函数是一对,us->pid 也正是来自usb_stor_acquire_resources()函 数, 当时在调用kernel_thread 启动usb_stor_control_thread 的时候,记下了kernel_thread()的返回值, 并把她赋给了us->pid,实际上kernel_thread()对于父进程来说,返回值就是子进程的pid,也就是说当年 创建的精灵进程的pid 是被记录下来了的.写代码的人老辣的编程功底可见一斑. 840 行,设置us->srb 为NULL. 197 844 行和845 行,up(&us->sema),以及wait_for_completion(&us->notify),知道这两句干嘛的吗? 还记得usb_stor_control_thread(),当初讲到down_interruptible(&us->sema),咱们就说该守护进 程进入了睡眠,那么谁能把她唤醒,除了前面讲的queuecommand 之外,这里同样也是唤醒她的代码,并且 这个函数在唤醒别人之后,自己执行wait_for_completion 函数来进入等待.好,再次回到那个函数 吧,usb_stor_control_thread(),303 行,被up()唤醒的down_interruptible 返回0.然后312 行到 316 行的这个if 小段当然就会执行了,因为us->srb 这时候毫无疑问,等于NULL,所以break 会被执行,从而结
束for 死循环,从而usb_stor_control_thread 函数到了最后一行,最终调用 complete_and_exit(&(us->notify),0)来结束精灵进程自己并且唤醒我们这里的进入等待的 usb_stor_release_resources.很显然,这里两个进程通过四个函数,或者说两个组合,来实现了进程的同 步,这正是Linux 中内核同步机制的典型应用.(两大组合指的是:up 和down,wait_for_completion 和 complete.) 继续往下,849 行,struct us_data 还有一个元素,extra_data_destructor extra_destructor,这是一 个函数指针,实际上对某些设备来说,她们自己定义了一些额外的函数,在退出之前需要执行,比如Datafab USB 紧凑读卡器,不过像这样的变态的设备很少,对于大多数设备来说,这个函数指针都为空.如果定义了, 那么就去执行她. 然后856 行,scsi_host_put,只是对这个host 的引用计数减1,如果该host 的引用计数达到0 了,那么 将释放其对应的<strong>Scsi</strong>_Host 数据结构所占的空间.一个scsi 卡在其调用scsi_host_alloc 的时候会被设 置 引用计数为1,引用计数就是表征有多少进程使用了这个资源,我记得外企面试的时候也常常会问到这 个,2005年初,大四下的时候,去张江软件科技园,参加SAP的面试,当时谈到一个无盘工作站的话题,面试官 就问我,既然客户端都没有硬盘,那么如果多个人同时读写服务器上的同一个文件,那岂不是乱套了,当时这 个问题一问我就傻了.后来想想,也许这个和引用计数用点关系吧,再用上那个所谓的写拷贝 (copy-on-write)技术.不过我还是挺喜欢SAP,可惜,人家看不上我. 接下来859 行,判断us->extra,us->extra 就是为前面那个extra_data_destructor 函数准备的参数, 一般不会申请,如果申请过,那就释放她. 再接下来,current_urb 也没用了,释放吧.释放urb 需要调用专门的函数usb_free_urb,她来自 drivers/usb/core/urb.c 中. 到这里咱们前面占有的资源基本上就释放掉了. 再看下一个函数,dissociate_dev(),很显然,这个函数和咱们前面讲的associate_dev()函数是一对.在 associate_dev 函数中,咱们调用了usb_buffer_alloc()函数,先后为us->cr 和us->iobuf 分配了空 间, 所以这里首先调用相对应的函数usb_buffer_free()来释放这两段空间,然后,然后咱们曾经调用 usb_set_intfdata 来令us->pusb_intf 的所对应的设备的driver_data 指向了us,所以这里 usb_set_intfdata()再次调用从而让us->pusb_intf 的driver_data 指向空.最后,调用kfree 释放us. 好了,终于,世界清静了. 最后的最后,我们还有一点点内容要讲,那就是分析一下我们故事中的锁机制,至少我们曾经承诺过,要到 最后才能讲锁机制,理由很简单,只有我们把整个故事都弄明白了,我们才可能弄清楚为什么在某个地方要加 锁,因为锁机制永远都是牵连着多处的代码的,它不是一个人在战斗! 198 其实世上本有路,走的人多了,也便没了路 其实信号量这东西,就像北京户口,你占了一个名额,我就可能没有了名额.但是有些事情,没有北京户口你 又办不成.比如我满怀壮志的走到医院向医生表达说我希望死了以后可以捐献遗体,可得到的只是医生冷冷 的回复,对不起,你没有资格,因为你没有户口. 我们前面说过,Linux 中,有信号量,有自旋锁,有互斥锁,自旋锁或者互斥锁从某种意义上来说就只是一种 特殊的信号量,即信号量意味着资源数量有限,但这个有限也许可能比如像每年的北京户口的名额,有若干 个, 而锁反映的就是更加有限,限制到了数量为一,即类似于所谓的一夫一妻制.她只属于你一个人,一旦你占有 了她,如果别人还要想得到她,除非你释放.或者说除非你抛弃了她.
- 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 and 72:
802 int number_of_packets; /* (in)
- Page 73 and 74:
先说互斥锁.它诞生于这样
- 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: associate_dev()相对应.我们来
- Page 197 and 198: 317 for (i = 1; i < us->host->max_i