ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / drivers / isdn / sc / ioctl.c
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, (char *) 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, (char *)data->dataptr,
122                                    sizeof(char))) {
123                         kfree(rcvmsg);
124                         return -EFAULT;
125                 }
126
127                 pr_debug("%s: SCIOCSETSWITCH: setting switch type to %d\n",
128                         sc_adapter[card]->devicename,
129                         switchtype);
130                 status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0, ceReqCallSetSwitchType,
131                                                 0, sizeof(char),&switchtype, rcvmsg, SAR_TIMEOUT);
132                 if(!status && !(rcvmsg->rsp_status)) {
133                         pr_debug("%s: SCIOCSETSWITCH: command successful\n",
134                                 sc_adapter[card]->devicename);
135                         kfree(rcvmsg);
136                         return 0;
137                 }
138                 else {
139                         pr_debug("%s: SCIOCSETSWITCH: command failed (status = %d)\n",
140                                 sc_adapter[card]->devicename, status);
141                         kfree(rcvmsg);
142                         return status;
143                 }
144         }
145                 
146         case SCIOCGETSWITCH:
147         {
148                 pr_debug("%s: SCIOGETSWITCH: ioctl received\n",
149                                 sc_adapter[card]->devicename);
150
151                 /*
152                  * Get the switch type from the board
153                  */
154                 status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0, 
155                         ceReqCallGetSwitchType, 0, 0, 0, rcvmsg, SAR_TIMEOUT);
156                 if (!status && !(rcvmsg->rsp_status)) {
157                         pr_debug("%s: SCIOCGETSWITCH: command successful\n",
158                                         sc_adapter[card]->devicename);
159                 }
160                 else {
161                         pr_debug("%s: SCIOCGETSWITCH: command failed (status = %d)\n",
162                                 sc_adapter[card]->devicename, status);
163                         kfree(rcvmsg);
164                         return status;
165                 }
166
167                 switchtype = rcvmsg->msg_data.byte_array[0];
168
169                 /*
170                  * Package the switch type and send to user space
171                  */
172                 if (copy_to_user((char *)data->dataptr, &switchtype,
173                                  sizeof(char))) {
174                         kfree(rcvmsg);
175                         return -EFAULT;
176                 }
177
178                 kfree(rcvmsg);
179                 return 0;
180         }
181
182         case SCIOCGETSPID:
183         {
184                 pr_debug("%s: SCIOGETSPID: ioctl received\n",
185                                 sc_adapter[card]->devicename);
186
187                 spid = kmalloc(SCIOC_SPIDSIZE, GFP_KERNEL);
188                 if(!spid) {
189                         kfree(rcvmsg);
190                         return -ENOMEM;
191                 }
192                 /*
193                  * Get the spid from the board
194                  */
195                 status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0, ceReqCallGetSPID,
196                                         data->channel, 0, 0, rcvmsg, SAR_TIMEOUT);
197                 if (!status) {
198                         pr_debug("%s: SCIOCGETSPID: command successful\n",
199                                         sc_adapter[card]->devicename);
200                 }
201                 else {
202                         pr_debug("%s: SCIOCGETSPID: command failed (status = %d)\n",
203                                 sc_adapter[card]->devicename, status);
204                         kfree(rcvmsg);
205                         return status;
206                 }
207                 strcpy(spid, rcvmsg->msg_data.byte_array);
208
209                 /*
210                  * Package the switch type and send to user space
211                  */
212                 if (copy_to_user((char *)data->dataptr, spid, SCIOC_SPIDSIZE)) {
213                         kfree(spid);
214                         kfree(rcvmsg);
215                         return -EFAULT;
216                 }
217
218                 kfree(spid);
219                 kfree(rcvmsg);
220                 return 0;
221         }       
222
223         case SCIOCSETSPID:
224         {
225                 pr_debug("%s: DCBIOSETSPID: ioctl received\n",
226                                 sc_adapter[card]->devicename);
227
228                 spid = kmalloc(SCIOC_SPIDSIZE, GFP_KERNEL);
229                 if(!spid) {
230                         kfree(rcvmsg);
231                         return -ENOMEM;
232                 }
233
234                 /*
235                  * Get the spid from user space
236                  */
237                 if (copy_from_user(spid, (char *) data->dataptr, SCIOC_SPIDSIZE)) {
238                         kfree(rcvmsg);
239                         return -EFAULT;
240                 }
241
242                 pr_debug("%s: SCIOCSETSPID: setting channel %d spid to %s\n", 
243                         sc_adapter[card]->devicename, data->channel, spid);
244                 status = send_and_receive(card, CEPID, ceReqTypeCall, 
245                         ceReqClass0, ceReqCallSetSPID, data->channel, 
246                         strlen(spid), spid, rcvmsg, SAR_TIMEOUT);
247                 if(!status && !(rcvmsg->rsp_status)) {
248                         pr_debug("%s: SCIOCSETSPID: command successful\n", 
249                                 sc_adapter[card]->devicename);
250                         kfree(rcvmsg);
251                         kfree(spid);
252                         return 0;
253                 }
254                 else {
255                         pr_debug("%s: SCIOCSETSPID: command failed (status = %d)\n",
256                                 sc_adapter[card]->devicename, status);
257                         kfree(rcvmsg);
258                         kfree(spid);
259                         return status;
260                 }
261         }
262
263         case SCIOCGETDN:
264         {
265                 pr_debug("%s: SCIOGETDN: ioctl received\n",
266                                 sc_adapter[card]->devicename);
267
268                 /*
269                  * Get the dn from the board
270                  */
271                 status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0, ceReqCallGetMyNumber,
272                                         data->channel, 0, 0, rcvmsg, SAR_TIMEOUT);
273                 if (!status) {
274                         pr_debug("%s: SCIOCGETDN: command successful\n",
275                                         sc_adapter[card]->devicename);
276                 }
277                 else {
278                         pr_debug("%s: SCIOCGETDN: command failed (status = %d)\n",
279                                 sc_adapter[card]->devicename, status);
280                         kfree(rcvmsg);
281                         return status;
282                 }
283
284                 dn = kmalloc(SCIOC_DNSIZE, GFP_KERNEL);
285                 if (!dn) {
286                         kfree(rcvmsg);
287                         return -ENOMEM;
288                 }
289                 strcpy(dn, rcvmsg->msg_data.byte_array);
290                 kfree(rcvmsg);
291
292                 /*
293                  * Package the dn and send to user space
294                  */
295                 if (copy_to_user((char *)data->dataptr, dn, SCIOC_DNSIZE)) {
296                         kfree(dn);
297                         return -EFAULT;
298                 }
299                 kfree(dn);
300                 return 0;
301         }       
302
303         case SCIOCSETDN:
304         {
305                 pr_debug("%s: SCIOSETDN: ioctl received\n",
306                                 sc_adapter[card]->devicename);
307
308                 dn = kmalloc(SCIOC_DNSIZE, GFP_KERNEL);
309                 if (!dn) {
310                         kfree(rcvmsg);
311                         return -ENOMEM;
312                 }
313                 /*
314                  * Get the spid from user space
315                  */
316                 if (copy_from_user(dn, (char *)data->dataptr, SCIOC_DNSIZE)) {
317                         kfree(rcvmsg);
318                         kfree(dn);
319                         return -EFAULT;
320                 }
321
322                 pr_debug("%s: SCIOCSETDN: setting channel %d dn to %s\n", 
323                         sc_adapter[card]->devicename, data->channel, dn);
324                 status = send_and_receive(card, CEPID, ceReqTypeCall, 
325                         ceReqClass0, ceReqCallSetMyNumber, data->channel, 
326                         strlen(dn),dn,rcvmsg, SAR_TIMEOUT);
327                 if(!status && !(rcvmsg->rsp_status)) {
328                         pr_debug("%s: SCIOCSETDN: command successful\n", 
329                                 sc_adapter[card]->devicename);
330                         kfree(rcvmsg);
331                         kfree(dn);
332                         return 0;
333                 }
334                 else {
335                         pr_debug("%s: SCIOCSETDN: command failed (status = %d)\n",
336                                 sc_adapter[card]->devicename, status);
337                         kfree(rcvmsg);
338                         kfree(dn);
339                         return status;
340                 }
341         }
342
343         case SCIOCTRACE:
344
345                 pr_debug("%s: SCIOTRACE: ioctl received\n",
346                                 sc_adapter[card]->devicename);
347 /*              sc_adapter[card]->trace = !sc_adapter[card]->trace;
348                 pr_debug("%s: SCIOCTRACE: tracing turned %s\n",
349                                 sc_adapter[card]->devicename,
350                         sc_adapter[card]->trace ? "ON" : "OFF"); */
351                 break;
352
353         case SCIOCSTAT:
354         {
355                 boardInfo *bi;
356
357                 pr_debug("%s: SCIOSTAT: ioctl received\n",
358                                 sc_adapter[card]->devicename);
359
360                 bi = kmalloc (sizeof(boardInfo), GFP_KERNEL);
361                 if (!bi) {
362                         kfree(rcvmsg);
363                         return -ENOMEM;
364                 }
365
366                 kfree(rcvmsg);
367                 GetStatus(card, bi);
368
369                 if (copy_to_user((boardInfo *)data->dataptr, bi,
370                                  sizeof(boardInfo))) {
371                         kfree(bi);
372                         return -EFAULT;
373                 }
374
375                 kfree(bi);
376                 return 0;
377         }
378
379         case SCIOCGETSPEED:
380         {
381                 pr_debug("%s: SCIOGETSPEED: ioctl received\n",
382                                 sc_adapter[card]->devicename);
383
384                 /*
385                  * Get the speed from the board
386                  */
387                 status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0, 
388                         ceReqCallGetCallType, data->channel, 0, 0, rcvmsg, SAR_TIMEOUT);
389                 if (!status && !(rcvmsg->rsp_status)) {
390                         pr_debug("%s: SCIOCGETSPEED: command successful\n",
391                                 sc_adapter[card]->devicename);
392                 }
393                 else {
394                         pr_debug("%s: SCIOCGETSPEED: command failed (status = %d)\n",
395                                 sc_adapter[card]->devicename, status);
396                         kfree(rcvmsg);
397                         return status;
398                 }
399
400                 speed = rcvmsg->msg_data.byte_array[0];
401
402                 kfree(rcvmsg);
403
404                 /*
405                  * Package the switch type and send to user space
406                  */
407
408                 if (copy_to_user((char *) data->dataptr, &speed, sizeof(char)))
409                         return -EFAULT;
410
411                 return 0;
412         }
413
414         case SCIOCSETSPEED:
415                 pr_debug("%s: SCIOCSETSPEED: ioctl received\n",
416                                 sc_adapter[card]->devicename);
417                 break;
418
419         case SCIOCLOOPTST:
420                 pr_debug("%s: SCIOCLOOPTST: ioctl received\n",
421                                 sc_adapter[card]->devicename);
422                 break;
423
424         default:
425                 kfree(rcvmsg);
426                 return -1;
427         }
428
429         kfree(rcvmsg);
430         return 0;
431 }
432
433 int GetStatus(int card, boardInfo *bi)
434 {
435         RspMessage rcvmsg;
436         int i, status;
437
438         /*
439          * Fill in some of the basic info about the board
440          */
441         bi->modelid = sc_adapter[card]->model;
442         strcpy(bi->serial_no, sc_adapter[card]->hwconfig.serial_no);
443         strcpy(bi->part_no, sc_adapter[card]->hwconfig.part_no);
444         bi->iobase = sc_adapter[card]->iobase;
445         bi->rambase = sc_adapter[card]->rambase;
446         bi->irq = sc_adapter[card]->interrupt;
447         bi->ramsize = sc_adapter[card]->hwconfig.ram_size;
448         bi->interface = sc_adapter[card]->hwconfig.st_u_sense;
449         strcpy(bi->load_ver, sc_adapter[card]->load_ver);
450         strcpy(bi->proc_ver, sc_adapter[card]->proc_ver);
451
452         /*
453          * Get the current PhyStats and LnkStats
454          */
455         status = send_and_receive(card, CEPID, ceReqTypePhy, ceReqClass2,
456                 ceReqPhyStatus, 0, 0, NULL, &rcvmsg, SAR_TIMEOUT);
457         if(!status) {
458                 if(sc_adapter[card]->model < PRI_BOARD) {
459                         bi->l1_status = rcvmsg.msg_data.byte_array[2];
460                         for(i = 0 ; i < BRI_CHANNELS ; i++)
461                                 bi->status.bristats[i].phy_stat =
462                                         rcvmsg.msg_data.byte_array[i];
463                 }
464                 else {
465                         bi->l1_status = rcvmsg.msg_data.byte_array[0];
466                         bi->l2_status = rcvmsg.msg_data.byte_array[1];
467                         for(i = 0 ; i < PRI_CHANNELS ; i++)
468                                 bi->status.pristats[i].phy_stat = 
469                                         rcvmsg.msg_data.byte_array[i+2];
470                 }
471         }
472         
473         /*
474          * Get the call types for each channel
475          */
476         for (i = 0 ; i < sc_adapter[card]->nChannels ; i++) {
477                 status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0,
478                         ceReqCallGetCallType, 0, 0, NULL, &rcvmsg, SAR_TIMEOUT);
479                 if(!status) {
480                         if (sc_adapter[card]->model == PRI_BOARD) {
481                                 bi->status.pristats[i].call_type = 
482                                         rcvmsg.msg_data.byte_array[0];
483                         }
484                         else {
485                                 bi->status.bristats[i].call_type =
486                                         rcvmsg.msg_data.byte_array[0];
487                         }
488                 }
489         }
490         
491         /*
492          * If PRI, get the call states and service states for each channel
493          */
494         if (sc_adapter[card]->model == PRI_BOARD) {
495                 /*
496                  * Get the call states
497                  */
498                 status = send_and_receive(card, CEPID, ceReqTypeStat, ceReqClass2,
499                         ceReqPhyChCallState, 0, 0, NULL, &rcvmsg, SAR_TIMEOUT);
500                 if(!status) {
501                         for( i = 0 ; i < PRI_CHANNELS ; i++ )
502                                 bi->status.pristats[i].call_state = 
503                                         rcvmsg.msg_data.byte_array[i];
504                 }
505
506                 /*
507                  * Get the service states
508                  */
509                 status = send_and_receive(card, CEPID, ceReqTypeStat, ceReqClass2,
510                         ceReqPhyChServState, 0, 0, NULL, &rcvmsg, SAR_TIMEOUT);
511                 if(!status) {
512                         for( i = 0 ; i < PRI_CHANNELS ; i++ )
513                                 bi->status.pristats[i].serv_state = 
514                                         rcvmsg.msg_data.byte_array[i];
515                 }
516
517                 /*
518                  * Get the link stats for the channels
519                  */
520                 for (i = 1 ; i <= PRI_CHANNELS ; i++) {
521                         status = send_and_receive(card, CEPID, ceReqTypeLnk, ceReqClass0,
522                                 ceReqLnkGetStats, i, 0, NULL, &rcvmsg, SAR_TIMEOUT);
523                         if (!status) {
524                                 bi->status.pristats[i-1].link_stats.tx_good =
525                                         (unsigned long)rcvmsg.msg_data.byte_array[0];
526                                 bi->status.pristats[i-1].link_stats.tx_bad =
527                                         (unsigned long)rcvmsg.msg_data.byte_array[4];
528                                 bi->status.pristats[i-1].link_stats.rx_good =
529                                         (unsigned long)rcvmsg.msg_data.byte_array[8];
530                                 bi->status.pristats[i-1].link_stats.rx_bad =
531                                         (unsigned long)rcvmsg.msg_data.byte_array[12];
532                         }
533                 }
534
535                 /*
536                  * Link stats for the D channel
537                  */
538                 status = send_and_receive(card, CEPID, ceReqTypeLnk, ceReqClass0,
539                         ceReqLnkGetStats, 0, 0, NULL, &rcvmsg, SAR_TIMEOUT);
540                 if (!status) {
541                         bi->dch_stats.tx_good = (unsigned long)rcvmsg.msg_data.byte_array[0];
542                         bi->dch_stats.tx_bad = (unsigned long)rcvmsg.msg_data.byte_array[4];
543                         bi->dch_stats.rx_good = (unsigned long)rcvmsg.msg_data.byte_array[8];
544                         bi->dch_stats.rx_bad = (unsigned long)rcvmsg.msg_data.byte_array[12];
545                 }
546
547                 return 0;
548         }
549
550         /*
551          * If BRI or POTS, Get SPID, DN and call types for each channel
552          */
553
554         /*
555          * Get the link stats for the channels
556          */
557         status = send_and_receive(card, CEPID, ceReqTypeLnk, ceReqClass0,
558                 ceReqLnkGetStats, 0, 0, NULL, &rcvmsg, SAR_TIMEOUT);
559         if (!status) {
560                 bi->dch_stats.tx_good = (unsigned long)rcvmsg.msg_data.byte_array[0];
561                 bi->dch_stats.tx_bad = (unsigned long)rcvmsg.msg_data.byte_array[4];
562                 bi->dch_stats.rx_good = (unsigned long)rcvmsg.msg_data.byte_array[8];
563                 bi->dch_stats.rx_bad = (unsigned long)rcvmsg.msg_data.byte_array[12];
564                 bi->status.bristats[0].link_stats.tx_good = 
565                         (unsigned long)rcvmsg.msg_data.byte_array[16];
566                 bi->status.bristats[0].link_stats.tx_bad = 
567                         (unsigned long)rcvmsg.msg_data.byte_array[20];
568                 bi->status.bristats[0].link_stats.rx_good = 
569                         (unsigned long)rcvmsg.msg_data.byte_array[24];
570                 bi->status.bristats[0].link_stats.rx_bad = 
571                         (unsigned long)rcvmsg.msg_data.byte_array[28];
572                 bi->status.bristats[1].link_stats.tx_good = 
573                         (unsigned long)rcvmsg.msg_data.byte_array[32];
574                 bi->status.bristats[1].link_stats.tx_bad = 
575                         (unsigned long)rcvmsg.msg_data.byte_array[36];
576                 bi->status.bristats[1].link_stats.rx_good = 
577                         (unsigned long)rcvmsg.msg_data.byte_array[40];
578                 bi->status.bristats[1].link_stats.rx_bad = 
579                         (unsigned long)rcvmsg.msg_data.byte_array[44];
580         }
581
582         /*
583          * Get the SPIDs
584          */
585         for (i = 0 ; i < BRI_CHANNELS ; i++) {
586                 status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0,
587                         ceReqCallGetSPID, i+1, 0, NULL, &rcvmsg, SAR_TIMEOUT);
588                 if (!status)
589                         strcpy(bi->status.bristats[i].spid, rcvmsg.msg_data.byte_array);
590         }
591                 
592         /*
593          * Get the DNs
594          */
595         for (i = 0 ; i < BRI_CHANNELS ; i++) {
596                 status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0,
597                         ceReqCallGetMyNumber, i+1, 0, NULL, &rcvmsg, SAR_TIMEOUT);
598                 if (!status)
599                         strcpy(bi->status.bristats[i].dn, rcvmsg.msg_data.byte_array);
600         }
601                 
602         return 0;
603 }