11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This software may be used and distributed according to the terms 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * of the GNU General Public License, incorporated herein by reference. 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h> 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h> 11d43c36dc6b357fa1806800f18aa30123c747a6d1Alexey Dobriyan#include <linux/sched.h> 125a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "includes.h" 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "hardware.h" 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "card.h" 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("ISDN4Linux: Driver for Spellcaster card"); 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Spellcaster Telecommunications Inc."); 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsboard *sc_adapter[MAX_CARDS]; 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint cinst; 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic char devname[] = "scX"; 25e3ca5e762c2aca373f1762cbc622ebe20fd20869Adrian Bunkstatic const char version[] = "2.0b1"; 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27e3ca5e762c2aca373f1762cbc622ebe20fd20869Adrian Bunkstatic const char *boardname[] = { "DataCommute/BRI", "DataCommute/PRI", "TeleCommute/BRI" }; 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* insmod set parameters */ 30475be4d85a274d0961593db41cf85689db1d583cJoe Perchesstatic unsigned int io[] = {0, 0, 0, 0}; 31475be4d85a274d0961593db41cf85689db1d583cJoe Perchesstatic unsigned char irq[] = {0, 0, 0, 0}; 32475be4d85a274d0961593db41cf85689db1d583cJoe Perchesstatic unsigned long ram[] = {0, 0, 0, 0}; 3390ab5ee94171b3e28de6bb42ee30b527014e0be7Rusty Russellstatic bool do_reset = 0; 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param_array(io, int, NULL, 0); 36b9e48de110ec64bdfd4b83358d0e286551bb110cGeert Uytterhoevenmodule_param_array(irq, byte, NULL, 0); 37b9e48de110ec64bdfd4b83358d0e286551bb110cGeert Uytterhoevenmodule_param_array(ram, long, NULL, 0); 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(do_reset, bool, 0); 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40e3ca5e762c2aca373f1762cbc622ebe20fd20869Adrian Bunkstatic int identify_board(unsigned long, unsigned int); 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init sc_init(void) 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int b = -1; 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, j; 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int status = -ENODEV; 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long memsize = 0; 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long features = 0; 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds isdn_if *interface; 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char channels; 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char pgport; 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long magic; 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int model; 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int last_base = IOBASE_MIN; 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int probe_exhasted = 0; 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef MODULE 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pr_info("SpellCaster ISA ISDN Adapter Driver rev. %s Loaded\n", version); 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pr_info("SpellCaster ISA ISDN Adapter Driver rev. %s\n", version); 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pr_info("Copyright (C) 1996 SpellCaster Telecommunications Inc.\n"); 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 65475be4d85a274d0961593db41cf85689db1d583cJoe Perches while (b++ < MAX_CARDS - 1) { 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pr_debug("Probing for adapter #%d\n", b); 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Initialize reusable variables 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds model = -1; 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds magic = 0; 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds channels = 0; 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pgport = 0; 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 75475be4d85a274d0961593db41cf85689db1d583cJoe Perches /* 76475be4d85a274d0961593db41cf85689db1d583cJoe Perches * See if we should probe for IO base 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pr_debug("I/O Base for board %d is 0x%x, %s probe\n", b, io[b], 79475be4d85a274d0961593db41cf85689db1d583cJoe Perches io[b] == 0 ? "will" : "won't"); 80475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (io[b]) { 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * No, I/O Base has been provided 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 84475be4d85a274d0961593db41cf85689db1d583cJoe Perches for (i = 0; i < MAX_IO_REGS - 1; i++) { 85475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (!request_region(io[b] + i * 0x400, 1, "sc test")) { 86fb911ee849756fc6c609dddded92d9207ff3fb29Peter Osterlund pr_debug("request_region for 0x%x failed\n", io[b] + i * 0x400); 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds io[b] = 0; 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_region(io[b] + i * 0x400, 1); 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Confirm the I/O Address with a test 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 96475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (io[b] == 0) { 9776fd020937f2d09f76a4cd8dbae1f3bec640ff0bJeff Garzik pr_debug("I/O Address invalid.\n"); 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0x18, io[b] + 0x400 * EXP_PAGE0); 102475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (inb(io[b] + 0x400 * EXP_PAGE0) != 0x18) { 10376fd020937f2d09f76a4cd8dbae1f3bec640ff0bJeff Garzik pr_debug("I/O Base 0x%x fails test\n", 10476fd020937f2d09f76a4cd8dbae1f3bec640ff0bJeff Garzik io[b] + 0x400 * EXP_PAGE0); 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else { 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Yes, probe for I/O Base 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 112475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (probe_exhasted) { 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pr_debug("All probe addresses exhasted, skipping\n"); 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pr_debug("Probing for I/O...\n"); 117475be4d85a274d0961593db41cf85689db1d583cJoe Perches for (i = last_base; i <= IOBASE_MAX; i += IOBASE_OFFSET) { 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int found_io = 1; 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i == IOBASE_MAX) { 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds probe_exhasted = 1; /* No more addresses to probe */ 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pr_debug("End of Probes\n"); 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds last_base = i + IOBASE_OFFSET; 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pr_debug(" checking 0x%x...", i); 125475be4d85a274d0961593db41cf85689db1d583cJoe Perches for (j = 0; j < MAX_IO_REGS - 1; j++) { 126475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (!request_region(i + j * 0x400, 1, "sc test")) { 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pr_debug("Failed\n"); 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds found_io = 0; 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_region(i + j * 0x400, 1); 132475be4d85a274d0961593db41cf85689db1d583cJoe Perches } 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 134475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (found_io) { 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds io[b] = i; 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0x18, io[b] + 0x400 * EXP_PAGE0); 137475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (inb(io[b] + 0x400 * EXP_PAGE0) != 0x18) { 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pr_debug("Failed by test\n"); 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pr_debug("Passed\n"); 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 145475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (probe_exhasted) { 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * See if we should probe for shared RAM 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 153475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (do_reset) { 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pr_debug("Doing a SAFE probe reset\n"); 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0xFF, io[b] + RESET_OFFSET); 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msleep_interruptible(10000); 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15876fd020937f2d09f76a4cd8dbae1f3bec640ff0bJeff Garzik pr_debug("RAM Base for board %d is 0x%lx, %s probe\n", b, 159475be4d85a274d0961593db41cf85689db1d583cJoe Perches ram[b], ram[b] == 0 ? "will" : "won't"); 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 161475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (ram[b]) { 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * No, the RAM base has been provided 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Just look for a signature and ID the 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * board model 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 167475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (request_region(ram[b], SRAM_PAGESIZE, "sc test")) { 16876fd020937f2d09f76a4cd8dbae1f3bec640ff0bJeff Garzik pr_debug("request_region for RAM base 0x%lx succeeded\n", ram[b]); 169475be4d85a274d0961593db41cf85689db1d583cJoe Perches model = identify_board(ram[b], io[b]); 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_region(ram[b], SRAM_PAGESIZE); 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else { 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Yes, probe for free RAM and look for 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a signature and id the board model 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 178475be4d85a274d0961593db41cf85689db1d583cJoe Perches for (i = SRAM_MIN; i < SRAM_MAX; i += SRAM_PAGESIZE) { 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pr_debug("Checking RAM address 0x%x...\n", i); 180475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (request_region(i, SRAM_PAGESIZE, "sc test")) { 181fb911ee849756fc6c609dddded92d9207ff3fb29Peter Osterlund pr_debug(" request_region succeeded\n"); 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds model = identify_board(i, io[b]); 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_region(i, SRAM_PAGESIZE); 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (model >= 0) { 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pr_debug(" Identified a %s\n", 186475be4d85a274d0961593db41cf85689db1d583cJoe Perches boardname[model]); 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ram[b] = i; 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pr_debug(" Unidentifed or inaccessible\n"); 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pr_debug(" request failed\n"); 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * See if we found free RAM and the board model 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 199475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (!ram[b] || model < 0) { 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Nope, there was no place in RAM for the 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * board, or it couldn't be identified 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 204475be4d85a274d0961593db41cf85689db1d583cJoe Perches pr_debug("Failed to find an adapter at 0x%lx\n", ram[b]); 205475be4d85a274d0961593db41cf85689db1d583cJoe Perches continue; 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set the board's magic number, memory size and page register 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 211475be4d85a274d0961593db41cf85689db1d583cJoe Perches switch (model) { 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PRI_BOARD: 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds channels = 23; 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds magic = 0x20000; 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memsize = 0x100000; 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds features = PRI_FEATURES; 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case BRI_BOARD: 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case POTS_BOARD: 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds channels = 2; 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds magic = 0x60000; 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memsize = 0x10000; 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds features = BRI_FEATURES; 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 227475be4d85a274d0961593db41cf85689db1d583cJoe Perches switch (ram[b] >> 12 & 0x0F) { 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0x0: 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pr_debug("RAM Page register set to EXP_PAGE0\n"); 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pgport = EXP_PAGE0; 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0x4: 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pr_debug("RAM Page register set to EXP_PAGE1\n"); 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pgport = EXP_PAGE1; 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0x8: 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pr_debug("RAM Page register set to EXP_PAGE2\n"); 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pgport = EXP_PAGE2; 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0xC: 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pr_debug("RAM Page register set to EXP_PAGE3\n"); 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pgport = EXP_PAGE3; 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pr_debug("RAM base address doesn't fall on 16K boundary\n"); 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 253475be4d85a274d0961593db41cf85689db1d583cJoe Perches pr_debug("current IRQ: %d b: %d\n", irq[b], b); 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Make sure we got an IRQ 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 258475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (!irq[b]) { 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * No interrupt could be used 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pr_debug("Failed to acquire an IRQ line\n"); 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Horray! We found a board, Make sure we can register 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it with ISDN4Linux 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 27041f96935b4c41daea2c4dbbf137960375cf764c1Burman Yan interface = kzalloc(sizeof(isdn_if), GFP_KERNEL); 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (interface == NULL) { 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Oops, can't malloc isdn_if 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds interface->owner = THIS_MODULE; 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds interface->hl_hdrlen = 0; 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds interface->channels = channels; 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds interface->maxbufsize = BUFFER_SIZE; 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds interface->features = features; 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds interface->writebuf_skb = sndpkt; 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds interface->writecmd = NULL; 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds interface->command = command; 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strcpy(interface->id, devname); 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds interface->id[2] = '0' + cinst; 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Allocate the board structure 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 29241f96935b4c41daea2c4dbbf137960375cf764c1Burman Yan sc_adapter[cinst] = kzalloc(sizeof(board), GFP_KERNEL); 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sc_adapter[cinst] == NULL) { 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Oops, can't alloc memory for the board 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(interface); 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_init(&sc_adapter[cinst]->lock); 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 302475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (!register_isdn(interface)) { 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Oops, couldn't register for some reason 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(interface); 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(sc_adapter[cinst]); 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sc_adapter[cinst]->card = interface; 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sc_adapter[cinst]->driverId = interface->channels; 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strcpy(sc_adapter[cinst]->devicename, interface->id); 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sc_adapter[cinst]->nChannels = channels; 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sc_adapter[cinst]->ramsize = memsize; 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sc_adapter[cinst]->shmem_magic = magic; 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sc_adapter[cinst]->shmem_pgport = pgport; 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sc_adapter[cinst]->StartOnReset = 1; 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Allocate channels status structures 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 32341f96935b4c41daea2c4dbbf137960375cf764c1Burman Yan sc_adapter[cinst]->channel = kzalloc(sizeof(bchan) * channels, GFP_KERNEL); 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sc_adapter[cinst]->channel == NULL) { 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Oops, can't alloc memory for the channels 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds indicate_status(cinst, ISDN_STAT_UNLOAD, 0, NULL); /* Fix me */ 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(interface); 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(sc_adapter[cinst]); 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Lock down the hardware resources 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sc_adapter[cinst]->interrupt = irq[b]; 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (request_irq(sc_adapter[cinst]->interrupt, interrupt_handler, 33933235ca458b725bab5367f1e50562965c76af5caMichael Opdenacker 0, interface->id, 340080eb42f31a8a6dde1568f906692d9914cdfbfe8Jeff Garzik (void *)(unsigned long) cinst)) 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(sc_adapter[cinst]->channel); 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds indicate_status(cinst, ISDN_STAT_UNLOAD, 0, NULL); /* Fix me */ 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(interface); 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(sc_adapter[cinst]); 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 347475be4d85a274d0961593db41cf85689db1d583cJoe Perches 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sc_adapter[cinst]->iobase = io[b]; 350475be4d85a274d0961593db41cf85689db1d583cJoe Perches for (i = 0; i < MAX_IO_REGS - 1; i++) { 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sc_adapter[cinst]->ioport[i] = io[b] + i * 0x400; 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds request_region(sc_adapter[cinst]->ioport[i], 1, 353475be4d85a274d0961593db41cf85689db1d583cJoe Perches interface->id); 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pr_debug("Requesting I/O Port %#x\n", 355475be4d85a274d0961593db41cf85689db1d583cJoe Perches sc_adapter[cinst]->ioport[i]); 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sc_adapter[cinst]->ioport[IRQ_SELECT] = io[b] + 0x2; 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds request_region(sc_adapter[cinst]->ioport[IRQ_SELECT], 1, 359475be4d85a274d0961593db41cf85689db1d583cJoe Perches interface->id); 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pr_debug("Requesting I/O Port %#x\n", 361475be4d85a274d0961593db41cf85689db1d583cJoe Perches sc_adapter[cinst]->ioport[IRQ_SELECT]); 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sc_adapter[cinst]->rambase = ram[b]; 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds request_region(sc_adapter[cinst]->rambase, SRAM_PAGESIZE, 364475be4d85a274d0961593db41cf85689db1d583cJoe Perches interface->id); 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 366475be4d85a274d0961593db41cf85689db1d583cJoe Perches pr_info(" %s (%d) - %s %d channels IRQ %d, I/O Base 0x%x, RAM Base 0x%lx\n", 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sc_adapter[cinst]->devicename, 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sc_adapter[cinst]->driverId, 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds boardname[model], channels, irq[b], io[b], ram[b]); 370475be4d85a274d0961593db41cf85689db1d583cJoe Perches 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * reset the adapter to put things in motion 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reset(cinst); 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cinst++; 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = 0; 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 379475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (status) 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pr_info("Failed to find any adapters, driver unloaded\n"); 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return status; 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit sc_exit(void) 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, j; 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 388475be4d85a274d0961593db41cf85689db1d583cJoe Perches for (i = 0; i < cinst; i++) { 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pr_debug("Cleaning up after adapter %d\n", i); 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * kill the timers 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3930c295e44dea607be5f4cc2d19ce98afbd77e2619Julia Lawall del_timer_sync(&(sc_adapter[i]->reset_timer)); 3940c295e44dea607be5f4cc2d19ce98afbd77e2619Julia Lawall del_timer_sync(&(sc_adapter[i]->stat_timer)); 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Tell I4L we're toast 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds indicate_status(i, ISDN_STAT_STOP, 0, NULL); 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds indicate_status(i, ISDN_STAT_UNLOAD, 0, NULL); 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Release shared RAM 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_region(sc_adapter[i]->rambase, SRAM_PAGESIZE); 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Release the IRQ 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 410345225c8e4a4adad9eb261db26aebcd3b87055adFernando Luis Vázquez Cao free_irq(sc_adapter[i]->interrupt, NULL); 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Reset for a clean start 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0xFF, sc_adapter[i]->ioport[SFT_RESET]); 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Release the I/O Port regions 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 420475be4d85a274d0961593db41cf85689db1d583cJoe Perches for (j = 0; j < MAX_IO_REGS - 1; j++) { 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_region(sc_adapter[i]->ioport[j], 1); 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pr_debug("Releasing I/O Port %#x\n", 423475be4d85a274d0961593db41cf85689db1d583cJoe Perches sc_adapter[i]->ioport[j]); 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_region(sc_adapter[i]->ioport[IRQ_SELECT], 1); 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pr_debug("Releasing I/O Port %#x\n", 427475be4d85a274d0961593db41cf85689db1d583cJoe Perches sc_adapter[i]->ioport[IRQ_SELECT]); 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Release any memory we alloced 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(sc_adapter[i]->channel); 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(sc_adapter[i]->card); 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(sc_adapter[i]); 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pr_info("SpellCaster ISA ISDN Adapter Driver Unloaded.\n"); 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 439e3ca5e762c2aca373f1762cbc622ebe20fd20869Adrian Bunkstatic int identify_board(unsigned long rambase, unsigned int iobase) 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int pgport; 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long sig; 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DualPortMemory *dpm; 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds RspMessage rcvmsg; 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ReqMessage sndmsg; 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HWConfig_pl hwci; 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int x; 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 44976fd020937f2d09f76a4cd8dbae1f3bec640ff0bJeff Garzik pr_debug("Attempting to identify adapter @ 0x%lx io 0x%x\n", 450475be4d85a274d0961593db41cf85689db1d583cJoe Perches rambase, iobase); 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Enable the base pointer 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(rambase >> 12, iobase + 0x2c00); 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 457475be4d85a274d0961593db41cf85689db1d583cJoe Perches switch (rambase >> 12 & 0x0F) { 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0x0: 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pgport = iobase + PG0_OFFSET; 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pr_debug("Page Register offset is 0x%x\n", PG0_OFFSET); 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 462475be4d85a274d0961593db41cf85689db1d583cJoe Perches 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0x4: 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pgport = iobase + PG1_OFFSET; 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pr_debug("Page Register offset is 0x%x\n", PG1_OFFSET); 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0x8: 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pgport = iobase + PG2_OFFSET; 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pr_debug("Page Register offset is 0x%x\n", PG2_OFFSET); 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0xC: 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pgport = iobase + PG3_OFFSET; 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pr_debug("Page Register offset is 0x%x\n", PG3_OFFSET); 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pr_debug("Invalid rambase 0x%lx\n", rambase); 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Try to identify a PRI card 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(PRI_BASEPG_VAL, pgport); 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msleep_interruptible(1000); 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sig = readl(rambase + SIG_OFFSET); 48876fd020937f2d09f76a4cd8dbae1f3bec640ff0bJeff Garzik pr_debug("Looking for a signature, got 0x%lx\n", sig); 489475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (sig == SIGNATURE) 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return PRI_BOARD; 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Try to identify a PRI card 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(BRI_BASEPG_VAL, pgport); 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msleep_interruptible(1000); 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sig = readl(rambase + SIG_OFFSET); 49876fd020937f2d09f76a4cd8dbae1f3bec640ff0bJeff Garzik pr_debug("Looking for a signature, got 0x%lx\n", sig); 499475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (sig == SIGNATURE) 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return BRI_BOARD; 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Try to spot a card 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sig = readl(rambase + SIG_OFFSET); 50876fd020937f2d09f76a4cd8dbae1f3bec640ff0bJeff Garzik pr_debug("Looking for a signature, got 0x%lx\n", sig); 509475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (sig != SIGNATURE) 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dpm = (DualPortMemory *) rambase; 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(&sndmsg, 0, MSG_LEN); 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sndmsg.msg_byte_cnt = 3; 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sndmsg.type = cmReqType1; 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sndmsg.class = cmReqClass0; 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sndmsg.code = cmReqHWConfig; 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy_toio(&(dpm->req_queue[dpm->req_head++]), &sndmsg, MSG_LEN); 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0, iobase + 0x400); 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pr_debug("Sent HWConfig message\n"); 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Wait for the response 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds x = 0; 526475be4d85a274d0961593db41cf85689db1d583cJoe Perches while ((inb(iobase + FIFOSTAT_OFFSET) & RF_HAS_DATA) && x < 100) { 52724763c48a3c9cdf0a138038b51a7fca65859cd78Nishanth Aravamudan schedule_timeout_interruptible(1); 5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds x++; 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 530475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (x == 100) { 5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pr_debug("Timeout waiting for response\n"); 5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy_fromio(&rcvmsg, &(dpm->rsp_queue[dpm->rsp_tail]), MSG_LEN); 5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pr_debug("Got HWConfig response, status = 0x%x\n", rcvmsg.rsp_status); 5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(&hwci, &(rcvmsg.msg_data.HWCresponse), sizeof(HWConfig_pl)); 53876fd020937f2d09f76a4cd8dbae1f3bec640ff0bJeff Garzik pr_debug("Hardware Config: Interface: %s, RAM Size: %ld, Serial: %s\n" 5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds " Part: %s, Rev: %s\n", 5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hwci.st_u_sense ? "S/T" : "U", hwci.ram_size, 5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hwci.serial_no, hwci.part_no, hwci.rev_no); 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 543475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (!strncmp(PRI_PARTNO, hwci.part_no, 6)) 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return PRI_BOARD; 545475be4d85a274d0961593db41cf85689db1d583cJoe Perches if (!strncmp(BRI_PARTNO, hwci.part_no, 6)) 5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return BRI_BOARD; 547475be4d85a274d0961593db41cf85689db1d583cJoe Perches 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(sc_init); 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(sc_exit); 553