11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * linux/arch/arm/kernel/ecard.c 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright 1995-2001 Russell King 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it under the terms of the GNU General Public License version 2 as 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * published by the Free Software Foundation. 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Find all installed expansion cards, and handle interrupts from them. 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Created from information from Acorns RiscOS3 PRMs 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 08-Dec-1996 RMK Added code for the 9'th expansion card - the ether 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * podule slot. 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 06-May-1997 RMK Added blacklist for cards whose loader doesn't work. 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 12-Sep-1997 RMK Created new handling of interrupt enables/disables 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - cards can now register their own routine to control 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * interrupts (recommended). 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 29-Sep-1997 RMK Expansion card interrupt hardware not being re-enabled 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * on reset from Linux. (Caused cards not to respond 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * under RiscOS without hard reset). 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 15-Feb-1998 RMK Added DMA support 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 12-Sep-1998 RMK Added EASI support 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 10-Jan-1999 RMK Run loaders in a simulated RISC OS environment. 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 17-Apr-1999 RMK Support for EASI Type C cycles. 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ECARD_C 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h> 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sched.h> 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h> 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/completion.h> 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/reboot.h> 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mm.h> 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h> 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/proc_fs.h> 409b0012126ae191c90c88df4b535b0f2ade70ecb6Alexey Dobriyan#include <linux/seq_file.h> 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/device.h> 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 4300431707be0cc1236ee08459367872b57da5be29Arjan van de Ven#include <linux/mutex.h> 44134c99e907ef2572cdaa148c191984b95d671981Eric W. Biederman#include <linux/kthread.h> 45b4ac08492d06e4f2cea24a5b2579b4b0a0f537ceRussell King#include <linux/irq.h> 4610bdaaa0fad620145cf10e2b573266b2d80b44deRussell King#include <linux/io.h> 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/dma.h> 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/ecard.h> 50a09e64fbc0094e3073dbb09c3b4bfe4ab669244bRussell King#include <mach/hardware.h> 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/irq.h> 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/mmu_context.h> 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/mach/irq.h> 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/tlbflush.h> 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 56c0b04d1b2c427629b2dbe066422a507ad855bf61Russell King#include "ecard.h" 57c0b04d1b2c427629b2dbe066422a507ad855bf61Russell King 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct ecard_request { 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void (*fn)(struct ecard_request *); 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ecard_t *ec; 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int address; 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int length; 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int use_loader; 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void *buffer; 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct completion *complete; 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct expcard_blacklist { 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short manufacturer; 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short product; 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const char *type; 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ecard_t *cards; 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ecard_t *slot_to_expcard[MAX_ECARDS]; 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int ectcr; 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* List of descriptions of cards which don't have an extended 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * identification, or chunk directories containing a description. 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct expcard_blacklist __initdata blacklist[] = { 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { MANU_ACORN, PROD_ACORN_ETHER1, "Acorn Ether1" } 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsasmlinkage extern int 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsecard_loader_reset(unsigned long base, loader_t loader); 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsasmlinkage extern int 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsecard_loader_read(int off, unsigned long base, loader_t loader); 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline unsigned short ecard_getu16(unsigned char *v) 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return v[0] | v[1] << 8; 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline signed long ecard_gets24(unsigned char *v) 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return v[0] | v[1] << 8 | v[2] << 16 | ((v[2] & 0x80) ? 0xff000000 : 0); 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline ecard_t *slot_to_ecard(unsigned int slot) 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return slot < MAX_ECARDS ? slot_to_expcard[slot] : NULL; 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ===================== Expansion card daemon ======================== */ 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Since the loader programs on the expansion cards need to be run 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * in a specific environment, create a separate task with this 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * environment up, and pass requests to this task as and when we 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * need to. 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This should allow 99% of loaders to be called from Linux. 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * From a security standpoint, we trust the card vendors. This 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * may be a misplaced trust. 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ecard_task_reset(struct ecard_request *req) 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct expansion_card *ec = req->ec; 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct resource *res; 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds res = ec->slot_no == 8 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ? &ec->resource[ECARD_RES_MEMC] 1245559bca8e66f968192a5416d953c88cc3389cb22Russell King : ec->easi 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ? &ec->resource[ECARD_RES_EASI] 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds : &ec->resource[ECARD_RES_IOCSYNC]; 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ecard_loader_reset(res->start, ec->loader); 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ecard_task_readbytes(struct ecard_request *req) 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct expansion_card *ec = req->ec; 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char *buf = req->buffer; 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int len = req->length; 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int off = req->address; 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ec->slot_no == 8) { 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __iomem *base = (void __iomem *) 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ec->resource[ECARD_RES_MEMC].start; 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The card maintains an index which increments the address 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * into a 4096-byte page on each access. We need to keep 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * track of the counter. 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds static unsigned int index; 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int page; 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds page = (off >> 12) * 4; 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (page > 256 * 4) 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds off &= 4095; 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we are reading offset 0, or our current index is 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * greater than the offset, reset the hardware index counter. 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (off == 0 || index > off) { 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writeb(0, base); 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds index = 0; 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Increment the hardware index counter until we get to the 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * required offset. The read bytes are discarded. 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (index < off) { 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds readb(base + page); 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds index += 1; 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (len--) { 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *buf++ = readb(base + page); 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds index += 1; 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 1795559bca8e66f968192a5416d953c88cc3389cb22Russell King unsigned long base = (ec->easi 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ? &ec->resource[ECARD_RES_EASI] 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds : &ec->resource[ECARD_RES_IOCSYNC])->start; 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __iomem *pbase = (void __iomem *)base; 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!req->use_loader || !ec->loader) { 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds off *= 4; 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (len--) { 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *buf++ = readb(pbase + off); 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds off += 4; 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while(len--) { 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The following is required by some 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * expansion card loader programs. 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *(unsigned long *)0x108 = 0; 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *buf++ = ecard_loader_read(off++, base, 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ec->loader); 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DECLARE_WAIT_QUEUE_HEAD(ecard_wait); 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct ecard_request *ecard_req; 20700431707be0cc1236ee08459367872b57da5be29Arjan van de Venstatic DEFINE_MUTEX(ecard_mutex); 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set up the expansion card daemon's page tables. 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ecard_init_pgtables(struct mm_struct *mm) 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct vm_area_struct vma; 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We want to set up the page tables for the following mapping: 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Virtual Physical 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0x03000000 0x03000000 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0x03010000 unmapped 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0x03210000 0x03210000 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0x03400000 unmapped 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0x08000000 0x08000000 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0x10000000 unmapped 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * FIXME: we don't follow this 100% yet. 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pgd_t *src_pgd, *dst_pgd; 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds src_pgd = pgd_offset(mm, (unsigned long)IO_BASE); 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dst_pgd = pgd_offset(mm, IO_START); 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(dst_pgd, src_pgd, sizeof(pgd_t) * (IO_SIZE / PGDIR_SIZE)); 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2345e4cdb83edd69d24b744cd88a9537680e905a518Russell King src_pgd = pgd_offset(mm, (unsigned long)EASI_BASE); 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dst_pgd = pgd_offset(mm, EASI_START); 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(dst_pgd, src_pgd, sizeof(pgd_t) * (EASI_SIZE / PGDIR_SIZE)); 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23981caaf2503be8fbb738ea4f124063dcc24958397Russell King vma.vm_flags = VM_EXEC; 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vma.vm_mm = mm; 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds flush_tlb_range(&vma, IO_START, IO_START + IO_SIZE); 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds flush_tlb_range(&vma, EASI_START, EASI_START + EASI_SIZE); 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ecard_init_mm(void) 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mm_struct * mm = mm_alloc(); 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mm_struct *active_mm = current->active_mm; 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!mm) 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds current->mm = mm; 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds current->active_mm = mm; 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds activate_mm(active_mm, mm); 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmdrop(active_mm); 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ecard_init_pgtables(mm); 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsecard_task(void * unused) 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Allocate a mm. We're not a lazy-TLB kernel task since we need 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to set page table entries where the user space would be. Note 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * that this also creates the page tables. Failure is not an 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * option here. 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ecard_init_mm()) 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds panic("kecardd: unable to alloc mm\n"); 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (1) { 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ecard_request *req; 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wait_event_interruptible(ecard_wait, ecard_req != NULL); 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req = xchg(&ecard_req, NULL); 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (req != NULL) { 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->fn(req); 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds complete(req->complete); 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Wake the expansion card daemon to action our request. 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * FIXME: The test here is not sufficient to detect if the 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * kcardd is running. 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ecard_call(struct ecard_request *req) 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2956e9a4738c9fadb7cbdcabc1e3b415159f3741ed9Peter Zijlstra DECLARE_COMPLETION_ONSTACK(completion); 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->complete = &completion; 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29900431707be0cc1236ee08459367872b57da5be29Arjan van de Ven mutex_lock(&ecard_mutex); 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ecard_req = req; 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wake_up(&ecard_wait); 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Now wait for kecardd to run. 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wait_for_completion(&completion); 30700431707be0cc1236ee08459367872b57da5be29Arjan van de Ven mutex_unlock(&ecard_mutex); 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ======================= Mid-level card control ===================== */ 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsecard_readbytes(void *addr, ecard_t *ec, int off, int len, int useld) 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ecard_request req; 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req.fn = ecard_task_readbytes; 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req.ec = ec; 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req.address = off; 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req.length = len; 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req.use_loader = useld; 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req.buffer = addr; 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ecard_call(&req); 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint ecard_readchunk(struct in_chunk_dir *cd, ecard_t *ec, int id, int num) 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ex_chunk_dir excd; 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int index = 16; 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int useld = 0; 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ec->cid.cd) 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while(1) { 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ecard_readbytes(&excd, ec, index, 8, useld); 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds index += 8; 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (c_id(&excd) == 0) { 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!useld && ec->loader) { 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds useld = 1; 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds index = 0; 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (c_id(&excd) == 0xf0) { /* link */ 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds index = c_start(&excd); 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (c_id(&excd) == 0x80) { /* loader */ 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ec->loader) { 3535cbded585d129d0226cb48ac4202b253c781be26Robert P. J. Day ec->loader = kmalloc(c_len(&excd), 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds GFP_KERNEL); 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ec->loader) 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ecard_readbytes(ec->loader, ec, 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (int)c_start(&excd), 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds c_len(&excd), useld); 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (c_id(&excd) == id && num-- == 0) 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (c_id(&excd) & 0x80) { 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (c_id(&excd) & 0x70) { 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0x70: 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ecard_readbytes((unsigned char *)excd.d.string, ec, 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (int)c_start(&excd), c_len(&excd), 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds useld); 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0x00: 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cd->start_offset = c_start(&excd); 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(cd->d.string, excd.d.string, 256); 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ======================= Interrupt control ============================ */ 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ecard_def_irq_enable(ecard_t *ec, int irqnr) 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ecard_def_irq_disable(ecard_t *ec, int irqnr) 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ecard_def_irq_pending(ecard_t *ec) 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return !ec->irqmask || readb(ec->irqaddr) & ec->irqmask; 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ecard_def_fiq_enable(ecard_t *ec, int fiqnr) 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds panic("ecard_def_fiq_enable called - impossible"); 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ecard_def_fiq_disable(ecard_t *ec, int fiqnr) 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds panic("ecard_def_fiq_disable called - impossible"); 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ecard_def_fiq_pending(ecard_t *ec) 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return !ec->fiqmask || readb(ec->fiqaddr) & ec->fiqmask; 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic expansioncard_ops_t ecard_default_ops = { 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ecard_def_irq_enable, 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ecard_def_irq_disable, 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ecard_def_irq_pending, 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ecard_def_fiq_enable, 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ecard_def_fiq_disable, 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ecard_def_fiq_pending 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Enable and disable interrupts from expansion cards. 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (interrupts are disabled for these functions). 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * They are not meant to be called directly, but via enable/disable_irq. 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4294a87bac4c9b3291ade91fe4fc1382f22dd9e9e91Lennert Buytenhekstatic void ecard_irq_unmask(struct irq_data *d) 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 431c402c110721ed53916595473aed1013acde95babRussell King ecard_t *ec = irq_data_get_irq_chip_data(d); 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ec) { 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ec->ops) 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ec->ops = &ecard_default_ops; 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ec->claimed && ec->ops->irqenable) 4384a87bac4c9b3291ade91fe4fc1382f22dd9e9e91Lennert Buytenhek ec->ops->irqenable(ec, d->irq); 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "ecard: rejecting request to " 4414a87bac4c9b3291ade91fe4fc1382f22dd9e9e91Lennert Buytenhek "enable IRQs for %d\n", d->irq); 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4454a87bac4c9b3291ade91fe4fc1382f22dd9e9e91Lennert Buytenhekstatic void ecard_irq_mask(struct irq_data *d) 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 447c402c110721ed53916595473aed1013acde95babRussell King ecard_t *ec = irq_data_get_irq_chip_data(d); 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ec) { 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ec->ops) 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ec->ops = &ecard_default_ops; 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ec->ops && ec->ops->irqdisable) 4544a87bac4c9b3291ade91fe4fc1382f22dd9e9e91Lennert Buytenhek ec->ops->irqdisable(ec, d->irq); 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 45838c677cb9a683c9d477f845484b74b0a1b23e1fbDavid Brownellstatic struct irq_chip ecard_chip = { 4594a87bac4c9b3291ade91fe4fc1382f22dd9e9e91Lennert Buytenhek .name = "ECARD", 4604a87bac4c9b3291ade91fe4fc1382f22dd9e9e91Lennert Buytenhek .irq_ack = ecard_irq_mask, 4614a87bac4c9b3291ade91fe4fc1382f22dd9e9e91Lennert Buytenhek .irq_mask = ecard_irq_mask, 4624a87bac4c9b3291ade91fe4fc1382f22dd9e9e91Lennert Buytenhek .irq_unmask = ecard_irq_unmask, 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid ecard_enablefiq(unsigned int fiqnr) 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ecard_t *ec = slot_to_ecard(fiqnr); 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ec) { 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ec->ops) 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ec->ops = &ecard_default_ops; 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ec->claimed && ec->ops->fiqenable) 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ec->ops->fiqenable(ec, fiqnr); 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "ecard: rejecting request to " 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "enable FIQs for %d\n", fiqnr); 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid ecard_disablefiq(unsigned int fiqnr) 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ecard_t *ec = slot_to_ecard(fiqnr); 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ec) { 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ec->ops) 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ec->ops = &ecard_default_ops; 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ec->ops->fiqdisable) 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ec->ops->fiqdisable(ec, fiqnr); 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ecard_dump_irq_state(void) 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ecard_t *ec; 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("Expansion card IRQ state:\n"); 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (ec = cards; ec; ec = ec->next) { 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ec->slot_no == 8) 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(" %d: %sclaimed, ", 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ec->slot_no, ec->claimed ? "" : "not "); 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ec->ops && ec->ops->irqpending && 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ec->ops != &ecard_default_ops) 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("irq %spending\n", 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ec->ops->irqpending(ec) ? "" : "not "); 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("irqaddr %p, mask = %02X, status = %02X\n", 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ec->irqaddr, ec->irqmask, readb(ec->irqaddr)); 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 51710dd5ce28d78e2440e8fa1135d17e33399d75340Russell Kingstatic void ecard_check_lockup(struct irq_desc *desc) 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds static unsigned long last; 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds static int lockup; 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If the timer interrupt has not run since the last million 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * unrecognised expansion card interrupts, then there is 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * something seriously wrong. Disable the expansion card 5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * interrupts so at least we can continue. 5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Maybe we ought to start a timer to re-enable them some time 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * later? 5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (last == jiffies) { 5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lockup += 1; 5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lockup > 1000000) { 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "\nInterrupt lockup detected - " 5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "disabling all expansion card interrupts\n"); 5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5374a87bac4c9b3291ade91fe4fc1382f22dd9e9e91Lennert Buytenhek desc->irq_data.chip->irq_mask(&desc->irq_data); 5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ecard_dump_irq_state(); 5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lockup = 0; 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we did not recognise the source of this interrupt, 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * warn the user, but don't flood the user with these messages. 5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!last || time_after(jiffies, last + 5*HZ)) { 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds last = jiffies; 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_WARNING "Unrecognised interrupt from backplane\n"); 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ecard_dump_irq_state(); 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 55510dd5ce28d78e2440e8fa1135d17e33399d75340Russell Kingecard_irq_handler(unsigned int irq, struct irq_desc *desc) 5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ecard_t *ec; 5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int called = 0; 5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5604a87bac4c9b3291ade91fe4fc1382f22dd9e9e91Lennert Buytenhek desc->irq_data.chip->irq_mask(&desc->irq_data); 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (ec = cards; ec; ec = ec->next) { 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int pending; 5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 56441569e370c5e1f5714a3386a3795efff99891f97Russell King if (!ec->claimed || !ec->irq || ec->slot_no == 8) 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ec->ops && ec->ops->irqpending) 5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pending = ec->ops->irqpending(ec); 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pending = ecard_default_ops.irqpending(ec); 5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pending) { 573d8aa0251f12546e9bd1e9ee1d9782d6492819a04Dmitry Eremin-Solenikov generic_handle_irq(ec->irq); 5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds called ++; 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5774a87bac4c9b3291ade91fe4fc1382f22dd9e9e91Lennert Buytenhek desc->irq_data.chip->irq_unmask(&desc->irq_data); 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (called == 0) 5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ecard_check_lockup(desc); 5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5831ace756628443ac41e8b6b409277fc4ee847472eRussell Kingstatic void __iomem *__ecard_address(ecard_t *ec, card_type_t type, card_speed_t speed) 5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 58506cf0b5468f204754f32e571f8415b20cedbe5f0Russell King void __iomem *address = NULL; 5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int slot = ec->slot_no; 5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ec->slot_no == 8) 58906cf0b5468f204754f32e571f8415b20cedbe5f0Russell King return ECARD_MEMC8_BASE; 5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ectcr &= ~(1 << slot); 5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (type) { 5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ECARD_MEMC: 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (slot < 4) 59606cf0b5468f204754f32e571f8415b20cedbe5f0Russell King address = ECARD_MEMC_BASE + (slot << 14); 5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ECARD_IOC: 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (slot < 4) 60106cf0b5468f204754f32e571f8415b20cedbe5f0Russell King address = ECARD_IOC_BASE + (slot << 14); 6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 60306cf0b5468f204754f32e571f8415b20cedbe5f0Russell King address = ECARD_IOC4_BASE + ((slot - 4) << 14); 6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (address) 60506cf0b5468f204754f32e571f8415b20cedbe5f0Russell King address += speed << 19; 6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ECARD_EASI: 60906cf0b5468f204754f32e571f8415b20cedbe5f0Russell King address = ECARD_EASI_BASE + (slot << 24); 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (speed == ECARD_FAST) 6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ectcr |= 1 << slot; 6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 61306cf0b5468f204754f32e571f8415b20cedbe5f0Russell King 6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef IOMD_ECTCR 6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iomd_writeb(ectcr, IOMD_ECTCR); 6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 62106cf0b5468f204754f32e571f8415b20cedbe5f0Russell King return address; 6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6249b0012126ae191c90c88df4b535b0f2ade70ecb6Alexey Dobriyanstatic int ecard_prints(struct seq_file *m, ecard_t *ec) 6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6269b0012126ae191c90c88df4b535b0f2ade70ecb6Alexey Dobriyan seq_printf(m, " %d: %s ", ec->slot_no, ec->easi ? "EASI" : " "); 6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ec->cid.id == 0) { 6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct in_chunk_dir incd; 6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6319b0012126ae191c90c88df4b535b0f2ade70ecb6Alexey Dobriyan seq_printf(m, "[%04X:%04X] ", 6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ec->cid.manufacturer, ec->cid.product); 6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ec->card_desc && ec->cid.cd && 6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ecard_readchunk(&incd, ec, 0xf5, 0)) { 6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ec->card_desc = kmalloc(strlen(incd.d.string)+1, GFP_KERNEL); 6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ec->card_desc) 6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strcpy((char *)ec->card_desc, incd.d.string); 6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6429b0012126ae191c90c88df4b535b0f2ade70ecb6Alexey Dobriyan seq_printf(m, "%s\n", ec->card_desc ? ec->card_desc : "*unknown*"); 6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 6449b0012126ae191c90c88df4b535b0f2ade70ecb6Alexey Dobriyan seq_printf(m, "Simple card %d\n", ec->cid.id); 6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6469b0012126ae191c90c88df4b535b0f2ade70ecb6Alexey Dobriyan return 0; 6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6499b0012126ae191c90c88df4b535b0f2ade70ecb6Alexey Dobriyanstatic int ecard_devices_proc_show(struct seq_file *m, void *v) 6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ecard_t *ec = cards; 6529b0012126ae191c90c88df4b535b0f2ade70ecb6Alexey Dobriyan 6539b0012126ae191c90c88df4b535b0f2ade70ecb6Alexey Dobriyan while (ec) { 6549b0012126ae191c90c88df4b535b0f2ade70ecb6Alexey Dobriyan ecard_prints(m, ec); 6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ec = ec->next; 6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6579b0012126ae191c90c88df4b535b0f2ade70ecb6Alexey Dobriyan return 0; 6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6609b0012126ae191c90c88df4b535b0f2ade70ecb6Alexey Dobriyanstatic int ecard_devices_proc_open(struct inode *inode, struct file *file) 6619b0012126ae191c90c88df4b535b0f2ade70ecb6Alexey Dobriyan{ 6629b0012126ae191c90c88df4b535b0f2ade70ecb6Alexey Dobriyan return single_open(file, ecard_devices_proc_show, NULL); 6639b0012126ae191c90c88df4b535b0f2ade70ecb6Alexey Dobriyan} 6649b0012126ae191c90c88df4b535b0f2ade70ecb6Alexey Dobriyan 6659b0012126ae191c90c88df4b535b0f2ade70ecb6Alexey Dobriyanstatic const struct file_operations bus_ecard_proc_fops = { 6669b0012126ae191c90c88df4b535b0f2ade70ecb6Alexey Dobriyan .owner = THIS_MODULE, 6679b0012126ae191c90c88df4b535b0f2ade70ecb6Alexey Dobriyan .open = ecard_devices_proc_open, 6689b0012126ae191c90c88df4b535b0f2ade70ecb6Alexey Dobriyan .read = seq_read, 6699b0012126ae191c90c88df4b535b0f2ade70ecb6Alexey Dobriyan .llseek = seq_lseek, 6709b0012126ae191c90c88df4b535b0f2ade70ecb6Alexey Dobriyan .release = single_release, 6719b0012126ae191c90c88df4b535b0f2ade70ecb6Alexey Dobriyan}; 6729b0012126ae191c90c88df4b535b0f2ade70ecb6Alexey Dobriyan 6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct proc_dir_entry *proc_bus_ecard_dir = NULL; 6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ecard_proc_init(void) 6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6779c37066d888bf6e1b96ad12304971b3ddeabbad0Alexey Dobriyan proc_bus_ecard_dir = proc_mkdir("bus/ecard", NULL); 6789b0012126ae191c90c88df4b535b0f2ade70ecb6Alexey Dobriyan proc_create("devices", 0, proc_bus_ecard_dir, &bus_ecard_proc_fops); 6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ec_set_resource(ec,nr,st,sz) \ 6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { \ 6833f9787046ea37a26170dc4439efa21f8d23a9978Kay Sievers (ec)->resource[nr].name = dev_name(&ec->dev); \ 6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (ec)->resource[nr].start = st; \ 6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (ec)->resource[nr].end = (st) + (sz) - 1; \ 6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (ec)->resource[nr].flags = IORESOURCE_MEM; \ 6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while (0) 6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __init ecard_free_card(struct expansion_card *ec) 6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < ECARD_NUM_RESOURCES; i++) 6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ec->resource[i].flags) 6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_resource(&ec->resource[i]); 6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(ec); 6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct expansion_card *__init ecard_alloc_card(int type, int slot) 7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct expansion_card *ec; 7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long base; 7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 706d2a02b93cf78205dd23226efb66481569900976eRussell King ec = kzalloc(sizeof(ecard_t), GFP_KERNEL); 7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ec) { 7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ec = ERR_PTR(-ENOMEM); 7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto nomem; 7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ec->slot_no = slot; 7135559bca8e66f968192a5416d953c88cc3389cb22Russell King ec->easi = type == ECARD_EASI; 71441569e370c5e1f5714a3386a3795efff99891f97Russell King ec->irq = 0; 71541569e370c5e1f5714a3386a3795efff99891f97Russell King ec->fiq = 0; 7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ec->dma = NO_DMA; 7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ec->ops = &ecard_default_ops; 7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7191d559e29138834bbcdf34ac072232bf543bfc4e0Kay Sievers dev_set_name(&ec->dev, "ecard%d", slot); 7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ec->dev.parent = NULL; 7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ec->dev.bus = &ecard_bus_type; 7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ec->dev.dma_mask = &ec->dma_mask; 7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ec->dma_mask = (u64)0xffffffff; 72469f4f331a0f78470f0bc42ba8db8d6cdd9cae4a9Russell King ec->dev.coherent_dma_mask = ec->dma_mask; 7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (slot < 4) { 7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ec_set_resource(ec, ECARD_RES_MEMC, 7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PODSLOT_MEMC_BASE + (slot << 14), 7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PODSLOT_MEMC_SIZE); 7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds base = PODSLOT_IOC0_BASE + (slot << 14); 7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds base = PODSLOT_IOC4_BASE + ((slot - 4) << 14); 7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_ARCH_RPC 7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (slot < 8) { 7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ec_set_resource(ec, ECARD_RES_EASI, 7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PODSLOT_EASI_BASE + (slot << 24), 7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PODSLOT_EASI_SIZE); 7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (slot == 8) { 7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ec_set_resource(ec, ECARD_RES_MEMC, NETSLOT_BASE, NETSLOT_SIZE); 7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i <= ECARD_RES_IOCSYNC - ECARD_RES_IOCSLOW; i++) 7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ec_set_resource(ec, i + ECARD_RES_IOCSLOW, 7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds base + (i << 19), PODSLOT_IOC_SIZE); 7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < ECARD_NUM_RESOURCES; i++) { 7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ec->resource[i].flags && 7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds request_resource(&iomem_resource, &ec->resource[i])) { 753fc3a8828b139c24aade3f9d608775e36c248f8f5Greg Kroah-Hartman dev_err(&ec->dev, "resource(s) not available\n"); 7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ec->resource[i].end -= ec->resource[i].start; 7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ec->resource[i].start = 0; 7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ec->resource[i].flags = 0; 7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nomem: 7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ec; 7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 764ff381d2223a30ee70752791fd9c3588d8f1cab77Yani Ioannoustatic ssize_t ecard_show_irq(struct device *dev, struct device_attribute *attr, char *buf) 7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct expansion_card *ec = ECARD_DEV(dev); 7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return sprintf(buf, "%u\n", ec->irq); 7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 770ff381d2223a30ee70752791fd9c3588d8f1cab77Yani Ioannoustatic ssize_t ecard_show_dma(struct device *dev, struct device_attribute *attr, char *buf) 7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct expansion_card *ec = ECARD_DEV(dev); 7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return sprintf(buf, "%u\n", ec->dma); 7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 776ff381d2223a30ee70752791fd9c3588d8f1cab77Yani Ioannoustatic ssize_t ecard_show_resources(struct device *dev, struct device_attribute *attr, char *buf) 7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct expansion_card *ec = ECARD_DEV(dev); 7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *str = buf; 7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < ECARD_NUM_RESOURCES; i++) 783c9e4143c4df08f7b54ba2099480266a6a1303f17Russell King str += sprintf(str, "%08x %08x %08lx\n", 7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ec->resource[i].start, 7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ec->resource[i].end, 7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ec->resource[i].flags); 7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return str - buf; 7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 791ff381d2223a30ee70752791fd9c3588d8f1cab77Yani Ioannoustatic ssize_t ecard_show_vendor(struct device *dev, struct device_attribute *attr, char *buf) 7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct expansion_card *ec = ECARD_DEV(dev); 7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return sprintf(buf, "%u\n", ec->cid.manufacturer); 7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 797ff381d2223a30ee70752791fd9c3588d8f1cab77Yani Ioannoustatic ssize_t ecard_show_device(struct device *dev, struct device_attribute *attr, char *buf) 7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct expansion_card *ec = ECARD_DEV(dev); 8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return sprintf(buf, "%u\n", ec->cid.product); 8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 803ff381d2223a30ee70752791fd9c3588d8f1cab77Yani Ioannoustatic ssize_t ecard_show_type(struct device *dev, struct device_attribute *attr, char *buf) 8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct expansion_card *ec = ECARD_DEV(dev); 8065559bca8e66f968192a5416d953c88cc3389cb22Russell King return sprintf(buf, "%s\n", ec->easi ? "EASI" : "IOC"); 8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct device_attribute ecard_dev_attrs[] = { 8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __ATTR(device, S_IRUGO, ecard_show_device, NULL), 8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __ATTR(dma, S_IRUGO, ecard_show_dma, NULL), 8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __ATTR(irq, S_IRUGO, ecard_show_irq, NULL), 8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __ATTR(resource, S_IRUGO, ecard_show_resources, NULL), 8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __ATTR(type, S_IRUGO, ecard_show_type, NULL), 8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __ATTR(vendor, S_IRUGO, ecard_show_vendor, NULL), 8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __ATTR_NULL, 8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint ecard_request_resources(struct expansion_card *ec) 8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, err = 0; 8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < ECARD_NUM_RESOURCES; i++) { 8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ecard_resource_end(ec, i) && 8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds !request_mem_region(ecard_resource_start(ec, i), 8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ecard_resource_len(ec, i), 8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ec->dev.driver->name)) { 8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = -EBUSY; 8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) { 8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (i--) 8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ecard_resource_end(ec, i)) 8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_mem_region(ecard_resource_start(ec, i), 8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ecard_resource_len(ec, i)); 8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(ecard_request_resources); 8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid ecard_release_resources(struct expansion_card *ec) 8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < ECARD_NUM_RESOURCES; i++) 8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ecard_resource_end(ec, i)) 8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_mem_region(ecard_resource_start(ec, i), 8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ecard_resource_len(ec, i)); 8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(ecard_release_resources); 8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 855c7b87f3d5037a35b5c7bb916ffc826be3fcb208dRussell Kingvoid ecard_setirq(struct expansion_card *ec, const struct expansion_card_ops *ops, void *irq_data) 856c7b87f3d5037a35b5c7bb916ffc826be3fcb208dRussell King{ 857c7b87f3d5037a35b5c7bb916ffc826be3fcb208dRussell King ec->irq_data = irq_data; 858c7b87f3d5037a35b5c7bb916ffc826be3fcb208dRussell King barrier(); 859c7b87f3d5037a35b5c7bb916ffc826be3fcb208dRussell King ec->ops = ops; 860c7b87f3d5037a35b5c7bb916ffc826be3fcb208dRussell King} 861c7b87f3d5037a35b5c7bb916ffc826be3fcb208dRussell KingEXPORT_SYMBOL(ecard_setirq); 862c7b87f3d5037a35b5c7bb916ffc826be3fcb208dRussell King 86310bdaaa0fad620145cf10e2b573266b2d80b44deRussell Kingvoid __iomem *ecardm_iomap(struct expansion_card *ec, unsigned int res, 86410bdaaa0fad620145cf10e2b573266b2d80b44deRussell King unsigned long offset, unsigned long maxsize) 86510bdaaa0fad620145cf10e2b573266b2d80b44deRussell King{ 86610bdaaa0fad620145cf10e2b573266b2d80b44deRussell King unsigned long start = ecard_resource_start(ec, res); 86710bdaaa0fad620145cf10e2b573266b2d80b44deRussell King unsigned long end = ecard_resource_end(ec, res); 86810bdaaa0fad620145cf10e2b573266b2d80b44deRussell King 86910bdaaa0fad620145cf10e2b573266b2d80b44deRussell King if (offset > (end - start)) 87010bdaaa0fad620145cf10e2b573266b2d80b44deRussell King return NULL; 87110bdaaa0fad620145cf10e2b573266b2d80b44deRussell King 87210bdaaa0fad620145cf10e2b573266b2d80b44deRussell King start += offset; 87310bdaaa0fad620145cf10e2b573266b2d80b44deRussell King if (maxsize && end - start > maxsize) 87410bdaaa0fad620145cf10e2b573266b2d80b44deRussell King end = start + maxsize; 87510bdaaa0fad620145cf10e2b573266b2d80b44deRussell King 87610bdaaa0fad620145cf10e2b573266b2d80b44deRussell King return devm_ioremap(&ec->dev, start, end - start); 87710bdaaa0fad620145cf10e2b573266b2d80b44deRussell King} 87810bdaaa0fad620145cf10e2b573266b2d80b44deRussell KingEXPORT_SYMBOL(ecardm_iomap); 87910bdaaa0fad620145cf10e2b573266b2d80b44deRussell King 8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Probe for an expansion card. 8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If bit 1 of the first byte of the card is set, then the 8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * card does not exist. 8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 886b4ac08492d06e4f2cea24a5b2579b4b0a0f537ceRussell Kingstatic int __init ecard_probe(int slot, unsigned irq, card_type_t type) 8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ecard_t **ecp; 8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ecard_t *ec; 8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ex_ecid cid; 8911ace756628443ac41e8b6b409277fc4ee847472eRussell King void __iomem *addr; 8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, rc; 8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ec = ecard_alloc_card(type, slot); 8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (IS_ERR(ec)) { 8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = PTR_ERR(ec); 8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto nomem; 8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -ENODEV; 9011ace756628443ac41e8b6b409277fc4ee847472eRussell King if ((addr = __ecard_address(ec, type, ECARD_SYNC)) == NULL) 9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto nodev; 9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cid.r_zero = 1; 9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ecard_readbytes(&cid, ec, 0, 16, 0); 9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cid.r_zero) 9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto nodev; 9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ec->cid.id = cid.r_id; 9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ec->cid.cd = cid.r_cd; 9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ec->cid.is = cid.r_is; 9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ec->cid.w = cid.r_w; 9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ec->cid.manufacturer = ecard_getu16(cid.r_manu); 9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ec->cid.product = ecard_getu16(cid.r_prod); 9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ec->cid.country = cid.r_country; 9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ec->cid.irqmask = cid.r_irqmask; 9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ec->cid.irqoff = ecard_gets24(cid.r_irqoff); 9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ec->cid.fiqmask = cid.r_fiqmask; 9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ec->cid.fiqoff = ecard_gets24(cid.r_fiqoff); 9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ec->fiqaddr = 9211ace756628443ac41e8b6b409277fc4ee847472eRussell King ec->irqaddr = addr; 9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ec->cid.is) { 9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ec->irqmask = ec->cid.irqmask; 9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ec->irqaddr += ec->cid.irqoff; 9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ec->fiqmask = ec->cid.fiqmask; 9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ec->fiqaddr += ec->cid.fiqoff; 9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ec->irqmask = 1; 9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ec->fiqmask = 4; 9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 933eeea82ff4a3aebed9f501f04ca7b65d3605f247aAhmed S. Darwish for (i = 0; i < ARRAY_SIZE(blacklist); i++) 9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (blacklist[i].manufacturer == ec->cid.manufacturer && 9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds blacklist[i].product == ec->cid.product) { 9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ec->card_desc = blacklist[i].type; 9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 940b4ac08492d06e4f2cea24a5b2579b4b0a0f537ceRussell King ec->irq = irq; 941b4ac08492d06e4f2cea24a5b2579b4b0a0f537ceRussell King 9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * hook the interrupt handlers 9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (slot < 8) { 946f38c02f3b338651e145aac2889ba976baf6b28b3Thomas Gleixner irq_set_chip_and_handler(ec->irq, &ecard_chip, 947f38c02f3b338651e145aac2889ba976baf6b28b3Thomas Gleixner handle_level_irq); 948c402c110721ed53916595473aed1013acde95babRussell King irq_set_chip_data(ec->irq, ec); 9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_irq_flags(ec->irq, IRQF_VALID); 9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_ARCH_RPC 9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* On RiscPC, only first two slots have DMA capability */ 9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (slot < 2) 9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ec->dma = 2 + slot; 9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (ecp = &cards; *ecp; ecp = &(*ecp)->next); 9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *ecp = ec; 9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slot_to_expcard[slot] = ec; 9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9635f07809e93b4c05516d85a3f2770b1a77115eb70Arnd Bergmann rc = device_register(&ec->dev); 9645f07809e93b4c05516d85a3f2770b1a77115eb70Arnd Bergmann if (rc) 9655f07809e93b4c05516d85a3f2770b1a77115eb70Arnd Bergmann goto nodev; 9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nodev: 9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ecard_free_card(ec); 9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nomem: 9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Initialise the expansion card system. 9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Locate all hardware - interrupt management and 9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * actual cards. 9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init ecard_init(void) 9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 982134c99e907ef2572cdaa148c191984b95d671981Eric W. Biederman struct task_struct *task; 983530c2eaa6ab69fca94911f2aa74fe3e11b1cd19bRussell King int slot, irqbase; 984b4ac08492d06e4f2cea24a5b2579b4b0a0f537ceRussell King 985b4ac08492d06e4f2cea24a5b2579b4b0a0f537ceRussell King irqbase = irq_alloc_descs(-1, 0, 8, -1); 986b4ac08492d06e4f2cea24a5b2579b4b0a0f537ceRussell King if (irqbase < 0) 987b4ac08492d06e4f2cea24a5b2579b4b0a0f537ceRussell King return irqbase; 9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 989134c99e907ef2572cdaa148c191984b95d671981Eric W. Biederman task = kthread_run(ecard_task, NULL, "kecardd"); 990134c99e907ef2572cdaa148c191984b95d671981Eric W. Biederman if (IS_ERR(task)) { 991e6aeb47da6e02ec9807d30a368d4fc37972b022fRussell King printk(KERN_ERR "Ecard: unable to create kernel thread: %ld\n", 992134c99e907ef2572cdaa148c191984b95d671981Eric W. Biederman PTR_ERR(task)); 993b4ac08492d06e4f2cea24a5b2579b4b0a0f537ceRussell King irq_free_descs(irqbase, 8); 994134c99e907ef2572cdaa148c191984b95d671981Eric W. Biederman return PTR_ERR(task); 9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("Probing expansion cards\n"); 9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (slot = 0; slot < 8; slot ++) { 1000b4ac08492d06e4f2cea24a5b2579b4b0a0f537ceRussell King if (ecard_probe(slot, irqbase + slot, ECARD_EASI) == -ENODEV) 1001b4ac08492d06e4f2cea24a5b2579b4b0a0f537ceRussell King ecard_probe(slot, irqbase + slot, ECARD_IOC); 10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1004b4ac08492d06e4f2cea24a5b2579b4b0a0f537ceRussell King ecard_probe(8, 11, ECARD_IOC); 10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1006530c2eaa6ab69fca94911f2aa74fe3e11b1cd19bRussell King irq_set_chained_handler(IRQ_EXPANSIONCARD, ecard_irq_handler); 10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ecard_proc_init(); 10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssubsys_initcall(ecard_init); 10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ECARD "bus" 10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const struct ecard_id * 10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsecard_match_device(const struct ecard_id *ids, struct expansion_card *ec) 10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; ids[i].manufacturer != 65535; i++) 10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ec->cid.manufacturer == ids[i].manufacturer && 10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ec->cid.product == ids[i].product) 10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ids + i; 10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ecard_drv_probe(struct device *dev) 10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct expansion_card *ec = ECARD_DEV(dev); 10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ecard_driver *drv = ECARD_DRV(dev->driver); 10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const struct ecard_id *id; 10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds id = ecard_match_device(drv->id_table, ec); 10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10409ecba1f288d2cf87d1b6a9401d5ce17464eb776dRussell King ec->claimed = 1; 10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = drv->probe(ec, id); 10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret) 10439ecba1f288d2cf87d1b6a9401d5ce17464eb776dRussell King ec->claimed = 0; 10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ecard_drv_remove(struct device *dev) 10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct expansion_card *ec = ECARD_DEV(dev); 10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ecard_driver *drv = ECARD_DRV(dev->driver); 10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds drv->remove(ec); 10539ecba1f288d2cf87d1b6a9401d5ce17464eb776dRussell King ec->claimed = 0; 10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1055c7b87f3d5037a35b5c7bb916ffc826be3fcb208dRussell King /* 1056c7b87f3d5037a35b5c7bb916ffc826be3fcb208dRussell King * Restore the default operations. We ensure that the 1057c7b87f3d5037a35b5c7bb916ffc826be3fcb208dRussell King * ops are set before we change the data. 1058c7b87f3d5037a35b5c7bb916ffc826be3fcb208dRussell King */ 1059c7b87f3d5037a35b5c7bb916ffc826be3fcb208dRussell King ec->ops = &ecard_default_ops; 1060c7b87f3d5037a35b5c7bb916ffc826be3fcb208dRussell King barrier(); 1061c7b87f3d5037a35b5c7bb916ffc826be3fcb208dRussell King ec->irq_data = NULL; 1062c7b87f3d5037a35b5c7bb916ffc826be3fcb208dRussell King 10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Before rebooting, we must make sure that the expansion card is in a 10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * sensible state, so it can be re-detected. This means that the first 10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * page of the ROM must be visible. We call the expansion cards reset 10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * handler, if any. 10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ecard_drv_shutdown(struct device *dev) 10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct expansion_card *ec = ECARD_DEV(dev); 10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ecard_driver *drv = ECARD_DRV(dev->driver); 10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ecard_request req; 10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1078e08b754161d6de4f91e2d3c805f350b35a95d8b8Russell King if (dev->driver) { 1079e08b754161d6de4f91e2d3c805f350b35a95d8b8Russell King if (drv->shutdown) 1080e08b754161d6de4f91e2d3c805f350b35a95d8b8Russell King drv->shutdown(ec); 10819ecba1f288d2cf87d1b6a9401d5ce17464eb776dRussell King ec->claimed = 0; 1082e08b754161d6de4f91e2d3c805f350b35a95d8b8Russell King } 10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If this card has a loader, call the reset handler. 10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ec->loader) { 10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req.fn = ecard_task_reset; 10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req.ec = ec; 10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ecard_call(&req); 10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint ecard_register_driver(struct ecard_driver *drv) 10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds drv->drv.bus = &ecard_bus_type; 10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return driver_register(&drv->drv); 10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid ecard_remove_driver(struct ecard_driver *drv) 11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds driver_unregister(&drv->drv); 11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ecard_match(struct device *_dev, struct device_driver *_drv) 11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct expansion_card *ec = ECARD_DEV(_dev); 11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ecard_driver *drv = ECARD_DRV(_drv); 11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (drv->id_table) { 11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = ecard_match_device(drv->id_table, ec) != NULL; 11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = ec->cid.id == drv->id; 11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct bus_type ecard_bus_type = { 11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .name = "ecard", 11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .dev_attrs = ecard_dev_attrs, 11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .match = ecard_match, 1125e08b754161d6de4f91e2d3c805f350b35a95d8b8Russell King .probe = ecard_drv_probe, 1126e08b754161d6de4f91e2d3c805f350b35a95d8b8Russell King .remove = ecard_drv_remove, 1127e08b754161d6de4f91e2d3c805f350b35a95d8b8Russell King .shutdown = ecard_drv_shutdown, 11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ecard_bus_init(void) 11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return bus_register(&ecard_bus_type); 11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldspostcore_initcall(ecard_bus_init); 11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(ecard_readchunk); 11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(ecard_register_driver); 11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(ecard_remove_driver); 11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(ecard_bus_type); 1141