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