162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * (c) 1996-1998 Grant R. Guenther <grant@torque.net> 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * bpck.c is a low-level protocol driver for the MicroSolutions 662306a36Sopenharmony_ci * "backpack" parallel port IDE adapter. 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/module.h> 1062306a36Sopenharmony_ci#include <linux/init.h> 1162306a36Sopenharmony_ci#include <linux/delay.h> 1262306a36Sopenharmony_ci#include <linux/kernel.h> 1362306a36Sopenharmony_ci#include <linux/types.h> 1462306a36Sopenharmony_ci#include <linux/wait.h> 1562306a36Sopenharmony_ci#include <asm/io.h> 1662306a36Sopenharmony_ci#include "pata_parport.h" 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#undef r2 1962306a36Sopenharmony_ci#undef w2 2062306a36Sopenharmony_ci#undef PC 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#define PC pi->private 2362306a36Sopenharmony_ci#define r2() (PC=(in_p(2) & 0xff)) 2462306a36Sopenharmony_ci#define w2(byte) {out_p(2,byte); PC = byte;} 2562306a36Sopenharmony_ci#define t2(pat) {PC ^= pat; out_p(2,PC);} 2662306a36Sopenharmony_ci#define e2() {PC &= 0xfe; out_p(2,PC);} 2762306a36Sopenharmony_ci#define o2() {PC |= 1; out_p(2,PC);} 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#define j44(l,h) (((l>>3)&0x7)|((l>>4)&0x8)|((h<<1)&0x70)|(h&0x80)) 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci/* 3262306a36Sopenharmony_ci * cont = 0 - access the IDE register file 3362306a36Sopenharmony_ci * cont = 1 - access the IDE command set 3462306a36Sopenharmony_ci * cont = 2 - use internal bpck register addressing 3562306a36Sopenharmony_ci */ 3662306a36Sopenharmony_cistatic int cont_map[3] = { 0x40, 0x48, 0 }; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cistatic int bpck_read_regr(struct pi_adapter *pi, int cont, int regr) 3962306a36Sopenharmony_ci{ 4062306a36Sopenharmony_ci int r, l, h; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci r = regr + cont_map[cont]; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci switch (pi->mode) { 4562306a36Sopenharmony_ci case 0: 4662306a36Sopenharmony_ci w0(r & 0xf); w0(r); t2(2); t2(4); 4762306a36Sopenharmony_ci l = r1(); 4862306a36Sopenharmony_ci t2(4); 4962306a36Sopenharmony_ci h = r1(); 5062306a36Sopenharmony_ci return j44(l, h); 5162306a36Sopenharmony_ci case 1: 5262306a36Sopenharmony_ci w0(r & 0xf); w0(r); t2(2); 5362306a36Sopenharmony_ci e2(); t2(0x20); 5462306a36Sopenharmony_ci t2(4); h = r0(); 5562306a36Sopenharmony_ci t2(1); t2(0x20); 5662306a36Sopenharmony_ci return h; 5762306a36Sopenharmony_ci case 2: 5862306a36Sopenharmony_ci case 3: 5962306a36Sopenharmony_ci case 4: 6062306a36Sopenharmony_ci w0(r); w2(9); w2(0); w2(0x20); 6162306a36Sopenharmony_ci h = r4(); 6262306a36Sopenharmony_ci w2(0); 6362306a36Sopenharmony_ci return h; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci } 6662306a36Sopenharmony_ci return -1; 6762306a36Sopenharmony_ci} 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cistatic void bpck_write_regr(struct pi_adapter *pi, int cont, int regr, int val) 7062306a36Sopenharmony_ci{ 7162306a36Sopenharmony_ci int r; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci r = regr + cont_map[cont]; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci switch (pi->mode) { 7662306a36Sopenharmony_ci case 0: 7762306a36Sopenharmony_ci case 1: w0(r); 7862306a36Sopenharmony_ci t2(2); 7962306a36Sopenharmony_ci w0(val); 8062306a36Sopenharmony_ci o2(); t2(4); t2(1); 8162306a36Sopenharmony_ci break; 8262306a36Sopenharmony_ci case 2: 8362306a36Sopenharmony_ci case 3: 8462306a36Sopenharmony_ci case 4: w0(r); w2(9); w2(0); 8562306a36Sopenharmony_ci w0(val); w2(1); w2(3); w2(0); 8662306a36Sopenharmony_ci break; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci } 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci/* These macros access the bpck registers in native addressing */ 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci#define WR(r,v) bpck_write_regr(pi,2,r,v) 9462306a36Sopenharmony_ci#define RR(r) (bpck_read_regr(pi,2,r)) 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_cistatic void bpck_write_block(struct pi_adapter *pi, char *buf, int count) 9762306a36Sopenharmony_ci{ 9862306a36Sopenharmony_ci int i; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci switch (pi->mode) { 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci case 0: 10362306a36Sopenharmony_ci WR(4, 0x40); 10462306a36Sopenharmony_ci w0(0x40); t2(2); t2(1); 10562306a36Sopenharmony_ci for (i = 0; i < count; i++) { 10662306a36Sopenharmony_ci w0(buf[i]); 10762306a36Sopenharmony_ci t2(4); 10862306a36Sopenharmony_ci } 10962306a36Sopenharmony_ci WR(4, 0); 11062306a36Sopenharmony_ci break; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci case 1: 11362306a36Sopenharmony_ci WR(4, 0x50); 11462306a36Sopenharmony_ci w0(0x40); t2(2); t2(1); 11562306a36Sopenharmony_ci for (i = 0; i < count; i++) { 11662306a36Sopenharmony_ci w0(buf[i]); 11762306a36Sopenharmony_ci t2(4); 11862306a36Sopenharmony_ci } 11962306a36Sopenharmony_ci WR(4, 0x10); 12062306a36Sopenharmony_ci break; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci case 2: 12362306a36Sopenharmony_ci WR(4, 0x48); 12462306a36Sopenharmony_ci w0(0x40); w2(9); w2(0); w2(1); 12562306a36Sopenharmony_ci for (i = 0; i < count; i++) 12662306a36Sopenharmony_ci w4(buf[i]); 12762306a36Sopenharmony_ci w2(0); 12862306a36Sopenharmony_ci WR(4, 8); 12962306a36Sopenharmony_ci break; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci case 3: 13262306a36Sopenharmony_ci WR(4, 0x48); 13362306a36Sopenharmony_ci w0(0x40); w2(9); w2(0); w2(1); 13462306a36Sopenharmony_ci for (i = 0; i < count / 2; i++) 13562306a36Sopenharmony_ci w4w(((u16 *)buf)[i]); 13662306a36Sopenharmony_ci w2(0); 13762306a36Sopenharmony_ci WR(4, 8); 13862306a36Sopenharmony_ci break; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci case 4: 14162306a36Sopenharmony_ci WR(4, 0x48); 14262306a36Sopenharmony_ci w0(0x40); w2(9); w2(0); w2(1); 14362306a36Sopenharmony_ci for (i = 0; i < count / 4; i++) 14462306a36Sopenharmony_ci w4l(((u32 *)buf)[i]); 14562306a36Sopenharmony_ci w2(0); 14662306a36Sopenharmony_ci WR(4, 8); 14762306a36Sopenharmony_ci break; 14862306a36Sopenharmony_ci } 14962306a36Sopenharmony_ci} 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_cistatic void bpck_read_block(struct pi_adapter *pi, char *buf, int count) 15262306a36Sopenharmony_ci{ 15362306a36Sopenharmony_ci int i, l, h; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci switch (pi->mode) { 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci case 0: 15862306a36Sopenharmony_ci WR(4, 0x40); 15962306a36Sopenharmony_ci w0(0x40); t2(2); 16062306a36Sopenharmony_ci for (i = 0; i < count; i++) { 16162306a36Sopenharmony_ci t2(4); l = r1(); 16262306a36Sopenharmony_ci t2(4); h = r1(); 16362306a36Sopenharmony_ci buf[i] = j44(l, h); 16462306a36Sopenharmony_ci } 16562306a36Sopenharmony_ci WR(4, 0); 16662306a36Sopenharmony_ci break; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci case 1: 16962306a36Sopenharmony_ci WR(4, 0x50); 17062306a36Sopenharmony_ci w0(0x40); t2(2); t2(0x20); 17162306a36Sopenharmony_ci for (i = 0; i < count; i++) { 17262306a36Sopenharmony_ci t2(4); 17362306a36Sopenharmony_ci buf[i] = r0(); 17462306a36Sopenharmony_ci } 17562306a36Sopenharmony_ci t2(1); t2(0x20); 17662306a36Sopenharmony_ci WR(4, 0x10); 17762306a36Sopenharmony_ci break; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci case 2: 18062306a36Sopenharmony_ci WR(4, 0x48); 18162306a36Sopenharmony_ci w0(0x40); w2(9); w2(0); w2(0x20); 18262306a36Sopenharmony_ci for (i = 0; i < count; i++) 18362306a36Sopenharmony_ci buf[i] = r4(); 18462306a36Sopenharmony_ci w2(0); 18562306a36Sopenharmony_ci WR(4, 8); 18662306a36Sopenharmony_ci break; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci case 3: 18962306a36Sopenharmony_ci WR(4, 0x48); 19062306a36Sopenharmony_ci w0(0x40); w2(9); w2(0); w2(0x20); 19162306a36Sopenharmony_ci for (i = 0; i < count / 2; i++) 19262306a36Sopenharmony_ci ((u16 *)buf)[i] = r4w(); 19362306a36Sopenharmony_ci w2(0); 19462306a36Sopenharmony_ci WR(4, 8); 19562306a36Sopenharmony_ci break; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci case 4: 19862306a36Sopenharmony_ci WR(4, 0x48); 19962306a36Sopenharmony_ci w0(0x40); w2(9); w2(0); w2(0x20); 20062306a36Sopenharmony_ci for (i = 0; i < count / 4; i++) 20162306a36Sopenharmony_ci ((u32 *)buf)[i] = r4l(); 20262306a36Sopenharmony_ci w2(0); 20362306a36Sopenharmony_ci WR(4, 8); 20462306a36Sopenharmony_ci break; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci } 20762306a36Sopenharmony_ci} 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_cistatic int bpck_probe_unit(struct pi_adapter *pi) 21062306a36Sopenharmony_ci{ 21162306a36Sopenharmony_ci int o1, o0, f7, id; 21262306a36Sopenharmony_ci int t, s; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci id = pi->unit; 21562306a36Sopenharmony_ci s = 0; 21662306a36Sopenharmony_ci w2(4); w2(0xe); r2(); t2(2); 21762306a36Sopenharmony_ci o1 = r1()&0xf8; 21862306a36Sopenharmony_ci o0 = r0(); 21962306a36Sopenharmony_ci w0(255-id); w2(4); w0(id); 22062306a36Sopenharmony_ci t2(8); t2(8); t2(8); 22162306a36Sopenharmony_ci t2(2); t = r1()&0xf8; 22262306a36Sopenharmony_ci f7 = ((id % 8) == 7); 22362306a36Sopenharmony_ci if ((f7) || (t != o1)) { 22462306a36Sopenharmony_ci t2(2); 22562306a36Sopenharmony_ci s = r1() & 0xf8; 22662306a36Sopenharmony_ci } 22762306a36Sopenharmony_ci if ((t == o1) && ((!f7) || (s == o1))) { 22862306a36Sopenharmony_ci w2(0x4c); w0(o0); 22962306a36Sopenharmony_ci return 0; 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci t2(8); w0(0); t2(2); w2(0x4c); w0(o0); 23262306a36Sopenharmony_ci return 1; 23362306a36Sopenharmony_ci} 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_cistatic void bpck_connect(struct pi_adapter *pi) 23662306a36Sopenharmony_ci{ 23762306a36Sopenharmony_ci pi->saved_r0 = r0(); 23862306a36Sopenharmony_ci w0(0xff-pi->unit); w2(4); w0(pi->unit); 23962306a36Sopenharmony_ci t2(8); t2(8); t2(8); 24062306a36Sopenharmony_ci t2(2); t2(2); 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci switch (pi->mode) { 24362306a36Sopenharmony_ci case 0: 24462306a36Sopenharmony_ci t2(8); WR(4, 0); 24562306a36Sopenharmony_ci break; 24662306a36Sopenharmony_ci case 1: 24762306a36Sopenharmony_ci t2(8); WR(4, 0x10); 24862306a36Sopenharmony_ci break; 24962306a36Sopenharmony_ci case 2: 25062306a36Sopenharmony_ci case 3: 25162306a36Sopenharmony_ci case 4: 25262306a36Sopenharmony_ci w2(0); WR(4, 8); 25362306a36Sopenharmony_ci break; 25462306a36Sopenharmony_ci } 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci WR(5,8); 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci /* 25962306a36Sopenharmony_ci * Possibly wrong, purpose unknown (fiddle with ESS logic ???) 26062306a36Sopenharmony_ci * if (pi->devtype == PI_PCD) { 26162306a36Sopenharmony_ci */ 26262306a36Sopenharmony_ci WR(0x46, 0x10); 26362306a36Sopenharmony_ci WR(0x4c, 0x38); 26462306a36Sopenharmony_ci WR(0x4d, 0x88); 26562306a36Sopenharmony_ci WR(0x46, 0xa0); 26662306a36Sopenharmony_ci WR(0x41, 0); 26762306a36Sopenharmony_ci WR(0x4e, 8); 26862306a36Sopenharmony_ci /* } */ 26962306a36Sopenharmony_ci} 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_cistatic void bpck_disconnect(struct pi_adapter *pi) 27262306a36Sopenharmony_ci{ 27362306a36Sopenharmony_ci w0(0); 27462306a36Sopenharmony_ci if (pi->mode >= 2) { 27562306a36Sopenharmony_ci w2(9); w2(0); 27662306a36Sopenharmony_ci } else { 27762306a36Sopenharmony_ci t2(2); 27862306a36Sopenharmony_ci } 27962306a36Sopenharmony_ci w2(0x4c); w0(pi->saved_r0); 28062306a36Sopenharmony_ci} 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_cistatic void bpck_force_spp(struct pi_adapter *pi) 28362306a36Sopenharmony_ci{ 28462306a36Sopenharmony_ci /* This fakes the EPP protocol to turn off EPP ... */ 28562306a36Sopenharmony_ci pi->saved_r0 = r0(); 28662306a36Sopenharmony_ci w0(0xff-pi->unit); w2(4); w0(pi->unit); 28762306a36Sopenharmony_ci t2(8); t2(8); t2(8); 28862306a36Sopenharmony_ci t2(2); t2(2); 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci w2(0); 29162306a36Sopenharmony_ci w0(4); w2(9); w2(0); 29262306a36Sopenharmony_ci w0(0); w2(1); w2(3); w2(0); 29362306a36Sopenharmony_ci w0(0); w2(9); w2(0); 29462306a36Sopenharmony_ci w2(0x4c); w0(pi->saved_r0); 29562306a36Sopenharmony_ci} 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci#define TEST_LEN 16 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_cistatic int bpck_test_proto(struct pi_adapter *pi) 30062306a36Sopenharmony_ci{ 30162306a36Sopenharmony_ci int i, e, l, h, om; 30262306a36Sopenharmony_ci char buf[TEST_LEN]; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci bpck_force_spp(pi); 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci switch (pi->mode) { 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci case 0: 30962306a36Sopenharmony_ci bpck_connect(pi); 31062306a36Sopenharmony_ci WR(0x13, 0x7f); 31162306a36Sopenharmony_ci w0(0x13); t2(2); 31262306a36Sopenharmony_ci for (i = 0; i < TEST_LEN; i++) { 31362306a36Sopenharmony_ci t2(4); l = r1(); 31462306a36Sopenharmony_ci t2(4); h = r1(); 31562306a36Sopenharmony_ci buf[i] = j44(l, h); 31662306a36Sopenharmony_ci } 31762306a36Sopenharmony_ci bpck_disconnect(pi); 31862306a36Sopenharmony_ci break; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci case 1: 32162306a36Sopenharmony_ci bpck_connect(pi); 32262306a36Sopenharmony_ci WR(0x13, 0x7f); 32362306a36Sopenharmony_ci w0(0x13); t2(2); t2(0x20); 32462306a36Sopenharmony_ci for (i = 0; i < TEST_LEN; i++) { 32562306a36Sopenharmony_ci t2(4); 32662306a36Sopenharmony_ci buf[i] = r0(); 32762306a36Sopenharmony_ci } 32862306a36Sopenharmony_ci t2(1); t2(0x20); 32962306a36Sopenharmony_ci bpck_disconnect(pi); 33062306a36Sopenharmony_ci break; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci case 2: 33362306a36Sopenharmony_ci case 3: 33462306a36Sopenharmony_ci case 4: 33562306a36Sopenharmony_ci om = pi->mode; 33662306a36Sopenharmony_ci pi->mode = 0; 33762306a36Sopenharmony_ci bpck_connect(pi); 33862306a36Sopenharmony_ci WR(7, 3); 33962306a36Sopenharmony_ci WR(4, 8); 34062306a36Sopenharmony_ci bpck_disconnect(pi); 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci pi->mode = om; 34362306a36Sopenharmony_ci bpck_connect(pi); 34462306a36Sopenharmony_ci w0(0x13); w2(9); w2(1); w0(0); w2(3); w2(0); w2(0xe0); 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci switch (pi->mode) { 34762306a36Sopenharmony_ci case 2: 34862306a36Sopenharmony_ci for (i = 0; i < TEST_LEN; i++) 34962306a36Sopenharmony_ci buf[i] = r4(); 35062306a36Sopenharmony_ci break; 35162306a36Sopenharmony_ci case 3: 35262306a36Sopenharmony_ci for (i = 0; i < TEST_LEN / 2; i++) 35362306a36Sopenharmony_ci ((u16 *)buf)[i] = r4w(); 35462306a36Sopenharmony_ci break; 35562306a36Sopenharmony_ci case 4: 35662306a36Sopenharmony_ci for (i = 0; i < TEST_LEN / 4; i++) 35762306a36Sopenharmony_ci ((u32 *)buf)[i] = r4l(); 35862306a36Sopenharmony_ci break; 35962306a36Sopenharmony_ci } 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci w2(0); 36262306a36Sopenharmony_ci WR(7, 0); 36362306a36Sopenharmony_ci bpck_disconnect(pi); 36462306a36Sopenharmony_ci break; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci } 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci dev_dbg(&pi->dev, "bpck: 0x%x unit %d mode %d: ", 36962306a36Sopenharmony_ci pi->port, pi->unit, pi->mode); 37062306a36Sopenharmony_ci print_hex_dump_debug("bpck: ", DUMP_PREFIX_NONE, TEST_LEN, 1, buf, 37162306a36Sopenharmony_ci TEST_LEN, false); 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci e = 0; 37462306a36Sopenharmony_ci for (i = 0; i < TEST_LEN; i++) { 37562306a36Sopenharmony_ci if (buf[i] != i + 1) 37662306a36Sopenharmony_ci e++; 37762306a36Sopenharmony_ci } 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci return e; 38062306a36Sopenharmony_ci} 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_cistatic void bpck_read_eeprom(struct pi_adapter *pi, char *buf) 38362306a36Sopenharmony_ci{ 38462306a36Sopenharmony_ci int i, j, k, p, v, f, om, od; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci bpck_force_spp(pi); 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci om = pi->mode; od = pi->delay; 38962306a36Sopenharmony_ci pi->mode = 0; pi->delay = 6; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci bpck_connect(pi); 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci WR(4, 0); 39462306a36Sopenharmony_ci for (i = 0; i < 64; i++) { 39562306a36Sopenharmony_ci WR(6, 8); 39662306a36Sopenharmony_ci WR(6, 0xc); 39762306a36Sopenharmony_ci p = 0x100; 39862306a36Sopenharmony_ci for (k = 0; k < 9; k++) { 39962306a36Sopenharmony_ci f = (((i + 0x180) & p) != 0) * 2; 40062306a36Sopenharmony_ci WR(6, f + 0xc); 40162306a36Sopenharmony_ci WR(6, f + 0xd); 40262306a36Sopenharmony_ci WR(6, f + 0xc); 40362306a36Sopenharmony_ci p = (p >> 1); 40462306a36Sopenharmony_ci } 40562306a36Sopenharmony_ci for (j = 0; j < 2; j++) { 40662306a36Sopenharmony_ci v = 0; 40762306a36Sopenharmony_ci for (k = 0; k < 8; k++) { 40862306a36Sopenharmony_ci WR(6, 0xc); 40962306a36Sopenharmony_ci WR(6, 0xd); 41062306a36Sopenharmony_ci WR(6, 0xc); 41162306a36Sopenharmony_ci f = RR(0); 41262306a36Sopenharmony_ci v = 2 * v + (f == 0x84); 41362306a36Sopenharmony_ci } 41462306a36Sopenharmony_ci buf[2 * i + 1 - j] = v; 41562306a36Sopenharmony_ci } 41662306a36Sopenharmony_ci } 41762306a36Sopenharmony_ci WR(6, 8); 41862306a36Sopenharmony_ci WR(6, 0); 41962306a36Sopenharmony_ci WR(5, 8); 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci bpck_disconnect(pi); 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci if (om >= 2) { 42462306a36Sopenharmony_ci bpck_connect(pi); 42562306a36Sopenharmony_ci WR(7, 3); 42662306a36Sopenharmony_ci WR(4, 8); 42762306a36Sopenharmony_ci bpck_disconnect(pi); 42862306a36Sopenharmony_ci } 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci pi->mode = om; pi->delay = od; 43162306a36Sopenharmony_ci} 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_cistatic int bpck_test_port(struct pi_adapter *pi) 43462306a36Sopenharmony_ci{ 43562306a36Sopenharmony_ci int i, r, m; 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci /* Check for 8-bit port */ 43862306a36Sopenharmony_ci w2(0x2c); i = r0(); w0(255-i); r = r0(); w0(i); 43962306a36Sopenharmony_ci m = -1; 44062306a36Sopenharmony_ci if (r == i) 44162306a36Sopenharmony_ci m = 2; 44262306a36Sopenharmony_ci if (r == (255-i)) 44362306a36Sopenharmony_ci m = 0; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci w2(0xc); 44662306a36Sopenharmony_ci i = r0(); 44762306a36Sopenharmony_ci w0(255-i); 44862306a36Sopenharmony_ci r = r0(); 44962306a36Sopenharmony_ci w0(i); 45062306a36Sopenharmony_ci if (r != (255-i)) 45162306a36Sopenharmony_ci m = -1; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci if (m == 0) { 45462306a36Sopenharmony_ci w2(6); 45562306a36Sopenharmony_ci w2(0xc); 45662306a36Sopenharmony_ci r = r0(); 45762306a36Sopenharmony_ci w0(0xaa); 45862306a36Sopenharmony_ci w0(r); 45962306a36Sopenharmony_ci w0(0xaa); 46062306a36Sopenharmony_ci } 46162306a36Sopenharmony_ci if (m == 2) { 46262306a36Sopenharmony_ci w2(0x26); 46362306a36Sopenharmony_ci w2(0xc); 46462306a36Sopenharmony_ci } 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci if (m == -1) 46762306a36Sopenharmony_ci return 0; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci return 5; 47062306a36Sopenharmony_ci} 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_cistatic void bpck_log_adapter(struct pi_adapter *pi) 47362306a36Sopenharmony_ci{ 47462306a36Sopenharmony_ci char *mode_str[5] = { "4-bit", "8-bit", "EPP-8", "EPP-16", "EPP-32" }; 47562306a36Sopenharmony_ci char scratch[128]; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci bpck_read_eeprom(pi,scratch); 47862306a36Sopenharmony_ci print_hex_dump_bytes("bpck EEPROM: ", DUMP_PREFIX_NONE, scratch, 128); 47962306a36Sopenharmony_ci dev_info(&pi->dev, 48062306a36Sopenharmony_ci "backpack %8.8s unit %d at 0x%x, mode %d (%s), delay %d\n", 48162306a36Sopenharmony_ci &scratch[110], pi->unit, pi->port, pi->mode, 48262306a36Sopenharmony_ci mode_str[pi->mode], pi->delay); 48362306a36Sopenharmony_ci} 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_cistatic struct pi_protocol bpck = { 48662306a36Sopenharmony_ci .owner = THIS_MODULE, 48762306a36Sopenharmony_ci .name = "bpck", 48862306a36Sopenharmony_ci .max_mode = 5, 48962306a36Sopenharmony_ci .epp_first = 2, 49062306a36Sopenharmony_ci .default_delay = 4, 49162306a36Sopenharmony_ci .max_units = 255, 49262306a36Sopenharmony_ci .write_regr = bpck_write_regr, 49362306a36Sopenharmony_ci .read_regr = bpck_read_regr, 49462306a36Sopenharmony_ci .write_block = bpck_write_block, 49562306a36Sopenharmony_ci .read_block = bpck_read_block, 49662306a36Sopenharmony_ci .connect = bpck_connect, 49762306a36Sopenharmony_ci .disconnect = bpck_disconnect, 49862306a36Sopenharmony_ci .test_port = bpck_test_port, 49962306a36Sopenharmony_ci .probe_unit = bpck_probe_unit, 50062306a36Sopenharmony_ci .test_proto = bpck_test_proto, 50162306a36Sopenharmony_ci .log_adapter = bpck_log_adapter, 50262306a36Sopenharmony_ci}; 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 50562306a36Sopenharmony_ciMODULE_AUTHOR("Grant R. Guenther <grant@torque.net>"); 50662306a36Sopenharmony_ciMODULE_DESCRIPTION("MicroSolutions BACKPACK parallel port IDE adapter protocol driver"); 50762306a36Sopenharmony_cimodule_pata_parport_driver(bpck); 508