Merge branch 'upstream-linus' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik...
[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                 kfree(rcvmsg);
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, data->dataptr, SCIOC_SRECSIZE)) {
76                         kfree(rcvmsg);
77                         kfree(srec);
78                         return -EFAULT;
79                 }
80
81                 status = send_and_receive(card, CMPID, cmReqType2, cmReqClass0, cmReqLoadProc,
82                                 0, SCIOC_SRECSIZE, 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                 kfree(rcvmsg);
101                 pr_debug("%s: SCIOSTART: ioctl received\n",
102                                 sc_adapter[card]->devicename);
103                 if(sc_adapter[card]->EngineUp) {
104                         pr_debug("%s: SCIOCSTART: command failed, engine already running.\n",
105                                 sc_adapter[card]->devicename);
106                         return -1;
107                 }
108
109                 sc_adapter[card]->StartOnReset = 1;
110                 startproc(card);
111                 return 0;
112         }
113
114         case SCIOCSETSWITCH:
115         {
116                 pr_debug("%s: SCIOSETSWITCH: ioctl received\n",
117                                 sc_adapter[card]->devicename);
118
119                 /*
120                  * Get the switch type from user space
121                  */
122                 if (copy_from_user(&switchtype, data->dataptr, 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, NULL, 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(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, NULL, rcvmsg, SAR_TIMEOUT);
197                 if (!status) {
198                         pr_debug("%s: SCIOCGETSPID: command successful\n",
199                                         sc_adapter[card]->devicename);
200                 } else {
201                         pr_debug("%s: SCIOCGETSPID: command failed (status = %d)\n",
202                                 sc_adapter[card]->devicename, status);
203                         kfree(spid);
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(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, 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, NULL, 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(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, 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(data->dataptr, bi, sizeof(boardInfo))) {
370                         kfree(bi);
371                         return -EFAULT;
372                 }
373
374                 kfree(bi);
375                 return 0;
376         }
377
378         case SCIOCGETSPEED:
379         {
380                 pr_debug("%s: SCIOGETSPEED: ioctl received\n",
381                                 sc_adapter[card]->devicename);
382
383                 /*
384                  * Get the speed from the board
385                  */
386                 status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0, 
387                         ceReqCallGetCallType, data->channel, 0, NULL, rcvmsg, SAR_TIMEOUT);
388                 if (!status && !(rcvmsg->rsp_status)) {
389                         pr_debug("%s: SCIOCGETSPEED: command successful\n",
390                                 sc_adapter[card]->devicename);
391                 }
392                 else {
393                         pr_debug("%s: SCIOCGETSPEED: command failed (status = %d)\n",
394                                 sc_adapter[card]->devicename, status);
395                         kfree(rcvmsg);
396                         return status;
397                 }
398
399                 speed = rcvmsg->msg_data.byte_array[0];
400
401                 kfree(rcvmsg);
402
403                 /*
404                  * Package the switch type and send to user space
405                  */
406
407                 if (copy_to_user(data->dataptr, &speed, sizeof(char)))
408                         return -EFAULT;
409
410                 return 0;
411         }
412
413         case SCIOCSETSPEED:
414                 pr_debug("%s: SCIOCSETSPEED: ioctl received\n",
415                                 sc_adapter[card]->devicename);
416                 break;
417
418         case SCIOCLOOPTST:
419                 pr_debug("%s: SCIOCLOOPTST: ioctl received\n",
420                                 sc_adapter[card]->devicename);
421                 break;
422
423         default:
424                 kfree(rcvmsg);
425                 return -1;
426         }
427
428         kfree(rcvmsg);
429         return 0;
430 }
431
432 static int GetStatus(int card, boardInfo *bi)
433 {
434         RspMessage rcvmsg;
435         int i, status;
436
437         /*
438          * Fill in some of the basic info about the board
439          */
440         bi->modelid = sc_adapter[card]->model;
441         strcpy(bi->serial_no, sc_adapter[card]->hwconfig.serial_no);
442         strcpy(bi->part_no, sc_adapter[card]->hwconfig.part_no);
443         bi->iobase = sc_adapter[card]->iobase;
444         bi->rambase = sc_adapter[card]->rambase;
445         bi->irq = sc_adapter[card]->interrupt;
446         bi->ramsize = sc_adapter[card]->hwconfig.ram_size;
447         bi->interface = sc_adapter[card]->hwconfig.st_u_sense;
448         strcpy(bi->load_ver, sc_adapter[card]->load_ver);
449         strcpy(bi->proc_ver, sc_adapter[card]->proc_ver);
450
451         /*
452          * Get the current PhyStats and LnkStats
453          */
454         status = send_and_receive(card, CEPID, ceReqTypePhy, ceReqClass2,
455                 ceReqPhyStatus, 0, 0, NULL, &rcvmsg, SAR_TIMEOUT);
456         if(!status) {
457                 if(sc_adapter[card]->model < PRI_BOARD) {
458                         bi->l1_status = rcvmsg.msg_data.byte_array[2];
459                         for(i = 0 ; i < BRI_CHANNELS ; i++)
460                                 bi->status.bristats[i].phy_stat =
461                                         rcvmsg.msg_data.byte_array[i];
462                 }
463                 else {
464                         bi->l1_status = rcvmsg.msg_data.byte_array[0];
465                         bi->l2_status = rcvmsg.msg_data.byte_array[1];
466                         for(i = 0 ; i < PRI_CHANNELS ; i++)
467                                 bi->status.pristats[i].phy_stat = 
468                                         rcvmsg.msg_data.byte_array[i+2];
469                 }
470         }
471         
472         /*
473          * Get the call types for each channel
474          */
475         for (i = 0 ; i < sc_adapter[card]->nChannels ; i++) {
476                 status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0,
477                         ceReqCallGetCallType, 0, 0, NULL, &rcvmsg, SAR_TIMEOUT);
478                 if(!status) {
479                         if (sc_adapter[card]->model == PRI_BOARD) {
480                                 bi->status.pristats[i].call_type = 
481                                         rcvmsg.msg_data.byte_array[0];
482                         }
483                         else {
484                                 bi->status.bristats[i].call_type =
485                                         rcvmsg.msg_data.byte_array[0];
486                         }
487                 }
488         }
489         
490         /*
491          * If PRI, get the call states and service states for each channel
492          */
493         if (sc_adapter[card]->model == PRI_BOARD) {
494                 /*
495                  * Get the call states
496                  */
497                 status = send_and_receive(card, CEPID, ceReqTypeStat, ceReqClass2,
498                         ceReqPhyChCallState, 0, 0, NULL, &rcvmsg, SAR_TIMEOUT);
499                 if(!status) {
500                         for( i = 0 ; i < PRI_CHANNELS ; i++ )
501                                 bi->status.pristats[i].call_state = 
502                                         rcvmsg.msg_data.byte_array[i];
503                 }
504
505                 /*
506                  * Get the service states
507                  */
508                 status = send_and_receive(card, CEPID, ceReqTypeStat, ceReqClass2,
509                         ceReqPhyChServState, 0, 0, NULL, &rcvmsg, SAR_TIMEOUT);
510                 if(!status) {
511                         for( i = 0 ; i < PRI_CHANNELS ; i++ )
512                                 bi->status.pristats[i].serv_state = 
513                                         rcvmsg.msg_data.byte_array[i];
514                 }
515
516                 /*
517                  * Get the link stats for the channels
518                  */
519                 for (i = 1 ; i <= PRI_CHANNELS ; i++) {
520                         status = send_and_receive(card, CEPID, ceReqTypeLnk, ceReqClass0,
521                                 ceReqLnkGetStats, i, 0, NULL, &rcvmsg, SAR_TIMEOUT);
522                         if (!status) {
523                                 bi->status.pristats[i-1].link_stats.tx_good =
524                                         (unsigned long)rcvmsg.msg_data.byte_array[0];
525                                 bi->status.pristats[i-1].link_stats.tx_bad =
526                                         (unsigned long)rcvmsg.msg_data.byte_array[4];
527                                 bi->status.pristats[i-1].link_stats.rx_good =
528                                         (unsigned long)rcvmsg.msg_data.byte_array[8];
529                                 bi->status.pristats[i-1].link_stats.rx_bad =
530                                         (unsigned long)rcvmsg.msg_data.byte_array[12];
531                         }
532                 }
533
534                 /*
535                  * Link stats for the D channel
536                  */
537                 status = send_and_receive(card, CEPID, ceReqTypeLnk, ceReqClass0,
538                         ceReqLnkGetStats, 0, 0, NULL, &rcvmsg, SAR_TIMEOUT);
539                 if (!status) {
540                         bi->dch_stats.tx_good = (unsigned long)rcvmsg.msg_data.byte_array[0];
541                         bi->dch_stats.tx_bad = (unsigned long)rcvmsg.msg_data.byte_array[4];
542                         bi->dch_stats.rx_good = (unsigned long)rcvmsg.msg_data.byte_array[8];
543                         bi->dch_stats.rx_bad = (unsigned long)rcvmsg.msg_data.byte_array[12];
544                 }
545
546                 return 0;
547         }
548
549         /*
550          * If BRI or POTS, Get SPID, DN and call types for each channel
551          */
552
553         /*
554          * Get the link stats for the channels
555          */
556         status = send_and_receive(card, CEPID, ceReqTypeLnk, ceReqClass0,
557                 ceReqLnkGetStats, 0, 0, NULL, &rcvmsg, SAR_TIMEOUT);
558         if (!status) {
559                 bi->dch_stats.tx_good = (unsigned long)rcvmsg.msg_data.byte_array[0];
560                 bi->dch_stats.tx_bad = (unsigned long)rcvmsg.msg_data.byte_array[4];
561                 bi->dch_stats.rx_good = (unsigned long)rcvmsg.msg_data.byte_array[8];
562                 bi->dch_stats.rx_bad = (unsigned long)rcvmsg.msg_data.byte_array[12];
563                 bi->status.bristats[0].link_stats.tx_good = 
564                         (unsigned long)rcvmsg.msg_data.byte_array[16];
565                 bi->status.bristats[0].link_stats.tx_bad = 
566                         (unsigned long)rcvmsg.msg_data.byte_array[20];
567                 bi->status.bristats[0].link_stats.rx_good = 
568                         (unsigned long)rcvmsg.msg_data.byte_array[24];
569                 bi->status.bristats[0].link_stats.rx_bad = 
570                         (unsigned long)rcvmsg.msg_data.byte_array[28];
571                 bi->status.bristats[1].link_stats.tx_good = 
572                         (unsigned long)rcvmsg.msg_data.byte_array[32];
573                 bi->status.bristats[1].link_stats.tx_bad = 
574                         (unsigned long)rcvmsg.msg_data.byte_array[36];
575                 bi->status.bristats[1].link_stats.rx_good = 
576                         (unsigned long)rcvmsg.msg_data.byte_array[40];
577                 bi->status.bristats[1].link_stats.rx_bad = 
578                         (unsigned long)rcvmsg.msg_data.byte_array[44];
579         }
580
581         /*
582          * Get the SPIDs
583          */
584         for (i = 0 ; i < BRI_CHANNELS ; i++) {
585                 status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0,
586                         ceReqCallGetSPID, i+1, 0, NULL, &rcvmsg, SAR_TIMEOUT);
587                 if (!status)
588                         strcpy(bi->status.bristats[i].spid, rcvmsg.msg_data.byte_array);
589         }
590                 
591         /*
592          * Get the DNs
593          */
594         for (i = 0 ; i < BRI_CHANNELS ; i++) {
595                 status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0,
596                         ceReqCallGetMyNumber, i+1, 0, NULL, &rcvmsg, SAR_TIMEOUT);
597                 if (!status)
598                         strcpy(bi->status.bristats[i].dn, rcvmsg.msg_data.byte_array);
599         }
600                 
601         return 0;
602 }