📄 usb.c
字号:
if (unusual_dev->vendorName) strlcpy(us->vendor, unusual_dev->vendorName, sizeof(us->vendor)); else strcpy(us->vendor, "Unknown"); } if (strlen(us->product) == 0) { if (unusual_dev->productName) strlcpy(us->product, unusual_dev->productName, sizeof(us->product)); else strcpy(us->product, "Unknown"); } if (strlen(us->serial) == 0) strcpy(us->serial, "None");}/* Get the transport settings */static int get_transport(struct us_data *us){ switch (us->protocol) { case US_PR_CB: us->transport_name = "Control/Bulk"; us->transport = usb_stor_CB_transport; us->transport_reset = usb_stor_CB_reset; us->max_lun = 7; break; case US_PR_CBI: us->transport_name = "Control/Bulk/Interrupt"; us->transport = usb_stor_CBI_transport; us->transport_reset = usb_stor_CB_reset; us->max_lun = 7; break; case US_PR_BULK: us->transport_name = "Bulk"; us->transport = usb_stor_Bulk_transport; us->transport_reset = usb_stor_Bulk_reset; break;#ifdef CONFIG_USB_STORAGE_HP8200e case US_PR_SCM_ATAPI: us->transport_name = "SCM/ATAPI"; us->transport = hp8200e_transport; us->transport_reset = usb_stor_CB_reset; us->max_lun = 1; break;#endif#ifdef CONFIG_USB_STORAGE_SDDR09 case US_PR_EUSB_SDDR09: us->transport_name = "EUSB/SDDR09"; us->transport = sddr09_transport; us->transport_reset = usb_stor_CB_reset; us->max_lun = 0; break;#endif#ifdef CONFIG_USB_STORAGE_SDDR55 case US_PR_SDDR55: us->transport_name = "SDDR55"; us->transport = sddr55_transport; us->transport_reset = sddr55_reset; us->max_lun = 0; break;#endif#ifdef CONFIG_USB_STORAGE_DPCM case US_PR_DPCM_USB: us->transport_name = "Control/Bulk-EUSB/SDDR09"; us->transport = dpcm_transport; us->transport_reset = usb_stor_CB_reset; us->max_lun = 1; break;#endif#ifdef CONFIG_USB_STORAGE_FREECOM case US_PR_FREECOM: us->transport_name = "Freecom"; us->transport = freecom_transport; us->transport_reset = usb_stor_freecom_reset; us->max_lun = 0; break;#endif#ifdef CONFIG_USB_STORAGE_DATAFAB case US_PR_DATAFAB: us->transport_name = "Datafab Bulk-Only"; us->transport = datafab_transport; us->transport_reset = usb_stor_Bulk_reset; us->max_lun = 1; break;#endif#ifdef CONFIG_USB_STORAGE_JUMPSHOT case US_PR_JUMPSHOT: us->transport_name = "Lexar Jumpshot Control/Bulk"; us->transport = jumpshot_transport; us->transport_reset = usb_stor_Bulk_reset; us->max_lun = 1; break;#endif default: return -EIO; } US_DEBUGP("Transport: %s\n", us->transport_name); /* fix for single-lun devices */ if (us->flags & US_FL_SINGLE_LUN) us->max_lun = 0; return 0;}/* Get the protocol settings */static int get_protocol(struct us_data *us){ switch (us->subclass) { case US_SC_RBC: us->protocol_name = "Reduced Block Commands (RBC)"; us->proto_handler = usb_stor_transparent_scsi_command; break; case US_SC_8020: us->protocol_name = "8020i"; us->proto_handler = usb_stor_ATAPI_command; us->max_lun = 0; break; case US_SC_QIC: us->protocol_name = "QIC-157"; us->proto_handler = usb_stor_qic157_command; us->max_lun = 0; break; case US_SC_8070: us->protocol_name = "8070i"; us->proto_handler = usb_stor_ATAPI_command; us->max_lun = 0; break; case US_SC_SCSI: us->protocol_name = "Transparent SCSI"; us->proto_handler = usb_stor_transparent_scsi_command; break; case US_SC_UFI: us->protocol_name = "Uniform Floppy Interface (UFI)"; us->proto_handler = usb_stor_ufi_command; break;#ifdef CONFIG_USB_STORAGE_ISD200 case US_SC_ISD200: us->protocol_name = "ISD200 ATA/ATAPI"; us->proto_handler = isd200_ata_command; break;#endif default: return -EIO; } US_DEBUGP("Protocol: %s\n", us->protocol_name); return 0;}/* Get the pipe settings */static int get_pipes(struct us_data *us){ struct usb_host_interface *altsetting = us->pusb_intf->cur_altsetting; int i; struct usb_endpoint_descriptor *ep; struct usb_endpoint_descriptor *ep_in = NULL; struct usb_endpoint_descriptor *ep_out = NULL; struct usb_endpoint_descriptor *ep_int = NULL; /* * Find the endpoints we need. * 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 < altsetting->desc.bNumEndpoints; i++) { ep = &altsetting->endpoint[i].desc; /* Is it a BULK endpoint? */ if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) { /* BULK in or out? */ if (ep->bEndpointAddress & USB_DIR_IN) ep_in = ep; else ep_out = ep; } /* Is it an interrupt endpoint? */ else if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) { ep_int = ep; } } US_DEBUGP("Endpoints: In: 0x%p Out: 0x%p Int: 0x%p (Period %d)\n", ep_in, ep_out, ep_int, ep_int ? ep_int->bInterval : 0); if (!ep_in || !ep_out || (us->protocol == US_PR_CBI && !ep_int)) { US_DEBUGP("Endpoint sanity check failed! Rejecting dev.\n"); return -EIO; } /* Calculate and store the pipe values */ us->send_ctrl_pipe = usb_sndctrlpipe(us->pusb_dev, 0); us->recv_ctrl_pipe = usb_rcvctrlpipe(us->pusb_dev, 0); us->send_bulk_pipe = usb_sndbulkpipe(us->pusb_dev, ep_out->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); us->recv_bulk_pipe = usb_rcvbulkpipe(us->pusb_dev, ep_in->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); if (ep_int) { us->recv_intr_pipe = usb_rcvintpipe(us->pusb_dev, ep_int->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); us->ep_bInterval = ep_int->bInterval; } return 0;}/* Initialize all the dynamic resources we need */static int usb_stor_acquire_resources(struct us_data *us){ int p; us->current_urb = usb_alloc_urb(0, GFP_KERNEL); if (!us->current_urb) { US_DEBUGP("URB allocation failed\n"); return -ENOMEM; } /* Lock the device while we carry out the next two operations */ down(&us->dev_semaphore); /* For bulk-only devices, determine the max LUN value */ if (us->protocol == US_PR_BULK) { p = usb_stor_Bulk_max_lun(us); if (p < 0) { up(&us->dev_semaphore); return p; } us->max_lun = p; } /* Just before we start our control thread, initialize * the device if it needs initialization */ if (us->unusual_dev->initFunction) us->unusual_dev->initFunction(us); up(&us->dev_semaphore); /* * Since this is a new device, we need to register a SCSI * host definition with the higher SCSI layers. */ us->host = scsi_host_alloc(&usb_stor_host_template, sizeof(us)); if (!us->host) { printk(KERN_WARNING USB_STORAGE "Unable to allocate the scsi host\n"); return -EBUSY; } /* Set the hostdata to prepare for scanning */ us->host->hostdata[0] = (unsigned long) us; /* Start up our control thread */ us->sm_state = US_STATE_IDLE; p = kernel_thread(usb_stor_control_thread, us, CLONE_VM); if (p < 0) { printk(KERN_WARNING USB_STORAGE "Unable to start control thread\n"); return p; } us->pid = p; /* Wait for the thread to start */ wait_for_completion(&(us->notify)); return 0;}/* Release all our dynamic resources */void usb_stor_release_resources(struct us_data *us){ US_DEBUGP("-- %s\n", __FUNCTION__); /* Kill the control thread. The SCSI host must already have been * removed so it won't try to queue any more commands. */ if (us->pid) { /* Wait for the thread to be idle */ down(&us->dev_semaphore); US_DEBUGP("-- sending exit command to thread\n"); BUG_ON(us->sm_state != US_STATE_IDLE); /* If the SCSI midlayer queued a final command just before * scsi_remove_host() was called, us->srb might not be * NULL. We can overwrite it safely, because the midlayer * will not wait for the command to finish. Also the * control thread will already have been awakened. * That's okay, an extra up() on us->sema won't hurt. * * Enqueue the command, wake up the thread, and wait for * notification that it has exited. */ scsi_lock(us->host); us->srb = NULL; scsi_unlock(us->host); up(&us->dev_semaphore); up(&us->sema); wait_for_completion(&us->notify); } /* Call the destructor routine, if it exists */ if (us->extra_destructor) { US_DEBUGP("-- calling extra_destructor()\n"); us->extra_destructor(us->extra); } /* Finish the host removal sequence */ if (us->host) scsi_host_put(us->host); /* Free the extra data and the URB */ if (us->extra) kfree(us->extra); if (us->current_urb) usb_free_urb(us->current_urb);}/* Dissociate from the USB device */static void dissociate_dev(struct us_data *us){ US_DEBUGP("-- %s\n", __FUNCTION__); /* Free the device-related DMA-mapped buffers */ if (us->cr) usb_buffer_free(us->pusb_dev, sizeof(*us->cr), us->cr, us->cr_dma); if (us->iobuf) usb_buffer_free(us->pusb_dev, US_IOBUF_SIZE, us->iobuf, us->iobuf_dma); /* Remove our private data from the interface */ usb_set_intfdata(us->pusb_intf, NULL); /* Free the structure itself */ kfree(us);}/* Probe to see if we can drive a newly-connected USB device */static int storage_probe(struct usb_interface *intf, const struct usb_device_id *id){ struct us_data *us; const int id_index = id - storage_usb_ids; int result; US_DEBUGP("USB Mass Storage device detected\n"); US_DEBUGP("altsetting is %d, id_index is %d\n", intf->cur_altsetting->desc.bAlternateSetting, id_index); /* Allocate the us_data structure and initialize the mutexes */ us = (struct us_data *) kmalloc(sizeof(*us), GFP_KERNEL); if (!us) { printk(KERN_WARNING USB_STORAGE "Out of memory\n"); return -ENOMEM; } memset(us, 0, sizeof(struct us_data)); init_MUTEX(&(us->dev_semaphore)); init_MUTEX_LOCKED(&(us->sema)); init_completion(&(us->notify)); init_waitqueue_head(&us->dev_reset_wait); /* Associate the us_data structure with the USB device */ result = associate_dev(us, intf); if (result) goto BadDevice; /* * Get the unusual_devs entries and the descriptors * * id_index is calculated in the declaration to be the index number * of the match from the usb_device_id table, so we can find the * corresponding entry in the private table. */ get_device_info(us, id_index);#ifdef CONFIG_USB_STORAGE_SDDR09 if (us->protocol == US_PR_EUSB_SDDR09 || us->protocol == US_PR_DPCM_USB) { /* set the configuration -- STALL is an acceptable response here */ if (us->pusb_dev->actconfig->desc.bConfigurationValue != 1) { US_DEBUGP("active config #%d != 1 ??\n", us->pusb_dev ->actconfig->desc.bConfigurationValue); goto BadDevice; } result = usb_reset_configuration(us->pusb_dev); US_DEBUGP("Result of usb_reset_configuration is %d\n", result); if (result == -EPIPE) { US_DEBUGP("-- stall on control interface\n"); } else if (result != 0) { /* it's not a stall, but another error -- time to bail */ US_DEBUGP("-- Unknown error. Rejecting device\n"); goto BadDevice; } }#endif /* Get the transport, protocol, and pipe settings */ result = get_transport(us); if (result) goto BadDevice; result = get_protocol(us); if (result) goto BadDevice; result = get_pipes(us); if (result) goto BadDevice; /* Acquire all the other resources */ result = usb_stor_acquire_resources(us); if (result) goto BadDevice; /* Finally, add the host (this does SCSI device scanning) */ result = scsi_add_host(us->host, &intf->dev); if (result) { printk(KERN_WARNING USB_STORAGE "Unable to add the scsi host\n"); goto BadDevice; } scsi_scan_host(us->host); printk(KERN_DEBUG "USB Mass Storage device found at %d\n", us->pusb_dev->devnum); return 0; /* We come here if there are any problems */BadDevice: US_DEBUGP("storage_probe() failed\n"); usb_stor_release_resources(us); dissociate_dev(us); return result;}/* Handle a disconnect event from the USB core */static void storage_disconnect(struct usb_interface *intf){ struct us_data *us = usb_get_intfdata(intf); US_DEBUGP("storage_disconnect() called\n"); /* Prevent new USB transfers, stop the current command, and * interrupt a device-reset delay */ set_bit(US_FLIDX_DISCONNECTING, &us->flags); usb_stor_stop_transport(us); wake_up(&us->dev_reset_wait); /* Wait for the current command to finish, then remove the host */ down(&us->dev_semaphore); up(&us->dev_semaphore); scsi_remove_host(us->host); /* Wait for everything to become idle and release all our resources */ usb_stor_release_resources(us); dissociate_dev(us);}/*********************************************************************** * Initialization and registration ***********************************************************************/static int __init usb_stor_init(void){ int retval; printk(KERN_INFO "Initializing USB Mass Storage driver...\n"); /* register the driver, return usb_register return code if error */ retval = usb_register(&usb_storage_driver); if (retval) goto out; /* we're all set */ printk(KERN_INFO "USB Mass Storage support registered.\n");out: return retval;}static void __exit usb_stor_exit(void){ US_DEBUGP("usb_stor_exit() called\n"); /* Deregister the driver * This will cause disconnect() to be called for each * attached unit */ US_DEBUGP("-- calling usb_deregister()\n"); usb_deregister(&usb_storage_driver) ;}module_init(usb_stor_init);module_exit(usb_stor_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -