⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 isd200.c

📁 基于S3CEB2410平台LINUX操作系统下 USB驱动源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
        US_DEBUGP("usb_stor_bulk_msg() returned %d xferred %d/%d\n",                  result, partial, length);        /* if we stall, we need to clear it before we go on */        if (result == -EPIPE) {                US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);                usb_stor_clear_halt(us->pusb_dev, pipe);        }            /* did we send all the data? */        if (partial == length) {                US_DEBUGP("isd200_transfer_partial(): transfer complete\n");                return ISD200_TRANSPORT_GOOD;        }        /* uh oh... we have an error code, so something went wrong. */        if (result) {                /* NAK - that means we've retried a few times already */                if (result == -ETIMEDOUT) {                        US_DEBUGP("isd200_transfer_partial(): device NAKed\n");                        return ISD200_TRANSPORT_FAILED;                }                /* -ENOENT -- we canceled this transfer */                if (result == -ENOENT) {                        US_DEBUGP("isd200_transfer_partial(): transfer aborted\n");                        return ISD200_TRANSPORT_ABORTED;                }                /* the catch-all case */                US_DEBUGP("isd200_transfer_partial(): unknown error\n");                return ISD200_TRANSPORT_FAILED;        }        /* no error code, so we must have transferred some data,          * just not all of it */        return ISD200_TRANSPORT_SHORT;}/************************************************************************** * Transfer an entire SCSI command's worth of data payload over the bulk * pipe. * * Note that this uses us_transfer_partial to achieve it's goals -- this * function simply determines if we're going to use scatter-gather or not, * and acts appropriately.  For now, it also re-interprets the error codes. */static void isd200_transfer( struct us_data *us, Scsi_Cmnd *srb ){        int i;        int result = -1;        struct scatterlist *sg;        unsigned int total_transferred = 0;        unsigned int transfer_amount;        /* calculate how much we want to transfer */	int dir = srb->sc_data_direction;	srb->sc_data_direction = SCSI_DATA_WRITE;        transfer_amount = usb_stor_transfer_length(srb);	srb->sc_data_direction = dir;        /* was someone foolish enough to request more data than available         * buffer space? */        if (transfer_amount > srb->request_bufflen)                transfer_amount = srb->request_bufflen;        /* are we scatter-gathering? */        if (srb->use_sg) {                /* loop over all the scatter gather structures and                  * make the appropriate requests for each, until done                 */                sg = (struct scatterlist *) srb->request_buffer;                for (i = 0; i < srb->use_sg; i++) {                        /* transfer the lesser of the next buffer or the                         * remaining data */                        if (transfer_amount - total_transferred >=                             sg[i].length) {                                result = isd200_transfer_partial(us,                                                                  srb->sc_data_direction,                                                                 sg[i].address,                                                                  sg[i].length);                                total_transferred += sg[i].length;                        } else                                result = isd200_transfer_partial(us,                                                                  srb->sc_data_direction,                                                                                             sg[i].address,                                                                 transfer_amount - total_transferred);                        /* if we get an error, end the loop here */                        if (result)                                break;                }        }        else                /* no scatter-gather, just make the request */                result = isd200_transfer_partial(us,                                                  srb->sc_data_direction,                                                 srb->request_buffer,                                                  transfer_amount);        /* return the result in the data structure itself */        srb->result = result;}/*********************************************************************** * Transport routines ***********************************************************************//************************************************************************** *  ISD200 Bulk Transport * * Note:  This routine was copied from the usb_stor_Bulk_transport routine * located in the transport.c source file.  The scsi command is limited to * only 12 bytes while the CDB for the ISD200 must be 16 bytes. */int isd200_Bulk_transport( struct us_data *us, Scsi_Cmnd *srb,                            union ata_cdb *AtaCdb, unsigned char AtaCdbLength ){        struct bulk_cb_wrap bcb;        struct bulk_cs_wrap bcs;        int result;        int pipe;        int partial;        unsigned int transfer_amount;	int dir = srb->sc_data_direction;	srb->sc_data_direction = SCSI_DATA_WRITE;        transfer_amount = usb_stor_transfer_length(srb);	srb->sc_data_direction = dir;            /* set up the command wrapper */        bcb.Signature = cpu_to_le32(US_BULK_CB_SIGN);        bcb.DataTransferLength = cpu_to_le32(transfer_amount);        bcb.Flags = srb->sc_data_direction == SCSI_DATA_READ ? 1 << 7 : 0;        bcb.Tag = srb->serial_number;        bcb.Lun = srb->cmnd[1] >> 5;        if (us->flags & US_FL_SCM_MULT_TARG)                bcb.Lun |= srb->target << 4;        bcb.Length = AtaCdbLength;            /* construct the pipe handle */        pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);            /* copy the command payload */        memset(bcb.CDB, 0, sizeof(bcb.CDB));        memcpy(bcb.CDB, AtaCdb, bcb.Length);            /* send it to out endpoint */        US_DEBUGP("Bulk command S 0x%x T 0x%x Trg %d LUN %d L %d F %d CL %d\n",                  le32_to_cpu(bcb.Signature), bcb.Tag,                  (bcb.Lun >> 4), (bcb.Lun & 0xFF),                   bcb.DataTransferLength, bcb.Flags, bcb.Length);        result = usb_stor_bulk_msg(us, &bcb, pipe, US_BULK_CB_WRAP_LEN, 				   &partial);        US_DEBUGP("Bulk command transfer result=%d\n", result);    	if (result == -ENOENT)		return ISD200_TRANSPORT_ABORTED;	else if (result == -EPIPE) {		/* if we stall, we need to clear it before we go on */                US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);                usb_stor_clear_halt(us->pusb_dev, pipe);	} else if (result)                  return ISD200_TRANSPORT_ERROR;            /* if the command transfered well, then we go to the data stage */        if (!result && bcb.DataTransferLength) {		isd200_transfer(us, srb);		US_DEBUGP("Bulk data transfer result 0x%x\n", srb->result);				if (srb->result == ISD200_TRANSPORT_ABORTED)			return ISD200_TRANSPORT_ABORTED;        }            /* See flow chart on pg 15 of the Bulk Only Transport spec for         * an explanation of how this code works.         */            /* construct the pipe handle */        pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);            /* get CSW for device status */        US_DEBUGP("Attempting to get CSW...\n");        result = usb_stor_bulk_msg(us, &bcs, pipe, US_BULK_CS_WRAP_LEN, 				   &partial);        if (result == -ENOENT)                return ISD200_TRANSPORT_ABORTED;        /* did the attempt to read the CSW fail? */        if (result == -EPIPE) {                US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);                usb_stor_clear_halt(us->pusb_dev, pipe);                           /* get the status again */                US_DEBUGP("Attempting to get CSW (2nd try)...\n");                result = usb_stor_bulk_msg(us, &bcs, pipe,                                           US_BULK_CS_WRAP_LEN, &partial);                /* if the command was aborted, indicate that */                if (result == -ENOENT)                        return ISD200_TRANSPORT_ABORTED;                        /* if it fails again, we need a reset and return an error*/                if (result == -EPIPE) {                        US_DEBUGP("clearing halt for pipe 0x%x\n", pipe);                        usb_stor_clear_halt(us->pusb_dev, pipe);                        return ISD200_TRANSPORT_ERROR;                }        }            /* if we still have a failure at this point, we're in trouble */        US_DEBUGP("Bulk status result = %d\n", result);        if (result)                return ISD200_TRANSPORT_ERROR;            /* check bulk status */        US_DEBUGP("Bulk status Sig 0x%x T 0x%x R %d Stat 0x%x\n",                  le32_to_cpu(bcs.Signature), bcs.Tag,                   bcs.Residue, bcs.Status);        if (bcs.Signature != cpu_to_le32(US_BULK_CS_SIGN) ||             bcs.Tag != bcb.Tag ||             bcs.Status > US_BULK_STAT_PHASE || partial != 13) {                US_DEBUGP("Bulk logical error\n");                return ISD200_TRANSPORT_ERROR;        }            /* based on the status code, we report good or bad */        switch (bcs.Status) {        case US_BULK_STAT_OK:                /* command good -- note that we could be short on data */                return ISD200_TRANSPORT_GOOD;        case US_BULK_STAT_FAIL:                /* command failed */                return ISD200_TRANSPORT_FAILED;                case US_BULK_STAT_PHASE:                /* phase error */                usb_stor_Bulk_reset(us);                return ISD200_TRANSPORT_ERROR;        }            /* we should never get here, but if we do, we're in trouble */        return ISD200_TRANSPORT_ERROR;}/************************************************************************** *  isd200_action * * Routine for sending commands to the isd200 * * RETURNS: *    ISD status code */static int isd200_action( struct us_data *us, int action, 			  void* pointer, int value ){	union ata_cdb ata;	struct scsi_cmnd srb;	struct isd200_info *info = (struct isd200_info *)us->extra;	int status;	memset(&ata, 0, sizeof(ata));	memset(&srb, 0, sizeof(srb));	ata.generic.SignatureByte0 = info->ConfigData.ATAMajorCommand;	ata.generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;	ata.generic.TransferBlockSize = 1;	switch ( action ) {	case ACTION_READ_STATUS:		US_DEBUGP("   isd200_action(READ_STATUS)\n");		ata.generic.ActionSelect = ACTION_SELECT_0|ACTION_SELECT_2;		ata.read.SelectStatus = 1;		ata.read.SelectError = 1;		ata.read.SelectCylinderHigh = 1;		ata.read.SelectCylinderLow = 1;		srb.sc_data_direction = SCSI_DATA_READ;		srb.request_buffer = pointer;		srb.request_bufflen = value;		break;	case ACTION_ENUM:		US_DEBUGP("   isd200_action(ENUM,0x%02x)\n",value);		ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_2|			                   ACTION_SELECT_3|ACTION_SELECT_4|		                           ACTION_SELECT_5;		ata.write.SelectDeviceHead = 1;		ata.write.DeviceHeadByte = value;		srb.sc_data_direction = SCSI_DATA_NONE;		break;	case ACTION_RESET:		US_DEBUGP("   isd200_action(RESET)\n");		ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_2|			                   ACTION_SELECT_3|ACTION_SELECT_4;		ata.write.SelectDeviceControl = 1;		ata.write.DeviceControlByte = ATA_DC_RESET_CONTROLLER;		srb.sc_data_direction = SCSI_DATA_NONE;		break;	case ACTION_REENABLE:		US_DEBUGP("   isd200_action(REENABLE)\n");		ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_2|			                   ACTION_SELECT_3|ACTION_SELECT_4;		ata.write.SelectDeviceControl = 1;		ata.write.DeviceControlByte = ATA_DC_REENABLE_CONTROLLER;		srb.sc_data_direction = SCSI_DATA_NONE;		break;	case ACTION_SOFT_RESET:		US_DEBUGP("   isd200_action(SOFT_RESET)\n");		ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_5;		ata.write.SelectDeviceHead = 1;		ata.write.DeviceHeadByte = info->DeviceHead;		ata.write.SelectCommand = 1;		ata.write.CommandByte = WIN_SRST;		srb.sc_data_direction = SCSI_DATA_NONE;		break;	case ACTION_IDENTIFY:		US_DEBUGP("   isd200_action(IDENTIFY)\n");		ata.write.SelectCommand = 1;		ata.write.CommandByte = WIN_IDENTIFY;		srb.sc_data_direction = SCSI_DATA_READ;		srb.request_buffer = (void *)&info->drive;		srb.request_bufflen = sizeof(struct hd_driveid);		break;	default:		US_DEBUGP("Error: Undefined action %d\n",action);		break;	}	status = isd200_Bulk_transport(us, &srb, &ata, sizeof(ata.generic));	if (status != ISD200_TRANSPORT_GOOD) {		US_DEBUGP("   isd200_action(0x%02x) error: %d\n",action,status);		status = ISD200_ERROR;		/* need to reset device here */	}	return status;}/************************************************************************** * isd200_read_regs *                                                                          * Read ATA Registers * * RETURNS: *    ISD status code */                                                                        int isd200_read_regs( struct us_data *us ){	struct isd200_info *info = (struct isd200_info *)us->extra;	int retStatus = ISD200_GOOD;	int transferStatus;	US_DEBUGP("Entering isd200_IssueATAReadRegs\n");	transferStatus = isd200_action( us, ACTION_READ_STATUS,				    info->ATARegs, sizeof(info->ATARegs) );	if (transferStatus != ISD200_TRANSPORT_GOOD) {		US_DEBUGP("   Error reading ATA registers\n");		retStatus = ISD200_ERROR;        } else {		US_DEBUGP("   Got ATA Register[IDE_ERROR_OFFSET] = 0x%x\n", 			  info->ATARegs[IDE_ERROR_OFFSET]);        }	return retStatus;}/************************************************************************** * 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 recieve the response. */void isd200_invoke_transport( struct us_data *us, 			      Scsi_Cmnd *srb, 			      union ata_cdb *ataCdb ){	int need_auto_sense = 0;	int transferStatus;	/* send the command to the transport layer */	transferStatus = isd200_Bulk_transport(us, srb, ataCdb,					       sizeof(ataCdb->generic));	switch (transferStatus) {	case ISD200_TRANSPORT_GOOD:		/* Indicate a good result */		srb->result = GOOD;		break;	case ISD200_TRANSPORT_ABORTED:		/* if the command gets aborted by the higher layers, we need to		 * short-circuit all other processing		 */		US_DEBUGP("-- transport indicates command was aborted\n");		srb->result = DID_ABORT << 16;		break;	case ISD200_TRANSPORT_FAILED:		US_DEBUGP("-- transport indicates command failure\n");		need_auto_sense = 1;		break;	case ISD200_TRANSPORT_ERROR:		US_DEBUGP("-- transport indicates transport failure\n");		srb->result = DID_ERROR << 16;		break;	case ISD200_TRANSPORT_SHORT:		if (!((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))) {			US_DEBUGP("-- unexpectedly short transfer\n");			need_auto_sense = 1;		}		break;    	default:		US_DEBUGP("-- transport indicates unknown failure\n");   		srb->result = DID_ERROR << 16;       	}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -