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

📄 freecom.c

📁 linux下的usb接口驱动程序
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Transport for the Freecom USB/IDE adaptor. * */int freecom_transport(Scsi_Cmnd *srb, struct us_data *us){        struct freecom_cb_wrap *fcb;        struct freecom_status  *fst;        int ipipe, opipe;             /* We need both pipes. */        int result;        int partial;        int length;        freecom_udata_t extra;        extra = (freecom_udata_t) us->extra;        fcb = (struct freecom_cb_wrap *) extra->buffer;        fst = (struct freecom_status *) extra->buffer;        US_DEBUGP("Freecom TRANSPORT STARTED\n");        /* Get handles for both transports. */        opipe = usb_sndbulkpipe (us->pusb_dev, us->ep_out);        ipipe = usb_rcvbulkpipe (us->pusb_dev, us->ep_in);        /* The ATAPI Command always goes out first. */        fcb->Type = FCM_PACKET_ATAPI | 0x00;        fcb->Timeout = 0;        memcpy (fcb->Atapi, srb->cmnd, 12);        memset (fcb->Filler, 0, sizeof (fcb->Filler));        US_DEBUG(pdump (srb->cmnd, 12));        /* Send it out. */        result = usb_stor_bulk_msg (us, fcb, opipe,                        FCM_PACKET_LENGTH, &partial);        /* The Freecom device will only fail if there is something wrong in         * USB land.  It returns the status in its own registers, which         * come back in the bulk pipe. */        if (result != 0) {                US_DEBUGP ("freecom xport failure: r=%d, p=%d\n",                                result, partial);		/* -ENOENT -- we canceled this transfer */		if (result == -ENOENT) {			US_DEBUGP("freecom_transport(): transfer aborted\n");			return US_BULK_TRANSFER_ABORTED;		}                return USB_STOR_TRANSPORT_ERROR;        }        /* There are times we can optimize out this status read, but it         * doesn't hurt us to always do it now. */        result = usb_stor_bulk_msg (us, fst, ipipe,                        FCM_PACKET_LENGTH, &partial);        US_DEBUGP("foo Status result %d %d\n", result, partial);	/* -ENOENT -- we canceled this transfer */	if (result == -ENOENT) {		US_DEBUGP("freecom_transport(): transfer aborted\n");		return US_BULK_TRANSFER_ABORTED;	}        US_DEBUG(pdump ((void *) fst, partial));	/* The firmware will time-out commands after 20 seconds. Some commands	 * can legitimately take longer than this, so we use a different	 * command that only waits for the interrupt and then sends status,	 * without having to send a new ATAPI command to the device. 	 *	 * NOTE: There is some indication that a data transfer after a timeout	 * may not work, but that is a condition that should never happen.	 */	while (fst->Status & FCM_STATUS_BUSY) {		US_DEBUGP("20 second USB/ATAPI bridge TIMEOUT occured!\n");		US_DEBUGP("fst->Status is %x\n", fst->Status);		/* Get the status again */		fcb->Type = FCM_PACKET_STATUS;		fcb->Timeout = 0;		memset (fcb->Atapi, 0, sizeof(fcb->Atapi));		memset (fcb->Filler, 0, sizeof (fcb->Filler));        	/* Send it out. */		result = usb_stor_bulk_msg (us, fcb, opipe,				FCM_PACKET_LENGTH, &partial);		/* The Freecom device will only fail if there is something		 * wrong in USB land.  It returns the status in its own		 * registers, which come back in the bulk pipe.		 */		if (result != 0) {			US_DEBUGP ("freecom xport failure: r=%d, p=%d\n",					result, partial);			/* -ENOENT -- we canceled this transfer */			if (result == -ENOENT) {				US_DEBUGP("freecom_transport(): transfer aborted\n");				return US_BULK_TRANSFER_ABORTED;			}			return USB_STOR_TRANSPORT_ERROR;		}		/* get the data */        	result = usb_stor_bulk_msg (us, fst, ipipe,				FCM_PACKET_LENGTH, &partial);		US_DEBUGP("bar Status result %d %d\n", result, partial);		/* -ENOENT -- we canceled this transfer */		if (result == -ENOENT) {			US_DEBUGP("freecom_transport(): transfer aborted\n");			return US_BULK_TRANSFER_ABORTED;		}		US_DEBUG(pdump ((void *) fst, partial));	}        if (partial != 4 || result != 0) {                return USB_STOR_TRANSPORT_ERROR;        }        if ((fst->Status & 1) != 0) {                US_DEBUGP("operation failed\n");                return USB_STOR_TRANSPORT_FAILED;        }        /* The device might not have as much data available as we         * requested.  If you ask for more than the device has, this reads         * and such will hang. */        US_DEBUGP("Device indicates that it has %d bytes available\n",                        le16_to_cpu (fst->Count));        US_DEBUGP("SCSI requested %d\n", usb_stor_transfer_length(srb));        /* Find the length we desire to read. */	switch (srb->cmnd[0]) {		case INQUIRY:		case REQUEST_SENSE:		/* 16 or 18 bytes? spec says 18, lots of devices only have 16 */		case MODE_SENSE:		case MODE_SENSE_10:			length = fst->Count;			break;		default: 			length = usb_stor_transfer_length (srb);	}	/* verify that this amount is legal */	if (length > srb->request_bufflen) {		length = srb->request_bufflen;		US_DEBUGP("Truncating request to match buffer length: %d\n", length);	}        /* What we do now depends on what direction the data is supposed to         * move in. */        switch (us->srb->sc_data_direction) {        case SCSI_DATA_READ:                /* Make sure that the status indicates that the device                 * wants data as well. */                if ((fst->Status & DRQ_STAT) == 0 || (fst->Reason & 3) != 2) {                        US_DEBUGP("SCSI wants data, drive doesn't have any\n");                        return USB_STOR_TRANSPORT_FAILED;                }                result = freecom_readdata (srb, us, ipipe, opipe, length);                if (result != USB_STOR_TRANSPORT_GOOD)                        return result;                US_DEBUGP("FCM: Waiting for status\n");                result = usb_stor_bulk_msg (us, fst, ipipe,                                FCM_PACKET_LENGTH, &partial);		US_DEBUG(pdump ((void *) fst, partial));                if (result == -ENOENT) {                        US_DEBUGP ("freecom_transport: transfer aborted\n");                        return US_BULK_TRANSFER_ABORTED;                }                if (partial != 4 || result != 0)                        return USB_STOR_TRANSPORT_ERROR;                if ((fst->Status & ERR_STAT) != 0) {                        US_DEBUGP("operation failed\n");                        return USB_STOR_TRANSPORT_FAILED;                }                if ((fst->Reason & 3) != 3) {                        US_DEBUGP("Drive seems still hungry\n");                        return USB_STOR_TRANSPORT_FAILED;                }                US_DEBUGP("Transfer happy\n");                break;        case SCSI_DATA_WRITE:                /* Make sure the status indicates that the device wants to                 * send us data. */                /* !!IMPLEMENT!! */                result = freecom_writedata (srb, us, ipipe, opipe, length);                if (result != USB_STOR_TRANSPORT_GOOD)                        return result;                US_DEBUGP("FCM: Waiting for status\n");                result = usb_stor_bulk_msg (us, fst, ipipe,                                FCM_PACKET_LENGTH, &partial);                if (result == -ENOENT) {                        US_DEBUGP ("freecom_transport: transfer aborted\n");                        return US_BULK_TRANSFER_ABORTED;                }                if (partial != 4 || result != 0)                        return USB_STOR_TRANSPORT_ERROR;                if ((fst->Status & ERR_STAT) != 0) {                        US_DEBUGP("operation failed\n");                        return USB_STOR_TRANSPORT_FAILED;                }                if ((fst->Reason & 3) != 3) {                        US_DEBUGP("Drive seems still hungry\n");                        return USB_STOR_TRANSPORT_FAILED;                }                US_DEBUGP("Transfer happy\n");                break;        case SCSI_DATA_NONE:                /* Easy, do nothing. */                break;        default:                US_DEBUGP ("freecom unimplemented direction: %d\n",                                us->srb->sc_data_direction);                // Return fail, SCSI seems to handle this better.                return USB_STOR_TRANSPORT_FAILED;                break;        }        return USB_STOR_TRANSPORT_GOOD;        US_DEBUGP("Freecom: transfer_length = %d\n",			usb_stor_transfer_length (srb));        US_DEBUGP("Freecom: direction = %d\n", srb->sc_data_direction);        return USB_STOR_TRANSPORT_ERROR;}intfreecom_init (struct us_data *us){        int result;	char buffer[33];        /* Allocate a buffer for us.  The upper usb transport code will         * free this for us when cleaning up. */        if (us->extra == NULL) {                us->extra = kmalloc (sizeof (struct freecom_udata),                                GFP_KERNEL);                if (us->extra == NULL) {                        US_DEBUGP("Out of memory\n");                        return USB_STOR_TRANSPORT_ERROR;                }        }	result = usb_control_msg(us->pusb_dev,			usb_rcvctrlpipe(us->pusb_dev, 0),			0x4c, 0xc0, 0x4346, 0x0, buffer, 0x20, 3*HZ);	buffer[32] = '\0';	US_DEBUGP("String returned from FC init is: %s\n", buffer);	/* Special thanks to the people at Freecom for providing me with	 * this "magic sequence", which they use in their Windows and MacOS	 * drivers to make sure that all the attached perhiperals are	 * properly reset.	 */	/* send reset */	result = usb_control_msg(us->pusb_dev,			usb_sndctrlpipe(us->pusb_dev, 0),			0x4d, 0x40, 0x24d8, 0x0, NULL, 0x0, 3*HZ);	US_DEBUGP("result from activate reset is %d\n", result);	/* wait 250ms */	mdelay(250);	/* clear reset */	result = usb_control_msg(us->pusb_dev,			usb_sndctrlpipe(us->pusb_dev, 0),			0x4d, 0x40, 0x24f8, 0x0, NULL, 0x0, 3*HZ);	US_DEBUGP("result from clear reset is %d\n", result);	/* wait 3 seconds */	mdelay(3 * 1000);        return USB_STOR_TRANSPORT_GOOD;}int usb_stor_freecom_reset(struct us_data *us){        printk (KERN_CRIT "freecom reset called\n");        /* We don't really have this feature. */        return FAILED;}#ifdef CONFIG_USB_STORAGE_DEBUGstatic void pdump (void *ibuffer, int length){	static char line[80];	int offset = 0;	unsigned char *buffer = (unsigned char *) ibuffer;	int i, j;	int from, base;	offset = 0;	for (i = 0; i < length; i++) {		if ((i & 15) == 0) {			if (i > 0) {				offset += sprintf (line+offset, " - ");				for (j = i - 16; j < i; j++) {					if (buffer[j] >= 32 && buffer[j] <= 126)						line[offset++] = buffer[j];					else						line[offset++] = '.';				}				line[offset] = 0;				US_DEBUGP("%s\n", line);				offset = 0;			}			offset += sprintf (line+offset, "%08x:", i);		}		else if ((i & 7) == 0) {			offset += sprintf (line+offset, " -");		}		offset += sprintf (line+offset, " %02x", buffer[i] & 0xff);	}	/* Add the last "chunk" of data. */	from = (length - 1) % 16;	base = ((length - 1) / 16) * 16;	for (i = from + 1; i < 16; i++)		offset += sprintf (line+offset, "   ");	if (from < 8)		offset += sprintf (line+offset, "  ");	offset += sprintf (line+offset, " - ");	for (i = 0; i <= from; i++) {		if (buffer[base+i] >= 32 && buffer[base+i] <= 126)			line[offset++] = buffer[base+i];		else			line[offset++] = '.';	}	line[offset] = 0;	US_DEBUGP("%s\n", line);	offset = 0;}#endif

⌨️ 快捷键说明

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