727 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			727 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
	ppc6lnx.c (c) 2001 Micro Solutions Inc.
 | 
						|
		Released under the terms of the GNU General Public license
 | 
						|
 | 
						|
	ppc6lnx.c  is a par of the protocol driver for the Micro Solutions
 | 
						|
		"BACKPACK" parallel port IDE adapter
 | 
						|
		(Works on Series 6 drives)
 | 
						|
 | 
						|
*/
 | 
						|
 | 
						|
//***************************************************************************
 | 
						|
 | 
						|
// PPC 6 Code in C sanitized for LINUX
 | 
						|
// Original x86 ASM by Ron, Converted to C by Clive
 | 
						|
 | 
						|
//***************************************************************************
 | 
						|
 | 
						|
 | 
						|
#define port_stb					1
 | 
						|
#define port_afd					2
 | 
						|
#define cmd_stb						port_afd
 | 
						|
#define port_init					4
 | 
						|
#define data_stb					port_init
 | 
						|
#define port_sel					8
 | 
						|
#define port_int					16
 | 
						|
#define port_dir					0x20
 | 
						|
 | 
						|
#define ECR_EPP	0x80
 | 
						|
#define ECR_BI	0x20
 | 
						|
 | 
						|
//***************************************************************************
 | 
						|
 | 
						|
//  60772 Commands
 | 
						|
 | 
						|
#define ACCESS_REG				0x00
 | 
						|
#define ACCESS_PORT				0x40
 | 
						|
 | 
						|
#define ACCESS_READ				0x00
 | 
						|
#define ACCESS_WRITE			0x20
 | 
						|
 | 
						|
//  60772 Command Prefix
 | 
						|
 | 
						|
#define CMD_PREFIX_SET		0xe0		// Special command that modifies the next command's operation
 | 
						|
#define CMD_PREFIX_RESET	0xc0		// Resets current cmd modifier reg bits
 | 
						|
 #define PREFIX_IO16			0x01		// perform 16-bit wide I/O
 | 
						|
 #define PREFIX_FASTWR		0x04		// enable PPC mode fast-write
 | 
						|
 #define PREFIX_BLK				0x08		// enable block transfer mode
 | 
						|
 | 
						|
// 60772 Registers
 | 
						|
 | 
						|
#define REG_STATUS				0x00		// status register
 | 
						|
 #define STATUS_IRQA			0x01		// Peripheral IRQA line
 | 
						|
 #define STATUS_EEPROM_DO	0x40		// Serial EEPROM data bit
 | 
						|
#define REG_VERSION				0x01		// PPC version register (read)
 | 
						|
#define REG_HWCFG					0x02		// Hardware Config register
 | 
						|
#define REG_RAMSIZE				0x03		// Size of RAM Buffer
 | 
						|
 #define RAMSIZE_128K			0x02
 | 
						|
#define REG_EEPROM				0x06		// EEPROM control register
 | 
						|
 #define EEPROM_SK				0x01		// eeprom SK bit
 | 
						|
 #define EEPROM_DI				0x02		// eeprom DI bit
 | 
						|
 #define EEPROM_CS				0x04		// eeprom CS bit
 | 
						|
 #define EEPROM_EN				0x08		// eeprom output enable
 | 
						|
#define REG_BLKSIZE				0x08		// Block transfer len (24 bit)
 | 
						|
 | 
						|
//***************************************************************************
 | 
						|
 | 
						|
typedef struct ppc_storage {
 | 
						|
	u16	lpt_addr;				// LPT base address
 | 
						|
	u8	ppc_id;
 | 
						|
	u8	mode;						// operating mode
 | 
						|
					// 0 = PPC Uni SW
 | 
						|
					// 1 = PPC Uni FW
 | 
						|
					// 2 = PPC Bi SW
 | 
						|
					// 3 = PPC Bi FW
 | 
						|
					// 4 = EPP Byte
 | 
						|
					// 5 = EPP Word
 | 
						|
					// 6 = EPP Dword
 | 
						|
	u8	ppc_flags;
 | 
						|
	u8	org_data;				// original LPT data port contents
 | 
						|
	u8	org_ctrl;				// original LPT control port contents
 | 
						|
	u8	cur_ctrl;				// current control port contents
 | 
						|
} Interface;
 | 
						|
 | 
						|
//***************************************************************************
 | 
						|
 | 
						|
// ppc_flags
 | 
						|
 | 
						|
#define fifo_wait					0x10
 | 
						|
 | 
						|
//***************************************************************************
 | 
						|
 | 
						|
// DONT CHANGE THESE LEST YOU BREAK EVERYTHING - BIT FIELD DEPENDENCIES
 | 
						|
 | 
						|
#define PPCMODE_UNI_SW		0
 | 
						|
#define PPCMODE_UNI_FW		1
 | 
						|
#define PPCMODE_BI_SW			2
 | 
						|
#define PPCMODE_BI_FW			3
 | 
						|
#define PPCMODE_EPP_BYTE	4
 | 
						|
#define PPCMODE_EPP_WORD	5
 | 
						|
#define PPCMODE_EPP_DWORD	6
 | 
						|
 | 
						|
//***************************************************************************
 | 
						|
 | 
						|
static int ppc6_select(Interface *ppc);
 | 
						|
static void ppc6_deselect(Interface *ppc);
 | 
						|
static void ppc6_send_cmd(Interface *ppc, u8 cmd);
 | 
						|
static void ppc6_wr_data_byte(Interface *ppc, u8 data);
 | 
						|
static u8 ppc6_rd_data_byte(Interface *ppc);
 | 
						|
static u8 ppc6_rd_port(Interface *ppc, u8 port);
 | 
						|
static void ppc6_wr_port(Interface *ppc, u8 port, u8 data);
 | 
						|
static void ppc6_rd_data_blk(Interface *ppc, u8 *data, long count);
 | 
						|
static void ppc6_wait_for_fifo(Interface *ppc);
 | 
						|
static void ppc6_wr_data_blk(Interface *ppc, u8 *data, long count);
 | 
						|
static void ppc6_rd_port16_blk(Interface *ppc, u8 port, u8 *data, long length);
 | 
						|
static void ppc6_wr_port16_blk(Interface *ppc, u8 port, u8 *data, long length);
 | 
						|
static void ppc6_wr_extout(Interface *ppc, u8 regdata);
 | 
						|
static int ppc6_open(Interface *ppc);
 | 
						|
static void ppc6_close(Interface *ppc);
 | 
						|
 | 
						|
//***************************************************************************
 | 
						|
 | 
						|
