diff options
Diffstat (limited to 'drivers/isdn/sc/command.c')
-rw-r--r-- | drivers/isdn/sc/command.c | 441 |
1 files changed, 441 insertions, 0 deletions
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 | } | ||