patch-2.4.22 linux-2.4.22/arch/arm/kernel/ecard.c
Next file: linux-2.4.22/arch/arm/kernel/entry-armv.S
Previous file: linux-2.4.22/arch/arm/kernel/dma.c
Back to the patch index
Back to the overall index
- Lines: 415
- Date:
2003-08-25 04:44:39.000000000 -0700
- Orig file:
linux-2.4.21/arch/arm/kernel/ecard.c
- Orig date:
2003-06-13 07:51:29.000000000 -0700
diff -urN linux-2.4.21/arch/arm/kernel/ecard.c linux-2.4.22/arch/arm/kernel/ecard.c
@@ -38,7 +38,10 @@
#include <linux/slab.h>
#include <linux/proc_fs.h>
#include <linux/notifier.h>
+#include <linux/list.h>
+#include <linux/timer.h>
#include <linux/init.h>
+#include <linux/ioport.h>
#include <asm/dma.h>
#include <asm/ecard.h>
@@ -55,7 +58,7 @@
enum req {
req_readbytes,
- req_reset_all
+ req_reset
};
struct ecard_request {
@@ -136,14 +139,11 @@
#define POD_INT_ADDR(x) ((volatile unsigned char *)\
((BUS_ADDR((x)) - IO_BASE) + IO_START))
-static inline void ecard_task_reset(void)
+static inline void ecard_task_reset(struct ecard_request *req)
{
- ecard_t *ec;
-
- for (ec = cards; ec; ec = ec->next)
- if (ec->loader)
- ecard_loader_reset(POD_INT_ADDR(ec->podaddr),
- ec->loader);
+ struct expansion_card *ec = req->ec;
+ if (ec->loader)
+ ecard_loader_reset(POD_INT_ADDR(ec->podaddr), ec->loader);
}
static void
@@ -223,8 +223,8 @@
ecard_task_readbytes(req);
break;
- case req_reset_all:
- ecard_task_reset();
+ case req_reset:
+ ecard_task_reset(req);
break;
}
}
@@ -371,60 +371,6 @@
/* ======================= Mid-level card control ===================== */
-/*
- * This function is responsible for resetting the expansion cards to a
- * sensible state immediately prior to rebooting the system. This function
- * has process state (keventd), so we can sleep.
- *
- * Possible "val" values here:
- * SYS_RESTART - restarting system
- * SYS_HALT - halting system
- * SYS_POWER_OFF - powering down system
- *
- * We ignore all calls, unless it is a SYS_RESTART call - power down/halts
- * will be followed by a SYS_RESTART if ctrl-alt-del is pressed again.
- */
-static int ecard_reboot(struct notifier_block *me, unsigned long val, void *v)
-{
- struct ecard_request req;
-
- if (val != SYS_RESTART)
- return 0;
-
- /*
- * Disable the expansion card interrupt
- */
- disable_irq(IRQ_EXPANSIONCARD);
-
- /*
- * If we have any expansion card loader code which will handle
- * the reset for us, call it now.
- */
- req.req = req_reset_all;
- ecard_call(&req);
-
- /*
- * Disable the expansion card interrupt again, just to be sure.
- */
- disable_irq(IRQ_EXPANSIONCARD);
-
- /*
- * Finally, reset the expansion card interrupt mask to
- * all enable (RISC OS doesn't set this)
- */
-#ifdef HAS_EXPMASK
- have_expmask = ~0;
- __raw_writeb(have_expmask, EXPMASK_ENABLE);
-#endif
- return 0;
-}
-
-static struct notifier_block ecard_reboot_notifier = {
- .notifier_call = ecard_reboot,
-};
-
-
-
static void
ecard_readbytes(void *addr, ecard_t *ec, int off, int len, int useld)
{
@@ -628,8 +574,7 @@
ec->irqaddr, ec->irqmask, *ec->irqaddr);
}
-static void
-ecard_check_lockup(void)
+static void ecard_check_lockup(void)
{
static int last, lockup;
ecard_t *ec;
@@ -757,8 +702,7 @@
printk(KERN_WARNING "Wild interrupt from backplane (masks)\n");
}
-static void __init
-ecard_probeirqhw(void)
+static void __init ecard_probeirqhw(void)
{
ecard_t *ec;
int found;
@@ -785,7 +729,7 @@
__raw_writeb(have_expmask, EXPMASK_ENABLE);
}
#else
-#define ecard_probeirqhw()
+#define ecard_probeirqhw() do { } while (0)
#endif
#ifndef IO_EC_MEMC8_BASE
@@ -896,6 +840,57 @@
get_ecard_dev_info);
}
+#define ec_set_resource(ec,nr,st,sz,flg) \
+ do { \
+ (ec)->resource[nr].name = ec->name; \
+ (ec)->resource[nr].start = st; \
+ (ec)->resource[nr].end = (st) + (sz) - 1; \
+ (ec)->resource[nr].flags = flg; \
+ } while (0)
+
+static void __init ecard_init_resources(struct expansion_card *ec)
+{
+ unsigned long base = PODSLOT_IOC4_BASE;
+ unsigned int slot = ec->slot_no;
+ int i;
+
+ if (slot < 4) {
+ ec_set_resource(ec, ECARD_RES_MEMC,
+ PODSLOT_MEMC_BASE + (slot << 14),
+ PODSLOT_MEMC_SIZE, IORESOURCE_MEM);
+ base = PODSLOT_IOC0_BASE;
+ }
+
+#ifdef CONFIG_ARCH_RPC
+ if (slot < 8) {
+ ec_set_resource(ec, ECARD_RES_EASI,
+ PODSLOT_EASI_BASE + (slot << 24),
+ PODSLOT_EASI_SIZE, IORESOURCE_MEM);
+ }
+
+ if (slot == 8) {
+ ec_set_resource(ec, ECARD_RES_MEMC, NETSLOT_BASE,
+ NETSLOT_SIZE, IORESOURCE_MEM);
+ } else
+#endif
+
+ for (i = 0; i < ECARD_RES_IOCSYNC - ECARD_RES_IOCSLOW; i++) {
+ ec_set_resource(ec, i + ECARD_RES_IOCSLOW,
+ base + (slot << 14) + (i << 19),
+ PODSLOT_IOC_SIZE, IORESOURCE_MEM);
+ }
+
+ for (i = 0; i < ECARD_NUM_RESOURCES; i++) {
+ if (ec->resource[i].start &&
+ request_resource(&iomem_resource, &ec->resource[i])) {
+ printk(KERN_ERR "ecard%d: resource(s) not available\n",
+ ec->slot_no);
+ ec->resource[i].end -= ec->resource[i].start;
+ ec->resource[i].start = 0;
+ }
+ }
+}
+
/*
* Probe for an expansion card.
*
@@ -964,21 +959,26 @@
break;
}
- ec->irq = 32 + slot;
-#ifdef IO_EC_MEMC8_BASE
- if (slot == 8)
- ec->irq = 11;
-#endif
+ snprintf(ec->name, sizeof(ec->name), "ecard %04x:%04x",
+ ec->cid.manufacturer, ec->cid.product);
+
+ ecard_init_resources(ec);
+
/*
* hook the interrupt handlers
*/
- if (ec->irq != 0 && ec->irq >= 32) {
+ if (slot < 8) {
+ ec->irq = 32 + slot;
irq_desc[ec->irq].mask_ack = ecard_disableirq;
irq_desc[ec->irq].mask = ecard_disableirq;
irq_desc[ec->irq].unmask = ecard_enableirq;
irq_desc[ec->irq].valid = 1;
}
+#ifdef IO_EC_MEMC8_BASE
+ if (slot == 8)
+ ec->irq = 11;
+#endif
#ifdef CONFIG_ARCH_RPC
/* On RiscPC, only first two slots have DMA capability */
if (slot < 2)
@@ -1012,7 +1012,7 @@
finding_pos = finding_pos->next;
for (; finding_pos; finding_pos = finding_pos->next) {
- if (finding_pos->claimed)
+ if (finding_pos->claimed || finding_pos->driver)
continue;
if (!cids) {
@@ -1062,11 +1062,6 @@
{
int slot;
- /*
- * Register our reboot notifier
- */
- register_reboot_notifier(&ecard_reboot_notifier);
-
#ifdef CONFIG_CPU_32
init_waitqueue_head(&ecard_wait);
#endif
@@ -1093,7 +1088,162 @@
ecard_proc_init();
}
+/*
+ * ECARD driver functions
+ */
+static const struct ecard_id *
+ecard_match_device(const struct ecard_id *ids, struct expansion_card *ec)
+{
+ int i;
+
+ for (i = 0; ids[i].manufacturer != 65535; i++)
+ if (ec->cid.manufacturer == ids[i].manufacturer &&
+ ec->cid.product == ids[i].product)
+ return ids + i;
+
+ return NULL;
+}
+
+static int ecard_drv_probe(struct expansion_card *ec, const struct ecard_id *id)
+{
+ struct ecard_driver *drv = ec->driver;
+ int ret;
+
+ ecard_claim(ec);
+ ret = drv->probe(ec, id);
+ if (ret)
+ ecard_release(ec);
+ return ret;
+}
+
+static int ecard_drv_remove(struct expansion_card *ec)
+{
+ struct ecard_driver *drv = ec->driver;
+
+ drv->remove(ec);
+ ecard_release(ec);
+
+ return 0;
+}
+
+/*
+ * Before rebooting, we must make sure that the expansion card is in a
+ * sensible state, so it can be re-detected. This means that the first
+ * page of the ROM must be visible. We call the expansion cards reset
+ * handler, if any.
+ */
+static void ecard_drv_shutdown(struct expansion_card *ec)
+{
+ struct ecard_driver *drv = ec->driver;
+ struct ecard_request req;
+
+ if (drv && drv->shutdown)
+ drv->shutdown(ec);
+ ecard_release(ec);
+ req.req = req_reset;
+ req.ec = ec;
+ ecard_call(&req);
+}
+
+int ecard_register_driver(struct ecard_driver *drv)
+{
+ struct expansion_card *ec;
+ int ret, found = 0;
+
+ for (ec = cards; ec; ec = ec->next) {
+ const struct ecard_id *id;
+
+ if (ec->driver || ec->claimed)
+ continue;
+
+ if (drv->id_table) {
+ id = ecard_match_device(drv->id_table, ec);
+ ret = id != NULL;
+ } else {
+ id = NULL;
+ ret = ec->cid.id == drv->id;
+ }
+
+ if (ret) {
+ ec->driver = drv;
+ ret = ecard_drv_probe(ec, id);
+ if (ret) {
+ ec->driver = NULL;
+ } else {
+ found++;
+ }
+ }
+ }
+
+ return found ? 0 : -ENODEV;
+}
+
+void ecard_remove_driver(struct ecard_driver *drv)
+{
+ struct expansion_card *ec;
+
+ for (ec = cards; ec; ec = ec->next)
+ if (ec->driver == drv) {
+ ecard_drv_remove(ec);
+ ec->driver = NULL;
+ }
+}
+
+/*
+ * This function is responsible for resetting the expansion cards to a
+ * sensible state immediately prior to rebooting the system. This function
+ * has process state (keventd), so we can sleep.
+ *
+ * Possible "val" values here:
+ * SYS_RESTART - restarting system
+ * SYS_HALT - halting system
+ * SYS_POWER_OFF - powering down system
+ *
+ * We ignore all calls, unless it is a SYS_RESTART call - power down/halts
+ * will be followed by a SYS_RESTART if ctrl-alt-del is pressed again.
+ */
+static int ecard_reboot(struct notifier_block *me, unsigned long val, void *v)
+{
+ struct expansion_card *ec;
+
+ if (val != SYS_RESTART)
+ return 0;
+
+ for (ec = cards; ec; ec = ec->next)
+ if (ec->driver || ec->claimed)
+ ecard_drv_shutdown(ec);
+
+ /*
+ * Disable the expansion card interrupt
+ */
+ disable_irq(IRQ_EXPANSIONCARD);
+
+ /*
+ * Finally, reset the expansion card interrupt mask to
+ * all enable (RISC OS doesn't set this)
+ */
+#ifdef HAS_EXPMASK
+ have_expmask = ~0;
+ __raw_writeb(have_expmask, EXPMASK_ENABLE);
+#endif
+ return 0;
+}
+
+static struct notifier_block ecard_reboot_notifier = {
+ .notifier_call = ecard_reboot,
+};
+
+static int ecard_bus_init(void)
+{
+ register_reboot_notifier(&ecard_reboot_notifier);
+ return 0;
+}
+
+__initcall(ecard_bus_init);
+
EXPORT_SYMBOL(ecard_startfind);
EXPORT_SYMBOL(ecard_find);
EXPORT_SYMBOL(ecard_readchunk);
EXPORT_SYMBOL(ecard_address);
+EXPORT_SYMBOL(ecard_register_driver);
+EXPORT_SYMBOL(ecard_remove_driver);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)