以海洋广阔无边;而这个函数支持各种传输,作为usb-storage 模块,无论其采用何种传输方式,无论传输数 据量的多少,最终都一定要调用这个函数,所以我们必须承认这个函数很伟大. 鉴于这个函数的重要性,它适用于各种信息的传送,而不仅仅是控制传送,日后在bulk 传输中我们还将遇 上它,我们将在下一节专门来分析.但是在看这个函数之前,有些事情必须要心里有数,那就是作为设备驱动 程序,只需要提交一个urb 就可以了,剩下的事情usb core 会去处理,有了结果它会通知我们.而提交 urb,usb core 为我们准备了一个函数,usb_submit_urb()不管我们使用什么传输方式,我们都只要调用 这 个函数即可,在此之前,我们需要做的只是准备好这么一个urb,把urb 中各相关的成员填充好,然后就ok 了. 而这usb_stor_msg_common 正是这样做的.而显然,不同的传输方式其填写urb 的方式也不同. 最后我们需要指出一点,这里我们的cr 是一个指针,有同志会问这个指针申请过内存了吗?答案是肯定的, 忆往昔峥嵘岁月,曾几何时,我们在函数associate_dev()中就见到了us->cr,并且用usb_buffer_alloc 为其申请了内存,当时我们就讲过的. 80 第一次亲密接触(三) 让我们单刀直入,进入usb_stor_msg_common()函数. 首先看145 行,让us->flags 和ABORTING_OR_DISCONNECTING 相 与,ABORTING_OR_DISCONNECTING 宏定义于drivers/usb/storage/usb.h 中: 78 /* Dynamic flag definitions: used in set_bit() etc. */ 79 #define US_FLIDX_URB_ACTIVE 18 /* 0x00040000 current_urb is in use */ 80 #define US_FLIDX_SG_ACTIVE 19 /* 0x00080000 current_sg is in use */ 81 #define US_FLIDX_ABORTING 20 /* 0x00100000 abort is in progress */ 82 #define US_FLIDX_DISCONNECTING 21 /* 0x00200000 disconnect in progress */ 83 #define ABORTING_OR_DISCONNECTING ((1UL
25 { 26 x->done = 0; 27 init_waitqueue_head(&x->wait); 28 } 她只是调用了init_waitqueue_head 去初始化一个等待队列.而struct completion 的定义也在上面已 经列出.关于init_waitqueue_head 咱们将在下面的故事中专门进行描述. 而接下来,都是在设置us 的current_urb 结构,咱们看161 行,transfer_flags 被设置成了 URB_ASYNC_UNLINK | URB_NO_SETUP_DMA_MAP,其中URB_ASYNC_UNLINK 表明 usb_unlink_urb()函数将被异步调用,不懂异步调用也没有关系,因为内核的发展是如此的迅速,这一点完 全可以和上海的发展速度有得一拼,最新的内核中,人们已经很少用这个宏了,因为usb_unlink_urb已经是 81 异步调用的函数了,如果是同步调用,则可以使用另一个函数usb_kill_urb().这两个函数的作用就是取消 一个urb 请求.同步调用用于这样一种情况,即函数执行过程中可以进入睡眠,满足一定条件再醒来继续执 行, 而异步调用则不会睡眠,那么这里之所以要设置URB_ASYNC_UNLINK,其目的就在于让 usb_unlink_urb 是异步的执行,原因是,有的时候我们取消一个urb request 的时候是处在一种不能睡 眠 的上下文,比如后面我们会看到的处理超时的函数.我们在互联网上下载一个很大文件的时候,常常会遇到超 时的情况,然后我们的请求就被中止了.对于usb 系统同样有这个问题,我们会给一个urb 设置超时,提交上 去到了一定时间还没能传输好的话就意味着可能传输有问题,这种情况我们通常也会把这个urb 给取消掉. 于是这里有两种情况,第一,我们提交了urb 之后就不管事了,我们等待,怎么等待?睡眠,我们的进程进入睡 眠,换句话说在我们这个上下文情景中也就是storage_probe 函数睡了.如果不超时,那么万事大吉,urb 执 行完了之后我们的进程被唤醒,继续往下走.那么天下平安.但是第二种情况是,我们进入了睡眠,可是时间到 了,urb 还没有执行完,那么超时函数会被执行,它就会去取消这个urb,如果说这个超时函数也可以睡眠,那 就不得了了,天下大乱了,都睡了,谁干活?整个驱动不就瘫痪了!所以,这种情况下我们要调用的函数是不能 睡眠的,也就是说必须是异步的.而usb_unlink_urb 内部会通过判断是否有URB_ASYNC_UNLINK 这 么 一个flag 被设置在了urb->transfer_flags 中,来选择是异步执行还是同步执行,实际上它的同步执行就 是 调用usb_kill_urb 而已.不过刚才说的,最新版的内核,比如2.6.21,它里边就把这两个函数彻底分开了,不 用设这么一个flag,usb_unlink_urb 就是异步,usb_kill_urb 就是同步. 而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.(157至160的注释表明,只要transfer_buffer 被赋了值,那就假设有DMA缓冲区需要传输, 于是就去设URB_NO_TRANSFER_DMA_MAP.)关于DMA 这一段,因为比较难理解,所以我们多说几句. 首先,这里是两个DMA 相关的flag,一个是URB_NO_SETUP_DMA_MAP,而另一个是 URB_NO_TRANSFER_DMA_MAP.主意这两个是不一样的,前一个是专门为控制传输准备的,因为只有控 制传输需要有这么一个setup 阶段需要准备一个setup packet.而我们把让setup_packet 指向了
- 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: 830 void *transfer_buffer, 831 int
- 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