linux-stable/drivers/ata/pata_parport/bpck6.c
Damien Le Moal ec52d5241e ata: pata_parport: Fix bpck6 module code indentation and style
Fix the header, indentation and coding style in the bpck6 pata parport
protocol module to suppress warnings from smatch and other static code
analyzers.

No functional changes.

Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
2023-05-16 20:17:04 +09:00

463 lines
12 KiB
C

// SPDX-License-Identifier: GPL-2.0-or-later
/*
* (c) 2001 Micro Solutions Inc.
*
* 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>
#include "pata_parport.h"
/* 60772 Commands */
#define ACCESS_REG 0x00
#define ACCESS_PORT 0x40
#define ACCESS_READ 0x00
#define ACCESS_WRITE 0x20
/* 60772 Command Prefix */
#define CMD_PREFIX_SET 0xe0 // Special command that modifies next command's operation
#define CMD_PREFIX_RESET 0xc0 // Resets current cmd modifier reg bits
#define PREFIX_IO16 0x01 // perform 16-bit wide I/O
#define PREFIX_FASTWR 0x04 // enable PPC mode fast-write
#define PREFIX_BLK 0x08 // enable block transfer mode
/* 60772 Registers */
#define REG_STATUS 0x00 // status register
#define STATUS_IRQA 0x01 // Peripheral IRQA line
#define STATUS_EEPROM_DO 0x40 // Serial EEPROM data bit
#define REG_VERSION 0x01 // PPC version register (read)
#define REG_HWCFG 0x02 // Hardware Config register
#define REG_RAMSIZE 0x03 // Size of RAM Buffer
#define RAMSIZE_128K 0x02
#define REG_EEPROM 0x06 // EEPROM control register
#define EEPROM_SK 0x01 // eeprom SK bit
#define EEPROM_DI 0x02 // eeprom DI bit
#define EEPROM_CS 0x04 // eeprom CS bit
#define EEPROM_EN 0x08 // eeprom output enable
#define REG_BLKSIZE 0x08 // Block transfer len (24 bit)
/* flags */
#define fifo_wait 0x10
/* DONT CHANGE THESE LEST YOU BREAK EVERYTHING - BIT FIELD DEPENDENCIES */
#define PPCMODE_UNI_SW 0
#define PPCMODE_UNI_FW 1
#define PPCMODE_BI_SW 2
#define PPCMODE_BI_FW 3
#define PPCMODE_EPP_BYTE 4
#define PPCMODE_EPP_WORD 5
#define PPCMODE_EPP_DWORD 6
static int mode_map[] = { PPCMODE_UNI_FW, PPCMODE_BI_FW, PPCMODE_EPP_BYTE,
PPCMODE_EPP_WORD, PPCMODE_EPP_DWORD };
static void bpck6_send_cmd(struct pi_adapter *pi, u8 cmd)
{
switch (mode_map[pi->mode]) {
case PPCMODE_UNI_SW:
case PPCMODE_UNI_FW:
case PPCMODE_BI_SW:
case PPCMODE_BI_FW:
parport_write_data(pi->pardev->port, cmd);
parport_frob_control(pi->pardev->port, 0, PARPORT_CONTROL_AUTOFD);
break;
case PPCMODE_EPP_BYTE:
case PPCMODE_EPP_WORD:
case PPCMODE_EPP_DWORD:
pi->pardev->port->ops->epp_write_addr(pi->pardev->port, &cmd, 1, 0);
break;
}
}
static u8 bpck6_rd_data_byte(struct pi_adapter *pi)
{
u8 data = 0;
switch (mode_map[pi->mode]) {
case PPCMODE_UNI_SW:
case PPCMODE_UNI_FW:
parport_frob_control(pi->pardev->port, PARPORT_CONTROL_STROBE,
PARPORT_CONTROL_INIT);
data = parport_read_status(pi->pardev->port);
data = ((data & 0x80) >> 1) | ((data & 0x38) >> 3);
parport_frob_control(pi->pardev->port, PARPORT_CONTROL_STROBE,
PARPORT_CONTROL_STROBE);
data |= parport_read_status(pi->pardev->port) & 0xB8;
break;
case PPCMODE_BI_SW:
case PPCMODE_BI_FW:
parport_data_reverse(pi->pardev->port);
parport_frob_control(pi->pardev->port, PARPORT_CONTROL_STROBE,
PARPORT_CONTROL_STROBE | PARPORT_CONTROL_INIT);
data = parport_read_data(pi->pardev->port);
parport_frob_control(pi->pardev->port, PARPORT_CONTROL_STROBE, 0);
parport_data_forward(pi->pardev->port);
break;
case PPCMODE_EPP_BYTE:
case PPCMODE_EPP_WORD:
case PPCMODE_EPP_DWORD:
pi->pardev->port->ops->epp_read_data(pi->pardev->port, &data, 1, 0);
break;
}
return data;
}
static void bpck6_wr_data_byte(struct pi_adapter *pi, u8 data)
{
switch (mode_map[pi->mode]) {
case PPCMODE_UNI_SW:
case PPCMODE_UNI_FW:
case PPCMODE_BI_SW:
case PPCMODE_BI_FW:
parport_write_data(pi->pardev->port, data);
parport_frob_control(pi->pardev->port, 0, PARPORT_CONTROL_INIT);
break;
case PPCMODE_EPP_BYTE:
case PPCMODE_EPP_WORD:
case PPCMODE_EPP_DWORD:
pi->pardev->port->ops->epp_write_data(pi->pardev->port, &data, 1, 0);
break;
}
}
static int bpck6_read_regr(struct pi_adapter *pi, int cont, int reg)
{
u8 port = cont ? reg | 8 : reg;
bpck6_send_cmd(pi, port | ACCESS_PORT | ACCESS_READ);
return bpck6_rd_data_byte(pi);
}
static void bpck6_write_regr(struct pi_adapter *pi, int cont, int reg, int val)
{
u8 port = cont ? reg | 8 : reg;
bpck6_send_cmd(pi, port | ACCESS_PORT | ACCESS_WRITE);
bpck6_wr_data_byte(pi, val);
}
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);
}
}
static void bpck6_write_block(struct pi_adapter *pi, char *buf, int len)
{
u8 this, last;
bpck6_send_cmd(pi, REG_BLKSIZE | ACCESS_REG | ACCESS_WRITE);
bpck6_wr_data_byte(pi, (u8)len);
bpck6_wr_data_byte(pi, (u8)(len >> 8));
bpck6_wr_data_byte(pi, 0);
bpck6_send_cmd(pi, CMD_PREFIX_SET | PREFIX_IO16 | PREFIX_BLK);
bpck6_send_cmd(pi, ATA_REG_DATA | ACCESS_PORT | ACCESS_WRITE);
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:
bpck6_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);
bpck6_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);
bpck6_wait_for_fifo(pi);
break;
case PPCMODE_EPP_WORD:
pi->pardev->port->ops->epp_write_data(pi->pardev->port, buf,
len, PARPORT_EPP_FAST_16);
bpck6_wait_for_fifo(pi);
break;
case PPCMODE_EPP_DWORD:
pi->pardev->port->ops->epp_write_data(pi->pardev->port, buf,
len, PARPORT_EPP_FAST_32);
bpck6_wait_for_fifo(pi);
break;
}
bpck6_send_cmd(pi, CMD_PREFIX_RESET | PREFIX_IO16 | PREFIX_BLK);
}
static void bpck6_read_block(struct pi_adapter *pi, char *buf, int len)
{
bpck6_send_cmd(pi, REG_BLKSIZE | ACCESS_REG | ACCESS_WRITE);
bpck6_wr_data_byte(pi, (u8)len);
bpck6_wr_data_byte(pi, (u8)(len >> 8));
bpck6_wr_data_byte(pi, 0);
bpck6_send_cmd(pi, CMD_PREFIX_SET | PREFIX_IO16 | PREFIX_BLK);
bpck6_send_cmd(pi, ATA_REG_DATA | ACCESS_PORT | ACCESS_READ);
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;
}
bpck6_send_cmd(pi, CMD_PREFIX_RESET | PREFIX_IO16 | PREFIX_BLK);
}
static int bpck6_open(struct pi_adapter *pi)
{
u8 i, j, k;
pi->saved_r0 = parport_read_data(pi->pardev->port);
pi->saved_r2 = parport_read_control(pi->pardev->port) & 0x5F;
parport_frob_control(pi->pardev->port, PARPORT_CONTROL_SELECT,
PARPORT_CONTROL_SELECT);
if (pi->saved_r0 == 'b')
parport_write_data(pi->pardev->port, 'x');
parport_write_data(pi->pardev->port, 'b');
parport_write_data(pi->pardev->port, 'p');
parport_write_data(pi->pardev->port, pi->unit);
parport_write_data(pi->pardev->port, ~pi->unit);
parport_frob_control(pi->pardev->port, PARPORT_CONTROL_SELECT, 0);
parport_write_control(pi->pardev->port, PARPORT_CONTROL_INIT);
i = mode_map[pi->mode] & 0x0C;
if (i == 0)
i = (mode_map[pi->mode] & 2) | 1;
parport_write_data(pi->pardev->port, i);
parport_frob_control(pi->pardev->port, PARPORT_CONTROL_SELECT,
PARPORT_CONTROL_SELECT);
parport_frob_control(pi->pardev->port, PARPORT_CONTROL_AUTOFD,
PARPORT_CONTROL_AUTOFD);
j = ((i & 0x08) << 4) | ((i & 0x07) << 3);
k = parport_read_status(pi->pardev->port) & 0xB8;
if (j != k)
goto fail;
parport_frob_control(pi->pardev->port, PARPORT_CONTROL_AUTOFD, 0);
k = (parport_read_status(pi->pardev->port) & 0xB8) ^ 0xB8;
if (j != k)
goto fail;
if (i & 4) {
/* EPP */
parport_frob_control(pi->pardev->port,
PARPORT_CONTROL_SELECT | PARPORT_CONTROL_INIT, 0);
} else {
/* PPC/ECP */
parport_frob_control(pi->pardev->port, PARPORT_CONTROL_SELECT, 0);
}
pi->private = 0;
bpck6_send_cmd(pi, ACCESS_REG | ACCESS_WRITE | REG_RAMSIZE);
bpck6_wr_data_byte(pi, RAMSIZE_128K);
bpck6_send_cmd(pi, ACCESS_REG | ACCESS_READ | REG_VERSION);
if ((bpck6_rd_data_byte(pi) & 0x3F) == 0x0C)
pi->private |= fifo_wait;
return 1;
fail:
parport_write_control(pi->pardev->port, pi->saved_r2);
parport_write_data(pi->pardev->port, pi->saved_r0);
return 0;
}
static void bpck6_deselect(struct pi_adapter *pi)
{
if (mode_map[pi->mode] & 4) {
/* EPP */
parport_frob_control(pi->pardev->port, PARPORT_CONTROL_INIT,
PARPORT_CONTROL_INIT);
} else {
/* PPC/ECP */
parport_frob_control(pi->pardev->port, PARPORT_CONTROL_SELECT,
PARPORT_CONTROL_SELECT);
}
parport_write_data(pi->pardev->port, pi->saved_r0);
parport_write_control(pi->pardev->port,
pi->saved_r2 | PARPORT_CONTROL_SELECT);
parport_write_control(pi->pardev->port, pi->saved_r2);
}
static void bpck6_wr_extout(struct pi_adapter *pi, u8 regdata)
{
bpck6_send_cmd(pi, REG_VERSION | ACCESS_REG | ACCESS_WRITE);
bpck6_wr_data_byte(pi, (u8)((regdata & 0x03) << 6));
}
static void bpck6_connect(struct pi_adapter *pi)
{
dev_dbg(&pi->dev, "connect\n");
bpck6_open(pi);
bpck6_wr_extout(pi, 0x3);
}
static void bpck6_disconnect(struct pi_adapter *pi)
{
dev_dbg(&pi->dev, "disconnect\n");
bpck6_wr_extout(pi, 0x0);
bpck6_deselect(pi);
}
/* check for 8-bit port */
static int bpck6_test_port(struct pi_adapter *pi)
{
dev_dbg(&pi->dev, "PARPORT indicates modes=%x for lp=0x%lx\n",
pi->pardev->port->modes, pi->pardev->port->base);
/* 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)
return 2;
return 1; /* Just flat SPP */
}
static int bpck6_probe_unit(struct pi_adapter *pi)
{
int out, saved_mode;
dev_dbg(&pi->dev, "PROBE UNIT %x on port:%x\n", pi->unit, pi->port);
saved_mode = pi->mode;
/*LOWER DOWN TO UNIDIRECTIONAL*/
pi->mode = 0;
out = bpck6_open(pi);
dev_dbg(&pi->dev, "ppc_open returned %2x\n", out);
if (out) {
bpck6_deselect(pi);
dev_dbg(&pi->dev, "leaving probe\n");
pi->mode = saved_mode;
return 1;
}
dev_dbg(&pi->dev, "Failed open\n");
pi->mode = saved_mode;
return 0;
}
static void bpck6_log_adapter(struct pi_adapter *pi)
{
char *mode_string[5] = { "4-bit", "8-bit", "EPP-8", "EPP-16", "EPP-32" };
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);
}
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");
module_pata_parport_driver(bpck6);