172f2b0b2SOndrej Zary /* 272f2b0b2SOndrej Zary epia.c (c) 1997-8 Grant R. Guenther <grant@torque.net> 372f2b0b2SOndrej Zary Under the terms of the GNU General Public License. 472f2b0b2SOndrej Zary 572f2b0b2SOndrej Zary epia.c is a low-level protocol driver for Shuttle Technologies 672f2b0b2SOndrej Zary EPIA parallel to IDE adapter chip. This device is now obsolete 772f2b0b2SOndrej Zary and has been replaced with the EPAT chip, which is supported 872f2b0b2SOndrej Zary by epat.c, however, some devices based on EPIA are still 972f2b0b2SOndrej Zary available. 1072f2b0b2SOndrej Zary 1172f2b0b2SOndrej Zary */ 1272f2b0b2SOndrej Zary 1372f2b0b2SOndrej Zary /* Changes: 1472f2b0b2SOndrej Zary 1572f2b0b2SOndrej Zary 1.01 GRG 1998.05.06 init_proto, release_proto 1672f2b0b2SOndrej Zary 1.02 GRG 1998.06.17 support older versions of EPIA 1772f2b0b2SOndrej Zary 1872f2b0b2SOndrej Zary */ 1972f2b0b2SOndrej Zary 2072f2b0b2SOndrej Zary #define EPIA_VERSION "1.02" 2172f2b0b2SOndrej Zary 2272f2b0b2SOndrej Zary #include <linux/module.h> 2372f2b0b2SOndrej Zary #include <linux/init.h> 2472f2b0b2SOndrej Zary #include <linux/delay.h> 2572f2b0b2SOndrej Zary #include <linux/kernel.h> 2672f2b0b2SOndrej Zary #include <linux/types.h> 2772f2b0b2SOndrej Zary #include <linux/wait.h> 2872f2b0b2SOndrej Zary #include <asm/io.h> 2972f2b0b2SOndrej Zary 3072f2b0b2SOndrej Zary #include <linux/pata_parport.h> 3172f2b0b2SOndrej Zary 3272f2b0b2SOndrej Zary /* mode codes: 0 nybble reads on port 1, 8-bit writes 3372f2b0b2SOndrej Zary 1 5/3 reads on ports 1 & 2, 8-bit writes 3472f2b0b2SOndrej Zary 2 8-bit reads and writes 3572f2b0b2SOndrej Zary 3 8-bit EPP mode 3672f2b0b2SOndrej Zary 4 16-bit EPP 3772f2b0b2SOndrej Zary 5 32-bit EPP 3872f2b0b2SOndrej Zary */ 3972f2b0b2SOndrej Zary 4072f2b0b2SOndrej Zary #define j44(a,b) (((a>>4)&0x0f)+(b&0xf0)) 4172f2b0b2SOndrej Zary #define j53(a,b) (((a>>3)&0x1f)+((b<<4)&0xe0)) 4272f2b0b2SOndrej Zary 4372f2b0b2SOndrej Zary /* cont = 0 IDE register file 4472f2b0b2SOndrej Zary cont = 1 IDE control registers 4572f2b0b2SOndrej Zary */ 4672f2b0b2SOndrej Zary 4772f2b0b2SOndrej Zary static int cont_map[2] = { 0, 0x80 }; 4872f2b0b2SOndrej Zary 49*882ff0caSOndrej Zary static int epia_read_regr(struct pi_adapter *pi, int cont, int regr) 5072f2b0b2SOndrej Zary 5172f2b0b2SOndrej Zary { int a, b, r; 5272f2b0b2SOndrej Zary 5372f2b0b2SOndrej Zary regr += cont_map[cont]; 5472f2b0b2SOndrej Zary 5572f2b0b2SOndrej Zary switch (pi->mode) { 5672f2b0b2SOndrej Zary 5772f2b0b2SOndrej Zary case 0: r = regr^0x39; 5872f2b0b2SOndrej Zary w0(r); w2(1); w2(3); w0(r); 5972f2b0b2SOndrej Zary a = r1(); w2(1); b = r1(); w2(4); 6072f2b0b2SOndrej Zary return j44(a,b); 6172f2b0b2SOndrej Zary 6272f2b0b2SOndrej Zary case 1: r = regr^0x31; 6372f2b0b2SOndrej Zary w0(r); w2(1); w0(r&0x37); 6472f2b0b2SOndrej Zary w2(3); w2(5); w0(r|0xf0); 6572f2b0b2SOndrej Zary a = r1(); b = r2(); w2(4); 6672f2b0b2SOndrej Zary return j53(a,b); 6772f2b0b2SOndrej Zary 6872f2b0b2SOndrej Zary case 2: r = regr^0x29; 6972f2b0b2SOndrej Zary w0(r); w2(1); w2(0X21); w2(0x23); 7072f2b0b2SOndrej Zary a = r0(); w2(4); 7172f2b0b2SOndrej Zary return a; 7272f2b0b2SOndrej Zary 7372f2b0b2SOndrej Zary case 3: 7472f2b0b2SOndrej Zary case 4: 7572f2b0b2SOndrej Zary case 5: w3(regr); w2(0x24); a = r4(); w2(4); 7672f2b0b2SOndrej Zary return a; 7772f2b0b2SOndrej Zary 7872f2b0b2SOndrej Zary } 7972f2b0b2SOndrej Zary return -1; 8072f2b0b2SOndrej Zary } 8172f2b0b2SOndrej Zary 82*882ff0caSOndrej Zary static void epia_write_regr(struct pi_adapter *pi, int cont, int regr, int val) 8372f2b0b2SOndrej Zary 8472f2b0b2SOndrej Zary { int r; 8572f2b0b2SOndrej Zary 8672f2b0b2SOndrej Zary regr += cont_map[cont]; 8772f2b0b2SOndrej Zary 8872f2b0b2SOndrej Zary switch (pi->mode) { 8972f2b0b2SOndrej Zary 9072f2b0b2SOndrej Zary case 0: 9172f2b0b2SOndrej Zary case 1: 9272f2b0b2SOndrej Zary case 2: r = regr^0x19; 9372f2b0b2SOndrej Zary w0(r); w2(1); w0(val); w2(3); w2(4); 9472f2b0b2SOndrej Zary break; 9572f2b0b2SOndrej Zary 9672f2b0b2SOndrej Zary case 3: 9772f2b0b2SOndrej Zary case 4: 9872f2b0b2SOndrej Zary case 5: r = regr^0x40; 9972f2b0b2SOndrej Zary w3(r); w4(val); w2(4); 10072f2b0b2SOndrej Zary break; 10172f2b0b2SOndrej Zary } 10272f2b0b2SOndrej Zary } 10372f2b0b2SOndrej Zary 10472f2b0b2SOndrej Zary #define WR(r,v) epia_write_regr(pi,0,r,v) 10572f2b0b2SOndrej Zary #define RR(r) (epia_read_regr(pi,0,r)) 10672f2b0b2SOndrej Zary 10772f2b0b2SOndrej Zary /* The use of register 0x84 is entirely unclear - it seems to control 10872f2b0b2SOndrej Zary some EPP counters ... currently we know about 3 different block 10972f2b0b2SOndrej Zary sizes: the standard 512 byte reads and writes, 12 byte writes and 11072f2b0b2SOndrej Zary 2048 byte reads (the last two being used in the CDrom drivers. 11172f2b0b2SOndrej Zary */ 11272f2b0b2SOndrej Zary 113*882ff0caSOndrej Zary static void epia_connect(struct pi_adapter *pi) 11472f2b0b2SOndrej Zary 11572f2b0b2SOndrej Zary { pi->saved_r0 = r0(); 11672f2b0b2SOndrej Zary pi->saved_r2 = r2(); 11772f2b0b2SOndrej Zary 11872f2b0b2SOndrej Zary w2(4); w0(0xa0); w0(0x50); w0(0xc0); w0(0x30); w0(0xa0); w0(0); 11972f2b0b2SOndrej Zary w2(1); w2(4); 12072f2b0b2SOndrej Zary if (pi->mode >= 3) { 12172f2b0b2SOndrej Zary w0(0xa); w2(1); w2(4); w0(0x82); w2(4); w2(0xc); w2(4); 12272f2b0b2SOndrej Zary w2(0x24); w2(0x26); w2(4); 12372f2b0b2SOndrej Zary } 12472f2b0b2SOndrej Zary WR(0x86,8); 12572f2b0b2SOndrej Zary } 12672f2b0b2SOndrej Zary 127*882ff0caSOndrej Zary static void epia_disconnect(struct pi_adapter *pi) 12872f2b0b2SOndrej Zary 12972f2b0b2SOndrej Zary { /* WR(0x84,0x10); */ 13072f2b0b2SOndrej Zary w0(pi->saved_r0); 13172f2b0b2SOndrej Zary w2(1); w2(4); 13272f2b0b2SOndrej Zary w0(pi->saved_r0); 13372f2b0b2SOndrej Zary w2(pi->saved_r2); 13472f2b0b2SOndrej Zary } 13572f2b0b2SOndrej Zary 136*882ff0caSOndrej Zary static void epia_read_block(struct pi_adapter *pi, char *buf, int count) 13772f2b0b2SOndrej Zary 13872f2b0b2SOndrej Zary { int k, ph, a, b; 13972f2b0b2SOndrej Zary 14072f2b0b2SOndrej Zary switch (pi->mode) { 14172f2b0b2SOndrej Zary 14272f2b0b2SOndrej Zary case 0: w0(0x81); w2(1); w2(3); w0(0xc1); 14372f2b0b2SOndrej Zary ph = 1; 14472f2b0b2SOndrej Zary for (k=0;k<count;k++) { 14572f2b0b2SOndrej Zary w2(2+ph); a = r1(); 14672f2b0b2SOndrej Zary w2(4+ph); b = r1(); 14772f2b0b2SOndrej Zary buf[k] = j44(a,b); 14872f2b0b2SOndrej Zary ph = 1 - ph; 14972f2b0b2SOndrej Zary } 15072f2b0b2SOndrej Zary w0(0); w2(4); 15172f2b0b2SOndrej Zary break; 15272f2b0b2SOndrej Zary 15372f2b0b2SOndrej Zary case 1: w0(0x91); w2(1); w0(0x10); w2(3); 15472f2b0b2SOndrej Zary w0(0x51); w2(5); w0(0xd1); 15572f2b0b2SOndrej Zary ph = 1; 15672f2b0b2SOndrej Zary for (k=0;k<count;k++) { 15772f2b0b2SOndrej Zary w2(4+ph); 15872f2b0b2SOndrej Zary a = r1(); b = r2(); 15972f2b0b2SOndrej Zary buf[k] = j53(a,b); 16072f2b0b2SOndrej Zary ph = 1 - ph; 16172f2b0b2SOndrej Zary } 16272f2b0b2SOndrej Zary w0(0); w2(4); 16372f2b0b2SOndrej Zary break; 16472f2b0b2SOndrej Zary 16572f2b0b2SOndrej Zary case 2: w0(0x89); w2(1); w2(0x23); w2(0x21); 16672f2b0b2SOndrej Zary ph = 1; 16772f2b0b2SOndrej Zary for (k=0;k<count;k++) { 16872f2b0b2SOndrej Zary w2(0x24+ph); 16972f2b0b2SOndrej Zary buf[k] = r0(); 17072f2b0b2SOndrej Zary ph = 1 - ph; 17172f2b0b2SOndrej Zary } 17272f2b0b2SOndrej Zary w2(6); w2(4); 17372f2b0b2SOndrej Zary break; 17472f2b0b2SOndrej Zary 17572f2b0b2SOndrej Zary case 3: if (count > 512) WR(0x84,3); 17672f2b0b2SOndrej Zary w3(0); w2(0x24); 17772f2b0b2SOndrej Zary for (k=0;k<count;k++) buf[k] = r4(); 17872f2b0b2SOndrej Zary w2(4); WR(0x84,0); 17972f2b0b2SOndrej Zary break; 18072f2b0b2SOndrej Zary 18172f2b0b2SOndrej Zary case 4: if (count > 512) WR(0x84,3); 18272f2b0b2SOndrej Zary w3(0); w2(0x24); 18372f2b0b2SOndrej Zary for (k=0;k<count/2;k++) ((u16 *)buf)[k] = r4w(); 18472f2b0b2SOndrej Zary w2(4); WR(0x84,0); 18572f2b0b2SOndrej Zary break; 18672f2b0b2SOndrej Zary 18772f2b0b2SOndrej Zary case 5: if (count > 512) WR(0x84,3); 18872f2b0b2SOndrej Zary w3(0); w2(0x24); 18972f2b0b2SOndrej Zary for (k=0;k<count/4;k++) ((u32 *)buf)[k] = r4l(); 19072f2b0b2SOndrej Zary w2(4); WR(0x84,0); 19172f2b0b2SOndrej Zary break; 19272f2b0b2SOndrej Zary 19372f2b0b2SOndrej Zary } 19472f2b0b2SOndrej Zary } 19572f2b0b2SOndrej Zary 196*882ff0caSOndrej Zary static void epia_write_block(struct pi_adapter *pi, char *buf, int count) 19772f2b0b2SOndrej Zary 19872f2b0b2SOndrej Zary { int ph, k, last, d; 19972f2b0b2SOndrej Zary 20072f2b0b2SOndrej Zary switch (pi->mode) { 20172f2b0b2SOndrej Zary 20272f2b0b2SOndrej Zary case 0: 20372f2b0b2SOndrej Zary case 1: 20472f2b0b2SOndrej Zary case 2: w0(0xa1); w2(1); w2(3); w2(1); w2(5); 20572f2b0b2SOndrej Zary ph = 0; last = 0x8000; 20672f2b0b2SOndrej Zary for (k=0;k<count;k++) { 20772f2b0b2SOndrej Zary d = buf[k]; 20872f2b0b2SOndrej Zary if (d != last) { last = d; w0(d); } 20972f2b0b2SOndrej Zary w2(4+ph); 21072f2b0b2SOndrej Zary ph = 1 - ph; 21172f2b0b2SOndrej Zary } 21272f2b0b2SOndrej Zary w2(7); w2(4); 21372f2b0b2SOndrej Zary break; 21472f2b0b2SOndrej Zary 21572f2b0b2SOndrej Zary case 3: if (count < 512) WR(0x84,1); 21672f2b0b2SOndrej Zary w3(0x40); 21772f2b0b2SOndrej Zary for (k=0;k<count;k++) w4(buf[k]); 21872f2b0b2SOndrej Zary if (count < 512) WR(0x84,0); 21972f2b0b2SOndrej Zary break; 22072f2b0b2SOndrej Zary 22172f2b0b2SOndrej Zary case 4: if (count < 512) WR(0x84,1); 22272f2b0b2SOndrej Zary w3(0x40); 22372f2b0b2SOndrej Zary for (k=0;k<count/2;k++) w4w(((u16 *)buf)[k]); 22472f2b0b2SOndrej Zary if (count < 512) WR(0x84,0); 22572f2b0b2SOndrej Zary break; 22672f2b0b2SOndrej Zary 22772f2b0b2SOndrej Zary case 5: if (count < 512) WR(0x84,1); 22872f2b0b2SOndrej Zary w3(0x40); 22972f2b0b2SOndrej Zary for (k=0;k<count/4;k++) w4l(((u32 *)buf)[k]); 23072f2b0b2SOndrej Zary if (count < 512) WR(0x84,0); 23172f2b0b2SOndrej Zary break; 23272f2b0b2SOndrej Zary 23372f2b0b2SOndrej Zary } 23472f2b0b2SOndrej Zary 23572f2b0b2SOndrej Zary } 23672f2b0b2SOndrej Zary 237*882ff0caSOndrej Zary static int epia_test_proto(struct pi_adapter *pi, char *scratch, int verbose) 23872f2b0b2SOndrej Zary 23972f2b0b2SOndrej Zary { int j, k, f; 24072f2b0b2SOndrej Zary int e[2] = {0,0}; 24172f2b0b2SOndrej Zary 24272f2b0b2SOndrej Zary epia_connect(pi); 24372f2b0b2SOndrej Zary for (j=0;j<2;j++) { 24472f2b0b2SOndrej Zary WR(6,0xa0+j*0x10); 24572f2b0b2SOndrej Zary for (k=0;k<256;k++) { 24672f2b0b2SOndrej Zary WR(2,k^0xaa); 24772f2b0b2SOndrej Zary WR(3,k^0x55); 24872f2b0b2SOndrej Zary if (RR(2) != (k^0xaa)) e[j]++; 24972f2b0b2SOndrej Zary } 25072f2b0b2SOndrej Zary WR(2,1); WR(3,1); 25172f2b0b2SOndrej Zary } 25272f2b0b2SOndrej Zary epia_disconnect(pi); 25372f2b0b2SOndrej Zary 25472f2b0b2SOndrej Zary f = 0; 25572f2b0b2SOndrej Zary epia_connect(pi); 25672f2b0b2SOndrej Zary WR(0x84,8); 25772f2b0b2SOndrej Zary epia_read_block(pi,scratch,512); 25872f2b0b2SOndrej Zary for (k=0;k<256;k++) { 25972f2b0b2SOndrej Zary if ((scratch[2*k] & 0xff) != ((k+1) & 0xff)) f++; 26072f2b0b2SOndrej Zary if ((scratch[2*k+1] & 0xff) != ((-2-k) & 0xff)) f++; 26172f2b0b2SOndrej Zary } 26272f2b0b2SOndrej Zary WR(0x84,0); 26372f2b0b2SOndrej Zary epia_disconnect(pi); 26472f2b0b2SOndrej Zary 26572f2b0b2SOndrej Zary if (verbose) { 266a4f2ff92SOndrej Zary printk("epia: port 0x%x, mode %d, test=(%d,%d,%d)\n", 267a4f2ff92SOndrej Zary pi->port, pi->mode, e[0], e[1], f); 26872f2b0b2SOndrej Zary } 26972f2b0b2SOndrej Zary 27072f2b0b2SOndrej Zary return (e[0] && e[1]) || f; 27172f2b0b2SOndrej Zary 27272f2b0b2SOndrej Zary } 27372f2b0b2SOndrej Zary 27472f2b0b2SOndrej Zary 275*882ff0caSOndrej Zary static void epia_log_adapter(struct pi_adapter *pi, char *scratch, int verbose) 27672f2b0b2SOndrej Zary 27772f2b0b2SOndrej Zary { char *mode_string[6] = {"4-bit","5/3","8-bit", 27872f2b0b2SOndrej Zary "EPP-8","EPP-16","EPP-32"}; 27972f2b0b2SOndrej Zary 280a4f2ff92SOndrej Zary printk("epia %s, Shuttle EPIA at 0x%x, ", EPIA_VERSION, pi->port); 28172f2b0b2SOndrej Zary printk("mode %d (%s), delay %d\n",pi->mode, 28272f2b0b2SOndrej Zary mode_string[pi->mode],pi->delay); 28372f2b0b2SOndrej Zary 28472f2b0b2SOndrej Zary } 28572f2b0b2SOndrej Zary 28672f2b0b2SOndrej Zary static struct pi_protocol epia = { 28772f2b0b2SOndrej Zary .owner = THIS_MODULE, 28872f2b0b2SOndrej Zary .name = "epia", 28972f2b0b2SOndrej Zary .max_mode = 6, 29072f2b0b2SOndrej Zary .epp_first = 3, 29172f2b0b2SOndrej Zary .default_delay = 1, 29272f2b0b2SOndrej Zary .max_units = 1, 29372f2b0b2SOndrej Zary .write_regr = epia_write_regr, 29472f2b0b2SOndrej Zary .read_regr = epia_read_regr, 29572f2b0b2SOndrej Zary .write_block = epia_write_block, 29672f2b0b2SOndrej Zary .read_block = epia_read_block, 29772f2b0b2SOndrej Zary .connect = epia_connect, 29872f2b0b2SOndrej Zary .disconnect = epia_disconnect, 29972f2b0b2SOndrej Zary .test_proto = epia_test_proto, 30072f2b0b2SOndrej Zary .log_adapter = epia_log_adapter, 30172f2b0b2SOndrej Zary }; 30272f2b0b2SOndrej Zary 30372f2b0b2SOndrej Zary MODULE_LICENSE("GPL"); 3042c08ec0fSOndrej Zary module_pata_parport_driver(epia); 305