usb_stor_probe1
{
init_waitqueue_head(&us->delay_wait);
INIT_DELAYED_WORK(&us->scan_dwork, usb_stor_scan_dwork);
}
usb_stor_probe2
{
queue_delayed_work(system_freezable_wq, &us->scan_dwork,delay_use * HZ);
}
}
static void usb_stor_scan_dwork(struct work_struct *work)
{
if (us->protocol == USB_PR_BULK && !(us->fflags & US_FL_SINGLE_LUN)) {
mutex_lock(&us->dev_mutex);
us->max_lun = usb_stor_Bulk_max_lun(us); //对于有多个LUN的设备,调用usb_stor_Bulk_max_lun()来获得max_lun。 mutex_unlock(&us->dev_mutex);
}
if (us->protocol == USB_PR_BULK && !(us->fflags & US_FL_SINGLE_LUN)) {
mutex_lock(&us->dev_mutex);
us->max_lun = usb_stor_Bulk_max_lun(us); //对于有多个LUN的设备,调用usb_stor_Bulk_max_lun()来获得max_lun。 mutex_unlock(&us->dev_mutex);
}
scsi_scan_host(us_to_host(us));
//执行scsi_scan_host()函数扫描,扫描然后就知道这个host或者说这个SCSI卡上面接了什么设备(这个只是模拟的SCSI卡),然后cat/proc/scsi/scsi才能看到您的U盘。
}
static void get_transport(struct us_data *us)
{
case USB_PR_BULK:
us->transport_name = "Bulk";
us->transport = usb_stor_Bulk_transport;
us->transport_reset = usb_stor_Bulk_reset;
break;
//us的transport_name被赋值为“Bulk”
transport被赋值为usb_stor_Bulk_transport
transport_reset被赋值为usb_stor_Bulk_reset。其中我们最需要记住us的成员transport和transport_reset是两个函数指针。这两个函数叫“钩子”函数。这两个赋值我们需要牢记,日后我们一定会用到它们,因为这正是我们真正的数据传输时调用的东西。
}
int usb_stor_Bulk_reset(struct us_data *us)
{
return usb_stor_reset_common(us, US_BULK_RESET_REQUEST,
USB_TYPE_CLASS | USB_RECIP_INTERFACE,
0, us->ifnum, NULL, 0);
}
EXPORT_SYMBOL_GPL(usb_stor_Bulk_reset);
static int usb_stor_reset_common(struct us_data *us,
u8 request, u8 requesttype,
u16 value, u16 index, void *data, u16 size)
{
//wait_event_interruptible_timeout()是一个宏,它代表着Linux中的一种等待机制,等待某个事件的发生,函数原型中,第1个参数是一个等待队列头,即wait_queue_head_t定义的变量,在内核中使用init_waitqueue_head()函数初始化这个等待队列,然后第3个参数是设置超时。比如这里设了5秒,这表示如果5秒到了,那么函数会返回0,不管其他条件如何。第2个参数是一种等待的条件,或者说等待的事件,如果条件满足了,那么函数也会返回,条件要是不满足,那么这个进程会进入睡眠,不过interruptible表明了信号可以把它中断。
wait_event_interruptible_timeout(us->delay_wait,
test_bit(US_FLIDX_DISCONNECTING, &us->dflags),
HZ*6);
test_bit(US_FLIDX_DISCONNECTING, &us->dflags),
HZ*6);
}
一旦进入睡眠,那么有三种情况:一种是wake_up或者wake_up_interruptible函数被另一个进程执行,从而唤醒它,第二种是信号中断它,第三种就是刚才讲的超时,时间到了,自然就会返回。
先判断US_FLIDX_DISCONNECTING这个flag有没有设置,如果没有设置才进入睡眠。在进入睡眠之后,如果5秒之内没有把U盘拔出来,那么5秒一到,函数返回0,继续往下走,如果在5秒之前拔出来U盘了,那么后来咱们会讲,storage_disconnect()函数会执行,它会设置US_FLIDX_DISCONNECTING这个flag,并且它会调用wake_up(&;us->scsi_scan_wait)来唤醒这里睡眠的进程,这样函数就会提前返回,不用等到5秒再返回了。总之不管条件满不满足,5秒之内肯定会返回,所以我们继续往下看。