Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
diva.c
Go to the documentation of this file.
1 /* $Id: diva.c,v 1.21.4.1 2004/05/08 14:33:43 armin Exp $ */
2 
3 #define CARDTYPE_H_WANT_DATA 1
4 #define CARDTYPE_H_WANT_IDI_DATA 0
5 #define CARDTYPE_H_WANT_RESOURCE_DATA 0
6 #define CARDTYPE_H_WANT_FILE_DATA 0
7 
8 #include "platform.h"
9 #include "debuglib.h"
10 #include "cardtype.h"
11 #include "pc.h"
12 #include "di_defs.h"
13 #include "di.h"
14 #include "io.h"
15 #include "pc_maint.h"
16 #include "xdi_msg.h"
17 #include "xdi_adapter.h"
18 #include "diva_pci.h"
19 #include "diva.h"
20 
21 #ifdef CONFIG_ISDN_DIVAS_PRIPCI
22 #include "os_pri.h"
23 #endif
24 #ifdef CONFIG_ISDN_DIVAS_BRIPCI
25 #include "os_bri.h"
26 #include "os_4bri.h"
27 #endif
28 
33 
34 #define DivaIdiReqFunc(N) \
35  static void DivaIdiRequest##N(ENTITY *e) \
36  { if (IoAdapters[N]) (*IoAdapters[N]->DIRequest)(IoAdapters[N], e); }
37 
38 /*
39 ** Create own 32 Adapters
40 */
73 
74 /*
75 ** LOCALS
76 */
77 static LIST_HEAD(adapter_queue);
78 
79 typedef struct _diva_get_xlog {
80  word command;
81  byte req;
82  byte rc;
83  byte data[sizeof(struct mi_pc_maint)];
85 
90 
91 static diva_supported_cards_info_t divas_supported_cards[] = {
92 #ifdef CONFIG_ISDN_DIVAS_PRIPCI
93  /*
94  PRI Cards
95  */
97  /*
98  PRI Rev.2 Cards
99  */
101  /*
102  PRI Rev.2 VoIP Cards
103  */
105 #endif
106 #ifdef CONFIG_ISDN_DIVAS_BRIPCI
107  /*
108  4BRI Rev 1 Cards
109  */
112  /*
113  4BRI Rev 2 Cards
114  */
117  /*
118  4BRI Based BRI Rev 2 Cards
119  */
123  /*
124  BRI
125  */
127 #endif
128 
129  /*
130  EOL
131  */
132  {-1}
133 };
134 
135 static void diva_init_request_array(void);
136 static void *divas_create_pci_card(int handle, void *pci_dev_handle);
137 
138 static diva_os_spin_lock_t adapter_lock;
139 
140 static int diva_find_free_adapters(int base, int nr)
141 {
142  int i;
143 
144  for (i = 0; i < nr; i++) {
145  if (IoAdapters[base + i]) {
146  return (-1);
147  }
148  }
149 
150  return (0);
151 }
152 
153 static diva_os_xdi_adapter_t *diva_q_get_next(struct list_head *what)
154 {
156 
157  if (what && (what->next != &adapter_queue))
159 
160  return (a);
161 }
162 
163 /* --------------------------------------------------------------------------
164  Add card to the card list
165  -------------------------------------------------------------------------- */
166 void *diva_driver_add_card(void *pdev, unsigned long CardOrdinal)
167 {
168  diva_os_spin_lock_magic_t old_irql;
169  diva_os_xdi_adapter_t *pdiva, *pa;
170  int i, j, max, nr;
171 
172  for (i = 0; divas_supported_cards[i].CardOrdinal != -1; i++) {
173  if (divas_supported_cards[i].CardOrdinal == CardOrdinal) {
174  if (!(pdiva = divas_create_pci_card(i, pdev))) {
175  return NULL;
176  }
177  switch (CardOrdinal) {
182  max = MAX_ADAPTER - 4;
183  nr = 4;
184  break;
185 
186  default:
187  max = MAX_ADAPTER;
188  nr = 1;
189  }
190 
191  diva_os_enter_spin_lock(&adapter_lock, &old_irql, "add card");
192 
193  for (i = 0; i < max; i++) {
194  if (!diva_find_free_adapters(i, nr)) {
195  pdiva->controller = i + 1;
196  pdiva->xdi_adapter.ANum = pdiva->controller;
197  IoAdapters[i] = &pdiva->xdi_adapter;
198  diva_os_leave_spin_lock(&adapter_lock, &old_irql, "add card");
199  create_adapter_proc(pdiva); /* add adapter to proc file system */
200 
201  DBG_LOG(("add %s:%d",
203  [CardOrdinal].Name,
204  pdiva->controller))
205 
206  diva_os_enter_spin_lock(&adapter_lock, &old_irql, "add card");
207  pa = pdiva;
208  for (j = 1; j < nr; j++) { /* slave adapters, if any */
209  pa = diva_q_get_next(&pa->link);
210  if (pa && !pa->interface.cleanup_adapter_proc) {
211  pa->controller = i + 1 + j;
212  pa->xdi_adapter.ANum = pa->controller;
213  IoAdapters[i + j] = &pa->xdi_adapter;
214  diva_os_leave_spin_lock(&adapter_lock, &old_irql, "add card");
215  DBG_LOG(("add slave adapter (%d)",
216  pa->controller))
217  create_adapter_proc(pa); /* add adapter to proc file system */
218  diva_os_enter_spin_lock(&adapter_lock, &old_irql, "add card");
219  } else {
220  DBG_ERR(("slave adapter problem"))
221  break;
222  }
223  }
224 
225  diva_os_leave_spin_lock(&adapter_lock, &old_irql, "add card");
226  return (pdiva);
227  }
228  }
229 
230  diva_os_leave_spin_lock(&adapter_lock, &old_irql, "add card");
231 
232  /*
233  Not able to add adapter - remove it and return error
234  */
235  DBG_ERR(("can not alloc request array"))
237 
238  return NULL;
239  }
240  }
241 
242  return NULL;
243 }
244 
245 /* --------------------------------------------------------------------------
246  Called on driver load, MAIN, main, DriverEntry
247  -------------------------------------------------------------------------- */
249 {
250  diva_os_initialize_spin_lock(&adapter_lock, "adapter");
251  memset(&IoAdapters[0], 0x00, sizeof(IoAdapters));
252  diva_init_request_array();
253 
254  return (0);
255 }
256 
257 /* --------------------------------------------------------------------------
258  Remove adapter from list
259  -------------------------------------------------------------------------- */
260 static diva_os_xdi_adapter_t *get_and_remove_from_queue(void)
261 {
262  diva_os_spin_lock_magic_t old_irql;
264 
265  diva_os_enter_spin_lock(&adapter_lock, &old_irql, "driver_unload");
266 
267  if (!list_empty(&adapter_queue)) {
268  a = list_entry(adapter_queue.next, diva_os_xdi_adapter_t, link);
269  list_del(adapter_queue.next);
270  }
271 
272  diva_os_leave_spin_lock(&adapter_lock, &old_irql, "driver_unload");
273  return (a);
274 }
275 
276 /* --------------------------------------------------------------------------
277  Remove card from the card list
278  -------------------------------------------------------------------------- */
279 void diva_driver_remove_card(void *pdiva)
280 {
281  diva_os_spin_lock_magic_t old_irql;
282  diva_os_xdi_adapter_t *a[4];
284  int i;
285 
286  pa = a[0] = (diva_os_xdi_adapter_t *) pdiva;
287  a[1] = a[2] = a[3] = NULL;
288 
289  diva_os_enter_spin_lock(&adapter_lock, &old_irql, "remode adapter");
290 
291  for (i = 1; i < 4; i++) {
292  if ((pa = diva_q_get_next(&pa->link))
294  a[i] = pa;
295  } else {
296  break;
297  }
298  }
299 
300  for (i = 0; ((i < 4) && a[i]); i++) {
301  list_del(&a[i]->link);
302  }
303 
304  diva_os_leave_spin_lock(&adapter_lock, &old_irql, "driver_unload");
305 
306  (*(a[0]->interface.cleanup_adapter_proc)) (a[0]);
307 
308  for (i = 0; i < 4; i++) {
309  if (a[i]) {
310  if (a[i]->controller) {
311  DBG_LOG(("remove adapter (%d)",
312  a[i]->controller)) IoAdapters[a[i]->controller - 1] = NULL;
313  remove_adapter_proc(a[i]);
314  }
315  diva_os_free(0, a[i]);
316  }
317  }
318 }
319 
320 /* --------------------------------------------------------------------------
321  Create diva PCI adapter and init internal adapter structures
322  -------------------------------------------------------------------------- */
323 static void *divas_create_pci_card(int handle, void *pci_dev_handle)
324 {
325  diva_supported_cards_info_t *pI = &divas_supported_cards[handle];
326  diva_os_spin_lock_magic_t old_irql;
328 
329  DBG_LOG(("found %d-%s", pI->CardOrdinal, CardProperties[pI->CardOrdinal].Name))
330 
331  if (!(a = (diva_os_xdi_adapter_t *) diva_os_malloc(0, sizeof(*a)))) {
332  DBG_ERR(("A: can't alloc adapter"));
333  return NULL;
334  }
335 
336  memset(a, 0x00, sizeof(*a));
337 
338  a->CardIndex = handle;
339  a->CardOrdinal = pI->CardOrdinal;
340  a->Bus = DIVAS_XDI_ADAPTER_BUS_PCI;
341  a->xdi_adapter.cardType = a->CardOrdinal;
342  a->resources.pci.bus = diva_os_get_pci_bus(pci_dev_handle);
343  a->resources.pci.func = diva_os_get_pci_func(pci_dev_handle);
344  a->resources.pci.hdev = pci_dev_handle;
345 
346  /*
347  Add master adapter first, so slave adapters will receive higher
348  numbers as master adapter
349  */
350  diva_os_enter_spin_lock(&adapter_lock, &old_irql, "found_pci_card");
351  list_add_tail(&a->link, &adapter_queue);
352  diva_os_leave_spin_lock(&adapter_lock, &old_irql, "found_pci_card");
353 
354  if ((*(pI->init_card)) (a)) {
355  diva_os_enter_spin_lock(&adapter_lock, &old_irql, "found_pci_card");
356  list_del(&a->link);
357  diva_os_leave_spin_lock(&adapter_lock, &old_irql, "found_pci_card");
358  diva_os_free(0, a);
359  DBG_ERR(("A: can't get adapter resources"));
360  return NULL;
361  }
362 
363  return (a);
364 }
365 
366 /* --------------------------------------------------------------------------
367  Called on driver unload FINIT, finit, Unload
368  -------------------------------------------------------------------------- */
370 {
372 
373  while ((a = get_and_remove_from_queue())) {
375  (*(a->interface.cleanup_adapter_proc)) (a);
376  }
377  if (a->controller) {
378  IoAdapters[a->controller - 1] = NULL;
380  }
381  diva_os_free(0, a);
382  }
383  diva_os_destroy_spin_lock(&adapter_lock, "adapter");
384 }
385 
386 /*
387 ** Receive and process command from user mode utility
388 */
389 void *diva_xdi_open_adapter(void *os_handle, const void __user *src,
390  int length,
392 {
395  diva_os_spin_lock_magic_t old_irql;
396  struct list_head *tmp;
397 
398  if (length < sizeof(diva_xdi_um_cfg_cmd_t)) {
399  DBG_ERR(("A: A(?) open, msg too small (%d < %d)",
400  length, sizeof(diva_xdi_um_cfg_cmd_t)))
401  return NULL;
402  }
403  if ((*cp_fn) (os_handle, &msg, src, sizeof(msg)) <= 0) {
404  DBG_ERR(("A: A(?) open, write error"))
405  return NULL;
406  }
407  diva_os_enter_spin_lock(&adapter_lock, &old_irql, "open_adapter");
408  list_for_each(tmp, &adapter_queue) {
410  if (a->controller == (int)msg.adapter)
411  break;
412  a = NULL;
413  }
414  diva_os_leave_spin_lock(&adapter_lock, &old_irql, "open_adapter");
415 
416  if (!a) {
417  DBG_ERR(("A: A(%d) open, adapter not found", msg.adapter))
418  }
419 
420  return (a);
421 }
422 
423 /*
424 ** Easy cleanup mailbox status
425 */
426 void diva_xdi_close_adapter(void *adapter, void *os_handle)
427 {
429 
431  if (a->xdi_mbox.data) {
432  diva_os_free(0, a->xdi_mbox.data);
433  a->xdi_mbox.data = NULL;
434  }
435 }
436 
437 int
438 diva_xdi_write(void *adapter, void *os_handle, const void __user *src,
440 {
442  void *data;
443 
445  DBG_ERR(("A: A(%d) write, mbox busy", a->controller))
446  return (-1);
447  }
448 
449  if (length < sizeof(diva_xdi_um_cfg_cmd_t)) {
450  DBG_ERR(("A: A(%d) write, message too small (%d < %d)",
451  a->controller, length,
452  sizeof(diva_xdi_um_cfg_cmd_t)))
453  return (-3);
454  }
455 
456  if (!(data = diva_os_malloc(0, length))) {
457  DBG_ERR(("A: A(%d) write, ENOMEM", a->controller))
458  return (-2);
459  }
460 
461  length = (*cp_fn) (os_handle, data, src, length);
462  if (length > 0) {
463  if ((*(a->interface.cmd_proc))
464  (a, (diva_xdi_um_cfg_cmd_t *) data, length)) {
465  length = -3;
466  }
467  } else {
468  DBG_ERR(("A: A(%d) write error (%d)", a->controller,
469  length))
470  }
471 
472  diva_os_free(0, data);
473 
474  return (length);
475 }
476 
477 /*
478 ** Write answers to user mode utility, if any
479 */
480 int
481 diva_xdi_read(void *adapter, void *os_handle, void __user *dst,
482  int max_length, divas_xdi_copy_to_user_fn_t cp_fn)
483 {
485  int ret;
486 
487  if (!(a->xdi_mbox.status & DIVA_XDI_MBOX_BUSY)) {
488  DBG_ERR(("A: A(%d) rx mbox empty", a->controller))
489  return (-1);
490  }
491  if (!a->xdi_mbox.data) {
493  DBG_ERR(("A: A(%d) rx ENOMEM", a->controller))
494  return (-2);
495  }
496 
497  if (max_length < a->xdi_mbox.data_length) {
498  DBG_ERR(("A: A(%d) rx buffer too short(%d < %d)",
499  a->controller, max_length,
500  a->xdi_mbox.data_length))
501  return (-3);
502  }
503 
504  ret = (*cp_fn) (os_handle, dst, a->xdi_mbox.data,
505  a->xdi_mbox.data_length);
506  if (ret > 0) {
507  diva_os_free(0, a->xdi_mbox.data);
508  a->xdi_mbox.data = NULL;
510  }
511 
512  return (ret);
513 }
514 
515 
517 {
519  diva_xdi_clear_interrupts_proc_t clear_int_proc;
520 
521  if (!a || !a->xdi_adapter.diva_isr_handler)
522  return IRQ_NONE;
523 
524  if ((clear_int_proc = a->clear_interrupts_proc)) {
525  (*clear_int_proc) (a);
527  return IRQ_HANDLED;
528  }
529 
531  return IRQ_HANDLED;
532 }
533 
534 static void diva_init_request_array(void)
535 {
536  Requests[0] = DivaIdiRequest0;
537  Requests[1] = DivaIdiRequest1;
538  Requests[2] = DivaIdiRequest2;
539  Requests[3] = DivaIdiRequest3;
540  Requests[4] = DivaIdiRequest4;
541  Requests[5] = DivaIdiRequest5;
542  Requests[6] = DivaIdiRequest6;
543  Requests[7] = DivaIdiRequest7;
544  Requests[8] = DivaIdiRequest8;
545  Requests[9] = DivaIdiRequest9;
546  Requests[10] = DivaIdiRequest10;
547  Requests[11] = DivaIdiRequest11;
548  Requests[12] = DivaIdiRequest12;
549  Requests[13] = DivaIdiRequest13;
550  Requests[14] = DivaIdiRequest14;
551  Requests[15] = DivaIdiRequest15;
552  Requests[16] = DivaIdiRequest16;
553  Requests[17] = DivaIdiRequest17;
554  Requests[18] = DivaIdiRequest18;
555  Requests[19] = DivaIdiRequest19;
556  Requests[20] = DivaIdiRequest20;
557  Requests[21] = DivaIdiRequest21;
558  Requests[22] = DivaIdiRequest22;
559  Requests[23] = DivaIdiRequest23;
560  Requests[24] = DivaIdiRequest24;
561  Requests[25] = DivaIdiRequest25;
562  Requests[26] = DivaIdiRequest26;
563  Requests[27] = DivaIdiRequest27;
564  Requests[28] = DivaIdiRequest28;
565  Requests[29] = DivaIdiRequest29;
566  Requests[30] = DivaIdiRequest30;
567  Requests[31] = DivaIdiRequest31;
568 }
569 
571 {
572  dword features;
573  if (!card || ((card - 1) >= MAX_ADAPTER) || !IoAdapters[card - 1]) {
574  return;
575  }
576  card--;
577  features = IoAdapters[card]->Properties.Features;
578 
579  DBG_LOG(("FEATURES FOR ADAPTER: %d", card + 1))
580  DBG_LOG((" DI_FAX3 : %s",
581  (features & DI_FAX3) ? "Y" : "N"))
582  DBG_LOG((" DI_MODEM : %s",
583  (features & DI_MODEM) ? "Y" : "N"))
584  DBG_LOG((" DI_POST : %s",
585  (features & DI_POST) ? "Y" : "N"))
586  DBG_LOG((" DI_V110 : %s",
587  (features & DI_V110) ? "Y" : "N"))
588  DBG_LOG((" DI_V120 : %s",
589  (features & DI_V120) ? "Y" : "N"))
590  DBG_LOG((" DI_POTS : %s",
591  (features & DI_POTS) ? "Y" : "N"))
592  DBG_LOG((" DI_CODEC : %s",
593  (features & DI_CODEC) ? "Y" : "N"))
594  DBG_LOG((" DI_MANAGE : %s",
595  (features & DI_MANAGE) ? "Y" : "N"))
596  DBG_LOG((" DI_V_42 : %s",
597  (features & DI_V_42) ? "Y" : "N"))
598  DBG_LOG((" DI_EXTD_FAX : %s",
599  (features & DI_EXTD_FAX) ? "Y" : "N"))
600  DBG_LOG((" DI_AT_PARSER : %s",
601  (features & DI_AT_PARSER) ? "Y" : "N"))
602  DBG_LOG((" DI_VOICE_OVER_IP : %s",
603  (features & DI_VOICE_OVER_IP) ? "Y" : "N"))
604  }
605 
607 {
608  diva_os_spin_lock_magic_t old_irql;
609 
610  diva_os_enter_spin_lock(&adapter_lock, &old_irql, "add_slave");
611  list_add_tail(&a->link, &adapter_queue);
612  diva_os_leave_spin_lock(&adapter_lock, &old_irql, "add_slave");
613 }
614 
616 {
618  byte *data;
619 
620  if (!a->xdi_adapter.Initialized || !a->xdi_adapter.DIRequest) {
621  return (-1);
622  }
623  if (!(data = diva_os_malloc(0, sizeof(struct mi_pc_maint)))) {
624  return (-1);
625  }
626  memset(data, 0x00, sizeof(struct mi_pc_maint));
627 
628  if (!(req = diva_os_malloc(0, sizeof(*req)))) {
629  diva_os_free(0, data);
630  return (-1);
631  }
632  req->command = 0x0400;
633  req->req = LOG;
634  req->rc = 0x00;
635 
636  (*(a->xdi_adapter.DIRequest)) (&a->xdi_adapter, (ENTITY *) req);
637 
638  if (!req->rc || req->req) {
639  diva_os_free(0, data);
640  diva_os_free(0, req);
641  return (-1);
642  }
643 
644  memcpy(data, &req->req, sizeof(struct mi_pc_maint));
645 
646  diva_os_free(0, req);
647 
648  a->xdi_mbox.data_length = sizeof(struct mi_pc_maint);
649  a->xdi_mbox.data = data;
651 
652  return (0);
653 }
654 
655 void xdiFreeFile(void *handle)
656 {
657 }