2 ppc6lnx.c (c) 2001 Micro Solutions Inc.
3 Released under the terms of the GNU General Public license
5 ppc6lnx.c is a par of the protocol driver for the Micro Solutions
6 "BACKPACK" parallel port IDE adapter
7 (Works on Series 6 drives)
11 //***************************************************************************
13 // PPC 6 Code in C sanitized for LINUX
14 // Original x86 ASM by Ron, Converted to C by Clive
16 //***************************************************************************
21 #define cmd_stb port_afd
23 #define data_stb port_init
31 //***************************************************************************
35 #define ACCESS_REG 0x00
36 #define ACCESS_PORT 0x40
38 #define ACCESS_READ 0x00
39 #define ACCESS_WRITE 0x20
41 // 60772 Command Prefix
43 #define CMD_PREFIX_SET 0xe0 // Special command that modifies the next command's operation
44 #define CMD_PREFIX_RESET 0xc0 // Resets current cmd modifier reg bits
45 #define PREFIX_IO16 0x01 // perform 16-bit wide I/O
46 #define PREFIX_FASTWR 0x04 // enable PPC mode fast-write
47 #define PREFIX_BLK 0x08 // enable block transfer mode
51 #define REG_STATUS 0x00 // status register
52 #define STATUS_IRQA 0x01 // Peripheral IRQA line
53 #define STATUS_EEPROM_DO 0x40 // Serial EEPROM data bit
54 #define REG_VERSION 0x01 // PPC version register (read)
55 #define REG_HWCFG 0x02 // Hardware Config register
56 #define REG_RAMSIZE 0x03 // Size of RAM Buffer
57 #define RAMSIZE_128K 0x02
58 #define REG_EEPROM 0x06 // EEPROM control register
59 #define EEPROM_SK 0x01 // eeprom SK bit
60 #define EEPROM_DI 0x02 // eeprom DI bit
61 #define EEPROM_CS 0x04 // eeprom CS bit
62 #define EEPROM_EN 0x08 // eeprom output enable
63 #define REG_BLKSIZE 0x08 // Block transfer len (24 bit)
65 //***************************************************************************
67 typedef struct ppc_storage
{
68 u16 lpt_addr
; // LPT base address
70 u8 mode
; // operating mode
79 u8 org_data
; // original LPT data port contents
80 u8 org_ctrl
; // original LPT control port contents
81 u8 cur_ctrl
; // current control port contents
84 //***************************************************************************
88 #define fifo_wait 0x10
90 //***************************************************************************
92 // DONT CHANGE THESE LEST YOU BREAK EVERYTHING - BIT FIELD DEPENDENCIES
94 #define PPCMODE_UNI_SW 0
95 #define PPCMODE_UNI_FW 1
96 #define PPCMODE_BI_SW 2
97 #define PPCMODE_BI_FW 3
98 #define PPCMODE_EPP_BYTE 4
99 #define PPCMODE_EPP_WORD 5
100 #define PPCMODE_EPP_DWORD 6
102 //***************************************************************************
104 static int ppc6_select(Interface
*ppc
);
105 static void ppc6_deselect(Interface
*ppc
);
106 static void ppc6_send_cmd(Interface
*ppc
, u8 cmd
);
107 static void ppc6_wr_data_byte(Interface
*ppc
, u8 data
);
108 static u8
ppc6_rd_data_byte(Interface
*ppc
);
109 static u8
ppc6_rd_port(Interface
*ppc
, u8 port
);
110 static void ppc6_wr_port(Interface
*ppc
, u8 port
, u8 data
);
111 static void ppc6_rd_data_blk(Interface
*ppc
, u8
*data
, long count
);
112 static void ppc6_wait_for_fifo(Interface
*ppc
);
113 static void ppc6_wr_data_blk(Interface
*ppc
, u8
*data
, long count
);
114 static void ppc6_rd_port16_blk(Interface
*ppc
, u8 port
, u8
*data
, long length
);
115 static void ppc6_wr_port16_blk(Interface
*ppc
, u8 port
, u8
*data
, long length
);
116 static void ppc6_wr_extout(Interface
*ppc
, u8 regdata
);
117 static int ppc6_open(Interface
*ppc
);
118 static void ppc6_close(Interface
*ppc
);
120 //***************************************************************************
122 static int ppc6_select(Interface
*ppc
)
126 i
= inb(ppc
->lpt_addr
+ 1);
129 outb(i
, ppc
->lpt_addr
+ 1);
131 ppc
->org_data
= inb(ppc
->lpt_addr
);
133 ppc
->org_ctrl
= inb(ppc
->lpt_addr
+ 2) & 0x5F; // readback ctrl
135 ppc
->cur_ctrl
= ppc
->org_ctrl
;
137 ppc
->cur_ctrl
|= port_sel
;
139 outb(ppc
->cur_ctrl
, ppc
->lpt_addr
+ 2);
141 if (ppc
->org_data
== 'b')
142 outb('x', ppc
->lpt_addr
);
144 outb('b', ppc
->lpt_addr
);
145 outb('p', ppc
->lpt_addr
);
146 outb(ppc
->ppc_id
, ppc
->lpt_addr
);
147 outb(~ppc
->ppc_id
,ppc
->lpt_addr
);
149 ppc
->cur_ctrl
&= ~port_sel
;
151 outb(ppc
->cur_ctrl
, ppc
->lpt_addr
+ 2);
153 ppc
->cur_ctrl
= (ppc
->cur_ctrl
& port_int
) | port_init
;
155 outb(ppc
->cur_ctrl
, ppc
->lpt_addr
+ 2);
157 i
= ppc
->mode
& 0x0C;
160 i
= (ppc
->mode
& 2) | 1;
162 outb(i
, ppc
->lpt_addr
);
164 ppc
->cur_ctrl
|= port_sel
;
166 outb(ppc
->cur_ctrl
, ppc
->lpt_addr
+ 2);
170 ppc
->cur_ctrl
|= port_afd
;
172 outb(ppc
->cur_ctrl
, ppc
->lpt_addr
+ 2);
174 j
= ((i
& 0x08) << 4) | ((i
& 0x07) << 3);
176 k
= inb(ppc
->lpt_addr
+ 1) & 0xB8;
180 ppc
->cur_ctrl
&= ~port_afd
;
182 outb(ppc
->cur_ctrl
, ppc
->lpt_addr
+ 2);
184 k
= (inb(ppc
->lpt_addr
+ 1) & 0xB8) ^ 0xB8;
189 ppc
->cur_ctrl
&= ~(port_sel
| port_init
);
191 ppc
->cur_ctrl
&= ~port_sel
;
193 outb(ppc
->cur_ctrl
, ppc
->lpt_addr
+ 2);
199 outb(ppc
->org_ctrl
, ppc
->lpt_addr
+ 2);
201 outb(ppc
->org_data
, ppc
->lpt_addr
);
206 //***************************************************************************
208 static void ppc6_deselect(Interface
*ppc
)
210 if (ppc
->mode
& 4) // EPP
211 ppc
->cur_ctrl
|= port_init
;
213 ppc
->cur_ctrl
|= port_sel
;
215 outb(ppc
->cur_ctrl
, ppc
->lpt_addr
+ 2);
217 outb(ppc
->org_data
, ppc
->lpt_addr
);
219 outb((ppc
->org_ctrl
| port_sel
), ppc
->lpt_addr
+ 2);
221 outb(ppc
->org_ctrl
, ppc
->lpt_addr
+ 2);
224 //***************************************************************************
226 static void ppc6_send_cmd(Interface
*ppc
, u8 cmd
)
230 case PPCMODE_UNI_SW
:
231 case PPCMODE_UNI_FW
:
235 outb(cmd
, ppc
->lpt_addr
);
237 ppc
->cur_ctrl
^= cmd_stb
;
239 outb(ppc
->cur_ctrl
, ppc
->lpt_addr
+ 2);
244 case PPCMODE_EPP_BYTE
:
245 case PPCMODE_EPP_WORD
:
246 case PPCMODE_EPP_DWORD
:
248 outb(cmd
, ppc
->lpt_addr
+ 3);
255 //***************************************************************************
257 static void ppc6_wr_data_byte(Interface
*ppc
, u8 data
)
261 case PPCMODE_UNI_SW
:
262 case PPCMODE_UNI_FW
:
266 outb(data
, ppc
->lpt_addr
);
268 ppc
->cur_ctrl
^= data_stb
;
270 outb(ppc
->cur_ctrl
, ppc
->lpt_addr
+ 2);
275 case PPCMODE_EPP_BYTE
:
276 case PPCMODE_EPP_WORD
:
277 case PPCMODE_EPP_DWORD
:
279 outb(data
, ppc
->lpt_addr
+ 4);
286 //***************************************************************************
288 static u8
ppc6_rd_data_byte(Interface
*ppc
)
294 case PPCMODE_UNI_SW
:
295 case PPCMODE_UNI_FW
:
297 ppc
->cur_ctrl
= (ppc
->cur_ctrl
& ~port_stb
) ^ data_stb
;
299 outb(ppc
->cur_ctrl
, ppc
->lpt_addr
+ 2);
303 data
= inb(ppc
->lpt_addr
+ 1);
305 data
= ((data
& 0x80) >> 1) | ((data
& 0x38) >> 3);
307 ppc
->cur_ctrl
|= port_stb
;
309 outb(ppc
->cur_ctrl
, ppc
->lpt_addr
+ 2);
313 data
|= inb(ppc
->lpt_addr
+ 1) & 0xB8;
321 ppc
->cur_ctrl
|= port_dir
;
323 outb(ppc
->cur_ctrl
, ppc
->lpt_addr
+ 2);
325 ppc
->cur_ctrl
= (ppc
->cur_ctrl
| port_stb
) ^ data_stb
;
327 outb(ppc
->cur_ctrl
, ppc
->lpt_addr
+ 2);
329 data
= inb(ppc
->lpt_addr
);
331 ppc
->cur_ctrl
&= ~port_stb
;
333 outb(ppc
->cur_ctrl
,ppc
->lpt_addr
+ 2);
335 ppc
->cur_ctrl
&= ~port_dir
;
337 outb(ppc
->cur_ctrl
, ppc
->lpt_addr
+ 2);
342 case PPCMODE_EPP_BYTE
:
343 case PPCMODE_EPP_WORD
:
344 case PPCMODE_EPP_DWORD
:
346 outb((ppc
->cur_ctrl
| port_dir
),ppc
->lpt_addr
+ 2);
348 data
= inb(ppc
->lpt_addr
+ 4);
350 outb(ppc
->cur_ctrl
,ppc
->lpt_addr
+ 2);
359 //***************************************************************************
361 static u8
ppc6_rd_port(Interface
*ppc
, u8 port
)
363 ppc6_send_cmd(ppc
,(u8
)(port
| ACCESS_PORT
| ACCESS_READ
));
365 return(ppc6_rd_data_byte(ppc
));
368 //***************************************************************************
370 static void ppc6_wr_port(Interface
*ppc
, u8 port
, u8 data
)
372 ppc6_send_cmd(ppc
,(u8
)(port
| ACCESS_PORT
| ACCESS_WRITE
));
374 ppc6_wr_data_byte(ppc
, data
);
377 //***************************************************************************
379 static void ppc6_rd_data_blk(Interface
*ppc
, u8
*data
, long count
)
383 case PPCMODE_UNI_SW
:
384 case PPCMODE_UNI_FW
:
390 ppc
->cur_ctrl
= (ppc
->cur_ctrl
& ~port_stb
) ^ data_stb
;
392 outb(ppc
->cur_ctrl
, ppc
->lpt_addr
+ 2);
396 d
= inb(ppc
->lpt_addr
+ 1);
398 d
= ((d
& 0x80) >> 1) | ((d
& 0x38) >> 3);
400 ppc
->cur_ctrl
|= port_stb
;
402 outb(ppc
->cur_ctrl
, ppc
->lpt_addr
+ 2);
406 d
|= inb(ppc
->lpt_addr
+ 1) & 0xB8;
418 ppc
->cur_ctrl
|= port_dir
;
420 outb(ppc
->cur_ctrl
, ppc
->lpt_addr
+ 2);
422 ppc
->cur_ctrl
|= port_stb
;
426 ppc
->cur_ctrl
^= data_stb
;
428 outb(ppc
->cur_ctrl
, ppc
->lpt_addr
+ 2);
430 *data
++ = inb(ppc
->lpt_addr
);
434 ppc
->cur_ctrl
&= ~port_stb
;
436 outb(ppc
->cur_ctrl
, ppc
->lpt_addr
+ 2);
438 ppc
->cur_ctrl
&= ~port_dir
;
440 outb(ppc
->cur_ctrl
, ppc
->lpt_addr
+ 2);
445 case PPCMODE_EPP_BYTE
:
447 outb((ppc
->cur_ctrl
| port_dir
), ppc
->lpt_addr
+ 2);
453 *data
++ = inb(ppc
->lpt_addr
+ 4);
457 outb(ppc
->cur_ctrl
, ppc
->lpt_addr
+ 2);
462 case PPCMODE_EPP_WORD
:
464 outb((ppc
->cur_ctrl
| port_dir
), ppc
->lpt_addr
+ 2);
470 *((u16
*)data
) = inw(ppc
->lpt_addr
+ 4);
477 *data
++ = inb(ppc
->lpt_addr
+ 4);
481 outb(ppc
->cur_ctrl
, ppc
->lpt_addr
+ 2);
486 case PPCMODE_EPP_DWORD
:
488 outb((ppc
->cur_ctrl
| port_dir
),ppc
->lpt_addr
+ 2);
494 *((u32
*)data
) = inl(ppc
->lpt_addr
+ 4);
501 *data
++ = inb(ppc
->lpt_addr
+ 4);
505 outb(ppc
->cur_ctrl
, ppc
->lpt_addr
+ 2);
513 //***************************************************************************
515 static void ppc6_wait_for_fifo(Interface
*ppc
)
519 if (ppc
->ppc_flags
& fifo_wait
)
522 inb(ppc
->lpt_addr
+ 1);
526 //***************************************************************************
528 static void ppc6_wr_data_blk(Interface
*ppc
, u8
*data
, long count
)
532 case PPCMODE_UNI_SW
:
537 outb(*data
++, ppc
->lpt_addr
);
539 ppc
->cur_ctrl
^= data_stb
;
541 outb(ppc
->cur_ctrl
, ppc
->lpt_addr
+ 2);
547 case PPCMODE_UNI_FW
:
552 ppc6_send_cmd(ppc
,(CMD_PREFIX_SET
| PREFIX_FASTWR
));
554 ppc
->cur_ctrl
|= port_stb
;
556 outb(ppc
->cur_ctrl
, ppc
->lpt_addr
+ 2);
560 outb(last
, ppc
->lpt_addr
);
569 ppc
->cur_ctrl
^= data_stb
;
571 outb(ppc
->cur_ctrl
, ppc
->lpt_addr
+ 2);
575 outb(this, ppc
->lpt_addr
);
581 ppc
->cur_ctrl
&= ~port_stb
;
583 outb(ppc
->cur_ctrl
, ppc
->lpt_addr
+ 2);
585 ppc6_send_cmd(ppc
,(CMD_PREFIX_RESET
| PREFIX_FASTWR
));
590 case PPCMODE_EPP_BYTE
:
594 outb(*data
++,ppc
->lpt_addr
+ 4);
598 ppc6_wait_for_fifo(ppc
);
603 case PPCMODE_EPP_WORD
:
607 outw(*((u16
*)data
),ppc
->lpt_addr
+ 4);
614 outb(*data
++,ppc
->lpt_addr
+ 4);
618 ppc6_wait_for_fifo(ppc
);
623 case PPCMODE_EPP_DWORD
:
627 outl(*((u32
*)data
),ppc
->lpt_addr
+ 4);
634 outb(*data
++,ppc
->lpt_addr
+ 4);
638 ppc6_wait_for_fifo(ppc
);
645 //***************************************************************************
647 static void ppc6_rd_port16_blk(Interface
*ppc
, u8 port
, u8
*data
, long length
)
649 length
= length
<< 1;
651 ppc6_send_cmd(ppc
, (REG_BLKSIZE
| ACCESS_REG
| ACCESS_WRITE
));
652 ppc6_wr_data_byte(ppc
,(u8
)length
);
653 ppc6_wr_data_byte(ppc
,(u8
)(length
>> 8));
654 ppc6_wr_data_byte(ppc
,0);
656 ppc6_send_cmd(ppc
, (CMD_PREFIX_SET
| PREFIX_IO16
| PREFIX_BLK
));
658 ppc6_send_cmd(ppc
, (u8
)(port
| ACCESS_PORT
| ACCESS_READ
));
660 ppc6_rd_data_blk(ppc
, data
, length
);
662 ppc6_send_cmd(ppc
, (CMD_PREFIX_RESET
| PREFIX_IO16
| PREFIX_BLK
));
665 //***************************************************************************
667 static void ppc6_wr_port16_blk(Interface
*ppc
, u8 port
, u8
*data
, long length
)
669 length
= length
<< 1;
671 ppc6_send_cmd(ppc
, (REG_BLKSIZE
| ACCESS_REG
| ACCESS_WRITE
));
672 ppc6_wr_data_byte(ppc
,(u8
)length
);
673 ppc6_wr_data_byte(ppc
,(u8
)(length
>> 8));
674 ppc6_wr_data_byte(ppc
,0);
676 ppc6_send_cmd(ppc
, (CMD_PREFIX_SET
| PREFIX_IO16
| PREFIX_BLK
));
678 ppc6_send_cmd(ppc
, (u8
)(port
| ACCESS_PORT
| ACCESS_WRITE
));
680 ppc6_wr_data_blk(ppc
, data
, length
);
682 ppc6_send_cmd(ppc
, (CMD_PREFIX_RESET
| PREFIX_IO16
| PREFIX_BLK
));
685 //***************************************************************************
687 static void ppc6_wr_extout(Interface
*ppc
, u8 regdata
)
689 ppc6_send_cmd(ppc
,(REG_VERSION
| ACCESS_REG
| ACCESS_WRITE
));
691 ppc6_wr_data_byte(ppc
, (u8
)((regdata
& 0x03) << 6));
694 //***************************************************************************
696 static int ppc6_open(Interface
*ppc
)
700 ret
= ppc6_select(ppc
);
705 ppc
->ppc_flags
&= ~fifo_wait
;
707 ppc6_send_cmd(ppc
, (ACCESS_REG
| ACCESS_WRITE
| REG_RAMSIZE
));
708 ppc6_wr_data_byte(ppc
, RAMSIZE_128K
);
710 ppc6_send_cmd(ppc
, (ACCESS_REG
| ACCESS_READ
| REG_VERSION
));
712 if ((ppc6_rd_data_byte(ppc
) & 0x3F) == 0x0C)
713 ppc
->ppc_flags
|= fifo_wait
;
718 //***************************************************************************
720 static void ppc6_close(Interface
*ppc
)
725 //***************************************************************************