/*
* ISA Plug & Play support
* Copyright (c) by Jaroslav Kysela <perex@suse.cz>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Changelog:
* 2000-01-01 Added quirks handling for buggy hardware
* Peter Denison <peterd@pnd-pc.demon.co.uk>
* 2000-06-14 Added isapnp_probe_devs() and isapnp_activate_dev()
* Christoph Hellwig <hch@infradead.org>
* 2001-06-03 Added release_region calls to correspond with
* request_region calls when a failure occurs. Also
* added KERN_* constants to printk() calls.
* 2001-11-07 Added isapnp_{,un}register_driver calls along the lines
* of the pci driver interface
* Kai Germaschewski <kai.germaschewski@gmx.de>
* 2002-06-06 Made the use of dma channel 0 configurable
* Gerald Teschl <gerald.teschl@univie.ac.at>
* 2002-10-06 Ported to PnP Layer - Adam Belay <ambx1@neo.rr.com>
* 2003-08-11 Resource Management Updates - Adam Belay <ambx1@neo.rr.com>
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/isapnp.h>
#include <asm/io.h>
#if 0
#define ISAPNP_REGION_OK
#endif
#if 0
#define ISAPNP_DEBUG
#endif
int isapnp_disable; /* Disable ISA PnP */
static int isapnp_rdp; /* Read Data Port */
static int isapnp_reset = 1; /* reset all PnP cards (deactivate) */
static int isapnp_verbose = 1; /* verbose mode */
MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
MODULE_DESCRIPTION("Generic ISA Plug & Play support");
module_param(isapnp_disable, int, 0);
MODULE_PARM_DESC(isapnp_disable, "ISA Plug & Play disable");
module_param(isapnp_rdp, int, 0);
MODULE_PARM_DESC(isapnp_rdp, "ISA Plug & Play read data port");
module_param(isapnp_reset, int, 0);
MODULE_PARM_DESC(isapnp_reset, "ISA Plug & Play reset all cards");
module_param(isapnp_verbose, int, 0);
MODULE_PARM_DESC(isapnp_verbose, "ISA Plug & Play verbose mode");
MODULE_LICENSE("GPL");
#define _PIDXR 0x279
#define _PNPWRP 0xa79
/* short tags */
#define _STAG_PNPVERNO 0x01
#define _STAG_LOGDEVID 0x02
#define _STAG_COMPATDEVID 0x03
#define _STAG_IRQ 0x04
#define _STAG_DMA 0x05
#define _STAG_STARTDEP 0x06
#define _STAG_ENDDEP 0x07
#define _STAG_IOPORT 0x08
#define _STAG_FIXEDIO 0x09
#define _STAG_VENDOR 0x0e
#define _STAG_END 0x0f
/* long tags */
#define _LTAG_MEMRANGE 0x81
#define _LTAG_ANSISTR 0x82
#define _LTAG_UNICODESTR 0x83
#define _LTAG_VENDOR 0x84
#define _LTAG_MEM32RANGE 0x85
#define _LTAG_FIXEDMEM32RANGE 0x86
static unsigned char isapnp_checksum_value;
static DECLARE_MUTEX(isapnp_cfg_mutex);
static int isapnp_detected;
static int isapnp_csn_count;
/* some prototypes */
static inline void write_data(unsigned char x)
{
outb(x, _PNPWRP);
}
static inline void write_address(unsigned char x)
{
outb(x, _PIDXR);
udelay(20);
}
static inline unsigned char read_data(void)
{
unsigned char val = inb(isapnp_rdp);
return val;
}
unsigned char isapnp_read_byte(unsigned char idx)
{
write_address(idx);
return read_data();
}
static unsigned short isapnp_read_word(unsigned char idx)
{
unsigned short val;
val = isapnp_read_byte(idx);
val = (val << 8) + isapnp_read_byte(idx+1);
return val;
}
void isapnp_write_byte(unsigned char idx, unsigned char val)
{
write_address(idx);
write_data(val);
}
static void isapnp_write_word(unsigned char idx, unsigned short val)
{
isapnp_write_byte(idx, val >> 8);
isapnp_write_byte(idx+1, val);
}
static void isapnp_key(void)
{
unsigned char code = 0x6a, msb;
int i;
mdelay(1);
write_address(0x00);
write_address(0x00);
write_address(code);
for (i = 1; i < 32; i++) {
msb = ((code & 0x01) ^ ((code