static int ppc6_select(Interface *ppc)
 | 
						|
{
 | 
						|
	u8 i, j, k;
 | 
						|
 | 
						|
	i = inb(ppc->lpt_addr + 1);
 | 
						|
 | 
						|
	if (i & 1)
 | 
						|
		outb(i, ppc->lpt_addr + 1);
 | 
						|
 | 
						|
	ppc->org_data = inb(ppc->lpt_addr);
 | 
						|
 | 
						|
	ppc->org_ctrl = inb(ppc->lpt_addr + 2) & 0x5F; // readback ctrl
 | 
						|
 | 
						|
	ppc->cur_ctrl = ppc->org_ctrl;
 | 
						|
 | 
						|
	ppc->cur_ctrl |= port_sel;
 | 
						|
 | 
						|
	outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
 | 
						|
 | 
						|
	if (ppc->org_data == 'b')
 | 
						|
		outb('x', ppc->lpt_addr);
 | 
						|
 | 
						|
	outb('b', ppc->lpt_addr);
 | 
						|
	outb('p', ppc->lpt_addr);
 | 
						|
	outb(ppc->ppc_id, ppc->lpt_addr);
 | 
						|
	outb(~ppc->ppc_id,ppc->lpt_addr);
 | 
						|
 | 
						|
	ppc->cur_ctrl &= ~port_sel;
 | 
						|
 | 
						|
	outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
 | 
						|
 | 
						|
	ppc->cur_ctrl = (ppc->cur_ctrl & port_int) | port_init;
 | 
						|
 | 
						|
	outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
 | 
						|
 | 
						|
	i = ppc->mode & 0x0C;
 | 
						|
 | 
						|
	if (i == 0)
 | 
						|
		i = (ppc->mode & 2) | 1;
 | 
						|
 | 
						|
	outb(i, ppc->lpt_addr);
 | 
						|
 | 
						|
	ppc->cur_ctrl |= port_sel;
 | 
						|
 | 
						|
	outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
 | 
						|
 | 
						|
	// DELAY
 | 
						|
 | 
						|
	ppc->cur_ctrl |= port_afd;
 | 
						|
 | 
						|
	outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
 | 
						|
 | 
						|
	j = ((i & 0x08) << 4) | ((i & 0x07) << 3);
 | 
						|
 | 
						|
	k = inb(ppc->lpt_addr + 1) & 0xB8;
 | 
						|
 | 
						|
	if (j == k)
 | 
						|
	{
 | 
						|
		ppc->cur_ctrl &= ~port_afd;
 | 
						|
 | 
						|
		outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
 | 
						|
 | 
						|
		k = (inb(ppc->lpt_addr + 1) & 0xB8) ^ 0xB8;
 | 
						|
 | 
						|
		if (j == k)
 | 
						|
		{
 | 
						|
			if (i & 4)	// EPP
 | 
						|
				ppc->cur_ctrl &= ~(port_sel | port_init);
 | 
						|
			else				// PPC/ECP
 | 
						|
				ppc->cur_ctrl &= ~port_sel;
 | 
						|
 | 
						|
			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
 | 
						|
 | 
						|
			return(1);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	outb(ppc->org_ctrl, ppc->lpt_addr + 2);
 | 
						|
 | 
						|
	outb(ppc->org_data, ppc->lpt_addr);
 | 
						|
 | 
						|
	return(0); // FAIL
 | 
						|
}
 | 
						|
 | 
						|
//***************************************************************************
 | 
						|
 | 
						|
static void ppc6_deselect(Interface *ppc)
 | 
						|
{
 | 
						|
	if (ppc->mode & 4)	// EPP
 | 
						|
		ppc->cur_ctrl |= port_init;
 | 
						|
	else								// PPC/ECP
 | 
						|
		ppc->cur_ctrl |= port_sel;
 | 
						|
 | 
						|
	outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
 | 
						|
 | 
						|
	outb(ppc->org_data, ppc->lpt_addr);
 | 
						|
 | 
						|
	outb((ppc->org_ctrl | port_sel), ppc->lpt_addr + 2);
 | 
						|
 | 
						|
	outb(ppc->org_ctrl, ppc->lpt_addr + 2);
 | 
						|
}
 | 
						|
 | 
						|
//***************************************************************************
 | 
						|
 | 
						|
static void ppc6_send_cmd(Interface *ppc, u8 cmd)
 | 
						|
{
 | 
						|
	switch(ppc->mode)
 | 
						|
	{
 | 
						|
		case PPCMODE_UNI_SW :
 | 
						|
		case PPCMODE_UNI_FW :
 | 
						|
		case PPCMODE_BI_SW :
 | 
						|
		case PPCMODE_BI_FW :
 | 
						|
		{
 | 
						|
			outb(cmd, ppc->lpt_addr);
 | 
						|
 | 
						|
			ppc->cur_ctrl ^= cmd_stb;
 | 
						|
 | 
						|
			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
 | 
						|
 | 
						|
			break;
 | 
						|
		}
 | 
						|
 | 
						|
		case PPCMODE_EPP_BYTE :
 | 
						|
		case PPCMODE_EPP_WORD :
 | 
						|
		case PPCMODE_EPP_DWORD :
 | 
						|
		{
 | 
						|
			outb(cmd, ppc->lpt_addr + 3);
 | 
						|
 | 
						|
			break;
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
//***************************************************************************
 | 
						|
 | 
						|
static void ppc6_wr_data_byte(Interface *ppc, u8 data)
 | 
						|
{
 | 
						|
	switch(ppc->mode)
 | 
						|
	{
 | 
						|
		case PPCMODE_UNI_SW :
 | 
						|
		case PPCMODE_UNI_FW :
 | 
						|
		case PPCMODE_BI_SW :
 | 
						|
		case PPCMODE_BI_FW :
 | 
						|
		{
 | 
						|
			outb(data, ppc->lpt_addr);
 | 
						|
 | 
						|
			ppc->cur_ctrl ^= data_stb;
 | 
						|
 | 
						|
			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
 | 
						|
 | 
						|
			break;
 | 
						|
		}
 | 
						|
 | 
						|
		case PPCMODE_EPP_BYTE :
 | 
						|
		case PPCMODE_EPP_WORD :
 | 
						|
		case PPCMODE_EPP_DWORD :
 | 
						|
		{
 | 
						|
			outb(data, ppc->lpt_addr + 4);
 | 
						|
 | 
						|
			break;
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
//***************************************************************************
 | 
						|
 | 
						|
static u8 ppc6_rd_data_byte(Interface *ppc)
 | 
						|
{
 | 
						|
	u8 data = 0;
 | 
						|
 | 
						|
	switch(ppc->mode)
 | 
						|
	{
 | 
						|
		case PPCMODE_UNI_SW :
 | 
						|
		case PPCMODE_UNI_FW :
 | 
						|
		{
 | 
						|
			ppc->cur_ctrl = (ppc->cur_ctrl & ~port_stb) ^ data_stb;
 | 
						|
 | 
						|
			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
 | 
						|
 | 
						|
			// DELAY
 | 
						|
 | 
						|
			data = inb(ppc->lpt_addr + 1);
 | 
						|
 | 
						|
			data = ((data & 0x80) >> 1) | ((data & 0x38) >> 3);
 | 
						|
 | 
						|
			ppc->cur_ctrl |= port_stb;
 | 
						|
 | 
						|
			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
 | 
						|
 | 
						|
			// DELAY
 | 
						|
 | 
						|
			data |= inb(ppc->lpt_addr + 1) & 0xB8;
 | 
						|
 | 
						|
			break;
 | 
						|
		}
 | 
						|
 | 
						|
		case PPCMODE_BI_SW :
 | 
						|
		case PPCMODE_BI_FW :
 | 
						|
		{
 | 
						|
			ppc->cur_ctrl |= port_dir;
 | 
						|
 | 
						|
			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
 | 
						|
 | 
						|
			ppc->cur_ctrl = (ppc->cur_ctrl | port_stb) ^ data_stb;
 | 
						|
 | 
						|
			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
 | 
						|
 | 
						|
			data = inb(ppc->lpt_addr);
 | 
						|
 | 
						|
			ppc->cur_ctrl &= ~port_stb;
 | 
						|
 | 
						|
			outb(ppc->cur_ctrl,ppc->lpt_addr + 2);
 | 
						|
 | 
						|
			ppc->cur_ctrl &= ~port_dir;
 | 
						|
 | 
						|
			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
 | 
						|
 | 
						|
			break;
 | 
						|
		}
 | 
						|
 | 
						|
		case PPCMODE_EPP_BYTE :
 | 
						|
		case PPCMODE_EPP_WORD :
 | 
						|
		case PPCMODE_EPP_DWORD :
 | 
						|
		{
 | 
						|
			outb((ppc->cur_ctrl | port_dir),ppc->lpt_addr + 2);
 | 
						|
 | 
						|
			data = inb(ppc->lpt_addr + 4);
 | 
						|
 | 
						|
			outb(ppc->cur_ctrl,ppc->lpt_addr + 2);
 | 
						|
 | 
						|
			break;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return(data);
 | 
						|
}
 | 
						|
 | 
						|
//***************************************************************************
 | 
						|
 | 
						|
static u8 ppc6_rd_port(Interface *ppc, u8 port)
 | 
						|
{
 | 
						|
	ppc6_send_cmd(ppc,(u8)(port | ACCESS_PORT | ACCESS_READ));
 | 
						|
 | 
						|
	return(ppc6_rd_data_byte(ppc));
 | 
						|
}
 | 
						|
 | 
						|
//***************************************************************************
 | 
						|
 | 
						|
static void ppc6_wr_port(Interface *ppc, u8 port, u8 data)
 | 
						|
{
 | 
						|
	ppc6_send_cmd(ppc,(u8)(port | ACCESS_PORT | ACCESS_WRITE));
 | 
						|
 | 
						|
	ppc6_wr_data_byte(ppc, data);
 | 
						|
}
 | 
						|
 | 
						|
//***************************************************************************
 | 
						|
 | 
						|
static void ppc6_rd_data_blk(Interface *ppc, u8 *data, long count)
 | 
						|
{
 | 
						|
	switch(ppc->mode)
 | 
						|
	{
 | 
						|
		case PPCMODE_UNI_SW :
 | 
						|
		case PPCMODE_UNI_FW :
 | 
						|
		{
 | 
						|
			while(count)
 | 
						|
			{
 | 
						|
				u8 d;
 | 
						|
 | 
						|
				ppc->cur_ctrl = (ppc->cur_ctrl & ~port_stb) ^ data_stb;
 | 
						|
 | 
						|
				outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
 | 
						|
 | 
						|
				// DELAY
 | 
						|
 | 
						|
				d = inb(ppc->lpt_addr + 1);
 | 
						|
 | 
						|
				d = ((d & 0x80) >> 1) | ((d & 0x38) >> 3);
 | 
						|
 | 
						|
				ppc->cur_ctrl |= port_stb;
 | 
						|
 | 
						|
				outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
 | 
						|
 | 
						|
				// DELAY
 | 
						|
 | 
						|
				d |= inb(ppc->lpt_addr + 1) & 0xB8;
 | 
						|
 | 
						|
				*data++ = d;
 | 
						|
				count--;
 | 
						|
			}
 | 
						|
 | 
						|
			break;
 | 
						|
		}
 | 
						|
 | 
						|
		case PPCMODE_BI_SW :
 | 
						|
		case PPCMODE_BI_FW :
 | 
						|
		{
 | 
						|
			ppc->cur_ctrl |= port_dir;
 | 
						|
 | 
						|
			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
 | 
						|
 | 
						|
			ppc->cur_ctrl |= port_stb;
 | 
						|
 | 
						|
			while(count)
 | 
						|
			{
 | 
						|
				ppc->cur_ctrl ^= data_stb;
 | 
						|
 | 
						|
				outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
 | 
						|
 | 
						|
				*data++ = inb(ppc->lpt_addr);
 | 
						|
				count--;
 | 
						|
			}
 | 
						|
 | 
						|
			ppc->cur_ctrl &= ~port_stb;
 | 
						|
 | 
						|
			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
 | 
						|
 | 
						|
			ppc->cur_ctrl &= ~port_dir;
 | 
						|
 | 
						|
			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
 | 
						|
 | 
						|
			break;
 | 
						|
		}
 | 
						|
 | 
						|
		case PPCMODE_EPP_BYTE :
 | 
						|
		{
 | 
						|
			outb((ppc->cur_ctrl | port_dir), ppc->lpt_addr + 2);
 | 
						|
 | 
						|
			// DELAY
 | 
						|
 | 
						|
			while(count)
 | 
						|
			{
 | 
						|
				*data++ = inb(ppc->lpt_addr + 4);
 | 
						|
				count--;
 | 
						|
			}
 | 
						|
 | 
						|
			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
 | 
						|
 | 
						|
			break;
 | 
						|
		}
 | 
						|
 | 
						|
		case PPCMODE_EPP_WORD :
 | 
						|
		{
 | 
						|
			outb((ppc->cur_ctrl | port_dir), ppc->lpt_addr + 2);
 | 
						|
 | 
						|
			// DELAY
 | 
						|
 | 
						|
			while(count > 1)
 | 
						|
			{
 | 
						|
				*((u16 *)data) = inw(ppc->lpt_addr + 4);
 | 
						|
				data  += 2;
 | 
						|
				count -= 2;
 | 
						|
			}
 | 
						|
 | 
						|
			while(count)
 | 
						|
			{
 | 
						|
				*data++ = inb(ppc->lpt_addr + 4);
 | 
						|
				count--;
 | 
						|
			}
 | 
						|
 | 
						|
			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
 | 
						|
 | 
						|
			break;
 | 
						|
		}
 | 
						|
 | 
						|
		case PPCMODE_EPP_DWORD :
 | 
						|
		{
 | 
						|
			outb((ppc->cur_ctrl | port_dir),ppc->lpt_addr + 2);
 | 
						|
 | 
						|
			// DELAY
 | 
						|
 | 
						|
			while(count > 3)
 | 
						|
			{
 | 
						|
				*((u32 *)data) = inl(ppc->lpt_addr + 4);
 | 
						|
				data  += 4;
 | 
						|
				count -= 4;
 | 
						|
			}
 | 
						|
 | 
						|
			while(count)
 | 
						|
			{
 | 
						|
				*data++ = inb(ppc->lpt_addr + 4);
 | 
						|
				count--;
 | 
						|
			}
 | 
						|
 | 
						|
			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
 | 
						|
 | 
						|
			break;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
//***************************************************************************
 | 
						|
 | 
						|
static void ppc6_wait_for_fifo(Interface *ppc)
 | 
						|
{
 | 
						|
	int i;
 | 
						|
 | 
						|
	if (ppc->ppc_flags & fifo_wait)
 | 
						|
	{
 | 
						|
		for(i=0; i<20; i++)
 | 
						|
			inb(ppc->lpt_addr + 1);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
//***************************************************************************
 | 
						|
 | 
						|
static void ppc6_wr_data_blk(Interface *ppc, u8 *data, long count)
 | 
						|
{
 | 
						|
	switch(ppc->mode)
 | 
						|
	{
 | 
						|
		case PPCMODE_UNI_SW :
 | 
						|
		case PPCMODE_BI_SW :
 | 
						|
		{
 | 
						|
			while(count--)
 | 
						|
			{
 | 
						|
				outb(*data++, ppc->lpt_addr);
 | 
						|
 | 
						|
				ppc->cur_ctrl ^= data_stb;
 | 
						|
 | 
						|
				outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
 | 
						|
			}
 | 
						|
 | 
						|
			break;
 | 
						|
		}
 | 
						|
 | 
						|
		case PPCMODE_UNI_FW :
 | 
						|
		case PPCMODE_BI_FW :
 | 
						|
		{
 | 
						|
			u8 this, last;
 | 
						|
 | 
						|
			ppc6_send_cmd(ppc,(CMD_PREFIX_SET | PREFIX_FASTWR));
 | 
						|
 | 
						|
			ppc->cur_ctrl |= port_stb;
 | 
						|
 | 
						|
			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
 | 
						|
 | 
						|
			last = *data;
 | 
						|
 | 
						|
			outb(last, ppc->lpt_addr);
 | 
						|
 | 
						|
			while(count)
 | 
						|
			{
 | 
						|
				this = *data++;
 | 
						|
				count--;
 | 
						|
 | 
						|
				if (this == last)
 | 
						|
				{
 | 
						|
					ppc->cur_ctrl ^= data_stb;
 | 
						|
 | 
						|
					outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
 | 
						|
				}
 | 
						|
				else
 | 
						|
				{
 | 
						|
					outb(this, ppc->lpt_addr);
 | 
						|
 | 
						|
					last = this;
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			ppc->cur_ctrl &= ~port_stb;
 | 
						|
 | 
						|
			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
 | 
						|
 | 
						|
			ppc6_send_cmd(ppc,(CMD_PREFIX_RESET | PREFIX_FASTWR));
 | 
						|
 | 
						|
			break;
 | 
						|
		}
 | 
						|
 | 
						|
		case PPCMODE_EPP_BYTE :
 | 
						|
		{
 | 
						|
			while(count)
 | 
						|
			{
 | 
						|
				outb(*data++,ppc->lpt_addr + 4);
 | 
						|
				count--;
 | 
						|
			}
 | 
						|
 | 
						|
			ppc6_wait_for_fifo(ppc);
 | 
						|
 | 
						|
			break;
 | 
						|
		}
 | 
						|
 | 
						|
		case PPCMODE_EPP_WORD :
 | 
						|
		{
 | 
						|
			while(count > 1)
 | 
						|
			{
 | 
						|
				outw(*((u16 *)data),ppc->lpt_addr + 4);
 | 
						|
				data  += 2;
 | 
						|
				count -= 2;
 | 
						|
			}
 | 
						|
 | 
						|
			while(count)
 | 
						|
			{
 | 
						|
				outb(*data++,ppc->lpt_addr + 4);
 | 
						|
				count--;
 | 
						|
			}
 | 
						|
 | 
						|
			ppc6_wait_for_fifo(ppc);
 | 
						|
 | 
						|
			break;
 | 
						|
		}
 | 
						|
 | 
						|
		case PPCMODE_EPP_DWORD :
 | 
						|
		{
 | 
						|
			while(count > 3)
 | 
						|
			{
 | 
						|
				outl(*((u32 *)data),ppc->lpt_addr + 4);
 | 
						|
				data  += 4;
 | 
						|
				count -= 4;
 | 
						|
			}
 | 
						|
 | 
						|
			while(count)
 | 
						|
			{
 | 
						|
				outb(*data++,ppc->lpt_addr + 4);
 | 
						|
				count--;
 | 
						|
			}
 | 
						|
 | 
						|
			ppc6_wait_for_fifo(ppc);
 | 
						|
 | 
						|
			break;
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
//***************************************************************************
 | 
						|
 | 
						|
static void ppc6_rd_port16_blk(Interface *ppc, u8 port, u8 *data, long length)
 | 
						|
{
 | 
						|
	length = length << 1;
 | 
						|
 | 
						|
	ppc6_send_cmd(ppc, (REG_BLKSIZE | ACCESS_REG | ACCESS_WRITE));
 | 
						|
	ppc6_wr_data_byte(ppc,(u8)length);
 | 
						|
	ppc6_wr_data_byte(ppc,(u8)(length >> 8));
 | 
						|
	ppc6_wr_data_byte(ppc,0);
 | 
						|
 | 
						|
	ppc6_send_cmd(ppc, (CMD_PREFIX_SET | PREFIX_IO16 | PREFIX_BLK));
 | 
						|
 | 
						|
	ppc6_send_cmd(ppc, (u8)(port | ACCESS_PORT | ACCESS_READ));
 | 
						|
 | 
						|
	ppc6_rd_data_blk(ppc, data, length);
 | 
						|
 | 
						|
	ppc6_send_cmd(ppc, (CMD_PREFIX_RESET | PREFIX_IO16 | PREFIX_BLK));
 | 
						|
}
 | 
						|
 | 
						|
//***************************************************************************
 | 
						|
 | 
						|
static void ppc6_wr_port16_blk(Interface *ppc, u8 port, u8 *data, long length)
 | 
						|
{
 | 
						|
	length = length << 1;
 | 
						|
 | 
						|
	ppc6_send_cmd(ppc, (REG_BLKSIZE | ACCESS_REG | ACCESS_WRITE));
 | 
						|
	ppc6_wr_data_byte(ppc,(u8)length);
 | 
						|
	ppc6_wr_data_byte(ppc,(u8)(length >> 8));
 | 
						|
	ppc6_wr_data_byte(ppc,0);
 | 
						|
 | 
						|
	ppc6_send_cmd(ppc, (CMD_PREFIX_SET | PREFIX_IO16 | PREFIX_BLK));
 | 
						|
 | 
						|
	ppc6_send_cmd(ppc, (u8)(port | ACCESS_PORT | ACCESS_WRITE));
 | 
						|
 | 
						|
	ppc6_wr_data_blk(ppc, data, length);
 | 
						|
 | 
						|
	ppc6_send_cmd(ppc, (CMD_PREFIX_RESET | PREFIX_IO16 | PREFIX_BLK));
 | 
						|
}
 | 
						|
 | 
						|
//***************************************************************************
 | 
						|
 | 
						|
static void ppc6_wr_extout(Interface *ppc, u8 regdata)
 | 
						|
{
 | 
						|
	ppc6_send_cmd(ppc,(REG_VERSION | ACCESS_REG | ACCESS_WRITE));
 | 
						|
 | 
						|
	ppc6_wr_data_byte(ppc, (u8)((regdata & 0x03) << 6));
 | 
						|
}
 | 
						|
 | 
						|
//***************************************************************************
 | 
						|
 | 
						|
static int ppc6_open(Interface *ppc)
 | 
						|
{
 | 
						|
	int ret;
 | 
						|
 | 
						|
	ret = ppc6_select(ppc);
 | 
						|
 | 
						|
	if (ret == 0)
 | 
						|
		return(ret);
 | 
						|
 | 
						|
	ppc->ppc_flags &= ~fifo_wait;
 | 
						|
 | 
						|
	ppc6_send_cmd(ppc, (ACCESS_REG | ACCESS_WRITE | REG_RAMSIZE));
 | 
						|
	ppc6_wr_data_byte(ppc, RAMSIZE_128K);
 | 
						|
 | 
						|
	ppc6_send_cmd(ppc, (ACCESS_REG | ACCESS_READ | REG_VERSION));
 | 
						|
 | 
						|
	if ((ppc6_rd_data_byte(ppc) & 0x3F) == 0x0C)
 | 
						|
		ppc->ppc_flags |= fifo_wait;
 | 
						|
 | 
						|
	return(ret);
 | 
						|
}
 | 
						|
 | 
						|
//***************************************************************************
 | 
						|
 | 
						|
static void ppc6_close(Interface *ppc)
 | 
						|
{
 | 
						|
	ppc6_deselect(ppc);
 | 
						|
}
 | 
						|
 | 
						|
//***************************************************************************
 | 
						|
 |