0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019 #define port_stb 1
0020 #define port_afd 2
0021 #define cmd_stb port_afd
0022 #define port_init 4
0023 #define data_stb port_init
0024 #define port_sel 8
0025 #define port_int 16
0026 #define port_dir 0x20
0027
0028 #define ECR_EPP 0x80
0029 #define ECR_BI 0x20
0030
0031
0032
0033
0034
0035 #define ACCESS_REG 0x00
0036 #define ACCESS_PORT 0x40
0037
0038 #define ACCESS_READ 0x00
0039 #define ACCESS_WRITE 0x20
0040
0041
0042
0043 #define CMD_PREFIX_SET 0xe0
0044 #define CMD_PREFIX_RESET 0xc0
0045 #define PREFIX_IO16 0x01
0046 #define PREFIX_FASTWR 0x04
0047 #define PREFIX_BLK 0x08
0048
0049
0050
0051 #define REG_STATUS 0x00
0052 #define STATUS_IRQA 0x01
0053 #define STATUS_EEPROM_DO 0x40
0054 #define REG_VERSION 0x01
0055 #define REG_HWCFG 0x02
0056 #define REG_RAMSIZE 0x03
0057 #define RAMSIZE_128K 0x02
0058 #define REG_EEPROM 0x06
0059 #define EEPROM_SK 0x01
0060 #define EEPROM_DI 0x02
0061 #define EEPROM_CS 0x04
0062 #define EEPROM_EN 0x08
0063 #define REG_BLKSIZE 0x08
0064
0065
0066
0067 typedef struct ppc_storage {
0068 u16 lpt_addr;
0069 u8 ppc_id;
0070 u8 mode;
0071
0072
0073
0074
0075
0076
0077
0078 u8 ppc_flags;
0079 u8 org_data;
0080 u8 org_ctrl;
0081 u8 cur_ctrl;
0082 } Interface;
0083
0084
0085
0086
0087
0088 #define fifo_wait 0x10
0089
0090
0091
0092
0093
0094 #define PPCMODE_UNI_SW 0
0095 #define PPCMODE_UNI_FW 1
0096 #define PPCMODE_BI_SW 2
0097 #define PPCMODE_BI_FW 3
0098 #define PPCMODE_EPP_BYTE 4
0099 #define PPCMODE_EPP_WORD 5
0100 #define PPCMODE_EPP_DWORD 6
0101
0102
0103
0104 static int ppc6_select(Interface *ppc);
0105 static void ppc6_deselect(Interface *ppc);
0106 static void ppc6_send_cmd(Interface *ppc, u8 cmd);
0107 static void ppc6_wr_data_byte(Interface *ppc, u8 data);
0108 static u8 ppc6_rd_data_byte(Interface *ppc);
0109 static u8 ppc6_rd_port(Interface *ppc, u8 port);
0110 static void ppc6_wr_port(Interface *ppc, u8 port, u8 data);
0111 static void ppc6_rd_data_blk(Interface *ppc, u8 *data, long count);
0112 static void ppc6_wait_for_fifo(Interface *ppc);
0113 static void ppc6_wr_data_blk(Interface *ppc, u8 *data, long count);
0114 static void ppc6_rd_port16_blk(Interface *ppc, u8 port, u8 *data, long length);
0115 static void ppc6_wr_port16_blk(Interface *ppc, u8 port, u8 *data, long length);
0116 static void ppc6_wr_extout(Interface *ppc, u8 regdata);
0117 static int ppc6_open(Interface *ppc);
0118 static void ppc6_close(Interface *ppc);
0119
0120
0121
0122 static int ppc6_select(Interface *ppc)
0123 {
0124 u8 i, j, k;
0125
0126 i = inb(ppc->lpt_addr + 1);
0127
0128 if (i & 1)
0129 outb(i, ppc->lpt_addr + 1);
0130
0131 ppc->org_data = inb(ppc->lpt_addr);
0132
0133 ppc->org_ctrl = inb(ppc->lpt_addr + 2) & 0x5F;
0134
0135 ppc->cur_ctrl = ppc->org_ctrl;
0136
0137 ppc->cur_ctrl |= port_sel;
0138
0139 outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
0140
0141 if (ppc->org_data == 'b')
0142 outb('x', ppc->lpt_addr);
0143
0144 outb('b', ppc->lpt_addr);
0145 outb('p', ppc->lpt_addr);
0146 outb(ppc->ppc_id, ppc->lpt_addr);
0147 outb(~ppc->ppc_id,ppc->lpt_addr);
0148
0149 ppc->cur_ctrl &= ~port_sel;
0150
0151 outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
0152
0153 ppc->cur_ctrl = (ppc->cur_ctrl & port_int) | port_init;
0154
0155 outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
0156
0157 i = ppc->mode & 0x0C;
0158
0159 if (i == 0)
0160 i = (ppc->mode & 2) | 1;
0161
0162 outb(i, ppc->lpt_addr);
0163
0164 ppc->cur_ctrl |= port_sel;
0165
0166 outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
0167
0168
0169
0170 ppc->cur_ctrl |= port_afd;
0171
0172 outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
0173
0174 j = ((i & 0x08) << 4) | ((i & 0x07) << 3);
0175
0176 k = inb(ppc->lpt_addr + 1) & 0xB8;
0177
0178 if (j == k)
0179 {
0180 ppc->cur_ctrl &= ~port_afd;
0181
0182 outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
0183
0184 k = (inb(ppc->lpt_addr + 1) & 0xB8) ^ 0xB8;
0185
0186 if (j == k)
0187 {
0188 if (i & 4)
0189 ppc->cur_ctrl &= ~(port_sel | port_init);
0190 else
0191 ppc->cur_ctrl &= ~port_sel;
0192
0193 outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
0194
0195 return(1);
0196 }
0197 }
0198
0199 outb(ppc->org_ctrl, ppc->lpt_addr + 2);
0200
0201 outb(ppc->org_data, ppc->lpt_addr);
0202
0203 return(0);
0204 }
0205
0206
0207
0208 static void ppc6_deselect(Interface *ppc)
0209 {
0210 if (ppc->mode & 4)
0211 ppc->cur_ctrl |= port_init;
0212 else
0213 ppc->cur_ctrl |= port_sel;
0214
0215 outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
0216
0217 outb(ppc->org_data, ppc->lpt_addr);
0218
0219 outb((ppc->org_ctrl | port_sel), ppc->lpt_addr + 2);
0220
0221 outb(ppc->org_ctrl, ppc->lpt_addr + 2);
0222 }
0223
0224
0225
0226 static void ppc6_send_cmd(Interface *ppc, u8 cmd)
0227 {
0228 switch(ppc->mode)
0229 {
0230 case PPCMODE_UNI_SW :
0231 case PPCMODE_UNI_FW :
0232 case PPCMODE_BI_SW :
0233 case PPCMODE_BI_FW :
0234 {
0235 outb(cmd, ppc->lpt_addr);
0236
0237 ppc->cur_ctrl ^= cmd_stb;
0238
0239 outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
0240
0241 break;
0242 }
0243
0244 case PPCMODE_EPP_BYTE :
0245 case PPCMODE_EPP_WORD :
0246 case PPCMODE_EPP_DWORD :
0247 {
0248 outb(cmd, ppc->lpt_addr + 3);
0249
0250 break;
0251 }
0252 }
0253 }
0254
0255
0256
0257 static void ppc6_wr_data_byte(Interface *ppc, u8 data)
0258 {
0259 switch(ppc->mode)
0260 {
0261 case PPCMODE_UNI_SW :
0262 case PPCMODE_UNI_FW :
0263 case PPCMODE_BI_SW :
0264 case PPCMODE_BI_FW :
0265 {
0266 outb(data, ppc->lpt_addr);
0267
0268 ppc->cur_ctrl ^= data_stb;
0269
0270 outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
0271
0272 break;
0273 }
0274
0275 case PPCMODE_EPP_BYTE :
0276 case PPCMODE_EPP_WORD :
0277 case PPCMODE_EPP_DWORD :
0278 {
0279 outb(data, ppc->lpt_addr + 4);
0280
0281 break;
0282 }
0283 }
0284 }
0285
0286
0287
0288 static u8 ppc6_rd_data_byte(Interface *ppc)
0289 {
0290 u8 data = 0;
0291
0292 switch(ppc->mode)
0293 {
0294 case PPCMODE_UNI_SW :
0295 case PPCMODE_UNI_FW :
0296 {
0297 ppc->cur_ctrl = (ppc->cur_ctrl & ~port_stb) ^ data_stb;
0298
0299 outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
0300
0301
0302
0303 data = inb(ppc->lpt_addr + 1);
0304
0305 data = ((data & 0x80) >> 1) | ((data & 0x38) >> 3);
0306
0307 ppc->cur_ctrl |= port_stb;
0308
0309 outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
0310
0311
0312
0313 data |= inb(ppc->lpt_addr + 1) & 0xB8;
0314
0315 break;
0316 }
0317
0318 case PPCMODE_BI_SW :
0319 case PPCMODE_BI_FW :
0320 {
0321 ppc->cur_ctrl |= port_dir;
0322
0323 outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
0324
0325 ppc->cur_ctrl = (ppc->cur_ctrl | port_stb) ^ data_stb;
0326
0327 outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
0328
0329 data = inb(ppc->lpt_addr);
0330
0331 ppc->cur_ctrl &= ~port_stb;
0332
0333 outb(ppc->cur_ctrl,ppc->lpt_addr + 2);
0334
0335 ppc->cur_ctrl &= ~port_dir;
0336
0337 outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
0338
0339 break;
0340 }
0341
0342 case PPCMODE_EPP_BYTE :
0343 case PPCMODE_EPP_WORD :
0344 case PPCMODE_EPP_DWORD :
0345 {
0346 outb((ppc->cur_ctrl | port_dir),ppc->lpt_addr + 2);
0347
0348 data = inb(ppc->lpt_addr + 4);
0349
0350 outb(ppc->cur_ctrl,ppc->lpt_addr + 2);
0351
0352 break;
0353 }
0354 }
0355
0356 return(data);
0357 }
0358
0359
0360
0361 static u8 ppc6_rd_port(Interface *ppc, u8 port)
0362 {
0363 ppc6_send_cmd(ppc,(u8)(port | ACCESS_PORT | ACCESS_READ));
0364
0365 return(ppc6_rd_data_byte(ppc));
0366 }
0367
0368
0369
0370 static void ppc6_wr_port(Interface *ppc, u8 port, u8 data)
0371 {
0372 ppc6_send_cmd(ppc,(u8)(port | ACCESS_PORT | ACCESS_WRITE));
0373
0374 ppc6_wr_data_byte(ppc, data);
0375 }
0376
0377
0378
0379 static void ppc6_rd_data_blk(Interface *ppc, u8 *data, long count)
0380 {
0381 switch(ppc->mode)
0382 {
0383 case PPCMODE_UNI_SW :
0384 case PPCMODE_UNI_FW :
0385 {
0386 while(count)
0387 {
0388 u8 d;
0389
0390 ppc->cur_ctrl = (ppc->cur_ctrl & ~port_stb) ^ data_stb;
0391
0392 outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
0393
0394
0395
0396 d = inb(ppc->lpt_addr + 1);
0397
0398 d = ((d & 0x80) >> 1) | ((d & 0x38) >> 3);
0399
0400 ppc->cur_ctrl |= port_stb;
0401
0402 outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
0403
0404
0405
0406 d |= inb(ppc->lpt_addr + 1) & 0xB8;
0407
0408 *data++ = d;
0409 count--;
0410 }
0411
0412 break;
0413 }
0414
0415 case PPCMODE_BI_SW :
0416 case PPCMODE_BI_FW :
0417 {
0418 ppc->cur_ctrl |= port_dir;
0419
0420 outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
0421
0422 ppc->cur_ctrl |= port_stb;
0423
0424 while(count)
0425 {
0426 ppc->cur_ctrl ^= data_stb;
0427
0428 outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
0429
0430 *data++ = inb(ppc->lpt_addr);
0431 count--;
0432 }
0433
0434 ppc->cur_ctrl &= ~port_stb;
0435
0436 outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
0437
0438 ppc->cur_ctrl &= ~port_dir;
0439
0440 outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
0441
0442 break;
0443 }
0444
0445 case PPCMODE_EPP_BYTE :
0446 {
0447 outb((ppc->cur_ctrl | port_dir), ppc->lpt_addr + 2);
0448
0449
0450
0451 while(count)
0452 {
0453 *data++ = inb(ppc->lpt_addr + 4);
0454 count--;
0455 }
0456
0457 outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
0458
0459 break;
0460 }
0461
0462 case PPCMODE_EPP_WORD :
0463 {
0464 outb((ppc->cur_ctrl | port_dir), ppc->lpt_addr + 2);
0465
0466
0467
0468 while(count > 1)
0469 {
0470 *((u16 *)data) = inw(ppc->lpt_addr + 4);
0471 data += 2;
0472 count -= 2;
0473 }
0474
0475 while(count)
0476 {
0477 *data++ = inb(ppc->lpt_addr + 4);
0478 count--;
0479 }
0480
0481 outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
0482
0483 break;
0484 }
0485
0486 case PPCMODE_EPP_DWORD :
0487 {
0488 outb((ppc->cur_ctrl | port_dir),ppc->lpt_addr + 2);
0489
0490
0491
0492 while(count > 3)
0493 {
0494 *((u32 *)data) = inl(ppc->lpt_addr + 4);
0495 data += 4;
0496 count -= 4;
0497 }
0498
0499 while(count)
0500 {
0501 *data++ = inb(ppc->lpt_addr + 4);
0502 count--;
0503 }
0504
0505 outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
0506
0507 break;
0508 }
0509 }
0510
0511 }
0512
0513
0514
0515 static void ppc6_wait_for_fifo(Interface *ppc)
0516 {
0517 int i;
0518
0519 if (ppc->ppc_flags & fifo_wait)
0520 {
0521 for(i=0; i<20; i++)
0522 inb(ppc->lpt_addr + 1);
0523 }
0524 }
0525
0526
0527
0528 static void ppc6_wr_data_blk(Interface *ppc, u8 *data, long count)
0529 {
0530 switch(ppc->mode)
0531 {
0532 case PPCMODE_UNI_SW :
0533 case PPCMODE_BI_SW :
0534 {
0535 while(count--)
0536 {
0537 outb(*data++, ppc->lpt_addr);
0538
0539 ppc->cur_ctrl ^= data_stb;
0540
0541 outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
0542 }
0543
0544 break;
0545 }
0546
0547 case PPCMODE_UNI_FW :
0548 case PPCMODE_BI_FW :
0549 {
0550 u8 this, last;
0551
0552 ppc6_send_cmd(ppc,(CMD_PREFIX_SET | PREFIX_FASTWR));
0553
0554 ppc->cur_ctrl |= port_stb;
0555
0556 outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
0557
0558 last = *data;
0559
0560 outb(last, ppc->lpt_addr);
0561
0562 while(count)
0563 {
0564 this = *data++;
0565 count--;
0566
0567 if (this == last)
0568 {
0569 ppc->cur_ctrl ^= data_stb;
0570
0571 outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
0572 }
0573 else
0574 {
0575 outb(this, ppc->lpt_addr);
0576
0577 last = this;
0578 }
0579 }
0580
0581 ppc->cur_ctrl &= ~port_stb;
0582
0583 outb(ppc->cur_ctrl, ppc->lpt_addr + 2);
0584
0585 ppc6_send_cmd(ppc,(CMD_PREFIX_RESET | PREFIX_FASTWR));
0586
0587 break;
0588 }
0589
0590 case PPCMODE_EPP_BYTE :
0591 {
0592 while(count)
0593 {
0594 outb(*data++,ppc->lpt_addr + 4);
0595 count--;
0596 }
0597
0598 ppc6_wait_for_fifo(ppc);
0599
0600 break;
0601 }
0602
0603 case PPCMODE_EPP_WORD :
0604 {
0605 while(count > 1)
0606 {
0607 outw(*((u16 *)data),ppc->lpt_addr + 4);
0608 data += 2;
0609 count -= 2;
0610 }
0611
0612 while(count)
0613 {
0614 outb(*data++,ppc->lpt_addr + 4);
0615 count--;
0616 }
0617
0618 ppc6_wait_for_fifo(ppc);
0619
0620 break;
0621 }
0622
0623 case PPCMODE_EPP_DWORD :
0624 {
0625 while(count > 3)
0626 {
0627 outl(*((u32 *)data),ppc->lpt_addr + 4);
0628 data += 4;
0629 count -= 4;
0630 }
0631
0632 while(count)
0633 {
0634 outb(*data++,ppc->lpt_addr + 4);
0635 count--;
0636 }
0637
0638 ppc6_wait_for_fifo(ppc);
0639
0640 break;
0641 }
0642 }
0643 }
0644
0645
0646
0647 static void ppc6_rd_port16_blk(Interface *ppc, u8 port, u8 *data, long length)
0648 {
0649 length = length << 1;
0650
0651 ppc6_send_cmd(ppc, (REG_BLKSIZE | ACCESS_REG | ACCESS_WRITE));
0652 ppc6_wr_data_byte(ppc,(u8)length);
0653 ppc6_wr_data_byte(ppc,(u8)(length >> 8));
0654 ppc6_wr_data_byte(ppc,0);
0655
0656 ppc6_send_cmd(ppc, (CMD_PREFIX_SET | PREFIX_IO16 | PREFIX_BLK));
0657
0658 ppc6_send_cmd(ppc, (u8)(port | ACCESS_PORT | ACCESS_READ));
0659
0660 ppc6_rd_data_blk(ppc, data, length);
0661
0662 ppc6_send_cmd(ppc, (CMD_PREFIX_RESET | PREFIX_IO16 | PREFIX_BLK));
0663 }
0664
0665
0666
0667 static void ppc6_wr_port16_blk(Interface *ppc, u8 port, u8 *data, long length)
0668 {
0669 length = length << 1;
0670
0671 ppc6_send_cmd(ppc, (REG_BLKSIZE | ACCESS_REG | ACCESS_WRITE));
0672 ppc6_wr_data_byte(ppc,(u8)length);
0673 ppc6_wr_data_byte(ppc,(u8)(length >> 8));
0674 ppc6_wr_data_byte(ppc,0);
0675
0676 ppc6_send_cmd(ppc, (CMD_PREFIX_SET | PREFIX_IO16 | PREFIX_BLK));
0677
0678 ppc6_send_cmd(ppc, (u8)(port | ACCESS_PORT | ACCESS_WRITE));
0679
0680 ppc6_wr_data_blk(ppc, data, length);
0681
0682 ppc6_send_cmd(ppc, (CMD_PREFIX_RESET | PREFIX_IO16 | PREFIX_BLK));
0683 }
0684
0685
0686
0687 static void ppc6_wr_extout(Interface *ppc, u8 regdata)
0688 {
0689 ppc6_send_cmd(ppc,(REG_VERSION | ACCESS_REG | ACCESS_WRITE));
0690
0691 ppc6_wr_data_byte(ppc, (u8)((regdata & 0x03) << 6));
0692 }
0693
0694
0695
0696 static int ppc6_open(Interface *ppc)
0697 {
0698 int ret;
0699
0700 ret = ppc6_select(ppc);
0701
0702 if (ret == 0)
0703 return(ret);
0704
0705 ppc->ppc_flags &= ~fifo_wait;
0706
0707 ppc6_send_cmd(ppc, (ACCESS_REG | ACCESS_WRITE | REG_RAMSIZE));
0708 ppc6_wr_data_byte(ppc, RAMSIZE_128K);
0709
0710 ppc6_send_cmd(ppc, (ACCESS_REG | ACCESS_READ | REG_VERSION));
0711
0712 if ((ppc6_rd_data_byte(ppc) & 0x3F) == 0x0C)
0713 ppc->ppc_flags |= fifo_wait;
0714
0715 return(ret);
0716 }
0717
0718
0719
0720 static void ppc6_close(Interface *ppc)
0721 {
0722 ppc6_deselect(ppc);
0723 }
0724
0725
0726