📄 csk_udisk_mgr.c
字号:
ep_in = ep; else ep_out = ep; } /* Is it an interrupt endpoint? */ else if (usb_endpoint_xfer_int(ep)) { ep_int = ep; } } if (!ep_in || !ep_out) { goto BadDevice; } /* 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; } ////// us->current_urb = usb_alloc_urb(0, GFP_KERNEL); if (!us->current_urb) { goto BadDevice; } th = kthread_create(usb_worker, us, "csk-usb-storage"); if (IS_ERR(th)) { printk(KERN_WARNING "Unable to start control thread\n"); goto BadDevice; } /* Take a reference to the host for the control thread and * count it among all the threads we have launched. Then * start it up. */ scsi_host_get(us_to_host(us)); atomic_inc(&g_total_workers); wake_up_process(th); Ans = scsi_add_host(host, &intf->dev); if (Ans) { printk(KERN_WARNING "Unable to add the scsi host\n"); goto BadDevice; } ///// printk(KERN_DEBUG "SUMANG MOBILE device found at %d\n", us->pusb_dev->devnum); /* If the device is still connected, perform the scanning */ if (!test_bit(US_FLIDX_DISCONNECTING, &us->flags)) { /* For bulk-only devices, determine the max LUN value */ if (!(us->flags & US_FL_SINGLE_LUN)) { mutex_lock(&us->dev_mutex); ///// /* issue the command */ us->iobuf[0] = 0; Ans = usb_stor_control_msg(us, us->recv_ctrl_pipe, US_BULK_GET_MAX_LUN, USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, us->ifnum, us->iobuf, 1, HZ); /* if we have a successful request, return the result */ if (Ans > 0) { us->max_lun = us->iobuf[0]; } if (Ans == -EPIPE) { usb_stor_clear_halt(us, us->recv_bulk_pipe); usb_stor_clear_halt(us, us->send_bulk_pipe); } //// mutex_unlock(&us->dev_mutex); } scsi_scan_host(us_to_host(us)); printk(KERN_DEBUG "device scan complete\n"); /* Should we unbind if no devices were detected? */ } scsi_host_put(us_to_host(us)); scsi_host_get(us_to_host(us)); ///// return 0; /* We come here if there are any problems */BadDevice: FreeUpAll(us); return -EPIPE;}//go home and have a rest..static void storage_disconnect(struct usb_interface *i){ struct us_data *us = usb_get_intfdata(i); quiesce_and_remove_host(us); FreeUpAll(us);}static struct usb_driver usb_storage_driver = { .name = "csk-usb-storage", .probe = storage_probe, .disconnect = storage_disconnect, .pre_reset = storage_pre_reset, .post_reset = storage_post_reset, .id_table = storage_usb_ids,};static int __init mod_init(void){ int ans; if ((ans = usb_register(&usb_storage_driver)) == 0) { printk(KERN_INFO "CSK's USB Mass Storage driver,Loaded\n"); } return ans;}static void __exit mod_exit(void){ usb_deregister(&usb_storage_driver) ;}module_init(mod_init);module_exit(mod_exit);static void FreeUpAll(struct us_data *us){ set_bit(US_FLIDX_DISCONNECTING, &us->flags); //let our worker suspend up(&us->sema); usb_free_urb(us->current_urb); kfree(us->sensebuf); 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); usb_set_intfdata(us->pusb_intf, NULL); scsi_host_put(us_to_host(us));}static void quiesce_and_remove_host(struct us_data *us){ struct Scsi_Host *host = us_to_host(us); scsi_lock(host); set_bit(US_FLIDX_DISCONNECTING, &us->flags); scsi_unlock(host); usb_stor_stop_transport(us); wake_up(&us->delay_wait); mutex_lock(&us->dev_mutex); if (us->srb) { us->srb->result = DID_NO_CONNECT << 16; scsi_lock(host); us->srb->scsi_done(us->srb); us->srb = NULL; scsi_unlock(host); } mutex_unlock(&us->dev_mutex); /* Now we own no commands so it's safe to remove the SCSI host */ scsi_remove_host(host);}/* Invoke the transport and basic error-handling/recovery methods * * This is used by the protocol layers to actually send the message to * the device and receive the response. */static void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us){ int need_auto_sense; int result; /* send the command to the transport layer */ srb->resid = 0; result = usb_stor_Bulk_transport(srb, us); /* if the command gets aborted by the higher layers, we need to * short-circuit all other processing */ if (test_bit(US_FLIDX_TIMED_OUT, &us->flags)) { srb->result = DID_ABORT << 16; goto Handle_Errors; } /* if there is a transport error, reset and don't auto-sense */ if (result == USB_STOR_TRANSPORT_ERROR) { srb->result = DID_ERROR << 16; goto Handle_Errors; } /* if the transport provided its own sense data, don't auto-sense */ if (result == USB_STOR_TRANSPORT_NO_SENSE) { srb->result = SAM_STAT_CHECK_CONDITION; return; } srb->result = SAM_STAT_GOOD; /* Determine if we need to auto-sense * * I normally don't use a flag like this, but it's almost impossible * to understand what's going on here if I don't. */ need_auto_sense = 0; /* * If we have a failure, we're going to do a REQUEST_SENSE * automatically. Note that we differentiate between a command * "failure" and an "error" in the transport mechanism. */ if (result == USB_STOR_TRANSPORT_FAILED) { need_auto_sense = 1; } /* * A short transfer on a command where we don't expect it * is unusual, but it doesn't mean we need to auto-sense. */ if ((srb->resid > 0) && !((srb->cmnd[0] == REQUEST_SENSE) || (srb->cmnd[0] == INQUIRY) || (srb->cmnd[0] == MODE_SENSE) || (srb->cmnd[0] == LOG_SENSE) || (srb->cmnd[0] == MODE_SENSE_10))) { } /* Now, if we need to do the auto-sense, let's do it */ if (need_auto_sense) { int temp_result; void* old_request_buffer; unsigned short old_sg; unsigned old_request_bufflen; unsigned char old_sc_data_direction; unsigned char old_cmd_len; unsigned char old_cmnd[MAX_COMMAND_SIZE]; int old_resid; /* save the old command */ memcpy(old_cmnd, srb->cmnd, MAX_COMMAND_SIZE); old_cmd_len = srb->cmd_len; /* set the command and the LUN */ memset(srb->cmnd, 0, MAX_COMMAND_SIZE); srb->cmnd[0] = REQUEST_SENSE; srb->cmnd[1] = old_cmnd[1] & 0xE0; srb->cmnd[4] = 18; srb->cmd_len = 12; /* set the transfer direction */ old_sc_data_direction = srb->sc_data_direction; srb->sc_data_direction = DMA_FROM_DEVICE; /* use the new buffer we have */ old_request_buffer = srb->request_buffer; srb->request_buffer = us->sensebuf; /* set the buffer length for transfer */ old_request_bufflen = srb->request_bufflen; srb->request_bufflen = US_SENSE_SIZE; /* set up for no scatter-gather use */ old_sg = srb->use_sg; srb->use_sg = 0; /* issue the auto-sense command */ old_resid = srb->resid; srb->resid = 0; temp_result = usb_stor_Bulk_transport(us->srb, us); /* let's clean up right away */ memcpy(srb->sense_buffer, us->sensebuf, US_SENSE_SIZE); srb->resid = old_resid; srb->request_buffer = old_request_buffer; srb->request_bufflen = old_request_bufflen; srb->use_sg = old_sg; srb->sc_data_direction = old_sc_data_direction; srb->cmd_len = old_cmd_len; memcpy(srb->cmnd, old_cmnd, MAX_COMMAND_SIZE); if (test_bit(US_FLIDX_TIMED_OUT, &us->flags)) { srb->result = DID_ABORT << 16; goto Handle_Errors; } if (temp_result != USB_STOR_TRANSPORT_GOOD) { /* we skip the reset if this happens to be a * multi-target device, since failure of an * auto-sense is perfectly valid */ srb->result = DID_ERROR << 16; if (!(us->flags & US_FL_SCM_MULT_TARG)) goto Handle_Errors; return; } /* set the result so the higher layers expect this data */ srb->result = SAM_STAT_CHECK_CONDITION; /* If things are really okay, then let's show that. Zero * out the sense buffer so the higher layers won't realize * we did an unsolicited auto-sense. */ if (result == USB_STOR_TRANSPORT_GOOD && /* Filemark 0, ignore EOM, ILI 0, no sense */ (srb->sense_buffer[2] & 0xaf) == 0 && /* No ASC or ASCQ */ srb->sense_buffer[12] == 0 && srb->sense_buffer[13] == 0) { srb->result = SAM_STAT_GOOD; srb->sense_buffer[0] = 0x0; } } /* Did we transfer less than the minimum amount required? */ if (srb->result == SAM_STAT_GOOD && srb->request_bufflen - srb->resid < srb->underflow) srb->result = (DID_ERROR << 16) | (SUGGEST_RETRY << 24); return; /* Error and abort processing: try to resynchronize with the device * by issuing a port reset. If that fails, try a class-specific * device reset. */ Handle_Errors: /* Set the RESETTING bit, and clear the ABORTING bit so that * the reset may proceed. */ scsi_lock(us_to_host(us)); set_bit(US_FLIDX_RESETTING, &us->flags); clear_bit(US_FLIDX_ABORTING, &us->flags); scsi_unlock(us_to_host(us)); /* We must release the device lock because the pre_reset routine * will want to acquire it. */ mutex_unlock(&us->dev_mutex); result = usb_stor_port_reset(us); mutex_lock(&us->dev_mutex); if (result < 0) { scsi_lock(us_to_host(us)); usb_stor_report_device_reset(us); scsi_unlock(us_to_host(us)); usb_stor_Bulk_reset(us); } clear_bit(US_FLIDX_RESETTING, &us->flags);}static void usb_stor_stop_transport(struct us_data *us){ /* If the state machine is blocked waiting for an URB, * let's wake it up. The test_and_clear_bit() call * guarantees that if a URB has just been submitted, * it won't be cancelled more than once. */ if (test_and_clear_bit(US_FLIDX_URB_ACTIVE, &us->flags)) { usb_unlink_urb(us->current_urb); } /* If we are waiting for a scatter-gather operation, cancel it. */ if (test_and_clear_bit(US_FLIDX_SG_ACTIVE, &us->flags)) { usb_sg_cancel(&us->current_sg); }}static int usb_worker(void * __us){ struct us_data *us = (struct us_data *)__us; struct Scsi_Host *host = us_to_host(us); current->flags |= PF_NOFREEZE; for(;;) { if(down_interruptible(&us->sema)) break; /* lock the device pointers */ mutex_lock(&(us->dev_mutex)); /* if the device has disconnected, we are free to exit */ if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) { mutex_unlock(&us->dev_mutex); break; } /* lock access to the state */ scsi_lock(host); /* has the command timed out *already* ? */ if (test_bit(US_FLIDX_TIMED_OUT, &us->flags)) { us->srb->result = DID_ABORT << 16; goto SkipForAbort;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -