linux/drivers/block/paride/epat.c
<<
>>
Prefs
   1/* 
   2        epat.c  (c) 1997-8  Grant R. Guenther <grant@torque.net>
   3                            Under the terms of the GNU General Public License.
   4
   5        This is the low level protocol driver for the EPAT parallel
   6        to IDE adapter from Shuttle Technologies.  This adapter is
   7        used in many popular parallel port disk products such as the
   8        SyQuest EZ drives, the Avatar Shark and the Imation SuperDisk.
   9        
  10*/
  11
  12/* Changes:
  13
  14        1.01    GRG 1998.05.06 init_proto, release_proto
  15        1.02    Joshua b. Jore CPP(renamed), epat_connect, epat_disconnect
  16
  17*/
  18
  19#define EPAT_VERSION      "1.02"
  20
  21#include <linux/module.h>
  22#include <linux/init.h>
  23#include <linux/delay.h>
  24#include <linux/kernel.h>
  25#include <linux/types.h>
  26#include <linux/wait.h>
  27#include <asm/io.h>
  28
  29#include "paride.h"
  30
  31#define j44(a,b)                (((a>>4)&0x0f)+(b&0xf0))
  32#define j53(a,b)                (((a>>3)&0x1f)+((b<<4)&0xe0))
  33
  34static int epatc8;
  35
  36module_param(epatc8, int, 0);
  37MODULE_PARM_DESC(epatc8, "support for the Shuttle EP1284 chip, "
  38        "used in any recent Imation SuperDisk (LS-120) drive.");
  39
  40/* cont =  0   IDE register file
  41   cont =  1   IDE control registers
  42   cont =  2   internal EPAT registers
  43*/
  44
  45static int cont_map[3] = { 0x18, 0x10, 0 };
  46
  47static void epat_write_regr( PIA *pi, int cont, int regr, int val)
  48
  49{       int r;
  50
  51        r = regr + cont_map[cont];
  52
  53        switch (pi->mode) {
  54
  55        case 0:
  56        case 1:
  57        case 2: w0(0x60+r); w2(1); w0(val); w2(4);
  58                break;
  59
  60        case 3:
  61        case 4:
  62        case 5: w3(0x40+r); w4(val);
  63                break;
  64
  65        }
  66}
  67
  68static int epat_read_regr( PIA *pi, int cont, int regr )
  69
  70{       int  a, b, r;
  71
  72        r = regr + cont_map[cont];
  73
  74        switch (pi->mode) {
  75
  76        case 0: w0(r); w2(1); w2(3); 
  77                a = r1(); w2(4); b = r1();
  78                return j44(a,b);
  79
  80        case 1: w0(0x40+r); w2(1); w2(4);
  81                a = r1(); b = r2(); w0(0xff);
  82                return j53(a,b);
  83
  84        case 2: w0(0x20+r); w2(1); w2(0x25);
  85                a = r0(); w2(4);
  86                return a;
  87
  88        case 3:
  89        case 4:
  90        case 5: w3(r); w2(0x24); a = r4(); w2(4);
  91                return a;
  92
  93        }
  94        return -1;      /* never gets here */
  95}
  96
  97static void epat_read_block( PIA *pi, char * buf, int count )
  98
  99{       int  k, ph, a, b;
 100
 101        switch (pi->mode) {
 102
 103        case 0: w0(7); w2(1); w2(3); w0(0xff);
 104                ph = 0;
 105                for(k=0;k<count;k++) {
 106                        if (k == count-1) w0(0xfd);
 107                        w2(6+ph); a = r1();
 108                        if (a & 8) b = a; 
 109                          else { w2(4+ph); b = r1(); }
 110                        buf[k] = j44(a,b);
 111                        ph =  1 - ph;
 112                }
 113                w0(0); w2(4);
 114                break;
 115
 116        case 1: w0(0x47); w2(1); w2(5); w0(0xff);
 117                ph = 0;
 118                for(k=0;k<count;k++) {
 119                        if (k == count-1) w0(0xfd); 
 120                        w2(4+ph);
 121                        a = r1(); b = r2();
 122                        buf[k] = j53(a,b);
 123                        ph = 1 - ph;
 124                }
 125                w0(0); w2(4);
 126                break;
 127
 128        case 2: w0(0x27); w2(1); w2(0x25); w0(0);
 129                ph = 0;
 130                for(k=0;k<count-1;k++) {
 131                        w2(0x24+ph);
 132                        buf[k] = r0();
 133                        ph = 1 - ph;
 134                }
 135                w2(0x26); w2(0x27); buf[count-1] = r0(); 
 136                w2(0x25); w2(4);
 137                break;
 138
 139        case 3: w3(0x80); w2(0x24);
 140                for(k=0;k<count-1;k++) buf[k] = r4();
 141                w2(4); w3(0xa0); w2(0x24); buf[count-1] = r4();
 142                w2(4);
 143                break;
 144
 145        case 4: w3(0x80); w2(0x24);
 146                for(k=0;k<(count/2)-1;k++) ((u16 *)buf)[k] = r4w();
 147                buf[count-2] = r4();
 148                w2(4); w3(0xa0); w2(0x24); buf[count-1] = r4();
 149                w2(4);
 150                break;
 151
 152        case 5: w3(0x80); w2(0x24);
 153                for(k=0;k<(count/4)-1;k++) ((u32 *)buf)[k] = r4l();
 154                for(k=count-4;k<count-1;k++) buf[k] = r4();
 155                w2(4); w3(0xa0); w2(0x24); buf[count-1] = r4();
 156                w2(4);
 157                break;
 158
 159        }
 160}
 161
 162static void epat_write_block( PIA *pi, char * buf, int count )   
 163
 164{       int ph, k;
 165
 166        switch (pi->mode) {
 167
 168        case 0:
 169        case 1:
 170        case 2: w0(0x67); w2(1); w2(5);
 171                ph = 0;
 172                for(k=0;k<count;k++) {
 173                        w0(buf[k]);
 174                        w2(4+ph);
 175                        ph = 1 - ph;
 176                }
 177                w2(7); w2(4);
 178                break;
 179
 180        case 3: w3(0xc0); 
 181                for(k=0;k<count;k++) w4(buf[k]);
 182                w2(4);
 183                break;
 184
 185        case 4: w3(0xc0); 
 186                for(k=0;k<(count/2);k++) w4w(((u16 *)buf)[k]);
 187                w2(4);
 188                break;
 189
 190        case 5: w3(0xc0); 
 191                for(k=0;k<(count/4);k++) w4l(((u32 *)buf)[k]);
 192                w2(4);
 193                break;
 194
 195        }
 196}
 197
 198/* these macros access the EPAT registers in native addressing */
 199
 200#define WR(r,v)         epat_write_regr(pi,2,r,v)
 201#define RR(r)           (epat_read_regr(pi,2,r))
 202
 203/* and these access the IDE task file */
 204
 205#define WRi(r,v)         epat_write_regr(pi,0,r,v)
 206#define RRi(r)           (epat_read_regr(pi,0,r))
 207
 208/* FIXME:  the CPP stuff should be fixed to handle multiple EPATs on a chain */
 209
 210#define CPP(x)  w2(4);w0(0x22);w0(0xaa);w0(0x55);w0(0);w0(0xff);\
 211                w0(0x87);w0(0x78);w0(x);w2(4);w2(5);w2(4);w0(0xff);
 212
 213static void epat_connect ( PIA *pi )
 214
 215{       pi->saved_r0 = r0();
 216        pi->saved_r2 = r2();
 217
 218        /* Initialize the chip */
 219        CPP(0);
 220
 221        if (epatc8) {
 222                CPP(0x40);CPP(0xe0);
 223                w0(0);w2(1);w2(4);
 224                WR(0x8,0x12);WR(0xc,0x14);WR(0x12,0x10);
 225                WR(0xe,0xf);WR(0xf,4);
 226                /* WR(0xe,0xa);WR(0xf,4); */
 227                WR(0xe,0xd);WR(0xf,0);
 228                /* CPP(0x30); */
 229        }
 230
 231        /* Connect to the chip */
 232        CPP(0xe0);
 233        w0(0);w2(1);w2(4); /* Idle into SPP */
 234        if (pi->mode >= 3) {
 235          w0(0);w2(1);w2(4);w2(0xc);
 236          /* Request EPP */
 237          w0(0x40);w2(6);w2(7);w2(4);w2(0xc);w2(4);
 238        }
 239
 240        if (!epatc8) {
 241                WR(8,0x10); WR(0xc,0x14); WR(0xa,0x38); WR(0x12,0x10);
 242        }
 243}
 244
 245static void epat_disconnect (PIA *pi)
 246{       CPP(0x30);
 247        w0(pi->saved_r0);
 248        w2(pi->saved_r2);
 249}
 250
 251static int epat_test_proto( PIA *pi, char * scratch, int verbose )
 252
 253{       int     k, j, f, cc;
 254        int     e[2] = {0,0};
 255
 256        epat_connect(pi);
 257        cc = RR(0xd);
 258        epat_disconnect(pi);
 259
 260        epat_connect(pi);
 261        for (j=0;j<2;j++) {
 262            WRi(6,0xa0+j*0x10);
 263            for (k=0;k<256;k++) {
 264                WRi(2,k^0xaa);
 265                WRi(3,k^0x55);
 266                if (RRi(2) != (k^0xaa)) e[j]++;
 267                }
 268            }
 269        epat_disconnect(pi);
 270
 271        f = 0;
 272        epat_connect(pi);
 273        WR(0x13,1); WR(0x13,0); WR(0xa,0x11);
 274        epat_read_block(pi,scratch,512);
 275        
 276        for (k=0;k<256;k++) {
 277            if ((scratch[2*k] & 0xff) != k) f++;
 278            if ((scratch[2*k+1] & 0xff) != (0xff-k)) f++;
 279        }
 280        epat_disconnect(pi);
 281
 282        if (verbose)  {
 283            printk("%s: epat: port 0x%x, mode %d, ccr %x, test=(%d,%d,%d)\n",
 284                   pi->device,pi->port,pi->mode,cc,e[0],e[1],f);
 285        }
 286        
 287        return (e[0] && e[1]) || f;
 288}
 289
 290static void epat_log_adapter( PIA *pi, char * scratch, int verbose )
 291
 292{       int     ver;
 293        char    *mode_string[6] = 
 294                   {"4-bit","5/3","8-bit","EPP-8","EPP-16","EPP-32"};
 295
 296        epat_connect(pi);
 297        WR(0xa,0x38);           /* read the version code */
 298        ver = RR(0xb);
 299        epat_disconnect(pi);
 300
 301        printk("%s: epat %s, Shuttle EPAT chip %x at 0x%x, ",
 302                pi->device,EPAT_VERSION,ver,pi->port);
 303        printk("mode %d (%s), delay %d\n",pi->mode,
 304                mode_string[pi->mode],pi->delay);
 305
 306}
 307
 308static struct pi_protocol epat = {
 309        .owner          = THIS_MODULE,
 310        .name           = "epat",
 311        .max_mode       = 6,
 312        .epp_first      = 3,
 313        .default_delay  = 1,
 314        .max_units      = 1,
 315        .write_regr     = epat_write_regr,
 316        .read_regr      = epat_read_regr,
 317        .write_block    = epat_write_block,
 318        .read_block     = epat_read_block,
 319        .connect        = epat_connect,
 320        .disconnect     = epat_disconnect,
 321        .test_proto     = epat_test_proto,
 322        .log_adapter    = epat_log_adapter,
 323};
 324
 325static int __init epat_init(void)
 326{
 327#ifdef CONFIG_PARIDE_EPATC8
 328        epatc8 = 1;
 329#endif
 330        return paride_register(&epat);
 331}
 332
 333static void __exit epat_exit(void)
 334{
 335        paride_unregister(&epat);
 336}
 337
 338MODULE_LICENSE("GPL");
 339module_init(epat_init)
 340module_exit(epat_exit)
 341