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 29PISDN_ADAPTER IoAdapters[MAX_ADAPTER]; 30extern IDI_CALL Requests[MAX_ADAPTER]; 31extern int create_adapter_proc(diva_os_xdi_adapter_t *a); 32extern 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*/ 41DivaIdiReqFunc(0) 42DivaIdiReqFunc(1) 43DivaIdiReqFunc(2) 44DivaIdiReqFunc(3) 45DivaIdiReqFunc(4) 46DivaIdiReqFunc(5) 47DivaIdiReqFunc(6) 48DivaIdiReqFunc(7) 49DivaIdiReqFunc(8) 50DivaIdiReqFunc(9) 51DivaIdiReqFunc(10) 52DivaIdiReqFunc(11) 53DivaIdiReqFunc(12) 54DivaIdiReqFunc(13) 55DivaIdiReqFunc(14) 56DivaIdiReqFunc(15) 57DivaIdiReqFunc(16) 58DivaIdiReqFunc(17) 59DivaIdiReqFunc(18) 60DivaIdiReqFunc(19) 61DivaIdiReqFunc(20) 62DivaIdiReqFunc(21) 63DivaIdiReqFunc(22) 64DivaIdiReqFunc(23) 65DivaIdiReqFunc(24) 66DivaIdiReqFunc(25) 67DivaIdiReqFunc(26) 68DivaIdiReqFunc(27) 69DivaIdiReqFunc(28) 70DivaIdiReqFunc(29) 71DivaIdiReqFunc(30) 72DivaIdiReqFunc(31) 73 74/* 75** LOCALS 76*/ 77static LIST_HEAD(adapter_queue); 78 79typedef struct _diva_get_xlog { 80 word command; 81 byte req; 82 byte rc; 83 byte data[sizeof(struct mi_pc_maint)]; 84} diva_get_xlog_t; 85 86typedef struct _diva_supported_cards_info { 87 int CardOrdinal; 88 diva_init_card_proc_t init_card; 89} diva_supported_cards_info_t; 90 91static diva_supported_cards_info_t divas_supported_cards[] = { 92#ifdef CONFIG_ISDN_DIVAS_PRIPCI 93 /* 94 PRI Cards 95 */ 96 {CARDTYPE_DIVASRV_P_30M_PCI, diva_pri_init_card}, 97 /* 98 PRI Rev.2 Cards 99 */ 100 {CARDTYPE_DIVASRV_P_30M_V2_PCI, diva_pri_init_card}, 101 /* 102 PRI Rev.2 VoIP Cards 103 */ 104 {CARDTYPE_DIVASRV_VOICE_P_30M_V2_PCI, diva_pri_init_card}, 105#endif 106#ifdef CONFIG_ISDN_DIVAS_BRIPCI 107 /* 108 4BRI Rev 1 Cards 109 */ 110 {CARDTYPE_DIVASRV_Q_8M_PCI, diva_4bri_init_card}, 111 {CARDTYPE_DIVASRV_VOICE_Q_8M_PCI, diva_4bri_init_card}, 112 /* 113 4BRI Rev 2 Cards 114 */ 115 {CARDTYPE_DIVASRV_Q_8M_V2_PCI, diva_4bri_init_card}, 116 {CARDTYPE_DIVASRV_VOICE_Q_8M_V2_PCI, diva_4bri_init_card}, 117 /* 118 4BRI Based BRI Rev 2 Cards 119 */ 120 {CARDTYPE_DIVASRV_B_2M_V2_PCI, diva_4bri_init_card}, 121 {CARDTYPE_DIVASRV_B_2F_PCI, diva_4bri_init_card}, 122 {CARDTYPE_DIVASRV_VOICE_B_2M_V2_PCI, diva_4bri_init_card}, 123 /* 124 BRI 125 */ 126 {CARDTYPE_MAESTRA_PCI, diva_bri_init_card}, 127#endif 128 129 /* 130 EOL 131 */ 132 {-1} 133}; 134 135static void diva_init_request_array(void); 136static void *divas_create_pci_card(int handle, void *pci_dev_handle); 137 138static diva_os_spin_lock_t adapter_lock; 139 140static 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 153static diva_os_xdi_adapter_t *diva_q_get_next(struct list_head *what) 154{ 155 diva_os_xdi_adapter_t *a = NULL; 156 157 if (what && (what->next != &adapter_queue)) 158 a = list_entry(what->next, diva_os_xdi_adapter_t, link); 159 160 return (a); 161} 162 163/* -------------------------------------------------------------------------- 164 Add card to the card list 165 -------------------------------------------------------------------------- */ 166void *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) { 178 case CARDTYPE_DIVASRV_Q_8M_PCI: 179 case CARDTYPE_DIVASRV_VOICE_Q_8M_PCI: 180 case CARDTYPE_DIVASRV_Q_8M_V2_PCI: 181 case CARDTYPE_DIVASRV_VOICE_Q_8M_V2_PCI: 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", 202 CardProperties 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")) 236 diva_driver_remove_card(pdiva); 237 238 return NULL; 239 } 240 } 241 242 return NULL; 243} 244 245/* -------------------------------------------------------------------------- 246 Called on driver load, MAIN, main, DriverEntry 247 -------------------------------------------------------------------------- */ 248int divasa_xdi_driver_entry(void) 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 -------------------------------------------------------------------------- */ 260static diva_os_xdi_adapter_t *get_and_remove_from_queue(void) 261{ 262 diva_os_spin_lock_magic_t old_irql; 263 diva_os_xdi_adapter_t *a = NULL; 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 -------------------------------------------------------------------------- */ 279void diva_driver_remove_card(void *pdiva) 280{ 281 diva_os_spin_lock_magic_t old_irql; 282 diva_os_xdi_adapter_t *a[4]; 283 diva_os_xdi_adapter_t *pa; 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)) 293 && !pa->interface.cleanup_adapter_proc) { 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 -------------------------------------------------------------------------- */ 323static 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; 327 diva_os_xdi_adapter_t *a; 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 -------------------------------------------------------------------------- */ 369void divasa_xdi_driver_unload(void) 370{ 371 diva_os_xdi_adapter_t *a; 372 373 while ((a = get_and_remove_from_queue())) { 374 if (a->interface.cleanup_adapter_proc) { 375 (*(a->interface.cleanup_adapter_proc)) (a); 376 } 377 if (a->controller) { 378 IoAdapters[a->controller - 1] = NULL; 379 remove_adapter_proc(a); 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*/ 389void *diva_xdi_open_adapter(void *os_handle, const void __user *src, 390 int length, 391 divas_xdi_copy_from_user_fn_t cp_fn) 392{ 393 diva_xdi_um_cfg_cmd_t msg; 394 diva_os_xdi_adapter_t *a = NULL; 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) { 409 a = list_entry(tmp, diva_os_xdi_adapter_t, link); 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*/ 426void diva_xdi_close_adapter(void *adapter, void *os_handle) 427{ 428 diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) adapter; 429 430 a->xdi_mbox.status &= ~DIVA_XDI_MBOX_BUSY; 431 if (a->xdi_mbox.data) { 432 diva_os_free(0, a->xdi_mbox.data); 433 a->xdi_mbox.data = NULL; 434 } 435} 436 437int 438diva_xdi_write(void *adapter, void *os_handle, const void __user *src, 439 int length, divas_xdi_copy_from_user_fn_t cp_fn) 440{ 441 diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) adapter; 442 void *data; 443 444 if (a->xdi_mbox.status & DIVA_XDI_MBOX_BUSY) { 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*/ 480int 481diva_xdi_read(void *adapter, void *os_handle, void __user *dst, 482 int max_length, divas_xdi_copy_to_user_fn_t cp_fn) 483{ 484 diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) adapter; 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) { 492 a->xdi_mbox.status &= ~DIVA_XDI_MBOX_BUSY; 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; 509 a->xdi_mbox.status &= ~DIVA_XDI_MBOX_BUSY; 510 } 511 512 return (ret); 513} 514 515 516irqreturn_t diva_os_irq_wrapper(int irq, void *context) 517{ 518 diva_os_xdi_adapter_t *a = context; 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); 526 a->clear_interrupts_proc = NULL; 527 return IRQ_HANDLED; 528 } 529 530 (*(a->xdi_adapter.diva_isr_handler)) (&a->xdi_adapter); 531 return IRQ_HANDLED; 532} 533 534static 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 570void diva_xdi_display_adapter_features(int card) 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 606void diva_add_slave_adapter(diva_os_xdi_adapter_t *a) 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 615int diva_card_read_xlog(diva_os_xdi_adapter_t *a) 616{ 617 diva_get_xlog_t *req; 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; 650 a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY; 651 652 return (0); 653} 654 655void xdiFreeFile(void *handle) 656{ 657} 658