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