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