diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/isdn/sc |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/isdn/sc')
-rw-r--r-- | drivers/isdn/sc/Kconfig | 12 | ||||
-rw-r--r-- | drivers/isdn/sc/Makefile | 10 | ||||
-rw-r--r-- | drivers/isdn/sc/card.h | 101 | ||||
-rw-r--r-- | drivers/isdn/sc/command.c | 441 | ||||
-rw-r--r-- | drivers/isdn/sc/debug.c | 46 | ||||
-rw-r--r-- | drivers/isdn/sc/debug.h | 19 | ||||
-rw-r--r-- | drivers/isdn/sc/event.c | 69 | ||||
-rw-r--r-- | drivers/isdn/sc/hardware.h | 110 | ||||
-rw-r--r-- | drivers/isdn/sc/includes.h | 18 | ||||
-rw-r--r-- | drivers/isdn/sc/init.c | 571 | ||||
-rw-r--r-- | drivers/isdn/sc/interrupt.c | 260 | ||||
-rw-r--r-- | drivers/isdn/sc/ioctl.c | 601 | ||||
-rw-r--r-- | drivers/isdn/sc/message.c | 241 | ||||
-rw-r--r-- | drivers/isdn/sc/message.h | 245 | ||||
-rw-r--r-- | drivers/isdn/sc/packet.c | 231 | ||||
-rw-r--r-- | drivers/isdn/sc/scioc.h | 105 | ||||
-rw-r--r-- | drivers/isdn/sc/shmem.c | 143 | ||||
-rw-r--r-- | drivers/isdn/sc/timer.c | 147 |
18 files changed, 3370 insertions, 0 deletions
diff --git a/drivers/isdn/sc/Kconfig b/drivers/isdn/sc/Kconfig new file mode 100644 index 00000000000..5346e33d816 --- /dev/null +++ b/drivers/isdn/sc/Kconfig @@ -0,0 +1,12 @@ +# +# Config.in for Spellcaster ISDN driver +# +config ISDN_DRV_SC + tristate "Spellcaster support" + depends on ISDN_I4L && ISA + help + This enables support for the Spellcaster BRI ISDN boards. This + driver currently builds only in a modularized version. + To build it, choose M here: the module will be called sc. + See <file:Documentation/isdn/README.sc> for more information. + diff --git a/drivers/isdn/sc/Makefile b/drivers/isdn/sc/Makefile new file mode 100644 index 00000000000..9cc474cd0c4 --- /dev/null +++ b/drivers/isdn/sc/Makefile @@ -0,0 +1,10 @@ +# Makefile for the sc ISDN device driver + +# Each configuration option enables a list of files. + +obj-$(CONFIG_ISDN_DRV_SC) += sc.o + +# Multipart objects. + +sc-y := shmem.o init.o debug.o packet.o command.o event.o \ + ioctl.o interrupt.o message.o timer.o diff --git a/drivers/isdn/sc/card.h b/drivers/isdn/sc/card.h new file mode 100644 index 00000000000..8e44928cdf1 --- /dev/null +++ b/drivers/isdn/sc/card.h @@ -0,0 +1,101 @@ +/* $Id: card.h,v 1.1.10.1 2001/09/23 22:24:59 kai Exp $ + * + * Driver parameters for SpellCaster ISA ISDN adapters + * + * Copyright (C) 1996 SpellCaster Telecommunications Inc. + * + * This software may be used and distributed according to the terms + * of the GNU General Public License, incorporated herein by reference. + * + * For more information, please contact gpl-info@spellcast.com or write: + * + * SpellCaster Telecommunications Inc. + * 5621 Finch Avenue East, Unit #3 + * Scarborough, Ontario Canada + * M1B 2T9 + * +1 (416) 297-8565 + * +1 (416) 297-6433 Facsimile + */ + +#ifndef CARD_H +#define CARD_H + +/* + * We need these if they're not already included + */ +#include <linux/timer.h> +#include <linux/time.h> +#include <linux/isdnif.h> +#include "message.h" + +/* + * Amount of time to wait for a reset to complete + */ +#define CHECKRESET_TIME msecs_to_jiffies(4000) + +/* + * Amount of time between line status checks + */ +#define CHECKSTAT_TIME msecs_to_jiffies(8000) + +/* + * The maximum amount of time to wait for a message response + * to arrive. Use exclusively by send_and_receive + */ +#define SAR_TIMEOUT msecs_to_jiffies(10000) + +/* + * Macro to determine is a card id is valid + */ +#define IS_VALID_CARD(x) ((x >= 0) && (x <= cinst)) + +/* + * Per channel status and configuration + */ +typedef struct { + int l2_proto; + int l3_proto; + char dn[50]; + unsigned long first_sendbuf; /* Offset of first send buffer */ + unsigned int num_sendbufs; /* Number of send buffers */ + unsigned int free_sendbufs; /* Number of free sendbufs */ + unsigned int next_sendbuf; /* Next sequential buffer */ + char eazlist[50]; /* Set with SETEAZ */ + char sillist[50]; /* Set with SETSIL */ + int eazclear; /* Don't accept calls if TRUE */ +} bchan; + +/* + * Everything you want to know about the adapter ... + */ +typedef struct { + int model; + int driverId; /* LL Id */ + char devicename[20]; /* The device name */ + isdn_if *card; /* ISDN4Linux structure */ + bchan *channel; /* status of the B channels */ + char nChannels; /* Number of channels */ + unsigned int interrupt; /* Interrupt number */ + int iobase; /* I/O Base address */ + int ioport[MAX_IO_REGS]; /* Index to I/O ports */ + int shmem_pgport; /* port for the exp mem page reg. */ + int shmem_magic; /* adapter magic number */ + unsigned int rambase; /* Shared RAM base address */ + unsigned int ramsize; /* Size of shared memory */ + RspMessage async_msg; /* Async response message */ + int want_async_messages; /* Snoop the Q ? */ + unsigned char seq_no; /* Next send seq. number */ + struct timer_list reset_timer; /* Check reset timer */ + struct timer_list stat_timer; /* Check startproc timer */ + unsigned char nphystat; /* Latest PhyStat info */ + unsigned char phystat; /* Last PhyStat info */ + HWConfig_pl hwconfig; /* Hardware config info */ + char load_ver[11]; /* CommManage Version string */ + char proc_ver[11]; /* CommEngine Version */ + int StartOnReset; /* Indicates startproc after reset */ + int EngineUp; /* Indicates CommEngine Up */ + int trace_mode; /* Indicate if tracing is on */ + spinlock_t lock; /* local lock */ +} board; + +#endif /* CARD_H */ diff --git a/drivers/isdn/sc/command.c b/drivers/isdn/sc/command.c new file mode 100644 index 00000000000..b2c4eac7cef --- /dev/null +++ b/drivers/isdn/sc/command.c @@ -0,0 +1,441 @@ +/* $Id: command.c,v 1.4.10.1 2001/09/23 22:24:59 kai Exp $ + * + * Copyright (C) 1996 SpellCaster Telecommunications Inc. + * + * This software may be used and distributed according to the terms + * of the GNU General Public License, incorporated herein by reference. + * + * For more information, please contact gpl-info@spellcast.com or write: + * + * SpellCaster Telecommunications Inc. + * 5621 Finch Avenue East, Unit #3 + * Scarborough, Ontario Canada + * M1B 2T9 + * +1 (416) 297-8565 + * +1 (416) 297-6433 Facsimile + */ + +#include <linux/module.h> +#include "includes.h" /* This must be first */ +#include "hardware.h" +#include "message.h" +#include "card.h" +#include "scioc.h" + +int dial(int card, unsigned long channel, setup_parm setup); +int hangup(int card, unsigned long channel); +int answer(int card, unsigned long channel); +int clreaz(int card, unsigned long channel); +int seteaz(int card, unsigned long channel, char *); +int setl2(int card, unsigned long arg); +int setl3(int card, unsigned long arg); +int acceptb(int card, unsigned long channel); + +extern int cinst; +extern board *sc_adapter[]; + +extern int sc_ioctl(int, scs_ioctl *); +extern int setup_buffers(int, int, unsigned int); +extern int indicate_status(int, int,ulong,char*); +extern void check_reset(unsigned long); +extern int send_and_receive(int, unsigned int, unsigned char, unsigned char, + unsigned char, unsigned char, unsigned char, unsigned char *, + RspMessage *, int); +extern int sendmessage(int, unsigned int, unsigned int, unsigned int, + unsigned int, unsigned int, unsigned int, unsigned int *); +extern inline void pullphone(char *, char *); + +#ifdef DEBUG +/* + * Translate command codes to strings + */ +static char *commands[] = { "ISDN_CMD_IOCTL", + "ISDN_CMD_DIAL", + "ISDN_CMD_ACCEPTB", + "ISDN_CMD_ACCEPTB", + "ISDN_CMD_HANGUP", + "ISDN_CMD_CLREAZ", + "ISDN_CMD_SETEAZ", + NULL, + NULL, + NULL, + "ISDN_CMD_SETL2", + NULL, + "ISDN_CMD_SETL3", + NULL, + NULL, + NULL, + NULL, + NULL, }; + +/* + * Translates ISDN4Linux protocol codes to strings for debug messages + */ +static char *l3protos[] = { "ISDN_PROTO_L3_TRANS" }; +static char *l2protos[] = { "ISDN_PROTO_L2_X75I", + "ISDN_PROTO_L2_X75UI", + "ISDN_PROTO_L2_X75BUI", + "ISDN_PROTO_L2_HDLC", + "ISDN_PROTO_L2_TRANS" }; +#endif + +int get_card_from_id(int driver) +{ + int i; + + for(i = 0 ; i < cinst ; i++) { + if(sc_adapter[i]->driverId == driver) + return i; + } + return -ENODEV; +} + +/* + * command + */ + +int command(isdn_ctrl *cmd) +{ + int card; + + card = get_card_from_id(cmd->driver); + if(!IS_VALID_CARD(card)) { + pr_debug("Invalid param: %d is not a valid card id\n", card); + return -ENODEV; + } + + pr_debug("%s: Received %s command from Link Layer\n", + sc_adapter[card]->devicename, commands[cmd->command]); + + /* + * Dispatch the command + */ + switch(cmd->command) { + case ISDN_CMD_IOCTL: + { + unsigned long cmdptr; + scs_ioctl ioc; + + memcpy(&cmdptr, cmd->parm.num, sizeof(unsigned long)); + if (copy_from_user(&ioc, (scs_ioctl __user *)cmdptr, + sizeof(scs_ioctl))) { + pr_debug("%s: Failed to verify user space 0x%x\n", + sc_adapter[card]->devicename, cmdptr); + return -EFAULT; + } + return sc_ioctl(card, &ioc); + } + case ISDN_CMD_DIAL: + return dial(card, cmd->arg, cmd->parm.setup); + case ISDN_CMD_HANGUP: + return hangup(card, cmd->arg); + case ISDN_CMD_ACCEPTD: + return answer(card, cmd->arg); + case ISDN_CMD_ACCEPTB: + return acceptb(card, cmd->arg); + case ISDN_CMD_CLREAZ: + return clreaz(card, cmd->arg); + case ISDN_CMD_SETEAZ: + return seteaz(card, cmd->arg, cmd->parm.num); + case ISDN_CMD_SETL2: + return setl2(card, cmd->arg); + case ISDN_CMD_SETL3: + return setl3(card, cmd->arg); + default: + return -EINVAL; + } + return 0; +} + +/* + * Confirm our ability to communicate with the board. This test assumes no + * other message activity is present + */ +int loopback(int card) +{ + + int status; + static char testmsg[] = "Test Message"; + RspMessage rspmsg; + + if(!IS_VALID_CARD(card)) { + pr_debug("Invalid param: %d is not a valid card id\n", card); + return -ENODEV; + } + + pr_debug("%s: Sending loopback message\n", + sc_adapter[card]->devicename); + + /* + * Send the loopback message to confirm that memory transfer is + * operational + */ + status = send_and_receive(card, CMPID, cmReqType1, + cmReqClass0, + cmReqMsgLpbk, + 0, + (unsigned char) strlen(testmsg), + (unsigned char *)testmsg, + &rspmsg, SAR_TIMEOUT); + + + if (!status) { + pr_debug("%s: Loopback message successfully sent\n", + sc_adapter[card]->devicename); + if(strcmp(rspmsg.msg_data.byte_array, testmsg)) { + pr_debug("%s: Loopback return != sent\n", + sc_adapter[card]->devicename); + return -EIO; + } + return 0; + } + else { + pr_debug("%s: Send loopback message failed\n", + sc_adapter[card]->devicename); + return -EIO; + } + +} + +/* + * start the onboard firmware + */ +int startproc(int card) +{ + int status; + + if(!IS_VALID_CARD(card)) { + pr_debug("Invalid param: %d is not a valid card id\n", card); + return -ENODEV; + } + + /* + * send start msg + */ + status = sendmessage(card, CMPID,cmReqType2, + cmReqClass0, + cmReqStartProc, + 0,0,NULL); + pr_debug("%s: Sent startProc\n", sc_adapter[card]->devicename); + + return status; +} + + +int loadproc(int card, char *data) +{ + return -1; +} + + +/* + * Dials the number passed in + */ +int dial(int card, unsigned long channel, setup_parm setup) +{ + int status; + char Phone[48]; + + if(!IS_VALID_CARD(card)) { + pr_debug("Invalid param: %d is not a valid card id\n", card); + return -ENODEV; + } + + /*extract ISDN number to dial from eaz/msn string*/ + strcpy(Phone,setup.phone); + + /*send the connection message*/ + status = sendmessage(card, CEPID,ceReqTypePhy, + ceReqClass1, + ceReqPhyConnect, + (unsigned char) channel+1, + strlen(Phone), + (unsigned int *) Phone); + + pr_debug("%s: Dialing %s on channel %d\n", + sc_adapter[card]->devicename, Phone, channel+1); + + return status; +} + +/* + * Answer an incoming call + */ +int answer(int card, unsigned long channel) +{ + if(!IS_VALID_CARD(card)) { + pr_debug("Invalid param: %d is not a valid card id\n", card); + return -ENODEV; + } + + if(setup_buffers(card, channel+1, BUFFER_SIZE)) { + hangup(card, channel+1); + return -ENOBUFS; + } + + indicate_status(card, ISDN_STAT_BCONN,channel,NULL); + pr_debug("%s: Answered incoming call on channel %s\n", + sc_adapter[card]->devicename, channel+1); + return 0; +} + +/* + * Hangup up the call on specified channel + */ +int hangup(int card, unsigned long channel) +{ + int status; + + if(!IS_VALID_CARD(card)) { + pr_debug("Invalid param: %d is not a valid card id\n", card); + return -ENODEV; + } + + status = sendmessage(card, CEPID, ceReqTypePhy, + ceReqClass1, + ceReqPhyDisconnect, + (unsigned char) channel+1, + 0, + NULL); + pr_debug("%s: Sent HANGUP message to channel %d\n", + sc_adapter[card]->devicename, channel+1); + return status; +} + +/* + * Set the layer 2 protocol (X.25, HDLC, Raw) + */ +int setl2(int card, unsigned long arg) +{ + int status =0; + int protocol,channel; + + if(!IS_VALID_CARD(card)) { + pr_debug("Invalid param: %d is not a valid card id\n", card); + return -ENODEV; + } + protocol = arg >> 8; + channel = arg & 0xff; + sc_adapter[card]->channel[channel].l2_proto = protocol; + pr_debug("%s: Level 2 protocol for channel %d set to %s from %d\n", + sc_adapter[card]->devicename, channel+1, + l2protos[sc_adapter[card]->channel[channel].l2_proto],protocol); + + /* + * check that the adapter is also set to the correct protocol + */ + pr_debug("%s: Sending GetFrameFormat for channel %d\n", + sc_adapter[card]->devicename, channel+1); + status = sendmessage(card, CEPID, ceReqTypeCall, + ceReqClass0, + ceReqCallGetFrameFormat, + (unsigned char)channel+1, + 1, + (unsigned int *) protocol); + if(status) + return status; + return 0; +} + +/* + * Set the layer 3 protocol + */ +int setl3(int card, unsigned long channel) +{ + int protocol = channel >> 8; + + if(!IS_VALID_CARD(card)) { + pr_debug("Invalid param: %d is not a valid card id\n", card); + return -ENODEV; + } + + sc_adapter[card]->channel[channel].l3_proto = protocol; + pr_debug("%s: Level 3 protocol for channel %d set to %s\n", + sc_adapter[card]->devicename, channel+1, l3protos[protocol]); + return 0; +} + +int acceptb(int card, unsigned long channel) +{ + if(!IS_VALID_CARD(card)) { + pr_debug("Invalid param: %d is not a valid card id\n", card); + return -ENODEV; + } + + if(setup_buffers(card, channel+1, BUFFER_SIZE)) + { + hangup(card, channel+1); + return -ENOBUFS; + } + + pr_debug("%s: B-Channel connection accepted on channel %d\n", + sc_adapter[card]->devicename, channel+1); + indicate_status(card, ISDN_STAT_BCONN, channel, NULL); + return 0; +} + +int clreaz(int card, unsigned long arg) +{ + if(!IS_VALID_CARD(card)) { + pr_debug("Invalid param: %d is not a valid card id\n", card); + return -ENODEV; + } + + strcpy(sc_adapter[card]->channel[arg].eazlist, ""); + sc_adapter[card]->channel[arg].eazclear = 1; + pr_debug("%s: EAZ List cleared for channel %d\n", + sc_adapter[card]->devicename, arg+1); + return 0; +} + +int seteaz(int card, unsigned long arg, char *num) +{ + if(!IS_VALID_CARD(card)) { + pr_debug("Invalid param: %d is not a valid card id\n", card); + return -ENODEV; + } + + strcpy(sc_adapter[card]->channel[arg].eazlist, num); + sc_adapter[card]->channel[arg].eazclear = 0; + pr_debug("%s: EAZ list for channel %d set to: %s\n", + sc_adapter[card]->devicename, arg+1, + sc_adapter[card]->channel[arg].eazlist); + return 0; +} + +int reset(int card) +{ + unsigned long flags; + + if(!IS_VALID_CARD(card)) { + pr_debug("Invalid param: %d is not a valid card id\n", card); + return -ENODEV; + } + + indicate_status(card, ISDN_STAT_STOP, 0, NULL); + + if(sc_adapter[card]->EngineUp) { + del_timer(&sc_adapter[card]->stat_timer); + } + + sc_adapter[card]->EngineUp = 0; + + spin_lock_irqsave(&sc_adapter[card]->lock, flags); + init_timer(&sc_adapter[card]->reset_timer); + sc_adapter[card]->reset_timer.function = check_reset; + sc_adapter[card]->reset_timer.data = card; + sc_adapter[card]->reset_timer.expires = jiffies + CHECKRESET_TIME; + add_timer(&sc_adapter[card]->reset_timer); + spin_unlock_irqrestore(&sc_adapter[card]->lock, flags); + + outb(0x1,sc_adapter[card]->ioport[SFT_RESET]); + + pr_debug("%s: Adapter Reset\n", sc_adapter[card]->devicename); + return 0; +} + +void flushreadfifo (int card) +{ + while(inb(sc_adapter[card]->ioport[FIFO_STATUS]) & RF_HAS_DATA) + inb(sc_adapter[card]->ioport[FIFO_READ]); +} diff --git a/drivers/isdn/sc/debug.c b/drivers/isdn/sc/debug.c new file mode 100644 index 00000000000..1a992a75868 --- /dev/null +++ b/drivers/isdn/sc/debug.c @@ -0,0 +1,46 @@ +/* $Id: debug.c,v 1.5.6.1 2001/09/23 22:24:59 kai Exp $ + * + * Copyright (C) 1996 SpellCaster Telecommunications Inc. + * + * This software may be used and distributed according to the terms + * of the GNU General Public License, incorporated herein by reference. + * + * For more information, please contact gpl-info@spellcast.com or write: + * + * SpellCaster Telecommunications Inc. + * 5621 Finch Avenue East, Unit #3 + * Scarborough, Ontario Canada + * M1B 2T9 + * +1 (416) 297-8565 + * +1 (416) 297-6433 Facsimile + */ + +#include <linux/kernel.h> +#include <linux/string.h> + +int dbg_level = 0; +static char dbg_funcname[255]; + +void dbg_endfunc(void) +{ + if (dbg_level) { + printk("<-- Leaving function %s\n", dbg_funcname); + strcpy(dbg_funcname, ""); + } +} + +void dbg_func(char *func) +{ + strcpy(dbg_funcname, func); + if(dbg_level) + printk("--> Entering function %s\n", dbg_funcname); +} + +inline void pullphone(char *dn, char *str) +{ + int i = 0; + + while(dn[i] != ',') + str[i] = dn[i], i++; + str[i] = 0x0; +} diff --git a/drivers/isdn/sc/debug.h b/drivers/isdn/sc/debug.h new file mode 100644 index 00000000000..e9db96ede4b --- /dev/null +++ b/drivers/isdn/sc/debug.h @@ -0,0 +1,19 @@ +/* $Id: debug.h,v 1.2.8.1 2001/09/23 22:24:59 kai Exp $ + * + * Copyright (C) 1996 SpellCaster Telecommunications Inc. + * + * This software may be used and distributed according to the terms + * of the GNU General Public License, incorporated herein by reference. + * + * For more information, please contact gpl-info@spellcast.com or write: + * + * SpellCaster Telecommunications Inc. + * 5621 Finch Avenue East, Unit #3 + * Scarborough, Ontario Canada + * M1B 2T9 + * +1 (416) 297-8565 + * +1 (416) 297-6433 Facsimile + */ + +#define REQUEST_IRQ(a,b,c,d,e) request_irq(a,b,c,d,e) +#define FREE_IRQ(a,b) free_irq(a,b) diff --git a/drivers/isdn/sc/event.c b/drivers/isdn/sc/event.c new file mode 100644 index 00000000000..5b8c7c1a766 --- /dev/null +++ b/drivers/isdn/sc/event.c @@ -0,0 +1,69 @@ +/* $Id: event.c,v 1.4.8.1 2001/09/23 22:24:59 kai Exp $ + * + * Copyright (C) 1996 SpellCaster Telecommunications Inc. + * + * This software may be used and distributed according to the terms + * of the GNU General Public License, incorporated herein by reference. + * + * For more information, please contact gpl-info@spellcast.com or write: + * + * SpellCaster Telecommunications Inc. + * 5621 Finch Avenue East, Unit #3 + * Scarborough, Ontario Canada + * M1B 2T9 + * +1 (416) 297-8565 + * +1 (416) 297-6433 Facsimile + */ + +#include "includes.h" +#include "hardware.h" +#include "message.h" +#include "card.h" + +extern int cinst; +extern board *sc_adapter[]; + +#ifdef DEBUG +static char *events[] = { "ISDN_STAT_STAVAIL", + "ISDN_STAT_ICALL", + "ISDN_STAT_RUN", + "ISDN_STAT_STOP", + "ISDN_STAT_DCONN", + "ISDN_STAT_BCONN", + "ISDN_STAT_DHUP", + "ISDN_STAT_BHUP", + "ISDN_STAT_CINF", + "ISDN_STAT_LOAD", + "ISDN_STAT_UNLOAD", + "ISDN_STAT_BSENT", + "ISDN_STAT_NODCH", + "ISDN_STAT_ADDCH", + "ISDN_STAT_CAUSE" }; +#endif + +int indicate_status(int card, int event,ulong Channel,char *Data) +{ + isdn_ctrl cmd; + + pr_debug("%s: Indicating event %s on Channel %d\n", + sc_adapter[card]->devicename, events[event-256], Channel); + if (Data != NULL){ + pr_debug("%s: Event data: %s\n", sc_adapter[card]->devicename, + Data); + switch (event) { + case ISDN_STAT_BSENT: + memcpy(&cmd.parm.length, Data, sizeof(cmd.parm.length)); + break; + case ISDN_STAT_ICALL: + memcpy(&cmd.parm.setup, Data, sizeof(cmd.parm.setup)); + break; + default: + strcpy(cmd.parm.num, Data); + } + } + + cmd.command = event; + cmd.driver = sc_adapter[card]->driverId; + cmd.arg = Channel; + return sc_adapter[card]->card->statcallb(&cmd); +} diff --git a/drivers/isdn/sc/hardware.h b/drivers/isdn/sc/hardware.h new file mode 100644 index 00000000000..9e6d5302bf8 --- /dev/null +++ b/drivers/isdn/sc/hardware.h @@ -0,0 +1,110 @@ +/* + * Hardware specific macros, defines and structures + * + * This software may be used and distributed according to the terms + * of the GNU General Public License, incorporated herein by reference. + * + */ + +#ifndef HARDWARE_H +#define HARDWARE_H + +#include <asm/param.h> /* For HZ */ + +/* + * General hardware parameters common to all ISA adapters + */ + +#define MAX_CARDS 4 /* The maximum number of cards to + control or probe for. */ + +#define SIGNATURE 0x87654321 /* Board reset signature */ +#define SIG_OFFSET 0x1004 /* Where to find signature in shared RAM */ +#define TRACE_OFFSET 0x1008 /* Trace enable word offset in shared RAM */ +#define BUFFER_OFFSET 0x1800 /* Beginning of buffers */ + +/* I/O Port parameters */ +#define IOBASE_MIN 0x180 /* Lowest I/O port address */ +#define IOBASE_MAX 0x3C0 /* Highest I/O port address */ +#define IOBASE_OFFSET 0x20 /* Inter-board I/O port gap used during + probing */ +#define FIFORD_OFFSET 0x0 +#define FIFOWR_OFFSET 0x400 +#define FIFOSTAT_OFFSET 0x1000 +#define RESET_OFFSET 0x2800 +#define PG0_OFFSET 0x3000 /* Offset from I/O Base for Page 0 register */ +#define PG1_OFFSET 0x3400 /* Offset from I/O Base for Page 1 register */ +#define PG2_OFFSET 0x3800 /* Offset from I/O Base for Page 2 register */ +#define PG3_OFFSET 0x3C00 /* Offset from I/O Base for Page 3 register */ + +#define FIFO_READ 0 /* FIFO Read register */ +#define FIFO_WRITE 1 /* FIFO Write rgister */ +#define LO_ADDR_PTR 2 /* Extended RAM Low Addr Pointer */ +#define HI_ADDR_PTR 3 /* Extended RAM High Addr Pointer */ +#define NOT_USED_1 4 +#define FIFO_STATUS 5 /* FIFO Status Register */ +#define NOT_USED_2 6 +#define MEM_OFFSET 7 +#define SFT_RESET 10 /* Reset Register */ +#define EXP_BASE 11 /* Shared RAM Base address */ +#define EXP_PAGE0 12 /* Shared RAM Page0 register */ +#define EXP_PAGE1 13 /* Shared RAM Page1 register */ +#define EXP_PAGE2 14 /* Shared RAM Page2 register */ +#define EXP_PAGE3 15 /* Shared RAM Page3 register */ +#define IRQ_SELECT 16 /* IRQ selection register */ +#define MAX_IO_REGS 17 /* Total number of I/O ports */ + +/* FIFO register values */ +#define RF_HAS_DATA 0x01 /* fifo has data */ +#define RF_QUART_FULL 0x02 /* fifo quarter full */ +#define RF_HALF_FULL 0x04 /* fifo half full */ +#define RF_NOT_FULL 0x08 /* fifo not full */ +#define WF_HAS_DATA 0x10 /* fifo has data */ +#define WF_QUART_FULL 0x20 /* fifo quarter full */ +#define WF_HALF_FULL 0x40 /* fifo half full */ +#define WF_NOT_FULL 0x80 /* fifo not full */ + +/* Shared RAM parameters */ +#define SRAM_MIN 0xC0000 /* Lowest host shared RAM address */ +#define SRAM_MAX 0xEFFFF /* Highest host shared RAM address */ +#define SRAM_PAGESIZE 0x4000 /* Size of one RAM page (16K) */ + +/* Shared RAM buffer parameters */ +#define BUFFER_SIZE 0x800 /* The size of a buffer in bytes */ +#define BUFFER_BASE BUFFER_OFFSET /* Offset from start of shared RAM + where buffer start */ +#define BUFFERS_MAX 16 /* Maximum number of send/receive + buffers per channel */ +#define HDLC_PROTO 0x01 /* Frame Format for Layer 2 */ + +#define BRI_BOARD 0 +#define POTS_BOARD 1 +#define PRI_BOARD 2 + +/* + * Specific hardware parameters for the DataCommute/BRI + */ +#define BRI_CHANNELS 2 /* Number of B channels */ +#define BRI_BASEPG_VAL 0x98 +#define BRI_MAGIC 0x60000 /* Magic Number */ +#define BRI_MEMSIZE 0x10000 /* Ammount of RAM (64K) */ +#define BRI_PARTNO "72-029" +#define BRI_FEATURES ISDN_FEATURE_L2_HDLC | ISDN_FEATURE_L3_TRANS; +/* + * Specific hardware parameters for the DataCommute/PRI + */ +#define PRI_CHANNELS 23 /* Number of B channels */ +#define PRI_BASEPG_VAL 0x88 +#define PRI_MAGIC 0x20000 /* Magic Number */ +#define PRI_MEMSIZE 0x100000 /* Amount of RAM (1M) */ +#define PRI_PARTNO "72-030" +#define PRI_FEATURES ISDN_FEATURE_L2_HDLC | ISDN_FEATURE_L3_TRANS; + +/* + * Some handy macros + */ + +/* Determine if a channel number is valid for the adapter */ +#define IS_VALID_CHANNEL(y,x) ((x>0) && (x <= sc_adapter[y]->channels)) + +#endif diff --git a/drivers/isdn/sc/includes.h b/drivers/isdn/sc/includes.h new file mode 100644 index 00000000000..4611da6e923 --- /dev/null +++ b/drivers/isdn/sc/includes.h @@ -0,0 +1,18 @@ +/* + * This software may be used and distributed according to the terms + * of the GNU General Public License, incorporated herein by reference. + * + */ + +#include <linux/version.h> +#include <linux/errno.h> +#include <asm/io.h> +#include <linux/delay.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/mm.h> +#include <linux/ioport.h> +#include <linux/timer.h> +#include <linux/wait.h> +#include <linux/isdnif.h> +#include "debug.h" diff --git a/drivers/isdn/sc/init.c b/drivers/isdn/sc/init.c new file mode 100644 index 00000000000..efefedea37b --- /dev/null +++ b/drivers/isdn/sc/init.c @@ -0,0 +1,571 @@ +/* + * This software may be used and distributed according to the terms + * of the GNU General Public License, incorporated herein by reference. + * + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/delay.h> +#include "includes.h" +#include "hardware.h" +#include "card.h" + +MODULE_DESCRIPTION("ISDN4Linux: Driver for Spellcaster card"); +MODULE_AUTHOR("Spellcaster Telecommunications Inc."); +MODULE_LICENSE("GPL"); + +board *sc_adapter[MAX_CARDS]; +int cinst; + +static char devname[] = "scX"; +const char version[] = "2.0b1"; + +const char *boardname[] = { "DataCommute/BRI", "DataCommute/PRI", "TeleCommute/BRI" }; + +/* insmod set parameters */ +static unsigned int io[] = {0,0,0,0}; +static unsigned char irq[] = {0,0,0,0}; +static unsigned long ram[] = {0,0,0,0}; +static int do_reset = 0; + +module_param_array(io, int, NULL, 0); +module_param_array(irq, int, NULL, 0); +module_param_array(ram, int, NULL, 0); +module_param(do_reset, bool, 0); + +static int sup_irq[] = { 11, 10, 9, 5, 12, 14, 7, 3, 4, 6 }; +#define MAX_IRQS 10 + +extern irqreturn_t interrupt_handler(int, void *, struct pt_regs *); +extern int sndpkt(int, int, int, struct sk_buff *); +extern int command(isdn_ctrl *); +extern int indicate_status(int, int, ulong, char*); +extern int reset(int); + +int identify_board(unsigned long, unsigned int); + +int irq_supported(int irq_x) +{ + int i; + for(i=0 ; i < MAX_IRQS ; i++) { + if(sup_irq[i] == irq_x) + return 1; + } + return 0; +} + +static int __init sc_init(void) +{ + int b = -1; + int i, j; + int status = -ENODEV; + + unsigned long memsize = 0; + unsigned long features = 0; + isdn_if *interface; + unsigned char channels; + unsigned char pgport; + unsigned long magic; + int model; + int last_base = IOBASE_MIN; + int probe_exhasted = 0; + +#ifdef MODULE + pr_info("SpellCaster ISA ISDN Adapter Driver rev. %s Loaded\n", version); +#else + pr_info("SpellCaster ISA ISDN Adapter Driver rev. %s\n", version); +#endif + pr_info("Copyright (C) 1996 SpellCaster Telecommunications Inc.\n"); + + while(b++ < MAX_CARDS - 1) { + pr_debug("Probing for adapter #%d\n", b); + /* + * Initialize reusable variables + */ + model = -1; + magic = 0; + channels = 0; + pgport = 0; + + /* + * See if we should probe for IO base + */ + pr_debug("I/O Base for board %d is 0x%x, %s probe\n", b, io[b], + io[b] == 0 ? "will" : "won't"); + if(io[b]) { + /* + * No, I/O Base has been provided + */ + for (i = 0 ; i < MAX_IO_REGS - 1 ; i++) { + if(!request_region(io[b] + i * 0x400, 1, "sc test")) { + pr_debug("check_region for 0x%x failed\n", io[b] + i * 0x400); + io[b] = 0; + break; + } else + release_region(io[b] + i * 0x400, 1); + } + + /* + * Confirm the I/O Address with a test + */ + if(io[b] == 0) { + pr_debug("I/O Address 0x%x is in use.\n"); + continue; + } + + outb(0x18, io[b] + 0x400 * EXP_PAGE0); + if(inb(io[b] + 0x400 * EXP_PAGE0) != 0x18) { + pr_debug("I/O Base 0x%x fails test\n"); + continue; + } + } + else { + /* + * Yes, probe for I/O Base + */ + if(probe_exhasted) { + pr_debug("All probe addresses exhasted, skipping\n"); + continue; + } + pr_debug("Probing for I/O...\n"); + for (i = last_base ; i <= IOBASE_MAX ; i += IOBASE_OFFSET) { + int found_io = 1; + if (i == IOBASE_MAX) { + probe_exhasted = 1; /* No more addresses to probe */ + pr_debug("End of Probes\n"); + } + last_base = i + IOBASE_OFFSET; + pr_debug(" checking 0x%x...", i); + for ( j = 0 ; j < MAX_IO_ |