Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/drivers/ata/pata_parport/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 12 kB image not shown  

Quelle  bpck6.c   Sprache: 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("Micro Solutions BACKPACK parallel port IDE adapter "
     "(version 6 drives) protocol driver");
module_pata_parport_driver(bpck6);

Messung V0.5
C=88 H=89 G=88

¤ Dauer der Verarbeitung: 0.4 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.