Linux Audio

Check our new training course

Loading...
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 * (c) 2001 Micro Solutions Inc.
  4 *
  5 * backpack.c is a low-level protocol driver for the Micro Solutions
  6 * "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		0x00
 21#define ACCESS_PORT		0x40
 22
 23#define ACCESS_READ		0x00
 24#define ACCESS_WRITE		0x20
 25
 26/* 60772 Command Prefix */
 27#define CMD_PREFIX_SET		0xe0	// Special command that modifies next command's operation
 28#define CMD_PREFIX_RESET	0xc0	// Resets current cmd modifier reg bits
 29 #define PREFIX_IO16		0x01	// perform 16-bit wide I/O
 30 #define PREFIX_FASTWR		0x04	// enable PPC mode fast-write
 31 #define PREFIX_BLK		0x08	// enable block transfer mode
 32
 33/* 60772 Registers */
 34#define REG_STATUS		0x00	// status register
 35 #define STATUS_IRQA		0x01	// Peripheral IRQA line
 36 #define STATUS_EEPROM_DO	0x40	// Serial EEPROM data bit
 37#define REG_VERSION		0x01	// PPC version register (read)
 38#define REG_HWCFG		0x02	// Hardware Config register
 39#define REG_RAMSIZE		0x03	// Size of RAM Buffer
 40 #define RAMSIZE_128K		0x02
 41#define REG_EEPROM		0x06	// EEPROM control register
 42 #define EEPROM_SK		0x01	// eeprom SK bit
 43 #define EEPROM_DI		0x02	// eeprom DI bit
 44 #define EEPROM_CS		0x04	// eeprom CS bit
 45 #define EEPROM_EN		0x08	// eeprom output enable
 46#define REG_BLKSIZE		0x08	// Block transfer len (24 bit)
 47
 48/* flags */
 49#define fifo_wait		0x10
 50
 51/* DONT CHANGE THESE LEST YOU BREAK EVERYTHING - BIT FIELD DEPENDENCIES */
 52#define PPCMODE_UNI_SW		0
 53#define PPCMODE_UNI_FW		1
 54#define PPCMODE_BI_SW		2
 55#define PPCMODE_BI_FW		3
 56#define PPCMODE_EPP_BYTE	4
 57#define PPCMODE_EPP_WORD	5
 58#define PPCMODE_EPP_DWORD	6
 59
 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);
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 * (c) 2001 Micro Solutions Inc.
  4 *
  5 * backpack.c is a low-level protocol driver for the Micro Solutions
  6 * "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		0x00
 21#define ACCESS_PORT		0x40
 22
 23#define ACCESS_READ		0x00
 24#define ACCESS_WRITE		0x20
 25
 26/* 60772 Command Prefix */
 27#define CMD_PREFIX_SET		0xe0	// Special command that modifies next command's operation
 28#define CMD_PREFIX_RESET	0xc0	// Resets current cmd modifier reg bits
 29 #define PREFIX_IO16		0x01	// perform 16-bit wide I/O
 30 #define PREFIX_FASTWR		0x04	// enable PPC mode fast-write
 31 #define PREFIX_BLK		0x08	// enable block transfer mode
 32
 33/* 60772 Registers */
 34#define REG_STATUS		0x00	// status register
 35 #define STATUS_IRQA		0x01	// Peripheral IRQA line
 36 #define STATUS_EEPROM_DO	0x40	// Serial EEPROM data bit
 37#define REG_VERSION		0x01	// PPC version register (read)
 38#define REG_HWCFG		0x02	// Hardware Config register
 39#define REG_RAMSIZE		0x03	// Size of RAM Buffer
 40 #define RAMSIZE_128K		0x02
 41#define REG_EEPROM		0x06	// EEPROM control register
 42 #define EEPROM_SK		0x01	// eeprom SK bit
 43 #define EEPROM_DI		0x02	// eeprom DI bit
 44 #define EEPROM_CS		0x04	// eeprom CS bit
 45 #define EEPROM_EN		0x08	// eeprom output enable
 46#define REG_BLKSIZE		0x08	// Block transfer len (24 bit)
 47
 48/* flags */
 49#define fifo_wait		0x10
 50
 51/* DONT CHANGE THESE LEST YOU BREAK EVERYTHING - BIT FIELD DEPENDENCIES */
 52#define PPCMODE_UNI_SW		0
 53#define PPCMODE_UNI_FW		1
 54#define PPCMODE_BI_SW		2
 55#define PPCMODE_BI_FW		3
 56#define PPCMODE_EPP_BYTE	4
 57#define PPCMODE_EPP_WORD	5
 58#define PPCMODE_EPP_DWORD	6
 59
 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);