#include <linux/sched.h> #include <linux/errno.h> #include <linux/slab.h> #include <scsi/scsi.h> #include <scsi/scsi_eh.h> #include <scsi/scsi_device.h> #include "usb.h" #include "scsiglue.h" #include "transport.h" /*********************************************************************** * Data transfer routines ***********************************************************************/ //----- usb_stor_blocking_completion() --------------------- static void usb_stor_blocking_completion(struct urb *urb) { struct completion *urb_done_ptr = urb->context; //printk("transport --- usb_stor_blocking_completion\n"); complete(urb_done_ptr); } //----- usb_stor_msg_common() --------------------- static int usb_stor_msg_common(struct us_data *us, int timeout) { struct completion urb_done; long timeleft; int status; //printk("transport --- usb_stor_msg_common\n"); if (test_bit(US_FLIDX_ABORTING, &us->dflags)) return -EIO; init_completion(&urb_done); us->current_urb->context = &urb_done; us->current_urb->actual_length = 0; us->current_urb->error_count = 0; us->current_urb->status = 0; us->current_urb->transfer_flags = 0; if (us->current_urb->transfer_buffer == us->iobuf) us->current_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; us->current_urb->transfer_dma = us->iobuf_dma; us->current_urb->setup_dma = us->cr_dma; status = usb_submit_urb(us->current_urb, GFP_NOIO); if (status) return status; set_bit(US_FLIDX_URB_ACTIVE, &us->dflags); if (test_bit(US_FLIDX_ABORTING, &us->dflags)) { if (test_and_clear_bit(US_FLIDX_URB_ACTIVE, &us->dflags)) { //printk("-- cancelling URB\n"); usb_unlink_urb(us->current_urb); } } timeleft = wait_for_completion_interruptible_timeout(&urb_done, timeout ? : MAX_SCHEDULE_TIMEOUT); clear_bit(US_FLIDX_URB_ACTIVE, &us->dflags); if (timeleft <= 0) { //printk("%s -- cancelling URB\n", timeleft == 0 ? "Timeout" : "Signal"); usb_kill_urb(us->current_urb); } return us->current_urb->status; } //----- usb_stor_control_msg() --------------------- int usb_stor_control_msg(struct us_data *us, unsigned int pipe, u8 request, u8 requesttype, u16 value, u16 index, void *data, u16 size, int timeout) { int status; //printk("transport --- usb_stor_control_msg\n"); /* fill in the devrequest structure */ us->cr->bRequestType = requesttype; us->cr->bRequest = request; us->cr->wValue = cpu_to_le16(value); us->cr->wIndex = cpu_to_le16(index); us->cr->wLength = cpu_to_le16(size); /* fill and submit the URB */ usb_fill_control_urb(us->current_urb, us->pusb_dev, pipe, (unsigned char*) us->cr, data, size, usb_stor_blocking_completion, NULL); status = usb_stor_msg_common(us, timeout); /* return the actual length of the data transferred if no error */ if (status == 0) status = us->current_urb->actual_length; return status; } //----- usb_stor_clear_halt() --------------------- int usb_stor_clear_halt(struct us_data *us, unsigned int pipe) { int result; int endp = usb_pipeendpoint(pipe); //printk("transport --- usb_stor_clear_halt\n"); if (usb_pipein (pipe)) endp |= USB_DIR_IN; result = usb_stor_control_msg(us, us->send_ctrl_pipe, USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, USB_ENDPOINT_HALT, endp, NULL, 0, 3*HZ); /* reset the endpoint toggle */ if (result >= 0) //usb_settoggle(us->pusb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 0); usb_reset_endpoint(us->pusb_dev, endp); return result; } //----- interpret_urb_result() --------------------- static int interpret_urb_result(struct us_data *us, unsigned int pipe, unsigned int length, int result, unsigned int partial) { //printk("transport --- interpret_urb_result\n"); switch (result) { /* no error code; did we send all the data? */ case 0: if (partial != length) { //printk("-- short transfer\n"); return USB_STOR_XFER_SHORT; } //printk("-- transfer complete\n"); return USB_STOR_XFER_GOOD; case -EPIPE: if (usb_pipecontrol(pipe)) { //printk("-- stall on control pipe\n"); return USB_STOR_XFER_STALLED; } //printk("clearing endpoint halt for pipe 0x%x\n", pipe); if (usb_stor_clear_halt(us, pipe) < 0) return USB_STOR_XFER_ERROR; return USB_STOR_XFER_STALLED; case -EOVERFLOW: //printk("-- babble\n"); return USB_STOR_XFER_LONG; case -ECONNRESET: //printk("-- transfer cancelled\n"); return USB_STOR_XFER_ERROR; case -EREMOTEIO: //printk("-- short read transfer\n"); return USB_STOR_XFER_SHORT; case -EIO: //printk("-- abort or disconnect in progress\n"); return USB_STOR_XFER_ERROR; default: //printk("-- unknown error\n"); return USB_STOR_XFER_ERROR; } } //----- usb_stor_bulk_transfer_buf() --------------------- int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe, void *buf, unsigned int length, unsigned int *act_len) { int result; //printk("transport --- usb_stor_bulk_transfer_buf\n"); /* fill and submit the URB */ usb_fill_bulk_urb(us->current_urb, us->pusb_dev, pipe, buf, length, usb_stor_blocking_completion, NULL); result = usb_stor_msg_common(us, 0); /* store the actual length of the data transferred */ if (act_len) *act_len = us->current_urb->actual_length; return interpret_urb_result(us, pipe, length, result, us->current_urb->actual_length); } //----- usb_stor_bulk_transfer_sglist() --------------------- static int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe, struct scatterlist *sg, int num_sg, unsigned int length, unsigned int *act_len) { int result; //printk("transport --- usb_stor_bulk_transfer_sglist\n"); if (test_bit(US_FLIDX_ABORTING, &us->dflags)) return USB_STOR_XFER_ERROR; /* initialize the scatter-gather request block */ result = usb_sg_init(&us->current_sg, us->pusb_dev, pipe, 0, sg, num_sg, length, GFP_NOIO); if (result) { //printk("usb_sg_init returned %d\n", result); return USB_STOR_XFER_ERROR; } /* since the block has been initialized successfully, it's now okay to cancel it */ set_bit(US_FLIDX_SG_ACTIVE, &us->dflags); /* did an abort/disconnect occur during the submission? */ if (test_bit(US_FLIDX_ABORTING, &us->dflags)) { /* cancel the request, if it hasn't been cancelled already */ if (test_and_clear_bit(US_FLIDX_SG_ACTIVE, &us->dflags)) { //printk("-- cancelling sg request\n"); usb_sg_cancel(&us->current_sg); } } /* wait for the completion of the transfer */ usb_sg_wait(&us->current_sg); clear_bit(US_FLIDX_SG_ACTIVE, &us->dflags); result = us->current_sg.status; if (act_len) *act_len = us->current_sg.bytes; return interpret_urb_result(us, pipe, length, result, us->current_sg.bytes); } //----- usb_stor_bulk_srb() --------------------- int usb_stor_bulk_srb(struct us_data* us, unsigned int pipe, struct scsi_cmnd* srb) { unsigned int partial; int result = usb_stor_bulk_transfer_sglist(us, pipe, scsi_sglist(srb), scsi_sg_count(srb), scsi_bufflen(srb), &partial); scsi_set_resid(srb, scsi_bufflen(srb) - partial); return result; } //----- usb_stor_bulk_transfer_sg() --------------------- int usb_stor_bulk_transfer_sg(struct us_data* us, unsigned int pipe, void *buf, unsigned int length_left, int use_sg, int *residual) { int result; unsigned int partial; //printk("transport --- usb_stor_bulk_transfer_sg\n"); /* are we scatter-gathering? */ if (use_sg) { /* use the usb core scatter-gather primitives */ result = usb_stor_bulk_transfer_sglist(us, pipe, (struct scatterlist *) buf, use_sg, length_left, &partial); length_left -= partial; } else { /* no scatter-gather, just make the request */ result = usb_stor_bulk_transfer_buf(us, pipe, buf, length_left, &partial); length_left -= partial; } /* store the residual and return the error code */ if (residual) *residual = length_left; return result; } /*********************************************************************** * Transport routines ***********************************************************************/ //----- usb_stor_invoke_transport() --------------------- void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) { int need_auto_sense; int result; //printk("transport --- usb_stor_invoke_transport\n"); usb_stor_print_cmd(srb); /* send the command to the transport layer */ scsi_set_resid(srb, 0); result = us->transport(srb, us); //usb_stor_Bulk_transport; /* 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->dflags)) { //printk("-- command was aborted\n"); 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) { //printk("-- transport indicates error, resetting\n"); 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 */ need_auto_sense = 0; if ((us->protocol == USB_PR_CB || us->protocol == USB_PR_DPCM_USB) && srb->sc_data_direction != DMA_FROM_DEVICE) { //printk("-- CB transport device requiring auto-sense\n"); need_auto_sense = 1; } if (result == USB_STOR_TRANSPORT_FAILED) { //printk("-- transport indicates command failure\n"); need_auto_sense = 1; } /* Now, if we need to do the auto-sense, let's do it */ if (need_auto_sense) { int temp_result; struct scsi_eh_save ses; printk("Issuing auto-REQUEST_SENSE\n"); scsi_eh_prep_cmnd(srb, &ses, NULL, 0, US_SENSE_SIZE); /* we must do the protocol translation here */ if (us->subclass == USB_SC_RBC || us->subclass == USB_SC_SCSI || us->subclass == USB_SC_CYP_ATACB) srb->cmd_len = 6; else srb->cmd_len = 12; /* issue the auto-sense command */ scsi_set_resid(srb, 0); temp_result = us->transport(us->srb, us); /* let's clean up right away */ scsi_eh_restore_cmnd(srb, &ses); if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) { //printk("-- auto-sense aborted\n"); srb->result = DID_ABORT << 16; goto Handle_Errors; } if (temp_result != USB_STOR_TRANSPORT_GOOD) { //printk("-- auto-sense failure\n"); srb->result = DID_ERROR << 16; if (!(us->fflags & 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 (result == USB_STOR_TRANSPORT_GOOD && (srb->sense_buffer[2] & 0xaf) == 0 && 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 && scsi_bufflen(srb) - scsi_get_resid(srb) < srb->underflow) srb->result = (DID_ERROR << 16);//v02 | (SUGGEST_RETRY << 24); return; Handle_Errors: scsi_lock(us_to_host(us)); set_bit(US_FLIDX_RESETTING, &us->dflags); clear_bit(US_FLIDX_ABORTING, &us->dflags); scsi_unlock(us_to_host(us)); 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)); us->transport_reset(us); } clear_bit(US_FLIDX_RESETTING, &us->dflags); } //----- ENE_stor_invoke_transport() --------------------- void ENE_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) { int result=0; //printk("transport --- ENE_stor_invoke_transport\n"); usb_stor_print_cmd(srb); /* send the command to the transport layer */ scsi_set_resid(srb, 0); if (!(us->MS_Status.Ready || us->SM_Status.Ready)) result = ENE_InitMedia(us); if (us->Power_IsResum == true) { result = ENE_InitMedia(us); us->Power_IsResum = false; } if (us->MS_Status.Ready) result = MS_SCSIIrp(us, srb); if (us->SM_Status.Ready) result = SM_SCSIIrp(us, srb); /* 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->dflags)) { //printk("-- command was aborted\n"); 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) { //printk("-- transport indicates error, resetting\n"); 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; if (result == USB_STOR_TRANSPORT_FAILED) { //printk("-- transport indicates command failure\n"); //need_auto_sense = 1; BuildSenseBuffer(srb, us->SrbStatus); srb->result = SAM_STAT_CHECK_CONDITION; } /* Did we transfer less than the minimum amount required? */ if (srb->result == SAM_STAT_GOOD && scsi_bufflen(srb) - scsi_get_resid(srb) < srb->underflow) srb->result = (DID_ERROR << 16);//v02 | (SUGGEST_RETRY << 24); return; Handle_Errors: scsi_lock(us_to_host(us)); set_bit(US_FLIDX_RESETTING, &us->dflags); clear_bit(US_FLIDX_ABORTING, &us->dflags); scsi_unlock(us_to_host(us)); 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)); us->transport_reset(us); } clear_bit(US_FLIDX_RESETTING, &us->dflags); } //----- BuildSenseBuffer() ------------------------------------------- void BuildSenseBuffer(struct scsi_cmnd *srb, int SrbStatus) { BYTE *buf = srb->sense_buffer; BYTE asc; printk("transport --- BuildSenseBuffer\n"); switch (SrbStatus) { case SS_NOT_READY: asc = 0x3a; break; // sense key = 0x02 case SS_MEDIUM_ERR: asc = 0x0c; break; // sense key = 0x03 case SS_ILLEGAL_REQUEST: asc = 0x20; break; // sense key = 0x05 default: asc = 0x00; break; // ?? } memset(buf, 0, 18); buf[0x00] = 0xf0; buf[0x02] = SrbStatus; buf[0x07] = 0x0b; buf[0x0c] = asc; } //----- usb_stor_stop_transport() --------------------- void usb_stor_stop_transport(struct us_data *us) { //printk("transport --- usb_stor_stop_transport\n"); if (test_and_clear_bit(US_FLIDX_URB_ACTIVE, &us->dflags)) { //printk("-- cancelling URB\n"); usb_unlink_urb(us->current_urb); } if (test_and_clear_bit(US_FLIDX_SG_ACTIVE, &us->dflags)) { //printk("-- cancelling sg request\n"); usb_sg_cancel(&us->current_sg); } } //----- usb_stor_Bulk_max_lun() --------------------- int usb_stor_Bulk_max_lun(struct us_data *us) { int result; //printk("transport --- usb_stor_Bulk_max_lun\n"); /* issue the command */ us->iobuf[0] = 0; result = 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); //printk("GetMaxLUN command result is %d, data is %d\n", result, us->iobuf[0]); /* if we have a successful request, return the result */ if (result > 0) return us->iobuf[0]; return 0; } //----- usb_stor_Bulk_transport() --------------------- int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us) { struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; struct bulk_cs_wrap *bcs = (struct bulk_cs_wrap *) us->iobuf; unsigned int transfer_length = scsi_bufflen(srb); unsigned int residue; int result; int fake_sense = 0; unsigned int cswlen; unsigned int cbwlen = US_BULK_CB_WRAP_LEN; //printk("transport --- usb_stor_Bulk_transport\n"); /* Take care of BULK32 devices; set extra byte to 0 */ if (unlikely(us->fflags & US_FL_BULK32)) { cbwlen = 32; us->iobuf[31] = 0; } /* set up the command wrapper */ bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); bcb->DataTransferLength = cpu_to_le32(transfer_length); bcb->Flags = srb->sc_data_direction == DMA_FROM_DEVICE ? 1 << 7 : 0; bcb->Tag = ++us->tag; bcb->Lun = srb->device->lun; if (us->fflags & US_FL_SCM_MULT_TARG) bcb->Lun |= srb->device->id << 4; bcb->Length = srb->cmd_len; /* copy the command payload */ memset(bcb->CDB, 0, sizeof(bcb->CDB)); memcpy(bcb->CDB, srb->cmnd, bcb->Length); // send command /* send it to out endpoint */ /*printk("Bulk Command S 0x%x T 0x%x L %d F %d Trg %d LUN %d CL %d\n", le32_to_cpu(bcb->Signature), bcb->Tag, le32_to_cpu(bcb->DataTransferLength), bcb->Flags, (bcb->Lun >> 4), (bcb->Lun & 0x0F), bcb->Length);*/ result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, bcb, cbwlen, NULL); //printk("Bulk command transfer result=%d\n", result); if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; if (unlikely(us->fflags & US_FL_GO_SLOW)) udelay(125); // R/W data if (transfer_length) { unsigned int pipe = srb->sc_data_direction == DMA_FROM_DEVICE ? us->recv_bulk_pipe : us->send_bulk_pipe; result = usb_stor_bulk_srb(us, pipe, srb); //printk("Bulk data transfer result 0x%x\n", result); if (result == USB_STOR_XFER_ERROR) return USB_STOR_TRANSPORT_ERROR; if (result == USB_STOR_XFER_LONG) fake_sense = 1; } /* get CSW for device status */ //printk("Attempting to get CSW...\n"); result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, bcs, US_BULK_CS_WRAP_LEN, &cswlen); if (result == USB_STOR_XFER_SHORT && cswlen == 0) { //printk("Received 0-length CSW; retrying...\n"); result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, bcs, US_BULK_CS_WRAP_LEN, &cswlen); } /* did the attempt to read the CSW fail? */ if (result == USB_STOR_XFER_STALLED) { /* get the status again */ //printk("Attempting to get CSW (2nd try)...\n"); result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, bcs, US_BULK_CS_WRAP_LEN, NULL); } /* if we still have a failure at this point, we're in trouble */ //printk("Bulk status result = %d\n", result); if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; /* check bulk status */ residue = le32_to_cpu(bcs->Residue); //printk("Bulk Status S 0x%x T 0x%x R %u Stat 0x%x\n", le32_to_cpu(bcs->Signature), bcs->Tag, residue, bcs->Status); if (!(bcs->Tag == us->tag || (us->fflags & US_FL_BULK_IGNORE_TAG)) || bcs->Status > US_BULK_STAT_PHASE) { //printk("Bulk logical error\n"); return USB_STOR_TRANSPORT_ERROR; } if (!us->bcs_signature) { us->bcs_signature = bcs->Signature; //if (us->bcs_signature != cpu_to_le32(US_BULK_CS_SIGN)) // printk("Learnt BCS signature 0x%08X\n", le32_to_cpu(us->bcs_signature)); } else if (bcs->Signature != us->bcs_signature) { /*printk("Signature mismatch: got %08X, expecting %08X\n", le32_to_cpu(bcs->Signature), le32_to_cpu(us->bcs_signature));*/ return USB_STOR_TRANSPORT_ERROR; } /* try to compute the actual residue, based on how much data * was really transferred and what the device tells us */ if (residue && !(us->fflags & US_FL_IGNORE_RESIDUE)) { /* Heuristically detect devices that generate bogus residues * by seeing what happens with INQUIRY and READ CAPACITY * commands. */ if (bcs->Status == US_BULK_STAT_OK && scsi_get_resid(srb) == 0 && ((srb->cmnd[0] == INQUIRY && transfer_length == 36) || (srb->cmnd[0] == READ_CAPACITY && transfer_length == 8))) { us->fflags |= US_FL_IGNORE_RESIDUE; } else { residue = min(residue, transfer_length); scsi_set_resid(srb, max(scsi_get_resid(srb), (int) residue)); } } /* based on the status code, we report good or bad */ switch (bcs->Status) { case US_BULK_STAT_OK: if (fake_sense) { memcpy(srb->sense_buffer, usb_stor_sense_invalidCDB, sizeof(usb_stor_sense_invalidCDB)); return USB_STOR_TRANSPORT_NO_SENSE; } return USB_STOR_TRANSPORT_GOOD; case US_BULK_STAT_FAIL: return USB_STOR_TRANSPORT_FAILED; case US_BULK_STAT_PHASE: return USB_STOR_TRANSPORT_ERROR; } return USB_STOR_TRANSPORT_ERROR; } /*********************************************************************** * Reset routines ***********************************************************************/ //----- usb_stor_reset_common() --------------------- static int usb_stor_reset_common(struct us_data *us, u8 request, u8 requesttype, u16 value, u16 index, void *data, u16 size) { int result; int result2; //printk("transport --- usb_stor_reset_common\n"); if (test_bit(US_FLIDX_DISCONNECTING, &us->dflags)) { //printk("No reset during disconnect\n"); return -EIO; } result = usb_stor_control_msg(us, us->send_ctrl_pipe, request, requesttype, value, index, data, size, 5*HZ); if (result < 0) { //printk("Soft reset failed: %d\n", result); return result; } wait_event_interruptible_timeout(us->delay_wait, test_bit(US_FLIDX_DISCONNECTING, &us->dflags), HZ*6); if (test_bit(US_FLIDX_DISCONNECTING, &us->dflags)) { //printk("Reset interrupted by disconnect\n"); return -EIO; } //printk("Soft reset: clearing bulk-in endpoint halt\n"); result = usb_stor_clear_halt(us, us->recv_bulk_pipe); //printk("Soft reset: clearing bulk-out endpoint halt\n"); result2 = usb_stor_clear_halt(us, us->send_bulk_pipe); /* return a result code based on the result of the clear-halts */ if (result >= 0) result = result2; //if (result < 0) // printk("Soft reset failed\n"); //else // printk("Soft reset done\n"); return result; } //----- usb_stor_Bulk_reset() --------------------- int usb_stor_Bulk_reset(struct us_data *us) { //printk("transport --- usb_stor_Bulk_reset\n"); return usb_stor_reset_common(us, US_BULK_RESET_REQUEST, USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, us->ifnum, NULL, 0); } //----- usb_stor_port_reset() --------------------- int usb_stor_port_reset(struct us_data *us) { int result; //printk("transport --- usb_stor_port_reset\n"); result = usb_lock_device_for_reset(us->pusb_dev, us->pusb_intf); if (result < 0) printk("unable to lock device for reset: %d\n", result); else { /* Were we disconnected while waiting for the lock? */ if (test_bit(US_FLIDX_DISCONNECTING, &us->dflags)) { result = -EIO; //printk("No reset during disconnect\n"); } else { result = usb_reset_device(us->pusb_dev); //printk("usb_reset_composite_device returns %d\n", result); } usb_unlock_device(us->pusb_dev); } return result; }