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

📄 shuttle_usbat.c

📁 h内核
💻 C
📖 第 1 页 / 共 2 页
字号:
/* Driver for SCM Microsystems USB-ATAPI cable * * $Id: shuttle_usbat.c,v 1.17 2002/04/22 03:39:43 mdharm Exp $ * * Current development and maintenance by: *   (c) 2000, 2001 Robert Baruch (autophile@starband.net) * * Developed with the assistance of: *   (c) 2002 Alan Stern <stern@rowland.org> * * Many originally ATAPI devices were slightly modified to meet the USB * market by using some kind of translation from ATAPI to USB on the host, * and the peripheral would translate from USB back to ATAPI. * * SCM Microsystems (www.scmmicro.com) makes a device, sold to OEM's only,  * which does the USB-to-ATAPI conversion.  By obtaining the data sheet on * their device under nondisclosure agreement, I have been able to write * this driver for Linux. * * The chip used in the device can also be used for EPP and ISA translation * as well. This driver is only guaranteed to work with the ATAPI * translation. * * The only peripheral that I know of (as of 27 Mar 2001) that uses this * device is the Hewlett-Packard 8200e/8210e/8230e CD-Writer Plus. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 675 Mass Ave, Cambridge, MA 02139, USA. */#include <linux/sched.h>#include <linux/errno.h>#include <linux/slab.h>#include <linux/cdrom.h>#include <scsi/scsi.h>#include <scsi/scsi_cmnd.h>#include "transport.h"#include "protocol.h"#include "usb.h"#include "debug.h"#include "shuttle_usbat.h"#define short_pack(LSB,MSB) ( ((u16)(LSB)) | ( ((u16)(MSB))<<8 ) )#define LSB_of(s) ((s)&0xFF)#define MSB_of(s) ((s)>>8)int transferred = 0;static int usbat_read(struct us_data *us,		      unsigned char access,		      unsigned char reg,		      unsigned char *content){	int result;	result = usb_stor_ctrl_transfer(us,		us->recv_ctrl_pipe,		access,		0xC0,		(u16)reg,		0,		content,		1);	return result;}static int usbat_write(struct us_data *us,		       unsigned char access,		       unsigned char reg,		       unsigned char content){	int result;	result = usb_stor_ctrl_transfer(us,		us->send_ctrl_pipe,		access|0x01,		0x40,		short_pack(reg, content),		0,		NULL,		0);	return result;}static int usbat_set_shuttle_features(struct us_data *us,				      unsigned char external_trigger,				      unsigned char epp_control,				      unsigned char mask_byte,				      unsigned char test_pattern,				      unsigned char subcountH,				      unsigned char subcountL){	int result;	unsigned char *command = us->iobuf;	command[0] = 0x40;	command[1] = 0x81;	command[2] = epp_control;	command[3] = external_trigger;	command[4] = test_pattern;	command[5] = mask_byte;	command[6] = subcountL;	command[7] = subcountH;	result = usb_stor_ctrl_transfer(us,		us->send_ctrl_pipe,		0x80,		0x40,		0,		0,		command,		8);	return result;}static int usbat_read_block(struct us_data *us,			    unsigned char access,			    unsigned char reg,			    unsigned char *content,			    unsigned short len,			    int use_sg){	int result;	unsigned char *command = us->iobuf;	if (!len)		return USB_STOR_TRANSPORT_GOOD;	command[0] = 0xC0;	command[1] = access | 0x02;	command[2] = reg;	command[3] = 0;	command[4] = 0;	command[5] = 0;	command[6] = LSB_of(len);	command[7] = MSB_of(len);	result = usb_stor_ctrl_transfer(us,		us->send_ctrl_pipe,		0x80,		0x40,		0,		0,		command,		8);	if (result != USB_STOR_XFER_GOOD)		return USB_STOR_TRANSPORT_ERROR;	result = usb_stor_bulk_transfer_sg(us, us->recv_bulk_pipe,			content, len, use_sg, NULL);	return (result == USB_STOR_XFER_GOOD ?			USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR);}/* * Block, waiting for an ATA device to become not busy or to report * an error condition. */static int usbat_wait_not_busy(struct us_data *us, int minutes){	int i;	int result;	unsigned char *status = us->iobuf;	/* Synchronizing cache on a CDR could take a heck of a long time,	 * but probably not more than 10 minutes or so. On the other hand,	 * doing a full blank on a CDRW at speed 1 will take about 75	 * minutes!	 */	for (i=0; i<1200+minutes*60; i++) { 		result = usbat_read(us, USBAT_ATA, 0x17, status);		if (result!=USB_STOR_XFER_GOOD)			return USB_STOR_TRANSPORT_ERROR;		if (*status & 0x01) { // check condition			result = usbat_read(us, USBAT_ATA, 0x10, status);			return USB_STOR_TRANSPORT_FAILED;		}		if (*status & 0x20) // device fault			return USB_STOR_TRANSPORT_FAILED;		if ((*status & 0x80)==0x00) { // not busy			US_DEBUGP("Waited not busy for %d steps\n", i);			return USB_STOR_TRANSPORT_GOOD;		}		if (i<500)			msleep(10); // 5 seconds		else if (i<700)			msleep(50); // 10 seconds		else if (i<1200)			msleep(100); // 50 seconds		else			msleep(1000); // X minutes	}	US_DEBUGP("Waited not busy for %d minutes, timing out.\n",		minutes);	return USB_STOR_TRANSPORT_FAILED;}static int usbat_write_block(struct us_data *us,			     unsigned char access, 			     unsigned char reg,			     unsigned char *content,			     unsigned short len,			     int use_sg, int minutes){	int result;	unsigned char *command = us->iobuf;	if (!len)		return USB_STOR_TRANSPORT_GOOD;	command[0] = 0x40;	command[1] = access | 0x03;	command[2] = reg;	command[3] = 0;	command[4] = 0;	command[5] = 0;	command[6] = LSB_of(len);	command[7] = MSB_of(len);	result = usb_stor_ctrl_transfer(us,		us->send_ctrl_pipe,		0x80,		0x40,		0,		0,		command,		8);	if (result != USB_STOR_XFER_GOOD)		return USB_STOR_TRANSPORT_ERROR;	result = usb_stor_bulk_transfer_sg(us, us->send_bulk_pipe,			content, len, use_sg, NULL);	if (result != USB_STOR_XFER_GOOD)		return USB_STOR_TRANSPORT_ERROR;	return usbat_wait_not_busy(us, minutes);}static int usbat_rw_block_test(struct us_data *us,			       unsigned char access,			       unsigned char *registers,			       unsigned char *data_out,			       unsigned short num_registers,			       unsigned char data_reg,			       unsigned char status_reg,			       unsigned char timeout,			       unsigned char qualifier,			       int direction,			       unsigned char *content,			       unsigned short len,			       int use_sg,			       int minutes){	int result;	unsigned int pipe = (direction == DMA_FROM_DEVICE) ?			us->recv_bulk_pipe : us->send_bulk_pipe;	// Not really sure the 0x07, 0x17, 0xfc, 0xe7 is necessary here,	// but that's what came out of the trace every single time.	unsigned char *command = us->iobuf;	int i, j;	int cmdlen;	unsigned char *data = us->iobuf;	unsigned char *status = us->iobuf;	BUG_ON(num_registers > US_IOBUF_SIZE/2);	for (i=0; i<20; i++) {		/*		 * The first time we send the full command, which consists		 * of downloading the SCSI command followed by downloading		 * the data via a write-and-test.  Any other time we only		 * send the command to download the data -- the SCSI command		 * is still 'active' in some sense in the device.		 * 		 * We're only going to try sending the data 10 times. After		 * that, we just return a failure.		 */		if (i==0) {			cmdlen = 16;			command[0] = 0x40;			command[1] = access | 0x07;			command[2] = 0x07;			command[3] = 0x17;			command[4] = 0xFC;			command[5] = 0xE7;			command[6] = LSB_of(num_registers*2);			command[7] = MSB_of(num_registers*2);		} else			cmdlen = 8;		command[cmdlen-8] = (direction==DMA_TO_DEVICE ? 0x40 : 0xC0);		command[cmdlen-7] = access |				(direction==DMA_TO_DEVICE ? 0x05 : 0x04);		command[cmdlen-6] = data_reg;		command[cmdlen-5] = status_reg;		command[cmdlen-4] = timeout;		command[cmdlen-3] = qualifier;		command[cmdlen-2] = LSB_of(len);		command[cmdlen-1] = MSB_of(len);		result = usb_stor_ctrl_transfer(us,			us->send_ctrl_pipe,			0x80,			0x40,			0,			0,			command,			cmdlen);		if (result != USB_STOR_XFER_GOOD)			return USB_STOR_TRANSPORT_ERROR;		if (i==0) {			for (j=0; j<num_registers; j++) {				data[j<<1] = registers[j];				data[1+(j<<1)] = data_out[j];			}			result = usb_stor_bulk_transfer_buf(us,					us->send_bulk_pipe,					data, num_registers*2, NULL);			if (result != USB_STOR_XFER_GOOD)				return USB_STOR_TRANSPORT_ERROR;		}		//US_DEBUGP("Transfer %s %d bytes, sg buffers %d\n",		//	direction == DMA_TO_DEVICE ? "out" : "in",		//	len, use_sg);		result = usb_stor_bulk_transfer_sg(us,			pipe, content, len, use_sg, NULL);		/*		 * If we get a stall on the bulk download, we'll retry		 * the bulk download -- but not the SCSI command because		 * in some sense the SCSI command is still 'active' and		 * waiting for the data. Don't ask me why this should be;		 * I'm only following what the Windoze driver did.		 *		 * Note that a stall for the test-and-read/write command means		 * that the test failed. In this case we're testing to make		 * sure that the device is error-free		 * (i.e. bit 0 -- CHK -- of status is 0). The most likely		 * hypothesis is that the USBAT chip somehow knows what		 * the device will accept, but doesn't give the device any		 * data until all data is received. Thus, the device would		 * still be waiting for the first byte of data if a stall		 * occurs, even if the stall implies that some data was		 * transferred.		 */		if (result == USB_STOR_XFER_SHORT ||				result == USB_STOR_XFER_STALLED) {			/*			 * If we're reading and we stalled, then clear			 * the bulk output pipe only the first time.			 */			if (direction==DMA_FROM_DEVICE && i==0) {				if (usb_stor_clear_halt(us,						us->send_bulk_pipe) < 0)					return USB_STOR_TRANSPORT_ERROR;			}			/*			 * Read status: is the device angry, or just busy?			 */ 			result = usbat_read(us, USBAT_ATA, 				direction==DMA_TO_DEVICE ? 0x17 : 0x0E, 				status);			if (result!=USB_STOR_XFER_GOOD)				return USB_STOR_TRANSPORT_ERROR;			if (*status & 0x01) // check condition				return USB_STOR_TRANSPORT_FAILED;			if (*status & 0x20) // device fault				return USB_STOR_TRANSPORT_FAILED;			US_DEBUGP("Redoing %s\n",			  direction==DMA_TO_DEVICE ? "write" : "read");		} else if (result != USB_STOR_XFER_GOOD)			return USB_STOR_TRANSPORT_ERROR;		else			return usbat_wait_not_busy(us, minutes);	}	US_DEBUGP("Bummer! %s bulk data 20 times failed.\n",		direction==DMA_TO_DEVICE ? "Writing" : "Reading");	return USB_STOR_TRANSPORT_FAILED;}/* * Write data to multiple registers at once. Not meant for large * transfers of data! */static int usbat_multiple_write(struct us_data *us,				unsigned char access,				unsigned char *registers,				unsigned char *data_out,				unsigned short num_registers){	int result;	unsigned char *data = us->iobuf;	int i;	unsigned char *command = us->iobuf;	BUG_ON(num_registers > US_IOBUF_SIZE/2);	command[0] = 0x40;	command[1] = access | 0x07;	command[2] = 0;	command[3] = 0;	command[4] = 0;	command[5] = 0;	command[6] = LSB_of(num_registers*2);	command[7] = MSB_of(num_registers*2);	result = usb_stor_ctrl_transfer(us,		us->send_ctrl_pipe,		0x80,		0x40,		0,		0,		command,		8);	if (result != USB_STOR_XFER_GOOD)		return USB_STOR_TRANSPORT_ERROR;	for (i=0; i<num_registers; i++) {		data[i<<1] = registers[i];		data[1+(i<<1)] = data_out[i];	}	result = usb_stor_bulk_transfer_buf(us,

⌨️ 快捷键说明

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