brintos

brintos / linux-shallow public Read only

0
0
Text · 5.5 KiB · 7abe2ff Raw
265 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * (c) 1998    Grant R. Guenther <grant@torque.net>4 *5 * friq.c is a low-level protocol driver for the Freecom "IQ"6 * parallel port IDE adapter.   Early versions of this adapter7 * use the 'frpw' protocol.8 *9 * Freecom uses this adapter in a battery powered external10 * CD-ROM drive.  It is also used in LS-120 drives by11 * Maxell and Panasonic, and other devices.12 *13 * The battery powered drive requires software support to14 * control the power to the drive.  This module enables the15 * drive power when the high level driver (pcd) is loaded16 * and disables it when the module is unloaded.  Note, if17 * the friq module is built in to the kernel, the power18 * will never be switched off, so other means should be19 * used to conserve battery power.20 */21 22#include <linux/module.h>23#include <linux/init.h>24#include <linux/delay.h>25#include <linux/kernel.h>26#include <linux/types.h>27#include <linux/wait.h>28#include <asm/io.h>29#include "pata_parport.h"30 31#define CMD(x)							\32	do {							\33		w2(4); w0(0xff); w0(0xff); w0(0x73); w0(0x73);	\34		w0(0xc9); w0(0xc9); w0(0x26);			\35		w0(0x26); w0(x); w0(x);				\36	} while (0)37 38#define j44(l, h)	(((l >> 4) & 0x0f) | (h & 0xf0))39 40/*41 * cont = 0 - access the IDE register file42 * cont = 1 - access the IDE command set43 */44static int cont_map[2] = { 0x08, 0x10 };45 46static int friq_read_regr(struct pi_adapter *pi, int cont, int regr)47{48	int h, l, r;49 50	r = regr + cont_map[cont];51 52	CMD(r);53	w2(6); l = r1();54	w2(4); h = r1();55	w2(4);56 57	return j44(l, h);58}59 60static void friq_write_regr(struct pi_adapter *pi, int cont, int regr, int val)61{62	int r = regr + cont_map[cont];63 64	CMD(r);65	w0(val);66	w2(5); w2(7); w2(5); w2(4);67}68 69static void friq_read_block_int(struct pi_adapter *pi, char *buf, int count, int regr)70{71	int h, l, k, ph;72 73	switch (pi->mode) {74	case 0:75		CMD(regr);76		for (k = 0; k < count; k++) {77			w2(6); l = r1();78			w2(4); h = r1();79			buf[k] = j44(l, h);80		}81		w2(4);82		break;83	case 1:84		ph = 2;85		CMD(regr + 0xc0);86		w0(0xff);87		for (k = 0; k < count; k++) {88			w2(0xa4 + ph);89			buf[k] = r0();90			ph = 2 - ph;91		}92		w2(0xac); w2(0xa4); w2(4);93		break;94	case 2:95		CMD(regr + 0x80);96		for (k = 0; k < count - 2; k++)97			buf[k] = r4();98		w2(0xac); w2(0xa4);99		buf[count - 2] = r4();100		buf[count - 1] = r4();101		w2(4);102		break;103	case 3:104		CMD(regr + 0x80);105		for (k = 0; k < count / 2 - 1; k++)106			((u16 *)buf)[k] = r4w();107		w2(0xac); w2(0xa4);108		buf[count - 2] = r4();109		buf[count - 1] = r4();110		w2(4);111		break;112	case 4:113		CMD(regr + 0x80);114		for (k = 0; k < count / 4 - 1; k++)115			((u32 *)buf)[k] = r4l();116		buf[count - 4] = r4();117		buf[count - 3] = r4();118		w2(0xac); w2(0xa4);119		buf[count - 2] = r4();120		buf[count - 1] = r4();121		w2(4);122		break;123	}124}125 126static void friq_read_block(struct pi_adapter *pi, char *buf, int count)127{128	friq_read_block_int(pi, buf, count, 0x08);129}130 131static void friq_write_block(struct pi_adapter *pi, char *buf, int count)132{133	int k;134 135	switch (pi->mode) {136	case 0:137	case 1:138		CMD(8); w2(5);139		for (k = 0; k < count; k++) {140			w0(buf[k]);141			w2(7); w2(5);142		}143		w2(4);144		break;145	case 2:146		CMD(0xc8); w2(5);147		for (k = 0; k < count; k++)148			w4(buf[k]);149		w2(4);150		break;151	case 3:152		CMD(0xc8); w2(5);153		for (k = 0; k < count / 2; k++)154			w4w(((u16 *)buf)[k]);155		w2(4);156		break;157	case 4:158		CMD(0xc8); w2(5);159		for (k = 0; k < count / 4; k++)160			w4l(((u32 *)buf)[k]);161		w2(4);162		break;163}164}165 166static void friq_connect(struct pi_adapter *pi)167{168	pi->saved_r0 = r0();169	pi->saved_r2 = r2();170	w2(4);171}172 173static void friq_disconnect(struct pi_adapter *pi)174{175	CMD(0x20);176	w0(pi->saved_r0);177	w2(pi->saved_r2);178}179 180static int friq_test_proto(struct pi_adapter *pi)181{182	int j, k, r;183	int e[2] = { 0, 0 };184	char scratch[512];185 186	pi->saved_r0 = r0();187	w0(0xff); udelay(20); CMD(0x3d); /* turn the power on */188	udelay(500);189	w0(pi->saved_r0);190 191	friq_connect(pi);192	for (j = 0; j < 2; j++) {193		friq_write_regr(pi, 0, 6, 0xa0 + j * 0x10);194		for (k = 0; k < 256; k++) {195			friq_write_regr(pi, 0, 2, k ^ 0xaa);196			friq_write_regr(pi, 0, 3, k ^ 0x55);197			if (friq_read_regr(pi, 0, 2) != (k ^ 0xaa))198				e[j]++;199		}200	}201	friq_disconnect(pi);202 203	friq_connect(pi);204	friq_read_block_int(pi, scratch, 512, 0x10);205	r = 0;206	for (k = 0; k < 128; k++) {207		if (scratch[k] != k)208			r++;209	}210	friq_disconnect(pi);211 212	dev_dbg(&pi->dev,213		"friq: port 0x%x, mode %d, test=(%d,%d,%d)\n",214		pi->port, pi->mode, e[0], e[1], r);215 216	return r || (e[0] && e[1]);217}218 219static void friq_log_adapter(struct pi_adapter *pi)220{221	char *mode_string[6] = { "4-bit", "8-bit", "EPP-8", "EPP-16", "EPP-32"};222 223	dev_info(&pi->dev,224		 "Freecom IQ ASIC-2 adapter at 0x%x, mode %d (%s), delay %d\n",225		 pi->port, pi->mode, mode_string[pi->mode], pi->delay);226 227	pi->private = 1;228	friq_connect(pi);229	CMD(0x9e);  		/* disable sleep timer */230	friq_disconnect(pi);231}232 233static void friq_release_proto(struct pi_adapter *pi)234{235	if (pi->private) {		/* turn off the power */236		friq_connect(pi);237		CMD(0x1d); CMD(0x1e);238		friq_disconnect(pi);239		pi->private = 0;240	}241}242 243static struct pi_protocol friq = {244	.owner		= THIS_MODULE,245	.name		= "friq",246	.max_mode	= 5,247	.epp_first	= 2,248	.default_delay	= 1,249	.max_units	= 1,250	.write_regr	= friq_write_regr,251	.read_regr	= friq_read_regr,252	.write_block	= friq_write_block,253	.read_block	= friq_read_block,254	.connect	= friq_connect,255	.disconnect	= friq_disconnect,256	.test_proto	= friq_test_proto,257	.log_adapter	= friq_log_adapter,258	.release_proto	= friq_release_proto,259};260 261MODULE_LICENSE("GPL");262MODULE_AUTHOR("Grant R. Guenther <grant@torque.net>");263MODULE_DESCRIPTION("Freecom IQ parallel port IDE adapter protocol driver");264module_pata_parport_driver(friq);265