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