patch-2.1.88 linux/drivers/acorn/block/ide-ics.c
Next file: linux/drivers/acorn/block/ide-rapide.c
Previous file: linux/drivers/acorn/block/fd1772.c
Back to the patch index
Back to the overall index
- Lines: 272
- Date:
Mon Feb 16 14:26:56 1998
- Orig file:
v2.1.87/linux/drivers/acorn/block/ide-ics.c
- Orig date:
Wed Dec 31 16:00:00 1969
diff -u --recursive --new-file v2.1.87/linux/drivers/acorn/block/ide-ics.c linux/drivers/acorn/block/ide-ics.c
@@ -0,0 +1,271 @@
+/*
+ * linux/arch/arm/drivers/block/ide-ics.c
+ *
+ * Copyright (c) 1996,1997 Russell King.
+ *
+ * Changelog:
+ * 08-06-1996 RMK Created
+ * 12-09-1997 RMK Added interrupt enable/disable
+ */
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/blkdev.h>
+#include <linux/errno.h>
+#include <linux/hdreg.h>
+
+#include <asm/ecard.h>
+#include <asm/io.h>
+
+#include "../../block/ide.h"
+
+/*
+ * Maximum number of interfaces per card
+ */
+#define MAX_IFS 2
+
+#define ICS_IDENT_OFFSET 0x8a0
+
+#define ICS_ARCIN_V5_INTROFFSET 0x001
+#define ICS_ARCIN_V5_IDEOFFSET 0xa00
+#define ICS_ARCIN_V5_IDEALTOFFSET 0xae0
+#define ICS_ARCIN_V5_IDESTEPPING 4
+
+#define ICS_ARCIN_V6_IDEOFFSET_1 0x800
+#define ICS_ARCIN_V6_INTROFFSET_1 0x880
+#define ICS_ARCIN_V6_IDEALTOFFSET_1 0x8e0
+#define ICS_ARCIN_V6_IDEOFFSET_2 0xc00
+#define ICS_ARCIN_V6_INTROFFSET_2 0xc80
+#define ICS_ARCIN_V6_IDEALTOFFSET_2 0xce0
+#define ICS_ARCIN_V6_IDESTEPPING 4
+
+static const card_ids icside_cids[] = {
+ { MANU_ICS, PROD_ICS_IDE },
+ { 0xffff, 0xffff }
+};
+
+typedef enum {
+ ics_if_unknown,
+ ics_if_arcin_v5,
+ ics_if_arcin_v6
+} iftype_t;
+
+static struct expansion_card *ec[MAX_ECARDS];
+static int result[MAX_ECARDS][MAX_IFS];
+
+
+/* ---------------- Version 5 PCB Support Functions --------------------- */
+/* Prototype: icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr)
+ * Purpose : enable interrupts from card
+ */
+static void icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr)
+{
+ unsigned int memc_port = (unsigned int)ec->irq_data;
+ outb (0, memc_port + ICS_ARCIN_V5_INTROFFSET);
+}
+
+/* Prototype: icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr)
+ * Purpose : disable interrupts from card
+ */
+static void icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr)
+{
+ unsigned int memc_port = (unsigned int)ec->irq_data;
+ inb (memc_port + ICS_ARCIN_V5_INTROFFSET);
+}
+
+static const expansioncard_ops_t icside_ops_arcin_v5 = {
+ icside_irqenable_arcin_v5,
+ icside_irqdisable_arcin_v5,
+ NULL,
+ NULL
+};
+
+
+/* ---------------- Version 6 PCB Support Functions --------------------- */
+/* Prototype: icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr)
+ * Purpose : enable interrupts from card
+ */
+static void icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr)
+{
+ unsigned int ide_base_port = (unsigned int)ec->irq_data;
+ outb (0, ide_base_port + ICS_ARCIN_V6_INTROFFSET_1);
+ outb (0, ide_base_port + ICS_ARCIN_V6_INTROFFSET_2);
+}
+
+/* Prototype: icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr)
+ * Purpose : disable interrupts from card
+ */
+static void icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr)
+{
+ unsigned int ide_base_port = (unsigned int)ec->irq_data;
+ inb (ide_base_port + ICS_ARCIN_V6_INTROFFSET_1);
+ inb (ide_base_port + ICS_ARCIN_V6_INTROFFSET_2);
+}
+
+static const expansioncard_ops_t icside_ops_arcin_v6 = {
+ icside_irqenable_arcin_v6,
+ icside_irqdisable_arcin_v6,
+ NULL,
+ NULL
+};
+
+
+
+/* Prototype: icside_identifyif (struct expansion_card *ec)
+ * Purpose : identify IDE interface type
+ * Notes : checks the description string
+ */
+static iftype_t icside_identifyif (struct expansion_card *ec)
+{
+ unsigned int addr;
+ iftype_t iftype;
+ int id = 0;
+
+ iftype = ics_if_unknown;
+
+ addr = ecard_address (ec, ECARD_IOC, ECARD_FAST) + ICS_IDENT_OFFSET;
+
+ id = inb (addr) & 1;
+ id |= (inb (addr + 1) & 1) << 1;
+ id |= (inb (addr + 2) & 1) << 2;
+ id |= (inb (addr + 3) & 1) << 3;
+
+ switch (id) {
+ case 0: /* A3IN */
+ printk ("icside: A3IN unsupported\n");
+ break;
+
+ case 1: /* A3USER */
+ printk ("icside: A3USER unsupported\n");
+ break;
+
+ case 3: /* ARCIN V6 */
+ printk ("icside: detected ARCIN V6 in slot %d\n", ec->slot_no);
+ iftype = ics_if_arcin_v6;
+ break;
+
+ case 15:/* ARCIN V5 (no id) */
+ printk ("icside: detected ARCIN V5 in slot %d\n", ec->slot_no);
+ iftype = ics_if_arcin_v5;
+ break;
+
+ default:/* we don't know - complain very loudly */
+ printk ("icside: ***********************************\n");
+ printk ("icside: *** UNKNOWN ICS INTERFACE id=%d ***\n", id);
+ printk ("icside: ***********************************\n");
+ printk ("icside: please report this to: linux@arm.uk.linux.org\n");
+ printk ("icside: defaulting to ARCIN V5\n");
+ iftype = ics_if_arcin_v5;
+ break;
+ }
+
+ return iftype;
+}
+
+/* Prototype: icside_register (struct expansion_card *ec)
+ * Purpose : register an ICS IDE card with the IDE driver
+ * Notes : we make sure that interrupts are disabled from the card
+ */
+static inline void icside_register (struct expansion_card *ec, int index)
+{
+ unsigned long port;
+
+ result[index][0] = -1;
+ result[index][1] = -1;
+
+ switch (icside_identifyif (ec)) {
+ case ics_if_unknown:
+ default:
+ printk ("** Warning: ICS IDE Interface unrecognised! **\n");
+ break;
+
+ case ics_if_arcin_v5:
+ port = ecard_address (ec, ECARD_MEMC, 0);
+ ec->irq_data = (void *)port;
+ ec->ops = (expansioncard_ops_t *)&icside_ops_arcin_v5;
+
+ /*
+ * Be on the safe side - disable interrupts
+ */
+ inb (port + ICS_ARCIN_V5_INTROFFSET);
+ result[index][0] =
+ ide_register_port (port + ICS_ARCIN_V5_IDEOFFSET,
+ port + ICS_ARCIN_V5_IDEALTOFFSET,
+ ICS_ARCIN_V5_IDESTEPPING,
+ ec->irq);
+ break;
+
+ case ics_if_arcin_v6:
+ port = ecard_address (ec, ECARD_IOC, ECARD_FAST);
+ ec->irq_data = (void *)port;
+ ec->ops = (expansioncard_ops_t *)&icside_ops_arcin_v6;
+
+ /*
+ * Be on the safe side - disable interrupts
+ */
+ inb (port + ICS_ARCIN_V6_INTROFFSET_1);
+ inb (port + ICS_ARCIN_V6_INTROFFSET_2);
+ result[index][0] =
+ ide_register_port (port + ICS_ARCIN_V6_IDEOFFSET_1,
+ port + ICS_ARCIN_V6_IDEALTOFFSET_1,
+ ICS_ARCIN_V6_IDESTEPPING,
+ ec->irq);
+ result[index][1] =
+ ide_register_port (port + ICS_ARCIN_V6_IDEOFFSET_2,
+ port + ICS_ARCIN_V6_IDEALTOFFSET_2,
+ ICS_ARCIN_V6_IDESTEPPING,
+ ec->irq);
+ break;
+ }
+}
+
+int icside_init (void)
+{
+ int i;
+
+ for (i = 0; i < MAX_ECARDS; i++)
+ ec[i] = NULL;
+
+ ecard_startfind ();
+
+ for (i = 0; ; i++) {
+ if ((ec[i] = ecard_find (0, icside_cids)) == NULL)
+ break;
+
+ ecard_claim (ec[i]);
+ icside_register (ec[i], i);
+ }
+
+ for (i = 0; i < MAX_ECARDS; i++)
+ if (ec[i] && result[i][0] < 0 && result[i][1] < 0) {
+ ecard_release (ec[i]);
+ ec[i] = NULL;
+ }
+ return 0;
+}
+
+#ifdef MODULE
+int init_module (void)
+{
+ return icside_init();
+}
+
+void cleanup_module (void)
+{
+ int i;
+
+ for (i = 0; i < MAX_ECARDS; i++)
+ if (ec[i]) {
+ if (result[i][0] >= 0)
+ ide_unregister (result[i][0]);
+
+ if (result[i][1] >= 0)
+ ide_unregister (result[i][1]);
+
+ ecard_release (ec[i]);
+ ec[i] = NULL;
+ }
+}
+#endif
+
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov