18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci fit3.c (c) 1998 Grant R. Guenther <grant@torque.net> 38c2ecf20Sopenharmony_ci Under the terms of the GNU General Public License. 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci fit3.c is a low-level protocol driver for newer models 68c2ecf20Sopenharmony_ci of the Fidelity International Technology parallel port adapter. 78c2ecf20Sopenharmony_ci This adapter is used in their TransDisk 3000 portable 88c2ecf20Sopenharmony_ci hard-drives, as well as CD-ROM, PD-CD and other devices. 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci The TD-2000 and certain older devices use a different protocol. 118c2ecf20Sopenharmony_ci Try the fit2 protocol module with them. 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci NB: The FIT adapters do not appear to support the control 148c2ecf20Sopenharmony_ci registers. So, we map ALT_STATUS to STATUS and NO-OP writes 158c2ecf20Sopenharmony_ci to the device control register - this means that IDE reset 168c2ecf20Sopenharmony_ci will not work on these devices. 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci*/ 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#define FIT3_VERSION "1.0" 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include <linux/module.h> 238c2ecf20Sopenharmony_ci#include <linux/init.h> 248c2ecf20Sopenharmony_ci#include <linux/delay.h> 258c2ecf20Sopenharmony_ci#include <linux/kernel.h> 268c2ecf20Sopenharmony_ci#include <linux/types.h> 278c2ecf20Sopenharmony_ci#include <linux/wait.h> 288c2ecf20Sopenharmony_ci#include <asm/io.h> 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#include "paride.h" 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#define j44(a,b) (((a>>3)&0x0f)|((b<<1)&0xf0)) 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#define w7(byte) {out_p(7,byte);} 358c2ecf20Sopenharmony_ci#define r7() (in_p(7) & 0xff) 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci/* cont = 0 - access the IDE register file 388c2ecf20Sopenharmony_ci cont = 1 - access the IDE command set 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci*/ 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistatic void fit3_write_regr( PIA *pi, int cont, int regr, int val) 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci{ if (cont == 1) return; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci switch (pi->mode) { 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci case 0: 498c2ecf20Sopenharmony_ci case 1: w2(0xc); w0(regr); w2(0x8); w2(0xc); 508c2ecf20Sopenharmony_ci w0(val); w2(0xd); 518c2ecf20Sopenharmony_ci w0(0); w2(0xc); 528c2ecf20Sopenharmony_ci break; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci case 2: w2(0xc); w0(regr); w2(0x8); w2(0xc); 558c2ecf20Sopenharmony_ci w4(val); w4(0); 568c2ecf20Sopenharmony_ci w2(0xc); 578c2ecf20Sopenharmony_ci break; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci } 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic int fit3_read_regr( PIA *pi, int cont, int regr ) 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci{ int a, b; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci if (cont) { 678c2ecf20Sopenharmony_ci if (regr != 6) return 0xff; 688c2ecf20Sopenharmony_ci regr = 7; 698c2ecf20Sopenharmony_ci } 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci switch (pi->mode) { 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci case 0: w2(0xc); w0(regr + 0x10); w2(0x8); w2(0xc); 748c2ecf20Sopenharmony_ci w2(0xd); a = r1(); 758c2ecf20Sopenharmony_ci w2(0xf); b = r1(); 768c2ecf20Sopenharmony_ci w2(0xc); 778c2ecf20Sopenharmony_ci return j44(a,b); 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci case 1: w2(0xc); w0(regr + 0x90); w2(0x8); w2(0xc); 808c2ecf20Sopenharmony_ci w2(0xec); w2(0xee); w2(0xef); a = r0(); 818c2ecf20Sopenharmony_ci w2(0xc); 828c2ecf20Sopenharmony_ci return a; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci case 2: w2(0xc); w0(regr + 0x90); w2(0x8); w2(0xc); 858c2ecf20Sopenharmony_ci w2(0xec); 868c2ecf20Sopenharmony_ci a = r4(); b = r4(); 878c2ecf20Sopenharmony_ci w2(0xc); 888c2ecf20Sopenharmony_ci return a; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci } 918c2ecf20Sopenharmony_ci return -1; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistatic void fit3_read_block( PIA *pi, char * buf, int count ) 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci{ int k, a, b, c, d; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci switch (pi->mode) { 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci case 0: w2(0xc); w0(0x10); w2(0x8); w2(0xc); 1028c2ecf20Sopenharmony_ci for (k=0;k<count/2;k++) { 1038c2ecf20Sopenharmony_ci w2(0xd); a = r1(); 1048c2ecf20Sopenharmony_ci w2(0xf); b = r1(); 1058c2ecf20Sopenharmony_ci w2(0xc); c = r1(); 1068c2ecf20Sopenharmony_ci w2(0xe); d = r1(); 1078c2ecf20Sopenharmony_ci buf[2*k ] = j44(a,b); 1088c2ecf20Sopenharmony_ci buf[2*k+1] = j44(c,d); 1098c2ecf20Sopenharmony_ci } 1108c2ecf20Sopenharmony_ci w2(0xc); 1118c2ecf20Sopenharmony_ci break; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci case 1: w2(0xc); w0(0x90); w2(0x8); w2(0xc); 1148c2ecf20Sopenharmony_ci w2(0xec); w2(0xee); 1158c2ecf20Sopenharmony_ci for (k=0;k<count/2;k++) { 1168c2ecf20Sopenharmony_ci w2(0xef); a = r0(); 1178c2ecf20Sopenharmony_ci w2(0xee); b = r0(); 1188c2ecf20Sopenharmony_ci buf[2*k ] = a; 1198c2ecf20Sopenharmony_ci buf[2*k+1] = b; 1208c2ecf20Sopenharmony_ci } 1218c2ecf20Sopenharmony_ci w2(0xec); 1228c2ecf20Sopenharmony_ci w2(0xc); 1238c2ecf20Sopenharmony_ci break; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci case 2: w2(0xc); w0(0x90); w2(0x8); w2(0xc); 1268c2ecf20Sopenharmony_ci w2(0xec); 1278c2ecf20Sopenharmony_ci for (k=0;k<count;k++) buf[k] = r4(); 1288c2ecf20Sopenharmony_ci w2(0xc); 1298c2ecf20Sopenharmony_ci break; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci } 1328c2ecf20Sopenharmony_ci} 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cistatic void fit3_write_block( PIA *pi, char * buf, int count ) 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci{ int k; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci switch (pi->mode) { 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci case 0: 1418c2ecf20Sopenharmony_ci case 1: w2(0xc); w0(0); w2(0x8); w2(0xc); 1428c2ecf20Sopenharmony_ci for (k=0;k<count/2;k++) { 1438c2ecf20Sopenharmony_ci w0(buf[2*k ]); w2(0xd); 1448c2ecf20Sopenharmony_ci w0(buf[2*k+1]); w2(0xc); 1458c2ecf20Sopenharmony_ci } 1468c2ecf20Sopenharmony_ci break; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci case 2: w2(0xc); w0(0); w2(0x8); w2(0xc); 1498c2ecf20Sopenharmony_ci for (k=0;k<count;k++) w4(buf[k]); 1508c2ecf20Sopenharmony_ci w2(0xc); 1518c2ecf20Sopenharmony_ci break; 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic void fit3_connect ( PIA *pi ) 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci{ pi->saved_r0 = r0(); 1588c2ecf20Sopenharmony_ci pi->saved_r2 = r2(); 1598c2ecf20Sopenharmony_ci w2(0xc); w0(0); w2(0xa); 1608c2ecf20Sopenharmony_ci if (pi->mode == 2) { 1618c2ecf20Sopenharmony_ci w2(0xc); w0(0x9); w2(0x8); w2(0xc); 1628c2ecf20Sopenharmony_ci } 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistatic void fit3_disconnect ( PIA *pi ) 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci{ w2(0xc); w0(0xa); w2(0x8); w2(0xc); 1688c2ecf20Sopenharmony_ci w0(pi->saved_r0); 1698c2ecf20Sopenharmony_ci w2(pi->saved_r2); 1708c2ecf20Sopenharmony_ci} 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_cistatic void fit3_log_adapter( PIA *pi, char * scratch, int verbose ) 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci{ char *mode_string[3] = {"4-bit","8-bit","EPP"}; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci printk("%s: fit3 %s, FIT 3000 adapter at 0x%x, " 1778c2ecf20Sopenharmony_ci "mode %d (%s), delay %d\n", 1788c2ecf20Sopenharmony_ci pi->device,FIT3_VERSION,pi->port, 1798c2ecf20Sopenharmony_ci pi->mode,mode_string[pi->mode],pi->delay); 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci} 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_cistatic struct pi_protocol fit3 = { 1848c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 1858c2ecf20Sopenharmony_ci .name = "fit3", 1868c2ecf20Sopenharmony_ci .max_mode = 3, 1878c2ecf20Sopenharmony_ci .epp_first = 2, 1888c2ecf20Sopenharmony_ci .default_delay = 1, 1898c2ecf20Sopenharmony_ci .max_units = 1, 1908c2ecf20Sopenharmony_ci .write_regr = fit3_write_regr, 1918c2ecf20Sopenharmony_ci .read_regr = fit3_read_regr, 1928c2ecf20Sopenharmony_ci .write_block = fit3_write_block, 1938c2ecf20Sopenharmony_ci .read_block = fit3_read_block, 1948c2ecf20Sopenharmony_ci .connect = fit3_connect, 1958c2ecf20Sopenharmony_ci .disconnect = fit3_disconnect, 1968c2ecf20Sopenharmony_ci .log_adapter = fit3_log_adapter, 1978c2ecf20Sopenharmony_ci}; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_cistatic int __init fit3_init(void) 2008c2ecf20Sopenharmony_ci{ 2018c2ecf20Sopenharmony_ci return paride_register(&fit3); 2028c2ecf20Sopenharmony_ci} 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_cistatic void __exit fit3_exit(void) 2058c2ecf20Sopenharmony_ci{ 2068c2ecf20Sopenharmony_ci paride_unregister(&fit3); 2078c2ecf20Sopenharmony_ci} 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 2108c2ecf20Sopenharmony_cimodule_init(fit3_init) 2118c2ecf20Sopenharmony_cimodule_exit(fit3_exit) 212