2005-04-16 22:20:36 +00:00
|
|
|
/*
|
|
|
|
backpack.c (c) 2001 Micro Solutions Inc.
|
|
|
|
Released under the terms of the GNU General Public license
|
|
|
|
|
|
|
|
backpack.c is a low-level protocol driver for the Micro Solutions
|
|
|
|
"BACKPACK" parallel port IDE adapter
|
|
|
|
(Works on Series 6 drives)
|
|
|
|
|
|
|
|
Written by: Ken Hahn (linux-dev@micro-solutions.com)
|
|
|
|
Clive Turvey (linux-dev@micro-solutions.com)
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/module.h>
|
|
|
|
#include <linux/init.h>
|
|
|
|
#include <linux/kernel.h>
|
|
|
|
#include <linux/types.h>
|
|
|
|
#include <linux/parport.h>
|
2023-02-18 22:01:38 +00:00
|
|
|
#include "pata_parport.h"
|
2023-03-07 22:45:59 +00:00
|
|
|
#include "ppc6lnx.c"
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2023-02-18 22:01:28 +00:00
|
|
|
static int bpck6_read_regr(struct pi_adapter *pi, int cont, int reg)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2023-03-07 22:46:11 +00:00
|
|
|
u8 port = cont ? reg | 8 : reg;
|
|
|
|
|
|
|
|
ppc6_send_cmd(pi, port | ACCESS_PORT | ACCESS_READ);
|
|
|
|
return ppc6_rd_data_byte(pi);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2023-02-18 22:01:28 +00:00
|
|
|
static void bpck6_write_regr(struct pi_adapter *pi, int cont, int reg, int val)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2023-03-07 22:46:12 +00:00
|
|
|
u8 port = cont ? reg | 8 : reg;
|
|
|
|
|
|
|
|
ppc6_send_cmd(pi, port | ACCESS_PORT | ACCESS_WRITE);
|
|
|
|
ppc6_wr_data_byte(pi, val);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2023-03-07 22:46:17 +00:00
|
|
|
static void bpck6_wait_for_fifo(struct pi_adapter *pi)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (pi->private & fifo_wait) {
|
|
|
|
for (i = 0; i < 20; i++)
|
|
|
|
parport_read_status(pi->pardev->port);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-18 22:01:28 +00:00
|
|
|
static void bpck6_write_block(struct pi_adapter *pi, char *buf, int len)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2023-03-07 22:46:16 +00:00
|
|
|
u8 this, last;
|
|
|
|
|
2023-03-07 22:46:14 +00:00
|
|
|
ppc6_send_cmd(pi, REG_BLKSIZE | ACCESS_REG | ACCESS_WRITE);
|
|
|
|
ppc6_wr_data_byte(pi, (u8)len);
|
|
|
|
ppc6_wr_data_byte(pi, (u8)(len >> 8));
|
|
|
|
ppc6_wr_data_byte(pi, 0);
|
|
|
|
|
|
|
|
ppc6_send_cmd(pi, CMD_PREFIX_SET | PREFIX_IO16 | PREFIX_BLK);
|
|
|
|
ppc6_send_cmd(pi, ATA_REG_DATA | ACCESS_PORT | ACCESS_WRITE);
|
2023-03-07 22:46:16 +00:00
|
|
|
|
|
|
|
switch (mode_map[pi->mode]) {
|
|
|
|
case PPCMODE_UNI_SW:
|
|
|
|
case PPCMODE_BI_SW:
|
|
|
|
while (len--) {
|
|
|
|
parport_write_data(pi->pardev->port, *buf++);
|
|
|
|
parport_frob_control(pi->pardev->port, 0,
|
|
|
|
PARPORT_CONTROL_INIT);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case PPCMODE_UNI_FW:
|
|
|
|
case PPCMODE_BI_FW:
|
|
|
|
ppc6_send_cmd(pi, CMD_PREFIX_SET | PREFIX_FASTWR);
|
|
|
|
|
|
|
|
parport_frob_control(pi->pardev->port, PARPORT_CONTROL_STROBE,
|
|
|
|
PARPORT_CONTROL_STROBE);
|
|
|
|
|
|
|
|
last = *buf;
|
|
|
|
|
|
|
|
parport_write_data(pi->pardev->port, last);
|
|
|
|
|
|
|
|
while (len) {
|
|
|
|
this = *buf++;
|
|
|
|
len--;
|
|
|
|
|
|
|
|
if (this == last) {
|
|
|
|
parport_frob_control(pi->pardev->port, 0,
|
|
|
|
PARPORT_CONTROL_INIT);
|
|
|
|
} else {
|
|
|
|
parport_write_data(pi->pardev->port, this);
|
|
|
|
last = this;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
parport_frob_control(pi->pardev->port, PARPORT_CONTROL_STROBE,
|
|
|
|
0);
|
|
|
|
ppc6_send_cmd(pi, CMD_PREFIX_RESET | PREFIX_FASTWR);
|
|
|
|
break;
|
|
|
|
case PPCMODE_EPP_BYTE:
|
|
|
|
pi->pardev->port->ops->epp_write_data(pi->pardev->port, buf,
|
|
|
|
len, PARPORT_EPP_FAST_8);
|
2023-03-07 22:46:17 +00:00
|
|
|
bpck6_wait_for_fifo(pi);
|
2023-03-07 22:46:16 +00:00
|
|
|
break;
|
|
|
|
case PPCMODE_EPP_WORD:
|
|
|
|
pi->pardev->port->ops->epp_write_data(pi->pardev->port, buf,
|
|
|
|
len, PARPORT_EPP_FAST_16);
|
2023-03-07 22:46:17 +00:00
|
|
|
bpck6_wait_for_fifo(pi);
|
2023-03-07 22:46:16 +00:00
|
|
|
break;
|
|
|
|
case PPCMODE_EPP_DWORD:
|
|
|
|
pi->pardev->port->ops->epp_write_data(pi->pardev->port, buf,
|
|
|
|
len, PARPORT_EPP_FAST_32);
|
2023-03-07 22:46:17 +00:00
|
|
|
bpck6_wait_for_fifo(pi);
|
2023-03-07 22:46:16 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2023-03-07 22:46:14 +00:00
|
|
|
ppc6_send_cmd(pi, CMD_PREFIX_RESET | PREFIX_IO16 | PREFIX_BLK);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2023-02-18 22:01:28 +00:00
|
|
|
static void bpck6_read_block(struct pi_adapter *pi, char *buf, int len)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2023-03-07 22:46:13 +00:00
|
|
|
ppc6_send_cmd(pi, REG_BLKSIZE | ACCESS_REG | ACCESS_WRITE);
|
|
|
|
ppc6_wr_data_byte(pi, (u8)len);
|
|
|
|
ppc6_wr_data_byte(pi, (u8)(len >> 8));
|
|
|
|
ppc6_wr_data_byte(pi, 0);
|
|
|
|
|
|
|
|
ppc6_send_cmd(pi, CMD_PREFIX_SET | PREFIX_IO16 | PREFIX_BLK);
|
|
|
|
ppc6_send_cmd(pi, ATA_REG_DATA | ACCESS_PORT | ACCESS_READ);
|
2023-03-07 22:46:15 +00:00
|
|
|
|
|
|
|
switch (mode_map[pi->mode]) {
|
|
|
|
case PPCMODE_UNI_SW:
|
|
|
|
case PPCMODE_UNI_FW:
|
|
|
|
while (len) {
|
|
|
|
u8 d;
|
|
|
|
|
|
|
|
parport_frob_control(pi->pardev->port,
|
|
|
|
PARPORT_CONTROL_STROBE,
|
|
|
|
PARPORT_CONTROL_INIT); /* DATA STROBE */
|
|
|
|
d = parport_read_status(pi->pardev->port);
|
|
|
|
d = ((d & 0x80) >> 1) | ((d & 0x38) >> 3);
|
|
|
|
parport_frob_control(pi->pardev->port,
|
|
|
|
PARPORT_CONTROL_STROBE,
|
|
|
|
PARPORT_CONTROL_STROBE);
|
|
|
|
d |= parport_read_status(pi->pardev->port) & 0xB8;
|
|
|
|
*buf++ = d;
|
|
|
|
len--;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case PPCMODE_BI_SW:
|
|
|
|
case PPCMODE_BI_FW:
|
|
|
|
parport_data_reverse(pi->pardev->port);
|
|
|
|
while (len) {
|
|
|
|
parport_frob_control(pi->pardev->port,
|
|
|
|
PARPORT_CONTROL_STROBE,
|
|
|
|
PARPORT_CONTROL_STROBE | PARPORT_CONTROL_INIT);
|
|
|
|
*buf++ = parport_read_data(pi->pardev->port);
|
|
|
|
len--;
|
|
|
|
}
|
|
|
|
parport_frob_control(pi->pardev->port, PARPORT_CONTROL_STROBE,
|
|
|
|
0);
|
|
|
|
parport_data_forward(pi->pardev->port);
|
|
|
|
break;
|
|
|
|
case PPCMODE_EPP_BYTE:
|
|
|
|
pi->pardev->port->ops->epp_read_data(pi->pardev->port, buf, len,
|
|
|
|
PARPORT_EPP_FAST_8);
|
|
|
|
break;
|
|
|
|
case PPCMODE_EPP_WORD:
|
|
|
|
pi->pardev->port->ops->epp_read_data(pi->pardev->port, buf, len,
|
|
|
|
PARPORT_EPP_FAST_16);
|
|
|
|
break;
|
|
|
|
case PPCMODE_EPP_DWORD:
|
|
|
|
pi->pardev->port->ops->epp_read_data(pi->pardev->port, buf, len,
|
|
|
|
PARPORT_EPP_FAST_32);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2023-03-07 22:46:13 +00:00
|
|
|
ppc6_send_cmd(pi, CMD_PREFIX_RESET | PREFIX_IO16 | PREFIX_BLK);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2023-02-18 22:01:28 +00:00
|
|
|
static void bpck6_connect(struct pi_adapter *pi)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2023-02-18 22:01:31 +00:00
|
|
|
dev_dbg(&pi->dev, "connect\n");
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2023-03-07 22:45:59 +00:00
|
|
|
ppc6_open(pi);
|
|
|
|
ppc6_wr_extout(pi, 0x3);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2023-02-18 22:01:28 +00:00
|
|
|
static void bpck6_disconnect(struct pi_adapter *pi)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2023-02-18 22:01:31 +00:00
|
|
|
dev_dbg(&pi->dev, "disconnect\n");
|
2023-03-07 22:45:59 +00:00
|
|
|
ppc6_wr_extout(pi, 0x0);
|
2023-03-07 22:46:10 +00:00
|
|
|
ppc6_deselect(pi);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2023-02-18 22:01:28 +00:00
|
|
|
static int bpck6_test_port(struct pi_adapter *pi) /* check for 8-bit port */
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2023-02-18 22:01:31 +00:00
|
|
|
dev_dbg(&pi->dev, "PARPORT indicates modes=%x for lp=0x%lx\n",
|
2023-03-07 22:45:58 +00:00
|
|
|
pi->pardev->port->modes, pi->pardev->port->base);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2023-03-07 22:45:58 +00:00
|
|
|
/* look at the parport device to see what modes we can use */
|
|
|
|
if (pi->pardev->port->modes & PARPORT_MODE_EPP)
|
|
|
|
return 5; /* Can do EPP */
|
|
|
|
if (pi->pardev->port->modes & PARPORT_MODE_TRISTATE)
|
2005-04-16 22:20:36 +00:00
|
|
|
return 2;
|
2023-03-07 22:45:58 +00:00
|
|
|
return 1; /* Just flat SPP */
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2023-02-18 22:01:28 +00:00
|
|
|
static int bpck6_probe_unit(struct pi_adapter *pi)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2023-03-07 22:46:03 +00:00
|
|
|
int out, saved_mode;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2023-02-18 22:01:31 +00:00
|
|
|
dev_dbg(&pi->dev, "PROBE UNIT %x on port:%x\n", pi->unit, pi->port);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2023-03-07 22:46:03 +00:00
|
|
|
saved_mode = pi->mode;
|
2005-04-16 22:20:36 +00:00
|
|
|
/*LOWER DOWN TO UNIDIRECTIONAL*/
|
2023-03-07 22:46:03 +00:00
|
|
|
pi->mode = 0;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2023-03-07 22:45:59 +00:00
|
|
|
out = ppc6_open(pi);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2023-02-18 22:01:31 +00:00
|
|
|
dev_dbg(&pi->dev, "ppc_open returned %2x\n", out);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
if(out)
|
|
|
|
{
|
2023-03-07 22:46:10 +00:00
|
|
|
ppc6_deselect(pi);
|
2023-02-18 22:01:31 +00:00
|
|
|
dev_dbg(&pi->dev, "leaving probe\n");
|
2023-03-07 22:46:03 +00:00
|
|
|
pi->mode = saved_mode;
|
2005-04-16 22:20:36 +00:00
|
|
|
return(1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2023-02-18 22:01:31 +00:00
|
|
|
dev_dbg(&pi->dev, "Failed open\n");
|
2023-03-07 22:46:03 +00:00
|
|
|
pi->mode = saved_mode;
|
2005-04-16 22:20:36 +00:00
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-18 22:01:30 +00:00
|
|
|
static void bpck6_log_adapter(struct pi_adapter *pi)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
char *mode_string[5]=
|
|
|
|
{"4-bit","8-bit","EPP-8","EPP-16","EPP-32"};
|
|
|
|
|
2023-02-18 22:01:33 +00:00
|
|
|
dev_info(&pi->dev, "Micro Solutions BACKPACK Drive unit %d at 0x%x, mode:%d (%s), delay %d\n",
|
|
|
|
pi->unit, pi->port, pi->mode, mode_string[pi->mode], pi->delay);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static struct pi_protocol bpck6 = {
|
|
|
|
.owner = THIS_MODULE,
|
|
|
|
.name = "bpck6",
|
|
|
|
.max_mode = 5,
|
|
|
|
.epp_first = 2, /* 2-5 use epp (need 8 ports) */
|
|
|
|
.max_units = 255,
|
|
|
|
.write_regr = bpck6_write_regr,
|
|
|
|
.read_regr = bpck6_read_regr,
|
|
|
|
.write_block = bpck6_write_block,
|
|
|
|
.read_block = bpck6_read_block,
|
|
|
|
.connect = bpck6_connect,
|
|
|
|
.disconnect = bpck6_disconnect,
|
|
|
|
.test_port = bpck6_test_port,
|
|
|
|
.probe_unit = bpck6_probe_unit,
|
|
|
|
.log_adapter = bpck6_log_adapter,
|
|
|
|
};
|
|
|
|
|
|
|
|
MODULE_LICENSE("GPL");
|
|
|
|
MODULE_AUTHOR("Micro Solutions Inc.");
|
|
|
|
MODULE_DESCRIPTION("BACKPACK Protocol module, compatible with PARIDE");
|
2023-02-18 22:01:25 +00:00
|
|
|
module_pata_parport_driver(bpck6);
|