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

📄 ppc6lnx.c

📁 Linux块设备驱动源码
💻 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);}//***************************************************************************

⌨️ 快捷键说明

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