aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/isdn/sc
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /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/Kconfig12
-rw-r--r--drivers/isdn/sc/Makefile10
-rw-r--r--drivers/isdn/sc/card.h101
-rw-r--r--drivers/isdn/sc/command.c441
-rw-r--r--drivers/isdn/sc/debug.c46
-rw-r--r--drivers/isdn/sc/debug.h19
-rw-r--r--drivers/isdn/sc/event.c69
-rw-r--r--drivers/isdn/sc/hardware.h110
-rw-r--r--drivers/isdn/sc/includes.h18
-rw-r--r--drivers/isdn/sc/init.c571
-rw-r--r--drivers/isdn/sc/interrupt.c260
-rw-r--r--drivers/isdn/sc/ioctl.c601
-rw-r--r--drivers/isdn/sc/message.c241
-rw-r--r--drivers/isdn/sc/message.h245
-rw-r--r--drivers/isdn/sc/packet.c231
-rw-r--r--drivers/isdn/sc/scioc.h105
-rw-r--r--drivers/isdn/sc/shmem.c143
-rw-r--r--drivers/isdn/sc/timer.c147
18 files changed, 3370 insertions, 0 deletions
diff --git a/drivers/isdn/sc/Kconfig b/drivers/isdn/sc/Kconfig
new file mode 100644
index 000000000000..5346e33d816c
--- /dev/null
+++ b/drivers/isdn/sc/Kconfig
@@ -0,0 +1,12 @@
1#
2# Config.in for Spellcaster ISDN driver
3#
4config ISDN_DRV_SC
5 tristate "Spellcaster support"
6 depends on ISDN_I4L && ISA
7 help
8 This enables support for the Spellcaster BRI ISDN boards. This
9 driver currently builds only in a modularized version.
10 To build it, choose M here: the module will be called sc.
11 See <file:Documentation/isdn/README.sc> for more information.
12
diff --git a/drivers/isdn/sc/Makefile b/drivers/isdn/sc/Makefile
new file mode 100644
index 000000000000..9cc474cd0c44
--- /dev/null
+++ b/drivers/isdn/sc/Makefile
@@ -0,0 +1,10 @@
1# Makefile for the sc ISDN device driver
2
3# Each configuration option enables a list of files.
4
5obj-$(CONFIG_ISDN_DRV_SC) += sc.o
6
7# Multipart objects.
8
9sc-y := shmem.o init.o debug.o packet.o command.o event.o \
10 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 000000000000..8e44928cdf1c
--- /dev/null
+++ b/drivers/isdn/sc/card.h
@@ -0,0 +1,101 @@
1/* $Id: card.h,v 1.1.10.1 2001/09/23 22:24:59 kai Exp $
2 *
3 * Driver parameters for SpellCaster ISA ISDN adapters
4 *
5 * Copyright (C) 1996 SpellCaster Telecommunications Inc.
6 *
7 * This software may be used and distributed according to the terms
8 * of the GNU General Public License, incorporated herein by reference.
9 *
10 * For more information, please contact gpl-info@spellcast.com or write:
11 *
12 * SpellCaster Telecommunications Inc.
13 * 5621 Finch Avenue East, Unit #3
14 * Scarborough, Ontario Canada
15 * M1B 2T9
16 * +1 (416) 297-8565
17 * +1 (416) 297-6433 Facsimile
18 */
19
20#ifndef CARD_H
21#define CARD_H
22
23/*
24 * We need these if they're not already included
25 */
26#include <linux/timer.h>
27#include <linux/time.h>
28#include <linux/isdnif.h>
29#include "message.h"
30
31/*
32 * Amount of time to wait for a reset to complete
33 */
34#define CHECKRESET_TIME msecs_to_jiffies(4000)
35
36/*
37 * Amount of time between line status checks
38 */
39#define CHECKSTAT_TIME msecs_to_jiffies(8000)
40
41/*
42 * The maximum amount of time to wait for a message response
43 * to arrive. Use exclusively by send_and_receive
44 */
45#define SAR_TIMEOUT msecs_to_jiffies(10000)
46
47/*
48 * Macro to determine is a card id is valid
49 */
50#define IS_VALID_CARD(x) ((x >= 0) && (x <= cinst))
51
52/*
53 * Per channel status and configuration
54 */
55typedef struct {
56 int l2_proto;
57 int l3_proto;
58 char dn[50];
59 unsigned long first_sendbuf; /* Offset of first send buffer */
60 unsigned int num_sendbufs; /* Number of send buffers */
61 unsigned int free_sendbufs; /* Number of free sendbufs */
62 unsigned int next_sendbuf; /* Next sequential buffer */
63 char eazlist[50]; /* Set with SETEAZ */
64 char sillist[50]; /* Set with SETSIL */
65 int eazclear; /* Don't accept calls if TRUE */
66} bchan;
67
68/*
69 * Everything you want to know about the adapter ...
70 */
71typedef struct {
72 int model;
73 int driverId; /* LL Id */
74 char devicename[20]; /* The device name */
75 isdn_if *card; /* ISDN4Linux structure */
76 bchan *channel; /* status of the B channels */
77 char nChannels; /* Number of channels */
78 unsigned int interrupt; /* Interrupt number */
79 int iobase; /* I/O Base address */
80 int ioport[MAX_IO_REGS]; /* Index to I/O ports */
81 int shmem_pgport; /* port for the exp mem page reg. */
82 int shmem_magic; /* adapter magic number */
83 unsigned int rambase; /* Shared RAM base address */
84 unsigned int ramsize; /* Size of shared memory */
85 RspMessage async_msg; /* Async response message */
86 int want_async_messages; /* Snoop the Q ? */
87 unsigned char seq_no; /* Next send seq. number */
88 struct timer_list reset_timer; /* Check reset timer */
89 struct timer_list stat_timer; /* Check startproc timer */
90 unsigned char nphystat; /* Latest PhyStat info */
91 unsigned char phystat; /* Last PhyStat info */
92 HWConfig_pl hwconfig; /* Hardware config info */
93 char load_ver[11]; /* CommManage Version string */
94 char proc_ver[11]; /* CommEngine Version */
95 int StartOnReset; /* Indicates startproc after reset */
96 int EngineUp; /* Indicates CommEngine Up */
97 int trace_mode; /* Indicate if tracing is on */
98 spinlock_t lock; /* local lock */
99} board;
100
101#endif /* CARD_H */
diff --git a/drivers/isdn/sc/command.c b/drivers/isdn/sc/command.c
new file mode 100644
index 000000000000..b2c4eac7cef5
--- /dev/null
+++ b/drivers/isdn/sc/command.c
@@ -0,0 +1,441 @@
1/* $Id: command.c,v 1.4.10.1 2001/09/23 22:24:59 kai Exp $
2 *
3 * Copyright (C) 1996 SpellCaster Telecommunications Inc.
4 *
5 * This software may be used and distributed according to the terms
6 * of the GNU General Public License, incorporated herein by reference.
7 *
8 * For more information, please contact gpl-info@spellcast.com or write:
9 *
10 * SpellCaster Telecommunications Inc.
11 * 5621 Finch Avenue East, Unit #3
12 * Scarborough, Ontario Canada
13 * M1B 2T9
14 * +1 (416) 297-8565
15 * +1 (416) 297-6433 Facsimile
16 */
17
18#include <linux/module.h>
19#include "includes.h" /* This must be first */
20#include "hardware.h"
21#include "message.h"
22#include "card.h"
23#include "scioc.h"
24
25int dial(int card, unsigned long channel, setup_parm setup);
26int hangup(int card, unsigned long channel);
27int answer(int card, unsigned long channel);
28int clreaz(int card, unsigned long channel);
29int seteaz(int card, unsigned long channel, char *);
30int setl2(int card, unsigned long arg);
31int setl3(int card, unsigned long arg);
32int acceptb(int card, unsigned long channel);
33
34extern int cinst;
35extern board *sc_adapter[];
36
37extern int sc_ioctl(int, scs_ioctl *);
38extern int setup_buffers(int, int, unsigned int);
39extern int indicate_status(int, int,ulong,char*);
40extern void check_reset(unsigned long);
41extern int send_and_receive(int, unsigned int, unsigned char, unsigned char,
42 unsigned char, unsigned char, unsigned char, unsigned char *,
43 RspMessage *, int);
44extern int sendmessage(int, unsigned int, unsigned int, unsigned int,
45 unsigned int, unsigned int, unsigned int, unsigned int *);
46extern inline void pullphone(char *, char *);
47
48#ifdef DEBUG
49/*
50 * Translate command codes to strings
51 */
52static char *commands[] = { "ISDN_CMD_IOCTL",
53 "ISDN_CMD_DIAL",
54 "ISDN_CMD_ACCEPTB",
55 "ISDN_CMD_ACCEPTB",
56 "ISDN_CMD_HANGUP",
57 "ISDN_CMD_CLREAZ",
58 "ISDN_CMD_SETEAZ",
59 NULL,
60 NULL,
61 NULL,
62 "ISDN_CMD_SETL2",
63 NULL,
64 "ISDN_CMD_SETL3",
65 NULL,
66 NULL,
67 NULL,
68 NULL,
69 NULL, };
70
71/*
72 * Translates ISDN4Linux protocol codes to strings for debug messages
73 */
74static char *l3protos[] = { "ISDN_PROTO_L3_TRANS" };
75static char *l2protos[] = { "ISDN_PROTO_L2_X75I",
76 "ISDN_PROTO_L2_X75UI",
77 "ISDN_PROTO_L2_X75BUI",
78 "ISDN_PROTO_L2_HDLC",
79 "ISDN_PROTO_L2_TRANS" };
80#endif
81
82int get_card_from_id(int driver)
83{
84 int i;
85
86 for(i = 0 ; i < cinst ; i++) {
87 if(sc_adapter[i]->driverId == driver)
88 return i;
89 }
90 return -ENODEV;
91}
92
93/*
94 * command
95 */
96
97int command(isdn_ctrl *cmd)
98{
99 int card;
100
101 card = get_card_from_id(cmd->driver);
102 if(!IS_VALID_CARD(card)) {
103 pr_debug("Invalid param: %d is not a valid card id\n", card);
104 return -ENODEV;
105 }
106
107 pr_debug("%s: Received %s command from Link Layer\n",
108 sc_adapter[card]->devicename, commands[cmd->command]);
109
110 /*
111 * Dispatch the command
112 */
113 switch(cmd->command) {
114 case ISDN_CMD_IOCTL:
115 {
116 unsigned long cmdptr;
117 scs_ioctl ioc;
118
119 memcpy(&cmdptr, cmd->parm.num, sizeof(unsigned long));
120 if (copy_from_user(&ioc, (scs_ioctl __user *)cmdptr,
121 sizeof(scs_ioctl))) {
122 pr_debug("%s: Failed to verify user space 0x%x\n",
123 sc_adapter[card]->devicename, cmdptr);
124 return -EFAULT;
125 }
126 return sc_ioctl(card, &ioc);
127 }
128 case ISDN_CMD_DIAL:
129 return dial(card, cmd->arg, cmd->parm.setup);
130 case ISDN_CMD_HANGUP:
131 return hangup(card, cmd->arg);
132 case ISDN_CMD_ACCEPTD:
133 return answer(card, cmd->arg);
134 case ISDN_CMD_ACCEPTB:
135 return acceptb(card, cmd->arg);
136 case ISDN_CMD_CLREAZ:
137 return clreaz(card, cmd->arg);
138 case ISDN_CMD_SETEAZ:
139 return seteaz(card, cmd->arg, cmd->parm.num);
140 case ISDN_CMD_SETL2:
141 return setl2(card, cmd->arg);
142 case ISDN_CMD_SETL3:
143 return setl3(card, cmd->arg);
144 default:
145 return -EINVAL;
146 }
147 return 0;
148}
149
150/*
151 * Confirm our ability to communicate with the board. This test assumes no
152 * other message activity is present
153 */
154int loopback(int card)
155{
156
157 int status;
158 static char testmsg[] = "Test Message";
159 RspMessage rspmsg;
160
161 if(!IS_VALID_CARD(card)) {
162 pr_debug("Invalid param: %d is not a valid card id\n", card);
163 return -ENODEV;
164 }
165
166 pr_debug("%s: Sending loopback message\n",
167 sc_adapter[card]->devicename);
168
169 /*
170 * Send the loopback message to confirm that memory transfer is
171 * operational
172 */
173 status = send_and_receive(card, CMPID, cmReqType1,
174 cmReqClass0,
175 cmReqMsgLpbk,
176 0,
177 (unsigned char) strlen(testmsg),
178 (unsigned char *)testmsg,
179 &rspmsg, SAR_TIMEOUT);
180
181
182 if (!status) {
183 pr_debug("%s: Loopback message successfully sent\n",
184 sc_adapter[card]->devicename);
185 if(strcmp(rspmsg.msg_data.byte_array, testmsg)) {
186 pr_debug("%s: Loopback return != sent\n",
187 sc_adapter[card]->devicename);
188 return -EIO;
189 }
190 return 0;
191 }
192 else {
193 pr_debug("%s: Send loopback message failed\n",
194 sc_adapter[card]->devicename);
195 return -EIO;
196 }
197
198}
199
200/*
201 * start the onboard firmware
202 */
203int startproc(int card)
204{
205 int status;
206
207 if(!IS_VALID_CARD(card)) {
208 pr_debug("Invalid param: %d is not a valid card id\n", card);
209 return -ENODEV;
210 }
211
212 /*
213 * send start msg
214 */
215 status = sendmessage(card, CMPID,cmReqType2,
216 cmReqClass0,
217 cmReqStartProc,
218 0,0,NULL);
219 pr_debug("%s: Sent startProc\n", sc_adapter[card]->devicename);
220
221 return status;
222}
223
224
225int loadproc(int card, char *data)
226{
227 return -1;
228}
229
230
231/*
232 * Dials the number passed in
233 */
234int dial(int card, unsigned long channel, setup_parm setup)
235{
236 int status;
237 char Phone[48];
238
239 if(!IS_VALID_CARD(card)) {
240 pr_debug("Invalid param: %d is not a valid card id\n", card);
241 return -ENODEV;
242 }
243
244 /*extract ISDN number to dial from eaz/msn string*/
245 strcpy(Phone,setup.phone);
246
247 /*send the connection message*/
248 status = sendmessage(card, CEPID,ceReqTypePhy,
249 ceReqClass1,
250 ceReqPhyConnect,
251 (unsigned char) channel+1,
252 strlen(Phone),
253 (unsigned int *) Phone);
254
255 pr_debug("%s: Dialing %s on channel %d\n",
256 sc_adapter[card]->devicename, Phone, channel+1);
257
258 return status;
259}
260
261/*
262 * Answer an incoming call
263 */
264int answer(int card, unsigned long channel)
265{
266 if(!IS_VALID_CARD(card)) {
267 pr_debug("Invalid param: %d is not a valid card id\n", card);
268 return -ENODEV;
269 }
270
271 if(setup_buffers(card, channel+1, BUFFER_SIZE)) {
272 hangup(card, channel+1);
273 return -ENOBUFS;
274 }
275
276 indicate_status(card, ISDN_STAT_BCONN,channel,NULL);
277 pr_debug("%s: Answered incoming call on channel %s\n",
278 sc_adapter[card]->devicename, channel+1);
279 return 0;
280}
281
282/*
283 * Hangup up the call on specified channel
284 */
285int hangup(int card, unsigned long channel)
286{
287 int status;
288
289 if(!IS_VALID_CARD(card)) {
290 pr_debug("Invalid param: %d is not a valid card id\n", card);
291 return -ENODEV;
292 }
293
294 status = sendmessage(card, CEPID, ceReqTypePhy,
295 ceReqClass1,
296 ceReqPhyDisconnect,
297 (unsigned char) channel+1,
298 0,
299 NULL);
300 pr_debug("%s: Sent HANGUP message to channel %d\n",
301 sc_adapter[card]->devicename, channel+1);
302 return status;
303}
304
305/*
306 * Set the layer 2 protocol (X.25, HDLC, Raw)
307 */
308int setl2(int card, unsigned long arg)
309{
310 int status =0;
311 int protocol,channel;
312
313 if(!IS_VALID_CARD(card)) {
314 pr_debug("Invalid param: %d is not a valid card id\n", card);
315 return -ENODEV;
316 }
317 protocol = arg >> 8;
318 channel = arg & 0xff;
319 sc_adapter[card]->channel[channel].l2_proto = protocol;
320 pr_debug("%s: Level 2 protocol for channel %d set to %s from %d\n",
321 sc_adapter[card]->devicename, channel+1,
322 l2protos[sc_adapter[card]->channel[channel].l2_proto],protocol);
323
324 /*
325 * check that the adapter is also set to the correct protocol
326 */
327 pr_debug("%s: Sending GetFrameFormat for channel %d\n",
328 sc_adapter[card]->devicename, channel+1);
329 status = sendmessage(card, CEPID, ceReqTypeCall,
330 ceReqClass0,
331 ceReqCallGetFrameFormat,
332 (unsigned char)channel+1,
333 1,
334 (unsigned int *) protocol);
335 if(status)
336 return status;
337 return 0;
338}
339
340/*
341 * Set the layer 3 protocol
342 */
343int setl3(int card, unsigned long channel)
344{
345 int protocol = channel >> 8;
346
347 if(!IS_VALID_CARD(card)) {
348 pr_debug("Invalid param: %d is not a valid card id\n", card);
349 return -ENODEV;
350 }
351
352 sc_adapter[card]->channel[channel].l3_proto = protocol;
353 pr_debug("%s: Level 3 protocol for channel %d set to %s\n",
354 sc_adapter[card]->devicename, channel+1, l3protos[protocol]);
355 return 0;
356}
357
358int acceptb(int card, unsigned long channel)
359{
360 if(!IS_VALID_CARD(card)) {
361 pr_debug("Invalid param: %d is not a valid card id\n", card);
362 return -ENODEV;
363 }
364
365 if(setup_buffers(card, channel+1, BUFFER_SIZE))
366 {
367 hangup(card, channel+1);
368 return -ENOBUFS;
369 }
370
371 pr_debug("%s: B-Channel connection accepted on channel %d\n",
372 sc_adapter[card]->devicename, channel+1);
373 indicate_status(card, ISDN_STAT_BCONN, channel, NULL);
374 return 0;
375}
376
377int clreaz(int card, unsigned long arg)
378{
379 if(!IS_VALID_CARD(card)) {
380 pr_debug("Invalid param: %d is not a valid card id\n", card);
381 return -ENODEV;
382 }
383
384 strcpy(sc_adapter[card]->channel[arg].eazlist, "");
385 sc_adapter[card]->channel[arg].eazclear = 1;
386 pr_debug("%s: EAZ List cleared for channel %d\n",
387 sc_adapter[card]->devicename, arg+1);
388 return 0;
389}
390
391int seteaz(int card, unsigned long arg, char *num)
392{
393 if(!IS_VALID_CARD(card)) {
394 pr_debug("Invalid param: %d is not a valid card id\n", card);
395 return -ENODEV;
396 }
397
398 strcpy(sc_adapter[card]->channel[arg].eazlist, num);
399 sc_adapter[card]->channel[arg].eazclear = 0;
400 pr_debug("%s: EAZ list for channel %d set to: %s\n",
401 sc_adapter[card]->devicename, arg+1,
402 sc_adapter[card]->channel[arg].eazlist);
403 return 0;
404}
405
406int reset(int card)
407{
408 unsigned long flags;
409
410 if(!IS_VALID_CARD(card)) {
411 pr_debug("Invalid param: %d is not a valid card id\n", card);
412 return -ENODEV;
413 }
414
415 indicate_status(card, ISDN_STAT_STOP, 0, NULL);
416
417 if(sc_adapter[card]->EngineUp) {
418 del_timer(&sc_adapter[card]->stat_timer);
419 }
420
421 sc_adapter[card]->EngineUp = 0;
422
423 spin_lock_irqsave(&sc_adapter[card]->lock, flags);
424 init_timer(&sc_adapter[card]->reset_timer);
425 sc_adapter[card]->reset_timer.function = check_reset;
426 sc_adapter[card]->reset_timer.data = card;
427 sc_adapter[card]->reset_timer.expires = jiffies + CHECKRESET_TIME;
428 add_timer(&sc_adapter[card]->reset_timer);
429 spin_unlock_irqrestore(&sc_adapter[card]->lock, flags);
430
431 outb(0x1,sc_adapter[card]->ioport[SFT_RESET]);
432
433 pr_debug("%s: Adapter Reset\n", sc_adapter[card]->devicename);
434 return 0;
435}
436
437void flushreadfifo (int card)
438{
439 while(inb(sc_adapter[card]->ioport[FIFO_STATUS]) & RF_HAS_DATA)
440 inb(sc_adapter[card]->ioport[FIFO_READ]);
441}
diff --git a/drivers/isdn/sc/debug.c b/drivers/isdn/sc/debug.c
new file mode 100644
index 000000000000..1a992a75868b
--- /dev/null
+++ b/drivers/isdn/sc/debug.c
@@ -0,0 +1,46 @@
1/* $Id: debug.c,v 1.5.6.1 2001/09/23 22:24:59 kai Exp $
2 *
3 * Copyright (C) 1996 SpellCaster Telecommunications Inc.
4 *
5 * This software may be used and distributed according to the terms
6 * of the GNU General Public License, incorporated herein by reference.
7 *
8 * For more information, please contact gpl-info@spellcast.com or write:
9 *
10 * SpellCaster Telecommunications Inc.
11 * 5621 Finch Avenue East, Unit #3
12 * Scarborough, Ontario Canada
13 * M1B 2T9
14 * +1 (416) 297-8565
15 * +1 (416) 297-6433 Facsimile
16 */
17
18#include <linux/kernel.h>
19#include <linux/string.h>
20
21int dbg_level = 0;
22static char dbg_funcname[255];
23
24void dbg_endfunc(void)
25{
26 if (dbg_level) {
27 printk("<-- Leaving function %s\n", dbg_funcname);
28 strcpy(dbg_funcname, "");
29 }
30}
31
32void dbg_func(char *func)
33{
34 strcpy(dbg_funcname, func);
35 if(dbg_level)
36 printk("--> Entering function %s\n", dbg_funcname);
37}
38
39inline void pullphone(char *dn, char *str)
40{
41 int i = 0;
42
43 while(dn[i] != ',')
44 str[i] = dn[i], i++;
45 str[i] = 0x0;
46}
diff --git a/drivers/isdn/sc/debug.h b/drivers/isdn/sc/debug.h
new file mode 100644
index 000000000000..e9db96ede4b2
--- /dev/null
+++ b/drivers/isdn/sc/debug.h
@@ -0,0 +1,19 @@
1/* $Id: debug.h,v 1.2.8.1 2001/09/23 22:24:59 kai Exp $
2 *
3 * Copyright (C) 1996 SpellCaster Telecommunications Inc.
4 *
5 * This software may be used and distributed according to the terms
6 * of the GNU General Public License, incorporated herein by reference.
7 *
8 * For more information, please contact gpl-info@spellcast.com or write:
9 *
10 * SpellCaster Telecommunications Inc.
11 * 5621 Finch Avenue East, Unit #3
12 * Scarborough, Ontario Canada
13 * M1B 2T9
14 * +1 (416) 297-8565
15 * +1 (416) 297-6433 Facsimile
16 */
17
18#define REQUEST_IRQ(a,b,c,d,e) request_irq(a,b,c,d,e)
19#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 000000000000..5b8c7c1a7663
--- /dev/null
+++ b/drivers/isdn/sc/event.c
@@ -0,0 +1,69 @@
1/* $Id: event.c,v 1.4.8.1 2001/09/23 22:24:59 kai Exp $
2 *
3 * Copyright (C) 1996 SpellCaster Telecommunications Inc.
4 *
5 * This software may be used and distributed according to the terms
6 * of the GNU General Public License, incorporated herein by reference.
7 *
8 * For more information, please contact gpl-info@spellcast.com or write:
9 *
10 * SpellCaster Telecommunications Inc.
11 * 5621 Finch Avenue East, Unit #3
12 * Scarborough, Ontario Canada
13 * M1B 2T9
14 * +1 (416) 297-8565
15 * +1 (416) 297-6433 Facsimile
16 */
17
18#include "includes.h"
19#include "hardware.h"
20#include "message.h"
21#include "card.h"
22
23extern int cinst;
24extern board *sc_adapter[];
25
26#ifdef DEBUG
27static char *events[] = { "ISDN_STAT_STAVAIL",
28 "ISDN_STAT_ICALL",
29 "ISDN_STAT_RUN",
30 "ISDN_STAT_STOP",
31 "ISDN_STAT_DCONN",
32 "ISDN_STAT_BCONN",
33 "ISDN_STAT_DHUP",
34 "ISDN_STAT_BHUP",
35 "ISDN_STAT_CINF",
36 "ISDN_STAT_LOAD",
37 "ISDN_STAT_UNLOAD",
38 "ISDN_STAT_BSENT",
39 "ISDN_STAT_NODCH",
40 "ISDN_STAT_ADDCH",
41 "ISDN_STAT_CAUSE" };
42#endif
43
44int indicate_status(int card, int event,ulong Channel,char *Data)
45{
46 isdn_ctrl cmd;
47
48 pr_debug("%s: Indicating event %s on Channel %d\n",
49 sc_adapter[card]->devicename, events[event-256], Channel);
50 if (Data != NULL){
51 pr_debug("%s: Event data: %s\n", sc_adapter[card]->devicename,
52 Data);
53 switch (event) {
54 case ISDN_STAT_BSENT:
55 memcpy(&cmd.parm.length, Data, sizeof(cmd.parm.length));
56 break;
57 case ISDN_STAT_ICALL:
58 memcpy(&cmd.parm.setup, Data, sizeof(cmd.parm.setup));
59 break;
60 default:
61 strcpy(cmd.parm.num, Data);
62 }
63 }
64
65 cmd.command = event;
66 cmd.driver = sc_adapter[card]->driverId;
67 cmd.arg = Channel;
68 return sc_adapter[card]->card->statcallb(&cmd);
69}
diff --git a/drivers/isdn/sc/hardware.h b/drivers/isdn/sc/hardware.h
new file mode 100644
index 000000000000..9e6d5302bf8e
--- /dev/null
+++ b/drivers/isdn/sc/hardware.h
@@ -0,0 +1,110 @@
1/*
2 * Hardware specific macros, defines and structures
3 *
4 * This software may be used and distributed according to the terms
5 * of the GNU General Public License, incorporated herein by reference.
6 *
7 */
8
9#ifndef HARDWARE_H
10#define HARDWARE_H
11
12#include <asm/param.h> /* For HZ */
13
14/*
15 * General hardware parameters common to all ISA adapters
16 */
17
18#define MAX_CARDS 4 /* The maximum number of cards to
19 control or probe for. */
20
21#define SIGNATURE 0x87654321 /* Board reset signature */
22#define SIG_OFFSET 0x1004 /* Where to find signature in shared RAM */
23#define TRACE_OFFSET 0x1008 /* Trace enable word offset in shared RAM */
24#define BUFFER_OFFSET 0x1800 /* Beginning of buffers */
25
26/* I/O Port parameters */
27#define IOBASE_MIN 0x180 /* Lowest I/O port address */
28#define IOBASE_MAX 0x3C0 /* Highest I/O port address */
29#define IOBASE_OFFSET 0x20 /* Inter-board I/O port gap used during
30 probing */
31#define FIFORD_OFFSET 0x0
32#define FIFOWR_OFFSET 0x400
33#define FIFOSTAT_OFFSET 0x1000
34#define RESET_OFFSET 0x2800
35#define PG0_OFFSET 0x3000 /* Offset from I/O Base for Page 0 register */
36#define PG1_OFFSET 0x3400 /* Offset from I/O Base for Page 1 register */
37#define PG2_OFFSET 0x3800 /* Offset from I/O Base for Page 2 register */
38#define PG3_OFFSET 0x3C00 /* Offset from I/O Base for Page 3 register */
39
40#define FIFO_READ 0 /* FIFO Read register */
41#define FIFO_WRITE 1 /* FIFO Write rgister */
42#define LO_ADDR_PTR 2 /* Extended RAM Low Addr Pointer */
43#define HI_ADDR_PTR 3 /* Extended RAM High Addr Pointer */
44#define NOT_USED_1 4
45#define FIFO_STATUS 5 /* FIFO Status Register */
46#define NOT_USED_2 6
47#define MEM_OFFSET 7
48#define SFT_RESET 10 /* Reset Register */
49#define EXP_BASE 11 /* Shared RAM Base address */
50#define EXP_PAGE0 12 /* Shared RAM Page0 register */
51#define EXP_PAGE1 13 /* Shared RAM Page1 register */
52#define EXP_PAGE2 14 /* Shared RAM Page2 register */
53#define EXP_PAGE3 15 /* Shared RAM Page3 register */
54#define IRQ_SELECT 16 /* IRQ selection register */
55#define MAX_IO_REGS 17 /* Total number of I/O ports */
56
57/* FIFO register values */
58#define RF_HAS_DATA 0x01 /* fifo has data */
59#define RF_QUART_FULL 0x02 /* fifo quarter full */
60#define RF_HALF_FULL 0x04 /* fifo half full */
61#define RF_NOT_FULL 0x08 /* fifo not full */
62#define WF_HAS_DATA 0x10 /* fifo has data */
63#define WF_QUART_FULL 0x20 /* fifo quarter full */
64#define WF_HALF_FULL 0x40 /* fifo half full */
65#define WF_NOT_FULL 0x80 /* fifo not full */
66
67/* Shared RAM parameters */
68#define SRAM_MIN 0xC0000 /* Lowest host shared RAM address */
69#define SRAM_MAX 0xEFFFF /* Highest host shared RAM address */
70#define SRAM_PAGESIZE 0x4000 /* Size of one RAM page (16K) */
71
72/* Shared RAM buffer parameters */
73#define BUFFER_SIZE 0x800 /* The size of a buffer in bytes */
74#define BUFFER_BASE BUFFER_OFFSET /* Offset from start of shared RAM
75 where buffer start */
76#define BUFFERS_MAX 16 /* Maximum number of send/receive
77 buffers per channel */
78#define HDLC_PROTO 0x01 /* Frame Format for Layer 2 */
79
80#define BRI_BOARD 0
81#define POTS_BOARD 1
82#define PRI_BOARD 2
83
84/*
85 * Specific hardware parameters for the DataCommute/BRI
86 */
87#define BRI_CHANNELS 2 /* Number of B channels */
88#define BRI_BASEPG_VAL 0x98
89#define BRI_MAGIC 0x60000 /* Magic Number */
90#define BRI_MEMSIZE 0x10000 /* Ammount of RAM (64K) */
91#define BRI_PARTNO "72-029"
92#define BRI_FEATURES ISDN_FEATURE_L2_HDLC | ISDN_FEATURE_L3_TRANS;
93/*
94 * Specific hardware parameters for the DataCommute/PRI
95 */
96#define PRI_CHANNELS 23 /* Number of B channels */
97#define PRI_BASEPG_VAL 0x88
98#define PRI_MAGIC 0x20000 /* Magic Number */
99#define PRI_MEMSIZE 0x100000 /* Amount of RAM (1M) */
100#define PRI_PARTNO "72-030"
101#define PRI_FEATURES ISDN_FEATURE_L2_HDLC | ISDN_FEATURE_L3_TRANS;
102
103/*
104 * Some handy macros
105 */
106
107/* Determine if a channel number is valid for the adapter */
108#define IS_VALID_CHANNEL(y,x) ((x>0) && (x <= sc_adapter[y]->channels))
109
110#endif
diff --git a/drivers/isdn/sc/includes.h b/drivers/isdn/sc/includes.h
new file mode 100644
index 000000000000..4611da6e9231
--- /dev/null
+++ b/drivers/isdn/sc/includes.h
@@ -0,0 +1,18 @@
1/*
2 * This software may be used and distributed according to the terms
3 * of the GNU General Public License, incorporated herein by reference.
4 *
5 */
6
7#include <linux/version.h>
8#include <linux/errno.h>
9#include <asm/io.h>
10#include <linux/delay.h>
11#include <linux/kernel.h>
12#include <linux/slab.h>
13#include <linux/mm.h>
14#include <linux/ioport.h>
15#include <linux/timer.h>
16#include <linux/wait.h>
17#include <linux/isdnif.h>
18#include "debug.h"
diff --git a/drivers/isdn/sc/init.c b/drivers/isdn/sc/init.c
new file mode 100644
index 000000000000..efefedea37b9
--- /dev/null
+++ b/drivers/isdn/sc/init.c
@@ -0,0 +1,571 @@
1/*
2 * This software may be used and distributed according to the terms
3 * of the GNU General Public License, incorporated herein by reference.
4 *
5 */
6
7#include <linux/module.h>
8#include <linux/init.h>
9#include <linux/interrupt.h>
10#include <linux/delay.h>
11#include "includes.h"
12#include "hardware.h"
13#include "card.h"
14
15MODULE_DESCRIPTION("ISDN4Linux: Driver for Spellcaster card");
16MODULE_AUTHOR("Spellcaster Telecommunications Inc.");
17MODULE_LICENSE("GPL");
18
19board *sc_adapter[MAX_CARDS];
20int cinst;
21
22static char devname[] = "scX";
23const char version[] = "2.0b1";
24
25const char *boardname[] = { "DataCommute/BRI", "DataCommute/PRI", "TeleCommute/BRI" };
26
27/* insmod set parameters */
28static unsigned int io[] = {0,0,0,0};
29static unsigned char irq[] = {0,0,0,0};
30static unsigned long ram[] = {0,0,0,0};
31static int do_reset = 0;
32
33module_param_array(io, int, NULL, 0);
34module_param_array(irq, int, NULL, 0);
35module_param_array(ram, int, NULL, 0);
36module_param(do_reset, bool, 0);
37
38static int sup_irq[] = { 11, 10, 9, 5, 12, 14, 7, 3, 4, 6 };
39#define MAX_IRQS 10
40
41extern irqreturn_t interrupt_handler(int, void *, struct pt_regs *);
42extern int sndpkt(int, int, int, struct sk_buff *);
43extern int command(isdn_ctrl *);
44extern int indicate_status(int, int, ulong, char*);
45extern int reset(int);
46
47int identify_board(unsigned long, unsigned int);
48
49int irq_supported(int irq_x)
50{
51 int i;
52 for(i=0 ; i < MAX_IRQS ; i++) {
53 if(sup_irq[i] == irq_x)
54 return 1;
55 }
56 return 0;
57}
58
59static int __init sc_init(void)
60{
61 int b = -1;
62 int i, j;
63 int status = -ENODEV;
64
65 unsigned long memsize = 0;
66 unsigned long features = 0;
67 isdn_if *interface;
68 unsigned char channels;
69 unsigned char pgport;
70 unsigned long magic;
71 int model;
72 int last_base = IOBASE_MIN;
73 int probe_exhasted = 0;
74
75#ifdef MODULE
76 pr_info("SpellCaster ISA ISDN Adapter Driver rev. %s Loaded\n", version);
77#else
78 pr_info("SpellCaster ISA ISDN Adapter Driver rev. %s\n", version);
79#endif
80 pr_info("Copyright (C) 1996 SpellCaster Telecommunications Inc.\n");
81
82 while(b++ < MAX_CARDS - 1) {
83 pr_debug("Probing for adapter #%d\n", b);
84 /*
85 * Initialize reusable variables
86 */
87 model = -1;
88 magic = 0;
89 channels = 0;
90 pgport = 0;
91
92 /*
93 * See if we should probe for IO base
94 */
95 pr_debug("I/O Base for board %d is 0x%x, %s probe\n", b, io[b],
96 io[b] == 0 ? "will" : "won't");
97 if(io[b]) {
98 /*
99 * No, I/O Base has been provided
100 */
101 for (i = 0 ; i < MAX_IO_REGS - 1 ; i++) {
102 if(!request_region(io[b] + i * 0x400, 1, "sc test")) {
103 pr_debug("check_region for 0x%x failed\n", io[b] + i * 0x400);
104 io[b] = 0;
105 break;
106 } else
107 release_region(io[b] + i * 0x400, 1);
108 }
109
110 /*
111 * Confirm the I/O Address with a test
112 */
113 if(io[b] == 0) {
114 pr_debug("I/O Address 0x%x is in use.\n");
115 continue;
116 }
117
118 outb(0x18, io[b] + 0x400 * EXP_PAGE0);
119 if(inb(io[b] + 0x400 * EXP_PAGE0) != 0x18) {
120 pr_debug("I/O Base 0x%x fails test\n");
121 continue;
122 }
123 }
124 else {
125 /*
126 * Yes, probe for I/O Base
127 */
128 if(probe_exhasted) {
129 pr_debug("All probe addresses exhasted, skipping\n");
130 continue;
131 }
132 pr_debug("Probing for I/O...\n");
133 for (i = last_base ; i <= IOBASE_MAX ; i += IOBASE_OFFSET) {
134 int found_io = 1;
135 if (i == IOBASE_MAX) {
136 probe_exhasted = 1; /* No more addresses to probe */
137 pr_debug("End of Probes\n");
138 }
139 last_base = i + IOBASE_OFFSET;
140 pr_debug(" checking 0x%x...", i);
141 for ( j = 0 ; j < MAX_IO_REGS - 1 ; j++) {
142 if(!request_region(i + j * 0x400, 1, "sc test")) {
143 pr_debug("Failed\n");
144 found_io = 0;
145 break;
146 } else
147 release_region(i + j * 0x400, 1);
148 }
149
150 if(found_io) {
151 io[b] = i;
152 outb(0x18, io[b] + 0x400 * EXP_PAGE0);
153 if(inb(io[b] + 0x400 * EXP_PAGE0) != 0x18) {
154 pr_debug("Failed by test\n");
155 continue;
156 }
157 pr_debug("Passed\n");
158 break;
159 }
160 }
161 if(probe_exhasted) {
162 continue;
163 }
164 }
165
166 /*
167 * See if we should probe for shared RAM
168 */
169 if(do_reset) {
170 pr_debug("Doing a SAFE probe reset\n");
171 outb(0xFF, io[b] + RESET_OFFSET);
172 msleep_interruptible(10000);
173 }
174 pr_debug("RAM Base for board %d is 0x%x, %s probe\n", b, ram[b],
175 ram[b] == 0 ? "will" : "won't");
176
177 if(ram[b]) {
178 /*
179 * No, the RAM base has been provided
180 * Just look for a signature and ID the
181 * board model
182 */
183 if(request_region(ram[b], SRAM_PAGESIZE, "sc test")) {
184 pr_debug("request_region for RAM base 0x%x succeeded\n", ram[b]);
185 model = identify_board(ram[b], io[b]);
186 release_region(ram[b], SRAM_PAGESIZE);
187 }
188 }
189 else {
190 /*
191 * Yes, probe for free RAM and look for
192 * a signature and id the board model
193 */
194 for (i = SRAM_MIN ; i < SRAM_MAX ; i += SRAM_PAGESIZE) {
195 pr_debug("Checking RAM address 0x%x...\n", i);
196 if(request_region(i, SRAM_PAGESIZE, "sc test")) {
197 pr_debug(" check_region succeeded\n");
198 model = identify_board(i, io[b]);
199 release_region(i, SRAM_PAGESIZE);
200 if (model >= 0) {
201 pr_debug(" Identified a %s\n",
202 boardname[model]);
203 ram[b] = i;
204 break;
205 }
206 pr_debug(" Unidentifed or inaccessible\n");
207 continue;
208 }
209 pr_debug(" request failed\n");
210 }
211 }
212 /*
213 * See if we found free RAM and the board model
214 */
215 if(!ram[b] || model < 0) {
216 /*
217 * Nope, there was no place in RAM for the
218 * board, or it couldn't be identified
219 */
220 pr_debug("Failed to find an adapter at 0x%x\n", ram[b]);
221 continue;
222 }
223
224 /*
225 * Set the board's magic number, memory size and page register
226 */
227 switch(model) {
228 case PRI_BOARD:
229 channels = 23;
230 magic = 0x20000;
231 memsize = 0x100000;
232 features = PRI_FEATURES;
233 break;
234
235 case BRI_BOARD:
236 case POTS_BOARD:
237 channels = 2;
238 magic = 0x60000;
239 memsize = 0x10000;
240 features = BRI_FEATURES;
241 break;
242 }
243 switch(ram[b] >> 12 & 0x0F) {
244 case 0x0:
245 pr_debug("RAM Page register set to EXP_PAGE0\n");
246 pgport = EXP_PAGE0;
247 break;
248
249 case 0x4:
250 pr_debug("RAM Page register set to EXP_PAGE1\n");
251 pgport = EXP_PAGE1;
252 break;
253
254 case 0x8:
255 pr_debug("RAM Page register set to EXP_PAGE2\n");
256 pgport = EXP_PAGE2;
257 break;
258
259 case 0xC:
260 pr_debug("RAM Page register set to EXP_PAGE3\n");
261 pgport = EXP_PAGE3;
262 break;
263
264 default:
265 pr_debug("RAM base address doesn't fall on 16K boundary\n");
266 continue;
267 }
268
269 pr_debug("current IRQ: %d b: %d\n",irq[b],b);
270
271 /*
272 * Make sure we got an IRQ
273 */
274 if(!irq[b]) {
275 /*
276 * No interrupt could be used
277 */
278 pr_debug("Failed to acquire an IRQ line\n");
279 continue;
280 }
281
282 /*
283 * Horray! We found a board, Make sure we can register
284 * it with ISDN4Linux
285 */
286 interface = kmalloc(sizeof(isdn_if), GFP_KERNEL);
287 if (interface == NULL) {
288 /*
289 * Oops, can't malloc isdn_if
290 */
291 continue;
292 }
293 memset(interface, 0, sizeof(isdn_if));
294
295 interface->owner = THIS_MODULE;
296 interface->hl_hdrlen = 0;
297 interface->channels = channels;
298 interface->maxbufsize = BUFFER_SIZE;
299 interface->features = features;
300 interface->writebuf_skb = sndpkt;
301 interface->writecmd = NULL;
302 interface->command = command;
303 strcpy(interface->id, devname);
304 interface->id[2] = '0' + cinst;
305
306 /*
307 * Allocate the board structure
308 */
309 sc_adapter[cinst] = kmalloc(sizeof(board), GFP_KERNEL);
310 if (sc_adapter[cinst] == NULL) {
311 /*
312 * Oops, can't alloc memory for the board
313 */
314 kfree(interface);
315 continue;
316 }
317 memset(sc_adapter[cinst], 0, sizeof(board));
318 spin_lock_init(&sc_adapter[cinst]->lock);
319
320 if(!register_isdn(interface)) {
321 /*
322 * Oops, couldn't register for some reason
323 */
324 kfree(interface);
325 kfree(sc_adapter[cinst]);
326 continue;
327 }
328
329 sc_adapter[cinst]->card = interface;
330 sc_adapter[cinst]->driverId = interface->channels;
331 strcpy(sc_adapter[cinst]->devicename, interface->id);
332 sc_adapter[cinst]->nChannels = channels;
333 sc_adapter[cinst]->ramsize = memsize;
334 sc_adapter[cinst]->shmem_magic = magic;
335 sc_adapter[cinst]->shmem_pgport = pgport;
336 sc_adapter[cinst]->StartOnReset = 1;
337
338 /*
339 * Allocate channels status structures
340 */
341 sc_adapter[cinst]->channel = kmalloc(sizeof(bchan) * channels, GFP_KERNEL);
342 if (sc_adapter[cinst]->channel == NULL) {
343 /*
344 * Oops, can't alloc memory for the channels
345 */
346 indicate_status(cinst, ISDN_STAT_UNLOAD, 0, NULL); /* Fix me */
347 kfree(interface);
348 kfree(sc_adapter[cinst]);
349 continue;
350 }
351 memset(sc_adapter[cinst]->channel, 0, sizeof(bchan) * channels);
352
353 /*
354 * Lock down the hardware resources
355 */
356 sc_adapter[cinst]->interrupt = irq[b];
357 if (request_irq(sc_adapter[cinst]->interrupt, interrupt_handler,
358 SA_INTERRUPT, interface->id, NULL))
359 {
360 kfree(sc_adapter[cinst]->channel);
361 indicate_status(cinst, ISDN_STAT_UNLOAD, 0, NULL); /* Fix me */
362 kfree(interface);
363 kfree(sc_adapter[cinst]);
364 continue;
365
366 }
367 sc_adapter[cinst]->iobase = io[b];
368 for(i = 0 ; i < MAX_IO_REGS - 1 ; i++) {
369 sc_adapter[cinst]->ioport[i] = io[b] + i * 0x400;
370 request_region(sc_adapter[cinst]->ioport[i], 1,
371 interface->id);
372 pr_debug("Requesting I/O Port %#x\n",
373 sc_adapter[cinst]->ioport[i]);
374 }
375 sc_adapter[cinst]->ioport[IRQ_SELECT] = io[b] + 0x2;
376 request_region(sc_adapter[cinst]->ioport[IRQ_SELECT], 1,
377 interface->id);
378 pr_debug("Requesting I/O Port %#x\n",
379 sc_adapter[cinst]->ioport[IRQ_SELECT]);
380 sc_adapter[cinst]->rambase = ram[b];
381 request_region(sc_adapter[cinst]->rambase, SRAM_PAGESIZE,
382 interface->id);
383
384 pr_info(" %s (%d) - %s %d channels IRQ %d, I/O Base 0x%x, RAM Base 0x%lx\n",
385 sc_adapter[cinst]->devicename,
386 sc_adapter[cinst]->driverId,
387 boardname[model], channels, irq[b], io[b], ram[b]);
388
389 /*
390 * reset the adapter to put things in motion
391 */
392 reset(cinst);
393
394 cinst++;
395 status = 0;
396 }
397 if (status)
398 pr_info("Failed to find any adapters, driver unloaded\n");
399 return status;
400}
401
402static void __exit sc_exit(void)
403{
404 int i, j;
405
406 for(i = 0 ; i < cinst ; i++) {
407 pr_debug("Cleaning up after adapter %d\n", i);
408 /*
409 * kill the timers
410 */
411 del_timer(&(sc_adapter[i]->reset_timer));
412 del_timer(&(sc_adapter[i]->stat_timer));
413
414 /*
415 * Tell I4L we're toast
416 */
417 indicate_status(i, ISDN_STAT_STOP, 0, NULL);
418 indicate_status(i, ISDN_STAT_UNLOAD, 0, NULL);
419
420 /*
421 * Release shared RAM
422 */
423 release_region(sc_adapter[i]->rambase, SRAM_PAGESIZE);
424
425 /*
426 * Release the IRQ
427 */
428 FREE_IRQ(sc_adapter[i]->interrupt, NULL);
429
430 /*
431 * Reset for a clean start
432 */
433 outb(0xFF, sc_adapter[i]->ioport[SFT_RESET]);
434
435 /*
436 * Release the I/O Port regions
437 */
438 for(j = 0 ; j < MAX_IO_REGS - 1; j++) {
439 release_region(sc_adapter[i]->ioport[j], 1);
440 pr_debug("Releasing I/O Port %#x\n",
441 sc_adapter[i]->ioport[j]);
442 }
443 release_region(sc_adapter[i]->ioport[IRQ_SELECT], 1);
444 pr_debug("Releasing I/O Port %#x\n",
445 sc_adapter[i]->ioport[IRQ_SELECT]);
446
447 /*
448 * Release any memory we alloced
449 */
450 kfree(sc_adapter[i]->channel);
451 kfree(sc_adapter[i]->card);
452 kfree(sc_adapter[i]);
453 }
454 pr_info("SpellCaster ISA ISDN Adapter Driver Unloaded.\n");
455}
456
457int identify_board(unsigned long rambase, unsigned int iobase)
458{
459 unsigned int pgport;
460 unsigned long sig;
461 DualPortMemory *dpm;
462 RspMessage rcvmsg;
463 ReqMessage sndmsg;
464 HWConfig_pl hwci;
465 int x;
466
467 pr_debug("Attempting to identify adapter @ 0x%x io 0x%x\n",
468 rambase, iobase);
469
470 /*
471 * Enable the base pointer
472 */
473 outb(rambase >> 12, iobase + 0x2c00);
474
475 switch(rambase >> 12 & 0x0F) {
476 case 0x0:
477 pgport = iobase + PG0_OFFSET;
478 pr_debug("Page Register offset is 0x%x\n", PG0_OFFSET);
479 break;
480
481 case 0x4:
482 pgport = iobase + PG1_OFFSET;
483 pr_debug("Page Register offset is 0x%x\n", PG1_OFFSET);
484 break;
485
486 case 0x8:
487 pgport = iobase + PG2_OFFSET;
488 pr_debug("Page Register offset is 0x%x\n", PG2_OFFSET);
489 break;
490
491 case 0xC:
492 pgport = iobase + PG3_OFFSET;
493 pr_debug("Page Register offset is 0x%x\n", PG3_OFFSET);
494 break;
495 default:
496 pr_debug("Invalid rambase 0x%lx\n", rambase);
497 return -1;
498 }
499
500 /*
501 * Try to identify a PRI card
502 */
503 outb(PRI_BASEPG_VAL, pgport);
504 msleep_interruptible(1000);
505 sig = readl(rambase + SIG_OFFSET);
506 pr_debug("Looking for a signature, got 0x%x\n", sig);
507 if(sig == SIGNATURE)
508 return PRI_BOARD;
509
510 /*
511 * Try to identify a PRI card
512 */
513 outb(BRI_BASEPG_VAL, pgport);
514 msleep_interruptible(1000);
515 sig = readl(rambase + SIG_OFFSET);
516 pr_debug("Looking for a signature, got 0x%x\n", sig);
517 if(sig == SIGNATURE)
518 return BRI_BOARD;
519
520 return -1;
521
522 /*
523 * Try to spot a card
524 */
525 sig = readl(rambase + SIG_OFFSET);
526 pr_debug("Looking for a signature, got 0x%x\n", sig);
527 if(sig != SIGNATURE)
528 return -1;
529
530 dpm = (DualPortMemory *) rambase;
531
532 memset(&sndmsg, 0, MSG_LEN);
533 sndmsg.msg_byte_cnt = 3;
534 sndmsg.type = cmReqType1;
535 sndmsg.class = cmReqClass0;
536 sndmsg.code = cmReqHWConfig;
537 memcpy_toio(&(dpm->req_queue[dpm->req_head++]), &sndmsg, MSG_LEN);
538 outb(0, iobase + 0x400);
539 pr_debug("Sent HWConfig message\n");
540 /*
541 * Wait for the response
542 */
543 x = 0;
544 while((inb(iobase + FIFOSTAT_OFFSET) & RF_HAS_DATA) && x < 100) {
545 set_current_state(TASK_INTERRUPTIBLE);
546 schedule_timeout(1);
547 x++;
548 }
549 if(x == 100) {
550 pr_debug("Timeout waiting for response\n");
551 return -1;
552 }
553
554 memcpy_fromio(&rcvmsg, &(dpm->rsp_queue[dpm->rsp_tail]), MSG_LEN);
555 pr_debug("Got HWConfig response, status = 0x%x\n", rcvmsg.rsp_status);
556 memcpy(&hwci, &(rcvmsg.msg_data.HWCresponse), sizeof(HWConfig_pl));
557 pr_debug("Hardware Config: Interface: %s, RAM Size: %d, Serial: %s\n"
558 " Part: %s, Rev: %s\n",
559 hwci.st_u_sense ? "S/T" : "U", hwci.ram_size,
560 hwci.serial_no, hwci.part_no, hwci.rev_no);
561
562 if(!strncmp(PRI_PARTNO, hwci.part_no, 6))
563 return PRI_BOARD;
564 if(!strncmp(BRI_PARTNO, hwci.part_no, 6))
565 return BRI_BOARD;
566
567 return -1;
568}
569
570module_init(sc_init);
571module_exit(sc_exit);
diff --git a/drivers/isdn/sc/interrupt.c b/drivers/isdn/sc/interrupt.c
new file mode 100644
index 000000000000..e5e164aca7fa
--- /dev/null
+++ b/drivers/isdn/sc/interrupt.c
@@ -0,0 +1,260 @@
1/* $Id: interrupt.c,v 1.4.8.3 2001/09/23 22:24:59 kai Exp $
2 *
3 * Copyright (C) 1996 SpellCaster Telecommunications Inc.
4 *
5 * This software may be used and distributed according to the terms
6 * of the GNU General Public License, incorporated herein by reference.
7 *
8 * For more information, please contact gpl-info@spellcast.com or write:
9 *
10 * SpellCaster Telecommunications Inc.
11 * 5621 Finch Avenue East, Unit #3
12 * Scarborough, Ontario Canada
13 * M1B 2T9
14 * +1 (416) 297-8565
15 * +1 (416) 297-6433 Facsimile
16 */
17
18#include "includes.h"
19#include "hardware.h"
20#include "message.h"
21#include "card.h"
22#include <linux/interrupt.h>
23
24extern int indicate_status(int, int, ulong, char *);
25extern void check_phystat(unsigned long);
26extern int receivemessage(int, RspMessage *);
27extern int sendmessage(int, unsigned int, unsigned int, unsigned int,
28 unsigned int, unsigned int, unsigned int, unsigned int *);
29extern void rcvpkt(int, RspMessage *);
30
31extern int cinst;
32extern board *sc_adapter[];
33
34int get_card_from_irq(int irq)
35{
36 int i;
37
38 for(i = 0 ; i < cinst ; i++) {
39 if(sc_adapter[i]->interrupt == irq)
40 return i;
41 }
42 return -1;
43}
44
45/*
46 *
47 */
48irqreturn_t interrupt_handler(int interrupt, void *cardptr, struct pt_regs *regs)
49{
50
51 RspMessage rcvmsg;
52 int channel;
53 int card;
54
55 card = get_card_from_irq(interrupt);
56
57 if(!IS_VALID_CARD(card)) {
58 pr_debug("Invalid param: %d is not a valid card id\n", card);
59 return IRQ_NONE;
60 }
61
62 pr_debug("%s: Entered Interrupt handler\n",
63 sc_adapter[card]->devicename);
64
65 /*
66 * Pull all of the waiting messages off the response queue
67 */
68 while (!receivemessage(card, &rcvmsg)) {
69 /*
70 * Push the message to the adapter structure for
71 * send_and_receive to snoop
72 */
73 if(sc_adapter[card]->want_async_messages)
74 memcpy(&(sc_adapter[card]->async_msg),
75 &rcvmsg, sizeof(RspMessage));
76
77 channel = (unsigned int) rcvmsg.phy_link_no;
78
79 /*
80 * Trap Invalid request messages
81 */
82 if(IS_CM_MESSAGE(rcvmsg, 0, 0, Invalid)) {
83 pr_debug("%s: Invalid request Message, rsp_status = %d\n",
84 sc_adapter[card]->devicename,
85 rcvmsg.rsp_status);
86 break;
87 }
88
89 /*
90 * Check for a linkRead message
91 */
92 if (IS_CE_MESSAGE(rcvmsg, Lnk, 1, Read))
93 {
94 pr_debug("%s: Received packet 0x%x bytes long at 0x%x\n",
95 sc_adapter[card]->devicename,
96 rcvmsg.msg_data.response.msg_len,
97 rcvmsg.msg_data.response.buff_offset);
98 rcvpkt(card, &rcvmsg);
99 continue;
100
101 }
102
103 /*
104 * Handle a write acknoledgement
105 */
106 if(IS_CE_MESSAGE(rcvmsg, Lnk, 1, Write)) {
107 pr_debug("%s: Packet Send ACK on channel %d\n",
108 sc_adapter[card]->devicename,
109 rcvmsg.phy_link_no);
110 sc_adapter[card]->channel[rcvmsg.phy_link_no-1].free_sendbufs++;
111 continue;
112 }
113
114 /*
115 * Handle a connection message
116 */
117 if (IS_CE_MESSAGE(rcvmsg, Phy, 1, Connect))
118 {
119 unsigned int callid;
120 setup_parm setup;
121 pr_debug("%s: Connect message: line %d: status %d: cause 0x%x\n",
122 sc_adapter[card]->devicename,
123 rcvmsg.phy_link_no,
124 rcvmsg.rsp_status,
125 rcvmsg.msg_data.byte_array[2]);
126
127 memcpy(&callid,rcvmsg.msg_data.byte_array,sizeof(int));
128 if(callid>=0x8000 && callid<=0xFFFF)
129 {
130 pr_debug("%s: Got Dial-Out Rsp\n",
131 sc_adapter[card]->devicename);
132 indicate_status(card, ISDN_STAT_DCONN,
133 (unsigned long)rcvmsg.phy_link_no-1,NULL);
134
135 }
136 else if(callid>=0x0000 && callid<=0x7FFF)
137 {
138 pr_debug("%s: Got Incoming Call\n",
139 sc_adapter[card]->devicename);
140 strcpy(setup.phone,&(rcvmsg.msg_data.byte_array[4]));
141 strcpy(setup.eazmsn,
142 sc_adapter[card]->channel[rcvmsg.phy_link_no-1].dn);
143 setup.si1 = 7;
144 setup.si2 = 0;
145 setup.plan = 0;
146 setup.screen = 0;
147
148 indicate_status(card, ISDN_STAT_ICALL,(unsigned long)rcvmsg.phy_link_no-1,(char *)&setup);
149 indicate_status(card, ISDN_STAT_DCONN,(unsigned long)rcvmsg.phy_link_no-1,NULL);
150 }
151 continue;
152 }
153
154 /*
155 * Handle a disconnection message
156 */
157 if (IS_CE_MESSAGE(rcvmsg, Phy, 1, Disconnect))
158 {
159 pr_debug("%s: disconnect message: line %d: status %d: cause 0x%x\n",
160 sc_adapter[card]->devicename,
161 rcvmsg.phy_link_no,
162 rcvmsg.rsp_status,
163 rcvmsg.msg_data.byte_array[2]);
164
165 indicate_status(card, ISDN_STAT_BHUP,(unsigned long)rcvmsg.phy_link_no-1,NULL);
166 indicate_status(card, ISDN_STAT_DHUP,(unsigned long)rcvmsg.phy_link_no-1,NULL);
167 continue;
168
169 }
170
171 /*
172 * Handle a startProc engine up message
173 */
174 if (IS_CM_MESSAGE(rcvmsg, 5, 0, MiscEngineUp)) {
175 pr_debug("%s: Received EngineUp message\n",
176 sc_adapter[card]->devicename);
177 sc_adapter[card]->EngineUp = 1;
178 sendmessage(card, CEPID,ceReqTypeCall,ceReqClass0,ceReqCallGetMyNumber,1,0,NULL);
179 sendmessage(card, CEPID,ceReqTypeCall,ceReqClass0,ceReqCallGetMyNumber,2,0,NULL);
180 init_timer(&sc_adapter[card]->stat_timer);
181 sc_adapter[card]->stat_timer.function = check_phystat;
182 sc_adapter[card]->stat_timer.data = card;
183 sc_adapter[card]->stat_timer.expires = jiffies + CHECKSTAT_TIME;
184 add_timer(&sc_adapter[card]->stat_timer);
185 continue;
186 }
187
188 /*
189 * Start proc response
190 */
191 if (IS_CM_MESSAGE(rcvmsg, 2, 0, StartProc)) {
192 pr_debug("%s: StartProc Response Status %d\n",
193 sc_adapter[card]->devicename,
194 rcvmsg.rsp_status);
195 continue;
196 }
197
198 /*
199 * Handle a GetMyNumber Rsp
200 */
201 if (IS_CE_MESSAGE(rcvmsg,Call,0,GetMyNumber)){
202 strcpy(sc_adapter[card]->channel[rcvmsg.phy_link_no-1].dn,rcvmsg.msg_data.byte_array);
203 continue;
204 }
205
206 /*
207 * PhyStatus response
208 */
209 if(IS_CE_MESSAGE(rcvmsg, Phy, 2, Status)) {
210 unsigned int b1stat, b2stat;
211
212 /*
213 * Covert the message data to the adapter->phystat code
214 */
215 b1stat = (unsigned int) rcvmsg.msg_data.byte_array[0];
216 b2stat = (unsigned int) rcvmsg.msg_data.byte_array[1];
217
218 sc_adapter[card]->nphystat = (b2stat >> 8) | b1stat; /* endian?? */
219 pr_debug("%s: PhyStat is 0x%2x\n",
220 sc_adapter[card]->devicename,
221 sc_adapter[card]->nphystat);
222 continue;
223 }
224
225
226 /*
227 * Handle a GetFramFormat
228 */
229 if(IS_CE_MESSAGE(rcvmsg, Call, 0, GetFrameFormat)) {
230 if(rcvmsg.msg_data.byte_array[0] != HDLC_PROTO) {
231 unsigned int proto = HDLC_PROTO;
232 /*
233 * Set board format to HDLC if it wasn't already
234 */
235 pr_debug("%s: current frame format: 0x%x, will change to HDLC\n",
236 sc_adapter[card]->devicename,
237 rcvmsg.msg_data.byte_array[0]);
238 sendmessage(card, CEPID, ceReqTypeCall,
239 ceReqClass0,
240 ceReqCallSetFrameFormat,
241 (unsigned char) channel +1,
242 1,&proto);
243 }
244 continue;
245 }
246
247 /*
248 * Hmm...
249 */
250 pr_debug("%s: Received unhandled message (%d,%d,%d) link %d\n",
251 sc_adapter[card]->devicename,
252 rcvmsg.type, rcvmsg.class, rcvmsg.code,
253 rcvmsg.phy_link_no);
254
255 } /* while */
256
257 pr_debug("%s: Exiting Interrupt Handler\n",
258 sc_adapter[card]->devicename);
259 return IRQ_HANDLED;
260}
diff --git a/drivers/isdn/sc/ioctl.c b/drivers/isdn/sc/ioctl.c
new file mode 100644
index 000000000000..1371a990416a
--- /dev/null
+++ b/drivers/isdn/sc/ioctl.c
@@ -0,0 +1,601 @@
1/*
2 * Copyright (C) 1996 SpellCaster Telecommunications Inc.
3 *
4 * This software may be used and distributed according to the terms
5 * of the GNU General Public License, incorporated herein by reference.
6 *
7 */
8
9#include "includes.h"
10#include "hardware.h"
11#include "message.h"
12#include "card.h"
13#include "scioc.h"
14
15extern int indicate_status(int, int, unsigned long, char *);
16extern int startproc(int);
17extern int loadproc(int, char *record);
18extern int reset(int);
19extern int send_and_receive(int, unsigned int, unsigned char,unsigned char,
20 unsigned char,unsigned char,
21 unsigned char, unsigned char *, RspMessage *, int);
22
23extern board *sc_adapter[];
24
25
26int GetStatus(int card, boardInfo *);
27
28/*
29 * Process private IOCTL messages (typically from scctrl)
30 */
31int sc_ioctl(int card, scs_ioctl *data)
32{
33 int status;
34 RspMessage *rcvmsg;
35 char *spid;
36 char *dn;
37 char switchtype;
38 char speed;
39
40 rcvmsg = kmalloc(sizeof(RspMessage), GFP_KERNEL);
41 if (!rcvmsg)
42 return -ENOMEM;
43
44 switch(data->command) {
45 case SCIOCRESET: /* Perform a hard reset of the adapter */
46 {
47 pr_debug("%s: SCIOCRESET: ioctl received\n",
48 sc_adapter[card]->devicename);
49 sc_adapter[card]->StartOnReset = 0;
50 return (reset(card));
51 }
52
53 case SCIOCLOAD:
54 {
55 char *srec;
56
57 srec = kmalloc(SCIOC_SRECSIZE, GFP_KERNEL);
58 if (!srec) {
59 kfree(rcvmsg);
60 return -ENOMEM;
61 }
62 pr_debug("%s: SCIOLOAD: ioctl received\n",
63 sc_adapter[card]->devicename);
64 if(sc_adapter[card]->EngineUp) {
65 pr_debug("%s: SCIOCLOAD: command failed, LoadProc while engine running.\n",
66 sc_adapter[card]->devicename);
67 kfree(rcvmsg);
68 kfree(srec);
69 return -1;
70 }
71
72 /*
73 * Get the SRec from user space
74 */
75 if (copy_from_user(srec, data->dataptr, sizeof(srec))) {
76 kfree(rcvmsg);
77 kfree(srec);
78 return -EFAULT;
79 }
80
81 status = send_and_receive(card, CMPID, cmReqType2, cmReqClass0, cmReqLoadProc,
82 0, sizeof(srec), srec, rcvmsg, SAR_TIMEOUT);
83 kfree(rcvmsg);
84 kfree(srec);
85
86 if(status) {
87 pr_debug("%s: SCIOCLOAD: command failed, status = %d\n",
88 sc_adapter[card]->devicename, status);
89 return -1;
90 }
91 else {
92 pr_debug("%s: SCIOCLOAD: command successful\n",
93 sc_adapter[card]->devicename);
94 return 0;
95 }
96 }
97
98 case SCIOCSTART:
99 {
100 pr_debug("%s: SCIOSTART: ioctl received\n",
101 sc_adapter[card]->devicename);
102 if(sc_adapter[card]->EngineUp) {
103 pr_debug("%s: SCIOCSTART: command failed, engine already running.\n",
104 sc_adapter[card]->devicename);
105 return -1;
106 }
107
108 sc_adapter[card]->StartOnReset = 1;
109 startproc(card);
110 return 0;
111 }
112
113 case SCIOCSETSWITCH:
114 {
115 pr_debug("%s: SCIOSETSWITCH: ioctl received\n",
116 sc_adapter[card]->devicename);
117
118 /*
119 * Get the switch type from user space
120 */
121 if (copy_from_user(&switchtype, data->dataptr, sizeof(char))) {
122 kfree(rcvmsg);
123 return -EFAULT;
124 }
125
126 pr_debug("%s: SCIOCSETSWITCH: setting switch type to %d\n",
127 sc_adapter[card]->devicename,
128 switchtype);
129 status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0, ceReqCallSetSwitchType,
130 0, sizeof(char),&switchtype, rcvmsg, SAR_TIMEOUT);
131 if(!status && !(rcvmsg->rsp_status)) {
132 pr_debug("%s: SCIOCSETSWITCH: command successful\n",
133 sc_adapter[card]->devicename);
134 kfree(rcvmsg);
135 return 0;
136 }
137 else {
138 pr_debug("%s: SCIOCSETSWITCH: command failed (status = %d)\n",
139 sc_adapter[card]->devicename, status);
140 kfree(rcvmsg);
141 return status;
142 }
143 }
144
145 case SCIOCGETSWITCH:
146 {
147 pr_debug("%s: SCIOGETSWITCH: ioctl received\n",
148 sc_adapter[card]->devicename);
149
150 /*
151 * Get the switch type from the board
152 */
153 status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0,
154 ceReqCallGetSwitchType, 0, 0, NULL, rcvmsg, SAR_TIMEOUT);
155 if (!status && !(rcvmsg->rsp_status)) {
156 pr_debug("%s: SCIOCGETSWITCH: command successful\n",
157 sc_adapter[card]->devicename);
158 }
159 else {
160 pr_debug("%s: SCIOCGETSWITCH: command failed (status = %d)\n",
161 sc_adapter[card]->devicename, status);
162 kfree(rcvmsg);
163 return status;
164 }
165
166 switchtype = rcvmsg->msg_data.byte_array[0];
167
168 /*
169 * Package the switch type and send to user space
170 */
171 if (copy_to_user(data->dataptr, &switchtype,
172 sizeof(char))) {
173 kfree(rcvmsg);
174 return -EFAULT;
175 }
176
177 kfree(rcvmsg);
178 return 0;
179 }
180
181 case SCIOCGETSPID:
182 {
183 pr_debug("%s: SCIOGETSPID: ioctl received\n",
184 sc_adapter[card]->devicename);
185
186 spid = kmalloc(SCIOC_SPIDSIZE, GFP_KERNEL);
187 if(!spid) {
188 kfree(rcvmsg);
189 return -ENOMEM;
190 }
191 /*
192 * Get the spid from the board
193 */
194 status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0, ceReqCallGetSPID,
195 data->channel, 0, NULL, rcvmsg, SAR_TIMEOUT);
196 if (!status) {
197 pr_debug("%s: SCIOCGETSPID: command successful\n",
198 sc_adapter[card]->devicename);
199 }
200 else {
201 pr_debug("%s: SCIOCGETSPID: command failed (status = %d)\n",
202 sc_adapter[card]->devicename, status);
203 kfree(rcvmsg);
204 return status;
205 }
206 strcpy(spid, rcvmsg->msg_data.byte_array);
207
208 /*
209 * Package the switch type and send to user space
210 */
211 if (copy_to_user(data->dataptr, spid, SCIOC_SPIDSIZE)) {
212 kfree(spid);
213 kfree(rcvmsg);
214 return -EFAULT;
215 }
216
217 kfree(spid);
218 kfree(rcvmsg);
219 return 0;
220 }
221
222 case SCIOCSETSPID:
223 {
224 pr_debug("%s: DCBIOSETSPID: ioctl received\n",
225 sc_adapter[card]->devicename);
226
227 spid = kmalloc(SCIOC_SPIDSIZE, GFP_KERNEL);
228 if(!spid) {
229 kfree(rcvmsg);
230 return -ENOMEM;
231 }
232
233 /*
234 * Get the spid from user space
235 */
236 if (copy_from_user(spid, data->dataptr, SCIOC_SPIDSIZE)) {
237 kfree(rcvmsg);
238 return -EFAULT;
239 }
240
241 pr_debug("%s: SCIOCSETSPID: setting channel %d spid to %s\n",
242 sc_adapter[card]->devicename, data->channel, spid);
243 status = send_and_receive(card, CEPID, ceReqTypeCall,
244 ceReqClass0, ceReqCallSetSPID, data->channel,
245 strlen(spid), spid, rcvmsg, SAR_TIMEOUT);
246 if(!status && !(rcvmsg->rsp_status)) {
247 pr_debug("%s: SCIOCSETSPID: command successful\n",
248 sc_adapter[card]->devicename);
249 kfree(rcvmsg);
250 kfree(spid);
251 return 0;
252 }
253 else {
254 pr_debug("%s: SCIOCSETSPID: command failed (status = %d)\n",
255 sc_adapter[card]->devicename, status);
256 kfree(rcvmsg);
257 kfree(spid);
258 return status;
259 }
260 }
261
262 case SCIOCGETDN:
263 {
264 pr_debug("%s: SCIOGETDN: ioctl received\n",
265 sc_adapter[card]->devicename);
266
267 /*
268 * Get the dn from the board
269 */
270 status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0, ceReqCallGetMyNumber,
271 data->channel, 0, NULL, rcvmsg, SAR_TIMEOUT);
272 if (!status) {
273 pr_debug("%s: SCIOCGETDN: command successful\n",
274 sc_adapter[card]->devicename);
275 }
276 else {
277 pr_debug("%s: SCIOCGETDN: command failed (status = %d)\n",
278 sc_adapter[card]->devicename, status);
279 kfree(rcvmsg);
280 return status;
281 }
282
283 dn = kmalloc(SCIOC_DNSIZE, GFP_KERNEL);
284 if (!dn) {
285 kfree(rcvmsg);
286 return -ENOMEM;
287 }
288 strcpy(dn, rcvmsg->msg_data.byte_array);
289 kfree(rcvmsg);
290
291 /*
292 * Package the dn and send to user space
293 */
294 if (copy_to_user(data->dataptr, dn, SCIOC_DNSIZE)) {
295 kfree(dn);
296 return -EFAULT;
297 }
298 kfree(dn);
299 return 0;
300 }
301
302 case SCIOCSETDN:
303 {
304 pr_debug("%s: SCIOSETDN: ioctl received\n",
305 sc_adapter[card]->devicename);
306
307 dn = kmalloc(SCIOC_DNSIZE, GFP_KERNEL);
308 if (!dn) {
309 kfree(rcvmsg);
310 return -ENOMEM;
311 }
312 /*
313 * Get the spid from user space
314 */
315 if (copy_from_user(dn, data->dataptr, SCIOC_DNSIZE)) {
316 kfree(rcvmsg);
317 kfree(dn);
318 return -EFAULT;
319 }
320
321 pr_debug("%s: SCIOCSETDN: setting channel %d dn to %s\n",
322 sc_adapter[card]->devicename, data->channel, dn);
323 status = send_and_receive(card, CEPID, ceReqTypeCall,
324 ceReqClass0, ceReqCallSetMyNumber, data->channel,
325 strlen(dn),dn,rcvmsg, SAR_TIMEOUT);
326 if(!status && !(rcvmsg->rsp_status)) {
327 pr_debug("%s: SCIOCSETDN: command successful\n",
328 sc_adapter[card]->devicename);
329 kfree(rcvmsg);
330 kfree(dn);
331 return 0;
332 }
333 else {
334 pr_debug("%s: SCIOCSETDN: command failed (status = %d)\n",
335 sc_adapter[card]->devicename, status);
336 kfree(rcvmsg);
337 kfree(dn);
338 return status;
339 }
340 }
341
342 case SCIOCTRACE:
343
344 pr_debug("%s: SCIOTRACE: ioctl received\n",
345 sc_adapter[card]->devicename);
346/* sc_adapter[card]->trace = !sc_adapter[card]->trace;
347 pr_debug("%s: SCIOCTRACE: tracing turned %s\n",
348 sc_adapter[card]->devicename,
349 sc_adapter[card]->trace ? "ON" : "OFF"); */
350 break;
351
352 case SCIOCSTAT:
353 {
354 boardInfo *bi;
355
356 pr_debug("%s: SCIOSTAT: ioctl received\n",
357 sc_adapter[card]->devicename);
358
359 bi = kmalloc (sizeof(boardInfo), GFP_KERNEL);
360 if (!bi) {
361 kfree(rcvmsg);
362 return -ENOMEM;
363 }
364
365 kfree(rcvmsg);
366 GetStatus(card, bi);
367
368 if (copy_to_user(data->dataptr, bi, sizeof(boardInfo))) {
369 kfree(bi);
370 return -EFAULT;
371 }
372
373 kfree(bi);
374 return 0;
375 }
376
377 case SCIOCGETSPEED:
378 {
379 pr_debug("%s: SCIOGETSPEED: ioctl received\n",
380 sc_adapter[card]->devicename);
381
382 /*
383 * Get the speed from the board
384 */
385 status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0,
386 ceReqCallGetCallType, data->channel, 0, NULL, rcvmsg, SAR_TIMEOUT);
387 if (!status && !(rcvmsg->rsp_status)) {
388 pr_debug("%s: SCIOCGETSPEED: command successful\n",
389 sc_adapter[card]->devicename);
390 }
391 else {
392 pr_debug("%s: SCIOCGETSPEED: command failed (status = %d)\n",
393 sc_adapter[card]->devicename, status);
394 kfree(rcvmsg);
395 return status;
396 }
397
398 speed = rcvmsg->msg_data.byte_array[0];
399
400 kfree(rcvmsg);
401
402 /*
403 * Package the switch type and send to user space
404 */
405
406 if (copy_to_user(data->dataptr, &speed, sizeof(char)))
407 return -EFAULT;
408
409 return 0;
410 }
411
412 case SCIOCSETSPEED:
413 pr_debug("%s: SCIOCSETSPEED: ioctl received\n",
414 sc_adapter[card]->devicename);
415 break;
416
417 case SCIOCLOOPTST:
418 pr_debug("%s: SCIOCLOOPTST: ioctl received\n",
419 sc_adapter[card]->devicename);
420 break;
421
422 default:
423 kfree(rcvmsg);
424 return -1;
425 }
426
427 kfree(rcvmsg);
428 return 0;
429}
430
431int GetStatus(int card, boardInfo *bi)
432{
433 RspMessage rcvmsg;
434 int i, status;
435
436 /*
437 * Fill in some of the basic info about the board
438 */
439 bi->modelid = sc_adapter[card]->model;
440 strcpy(bi->serial_no, sc_adapter[card]->hwconfig.serial_no);
441 strcpy(bi->part_no, sc_adapter[card]->hwconfig.part_no);
442 bi->iobase = sc_adapter[card]->iobase;
443 bi->rambase = sc_adapter[card]->rambase;
444 bi->irq = sc_adapter[card]->interrupt;
445 bi->ramsize = sc_adapter[card]->hwconfig.ram_size;
446 bi->interface = sc_adapter[card]->hwconfig.st_u_sense;
447 strcpy(bi->load_ver, sc_adapter[card]->load_ver);
448 strcpy(bi->proc_ver, sc_adapter[card]->proc_ver);
449
450 /*
451 * Get the current PhyStats and LnkStats
452 */
453 status = send_and_receive(card, CEPID, ceReqTypePhy, ceReqClass2,
454 ceReqPhyStatus, 0, 0, NULL, &rcvmsg, SAR_TIMEOUT);
455 if(!status) {
456 if(sc_adapter[card]->model < PRI_BOARD) {
457 bi->l1_status = rcvmsg.msg_data.byte_array[2];
458 for(i = 0 ; i < BRI_CHANNELS ; i++)
459 bi->status.bristats[i].phy_stat =
460 rcvmsg.msg_data.byte_array[i];
461 }
462 else {
463 bi->l1_status = rcvmsg.msg_data.byte_array[0];
464 bi->l2_status = rcvmsg.msg_data.byte_array[1];
465 for(i = 0 ; i < PRI_CHANNELS ; i++)
466 bi->status.pristats[i].phy_stat =
467 rcvmsg.msg_data.byte_array[i+2];
468 }
469 }
470
471 /*
472 * Get the call types for each channel
473 */
474 for (i = 0 ; i < sc_adapter[card]->nChannels ; i++) {
475 status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0,
476 ceReqCallGetCallType, 0, 0, NULL, &rcvmsg, SAR_TIMEOUT);
477 if(!status) {
478 if (sc_adapter[card]->model == PRI_BOARD) {
479 bi->status.pristats[i].call_type =
480 rcvmsg.msg_data.byte_array[0];
481 }
482 else {
483 bi->status.bristats[i].call_type =
484 rcvmsg.msg_data.byte_array[0];
485 }
486 }
487 }
488
489 /*
490 * If PRI, get the call states and service states for each channel
491 */
492 if (sc_adapter[card]->model == PRI_BOARD) {
493 /*
494 * Get the call states
495 */
496 status = send_and_receive(card, CEPID, ceReqTypeStat, ceReqClass2,
497 ceReqPhyChCallState, 0, 0, NULL, &rcvmsg, SAR_TIMEOUT);
498 if(!status) {
499 for( i = 0 ; i < PRI_CHANNELS ; i++ )
500 bi->status.pristats[i].call_state =
501 rcvmsg.msg_data.byte_array[i];
502 }
503
504 /*
505 * Get the service states
506 */
507 status = send_and_receive(card, CEPID, ceReqTypeStat, ceReqClass2,
508 ceReqPhyChServState, 0, 0, NULL, &rcvmsg, SAR_TIMEOUT);
509 if(!status) {
510 for( i = 0 ; i < PRI_CHANNELS ; i++ )
511 bi->status.pristats[i].serv_state =
512 rcvmsg.msg_data.byte_array[i];
513 }
514
515 /*
516 * Get the link stats for the channels
517 */
518 for (i = 1 ; i <= PRI_CHANNELS ; i++) {
519 status = send_and_receive(card, CEPID, ceReqTypeLnk, ceReqClass0,
520 ceReqLnkGetStats, i, 0, NULL, &rcvmsg, SAR_TIMEOUT);
521 if (!status) {
522 bi->status.pristats[i-1].link_stats.tx_good =
523 (unsigned long)rcvmsg.msg_data.byte_array[0];
524 bi->status.pristats[i-1].link_stats.tx_bad =
525 (unsigned long)rcvmsg.msg_data.byte_array[4];
526 bi->status.pristats[i-1].link_stats.rx_good =
527 (unsigned long)rcvmsg.msg_data.byte_array[8];
528 bi->status.pristats[i-1].link_stats.rx_bad =
529 (unsigned long)rcvmsg.msg_data.byte_array[12];
530 }
531 }
532
533 /*
534 * Link stats for the D channel
535 */
536 status = send_and_receive(card, CEPID, ceReqTypeLnk, ceReqClass0,
537 ceReqLnkGetStats, 0, 0, NULL, &rcvmsg, SAR_TIMEOUT);
538 if (!status) {
539 bi->dch_stats.tx_good = (unsigned long)rcvmsg.msg_data.byte_array[0];
540 bi->dch_stats.tx_bad = (unsigned long)rcvmsg.msg_data.byte_array[4];
541 bi->dch_stats.rx_good = (unsigned long)rcvmsg.msg_data.byte_array[8];
542 bi->dch_stats.rx_bad = (unsigned long)rcvmsg.msg_data.byte_array[12];
543 }
544
545 return 0;
546 }
547
548 /*
549 * If BRI or POTS, Get SPID, DN and call types for each channel
550 */
551
552 /*
553 * Get the link stats for the channels
554 */
555 status = send_and_receive(card, CEPID, ceReqTypeLnk, ceReqClass0,
556 ceReqLnkGetStats, 0, 0, NULL, &rcvmsg, SAR_TIMEOUT);
557 if (!status) {
558 bi->dch_stats.tx_good = (unsigned long)rcvmsg.msg_data.byte_array[0];
559 bi->dch_stats.tx_bad = (unsigned long)rcvmsg.msg_data.byte_array[4];
560 bi->dch_stats.rx_good = (unsigned long)rcvmsg.msg_data.byte_array[8];
561 bi->dch_stats.rx_bad = (unsigned long)rcvmsg.msg_data.byte_array[12];
562 bi->status.bristats[0].link_stats.tx_good =
563 (unsigned long)rcvmsg.msg_data.byte_array[16];
564 bi->status.bristats[0].link_stats.tx_bad =
565 (unsigned long)rcvmsg.msg_data.byte_array[20];
566 bi->status.bristats[0].link_stats.rx_good =
567 (unsigned long)rcvmsg.msg_data.byte_array[24];
568 bi->status.bristats[0].link_stats.rx_bad =
569 (unsigned long)rcvmsg.msg_data.byte_array[28];
570 bi->status.bristats[1].link_stats.tx_good =
571 (unsigned long)rcvmsg.msg_data.byte_array[32];
572 bi->status.bristats[1].link_stats.tx_bad =
573 (unsigned long)rcvmsg.msg_data.byte_array[36];
574 bi->status.bristats[1].link_stats.rx_good =
575 (unsigned long)rcvmsg.msg_data.byte_array[40];
576 bi->status.bristats[1].link_stats.rx_bad =
577 (unsigned long)rcvmsg.msg_data.byte_array[44];
578 }
579
580 /*
581 * Get the SPIDs
582 */
583 for (i = 0 ; i < BRI_CHANNELS ; i++) {
584 status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0,
585 ceReqCallGetSPID, i+1, 0, NULL, &rcvmsg, SAR_TIMEOUT);
586 if (!status)
587 strcpy(bi->status.bristats[i].spid, rcvmsg.msg_data.byte_array);
588 }
589
590 /*
591 * Get the DNs
592 */
593 for (i = 0 ; i < BRI_CHANNELS ; i++) {
594 status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0,
595 ceReqCallGetMyNumber, i+1, 0, NULL, &rcvmsg, SAR_TIMEOUT);
596 if (!status)
597 strcpy(bi->status.bristats[i].dn, rcvmsg.msg_data.byte_array);
598 }
599
600 return 0;
601}
diff --git a/drivers/isdn/sc/message.c b/drivers/isdn/sc/message.c
new file mode 100644
index 000000000000..ca204da3257d
--- /dev/null
+++ b/drivers/isdn/sc/message.c
@@ -0,0 +1,241 @@
1/* $Id: message.c,v 1.5.8.2 2001/09/23 22:24:59 kai Exp $
2 *
3 * functions for sending and receiving control messages
4 *
5 * Copyright (C) 1996 SpellCaster Telecommunications Inc.
6 *
7 * This software may be used and distributed according to the terms
8 * of the GNU General Public License, incorporated herein by reference.
9 *
10 * For more information, please contact gpl-info@spellcast.com or write:
11 *
12 * SpellCaster Telecommunications Inc.
13 * 5621 Finch Avenue East, Unit #3
14 * Scarborough, Ontario Canada
15 * M1B 2T9
16 * +1 (416) 297-8565
17 * +1 (416) 297-6433 Facsimile
18 */
19
20#include "includes.h"
21#include "hardware.h"
22#include "message.h"
23#include "card.h"
24
25extern board *sc_adapter[];
26extern unsigned int cinst;
27
28/*
29 * Obligatory function prototypes
30 */
31extern int indicate_status(int,ulong,char*);
32extern int scm_command(isdn_ctrl *);
33
34
35/*
36 * receive a message from the board
37 */
38int receivemessage(int card, RspMessage *rspmsg)
39{
40 DualPortMemory *dpm;
41 unsigned long flags;
42
43 if (!IS_VALID_CARD(card)) {
44 pr_debug("Invalid param: %d is not a valid card id\n", card);
45 return -EINVAL;
46 }
47
48 pr_debug("%s: Entered receivemessage\n",
49 sc_adapter[card]->devicename);
50
51 /*
52 * See if there are messages waiting
53 */
54 if (inb(sc_adapter[card]->ioport[FIFO_STATUS]) & RF_HAS_DATA) {
55 /*
56 * Map in the DPM to the base page and copy the message
57 */
58 spin_lock_irqsave(&sc_adapter[card]->lock, flags);
59 outb((sc_adapter[card]->shmem_magic >> 14) | 0x80,
60 sc_adapter[card]->ioport[sc_adapter[card]->shmem_pgport]);
61 dpm = (DualPortMemory *) sc_adapter[card]->rambase;
62 memcpy_fromio(rspmsg, &(dpm->rsp_queue[dpm->rsp_tail]),
63 MSG_LEN);
64 dpm->rsp_tail = (dpm->rsp_tail+1) % MAX_MESSAGES;
65 inb(sc_adapter[card]->ioport[FIFO_READ]);
66 spin_unlock_irqrestore(&sc_adapter[card]->lock, flags);
67 /*
68 * Tell the board that the message is received
69 */
70 pr_debug("%s: Received Message seq:%d pid:%d time:%d cmd:%d "
71 "cnt:%d (type,class,code):(%d,%d,%d) "
72 "link:%d stat:0x%x\n",
73 sc_adapter[card]->devicename,
74 rspmsg->sequence_no,
75 rspmsg->process_id,
76 rspmsg->time_stamp,
77 rspmsg->cmd_sequence_no,
78 rspmsg->msg_byte_cnt,
79 rspmsg->type,
80 rspmsg->class,
81 rspmsg->code,
82 rspmsg->phy_link_no,
83 rspmsg->rsp_status);
84
85 return 0;
86 }
87 return -ENOMSG;
88}
89
90/*
91 * send a message to the board
92 */
93int sendmessage(int card,
94 unsigned int procid,
95 unsigned int type,
96 unsigned int class,
97 unsigned int code,
98 unsigned int link,
99 unsigned int data_len,
100 unsigned int *data)
101{
102 DualPortMemory *dpm;
103 ReqMessage sndmsg;
104 unsigned long flags;
105
106 if (!IS_VALID_CARD(card)) {
107 pr_debug("Invalid param: %d is not a valid card id\n", card);
108 return -EINVAL;
109 }
110
111 /*
112 * Make sure we only send CEPID messages when the engine is up
113 * and CMPID messages when it is down
114 */
115 if(sc_adapter[card]->EngineUp && procid == CMPID) {
116 pr_debug("%s: Attempt to send CM message with engine up\n",
117 sc_adapter[card]->devicename);
118 return -ESRCH;
119 }
120
121 if(!sc_adapter[card]->EngineUp && procid == CEPID) {
122 pr_debug("%s: Attempt to send CE message with engine down\n",
123 sc_adapter[card]->devicename);
124 return -ESRCH;
125 }
126
127 memset(&sndmsg, 0, MSG_LEN);
128 sndmsg.msg_byte_cnt = 4;
129 sndmsg.type = type;
130 sndmsg.class = class;
131 sndmsg.code = code;
132 sndmsg.phy_link_no = link;
133
134 if (data_len > 0) {
135 if (data_len > MSG_DATA_LEN)
136 data_len = MSG_DATA_LEN;
137 memcpy(&(sndmsg.msg_data), data, data_len);
138 sndmsg.msg_byte_cnt = data_len + 8;
139 }
140
141 sndmsg.process_id = procid;
142 sndmsg.sequence_no = sc_adapter[card]->seq_no++ % 256;
143
144 /*
145 * wait for an empty slot in the queue
146 */
147 while (!(inb(sc_adapter[card]->ioport[FIFO_STATUS]) & WF_NOT_FULL))
148 udelay(1);
149
150 /*
151 * Disable interrupts and map in shared memory
152 */
153 spin_lock_irqsave(&sc_adapter[card]->lock, flags);
154 outb((sc_adapter[card]->shmem_magic >> 14) | 0x80,
155 sc_adapter[card]->ioport[sc_adapter[card]->shmem_pgport]);
156 dpm = (DualPortMemory *) sc_adapter[card]->rambase; /* Fix me */
157 memcpy_toio(&(dpm->req_queue[dpm->req_head]),&sndmsg,MSG_LEN);
158 dpm->req_head = (dpm->req_head+1) % MAX_MESSAGES;
159 outb(sndmsg.sequence_no, sc_adapter[card]->ioport[FIFO_WRITE]);
160 spin_unlock_irqrestore(&sc_adapter[card]->lock, flags);
161
162 pr_debug("%s: Sent Message seq:%d pid:%d time:%d "
163 "cnt:%d (type,class,code):(%d,%d,%d) "
164 "link:%d\n ",
165 sc_adapter[card]->devicename,
166 sndmsg.sequence_no,
167 sndmsg.process_id,
168 sndmsg.time_stamp,
169 sndmsg.msg_byte_cnt,
170 sndmsg.type,
171 sndmsg.class,
172 sndmsg.code,
173 sndmsg.phy_link_no);
174
175 return 0;
176}
177
178int send_and_receive(int card,
179 unsigned int procid,
180 unsigned char type,
181 unsigned char class,
182 unsigned char code,
183 unsigned char link,
184 unsigned char data_len,
185 unsigned char *data,
186 RspMessage *mesgdata,
187 int timeout)
188{
189 int retval;
190 int tries;
191
192 if (!IS_VALID_CARD(card)) {
193 pr_debug("Invalid param: %d is not a valid card id\n", card);
194 return -EINVAL;
195 }
196
197 sc_adapter[card]->want_async_messages = 1;
198 retval = sendmessage(card, procid, type, class, code, link,
199 data_len, (unsigned int *) data);
200
201 if (retval) {
202 pr_debug("%s: SendMessage failed in SAR\n",
203 sc_adapter[card]->devicename);
204 sc_adapter[card]->want_async_messages = 0;
205 return -EIO;
206 }
207
208 tries = 0;
209 /* wait for the response */
210 while (tries < timeout) {
211 set_current_state(TASK_INTERRUPTIBLE);
212 schedule_timeout(1);
213
214 pr_debug("SAR waiting..\n");
215
216 /*
217 * See if we got our message back
218 */
219 if ((sc_adapter[card]->async_msg.type == type) &&
220 (sc_adapter[card]->async_msg.class == class) &&
221 (sc_adapter[card]->async_msg.code == code) &&
222 (sc_adapter[card]->async_msg.phy_link_no == link)) {
223
224 /*
225 * Got it!
226 */
227 pr_debug("%s: Got ASYNC message\n",
228 sc_adapter[card]->devicename);
229 memcpy(mesgdata, &(sc_adapter[card]->async_msg),
230 sizeof(RspMessage));
231 sc_adapter[card]->want_async_messages = 0;
232 return 0;
233 }
234
235 tries++;
236 }
237
238 pr_debug("%s: SAR message timeout\n", sc_adapter[card]->devicename);
239 sc_adapter[card]->want_async_messages = 0;
240 return -ETIME;
241}
diff --git a/drivers/isdn/sc/message.h b/drivers/isdn/sc/message.h
new file mode 100644
index 000000000000..8eb15e7306b2
--- /dev/null
+++ b/drivers/isdn/sc/message.h
@@ -0,0 +1,245 @@
1/* $Id: message.h,v 1.1.10.1 2001/09/23 22:24:59 kai Exp $
2 *
3 * Copyright (C) 1996 SpellCaster Telecommunications Inc.
4 *
5 * structures, macros and defines useful for sending
6 * messages to the adapter
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 * For more information, please contact gpl-info@spellcast.com or write:
12 *
13 * SpellCaster Telecommunications Inc.
14 * 5621 Finch Avenue East, Unit #3
15 * Scarborough, Ontario Canada
16 * M1B 2T9
17 * +1 (416) 297-8565
18 * +1 (416) 297-6433 Facsimile
19 */
20
21/*
22 * Board message macros, defines and structures
23 */
24
25#ifndef MESSAGE_H
26#define MESSAGE_H
27
28#define MAX_MESSAGES 32 /* Maximum messages that can be
29 queued */
30#define MSG_DATA_LEN 48 /* Maximum size of message payload */
31#define MSG_LEN 64 /* Size of a message */
32#define CMPID 0 /* Loader message process ID */
33#define CEPID 64 /* Firmware message process ID */
34
35/*
36 * Macro to determine if a message is a loader message
37 */
38#define IS_CM_MESSAGE(mesg, tx, cx, dx) \
39 ((mesg.type == cmRspType##tx) \
40 &&(mesg.class == cmRspClass##cx) \
41 &&(mesg.code == cmRsp##dx))
42
43/*
44 * Macro to determine if a message is a firmware message
45 */
46#define IS_CE_MESSAGE(mesg, tx, cx, dx) \
47 ((mesg.type == ceRspType##tx) \
48 &&(mesg.class == ceRspClass##cx) \
49 &&(mesg.code == ceRsp##tx##dx))
50
51/*
52 * Loader Request and Response Messages
53 */
54
55/* message types */
56#define cmReqType1 1
57#define cmReqType2 2
58#define cmRspType0 0
59#define cmRspType1 1
60#define cmRspType2 2
61#define cmRspType5 5
62
63/* message classes */
64#define cmReqClass0 0
65#define cmRspClass0 0
66
67/* message codes */
68#define cmReqHWConfig 1 /* 1,0,1 */
69#define cmReqMsgLpbk 2 /* 1,0,2 */
70#define cmReqVersion 3 /* 1,0,3 */
71#define cmReqLoadProc 1 /* 2,0,1 */
72#define cmReqStartProc 2 /* 2,0,2 */
73#define cmReqReadMem 6 /* 2,0,6 */
74#define cmRspHWConfig cmReqHWConfig
75#define cmRspMsgLpbk cmReqMsgLpbk
76#define cmRspVersion cmReqVersion
77#define cmRspLoadProc cmReqLoadProc
78#define cmRspStartProc cmReqStartProc
79#define cmRspReadMem cmReqReadMem
80#define cmRspMiscEngineUp 1 /* 5,0,1 */
81#define cmRspInvalid 0 /* 0,0,0 */
82
83
84/*
85 * Firmware Request and Response Messages
86 */
87
88/* message types */
89#define ceReqTypePhy 1
90#define ceReqTypeLnk 2
91#define ceReqTypeCall 3
92#define ceReqTypeStat 1
93#define ceRspTypeErr 0
94#define ceRspTypePhy ceReqTypePhy
95#define ceRspTypeLnk ceReqTypeLnk
96#define ceRspTypeCall ceReqTypeCall
97#define ceRspTypeStat ceReqTypeStat
98
99/* message classes */
100#define ceReqClass0 0
101#define ceReqClass1 1
102#define ceReqClass2 2
103#define ceReqClass3 3
104#define ceRspClass0 ceReqClass0
105#define ceRspClass1 ceReqClass1
106#define ceRspClass2 ceReqClass2
107#define ceRspClass3 ceReqClass3
108
109/* message codes (B) = BRI only, (P) = PRI only, (V) = POTS only */
110#define ceReqPhyProcInfo 1 /* 1,0,1 */
111#define ceReqPhyConnect 1 /* 1,1,1 */
112#define ceReqPhyDisconnect 2 /* 1,1,2 */
113#define ceReqPhySetParams 3 /* 1,1,3 (P) */
114#define ceReqPhyGetParams 4 /* 1,1,4 (P) */
115#define ceReqPhyStatus 1 /* 1,2,1 */
116#define ceReqPhyAcfaStatus 2 /* 1,2,2 (P) */
117#define ceReqPhyChCallState 3 /* 1,2,3 (P) */
118#define ceReqPhyChServState 4 /* 1,2,4 (P) */
119#define ceReqPhyRLoopBack 1 /* 1,3,1 */
120#define ceRspPhyProcInfo ceReqPhyProcInfo
121#define ceRspPhyConnect ceReqPhyConnect
122#define ceRspPhyDisconnect ceReqPhyDisconnect
123#define ceRspPhySetParams ceReqPhySetParams
124#define ceRspPhyGetParams ceReqPhyGetParams
125#define ceRspPhyStatus ceReqPhyStatus
126#define ceRspPhyAcfaStatus ceReqPhyAcfaStatus
127#define ceRspPhyChCallState ceReqPhyChCallState
128#define ceRspPhyChServState ceReqPhyChServState
129#define ceRspPhyRLoopBack ceReqphyRLoopBack
130#define ceReqLnkSetParam 1 /* 2,0,1 */
131#define ceReqLnkGetParam 2 /* 2,0,2 */
132#define ceReqLnkGetStats 3 /* 2,0,3 */
133#define ceReqLnkWrite 1 /* 2,1,1 */
134#define ceReqLnkRead 2 /* 2,1,2 */
135#define ceReqLnkFlush 3 /* 2,1,3 */
136#define ceReqLnkWrBufTrc 4 /* 2,1,4 */
137#define ceReqLnkRdBufTrc 5 /* 2,1,5 */
138#define ceRspLnkSetParam ceReqLnkSetParam
139#define ceRspLnkGetParam ceReqLnkGetParam
140#define ceRspLnkGetStats ceReqLnkGetStats
141#define ceRspLnkWrite ceReqLnkWrite
142#define ceRspLnkRead ceReqLnkRead
143#define ceRspLnkFlush ceReqLnkFlush
144#define ceRspLnkWrBufTrc ceReqLnkWrBufTrc
145#define ceRspLnkRdBufTrc ceReqLnkRdBufTrc
146#define ceReqCallSetSwitchType 1 /* 3,0,1 */
147#define ceReqCallGetSwitchType 2 /* 3,0,2 */
148#define ceReqCallSetFrameFormat 3 /* 3,0,3 */
149#define ceReqCallGetFrameFormat 4 /* 3,0,4 */
150#define ceReqCallSetCallType 5 /* 3,0,5 */
151#define ceReqCallGetCallType 6 /* 3,0,6 */
152#define ceReqCallSetSPID 7 /* 3,0,7 (!P) */
153#define ceReqCallGetSPID 8 /* 3,0,8 (!P) */
154#define ceReqCallSetMyNumber 9 /* 3,0,9 (!P) */
155#define ceReqCallGetMyNumber 10 /* 3,0,10 (!P) */
156#define ceRspCallSetSwitchType ceReqCallSetSwitchType
157#define ceRspCallGetSwitchType ceReqCallSetSwitchType
158#define ceRspCallSetFrameFormat ceReqCallSetFrameFormat
159#define ceRspCallGetFrameFormat ceReqCallGetFrameFormat
160#define ceRspCallSetCallType ceReqCallSetCallType
161#define ceRspCallGetCallType ceReqCallGetCallType
162#define ceRspCallSetSPID ceReqCallSetSPID
163#define ceRspCallGetSPID ceReqCallGetSPID
164#define ceRspCallSetMyNumber ceReqCallSetMyNumber
165#define ceRspCallGetMyNumber ceReqCallGetMyNumber
166#define ceRspStatAcfaStatus 2
167#define ceRspStat
168#define ceRspErrError 0 /* 0,0,0 */
169
170/*
171 * Call Types
172 */
173#define CALLTYPE_64K 0
174#define CALLTYPE_56K 1
175#define CALLTYPE_SPEECH 2
176#define CALLTYPE_31KHZ 3
177
178/*
179 * Link Level data contains a pointer to and the length of
180 * a buffer in shared RAM. Used by LnkRead and LnkWrite message
181 * types. Part of RspMsgStruct and ReqMsgStruct.
182 */
183typedef struct {
184 unsigned long buff_offset;
185 unsigned short msg_len;
186} LLData;
187
188
189/*
190 * Message payload template for an HWConfig message
191 */
192typedef struct {
193 char st_u_sense;
194 char powr_sense;
195 char sply_sense;
196 unsigned char asic_id;
197 long ram_size;
198 char serial_no[13];
199 char part_no[13];
200 char rev_no[2];
201} HWConfig_pl;
202
203/*
204 * A Message
205 */
206struct message {
207 unsigned char sequence_no;
208 unsigned char process_id;
209 unsigned char time_stamp;
210 unsigned char cmd_sequence_no; /* Rsp messages only */
211 unsigned char reserved1[3];
212 unsigned char msg_byte_cnt;
213 unsigned char type;
214 unsigned char class;
215 unsigned char code;
216 unsigned char phy_link_no;
217 unsigned char rsp_status; /* Rsp messages only */
218 unsigned char reseved2[3];
219 union {
220 unsigned char byte_array[MSG_DATA_LEN];
221 LLData response;
222 HWConfig_pl HWCresponse;
223 } msg_data;
224};
225
226typedef struct message ReqMessage; /* Request message */
227typedef struct message RspMessage; /* Response message */
228
229/*
230 * The first 5010 bytes of shared memory contain the message queues,
231 * indexes and other data. This structure is its template
232 */
233typedef struct {
234 volatile ReqMessage req_queue[MAX_MESSAGES];
235 volatile RspMessage rsp_queue[MAX_MESSAGES];
236 volatile unsigned char req_head;
237 volatile unsigned char req_tail;
238 volatile unsigned char rsp_head;
239 volatile unsigned char rsp_tail;
240 volatile unsigned long signature;
241 volatile unsigned long trace_enable;
242 volatile unsigned char reserved[4];
243} DualPortMemory;
244
245#endif
diff --git a/drivers/isdn/sc/packet.c b/drivers/isdn/sc/packet.c
new file mode 100644
index 000000000000..8e3fac3ba1a1
--- /dev/null
+++ b/drivers/isdn/sc/packet.c
@@ -0,0 +1,231 @@
1/* $Id: packet.c,v 1.5.8.1 2001/09/23 22:24:59 kai Exp $
2 *
3 * Copyright (C) 1996 SpellCaster Telecommunications Inc.
4 *
5 * This software may be used and distributed according to the terms
6 * of the GNU General Public License, incorporated herein by reference.
7 *
8 * For more information, please contact gpl-info@spellcast.com or write:
9 *
10 * SpellCaster Telecommunications Inc.
11 * 5621 Finch Avenue East, Unit #3
12 * Scarborough, Ontario Canada
13 * M1B 2T9
14 * +1 (416) 297-8565
15 * +1 (416) 297-6433 Facsimile
16 */
17
18#include "includes.h"
19#include "hardware.h"
20#include "message.h"
21#include "card.h"
22
23extern board *sc_adapter[];
24extern unsigned int cinst;
25
26extern int get_card_from_id(int);
27extern int indicate_status(int, int,ulong, char*);
28extern void memcpy_toshmem(int, void *, const void *, size_t);
29extern void memcpy_fromshmem(int, void *, const void *, size_t);
30extern int sendmessage(int, unsigned int, unsigned int, unsigned int,
31 unsigned int, unsigned int, unsigned int, unsigned int *);
32
33int sndpkt(int devId, int channel, struct sk_buff *data)
34{
35 LLData ReqLnkWrite;
36 int status;
37 int card;
38 unsigned long len;
39
40 card = get_card_from_id(devId);
41
42 if(!IS_VALID_CARD(card)) {
43 pr_debug("invalid param: %d is not a valid card id\n", card);
44 return -ENODEV;
45 }
46
47 pr_debug("%s: sndpkt: frst = 0x%x nxt = %d f = %d n = %d\n",
48 sc_adapter[card]->devicename,
49 sc_adapter[card]->channel[channel].first_sendbuf,
50 sc_adapter[card]->channel[channel].next_sendbuf,
51 sc_adapter[card]->channel[channel].free_sendbufs,
52 sc_adapter[card]->channel[channel].num_sendbufs);
53
54 if(!sc_adapter[card]->channel[channel].free_sendbufs) {
55 pr_debug("%s: out of TX buffers\n",
56 sc_adapter[card]->devicename);
57 return -EINVAL;
58 }
59
60 if(data->len > BUFFER_SIZE) {
61 pr_debug("%s: data overflows buffer size (data > buffer)\n",
62 sc_adapter[card]->devicename);
63 return -EINVAL;
64 }
65
66 ReqLnkWrite.buff_offset = sc_adapter[card]->channel[channel].next_sendbuf *
67 BUFFER_SIZE + sc_adapter[card]->channel[channel].first_sendbuf;
68 ReqLnkWrite.msg_len = data->len; /* sk_buff size */
69 pr_debug("%s: writing %d bytes to buffer offset 0x%x\n",
70 sc_adapter[card]->devicename,
71 ReqLnkWrite.msg_len, ReqLnkWrite.buff_offset);
72 memcpy_toshmem(card, (char *)ReqLnkWrite.buff_offset, data->data, ReqLnkWrite.msg_len);
73
74 /*
75 * sendmessage
76 */
77 pr_debug("%s: sndpkt size=%d, buf_offset=0x%x buf_indx=%d\n",
78 sc_adapter[card]->devicename,
79 ReqLnkWrite.msg_len, ReqLnkWrite.buff_offset,
80 sc_adapter[card]->channel[channel].next_sendbuf);
81
82 status = sendmessage(card, CEPID, ceReqTypeLnk, ceReqClass1, ceReqLnkWrite,
83 channel+1, sizeof(LLData), (unsigned int*)&ReqLnkWrite);
84 len = data->len;
85 if(status) {
86 pr_debug("%s: failed to send packet, status = %d\n",
87 sc_adapter[card]->devicename, status);
88 return -1;
89 }
90 else {
91 sc_adapter[card]->channel[channel].free_sendbufs--;
92 sc_adapter[card]->channel[channel].next_sendbuf =
93 ++sc_adapter[card]->channel[channel].next_sendbuf ==
94 sc_adapter[card]->channel[channel].num_sendbufs ? 0 :
95 sc_adapter[card]->channel[channel].next_sendbuf;
96 pr_debug("%s: packet sent successfully\n", sc_adapter[card]->devicename);
97 dev_kfree_skb(data);
98 indicate_status(card,ISDN_STAT_BSENT,channel, (char *)&len);
99 }
100 return len;
101}
102
103void rcvpkt(int card, RspMessage *rcvmsg)
104{
105 LLData newll;
106 struct sk_buff *skb;
107
108 if(!IS_VALID_CARD(card)) {
109 pr_debug("invalid param: %d is not a valid card id\n", card);
110 return;
111 }
112
113 switch(rcvmsg->rsp_status){
114 case 0x01:
115 case 0x02:
116 case 0x70:
117 pr_debug("%s: error status code: 0x%x\n",
118 sc_adapter[card]->devicename, rcvmsg->rsp_status);
119 return;
120 case 0x00:
121 if (!(skb = dev_alloc_skb(rcvmsg->msg_data.response.msg_len))) {
122 printk(KERN_WARNING "%s: rcvpkt out of memory, dropping packet\n",
123 sc_adapter[card]->devicename);
124 return;
125 }
126 skb_put(skb, rcvmsg->msg_data.response.msg_len);
127 pr_debug("%s: getting data from offset: 0x%x\n",
128 sc_adapter[card]->devicename,
129 rcvmsg->msg_data.response.buff_offset);
130 memcpy_fromshmem(card,
131 skb_put(skb, rcvmsg->msg_data.response.msg_len),
132 (char *)rcvmsg->msg_data.response.buff_offset,
133 rcvmsg->msg_data.response.msg_len);
134 sc_adapter[card]->card->rcvcallb_skb(sc_adapter[card]->driverId,
135 rcvmsg->phy_link_no-1, skb);
136
137 case 0x03:
138 /*
139 * Recycle the buffer
140 */
141 pr_debug("%s: buffer size : %d\n",
142 sc_adapter[card]->devicename, BUFFER_SIZE);
143/* memset_shmem(card, rcvmsg->msg_data.response.buff_offset, 0, BUFFER_SIZE); */
144 newll.buff_offset = rcvmsg->msg_data.response.buff_offset;
145 newll.msg_len = BUFFER_SIZE;
146 pr_debug("%s: recycled buffer at offset 0x%x size %d\n",
147 sc_adapter[card]->devicename,
148 newll.buff_offset, newll.msg_len);
149 sendmessage(card, CEPID, ceReqTypeLnk, ceReqClass1, ceReqLnkRead,
150 rcvmsg->phy_link_no, sizeof(LLData), (unsigned int *)&newll);
151 }
152
153}
154
155int setup_buffers(int card, int c)
156{
157 unsigned int nBuffers, i, cBase;
158 unsigned int buffer_size;
159 LLData RcvBuffOffset;
160
161 if(!IS_VALID_CARD(card)) {
162 pr_debug("invalid param: %d is not a valid card id\n", card);
163 return -ENODEV;
164 }
165
166 /*
167 * Calculate the buffer offsets (send/recv/send/recv)
168 */
169 pr_debug("%s: setting up channel buffer space in shared RAM\n",
170 sc_adapter[card]->devicename);
171 buffer_size = BUFFER_SIZE;
172 nBuffers = ((sc_adapter[card]->ramsize - BUFFER_BASE) / buffer_size) / 2;
173 nBuffers = nBuffers > BUFFERS_MAX ? BUFFERS_MAX : nBuffers;
174 pr_debug("%s: calculating buffer space: %d buffers, %d big\n",
175 sc_adapter[card]->devicename,
176 nBuffers, buffer_size);
177 if(nBuffers < 2) {
178 pr_debug("%s: not enough buffer space\n",
179 sc_adapter[card]->devicename);
180 return -1;
181 }
182 cBase = (nBuffers * buffer_size) * (c - 1);
183 pr_debug("%s: channel buffer offset from shared RAM: 0x%x\n",
184 sc_adapter[card]->devicename, cBase);
185 sc_adapter[card]->channel[c-1].first_sendbuf = BUFFER_BASE + cBase;
186 sc_adapter[card]->channel[c-1].num_sendbufs = nBuffers / 2;
187 sc_adapter[card]->channel[c-1].free_sendbufs = nBuffers / 2;
188 sc_adapter[card]->channel[c-1].next_sendbuf = 0;
189 pr_debug("%s: send buffer setup complete: first=0x%x n=%d f=%d, nxt=%d\n",
190 sc_adapter[card]->devicename,
191 sc_adapter[card]->channel[c-1].first_sendbuf,
192 sc_adapter[card]->channel[c-1].num_sendbufs,
193 sc_adapter[card]->channel[c-1].free_sendbufs,
194 sc_adapter[card]->channel[c-1].next_sendbuf);
195
196 /*
197 * Prep the receive buffers
198 */
199 pr_debug("%s: adding %d RecvBuffers:\n",
200 sc_adapter[card]->devicename, nBuffers /2);
201 for (i = 0 ; i < nBuffers / 2; i++) {
202 RcvBuffOffset.buff_offset =
203 ((sc_adapter[card]->channel[c-1].first_sendbuf +
204 (nBuffers / 2) * buffer_size) + (buffer_size * i));
205 RcvBuffOffset.msg_len = buffer_size;
206 pr_debug("%s: adding RcvBuffer #%d offset=0x%x sz=%d bufsz:%d\n",
207 sc_adapter[card]->devicename,
208 i + 1, RcvBuffOffset.buff_offset,
209 RcvBuffOffset.msg_len,buffer_size);
210 sendmessage(card, CEPID, ceReqTypeLnk, ceReqClass1, ceReqLnkRead,
211 c, sizeof(LLData), (unsigned int *)&RcvBuffOffset);
212 }
213 return 0;
214}
215
216int print_skb(int card,char *skb_p, int len){
217 int i,data;
218 pr_debug("%s: data at 0x%x len: 0x%x\n", sc_adapter[card]->devicename,
219 skb_p,len);
220 for(i=1;i<=len;i++,skb_p++){
221 data = (int) (0xff & (*skb_p));
222 pr_debug("%s: data = 0x%x", sc_adapter[card]->devicename,data);
223 if(!(i%4))
224 pr_debug(" ");
225 if(!(i%32))
226 pr_debug("\n");
227 }
228 pr_debug("\n");
229 return 0;
230}
231
diff --git a/drivers/isdn/sc/scioc.h b/drivers/isdn/sc/scioc.h
new file mode 100644
index 000000000000..d08e650c7b6a
--- /dev/null
+++ b/drivers/isdn/sc/scioc.h
@@ -0,0 +1,105 @@
1/*
2 * This software may be used and distributed according to the terms
3 * of the GNU General Public License, incorporated herein by reference.
4 */
5
6/*
7 * IOCTL Command Codes
8 */
9#define SCIOCLOAD 0x01 /* Load a firmware record */
10#define SCIOCRESET 0x02 /* Perform hard reset */
11#define SCIOCDEBUG 0x03 /* Set debug level */
12#define SCIOCREV 0x04 /* Get driver revision(s) */
13#define SCIOCSTART 0x05 /* Start the firmware */
14#define SCIOCGETSWITCH 0x06 /* Get switch type */
15#define SCIOCSETSWITCH 0x07 /* Set switch type */
16#define SCIOCGETSPID 0x08 /* Get channel SPID */
17#define SCIOCSETSPID 0x09 /* Set channel SPID */
18#define SCIOCGETDN 0x0A /* Get channel DN */
19#define SCIOCSETDN 0x0B /* Set channel DN */
20#define SCIOCTRACE 0x0C /* Toggle trace mode */
21#define SCIOCSTAT 0x0D /* Get line status */
22#define SCIOCGETSPEED 0x0E /* Set channel speed */
23#define SCIOCSETSPEED 0x0F /* Set channel speed */
24#define SCIOCLOOPTST 0x10 /* Perform loopback test */
25
26typedef struct {
27 int device;
28 int channel;
29 unsigned long command;
30 void __user *dataptr;
31} scs_ioctl;
32
33/* Size of strings */
34#define SCIOC_SPIDSIZE 49
35#define SCIOC_DNSIZE SCIOC_SPIDSIZE
36#define SCIOC_REVSIZE SCIOC_SPIDSIZE
37#define SCIOC_SRECSIZE 49
38
39typedef struct {
40 unsigned long tx_good;
41 unsigned long tx_bad;
42 unsigned long rx_good;
43 unsigned long rx_bad;
44} ChLinkStats;
45
46typedef struct {
47 char spid[49];
48 char dn[49];
49 char call_type;
50 char phy_stat;
51 ChLinkStats link_stats;
52} BRIStat;
53
54typedef BRIStat POTStat;
55
56typedef struct {
57 char call_type;
58 char call_state;
59 char serv_state;
60 char phy_stat;
61 ChLinkStats link_stats;
62} PRIStat;
63
64typedef char PRIInfo;
65typedef char BRIInfo;
66typedef char POTInfo;
67
68
69typedef struct {
70 char acfa_nos;
71 char acfa_ais;
72 char acfa_los;
73 char acfa_rra;
74 char acfa_slpp;
75 char acfa_slpn;
76 char acfa_fsrf;
77} ACFAStat;
78
79typedef struct {
80 unsigned char modelid;
81 char serial_no[13];
82 char part_no[13];
83 char load_ver[11];
84 char proc_ver[11];
85 int iobase;
86 long rambase;
87 char irq;
88 long ramsize;
89 char interface;
90 char switch_type;
91 char l1_status;
92 char l2_status;
93 ChLinkStats dch_stats;
94 ACFAStat AcfaStats;
95 union {
96 PRIStat pristats[23];
97 BRIStat bristats[2];
98 POTStat potsstats[2];
99 } status;
100 union {
101 PRIInfo priinfo;
102 BRIInfo briinfo;
103 POTInfo potsinfo;
104 } info;
105} boardInfo;
diff --git a/drivers/isdn/sc/shmem.c b/drivers/isdn/sc/shmem.c
new file mode 100644
index 000000000000..7bc2dfad0775
--- /dev/null
+++ b/drivers/isdn/sc/shmem.c
@@ -0,0 +1,143 @@
1/* $Id: shmem.c,v 1.2.10.1 2001/09/23 22:24:59 kai Exp $
2 *
3 * Copyright (C) 1996 SpellCaster Telecommunications Inc.
4 *
5 * Card functions implementing ISDN4Linux functionality
6 *
7 * This software may be used and distributed according to the terms
8 * of the GNU General Public License, incorporated herein by reference.
9 *
10 * For more information, please contact gpl-info@spellcast.com or write:
11 *
12 * SpellCaster Telecommunications Inc.
13 * 5621 Finch Avenue East, Unit #3
14 * Scarborough, Ontario Canada
15 * M1B 2T9
16 * +1 (416) 297-8565
17 * +1 (416) 297-6433 Facsimile
18 */
19
20#include "includes.h" /* This must be first */
21#include "hardware.h"
22#include "card.h"
23
24/*
25 * Main adapter array
26 */
27extern board *sc_adapter[];
28extern int cinst;
29
30/*
31 *
32 */
33void memcpy_toshmem(int card, void *dest, const void *src, size_t n)
34{
35 unsigned long flags;
36 unsigned char ch;
37
38 if(!IS_VALID_CARD(card)) {
39 pr_debug("Invalid param: %d is not a valid card id\n", card);
40 return;
41 }
42
43 if(n > SRAM_PAGESIZE) {
44 return;
45 }
46
47 /*
48 * determine the page to load from the address
49 */
50 ch = (unsigned long) dest / SRAM_PAGESIZE;
51 pr_debug("%s: loaded page %d\n", sc_adapter[card]->devicename,ch);
52 /*
53 * Block interrupts and load the page
54 */
55 spin_lock_irqsave(&sc_adapter[card]->lock, flags);
56
57 outb(((sc_adapter[card]->shmem_magic + ch * SRAM_PAGESIZE) >> 14) | 0x80,
58 sc_adapter[card]->ioport[sc_adapter[card]->shmem_pgport]);
59 memcpy_toio(sc_adapter[card]->rambase +
60 ((unsigned long) dest % 0x4000), src, n);
61 spin_unlock_irqrestore(&sc_adapter[card]->lock, flags);
62 pr_debug("%s: set page to %#x\n",sc_adapter[card]->devicename,
63 ((sc_adapter[card]->shmem_magic + ch * SRAM_PAGESIZE)>>14)|0x80);
64 pr_debug("%s: copying %d bytes from %#x to %#x\n",
65 sc_adapter[card]->devicename, n,
66 (unsigned long) src,
67 sc_adapter[card]->rambase + ((unsigned long) dest %0x4000));
68}
69
70/*
71 * Reverse of above
72 */
73void memcpy_fromshmem(int card, void *dest, const void *src, size_t n)
74{
75 unsigned long flags;
76 unsigned char ch;
77
78 if(!IS_VALID_CARD(card)) {
79 pr_debug("Invalid param: %d is not a valid card id\n", card);
80 return;
81 }
82
83 if(n > SRAM_PAGESIZE) {
84 return;
85 }
86
87 /*
88 * determine the page to load from the address
89 */
90 ch = (unsigned long) src / SRAM_PAGESIZE;
91 pr_debug("%s: loaded page %d\n", sc_adapter[card]->devicename,ch);
92
93
94 /*
95 * Block interrupts and load the page
96 */
97 spin_lock_irqsave(&sc_adapter[card]->lock, flags);
98
99 outb(((sc_adapter[card]->shmem_magic + ch * SRAM_PAGESIZE) >> 14) | 0x80,
100 sc_adapter[card]->ioport[sc_adapter[card]->shmem_pgport]);
101 memcpy_fromio(dest,(void *)(sc_adapter[card]->rambase +
102 ((unsigned long) src % 0x4000)), n);
103 spin_unlock_irqrestore(&sc_adapter[card]->lock, flags);
104 pr_debug("%s: set page to %#x\n",sc_adapter[card]->devicename,
105 ((sc_adapter[card]->shmem_magic + ch * SRAM_PAGESIZE)>>14)|0x80);
106/* pr_debug("%s: copying %d bytes from %#x to %#x\n",
107 sc_adapter[card]->devicename, n,
108 sc_adapter[card]->rambase + ((unsigned long) src %0x4000), (unsigned long) dest); */
109}
110
111void memset_shmem(int card, void *dest, int c, size_t n)
112{
113 unsigned long flags;
114 unsigned char ch;
115
116 if(!IS_VALID_CARD(card)) {
117 pr_debug("Invalid param: %d is not a valid card id\n", card);
118 return;
119 }
120
121 if(n > SRAM_PAGESIZE) {
122 return;
123 }
124
125 /*
126 * determine the page to load from the address
127 */
128 ch = (unsigned long) dest / SRAM_PAGESIZE;
129 pr_debug("%s: loaded page %d\n",sc_adapter[card]->devicename,ch);
130
131 /*
132 * Block interrupts and load the page
133 */
134 spin_lock_irqsave(&sc_adapter[card]->lock, flags);
135
136 outb(((sc_adapter[card]->shmem_magic + ch * SRAM_PAGESIZE) >> 14) | 0x80,
137 sc_adapter[card]->ioport[sc_adapter[card]->shmem_pgport]);
138 memset_io(sc_adapter[card]->rambase +
139 ((unsigned long) dest % 0x4000), c, n);
140 pr_debug("%s: set page to %#x\n",sc_adapter[card]->devicename,
141 ((sc_adapter[card]->shmem_magic + ch * SRAM_PAGESIZE)>>14)|0x80);
142 spin_unlock_irqrestore(&sc_adapter[card]->lock, flags);
143}
diff --git a/drivers/isdn/sc/timer.c b/drivers/isdn/sc/timer.c
new file mode 100644
index 000000000000..710d0f47ca35
--- /dev/null
+++ b/drivers/isdn/sc/timer.c
@@ -0,0 +1,147 @@
1/* $Id: timer.c,v 1.3.6.1 2001/09/23 22:24:59 kai Exp $
2 *
3 * Copyright (C) 1996 SpellCaster Telecommunications Inc.
4 *
5 * This software may be used and distributed according to the terms
6 * of the GNU General Public License, incorporated herein by reference.
7 *
8 * For more information, please contact gpl-info@spellcast.com or write:
9 *
10 * SpellCaster Telecommunications Inc.
11 * 5621 Finch Avenue East, Unit #3
12 * Scarborough, Ontario Canada
13 * M1B 2T9
14 * +1 (416) 297-8565
15 * +1 (416) 297-6433 Facsimile
16 */
17
18#include "includes.h"
19#include "hardware.h"
20#include "message.h"
21#include "card.h"
22
23extern board *sc_adapter[];
24
25extern void flushreadfifo(int);
26extern int startproc(int);
27extern int indicate_status(int, int, unsigned long, char *);
28extern int sendmessage(int, unsigned int, unsigned int, unsigned int,
29 unsigned int, unsigned int, unsigned int, unsigned int *);
30
31
32/*
33 * Write the proper values into the I/O ports following a reset
34 */
35void setup_ports(int card)
36{
37
38 outb((sc_adapter[card]->rambase >> 12), sc_adapter[card]->ioport[EXP_BASE]);
39
40 /* And the IRQ */
41 outb((sc_adapter[card]->interrupt | 0x80),
42 sc_adapter[card]->ioport[IRQ_SELECT]);
43}
44
45/*
46 * Timed function to check the status of a previous reset
47 * Must be very fast as this function runs in the context of
48 * an interrupt handler.
49 *
50 * Setup the ioports for the board that were cleared by the reset.
51 * Then, check to see if the signate has been set. Next, set the
52 * signature to a known value and issue a startproc if needed.
53 */
54void check_reset(unsigned long data)
55{
56 unsigned long flags;
57 unsigned long sig;
58 int card = (unsigned int) data;
59
60 pr_debug("%s: check_timer timer called\n",
61 sc_adapter[card]->devicename);
62
63 /* Setup the io ports */
64 setup_ports(card);
65
66 spin_lock_irqsave(&sc_adapter[card]->lock, flags);
67 outb(sc_adapter[card]->ioport[sc_adapter[card]->shmem_pgport],
68 (sc_adapter[card]->shmem_magic>>14) | 0x80);
69 sig = (unsigned long) *((unsigned long *)(sc_adapter[card]->rambase + SIG_OFFSET));
70
71 /* check the signature */
72 if(sig == SIGNATURE) {
73 flushreadfifo(card);
74 spin_unlock_irqrestore(&sc_adapter[card]->lock, flags);
75 /* See if we need to do a startproc */
76 if (sc_adapter[card]->StartOnReset)
77 startproc(card);
78 } else {
79 pr_debug("%s: No signature yet, waiting another %d jiffies.\n",
80 sc_adapter[card]->devicename, CHECKRESET_TIME);
81 mod_timer(&sc_adapter[card]->reset_timer, jiffies+CHECKRESET_TIME);
82 spin_unlock_irqrestore(&sc_adapter[card]->lock, flags);
83 }
84}
85
86/*
87 * Timed function to check the status of a previous reset
88 * Must be very fast as this function runs in the context of
89 * an interrupt handler.
90 *
91 * Send check sc_adapter->phystat to see if the channels are up
92 * If they are, tell ISDN4Linux that the board is up. If not,
93 * tell IADN4Linux that it is up. Always reset the timer to
94 * fire again (endless loop).
95 */
96void check_phystat(unsigned long data)
97{
98 unsigned long flags;
99 int card = (unsigned int) data;
100
101 pr_debug("%s: Checking status...\n", sc_adapter[card]->devicename);
102 /*
103 * check the results of the last PhyStat and change only if
104 * has changed drastically
105 */
106 if (sc_adapter[card]->nphystat && !sc_adapter[card]->phystat) { /* All is well */
107 pr_debug("PhyStat transition to RUN\n");
108 pr_info("%s: Switch contacted, transmitter enabled\n",
109 sc_adapter[card]->devicename);
110 indicate_status(card, ISDN_STAT_RUN, 0, NULL);
111 }
112 else if (!sc_adapter[card]->nphystat && sc_adapter[card]->phystat) { /* All is not well */
113 pr_debug("PhyStat transition to STOP\n");
114 pr_info("%s: Switch connection lost, transmitter disabled\n",
115 sc_adapter[card]->devicename);
116
117 indicate_status(card, ISDN_STAT_STOP, 0, NULL);
118 }
119
120 sc_adapter[card]->phystat = sc_adapter[card]->nphystat;
121
122 /* Reinitialize the timer */
123 spin_lock_irqsave(&sc_adapter[card]->lock, flags);
124 mod_timer(&sc_adapter[card]->stat_timer, jiffies+CHECKSTAT_TIME);
125 spin_unlock_irqrestore(&sc_adapter[card]->lock, flags);
126
127 /* Send a new cePhyStatus message */
128 sendmessage(card, CEPID,ceReqTypePhy,ceReqClass2,
129 ceReqPhyStatus,0,0,NULL);
130}
131
132/*
133 * When in trace mode, this callback is used to swap the working shared
134 * RAM page to the trace page(s) and process all received messages. It
135 * must be called often enough to get all of the messages out of RAM before
136 * it loops around.
137 * Trace messages are \n terminated strings.
138 * We output the messages in 64 byte chunks through readstat. Each chunk
139 * is scanned for a \n followed by a time stamp. If the timerstamp is older
140 * than the current time, scanning stops and the page and offset are recorded
141 * as the starting point the next time the trace timer is called. The final
142 * step is to restore the working page and reset the timer.
143 */
144void trace_timer(unsigned long data)
145{
146 /* not implemented */
147}