/*
* linux/arch/arm/kernel/ecard.c
*
* Copyright 1995-2001 Russell King
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Find all installed expansion cards, and handle interrupts from them.
*
* Created from information from Acorns RiscOS3 PRMs
*
* 08-Dec-1996 RMK Added code for the 9'th expansion card - the ether
* podule slot.
* 06-May-1997 RMK Added blacklist for cards whose loader doesn't work.
* 12-Sep-1997 RMK Created new handling of interrupt enables/disables
* - cards can now register their own routine to control
* interrupts (recommended).
* 29-Sep-1997 RMK Expansion card interrupt hardware not being re-enabled
* on reset from Linux. (Caused cards not to respond
* under RiscOS without hard reset).
* 15-Feb-1998 RMK Added DMA support
* 12-Sep-1998 RMK Added EASI support
* 10-Jan-1999 RMK Run loaders in a simulated RISC OS environment.
* 17-Apr-1999 RMK Support for EASI Type C cycles.
*/
#define ECARD_C
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/completion.h>
#include <linux/reboot.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/device.h>
#include <linux/init.h>
#include <linux/mutex.h>
#include <linux/kthread.h>
#include <linux/irq.h>
#include <linux/io.h>
#include <asm/dma.h>
#include <asm/ecard.h>
#include <mach/hardware.h>
#include <asm/irq.h>
#include <asm/mmu_context.h>
#include <asm/mach/irq.h>
#include <asm/tlbflush.h>
#include "ecard.h"
struct ecard_request {
void (*fn)(struct ecard_request *);
ecard_t *ec;
unsigned int address;
unsigned int length;
unsigned int use_loader;
void *buffer;
struct completion *complete;
};
struct expcard_blacklist {
unsigned short manufacturer;
unsigned short product;
const char *type;
};
static ecard_t *cards;
static ecard_t *slot_to_expcard[MAX_ECARDS];
static unsigned int ectcr;
/* List of descriptions of cards which don't have an extended
* identification, or chunk directories containing a description.
*/
static struct expcard_blacklist __initdata blacklist[] = {
{ MANU_ACORN, PROD_ACORN_ETHER1, "Acorn Ether1" }
};
asmlinkage extern int
ecard_loader_reset(unsigned long base, loader_t loader);
asmlinkage extern int
ecard_loader_read(int off, unsigned long base, loader_t loader);
static inline unsigned short ecard_getu16(unsigned char *v)
{
return v[0] | v[1] << 8;
}
static inline signed long ecard_gets24(unsigned char *v)
{
return v[0] | v[1] << 8 | v[2] << 16 | ((v[2] & 0x80) ? 0xff000000 : 0);
}
static inline ecard_t *slot_to_ecard(unsigned int slot)
{
return slot < MAX_ECARDS ? slot_to_expcard[slot] : NULL;
}
/* ===================== Expansion card daemon ======================== */
/*
* Since the loader programs on the expansion cards need to be run
* in a specific environment, create a separate task with this
* environment up, and pass requests to this task as and when we
* need to.
*
* This should allow 99% of loaders to be called from Linux.
*
* From a security standpoint, we trust the card vendors. This
* may be a misplaced trust.
*/
static void ecard_task_reset(struct ecard_request *req)
{
struct expansion_card *ec = req->ec;
struct resource *res;
res = ec->slot_no == 8
? &ec->resource[ECARD_RES_MEMC]
: ec->easi
? &ec->resource[ECARD_RES_EASI]
: &ec->resource[ECARD_RES_IOCSYNC];
ecard_loader_reset(res->start, ec->loader);
}
static void ecard_task_readbytes(struct ecard_request *req)
{
struct expansion_card *ec = req->ec;
unsigned char *buf = req->buffer;
unsigned int len = req->