brintos

brintos / linux-shallow public Read only

0
0
Text · 12.6 KiB · 62c2b53 Raw
465 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * (c) 2001 Micro Solutions Inc.4 *5 * backpack.c is a low-level protocol driver for the Micro Solutions6 * "BACKPACK" parallel port IDE adapter (works on Series 6 drives).7 *8 * Written by: Ken Hahn (linux-dev@micro-solutions.com)9 *             Clive Turvey (linux-dev@micro-solutions.com)10 */11 12#include <linux/module.h>13#include <linux/init.h>14#include <linux/kernel.h>15#include <linux/types.h>16#include <linux/parport.h>17#include "pata_parport.h"18 19/* 60772 Commands */20#define ACCESS_REG		0x0021#define ACCESS_PORT		0x4022 23#define ACCESS_READ		0x0024#define ACCESS_WRITE		0x2025 26/* 60772 Command Prefix */27#define CMD_PREFIX_SET		0xe0	// Special command that modifies next command's operation28#define CMD_PREFIX_RESET	0xc0	// Resets current cmd modifier reg bits29 #define PREFIX_IO16		0x01	// perform 16-bit wide I/O30 #define PREFIX_FASTWR		0x04	// enable PPC mode fast-write31 #define PREFIX_BLK		0x08	// enable block transfer mode32 33/* 60772 Registers */34#define REG_STATUS		0x00	// status register35 #define STATUS_IRQA		0x01	// Peripheral IRQA line36 #define STATUS_EEPROM_DO	0x40	// Serial EEPROM data bit37#define REG_VERSION		0x01	// PPC version register (read)38#define REG_HWCFG		0x02	// Hardware Config register39#define REG_RAMSIZE		0x03	// Size of RAM Buffer40 #define RAMSIZE_128K		0x0241#define REG_EEPROM		0x06	// EEPROM control register42 #define EEPROM_SK		0x01	// eeprom SK bit43 #define EEPROM_DI		0x02	// eeprom DI bit44 #define EEPROM_CS		0x04	// eeprom CS bit45 #define EEPROM_EN		0x08	// eeprom output enable46#define REG_BLKSIZE		0x08	// Block transfer len (24 bit)47 48/* flags */49#define fifo_wait		0x1050 51/* DONT CHANGE THESE LEST YOU BREAK EVERYTHING - BIT FIELD DEPENDENCIES */52#define PPCMODE_UNI_SW		053#define PPCMODE_UNI_FW		154#define PPCMODE_BI_SW		255#define PPCMODE_BI_FW		356#define PPCMODE_EPP_BYTE	457#define PPCMODE_EPP_WORD	558#define PPCMODE_EPP_DWORD	659 60static int mode_map[] = { PPCMODE_UNI_FW, PPCMODE_BI_FW, PPCMODE_EPP_BYTE,61			  PPCMODE_EPP_WORD, PPCMODE_EPP_DWORD };62 63static void bpck6_send_cmd(struct pi_adapter *pi, u8 cmd)64{65	switch (mode_map[pi->mode]) {66	case PPCMODE_UNI_SW:67	case PPCMODE_UNI_FW:68	case PPCMODE_BI_SW:69	case PPCMODE_BI_FW:70		parport_write_data(pi->pardev->port, cmd);71		parport_frob_control(pi->pardev->port, 0, PARPORT_CONTROL_AUTOFD);72		break;73	case PPCMODE_EPP_BYTE:74	case PPCMODE_EPP_WORD:75	case PPCMODE_EPP_DWORD:76		pi->pardev->port->ops->epp_write_addr(pi->pardev->port, &cmd, 1, 0);77		break;78	}79}80 81static u8 bpck6_rd_data_byte(struct pi_adapter *pi)82{83	u8 data = 0;84 85	switch (mode_map[pi->mode]) {86	case PPCMODE_UNI_SW:87	case PPCMODE_UNI_FW:88		parport_frob_control(pi->pardev->port, PARPORT_CONTROL_STROBE,89							PARPORT_CONTROL_INIT);90		data = parport_read_status(pi->pardev->port);91		data = ((data & 0x80) >> 1) | ((data & 0x38) >> 3);92		parport_frob_control(pi->pardev->port, PARPORT_CONTROL_STROBE,93							PARPORT_CONTROL_STROBE);94		data |= parport_read_status(pi->pardev->port) & 0xB8;95		break;96	case PPCMODE_BI_SW:97	case PPCMODE_BI_FW:98		parport_data_reverse(pi->pardev->port);99		parport_frob_control(pi->pardev->port, PARPORT_CONTROL_STROBE,100				PARPORT_CONTROL_STROBE | PARPORT_CONTROL_INIT);101		data = parport_read_data(pi->pardev->port);102		parport_frob_control(pi->pardev->port, PARPORT_CONTROL_STROBE, 0);103		parport_data_forward(pi->pardev->port);104		break;105	case PPCMODE_EPP_BYTE:106	case PPCMODE_EPP_WORD:107	case PPCMODE_EPP_DWORD:108		pi->pardev->port->ops->epp_read_data(pi->pardev->port, &data, 1, 0);109		break;110	}111 112	return data;113}114 115static void bpck6_wr_data_byte(struct pi_adapter *pi, u8 data)116{117	switch (mode_map[pi->mode]) {118	case PPCMODE_UNI_SW:119	case PPCMODE_UNI_FW:120	case PPCMODE_BI_SW:121	case PPCMODE_BI_FW:122		parport_write_data(pi->pardev->port, data);123		parport_frob_control(pi->pardev->port, 0, PARPORT_CONTROL_INIT);124		break;125	case PPCMODE_EPP_BYTE:126	case PPCMODE_EPP_WORD:127	case PPCMODE_EPP_DWORD:128		pi->pardev->port->ops->epp_write_data(pi->pardev->port, &data, 1, 0);129		break;130	}131}132 133static int bpck6_read_regr(struct pi_adapter *pi, int cont, int reg)134{135	u8 port = cont ? reg | 8 : reg;136 137	bpck6_send_cmd(pi, port | ACCESS_PORT | ACCESS_READ);138	return bpck6_rd_data_byte(pi);139}140 141static void bpck6_write_regr(struct pi_adapter *pi, int cont, int reg, int val)142{143	u8 port = cont ? reg | 8 : reg;144 145	bpck6_send_cmd(pi, port | ACCESS_PORT | ACCESS_WRITE);146	bpck6_wr_data_byte(pi, val);147}148 149static void bpck6_wait_for_fifo(struct pi_adapter *pi)150{151	int i;152 153	if (pi->private & fifo_wait) {154		for (i = 0; i < 20; i++)155			parport_read_status(pi->pardev->port);156	}157}158 159static void bpck6_write_block(struct pi_adapter *pi, char *buf, int len)160{161	u8 this, last;162 163	bpck6_send_cmd(pi, REG_BLKSIZE | ACCESS_REG | ACCESS_WRITE);164	bpck6_wr_data_byte(pi, (u8)len);165	bpck6_wr_data_byte(pi, (u8)(len >> 8));166	bpck6_wr_data_byte(pi, 0);167 168	bpck6_send_cmd(pi, CMD_PREFIX_SET | PREFIX_IO16 | PREFIX_BLK);169	bpck6_send_cmd(pi, ATA_REG_DATA | ACCESS_PORT | ACCESS_WRITE);170 171	switch (mode_map[pi->mode]) {172	case PPCMODE_UNI_SW:173	case PPCMODE_BI_SW:174		while (len--) {175			parport_write_data(pi->pardev->port, *buf++);176			parport_frob_control(pi->pardev->port, 0,177							PARPORT_CONTROL_INIT);178		}179		break;180	case PPCMODE_UNI_FW:181	case PPCMODE_BI_FW:182		bpck6_send_cmd(pi, CMD_PREFIX_SET | PREFIX_FASTWR);183 184		parport_frob_control(pi->pardev->port, PARPORT_CONTROL_STROBE,185							PARPORT_CONTROL_STROBE);186 187		last = *buf;188 189		parport_write_data(pi->pardev->port, last);190 191		while (len) {192			this = *buf++;193			len--;194 195			if (this == last) {196				parport_frob_control(pi->pardev->port, 0,197							PARPORT_CONTROL_INIT);198			} else {199				parport_write_data(pi->pardev->port, this);200				last = this;201			}202		}203 204		parport_frob_control(pi->pardev->port, PARPORT_CONTROL_STROBE,205							0);206		bpck6_send_cmd(pi, CMD_PREFIX_RESET | PREFIX_FASTWR);207		break;208	case PPCMODE_EPP_BYTE:209		pi->pardev->port->ops->epp_write_data(pi->pardev->port, buf,210						len, PARPORT_EPP_FAST_8);211		bpck6_wait_for_fifo(pi);212		break;213	case PPCMODE_EPP_WORD:214		pi->pardev->port->ops->epp_write_data(pi->pardev->port, buf,215						len, PARPORT_EPP_FAST_16);216		bpck6_wait_for_fifo(pi);217		break;218	case PPCMODE_EPP_DWORD:219		pi->pardev->port->ops->epp_write_data(pi->pardev->port, buf,220						len, PARPORT_EPP_FAST_32);221		bpck6_wait_for_fifo(pi);222		break;223	}224 225	bpck6_send_cmd(pi, CMD_PREFIX_RESET | PREFIX_IO16 | PREFIX_BLK);226}227 228static void bpck6_read_block(struct pi_adapter *pi, char *buf, int len)229{230	bpck6_send_cmd(pi, REG_BLKSIZE | ACCESS_REG | ACCESS_WRITE);231	bpck6_wr_data_byte(pi, (u8)len);232	bpck6_wr_data_byte(pi, (u8)(len >> 8));233	bpck6_wr_data_byte(pi, 0);234 235	bpck6_send_cmd(pi, CMD_PREFIX_SET | PREFIX_IO16 | PREFIX_BLK);236	bpck6_send_cmd(pi, ATA_REG_DATA | ACCESS_PORT | ACCESS_READ);237 238	switch (mode_map[pi->mode]) {239	case PPCMODE_UNI_SW:240	case PPCMODE_UNI_FW:241		while (len) {242			u8 d;243 244			parport_frob_control(pi->pardev->port,245					PARPORT_CONTROL_STROBE,246					PARPORT_CONTROL_INIT); /* DATA STROBE */247			d = parport_read_status(pi->pardev->port);248			d = ((d & 0x80) >> 1) | ((d & 0x38) >> 3);249			parport_frob_control(pi->pardev->port,250					PARPORT_CONTROL_STROBE,251					PARPORT_CONTROL_STROBE);252			d |= parport_read_status(pi->pardev->port) & 0xB8;253			*buf++ = d;254			len--;255		}256		break;257	case PPCMODE_BI_SW:258	case PPCMODE_BI_FW:259		parport_data_reverse(pi->pardev->port);260		while (len) {261			parport_frob_control(pi->pardev->port,262				PARPORT_CONTROL_STROBE,263				PARPORT_CONTROL_STROBE | PARPORT_CONTROL_INIT);264			*buf++ = parport_read_data(pi->pardev->port);265			len--;266		}267		parport_frob_control(pi->pardev->port, PARPORT_CONTROL_STROBE,268					0);269		parport_data_forward(pi->pardev->port);270		break;271	case PPCMODE_EPP_BYTE:272		pi->pardev->port->ops->epp_read_data(pi->pardev->port, buf, len,273						PARPORT_EPP_FAST_8);274		break;275	case PPCMODE_EPP_WORD:276		pi->pardev->port->ops->epp_read_data(pi->pardev->port, buf, len,277						PARPORT_EPP_FAST_16);278		break;279	case PPCMODE_EPP_DWORD:280		pi->pardev->port->ops->epp_read_data(pi->pardev->port, buf, len,281						PARPORT_EPP_FAST_32);282		break;283	}284 285	bpck6_send_cmd(pi, CMD_PREFIX_RESET | PREFIX_IO16 | PREFIX_BLK);286}287 288static int bpck6_open(struct pi_adapter *pi)289{290	u8 i, j, k;291 292	pi->saved_r0 = parport_read_data(pi->pardev->port);293	pi->saved_r2 = parport_read_control(pi->pardev->port) & 0x5F;294 295	parport_frob_control(pi->pardev->port, PARPORT_CONTROL_SELECT,296						PARPORT_CONTROL_SELECT);297	if (pi->saved_r0 == 'b')298		parport_write_data(pi->pardev->port, 'x');299	parport_write_data(pi->pardev->port, 'b');300	parport_write_data(pi->pardev->port, 'p');301	parport_write_data(pi->pardev->port, pi->unit);302	parport_write_data(pi->pardev->port, ~pi->unit);303 304	parport_frob_control(pi->pardev->port, PARPORT_CONTROL_SELECT, 0);305	parport_write_control(pi->pardev->port, PARPORT_CONTROL_INIT);306 307	i = mode_map[pi->mode] & 0x0C;308	if (i == 0)309		i = (mode_map[pi->mode] & 2) | 1;310	parport_write_data(pi->pardev->port, i);311 312	parport_frob_control(pi->pardev->port, PARPORT_CONTROL_SELECT,313						PARPORT_CONTROL_SELECT);314	parport_frob_control(pi->pardev->port, PARPORT_CONTROL_AUTOFD,315						PARPORT_CONTROL_AUTOFD);316 317	j = ((i & 0x08) << 4) | ((i & 0x07) << 3);318	k = parport_read_status(pi->pardev->port) & 0xB8;319	if (j != k)320		goto fail;321 322	parport_frob_control(pi->pardev->port, PARPORT_CONTROL_AUTOFD, 0);323	k = (parport_read_status(pi->pardev->port) & 0xB8) ^ 0xB8;324	if (j != k)325		goto fail;326 327	if (i & 4) {328		/* EPP */329		parport_frob_control(pi->pardev->port,330			PARPORT_CONTROL_SELECT | PARPORT_CONTROL_INIT, 0);331	} else {332		/* PPC/ECP */333		parport_frob_control(pi->pardev->port, PARPORT_CONTROL_SELECT, 0);334	}335 336	pi->private = 0;337 338	bpck6_send_cmd(pi, ACCESS_REG | ACCESS_WRITE | REG_RAMSIZE);339	bpck6_wr_data_byte(pi, RAMSIZE_128K);340 341	bpck6_send_cmd(pi, ACCESS_REG | ACCESS_READ | REG_VERSION);342	if ((bpck6_rd_data_byte(pi) & 0x3F) == 0x0C)343		pi->private |= fifo_wait;344 345	return 1;346 347fail:348	parport_write_control(pi->pardev->port, pi->saved_r2);349	parport_write_data(pi->pardev->port, pi->saved_r0);350 351	return 0;352}353 354static void bpck6_deselect(struct pi_adapter *pi)355{356	if (mode_map[pi->mode] & 4) {357		/* EPP */358		parport_frob_control(pi->pardev->port, PARPORT_CONTROL_INIT,359				     PARPORT_CONTROL_INIT);360	} else {361		/* PPC/ECP */362		parport_frob_control(pi->pardev->port, PARPORT_CONTROL_SELECT,363				     PARPORT_CONTROL_SELECT);364	}365 366	parport_write_data(pi->pardev->port, pi->saved_r0);367	parport_write_control(pi->pardev->port,368			pi->saved_r2 | PARPORT_CONTROL_SELECT);369	parport_write_control(pi->pardev->port, pi->saved_r2);370}371 372static void bpck6_wr_extout(struct pi_adapter *pi, u8 regdata)373{374	bpck6_send_cmd(pi, REG_VERSION | ACCESS_REG | ACCESS_WRITE);375	bpck6_wr_data_byte(pi, (u8)((regdata & 0x03) << 6));376}377 378static void bpck6_connect(struct pi_adapter *pi)379{380	dev_dbg(&pi->dev, "connect\n");381 382	bpck6_open(pi);383	bpck6_wr_extout(pi, 0x3);384}385 386static void bpck6_disconnect(struct pi_adapter *pi)387{388	dev_dbg(&pi->dev, "disconnect\n");389	bpck6_wr_extout(pi, 0x0);390	bpck6_deselect(pi);391}392 393/* check for 8-bit port */394static int bpck6_test_port(struct pi_adapter *pi)395{396	dev_dbg(&pi->dev, "PARPORT indicates modes=%x for lp=0x%lx\n",397		pi->pardev->port->modes, pi->pardev->port->base);398 399	/* look at the parport device to see what modes we can use */400	if (pi->pardev->port->modes & PARPORT_MODE_EPP)401		return 5; /* Can do EPP */402	if (pi->pardev->port->modes & PARPORT_MODE_TRISTATE)403		return 2;404	return 1; /* Just flat SPP */405}406 407static int bpck6_probe_unit(struct pi_adapter *pi)408{409	int out, saved_mode;410 411	dev_dbg(&pi->dev, "PROBE UNIT %x on port:%x\n", pi->unit, pi->port);412 413	saved_mode = pi->mode;414	/*LOWER DOWN TO UNIDIRECTIONAL*/415	pi->mode = 0;416 417	out = bpck6_open(pi);418 419	dev_dbg(&pi->dev, "ppc_open returned %2x\n", out);420 421	if (out) {422		bpck6_deselect(pi);423		dev_dbg(&pi->dev, "leaving probe\n");424		pi->mode = saved_mode;425		return 1;426	}427 428	dev_dbg(&pi->dev, "Failed open\n");429	pi->mode = saved_mode;430 431	return 0;432}433 434static void bpck6_log_adapter(struct pi_adapter *pi)435{436	char *mode_string[5] = { "4-bit", "8-bit", "EPP-8", "EPP-16", "EPP-32" };437 438	dev_info(&pi->dev,439		 "Micro Solutions BACKPACK Drive unit %d at 0x%x, mode:%d (%s), delay %d\n",440		 pi->unit, pi->port, pi->mode, mode_string[pi->mode], pi->delay);441}442 443static struct pi_protocol bpck6 = {444	.owner		= THIS_MODULE,445	.name		= "bpck6",446	.max_mode	= 5,447	.epp_first	= 2, /* 2-5 use epp (need 8 ports) */448	.max_units	= 255,449	.write_regr	= bpck6_write_regr,450	.read_regr	= bpck6_read_regr,451	.write_block	= bpck6_write_block,452	.read_block	= bpck6_read_block,453	.connect	= bpck6_connect,454	.disconnect	= bpck6_disconnect,455	.test_port	= bpck6_test_port,456	.probe_unit	= bpck6_probe_unit,457	.log_adapter	= bpck6_log_adapter,458};459 460MODULE_LICENSE("GPL");461MODULE_AUTHOR("Micro Solutions Inc.");462MODULE_DESCRIPTION("Micro Solutions BACKPACK parallel port IDE adapter "463		   "(version 6 drives) protocol driver");464module_pata_parport_driver(bpck6);465