diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/isdn/sc |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/isdn/sc')
-rw-r--r-- | drivers/isdn/sc/Kconfig | 12 | ||||
-rw-r--r-- | drivers/isdn/sc/Makefile | 10 | ||||
-rw-r--r-- | drivers/isdn/sc/card.h | 101 | ||||
-rw-r--r-- | drivers/isdn/sc/command.c | 441 | ||||
-rw-r--r-- | drivers/isdn/sc/debug.c | 46 | ||||
-rw-r--r-- | drivers/isdn/sc/debug.h | 19 | ||||
-rw-r--r-- | drivers/isdn/sc/event.c | 69 | ||||
-rw-r--r-- | drivers/isdn/sc/hardware.h | 110 | ||||
-rw-r--r-- | drivers/isdn/sc/includes.h | 18 | ||||
-rw-r--r-- | drivers/isdn/sc/init.c | 571 | ||||
-rw-r--r-- | drivers/isdn/sc/interrupt.c | 260 | ||||
-rw-r--r-- | drivers/isdn/sc/ioctl.c | 601 | ||||
-rw-r--r-- | drivers/isdn/sc/message.c | 241 | ||||
-rw-r--r-- | drivers/isdn/sc/message.h | 245 | ||||
-rw-r--r-- | drivers/isdn/sc/packet.c | 231 | ||||
-rw-r--r-- | drivers/isdn/sc/scioc.h | 105 | ||||
-rw-r--r-- | drivers/isdn/sc/shmem.c | 143 | ||||
-rw-r--r-- | drivers/isdn/sc/timer.c | 147 |
18 files changed, 3370 insertions, 0 deletions
diff --git a/drivers/isdn/sc/Kconfig b/drivers/isdn/sc/Kconfig new file mode 100644 index 000000000000..5346e33d816c --- /dev/null +++ b/drivers/isdn/sc/Kconfig | |||
@@ -0,0 +1,12 @@ | |||
1 | # | ||
2 | # Config.in for Spellcaster ISDN driver | ||
3 | # | ||
4 | config 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 | |||
5 | obj-$(CONFIG_ISDN_DRV_SC) += sc.o | ||
6 | |||
7 | # Multipart objects. | ||
8 | |||
9 | sc-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 | */ | ||
55 | typedef 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 | */ | ||
71 | typedef 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 | |||
25 | int dial(int card, unsigned long channel, setup_parm setup); | ||
26 | int hangup(int card, unsigned long channel); | ||
27 | int answer(int card, unsigned long channel); | ||
28 | int clreaz(int card, unsigned long channel); | ||
29 | int seteaz(int card, unsigned long channel, char *); | ||
30 | int setl2(int card, unsigned long arg); | ||
31 | int setl3(int card, unsigned long arg); | ||
32 | int acceptb(int card, unsigned long channel); | ||
33 | |||
34 | extern int cinst; | ||
35 | extern board *sc_adapter[]; | ||
36 | |||
37 | extern int sc_ioctl(int, scs_ioctl *); | ||
38 | extern int setup_buffers(int, int, unsigned int); | ||
39 | extern int indicate_status(int, int,ulong,char*); | ||
40 | extern void check_reset(unsigned long); | ||
41 | extern int send_and_receive(int, unsigned int, unsigned char, unsigned char, | ||
42 | unsigned char, unsigned char, unsigned char, unsigned char *, | ||
43 | RspMessage *, int); | ||
44 | extern int sendmessage(int, unsigned int, unsigned int, unsigned int, | ||
45 | unsigned int, unsigned int, unsigned int, unsigned int *); | ||
46 | extern inline void pullphone(char *, char *); | ||
47 | |||
48 | #ifdef DEBUG | ||
49 | /* | ||
50 | * Translate command codes to strings | ||
51 | */ | ||
52 | static 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 | */ | ||
74 | static char *l3protos[] = { "ISDN_PROTO_L3_TRANS" }; | ||
75 | static 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 | |||
82 | int 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 | |||
97 | int 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 | */ | ||
154 | int 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 | */ | ||
203 | int 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 | |||
225 | int loadproc(int card, char *data) | ||
226 | { | ||
227 | return -1; | ||
228 | } | ||
229 | |||
230 | |||
231 | /* | ||
232 | * Dials the number passed in | ||
233 | */ | ||
234 | int 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 | */ | ||
264 | int 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 | */ | ||
285 | int 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 | */ | ||
308 | int 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 | */ | ||
343 | int 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 | |||
358 | int 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 | |||
377 | int 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 | |||
391 | int 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 | |||
406 | int 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 | |||
437 | void 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 | |||
21 | int dbg_level = 0; | ||
22 | static char dbg_funcname[255]; | ||
23 | |||
24 | void dbg_endfunc(void) | ||
25 | { | ||
26 | if (dbg_level) { | ||
27 | printk("<-- Leaving function %s\n", dbg_funcname); | ||
28 | strcpy(dbg_funcname, ""); | ||
29 | } | ||
30 | } | ||
31 | |||
32 | void dbg_func(char *func) | ||
33 | { | ||
34 | strcpy(dbg_funcname, func); | ||
35 | if(dbg_level) | ||
36 | printk("--> Entering function %s\n", dbg_funcname); | ||
37 | } | ||
38 | |||
39 | inline 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 | |||
23 | extern int cinst; | ||
24 | extern board *sc_adapter[]; | ||
25 | |||
26 | #ifdef DEBUG | ||
27 | static 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 | |||
44 | int 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 | |||
15 | MODULE_DESCRIPTION("ISDN4Linux: Driver for Spellcaster card"); | ||
16 | MODULE_AUTHOR("Spellcaster Telecommunications Inc."); | ||
17 | MODULE_LICENSE("GPL"); | ||
18 | |||
19 | board *sc_adapter[MAX_CARDS]; | ||
20 | int cinst; | ||
21 | |||
22 | static char devname[] = "scX"; | ||
23 | const char version[] = "2.0b1"; | ||
24 | |||
25 | const char *boardname[] = { "DataCommute/BRI", "DataCommute/PRI", "TeleCommute/BRI" }; | ||
26 | |||
27 | /* insmod set parameters */ | ||
28 | static unsigned int io[] = {0,0,0,0}; | ||
29 | static unsigned char irq[] = {0,0,0,0}; | ||
30 | static unsigned long ram[] = {0,0,0,0}; | ||
31 | static int do_reset = 0; | ||
32 | |||
33 | module_param_array(io, int, NULL, 0); | ||
34 | module_param_array(irq, int, NULL, 0); | ||
35 | module_param_array(ram, int, NULL, 0); | ||
36 | module_param(do_reset, bool, 0); | ||
37 | |||
38 | static int sup_irq[] = { 11, 10, 9, 5, 12, 14, 7, 3, 4, 6 }; | ||
39 | #define MAX_IRQS 10 | ||
40 | |||
41 | extern irqreturn_t interrupt_handler(int, void *, struct pt_regs *); | ||
42 | extern int sndpkt(int, int, int, struct sk_buff *); | ||
43 | extern int command(isdn_ctrl *); | ||
44 | extern int indicate_status(int, int, ulong, char*); | ||
45 | extern int reset(int); | ||
46 | |||
47 | int identify_board(unsigned long, unsigned int); | ||
48 | |||
49 | int 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 | |||
59 | static 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 | |||
402 | static 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 | |||
457 | int 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 | |||
570 | module_init(sc_init); | ||
571 | module_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 | |||
24 | extern int indicate_status(int, int, ulong, char *); | ||
25 | extern void check_phystat(unsigned long); | ||
26 | extern int receivemessage(int, RspMessage *); | ||
27 | extern int sendmessage(int, unsigned int, unsigned int, unsigned int, | ||
28 | unsigned int, unsigned int, unsigned int, unsigned int *); | ||
29 | extern void rcvpkt(int, RspMessage *); | ||
30 | |||
31 | extern int cinst; | ||
32 | extern board *sc_adapter[]; | ||
33 | |||
34 | int 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 | */ | ||
48 | irqreturn_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 | |||
15 | extern int indicate_status(int, int, unsigned long, char *); | ||
16 | extern int startproc(int); | ||
17 | extern int loadproc(int, char *record); | ||
18 | extern int reset(int); | ||
19 | extern int send_and_receive(int, unsigned int, unsigned char,unsigned char, | ||
20 | unsigned char,unsigned char, | ||
21 | unsigned char, unsigned char *, RspMessage *, int); | ||
22 | |||
23 | extern board *sc_adapter[]; | ||
24 | |||
25 | |||
26 | int GetStatus(int card, boardInfo *); | ||
27 | |||
28 | /* | ||
29 | * Process private IOCTL messages (typically from scctrl) | ||
30 | */ | ||
31 | int 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 | |||
431 | int 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 | |||
25 | extern board *sc_adapter[]; | ||
26 | extern unsigned int cinst; | ||
27 | |||
28 | /* | ||
29 | * Obligatory function prototypes | ||
30 | */ | ||
31 | extern int indicate_status(int,ulong,char*); | ||
32 | extern int scm_command(isdn_ctrl *); | ||
33 | |||
34 | |||
35 | /* | ||
36 | * receive a message from the board | ||
37 | */ | ||
38 | int 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 | */ | ||
93 | int 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 | |||
178 | int 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 | */ | ||
183 | typedef 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 | */ | ||
192 | typedef 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 | */ | ||
206 | struct 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 | |||
226 | typedef struct message ReqMessage; /* Request message */ | ||
227 | typedef 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 | */ | ||
233 | typedef 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 | |||
23 | extern board *sc_adapter[]; | ||
24 | extern unsigned int cinst; | ||
25 | |||
26 | extern int get_card_from_id(int); | ||
27 | extern int indicate_status(int, int,ulong, char*); | ||
28 | extern void memcpy_toshmem(int, void *, const void *, size_t); | ||
29 | extern void memcpy_fromshmem(int, void *, const void *, size_t); | ||
30 | extern int sendmessage(int, unsigned int, unsigned int, unsigned int, | ||
31 | unsigned int, unsigned int, unsigned int, unsigned int *); | ||
32 | |||
33 | int 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 | |||
103 | void 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 | |||
155 | int 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 | |||
216 | int 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 | |||
26 | typedef 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 | |||
39 | typedef struct { | ||
40 | unsigned long tx_good; | ||
41 | unsigned long tx_bad; | ||
42 | unsigned long rx_good; | ||
43 | unsigned long rx_bad; | ||
44 | } ChLinkStats; | ||
45 | |||
46 | typedef struct { | ||
47 | char spid[49]; | ||
48 | char dn[49]; | ||
49 | char call_type; | ||
50 | char phy_stat; | ||
51 | ChLinkStats link_stats; | ||
52 | } BRIStat; | ||
53 | |||
54 | typedef BRIStat POTStat; | ||
55 | |||
56 | typedef struct { | ||
57 | char call_type; | ||
58 | char call_state; | ||
59 | char serv_state; | ||
60 | char phy_stat; | ||
61 | ChLinkStats link_stats; | ||
62 | } PRIStat; | ||
63 | |||
64 | typedef char PRIInfo; | ||
65 | typedef char BRIInfo; | ||
66 | typedef char POTInfo; | ||
67 | |||
68 | |||
69 | typedef 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 | |||
79 | typedef 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 | */ | ||
27 | extern board *sc_adapter[]; | ||
28 | extern int cinst; | ||
29 | |||
30 | /* | ||
31 | * | ||
32 | */ | ||
33 | void 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 | */ | ||
73 | void 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 | |||
111 | void 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 | |||
23 | extern board *sc_adapter[]; | ||
24 | |||
25 | extern void flushreadfifo(int); | ||
26 | extern int startproc(int); | ||
27 | extern int indicate_status(int, int, unsigned long, char *); | ||
28 | extern 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 | */ | ||
35 | void 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 | */ | ||
54 | void 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 | */ | ||
96 | void 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 | */ | ||
144 | void trace_timer(unsigned long data) | ||
145 | { | ||
146 | /* not implemented */ | ||
147 | } | ||