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