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