brintos

brintos / linux-shallow public Read only

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