Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  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
 69         u8      ppc_id;
 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
 78         u8      ppc_flags;
 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 
727 
  This page was automatically generated by the LXR engine.