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