// SPDX-License-Identifier: GPL-2.0-or-later /* * ISA Plug & Play support * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * * 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>
*/
if (old_rdp) {
release_region(old_rdp, 1);
old_rdp = 0;
} while (rdp <= 0x3ff) { /* * We cannot use NE2000 probe spaces for ISAPnP or we * will lock up machines.
*/ if ((rdp < 0x280 || rdp > 0x380)
&& request_region(rdp, 1, "ISAPnP")) {
isapnp_rdp = rdp;
old_rdp = rdp; return 0;
}
rdp += RDP_STEP;
} return -1;
}
/* Set read port address */ staticinlinevoid isapnp_set_rdp(void)
{
isapnp_write_byte(0x00, isapnp_rdp >> 2);
udelay(100);
}
/* * Perform an isolation. The port selection code now tries to avoid * "dangerous to read" ports.
*/ staticint __init isapnp_isolate_rdp_select(void)
{
isapnp_wait();
isapnp_key();
/* Control: reset CSN and conditionally everything else too */
isapnp_write_byte(0x02, isapnp_reset ? 0x05 : 0x04);
mdelay(2);
isapnp_wait();
isapnp_key();
isapnp_wake(0x00);
if (isapnp_next_rdp() < 0) {
isapnp_wait(); return -1;
}
/* * Isolate (assign uniqued CSN) to all ISA PnP devices.
*/ staticint __init isapnp_isolate(void)
{ unsignedchar checksum = 0x6a; unsignedchar chksum = 0x00; unsignedchar bit = 0x00; int data; int csn = 0; int i; int iteration = 1;
isapnp_rdp = 0x213; if (isapnp_isolate_rdp_select() < 0) return -1;
while (1) { for (i = 1; i <= 64; i++) {
data = read_data() << 8;
udelay(250);
data = data | read_data();
udelay(250); if (data == 0x55aa)
bit = 0x01;
checksum =
((((checksum ^ (checksum >> 1)) & 0x01) ^ bit) << 7)
| (checksum >> 1);
bit = 0x00;
} for (i = 65; i <= 72; i++) {
data = read_data() << 8;
udelay(250);
data = data | read_data();
udelay(250); if (data == 0x55aa)
chksum |= (1 << (i - 65));
} if (checksum != 0x00 && checksum == chksum) {
csn++;
int isapnp_cfg_begin(int csn, int logdev)
{ if (csn < 1 || csn > isapnp_csn_count || logdev > 10) return -EINVAL;
mutex_lock(&isapnp_cfg_mutex);
isapnp_wait();
isapnp_key();
isapnp_wake(csn); #if 0 /* to avoid malfunction when the isapnptools package is used */ /* we must set RDP to our value again */ /* it is possible to set RDP only in the isolation phase */ /* Jens Thoms Toerring <Jens.Toerring@physik.fu-berlin.de> */
isapnp_write_byte(0x02, 0x04); /* clear CSN of card */
mdelay(2); /* is this necessary? */
isapnp_wake(csn); /* bring card into sleep state */
isapnp_wake(0); /* bring card into isolation state */
isapnp_set_rdp(); /* reset the RDP port */
udelay(1000); /* delay 1000us */
isapnp_write_byte(0x06, csn); /* reset CSN to previous value */
udelay(250); /* is this necessary? */ #endif if (logdev >= 0)
isapnp_device(logdev); return 0;
}
int isapnp_cfg_end(void)
{
isapnp_wait();
mutex_unlock(&isapnp_cfg_mutex); return 0;
}
for (i = 0; i < ISAPNP_MAX_PORT; i++) {
ret = isapnp_read_word(ISAPNP_CFG_PORT + (i << 1));
pnp_add_io_resource(dev, ret, ret,
ret == 0 ? IORESOURCE_DISABLED : 0);
} for (i = 0; i < ISAPNP_MAX_MEM; i++) {
ret = isapnp_read_word(ISAPNP_CFG_MEM + (i << 3)) << 8;
pnp_add_mem_resource(dev, ret, ret,
ret == 0 ? IORESOURCE_DISABLED : 0);
} for (i = 0; i < ISAPNP_MAX_IRQ; i++) {
ret = isapnp_read_word(ISAPNP_CFG_IRQ + (i << 1)) >> 8;
pnp_add_irq_resource(dev, ret,
ret == 0 ? IORESOURCE_DISABLED : 0);
} for (i = 0; i < ISAPNP_MAX_DMA; i++) {
ret = isapnp_read_byte(ISAPNP_CFG_DMA + i);
pnp_add_dma_resource(dev, ret,
ret == 4 ? IORESOURCE_DISABLED : 0);
}
__end:
isapnp_cfg_end(); return 0;
}
staticint isapnp_set_resources(struct pnp_dev *dev)
{ struct resource *res; int tmp;
pnp_dbg(&dev->dev, "set resources\n");
isapnp_cfg_begin(dev->card->number, dev->number);
dev->active = 1; for (tmp = 0; tmp < ISAPNP_MAX_PORT; tmp++) {
res = pnp_get_resource(dev, IORESOURCE_IO, tmp); if (pnp_resource_enabled(res)) {
pnp_dbg(&dev->dev, " set io %d to %#llx\n",
tmp, (unsignedlonglong) res->start);
isapnp_write_word(ISAPNP_CFG_PORT + (tmp << 1),
res->start);
}
} for (tmp = 0; tmp < ISAPNP_MAX_IRQ; tmp++) {
res = pnp_get_resource(dev, IORESOURCE_IRQ, tmp); if (pnp_resource_enabled(res)) { int irq = res->start; if (irq == 2)
irq = 9;
pnp_dbg(&dev->dev, " set irq %d to %d\n", tmp, irq);
isapnp_write_byte(ISAPNP_CFG_IRQ + (tmp << 1), irq);
}
} for (tmp = 0; tmp < ISAPNP_MAX_DMA; tmp++) {
res = pnp_get_resource(dev, IORESOURCE_DMA, tmp); if (pnp_resource_enabled(res)) {
pnp_dbg(&dev->dev, " set dma %d to %lld\n",
tmp, (unsignedlonglong) res->start);
isapnp_write_byte(ISAPNP_CFG_DMA + tmp, res->start);
}
} for (tmp = 0; tmp < ISAPNP_MAX_MEM; tmp++) {
res = pnp_get_resource(dev, IORESOURCE_MEM, tmp); if (pnp_resource_enabled(res)) {
pnp_dbg(&dev->dev, " set mem %d to %#llx\n",
tmp, (unsignedlonglong) res->start);
isapnp_write_word(ISAPNP_CFG_MEM + (tmp << 3),
(res->start >> 8) & 0xffff);
}
} /* FIXME: We aren't handling 32bit mems properly here */
isapnp_activate(dev->number);
isapnp_cfg_end(); return 0;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.