xref: /OK3568_Linux_fs/kernel/drivers/block/paride/ppc6lnx.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun 	ppc6lnx.c (c) 2001 Micro Solutions Inc.
3*4882a593Smuzhiyun 		Released under the terms of the GNU General Public license
4*4882a593Smuzhiyun 
5*4882a593Smuzhiyun 	ppc6lnx.c  is a par of the protocol driver for the Micro Solutions
6*4882a593Smuzhiyun 		"BACKPACK" parallel port IDE adapter
7*4882a593Smuzhiyun 		(Works on Series 6 drives)
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun */
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun //***************************************************************************
12*4882a593Smuzhiyun 
13*4882a593Smuzhiyun // PPC 6 Code in C sanitized for LINUX
14*4882a593Smuzhiyun // Original x86 ASM by Ron, Converted to C by Clive
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun //***************************************************************************
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun #define port_stb					1
20*4882a593Smuzhiyun #define port_afd					2
21*4882a593Smuzhiyun #define cmd_stb						port_afd
22*4882a593Smuzhiyun #define port_init					4
23*4882a593Smuzhiyun #define data_stb					port_init
24*4882a593Smuzhiyun #define port_sel					8
25*4882a593Smuzhiyun #define port_int					16
26*4882a593Smuzhiyun #define port_dir					0x20
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun #define ECR_EPP	0x80
29*4882a593Smuzhiyun #define ECR_BI	0x20
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun //***************************************************************************
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun //  60772 Commands
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun #define ACCESS_REG				0x00
36*4882a593Smuzhiyun #define ACCESS_PORT				0x40
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun #define ACCESS_READ				0x00
39*4882a593Smuzhiyun #define ACCESS_WRITE			0x20
40*4882a593Smuzhiyun 
41*4882a593Smuzhiyun //  60772 Command Prefix
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun #define CMD_PREFIX_SET		0xe0		// Special command that modifies the next command's operation
44*4882a593Smuzhiyun #define CMD_PREFIX_RESET	0xc0		// Resets current cmd modifier reg bits
45*4882a593Smuzhiyun  #define PREFIX_IO16			0x01		// perform 16-bit wide I/O
46*4882a593Smuzhiyun  #define PREFIX_FASTWR		0x04		// enable PPC mode fast-write
47*4882a593Smuzhiyun  #define PREFIX_BLK				0x08		// enable block transfer mode
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun // 60772 Registers
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun #define REG_STATUS				0x00		// status register
52*4882a593Smuzhiyun  #define STATUS_IRQA			0x01		// Peripheral IRQA line
53*4882a593Smuzhiyun  #define STATUS_EEPROM_DO	0x40		// Serial EEPROM data bit
54*4882a593Smuzhiyun #define REG_VERSION				0x01		// PPC version register (read)
55*4882a593Smuzhiyun #define REG_HWCFG					0x02		// Hardware Config register
56*4882a593Smuzhiyun #define REG_RAMSIZE				0x03		// Size of RAM Buffer
57*4882a593Smuzhiyun  #define RAMSIZE_128K			0x02
58*4882a593Smuzhiyun #define REG_EEPROM				0x06		// EEPROM control register
59*4882a593Smuzhiyun  #define EEPROM_SK				0x01		// eeprom SK bit
60*4882a593Smuzhiyun  #define EEPROM_DI				0x02		// eeprom DI bit
61*4882a593Smuzhiyun  #define EEPROM_CS				0x04		// eeprom CS bit
62*4882a593Smuzhiyun  #define EEPROM_EN				0x08		// eeprom output enable
63*4882a593Smuzhiyun #define REG_BLKSIZE				0x08		// Block transfer len (24 bit)
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun //***************************************************************************
66*4882a593Smuzhiyun 
67*4882a593Smuzhiyun typedef struct ppc_storage {
68*4882a593Smuzhiyun 	u16	lpt_addr;				// LPT base address
69*4882a593Smuzhiyun 	u8	ppc_id;
70*4882a593Smuzhiyun 	u8	mode;						// operating mode
71*4882a593Smuzhiyun 					// 0 = PPC Uni SW
72*4882a593Smuzhiyun 					// 1 = PPC Uni FW
73*4882a593Smuzhiyun 					// 2 = PPC Bi SW
74*4882a593Smuzhiyun 					// 3 = PPC Bi FW
75*4882a593Smuzhiyun 					// 4 = EPP Byte
76*4882a593Smuzhiyun 					// 5 = EPP Word
77*4882a593Smuzhiyun 					// 6 = EPP Dword
78*4882a593Smuzhiyun 	u8	ppc_flags;
79*4882a593Smuzhiyun 	u8	org_data;				// original LPT data port contents
80*4882a593Smuzhiyun 	u8	org_ctrl;				// original LPT control port contents
81*4882a593Smuzhiyun 	u8	cur_ctrl;				// current control port contents
82*4882a593Smuzhiyun } Interface;
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun //***************************************************************************
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun // ppc_flags
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun #define fifo_wait					0x10
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun //***************************************************************************
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun // DONT CHANGE THESE LEST YOU BREAK EVERYTHING - BIT FIELD DEPENDENCIES
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun #define PPCMODE_UNI_SW		0
95*4882a593Smuzhiyun #define PPCMODE_UNI_FW		1
96*4882a593Smuzhiyun #define PPCMODE_BI_SW			2
97*4882a593Smuzhiyun #define PPCMODE_BI_FW			3
98*4882a593Smuzhiyun #define PPCMODE_EPP_BYTE	4
99*4882a593Smuzhiyun #define PPCMODE_EPP_WORD	5
100*4882a593Smuzhiyun #define PPCMODE_EPP_DWORD	6
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun //***************************************************************************
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun static int ppc6_select(Interface *ppc);
105*4882a593Smuzhiyun static void ppc6_deselect(Interface *ppc);
106*4882a593Smuzhiyun static void ppc6_send_cmd(Interface *ppc, u8 cmd);
107*4882a593Smuzhiyun static void ppc6_wr_data_byte(Interface *ppc, u8 data);
108*4882a593Smuzhiyun static u8 ppc6_rd_data_byte(Interface *ppc);
109*4882a593Smuzhiyun static u8 ppc6_rd_port(Interface *ppc, u8 port);
110*4882a593Smuzhiyun static void ppc6_wr_port(Interface *ppc, u8 port, u8 data);
111*4882a593Smuzhiyun static void ppc6_rd_data_blk(Interface *ppc, u8 *data, long count);
112*4882a593Smuzhiyun static void ppc6_wait_for_fifo(Interface *ppc);
113*4882a593Smuzhiyun static void ppc6_wr_data_blk(Interface *ppc, u8 *data, long count);
114*4882a593Smuzhiyun static void ppc6_rd_port16_blk(Interface *ppc, u8 port, u8 *data, long length);
115*4882a593Smuzhiyun static void ppc6_wr_port16_blk(Interface *ppc, u8 port, u8 *data, long length);
116*4882a593Smuzhiyun static void ppc6_wr_extout(Interface *ppc, u8 regdata);
117*4882a593Smuzhiyun static int ppc6_open(Interface *ppc);
118*4882a593Smuzhiyun static void ppc6_close(Interface *ppc);
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun //***************************************************************************
121*4882a593Smuzhiyun 
ppc6_select(Interface * ppc)122*4882a593Smuzhiyun static int ppc6_select(Interface *ppc)
123*4882a593Smuzhiyun {
124*4882a593Smuzhiyun 	u8 i, j, k;
125*4882a593Smuzhiyun 
126*4882a593Smuzhiyun 	i = inb(ppc->lpt_addr + 1);
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun 	if (i & 1)
129*4882a593Smuzhiyun 		outb(i, ppc->lpt_addr + 1);
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun 	ppc->org_data = inb(ppc->lpt_addr);
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun 	ppc->org_ctrl = inb(ppc->lpt_addr + 2) & 0x5F; // readback ctrl
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 	ppc->cur_ctrl = ppc->org_ctrl;
136*4882a593Smuzhiyun 
137*4882a593Smuzhiyun 	ppc->cur_ctrl |= port_sel;
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun 	outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun 	if (ppc->org_data == 'b')
142*4882a593Smuzhiyun 		outb('x', ppc->lpt_addr);
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun 	outb('b', ppc->lpt_addr);
145*4882a593Smuzhiyun 	outb('p', ppc->lpt_addr);
146*4882a593Smuzhiyun 	outb(ppc->ppc_id, ppc->lpt_addr);
147*4882a593Smuzhiyun 	outb(~ppc->ppc_id,ppc->lpt_addr);
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun 	ppc->cur_ctrl &= ~port_sel;
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun 	outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun 	ppc->cur_ctrl = (ppc->cur_ctrl & port_int) | port_init;
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun 	outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun 	i = ppc->mode & 0x0C;
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun 	if (i == 0)
160*4882a593Smuzhiyun 		i = (ppc->mode & 2) | 1;
161*4882a593Smuzhiyun 
162*4882a593Smuzhiyun 	outb(i, ppc->lpt_addr);
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun 	ppc->cur_ctrl |= port_sel;
165*4882a593Smuzhiyun 
166*4882a593Smuzhiyun 	outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
167*4882a593Smuzhiyun 
168*4882a593Smuzhiyun 	// DELAY
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun 	ppc->cur_ctrl |= port_afd;
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun 	outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun 	j = ((i & 0x08) << 4) | ((i & 0x07) << 3);
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun 	k = inb(ppc->lpt_addr + 1) & 0xB8;
177*4882a593Smuzhiyun 
178*4882a593Smuzhiyun 	if (j == k)
179*4882a593Smuzhiyun 	{
180*4882a593Smuzhiyun 		ppc->cur_ctrl &= ~port_afd;
181*4882a593Smuzhiyun 
182*4882a593Smuzhiyun 		outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
183*4882a593Smuzhiyun 
184*4882a593Smuzhiyun 		k = (inb(ppc->lpt_addr + 1) & 0xB8) ^ 0xB8;
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun 		if (j == k)
187*4882a593Smuzhiyun 		{
188*4882a593Smuzhiyun 			if (i & 4)	// EPP
189*4882a593Smuzhiyun 				ppc->cur_ctrl &= ~(port_sel | port_init);
190*4882a593Smuzhiyun 			else				// PPC/ECP
191*4882a593Smuzhiyun 				ppc->cur_ctrl &= ~port_sel;
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun 			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun 			return(1);
196*4882a593Smuzhiyun 		}
197*4882a593Smuzhiyun 	}
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 	outb(ppc->org_ctrl, ppc->lpt_addr + 2);
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun 	outb(ppc->org_data, ppc->lpt_addr);
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun 	return(0); // FAIL
204*4882a593Smuzhiyun }
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun //***************************************************************************
207*4882a593Smuzhiyun 
ppc6_deselect(Interface * ppc)208*4882a593Smuzhiyun static void ppc6_deselect(Interface *ppc)
209*4882a593Smuzhiyun {
210*4882a593Smuzhiyun 	if (ppc->mode & 4)	// EPP
211*4882a593Smuzhiyun 		ppc->cur_ctrl |= port_init;
212*4882a593Smuzhiyun 	else								// PPC/ECP
213*4882a593Smuzhiyun 		ppc->cur_ctrl |= port_sel;
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun 	outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
216*4882a593Smuzhiyun 
217*4882a593Smuzhiyun 	outb(ppc->org_data, ppc->lpt_addr);
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun 	outb((ppc->org_ctrl | port_sel), ppc->lpt_addr + 2);
220*4882a593Smuzhiyun 
221*4882a593Smuzhiyun 	outb(ppc->org_ctrl, ppc->lpt_addr + 2);
222*4882a593Smuzhiyun }
223*4882a593Smuzhiyun 
224*4882a593Smuzhiyun //***************************************************************************
225*4882a593Smuzhiyun 
ppc6_send_cmd(Interface * ppc,u8 cmd)226*4882a593Smuzhiyun static void ppc6_send_cmd(Interface *ppc, u8 cmd)
227*4882a593Smuzhiyun {
228*4882a593Smuzhiyun 	switch(ppc->mode)
229*4882a593Smuzhiyun 	{
230*4882a593Smuzhiyun 		case PPCMODE_UNI_SW :
231*4882a593Smuzhiyun 		case PPCMODE_UNI_FW :
232*4882a593Smuzhiyun 		case PPCMODE_BI_SW :
233*4882a593Smuzhiyun 		case PPCMODE_BI_FW :
234*4882a593Smuzhiyun 		{
235*4882a593Smuzhiyun 			outb(cmd, ppc->lpt_addr);
236*4882a593Smuzhiyun 
237*4882a593Smuzhiyun 			ppc->cur_ctrl ^= cmd_stb;
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun 			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
240*4882a593Smuzhiyun 
241*4882a593Smuzhiyun 			break;
242*4882a593Smuzhiyun 		}
243*4882a593Smuzhiyun 
244*4882a593Smuzhiyun 		case PPCMODE_EPP_BYTE :
245*4882a593Smuzhiyun 		case PPCMODE_EPP_WORD :
246*4882a593Smuzhiyun 		case PPCMODE_EPP_DWORD :
247*4882a593Smuzhiyun 		{
248*4882a593Smuzhiyun 			outb(cmd, ppc->lpt_addr + 3);
249*4882a593Smuzhiyun 
250*4882a593Smuzhiyun 			break;
251*4882a593Smuzhiyun 		}
252*4882a593Smuzhiyun 	}
253*4882a593Smuzhiyun }
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun //***************************************************************************
256*4882a593Smuzhiyun 
ppc6_wr_data_byte(Interface * ppc,u8 data)257*4882a593Smuzhiyun static void ppc6_wr_data_byte(Interface *ppc, u8 data)
258*4882a593Smuzhiyun {
259*4882a593Smuzhiyun 	switch(ppc->mode)
260*4882a593Smuzhiyun 	{
261*4882a593Smuzhiyun 		case PPCMODE_UNI_SW :
262*4882a593Smuzhiyun 		case PPCMODE_UNI_FW :
263*4882a593Smuzhiyun 		case PPCMODE_BI_SW :
264*4882a593Smuzhiyun 		case PPCMODE_BI_FW :
265*4882a593Smuzhiyun 		{
266*4882a593Smuzhiyun 			outb(data, ppc->lpt_addr);
267*4882a593Smuzhiyun 
268*4882a593Smuzhiyun 			ppc->cur_ctrl ^= data_stb;
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun 			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
271*4882a593Smuzhiyun 
272*4882a593Smuzhiyun 			break;
273*4882a593Smuzhiyun 		}
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun 		case PPCMODE_EPP_BYTE :
276*4882a593Smuzhiyun 		case PPCMODE_EPP_WORD :
277*4882a593Smuzhiyun 		case PPCMODE_EPP_DWORD :
278*4882a593Smuzhiyun 		{
279*4882a593Smuzhiyun 			outb(data, ppc->lpt_addr + 4);
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun 			break;
282*4882a593Smuzhiyun 		}
283*4882a593Smuzhiyun 	}
284*4882a593Smuzhiyun }
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun //***************************************************************************
287*4882a593Smuzhiyun 
ppc6_rd_data_byte(Interface * ppc)288*4882a593Smuzhiyun static u8 ppc6_rd_data_byte(Interface *ppc)
289*4882a593Smuzhiyun {
290*4882a593Smuzhiyun 	u8 data = 0;
291*4882a593Smuzhiyun 
292*4882a593Smuzhiyun 	switch(ppc->mode)
293*4882a593Smuzhiyun 	{
294*4882a593Smuzhiyun 		case PPCMODE_UNI_SW :
295*4882a593Smuzhiyun 		case PPCMODE_UNI_FW :
296*4882a593Smuzhiyun 		{
297*4882a593Smuzhiyun 			ppc->cur_ctrl = (ppc->cur_ctrl & ~port_stb) ^ data_stb;
298*4882a593Smuzhiyun 
299*4882a593Smuzhiyun 			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
300*4882a593Smuzhiyun 
301*4882a593Smuzhiyun 			// DELAY
302*4882a593Smuzhiyun 
303*4882a593Smuzhiyun 			data = inb(ppc->lpt_addr + 1);
304*4882a593Smuzhiyun 
305*4882a593Smuzhiyun 			data = ((data & 0x80) >> 1) | ((data & 0x38) >> 3);
306*4882a593Smuzhiyun 
307*4882a593Smuzhiyun 			ppc->cur_ctrl |= port_stb;
308*4882a593Smuzhiyun 
309*4882a593Smuzhiyun 			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun 			// DELAY
312*4882a593Smuzhiyun 
313*4882a593Smuzhiyun 			data |= inb(ppc->lpt_addr + 1) & 0xB8;
314*4882a593Smuzhiyun 
315*4882a593Smuzhiyun 			break;
316*4882a593Smuzhiyun 		}
317*4882a593Smuzhiyun 
318*4882a593Smuzhiyun 		case PPCMODE_BI_SW :
319*4882a593Smuzhiyun 		case PPCMODE_BI_FW :
320*4882a593Smuzhiyun 		{
321*4882a593Smuzhiyun 			ppc->cur_ctrl |= port_dir;
322*4882a593Smuzhiyun 
323*4882a593Smuzhiyun 			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
324*4882a593Smuzhiyun 
325*4882a593Smuzhiyun 			ppc->cur_ctrl = (ppc->cur_ctrl | port_stb) ^ data_stb;
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun 			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
328*4882a593Smuzhiyun 
329*4882a593Smuzhiyun 			data = inb(ppc->lpt_addr);
330*4882a593Smuzhiyun 
331*4882a593Smuzhiyun 			ppc->cur_ctrl &= ~port_stb;
332*4882a593Smuzhiyun 
333*4882a593Smuzhiyun 			outb(ppc->cur_ctrl,ppc->lpt_addr + 2);
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun 			ppc->cur_ctrl &= ~port_dir;
336*4882a593Smuzhiyun 
337*4882a593Smuzhiyun 			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
338*4882a593Smuzhiyun 
339*4882a593Smuzhiyun 			break;
340*4882a593Smuzhiyun 		}
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun 		case PPCMODE_EPP_BYTE :
343*4882a593Smuzhiyun 		case PPCMODE_EPP_WORD :
344*4882a593Smuzhiyun 		case PPCMODE_EPP_DWORD :
345*4882a593Smuzhiyun 		{
346*4882a593Smuzhiyun 			outb((ppc->cur_ctrl | port_dir),ppc->lpt_addr + 2);
347*4882a593Smuzhiyun 
348*4882a593Smuzhiyun 			data = inb(ppc->lpt_addr + 4);
349*4882a593Smuzhiyun 
350*4882a593Smuzhiyun 			outb(ppc->cur_ctrl,ppc->lpt_addr + 2);
351*4882a593Smuzhiyun 
352*4882a593Smuzhiyun 			break;
353*4882a593Smuzhiyun 		}
354*4882a593Smuzhiyun 	}
355*4882a593Smuzhiyun 
356*4882a593Smuzhiyun 	return(data);
357*4882a593Smuzhiyun }
358*4882a593Smuzhiyun 
359*4882a593Smuzhiyun //***************************************************************************
360*4882a593Smuzhiyun 
ppc6_rd_port(Interface * ppc,u8 port)361*4882a593Smuzhiyun static u8 ppc6_rd_port(Interface *ppc, u8 port)
362*4882a593Smuzhiyun {
363*4882a593Smuzhiyun 	ppc6_send_cmd(ppc,(u8)(port | ACCESS_PORT | ACCESS_READ));
364*4882a593Smuzhiyun 
365*4882a593Smuzhiyun 	return(ppc6_rd_data_byte(ppc));
366*4882a593Smuzhiyun }
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun //***************************************************************************
369*4882a593Smuzhiyun 
ppc6_wr_port(Interface * ppc,u8 port,u8 data)370*4882a593Smuzhiyun static void ppc6_wr_port(Interface *ppc, u8 port, u8 data)
371*4882a593Smuzhiyun {
372*4882a593Smuzhiyun 	ppc6_send_cmd(ppc,(u8)(port | ACCESS_PORT | ACCESS_WRITE));
373*4882a593Smuzhiyun 
374*4882a593Smuzhiyun 	ppc6_wr_data_byte(ppc, data);
375*4882a593Smuzhiyun }
376*4882a593Smuzhiyun 
377*4882a593Smuzhiyun //***************************************************************************
378*4882a593Smuzhiyun 
ppc6_rd_data_blk(Interface * ppc,u8 * data,long count)379*4882a593Smuzhiyun static void ppc6_rd_data_blk(Interface *ppc, u8 *data, long count)
380*4882a593Smuzhiyun {
381*4882a593Smuzhiyun 	switch(ppc->mode)
382*4882a593Smuzhiyun 	{
383*4882a593Smuzhiyun 		case PPCMODE_UNI_SW :
384*4882a593Smuzhiyun 		case PPCMODE_UNI_FW :
385*4882a593Smuzhiyun 		{
386*4882a593Smuzhiyun 			while(count)
387*4882a593Smuzhiyun 			{
388*4882a593Smuzhiyun 				u8 d;
389*4882a593Smuzhiyun 
390*4882a593Smuzhiyun 				ppc->cur_ctrl = (ppc->cur_ctrl & ~port_stb) ^ data_stb;
391*4882a593Smuzhiyun 
392*4882a593Smuzhiyun 				outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
393*4882a593Smuzhiyun 
394*4882a593Smuzhiyun 				// DELAY
395*4882a593Smuzhiyun 
396*4882a593Smuzhiyun 				d = inb(ppc->lpt_addr + 1);
397*4882a593Smuzhiyun 
398*4882a593Smuzhiyun 				d = ((d & 0x80) >> 1) | ((d & 0x38) >> 3);
399*4882a593Smuzhiyun 
400*4882a593Smuzhiyun 				ppc->cur_ctrl |= port_stb;
401*4882a593Smuzhiyun 
402*4882a593Smuzhiyun 				outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun 				// DELAY
405*4882a593Smuzhiyun 
406*4882a593Smuzhiyun 				d |= inb(ppc->lpt_addr + 1) & 0xB8;
407*4882a593Smuzhiyun 
408*4882a593Smuzhiyun 				*data++ = d;
409*4882a593Smuzhiyun 				count--;
410*4882a593Smuzhiyun 			}
411*4882a593Smuzhiyun 
412*4882a593Smuzhiyun 			break;
413*4882a593Smuzhiyun 		}
414*4882a593Smuzhiyun 
415*4882a593Smuzhiyun 		case PPCMODE_BI_SW :
416*4882a593Smuzhiyun 		case PPCMODE_BI_FW :
417*4882a593Smuzhiyun 		{
418*4882a593Smuzhiyun 			ppc->cur_ctrl |= port_dir;
419*4882a593Smuzhiyun 
420*4882a593Smuzhiyun 			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
421*4882a593Smuzhiyun 
422*4882a593Smuzhiyun 			ppc->cur_ctrl |= port_stb;
423*4882a593Smuzhiyun 
424*4882a593Smuzhiyun 			while(count)
425*4882a593Smuzhiyun 			{
426*4882a593Smuzhiyun 				ppc->cur_ctrl ^= data_stb;
427*4882a593Smuzhiyun 
428*4882a593Smuzhiyun 				outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
429*4882a593Smuzhiyun 
430*4882a593Smuzhiyun 				*data++ = inb(ppc->lpt_addr);
431*4882a593Smuzhiyun 				count--;
432*4882a593Smuzhiyun 			}
433*4882a593Smuzhiyun 
434*4882a593Smuzhiyun 			ppc->cur_ctrl &= ~port_stb;
435*4882a593Smuzhiyun 
436*4882a593Smuzhiyun 			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
437*4882a593Smuzhiyun 
438*4882a593Smuzhiyun 			ppc->cur_ctrl &= ~port_dir;
439*4882a593Smuzhiyun 
440*4882a593Smuzhiyun 			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
441*4882a593Smuzhiyun 
442*4882a593Smuzhiyun 			break;
443*4882a593Smuzhiyun 		}
444*4882a593Smuzhiyun 
445*4882a593Smuzhiyun 		case PPCMODE_EPP_BYTE :
446*4882a593Smuzhiyun 		{
447*4882a593Smuzhiyun 			outb((ppc->cur_ctrl | port_dir), ppc->lpt_addr + 2);
448*4882a593Smuzhiyun 
449*4882a593Smuzhiyun 			// DELAY
450*4882a593Smuzhiyun 
451*4882a593Smuzhiyun 			while(count)
452*4882a593Smuzhiyun 			{
453*4882a593Smuzhiyun 				*data++ = inb(ppc->lpt_addr + 4);
454*4882a593Smuzhiyun 				count--;
455*4882a593Smuzhiyun 			}
456*4882a593Smuzhiyun 
457*4882a593Smuzhiyun 			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
458*4882a593Smuzhiyun 
459*4882a593Smuzhiyun 			break;
460*4882a593Smuzhiyun 		}
461*4882a593Smuzhiyun 
462*4882a593Smuzhiyun 		case PPCMODE_EPP_WORD :
463*4882a593Smuzhiyun 		{
464*4882a593Smuzhiyun 			outb((ppc->cur_ctrl | port_dir), ppc->lpt_addr + 2);
465*4882a593Smuzhiyun 
466*4882a593Smuzhiyun 			// DELAY
467*4882a593Smuzhiyun 
468*4882a593Smuzhiyun 			while(count > 1)
469*4882a593Smuzhiyun 			{
470*4882a593Smuzhiyun 				*((u16 *)data) = inw(ppc->lpt_addr + 4);
471*4882a593Smuzhiyun 				data  += 2;
472*4882a593Smuzhiyun 				count -= 2;
473*4882a593Smuzhiyun 			}
474*4882a593Smuzhiyun 
475*4882a593Smuzhiyun 			while(count)
476*4882a593Smuzhiyun 			{
477*4882a593Smuzhiyun 				*data++ = inb(ppc->lpt_addr + 4);
478*4882a593Smuzhiyun 				count--;
479*4882a593Smuzhiyun 			}
480*4882a593Smuzhiyun 
481*4882a593Smuzhiyun 			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
482*4882a593Smuzhiyun 
483*4882a593Smuzhiyun 			break;
484*4882a593Smuzhiyun 		}
485*4882a593Smuzhiyun 
486*4882a593Smuzhiyun 		case PPCMODE_EPP_DWORD :
487*4882a593Smuzhiyun 		{
488*4882a593Smuzhiyun 			outb((ppc->cur_ctrl | port_dir),ppc->lpt_addr + 2);
489*4882a593Smuzhiyun 
490*4882a593Smuzhiyun 			// DELAY
491*4882a593Smuzhiyun 
492*4882a593Smuzhiyun 			while(count > 3)
493*4882a593Smuzhiyun 			{
494*4882a593Smuzhiyun 				*((u32 *)data) = inl(ppc->lpt_addr + 4);
495*4882a593Smuzhiyun 				data  += 4;
496*4882a593Smuzhiyun 				count -= 4;
497*4882a593Smuzhiyun 			}
498*4882a593Smuzhiyun 
499*4882a593Smuzhiyun 			while(count)
500*4882a593Smuzhiyun 			{
501*4882a593Smuzhiyun 				*data++ = inb(ppc->lpt_addr + 4);
502*4882a593Smuzhiyun 				count--;
503*4882a593Smuzhiyun 			}
504*4882a593Smuzhiyun 
505*4882a593Smuzhiyun 			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
506*4882a593Smuzhiyun 
507*4882a593Smuzhiyun 			break;
508*4882a593Smuzhiyun 		}
509*4882a593Smuzhiyun 	}
510*4882a593Smuzhiyun 
511*4882a593Smuzhiyun }
512*4882a593Smuzhiyun 
513*4882a593Smuzhiyun //***************************************************************************
514*4882a593Smuzhiyun 
ppc6_wait_for_fifo(Interface * ppc)515*4882a593Smuzhiyun static void ppc6_wait_for_fifo(Interface *ppc)
516*4882a593Smuzhiyun {
517*4882a593Smuzhiyun 	int i;
518*4882a593Smuzhiyun 
519*4882a593Smuzhiyun 	if (ppc->ppc_flags & fifo_wait)
520*4882a593Smuzhiyun 	{
521*4882a593Smuzhiyun 		for(i=0; i<20; i++)
522*4882a593Smuzhiyun 			inb(ppc->lpt_addr + 1);
523*4882a593Smuzhiyun 	}
524*4882a593Smuzhiyun }
525*4882a593Smuzhiyun 
526*4882a593Smuzhiyun //***************************************************************************
527*4882a593Smuzhiyun 
ppc6_wr_data_blk(Interface * ppc,u8 * data,long count)528*4882a593Smuzhiyun static void ppc6_wr_data_blk(Interface *ppc, u8 *data, long count)
529*4882a593Smuzhiyun {
530*4882a593Smuzhiyun 	switch(ppc->mode)
531*4882a593Smuzhiyun 	{
532*4882a593Smuzhiyun 		case PPCMODE_UNI_SW :
533*4882a593Smuzhiyun 		case PPCMODE_BI_SW :
534*4882a593Smuzhiyun 		{
535*4882a593Smuzhiyun 			while(count--)
536*4882a593Smuzhiyun 			{
537*4882a593Smuzhiyun 				outb(*data++, ppc->lpt_addr);
538*4882a593Smuzhiyun 
539*4882a593Smuzhiyun 				ppc->cur_ctrl ^= data_stb;
540*4882a593Smuzhiyun 
541*4882a593Smuzhiyun 				outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
542*4882a593Smuzhiyun 			}
543*4882a593Smuzhiyun 
544*4882a593Smuzhiyun 			break;
545*4882a593Smuzhiyun 		}
546*4882a593Smuzhiyun 
547*4882a593Smuzhiyun 		case PPCMODE_UNI_FW :
548*4882a593Smuzhiyun 		case PPCMODE_BI_FW :
549*4882a593Smuzhiyun 		{
550*4882a593Smuzhiyun 			u8 this, last;
551*4882a593Smuzhiyun 
552*4882a593Smuzhiyun 			ppc6_send_cmd(ppc,(CMD_PREFIX_SET | PREFIX_FASTWR));
553*4882a593Smuzhiyun 
554*4882a593Smuzhiyun 			ppc->cur_ctrl |= port_stb;
555*4882a593Smuzhiyun 
556*4882a593Smuzhiyun 			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
557*4882a593Smuzhiyun 
558*4882a593Smuzhiyun 			last = *data;
559*4882a593Smuzhiyun 
560*4882a593Smuzhiyun 			outb(last, ppc->lpt_addr);
561*4882a593Smuzhiyun 
562*4882a593Smuzhiyun 			while(count)
563*4882a593Smuzhiyun 			{
564*4882a593Smuzhiyun 				this = *data++;
565*4882a593Smuzhiyun 				count--;
566*4882a593Smuzhiyun 
567*4882a593Smuzhiyun 				if (this == last)
568*4882a593Smuzhiyun 				{
569*4882a593Smuzhiyun 					ppc->cur_ctrl ^= data_stb;
570*4882a593Smuzhiyun 
571*4882a593Smuzhiyun 					outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
572*4882a593Smuzhiyun 				}
573*4882a593Smuzhiyun 				else
574*4882a593Smuzhiyun 				{
575*4882a593Smuzhiyun 					outb(this, ppc->lpt_addr);
576*4882a593Smuzhiyun 
577*4882a593Smuzhiyun 					last = this;
578*4882a593Smuzhiyun 				}
579*4882a593Smuzhiyun 			}
580*4882a593Smuzhiyun 
581*4882a593Smuzhiyun 			ppc->cur_ctrl &= ~port_stb;
582*4882a593Smuzhiyun 
583*4882a593Smuzhiyun 			outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
584*4882a593Smuzhiyun 
585*4882a593Smuzhiyun 			ppc6_send_cmd(ppc,(CMD_PREFIX_RESET | PREFIX_FASTWR));
586*4882a593Smuzhiyun 
587*4882a593Smuzhiyun 			break;
588*4882a593Smuzhiyun 		}
589*4882a593Smuzhiyun 
590*4882a593Smuzhiyun 		case PPCMODE_EPP_BYTE :
591*4882a593Smuzhiyun 		{
592*4882a593Smuzhiyun 			while(count)
593*4882a593Smuzhiyun 			{
594*4882a593Smuzhiyun 				outb(*data++,ppc->lpt_addr + 4);
595*4882a593Smuzhiyun 				count--;
596*4882a593Smuzhiyun 			}
597*4882a593Smuzhiyun 
598*4882a593Smuzhiyun 			ppc6_wait_for_fifo(ppc);
599*4882a593Smuzhiyun 
600*4882a593Smuzhiyun 			break;
601*4882a593Smuzhiyun 		}
602*4882a593Smuzhiyun 
603*4882a593Smuzhiyun 		case PPCMODE_EPP_WORD :
604*4882a593Smuzhiyun 		{
605*4882a593Smuzhiyun 			while(count > 1)
606*4882a593Smuzhiyun 			{
607*4882a593Smuzhiyun 				outw(*((u16 *)data),ppc->lpt_addr + 4);
608*4882a593Smuzhiyun 				data  += 2;
609*4882a593Smuzhiyun 				count -= 2;
610*4882a593Smuzhiyun 			}
611*4882a593Smuzhiyun 
612*4882a593Smuzhiyun 			while(count)
613*4882a593Smuzhiyun 			{
614*4882a593Smuzhiyun 				outb(*data++,ppc->lpt_addr + 4);
615*4882a593Smuzhiyun 				count--;
616*4882a593Smuzhiyun 			}
617*4882a593Smuzhiyun 
618*4882a593Smuzhiyun 			ppc6_wait_for_fifo(ppc);
619*4882a593Smuzhiyun 
620*4882a593Smuzhiyun 			break;
621*4882a593Smuzhiyun 		}
622*4882a593Smuzhiyun 
623*4882a593Smuzhiyun 		case PPCMODE_EPP_DWORD :
624*4882a593Smuzhiyun 		{
625*4882a593Smuzhiyun 			while(count > 3)
626*4882a593Smuzhiyun 			{
627*4882a593Smuzhiyun 				outl(*((u32 *)data),ppc->lpt_addr + 4);
628*4882a593Smuzhiyun 				data  += 4;
629*4882a593Smuzhiyun 				count -= 4;
630*4882a593Smuzhiyun 			}
631*4882a593Smuzhiyun 
632*4882a593Smuzhiyun 			while(count)
633*4882a593Smuzhiyun 			{
634*4882a593Smuzhiyun 				outb(*data++,ppc->lpt_addr + 4);
635*4882a593Smuzhiyun 				count--;
636*4882a593Smuzhiyun 			}
637*4882a593Smuzhiyun 
638*4882a593Smuzhiyun 			ppc6_wait_for_fifo(ppc);
639*4882a593Smuzhiyun 
640*4882a593Smuzhiyun 			break;
641*4882a593Smuzhiyun 		}
642*4882a593Smuzhiyun 	}
643*4882a593Smuzhiyun }
644*4882a593Smuzhiyun 
645*4882a593Smuzhiyun //***************************************************************************
646*4882a593Smuzhiyun 
ppc6_rd_port16_blk(Interface * ppc,u8 port,u8 * data,long length)647*4882a593Smuzhiyun static void ppc6_rd_port16_blk(Interface *ppc, u8 port, u8 *data, long length)
648*4882a593Smuzhiyun {
649*4882a593Smuzhiyun 	length = length << 1;
650*4882a593Smuzhiyun 
651*4882a593Smuzhiyun 	ppc6_send_cmd(ppc, (REG_BLKSIZE | ACCESS_REG | ACCESS_WRITE));
652*4882a593Smuzhiyun 	ppc6_wr_data_byte(ppc,(u8)length);
653*4882a593Smuzhiyun 	ppc6_wr_data_byte(ppc,(u8)(length >> 8));
654*4882a593Smuzhiyun 	ppc6_wr_data_byte(ppc,0);
655*4882a593Smuzhiyun 
656*4882a593Smuzhiyun 	ppc6_send_cmd(ppc, (CMD_PREFIX_SET | PREFIX_IO16 | PREFIX_BLK));
657*4882a593Smuzhiyun 
658*4882a593Smuzhiyun 	ppc6_send_cmd(ppc, (u8)(port | ACCESS_PORT | ACCESS_READ));
659*4882a593Smuzhiyun 
660*4882a593Smuzhiyun 	ppc6_rd_data_blk(ppc, data, length);
661*4882a593Smuzhiyun 
662*4882a593Smuzhiyun 	ppc6_send_cmd(ppc, (CMD_PREFIX_RESET | PREFIX_IO16 | PREFIX_BLK));
663*4882a593Smuzhiyun }
664*4882a593Smuzhiyun 
665*4882a593Smuzhiyun //***************************************************************************
666*4882a593Smuzhiyun 
ppc6_wr_port16_blk(Interface * ppc,u8 port,u8 * data,long length)667*4882a593Smuzhiyun static void ppc6_wr_port16_blk(Interface *ppc, u8 port, u8 *data, long length)
668*4882a593Smuzhiyun {
669*4882a593Smuzhiyun 	length = length << 1;
670*4882a593Smuzhiyun 
671*4882a593Smuzhiyun 	ppc6_send_cmd(ppc, (REG_BLKSIZE | ACCESS_REG | ACCESS_WRITE));
672*4882a593Smuzhiyun 	ppc6_wr_data_byte(ppc,(u8)length);
673*4882a593Smuzhiyun 	ppc6_wr_data_byte(ppc,(u8)(length >> 8));
674*4882a593Smuzhiyun 	ppc6_wr_data_byte(ppc,0);
675*4882a593Smuzhiyun 
676*4882a593Smuzhiyun 	ppc6_send_cmd(ppc, (CMD_PREFIX_SET | PREFIX_IO16 | PREFIX_BLK));
677*4882a593Smuzhiyun 
678*4882a593Smuzhiyun 	ppc6_send_cmd(ppc, (u8)(port | ACCESS_PORT | ACCESS_WRITE));
679*4882a593Smuzhiyun 
680*4882a593Smuzhiyun 	ppc6_wr_data_blk(ppc, data, length);
681*4882a593Smuzhiyun 
682*4882a593Smuzhiyun 	ppc6_send_cmd(ppc, (CMD_PREFIX_RESET | PREFIX_IO16 | PREFIX_BLK));
683*4882a593Smuzhiyun }
684*4882a593Smuzhiyun 
685*4882a593Smuzhiyun //***************************************************************************
686*4882a593Smuzhiyun 
ppc6_wr_extout(Interface * ppc,u8 regdata)687*4882a593Smuzhiyun static void ppc6_wr_extout(Interface *ppc, u8 regdata)
688*4882a593Smuzhiyun {
689*4882a593Smuzhiyun 	ppc6_send_cmd(ppc,(REG_VERSION | ACCESS_REG | ACCESS_WRITE));
690*4882a593Smuzhiyun 
691*4882a593Smuzhiyun 	ppc6_wr_data_byte(ppc, (u8)((regdata & 0x03) << 6));
692*4882a593Smuzhiyun }
693*4882a593Smuzhiyun 
694*4882a593Smuzhiyun //***************************************************************************
695*4882a593Smuzhiyun 
ppc6_open(Interface * ppc)696*4882a593Smuzhiyun static int ppc6_open(Interface *ppc)
697*4882a593Smuzhiyun {
698*4882a593Smuzhiyun 	int ret;
699*4882a593Smuzhiyun 
700*4882a593Smuzhiyun 	ret = ppc6_select(ppc);
701*4882a593Smuzhiyun 
702*4882a593Smuzhiyun 	if (ret == 0)
703*4882a593Smuzhiyun 		return(ret);
704*4882a593Smuzhiyun 
705*4882a593Smuzhiyun 	ppc->ppc_flags &= ~fifo_wait;
706*4882a593Smuzhiyun 
707*4882a593Smuzhiyun 	ppc6_send_cmd(ppc, (ACCESS_REG | ACCESS_WRITE | REG_RAMSIZE));
708*4882a593Smuzhiyun 	ppc6_wr_data_byte(ppc, RAMSIZE_128K);
709*4882a593Smuzhiyun 
710*4882a593Smuzhiyun 	ppc6_send_cmd(ppc, (ACCESS_REG | ACCESS_READ | REG_VERSION));
711*4882a593Smuzhiyun 
712*4882a593Smuzhiyun 	if ((ppc6_rd_data_byte(ppc) & 0x3F) == 0x0C)
713*4882a593Smuzhiyun 		ppc->ppc_flags |= fifo_wait;
714*4882a593Smuzhiyun 
715*4882a593Smuzhiyun 	return(ret);
716*4882a593Smuzhiyun }
717*4882a593Smuzhiyun 
718*4882a593Smuzhiyun //***************************************************************************
719*4882a593Smuzhiyun 
ppc6_close(Interface * ppc)720*4882a593Smuzhiyun static void ppc6_close(Interface *ppc)
721*4882a593Smuzhiyun {
722*4882a593Smuzhiyun 	ppc6_deselect(ppc);
723*4882a593Smuzhiyun }
724*4882a593Smuzhiyun 
725*4882a593Smuzhiyun //***************************************************************************
726*4882a593Smuzhiyun 
727