Merge master.kernel.org:/home/rmk/linux-2.6-mmc
[linux-drm-fsl-dcu.git] / drivers / isdn / sc / command.c
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 static int dial(int card, unsigned long channel, setup_parm setup);
26 static int hangup(int card, unsigned long channel);
27 static int answer(int card, unsigned long channel);
28 static int clreaz(int card, unsigned long channel);
29 static int seteaz(int card, unsigned long channel, char *);
30 static int setl2(int card, unsigned long arg);
31 static int setl3(int card, unsigned long arg);
32 static 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
47 #ifdef DEBUG
48 /*
49  * Translate command codes to strings
50  */
51 static char *commands[] = { "ISDN_CMD_IOCTL",
52                             "ISDN_CMD_DIAL",
53                             "ISDN_CMD_ACCEPTB",
54                             "ISDN_CMD_ACCEPTB",
55                             "ISDN_CMD_HANGUP",
56                             "ISDN_CMD_CLREAZ",
57                             "ISDN_CMD_SETEAZ",
58                             NULL,
59                             NULL,
60                             NULL,
61                             "ISDN_CMD_SETL2",
62                             NULL,
63                             "ISDN_CMD_SETL3",
64                             NULL,
65                             NULL,
66                             NULL,
67                             NULL,
68                             NULL, };
69
70 /*
71  * Translates ISDN4Linux protocol codes to strings for debug messages
72  */
73 static char *l3protos[] = { "ISDN_PROTO_L3_TRANS" };
74 static char *l2protos[] = { "ISDN_PROTO_L2_X75I",
75                             "ISDN_PROTO_L2_X75UI",
76                             "ISDN_PROTO_L2_X75BUI",
77                             "ISDN_PROTO_L2_HDLC",
78                             "ISDN_PROTO_L2_TRANS" };
79 #endif
80
81 int get_card_from_id(int driver)
82 {
83         int i;
84
85         for(i = 0 ; i < cinst ; i++) {
86                 if(sc_adapter[i]->driverId == driver)
87                         return i;
88         }
89         return -ENODEV;
90 }
91
92 /* 
93  * command
94  */
95
96 int command(isdn_ctrl *cmd)
97 {
98         int card;
99
100         card = get_card_from_id(cmd->driver);
101         if(!IS_VALID_CARD(card)) {
102                 pr_debug("Invalid param: %d is not a valid card id\n", card);
103                 return -ENODEV;
104         }
105
106         pr_debug("%s: Received %s command from Link Layer\n",
107                 sc_adapter[card]->devicename, commands[cmd->command]);
108
109         /*
110          * Dispatch the command
111          */
112         switch(cmd->command) {
113         case ISDN_CMD_IOCTL:
114         {
115                 unsigned long   cmdptr;
116                 scs_ioctl       ioc;
117
118                 memcpy(&cmdptr, cmd->parm.num, sizeof(unsigned long));
119                 if (copy_from_user(&ioc, (scs_ioctl __user *)cmdptr,
120                                    sizeof(scs_ioctl))) {
121                         pr_debug("%s: Failed to verify user space 0x%x\n",
122                                 sc_adapter[card]->devicename, cmdptr);
123                         return -EFAULT;
124                 }
125                 return sc_ioctl(card, &ioc);
126         }
127         case ISDN_CMD_DIAL:
128                 return dial(card, cmd->arg, cmd->parm.setup);
129         case ISDN_CMD_HANGUP:
130                 return hangup(card, cmd->arg);
131         case ISDN_CMD_ACCEPTD:
132                 return answer(card, cmd->arg);
133         case ISDN_CMD_ACCEPTB:
134                 return acceptb(card, cmd->arg);
135         case ISDN_CMD_CLREAZ:
136                 return clreaz(card, cmd->arg);
137         case ISDN_CMD_SETEAZ:
138                 return seteaz(card, cmd->arg, cmd->parm.num);
139         case ISDN_CMD_SETL2:
140                 return setl2(card, cmd->arg);
141         case ISDN_CMD_SETL3:
142                 return setl3(card, cmd->arg);
143         default:
144                 return -EINVAL;
145         }
146         return 0;
147 }
148
149 /*
150  * start the onboard firmware
151  */
152 int startproc(int card) 
153 {
154         int status;
155
156         if(!IS_VALID_CARD(card)) {
157                 pr_debug("Invalid param: %d is not a valid card id\n", card);
158                 return -ENODEV;
159         }
160
161         /*
162          * send start msg 
163          */
164         status = sendmessage(card, CMPID,cmReqType2,
165                           cmReqClass0,
166                           cmReqStartProc,
167                           0,0,NULL);
168         pr_debug("%s: Sent startProc\n", sc_adapter[card]->devicename);
169         
170         return status;
171 }
172
173
174 /*
175  * Dials the number passed in 
176  */
177 static int dial(int card, unsigned long channel, setup_parm setup)
178 {
179         int status;
180         char Phone[48];
181   
182         if(!IS_VALID_CARD(card)) {
183                 pr_debug("Invalid param: %d is not a valid card id\n", card);
184                 return -ENODEV;
185         }
186
187         /*extract ISDN number to dial from eaz/msn string*/ 
188         strcpy(Phone,setup.phone); 
189
190         /*send the connection message*/
191         status = sendmessage(card, CEPID,ceReqTypePhy,
192                                 ceReqClass1,
193                                 ceReqPhyConnect,
194                                 (unsigned char) channel+1, 
195                                 strlen(Phone),
196                                 (unsigned int *) Phone);
197
198         pr_debug("%s: Dialing %s on channel %d\n",
199                 sc_adapter[card]->devicename, Phone, channel+1);
200         
201         return status;
202 }
203
204 /*
205  * Answer an incoming call 
206  */
207 static int answer(int card, unsigned long channel)
208 {
209         if(!IS_VALID_CARD(card)) {
210                 pr_debug("Invalid param: %d is not a valid card id\n", card);
211                 return -ENODEV;
212         }
213
214         if(setup_buffers(card, channel+1, BUFFER_SIZE)) {
215                 hangup(card, channel+1);
216                 return -ENOBUFS;
217         }
218
219         indicate_status(card, ISDN_STAT_BCONN,channel,NULL);
220         pr_debug("%s: Answered incoming call on channel %s\n",
221                 sc_adapter[card]->devicename, channel+1);
222         return 0;
223 }
224
225 /*
226  * Hangup up the call on specified channel
227  */
228 static int hangup(int card, unsigned long channel)
229 {
230         int status;
231
232         if(!IS_VALID_CARD(card)) {
233                 pr_debug("Invalid param: %d is not a valid card id\n", card);
234                 return -ENODEV;
235         }
236
237         status = sendmessage(card, CEPID, ceReqTypePhy,
238                                                  ceReqClass1,
239                                                  ceReqPhyDisconnect,
240                                                  (unsigned char) channel+1,
241                                                  0,
242                                                  NULL);
243         pr_debug("%s: Sent HANGUP message to channel %d\n",
244                 sc_adapter[card]->devicename, channel+1);
245         return status;
246 }
247
248 /*
249  * Set the layer 2 protocol (X.25, HDLC, Raw)
250  */
251 static int setl2(int card, unsigned long arg)
252 {
253         int status =0;
254         int protocol,channel;
255
256         if(!IS_VALID_CARD(card)) {
257                 pr_debug("Invalid param: %d is not a valid card id\n", card);
258                 return -ENODEV;
259         }
260         protocol = arg >> 8;
261         channel = arg & 0xff;
262         sc_adapter[card]->channel[channel].l2_proto = protocol;
263         pr_debug("%s: Level 2 protocol for channel %d set to %s from %d\n",
264                 sc_adapter[card]->devicename, channel+1,
265                 l2protos[sc_adapter[card]->channel[channel].l2_proto],protocol);
266
267         /*
268          * check that the adapter is also set to the correct protocol
269          */
270         pr_debug("%s: Sending GetFrameFormat for channel %d\n",
271                 sc_adapter[card]->devicename, channel+1);
272         status = sendmessage(card, CEPID, ceReqTypeCall,
273                                 ceReqClass0,
274                                 ceReqCallGetFrameFormat,
275                                 (unsigned char)channel+1,
276                                 1,
277                                 (unsigned int *) protocol);
278         if(status) 
279                 return status;
280         return 0;
281 }
282
283 /*
284  * Set the layer 3 protocol
285  */
286 static int setl3(int card, unsigned long channel)
287 {
288         int protocol = channel >> 8;
289
290         if(!IS_VALID_CARD(card)) {
291                 pr_debug("Invalid param: %d is not a valid card id\n", card);
292                 return -ENODEV;
293         }
294
295         sc_adapter[card]->channel[channel].l3_proto = protocol;
296         pr_debug("%s: Level 3 protocol for channel %d set to %s\n",
297                 sc_adapter[card]->devicename, channel+1, l3protos[protocol]);
298         return 0;
299 }
300
301 static int acceptb(int card, unsigned long channel)
302 {
303         if(!IS_VALID_CARD(card)) {
304                 pr_debug("Invalid param: %d is not a valid card id\n", card);
305                 return -ENODEV;
306         }
307
308         if(setup_buffers(card, channel+1, BUFFER_SIZE))
309         {
310                 hangup(card, channel+1);
311                 return -ENOBUFS;
312         }
313
314         pr_debug("%s: B-Channel connection accepted on channel %d\n",
315                 sc_adapter[card]->devicename, channel+1);
316         indicate_status(card, ISDN_STAT_BCONN, channel, NULL);
317         return 0;
318 }
319
320 static int clreaz(int card, unsigned long arg)
321 {
322         if(!IS_VALID_CARD(card)) {
323                 pr_debug("Invalid param: %d is not a valid card id\n", card);
324                 return -ENODEV;
325         }
326
327         strcpy(sc_adapter[card]->channel[arg].eazlist, "");
328         sc_adapter[card]->channel[arg].eazclear = 1;
329         pr_debug("%s: EAZ List cleared for channel %d\n",
330                 sc_adapter[card]->devicename, arg+1);
331         return 0;
332 }
333
334 static int seteaz(int card, unsigned long arg, char *num)
335 {
336         if(!IS_VALID_CARD(card)) {
337                 pr_debug("Invalid param: %d is not a valid card id\n", card);
338                 return -ENODEV;
339         }
340
341         strcpy(sc_adapter[card]->channel[arg].eazlist, num);
342         sc_adapter[card]->channel[arg].eazclear = 0;
343         pr_debug("%s: EAZ list for channel %d set to: %s\n",
344                 sc_adapter[card]->devicename, arg+1,
345                 sc_adapter[card]->channel[arg].eazlist);
346         return 0;
347 }
348
349 int reset(int card)
350 {
351         unsigned long flags;
352
353         if(!IS_VALID_CARD(card)) {
354                 pr_debug("Invalid param: %d is not a valid card id\n", card);
355                 return -ENODEV;
356         }
357
358         indicate_status(card, ISDN_STAT_STOP, 0, NULL);
359
360         if(sc_adapter[card]->EngineUp) {
361                 del_timer(&sc_adapter[card]->stat_timer);
362         }
363
364         sc_adapter[card]->EngineUp = 0;
365
366         spin_lock_irqsave(&sc_adapter[card]->lock, flags);
367         init_timer(&sc_adapter[card]->reset_timer);
368         sc_adapter[card]->reset_timer.function = check_reset;
369         sc_adapter[card]->reset_timer.data = card;
370         sc_adapter[card]->reset_timer.expires = jiffies + CHECKRESET_TIME;
371         add_timer(&sc_adapter[card]->reset_timer);
372         spin_unlock_irqrestore(&sc_adapter[card]->lock, flags);
373
374         outb(0x1,sc_adapter[card]->ioport[SFT_RESET]);
375
376         pr_debug("%s: Adapter Reset\n", sc_adapter[card]->devicename);
377         return 0;
378 }
379
380 void flushreadfifo (int card)
381 {
382         while(inb(sc_adapter[card]->ioport[FIFO_STATUS]) & RF_HAS_DATA)
383                 inb(sc_adapter[card]->ioport[FIFO_READ]);
384 }