📄 usb-storage.c
字号:
for(;;) { siginfo_t info; int unsigned long signr; interruptible_sleep_on(&us->waitq); action = us->action; us->action = 0; /* FIXME: we need to examine placment of break; and * scsi_done() calls */ switch (action) { case US_ACT_COMMAND: /* bad device */ if (us->srb->target || us->srb->lun) { US_DEBUGP( "Bad device number (%d/%d) or dev 0x%x\n", us->srb->target, us->srb->lun, (unsigned int)us->pusb_dev); us->srb->result = DID_BAD_TARGET << 16; us->srb->scsi_done(us->srb); us->srb = NULL; break; } /* our device has gone - pretend not ready */ /* FIXME: we also need to handle INQUIRY here, * probably */ if (!us->pusb_dev) { if (us->srb->cmnd[0] == REQUEST_SENSE) { memcpy(us->srb->request_buffer, sense_notready, sizeof(sense_notready)); us->srb->result = DID_OK << 16; } else { us->srb->result = (DID_OK << 16) | 2; } us->srb->scsi_done(us->srb); us->srb = NULL; break; } /* we've got a command, let's do it! */ US_DEBUG(us_show_command(us->srb)); /* FIXME: this is to support Shuttle E-USB bridges, it * appears */ if (us->srb->cmnd[0] == START_STOP && us->pusb_dev->descriptor.idProduct == 0x0001 && us->pusb_dev->descriptor.idVendor == 0x04e6) us->srb->result = DID_OK << 16; else { us->proto_handler(us->srb, us); } US_DEBUGP("scsi cmd done, result=0x%x\n", us->srb->result); us->srb->scsi_done(us->srb); us->srb = NULL; break; case US_ACT_ABORT: break; case US_ACT_DEVICE_RESET: break; case US_ACT_BUS_RESET: break; case US_ACT_HOST_RESET: break; } /* end switch on action */ if (signal_pending(current)) { /* sending SIGUSR1 makes us print out some info */ spin_lock_irq(¤t->sigmask_lock); signr = dequeue_signal(¤t->blocked, &info); spin_unlock_irq(¤t->sigmask_lock); if (signr == SIGUSR2) { usb_stor_debug = !usb_stor_debug; printk(USB_STORAGE "debug toggle = %d\n", usb_stor_debug); } else { break; /* exit the loop on any other signal */ } } } // MOD_DEC_USE_COUNT; printk("usb_stor_control_thread exiting\n"); /* FIXME: this is a hack to allow for debugging */ // scsi_unregister_module(MODULE_SCSI_HA, us->htmplt); return 0;} /* Probe to see if a new device is actually a SCSI device */static void * storage_probe(struct usb_device *dev, unsigned int ifnum){ struct usb_interface_descriptor *interface; int i; char mf[32]; /* manufacturer */ char prod[32]; /* product */ char serial[32]; /* serial number */ struct us_data *ss = NULL; unsigned int flags = 0; GUID(guid); /* Global Unique Identifier */ struct us_data *prev; Scsi_Host_Template *htmplt; int protocol = 0; int subclass = 0; struct usb_interface_descriptor *altsetting = &(dev->actconfig->interface[ifnum].altsetting[0]); /* clear the GUID and fetch the strings */ GUID_CLEAR(guid); memset(mf, 0, sizeof(mf)); memset(prod, 0, sizeof(prod)); memset(serial, 0, sizeof(serial)); if (dev->descriptor.iManufacturer) usb_string(dev, dev->descriptor.iManufacturer, mf, sizeof(mf)); if (dev->descriptor.iProduct) usb_string(dev, dev->descriptor.iProduct, prod, sizeof(prod)); if (dev->descriptor.iSerialNumber) usb_string(dev, dev->descriptor.iSerialNumber, serial, sizeof(serial)); /* let's examine the device now */ /* We make an exception for the shuttle E-USB */ if (dev->descriptor.idVendor == 0x04e6 && dev->descriptor.idProduct == 0x0001) { protocol = US_PR_CB; subclass = US_SC_8070; /* an assumption */ } else if (dev->descriptor.bDeviceClass != 0 || altsetting->bInterfaceClass != USB_CLASS_MASS_STORAGE || altsetting->bInterfaceSubClass < US_SC_MIN || altsetting->bInterfaceSubClass > US_SC_MAX) { /* if it's not a mass storage, we go no further */ return NULL; } /* At this point, we know we've got a live one */ US_DEBUGP("USB Mass Storage device detected\n"); /* Create a GUID for this device */ if (dev->descriptor.iSerialNumber && serial[0]) { /* If we have a serial number, and it's a non-NULL string */ make_guid(guid, dev->descriptor.idVendor, dev->descriptor.idProduct, serial); } else { /* We don't have a serial number, so we use 0 */ make_guid(guid, dev->descriptor.idVendor, dev->descriptor.idProduct, "0"); } /* Now check if we have seen this GUID before, and restore * the flags if we find it */ for (ss = us_list; ss != NULL; ss = ss->next) { if (!ss->pusb_dev && GUID_EQUAL(guid, ss->guid)) { US_DEBUGP("Found existing GUID " GUID_FORMAT "\n", GUID_ARGS(guid)); flags = ss->flags; break; } } /* If ss == NULL, then this is a new device. Allocate memory for it */ if (!ss) { if ((ss = (struct us_data *)kmalloc(sizeof(*ss), GFP_KERNEL)) == NULL) { printk(KERN_WARNING USB_STORAGE "Out of memory\n"); return NULL; } memset(ss, 0, sizeof(struct us_data)); } /* Initialize the us_data structure with some useful info */ interface = altsetting; ss->flags = flags; ss->ifnum = ifnum; ss->pusb_dev = dev; ss->attention_done = 0; /* If the device has subclass and protocol, then use that. Otherwise, * take data from the specific interface. */ if (subclass) { ss->subclass = subclass; ss->protocol = protocol; } else { ss->subclass = interface->bInterfaceSubClass; ss->protocol = interface->bInterfaceProtocol; } /* set the handler pointers based on the protocol */ US_DEBUGP("Transport: "); switch (ss->protocol) { case US_PR_CB: US_DEBUGPX("Control/Bulk\n"); ss->transport = CB_transport; ss->transport_reset = CB_reset; break; case US_PR_CBI: US_DEBUGPX("Control/Bulk/Interrupt\n"); ss->transport = CB_transport; ss->transport_reset = CB_reset; break; case US_PR_BULK: US_DEBUGPX("Bulk\n"); ss->transport = Bulk_transport; ss->transport_reset = Bulk_reset; break; default: US_DEBUGPX("Unknown\n"); kfree(ss); return NULL; break; } /* * We are expecting a minimum of 2 endpoints - in and out (bulk). * An optional interrupt is OK (necessary for CBI protocol). * We will ignore any others. */ for (i = 0; i < interface->bNumEndpoints; i++) { /* is it an BULK endpoint? */ if ((interface->endpoint[i].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) { if (interface->endpoint[i].bEndpointAddress & USB_DIR_IN) ss->ep_in = interface->endpoint[i].bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; else ss->ep_out = interface->endpoint[i].bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; } /* is it an interrupt endpoint? */ if ((interface->endpoint[i].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) { ss->ep_int = interface->endpoint[i].bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; } } US_DEBUGP("Endpoints In %d Out %d Int %d\n", ss->ep_in, ss->ep_out, ss->ep_int); /* Do some basic sanity checks, and bail if we find a problem */ if (usb_set_interface(dev, interface->bInterfaceNumber, 0) || !ss->ep_in || !ss->ep_out || (ss->protocol == US_PR_CBI && ss->ep_int == 0)) { US_DEBUGP("Problems with device\n"); if (ss->host) { scsi_unregister_module(MODULE_SCSI_HA, ss->htmplt); kfree(ss->htmplt->name); kfree(ss->htmplt); } kfree(ss); return NULL; } /* If this is a new device (i.e. we haven't seen it before), we need to * generate a scsi host definition, and register with scsi above us */ if (!ss->host) { /* copy the GUID we created before */ US_DEBUGP("New GUID " GUID_FORMAT "\n", GUID_ARGS(guid)); memcpy(ss->guid, guid, sizeof(guid)); /* set class specific stuff */ US_DEBUGP("Protocol: "); switch (ss->subclass) { case US_SC_RBC: US_DEBUGPX("Reduced Block Commands\n"); break; case US_SC_8020: US_DEBUGPX("8020\n"); break; case US_SC_QIC: US_DEBUGPX("QIC157\n"); break; case US_SC_8070: US_DEBUGPX("8070\n"); break; case US_SC_SCSI: US_DEBUGPX("Transparent SCSI\n"); ss->proto_handler = transparent_scsi_command; break; case US_SC_UFI: US_DEBUGPX("UFI\n"); ss->proto_handler = ufi_command; break; default: US_DEBUGPX("Unknown\n"); break; } /* We only handle certain protocols. Currently, these are *the only ones that devices use. */ if ((ss->subclass != US_SC_SCSI) && (ss->subclass != US_SC_UFI)) { US_DEBUGP("Sorry, we do not support that protocol yet.\n"); US_DEBUGP("If you have a device which uses one of the unsupported\n"); US_DEBUGP("protocols, please contact mdharm-usb@one-eyed-alien.net\n"); kfree(ss); return NULL; } /* Allocate memory for the SCSI Host Template */ if ((htmplt = (Scsi_Host_Template *) kmalloc(sizeof(*ss->htmplt), GFP_KERNEL)) == NULL ) { printk(KERN_WARNING USB_STORAGE "Out of memory\n"); kfree(ss); return NULL; } /* Initialize the host template based on the default one */ memcpy(htmplt, &my_host_template, sizeof(my_host_template)); /* Grab the next host number */ ss->host_number = my_host_number++; /* MDD: FIXME: this is bad. We abuse this pointer so we * can pass the ss pointer to the host controler thread * in us_detect */ (struct us_data *)htmplt->proc_dir = ss; /* shuttle E-USB */ if (dev->descriptor.idVendor == 0x04e6 && dev->descriptor.idProduct == 0x0001) { __u8 qstat[2]; int result; result = usb_control_msg(ss->pusb_dev, usb_rcvctrlpipe(dev,0), 1, 0xC0, 0, ss->ifnum, qstat, 2, HZ*5); US_DEBUGP("C0 status 0x%x 0x%x\n", qstat[0], qstat[1]); init_waitqueue_head(&ss->ip_waitq); ss->irqpipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int); result = usb_request_irq(ss->pusb_dev, ss->irqpipe, CBI_irq, 255, (void *)ss, &ss->irq_handle); if (result) return NULL; interruptible_sleep_on_timeout(&ss->ip_waitq, HZ*6); } else if (ss->protocol == US_PR_CBI) { int result; init_waitqueue_head(&ss->ip_waitq); /* set up the IRQ pipe and handler */ /* FIXME: This needs to get the period from the device */ ss->irqpipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int); result = usb_request_irq(ss->pusb_dev, ss->irqpipe, CBI_irq, 255, (void *)ss, &ss->irq_handle); if (result) { US_DEBUGP("usb_request_irq failed (0x%x), No interrupt for CBI\n", result); } } /* start up our thread */ { DECLARE_MUTEX_LOCKED(sem); init_waitqueue_head(&ss->waitq); ss->notify = &sem; ss->pid = kernel_thread(usb_stor_control_thread, ss, CLONE_FS | CLONE_FILES | CLONE_SIGHAND); if (ss->pid < 0) { printk(KERN_WARNING USB_STORAGE "Unable to start control thread\n"); kfree(htmplt); kfree(ss); return NULL; } /* wait for it to start */ down(&sem); } /* now register - our detect function will be called */ scsi_register_module(MODULE_SCSI_HA, htmplt); /* put us in the list */ prev = (struct us_data *)&us_list; while (prev->next) prev = prev->next; prev->next = ss; } printk(KERN_INFO "WARNING: USB Mass Storage data integrity not assured\n"); printk(KERN_INFO "USB Mass Storage device found at %d\n", dev->devnum); return ss;}/* Handle a disconnect event from the USB core */static void storage_disconnect(struct usb_device *dev, void *ptr){ struct us_data *ss = ptr; if (!ss) return; ss->pusb_dev = NULL; // MOD_DEC_USE_COUNT;}/*********************************************************************** * Initialization and registration ***********************************************************************/int __init usb_stor_init(void){ // MOD_INC_USE_COUNT; if (sizeof(my_host_template) != SCSI_HOST_TEMPLATE_SIZE) { printk(KERN_ERR "usb-storage: SCSI_HOST_TEMPLATE_SIZE does not match\n") ; printk(KERN_ERR "usb-storage: expected %d bytes, got %d bytes\n", SCSI_HOST_TEMPLATE_SIZE, sizeof(my_host_template)) ; return -1 ; } /* register the driver, return -1 if error */ if (usb_register(&storage_driver) < 0) return -1; printk(KERN_INFO "USB Mass Storage support registered.\n"); return 0;}void __exit usb_stor_exit(void){ usb_deregister(&storage_driver) ;}module_init(usb_stor_init) ;module_exit(usb_stor_exit) ;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -