|  | /* $Id: capifunc.c,v 1.61.4.7 2005/02/11 19:40:25 armin Exp $ | 
|  | * | 
|  | * ISDN interface module for Eicon active cards DIVA. | 
|  | * CAPI Interface common functions | 
|  | * | 
|  | * Copyright 2000-2003 by Armin Schindler (mac@melware.de) | 
|  | * Copyright 2000-2003 Cytronics & Melware (info@melware.de) | 
|  | * | 
|  | * This software may be used and distributed according to the terms | 
|  | * of the GNU General Public License, incorporated herein by reference. | 
|  | * | 
|  | */ | 
|  |  | 
|  | #include "platform.h" | 
|  | #include "os_capi.h" | 
|  | #include "di_defs.h" | 
|  | #include "capi20.h" | 
|  | #include "divacapi.h" | 
|  | #include "divasync.h" | 
|  | #include "capifunc.h" | 
|  |  | 
|  | #define DBG_MINIMUM  (DL_LOG + DL_FTL + DL_ERR) | 
|  | #define DBG_DEFAULT  (DBG_MINIMUM + DL_XLOG + DL_REG) | 
|  |  | 
|  | DIVA_CAPI_ADAPTER *adapter = (DIVA_CAPI_ADAPTER *) NULL; | 
|  | APPL *application = (APPL *) NULL; | 
|  | byte max_appl = MAX_APPL; | 
|  | byte max_adapter = 0; | 
|  | static CAPI_MSG *mapped_msg = (CAPI_MSG *) NULL; | 
|  |  | 
|  | byte UnMapController(byte); | 
|  | char DRIVERRELEASE_CAPI[32]; | 
|  |  | 
|  | extern void AutomaticLaw(DIVA_CAPI_ADAPTER *); | 
|  | extern void callback(ENTITY *); | 
|  | extern word api_remove_start(void); | 
|  | extern word CapiRelease(word); | 
|  | extern word CapiRegister(word); | 
|  | extern word api_put(APPL *, CAPI_MSG *); | 
|  |  | 
|  | static diva_os_spin_lock_t api_lock; | 
|  |  | 
|  | static LIST_HEAD(cards); | 
|  |  | 
|  | static dword notify_handle; | 
|  | static void DIRequest(ENTITY * e); | 
|  | static DESCRIPTOR MAdapter; | 
|  | static DESCRIPTOR DAdapter; | 
|  | static byte ControllerMap[MAX_DESCRIPTORS + 1]; | 
|  |  | 
|  |  | 
|  | static void diva_register_appl(struct capi_ctr *, __u16, | 
|  | capi_register_params *); | 
|  | static void diva_release_appl(struct capi_ctr *, __u16); | 
|  | static char *diva_procinfo(struct capi_ctr *); | 
|  | static u16 diva_send_message(struct capi_ctr *, | 
|  | diva_os_message_buffer_s *); | 
|  | extern void diva_os_set_controller_struct(struct capi_ctr *); | 
|  |  | 
|  | extern void DIVA_DIDD_Read(DESCRIPTOR *, int); | 
|  |  | 
|  | /* | 
|  | * debug | 
|  | */ | 
|  | static void no_printf(unsigned char *, ...); | 
|  | #include "debuglib.c" | 
|  | static void xlog(char *x, ...) | 
|  | { | 
|  | #ifndef DIVA_NO_DEBUGLIB | 
|  | va_list ap; | 
|  | if (myDriverDebugHandle.dbgMask & DL_XLOG) { | 
|  | va_start(ap, x); | 
|  | if (myDriverDebugHandle.dbg_irq) { | 
|  | myDriverDebugHandle.dbg_irq(myDriverDebugHandle.id, | 
|  | DLI_XLOG, x, ap); | 
|  | } else if (myDriverDebugHandle.dbg_old) { | 
|  | myDriverDebugHandle.dbg_old(myDriverDebugHandle.id, | 
|  | x, ap); | 
|  | } | 
|  | va_end(ap); | 
|  | } | 
|  | #endif | 
|  | } | 
|  |  | 
|  | /* | 
|  | * info for proc | 
|  | */ | 
|  | static char *diva_procinfo(struct capi_ctr *ctrl) | 
|  | { | 
|  | return (ctrl->serial); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * stop debugging | 
|  | */ | 
|  | static void stop_dbg(void) | 
|  | { | 
|  | DbgDeregister(); | 
|  | memset(&MAdapter, 0, sizeof(MAdapter)); | 
|  | dprintf = no_printf; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * dummy debug function | 
|  | */ | 
|  | static void no_printf(unsigned char *x, ...) | 
|  | { | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Controller mapping | 
|  | */ | 
|  | byte MapController(byte Controller) | 
|  | { | 
|  | byte i; | 
|  | byte MappedController = 0; | 
|  | byte ctrl = Controller & 0x7f;	/* mask external controller bit off */ | 
|  |  | 
|  | for (i = 1; i < max_adapter + 1; i++) { | 
|  | if (ctrl == ControllerMap[i]) { | 
|  | MappedController = (byte) i; | 
|  | break; | 
|  | } | 
|  | } | 
|  | if (i > max_adapter) { | 
|  | ControllerMap[0] = ctrl; | 
|  | MappedController = 0; | 
|  | } | 
|  | return (MappedController | (Controller & 0x80));	/* put back external controller bit */ | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Controller unmapping | 
|  | */ | 
|  | byte UnMapController(byte MappedController) | 
|  | { | 
|  | byte Controller; | 
|  | byte ctrl = MappedController & 0x7f;	/* mask external controller bit off */ | 
|  |  | 
|  | if (ctrl <= max_adapter) { | 
|  | Controller = ControllerMap[ctrl]; | 
|  | } else { | 
|  | Controller = 0; | 
|  | } | 
|  |  | 
|  | return (Controller | (MappedController & 0x80));	/* put back external controller bit */ | 
|  | } | 
|  |  | 
|  | /* | 
|  | * find a new free id | 
|  | */ | 
|  | static int find_free_id(void) | 
|  | { | 
|  | int num = 0; | 
|  | DIVA_CAPI_ADAPTER *a; | 
|  |  | 
|  | while (num < MAX_DESCRIPTORS) { | 
|  | a = &adapter[num]; | 
|  | if (!a->Id) | 
|  | break; | 
|  | num++; | 
|  | } | 
|  | return(num + 1); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * find a card structure by controller number | 
|  | */ | 
|  | static diva_card *find_card_by_ctrl(word controller) | 
|  | { | 
|  | struct list_head *tmp; | 
|  | diva_card *card; | 
|  |  | 
|  | list_for_each(tmp, &cards) { | 
|  | card = list_entry(tmp, diva_card, list); | 
|  | if (ControllerMap[card->Id] == controller) { | 
|  | if (card->remove_in_progress) | 
|  | card = NULL; | 
|  | return(card); | 
|  | } | 
|  | } | 
|  | return (diva_card *) 0; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Buffer RX/TX | 
|  | */ | 
|  | void *TransmitBufferSet(APPL * appl, dword ref) | 
|  | { | 
|  | appl->xbuffer_used[ref] = true; | 
|  | DBG_PRV1(("%d:xbuf_used(%d)", appl->Id, ref + 1)) | 
|  | return (void *)(long)ref; | 
|  | } | 
|  |  | 
|  | void *TransmitBufferGet(APPL * appl, void *p) | 
|  | { | 
|  | if (appl->xbuffer_internal[(dword)(long)p]) | 
|  | return appl->xbuffer_internal[(dword)(long)p]; | 
|  |  | 
|  | return appl->xbuffer_ptr[(dword)(long)p]; | 
|  | } | 
|  |  | 
|  | void TransmitBufferFree(APPL * appl, void *p) | 
|  | { | 
|  | appl->xbuffer_used[(dword)(long)p] = false; | 
|  | DBG_PRV1(("%d:xbuf_free(%d)", appl->Id, ((dword)(long)p) + 1)) | 
|  | } | 
|  |  | 
|  | void *ReceiveBufferGet(APPL * appl, int Num) | 
|  | { | 
|  | return &appl->ReceiveBuffer[Num * appl->MaxDataLength]; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * api_remove_start/complete for cleanup | 
|  | */ | 
|  | void api_remove_complete(void) | 
|  | { | 
|  | DBG_PRV1(("api_remove_complete")) | 
|  | } | 
|  |  | 
|  | /* | 
|  | * main function called by message.c | 
|  | */ | 
|  | void sendf(APPL * appl, word command, dword Id, word Number, byte * format, ...) | 
|  | { | 
|  | word i, j; | 
|  | word length = 12, dlength = 0; | 
|  | byte *write; | 
|  | CAPI_MSG msg; | 
|  | byte *string = NULL; | 
|  | va_list ap; | 
|  | diva_os_message_buffer_s *dmb; | 
|  | diva_card *card = NULL; | 
|  | dword tmp; | 
|  |  | 
|  | if (!appl) | 
|  | return; | 
|  |  | 
|  | DBG_PRV1(("sendf(a=%d,cmd=%x,format=%s)", | 
|  | appl->Id, command, (byte *) format)) | 
|  |  | 
|  | PUT_WORD(&msg.header.appl_id, appl->Id); | 
|  | PUT_WORD(&msg.header.command, command); | 
|  | if ((byte) (command >> 8) == 0x82) | 
|  | Number = appl->Number++; | 
|  | PUT_WORD(&msg.header.number, Number); | 
|  |  | 
|  | PUT_DWORD(&msg.header.controller, Id); | 
|  | write = (byte *) & msg; | 
|  | write += 12; | 
|  |  | 
|  | va_start(ap, format); | 
|  | for (i = 0; format[i]; i++) { | 
|  | switch (format[i]) { | 
|  | case 'b': | 
|  | tmp = va_arg(ap, dword); | 
|  | *(byte *) write = (byte) (tmp & 0xff); | 
|  | write += 1; | 
|  | length += 1; | 
|  | break; | 
|  | case 'w': | 
|  | tmp = va_arg(ap, dword); | 
|  | PUT_WORD(write, (tmp & 0xffff)); | 
|  | write += 2; | 
|  | length += 2; | 
|  | break; | 
|  | case 'd': | 
|  | tmp = va_arg(ap, dword); | 
|  | PUT_DWORD(write, tmp); | 
|  | write += 4; | 
|  | length += 4; | 
|  | break; | 
|  | case 's': | 
|  | case 'S': | 
|  | string = va_arg(ap, byte *); | 
|  | length += string[0] + 1; | 
|  | for (j = 0; j <= string[0]; j++) | 
|  | *write++ = string[j]; | 
|  | break; | 
|  | } | 
|  | } | 
|  | va_end(ap); | 
|  |  | 
|  | PUT_WORD(&msg.header.length, length); | 
|  | msg.header.controller = UnMapController(msg.header.controller); | 
|  |  | 
|  | if (command == _DATA_B3_I) | 
|  | dlength = GET_WORD( | 
|  | ((byte *) & msg.info.data_b3_ind.Data_Length)); | 
|  |  | 
|  | if (!(dmb = diva_os_alloc_message_buffer(length + dlength, | 
|  | (void **) &write))) { | 
|  | DBG_ERR(("sendf: alloc_message_buffer failed, incoming msg dropped.")) | 
|  | return; | 
|  | } | 
|  |  | 
|  | /* copy msg header to sk_buff */ | 
|  | memcpy(write, (byte *) & msg, length); | 
|  |  | 
|  | /* if DATA_B3_IND, copy data too */ | 
|  | if (command == _DATA_B3_I) { | 
|  | dword data = GET_DWORD(&msg.info.data_b3_ind.Data); | 
|  | memcpy(write + length, (void *)(long)data, dlength); | 
|  | } | 
|  |  | 
|  | #ifndef DIVA_NO_DEBUGLIB | 
|  | if (myDriverDebugHandle.dbgMask & DL_XLOG) { | 
|  | switch (command) { | 
|  | default: | 
|  | xlog("\x00\x02", &msg, 0x81, length); | 
|  | break; | 
|  | case _DATA_B3_R | CONFIRM: | 
|  | if (myDriverDebugHandle.dbgMask & DL_BLK) | 
|  | xlog("\x00\x02", &msg, 0x81, length); | 
|  | break; | 
|  | case _DATA_B3_I: | 
|  | if (myDriverDebugHandle.dbgMask & DL_BLK) { | 
|  | xlog("\x00\x02", &msg, 0x81, length); | 
|  | for (i = 0; i < dlength; i += 256) { | 
|  | DBG_BLK((((char *)(long)GET_DWORD(&msg.info.data_b3_ind.Data)) + i, | 
|  | ((dlength - i) < 256) ? (dlength - i) : 256)) | 
|  | if (!(myDriverDebugHandle.dbgMask & DL_PRV0)) | 
|  | break; /* not more if not explicitly requested */ | 
|  | } | 
|  | } | 
|  | break; | 
|  | } | 
|  | } | 
|  | #endif | 
|  |  | 
|  | /* find the card structure for this controller */ | 
|  | if (!(card = find_card_by_ctrl(write[8] & 0x7f))) { | 
|  | DBG_ERR(("sendf - controller %d not found, incoming msg dropped", | 
|  | write[8] & 0x7f)) | 
|  | diva_os_free_message_buffer(dmb); | 
|  | return; | 
|  | } | 
|  | /* send capi msg to capi layer */ | 
|  | capi_ctr_handle_message(&card->capi_ctrl, appl->Id, dmb); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * cleanup adapter | 
|  | */ | 
|  | static void clean_adapter(int id, struct list_head *free_mem_q) | 
|  | { | 
|  | DIVA_CAPI_ADAPTER *a; | 
|  | int i, k; | 
|  |  | 
|  | a = &adapter[id]; | 
|  | k = li_total_channels - a->li_channels; | 
|  | if (k == 0) { | 
|  | if (li_config_table) { | 
|  | list_add((struct list_head *)li_config_table, free_mem_q); | 
|  | li_config_table = NULL; | 
|  | } | 
|  | } else { | 
|  | if (a->li_base < k) { | 
|  | memmove(&li_config_table[a->li_base], | 
|  | &li_config_table[a->li_base + a->li_channels], | 
|  | (k - a->li_base) * sizeof(LI_CONFIG)); | 
|  | for (i = 0; i < k; i++) { | 
|  | memmove(&li_config_table[i].flag_table[a->li_base], | 
|  | &li_config_table[i].flag_table[a->li_base + a->li_channels], | 
|  | k - a->li_base); | 
|  | memmove(&li_config_table[i]. | 
|  | coef_table[a->li_base], | 
|  | &li_config_table[i].coef_table[a->li_base + a->li_channels], | 
|  | k - a->li_base); | 
|  | } | 
|  | } | 
|  | } | 
|  | li_total_channels = k; | 
|  | for (i = id; i < max_adapter; i++) { | 
|  | if (adapter[i].request) | 
|  | adapter[i].li_base -= a->li_channels; | 
|  | } | 
|  | if (a->plci) | 
|  | list_add((struct list_head *)a->plci, free_mem_q); | 
|  |  | 
|  | memset(a, 0x00, sizeof(DIVA_CAPI_ADAPTER)); | 
|  | while ((max_adapter != 0) && !adapter[max_adapter - 1].request) | 
|  | max_adapter--; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * remove a card, but ensures consistent state of LI tables | 
|  | * in the time adapter is removed | 
|  | */ | 
|  | static void divacapi_remove_card(DESCRIPTOR * d) | 
|  | { | 
|  | diva_card *card = NULL; | 
|  | diva_os_spin_lock_magic_t old_irql; | 
|  | LIST_HEAD(free_mem_q); | 
|  | struct list_head *link; | 
|  | struct list_head *tmp; | 
|  |  | 
|  | /* | 
|  | * Set "remove in progress flag". | 
|  | * Ensures that there is no call from sendf to CAPI in | 
|  | * the time CAPI controller is about to be removed. | 
|  | */ | 
|  | diva_os_enter_spin_lock(&api_lock, &old_irql, "remove card"); | 
|  | list_for_each(tmp, &cards) { | 
|  | card = list_entry(tmp, diva_card, list); | 
|  | if (card->d.request == d->request) { | 
|  | card->remove_in_progress = 1; | 
|  | list_del(tmp); | 
|  | break; | 
|  | } | 
|  | } | 
|  | diva_os_leave_spin_lock(&api_lock, &old_irql, "remove card"); | 
|  |  | 
|  | if (card) { | 
|  | /* | 
|  | * Detach CAPI. Sendf cannot call to CAPI any more. | 
|  | * After detach no call to send_message() is done too. | 
|  | */ | 
|  | detach_capi_ctr(&card->capi_ctrl); | 
|  |  | 
|  | /* | 
|  | * Now get API lock (to ensure stable state of LI tables) | 
|  | * and update the adapter map/LI table. | 
|  | */ | 
|  | diva_os_enter_spin_lock(&api_lock, &old_irql, "remove card"); | 
|  |  | 
|  | clean_adapter(card->Id - 1, &free_mem_q); | 
|  | DBG_TRC(("DelAdapterMap (%d) -> (%d)", | 
|  | ControllerMap[card->Id], card->Id)) | 
|  | ControllerMap[card->Id] = 0; | 
|  | DBG_TRC(("adapter remove, max_adapter=%d", | 
|  | max_adapter)); | 
|  | diva_os_leave_spin_lock(&api_lock, &old_irql, "remove card"); | 
|  |  | 
|  | /* After releasing the lock, we can free the memory */ | 
|  | diva_os_free (0, card); | 
|  | } | 
|  |  | 
|  | /* free queued memory areas */ | 
|  | list_for_each_safe(link, tmp, &free_mem_q) { | 
|  | list_del(link); | 
|  | diva_os_free(0, link); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* | 
|  | * remove cards | 
|  | */ | 
|  | static void divacapi_remove_cards(void) | 
|  | { | 
|  | DESCRIPTOR d; | 
|  | struct list_head *tmp; | 
|  | diva_card *card; | 
|  | diva_os_spin_lock_magic_t old_irql; | 
|  |  | 
|  | rescan: | 
|  | diva_os_enter_spin_lock(&api_lock, &old_irql, "remove cards"); | 
|  | list_for_each(tmp, &cards) { | 
|  | card = list_entry(tmp, diva_card, list); | 
|  | diva_os_leave_spin_lock(&api_lock, &old_irql, "remove cards"); | 
|  | d.request = card->d.request; | 
|  | divacapi_remove_card(&d); | 
|  | goto rescan; | 
|  | } | 
|  | diva_os_leave_spin_lock(&api_lock, &old_irql, "remove cards"); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * sync_callback | 
|  | */ | 
|  | static void sync_callback(ENTITY * e) | 
|  | { | 
|  | diva_os_spin_lock_magic_t old_irql; | 
|  |  | 
|  | DBG_TRC(("cb:Id=%x,Rc=%x,Ind=%x", e->Id, e->Rc, e->Ind)) | 
|  |  | 
|  | diva_os_enter_spin_lock(&api_lock, &old_irql, "sync_callback"); | 
|  | callback(e); | 
|  | diva_os_leave_spin_lock(&api_lock, &old_irql, "sync_callback"); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * add a new card | 
|  | */ | 
|  | static int diva_add_card(DESCRIPTOR * d) | 
|  | { | 
|  | int k = 0, i = 0; | 
|  | diva_os_spin_lock_magic_t old_irql; | 
|  | diva_card *card = NULL; | 
|  | struct capi_ctr *ctrl = NULL; | 
|  | DIVA_CAPI_ADAPTER *a = NULL; | 
|  | IDI_SYNC_REQ sync_req; | 
|  | char serial[16]; | 
|  | void* mem_to_free; | 
|  | LI_CONFIG *new_li_config_table; | 
|  | int j; | 
|  |  | 
|  | if (!(card = (diva_card *) diva_os_malloc(0, sizeof(diva_card)))) { | 
|  | DBG_ERR(("diva_add_card: failed to allocate card struct.")) | 
|  | return (0); | 
|  | } | 
|  | memset((char *) card, 0x00, sizeof(diva_card)); | 
|  | memcpy(&card->d, d, sizeof(DESCRIPTOR)); | 
|  | sync_req.GetName.Req = 0; | 
|  | sync_req.GetName.Rc = IDI_SYNC_REQ_GET_NAME; | 
|  | card->d.request((ENTITY *) & sync_req); | 
|  | strlcpy(card->name, sync_req.GetName.name, sizeof(card->name)); | 
|  | ctrl = &card->capi_ctrl; | 
|  | strcpy(ctrl->name, card->name); | 
|  | ctrl->register_appl = diva_register_appl; | 
|  | ctrl->release_appl = diva_release_appl; | 
|  | ctrl->send_message = diva_send_message; | 
|  | ctrl->procinfo = diva_procinfo; | 
|  | ctrl->driverdata = card; | 
|  | diva_os_set_controller_struct(ctrl); | 
|  |  | 
|  | if (attach_capi_ctr(ctrl)) { | 
|  | DBG_ERR(("diva_add_card: failed to attach controller.")) | 
|  | diva_os_free(0, card); | 
|  | return (0); | 
|  | } | 
|  |  | 
|  | diva_os_enter_spin_lock(&api_lock, &old_irql, "find id"); | 
|  | card->Id = find_free_id(); | 
|  | diva_os_leave_spin_lock(&api_lock, &old_irql, "find id"); | 
|  |  | 
|  | strlcpy(ctrl->manu, M_COMPANY, sizeof(ctrl->manu)); | 
|  | ctrl->version.majorversion = 2; | 
|  | ctrl->version.minorversion = 0; | 
|  | ctrl->version.majormanuversion = DRRELMAJOR; | 
|  | ctrl->version.minormanuversion = DRRELMINOR; | 
|  | sync_req.GetSerial.Req = 0; | 
|  | sync_req.GetSerial.Rc = IDI_SYNC_REQ_GET_SERIAL; | 
|  | sync_req.GetSerial.serial = 0; | 
|  | card->d.request((ENTITY *) & sync_req); | 
|  | if ((i = ((sync_req.GetSerial.serial & 0xff000000) >> 24))) { | 
|  | sprintf(serial, "%ld-%d", | 
|  | sync_req.GetSerial.serial & 0x00ffffff, i + 1); | 
|  | } else { | 
|  | sprintf(serial, "%ld", sync_req.GetSerial.serial); | 
|  | } | 
|  | serial[CAPI_SERIAL_LEN - 1] = 0; | 
|  | strlcpy(ctrl->serial, serial, sizeof(ctrl->serial)); | 
|  |  | 
|  | a = &adapter[card->Id - 1]; | 
|  | card->adapter = a; | 
|  | a->os_card = card; | 
|  | ControllerMap[card->Id] = (byte) (ctrl->cnr); | 
|  |  | 
|  | DBG_TRC(("AddAdapterMap (%d) -> (%d)", ctrl->cnr, card->Id)) | 
|  |  | 
|  | sync_req.xdi_capi_prms.Req = 0; | 
|  | sync_req.xdi_capi_prms.Rc = IDI_SYNC_REQ_XDI_GET_CAPI_PARAMS; | 
|  | sync_req.xdi_capi_prms.info.structure_length = | 
|  | sizeof(diva_xdi_get_capi_parameters_t); | 
|  | card->d.request((ENTITY *) & sync_req); | 
|  | a->flag_dynamic_l1_down = | 
|  | sync_req.xdi_capi_prms.info.flag_dynamic_l1_down; | 
|  | a->group_optimization_enabled = | 
|  | sync_req.xdi_capi_prms.info.group_optimization_enabled; | 
|  | a->request = DIRequest;	/* card->d.request; */ | 
|  | a->max_plci = card->d.channels + 30; | 
|  | a->max_listen = (card->d.channels > 2) ? 8 : 2; | 
|  | if (! | 
|  | (a->plci = | 
|  | (PLCI *) diva_os_malloc(0, sizeof(PLCI) * a->max_plci))) { | 
|  | DBG_ERR(("diva_add_card: failed alloc plci struct.")) | 
|  | memset(a, 0, sizeof(DIVA_CAPI_ADAPTER)); | 
|  | return (0); | 
|  | } | 
|  | memset(a->plci, 0, sizeof(PLCI) * a->max_plci); | 
|  |  | 
|  | for (k = 0; k < a->max_plci; k++) { | 
|  | a->Id = (byte) card->Id; | 
|  | a->plci[k].Sig.callback = sync_callback; | 
|  | a->plci[k].Sig.XNum = 1; | 
|  | a->plci[k].Sig.X = a->plci[k].XData; | 
|  | a->plci[k].Sig.user[0] = (word) (card->Id - 1); | 
|  | a->plci[k].Sig.user[1] = (word) k; | 
|  | a->plci[k].NL.callback = sync_callback; | 
|  | a->plci[k].NL.XNum = 1; | 
|  | a->plci[k].NL.X = a->plci[k].XData; | 
|  | a->plci[k].NL.user[0] = (word) ((card->Id - 1) | 0x8000); | 
|  | a->plci[k].NL.user[1] = (word) k; | 
|  | a->plci[k].adapter = a; | 
|  | } | 
|  |  | 
|  | a->profile.Number = card->Id; | 
|  | a->profile.Channels = card->d.channels; | 
|  | if (card->d.features & DI_FAX3) { | 
|  | a->profile.Global_Options = 0x71; | 
|  | if (card->d.features & DI_CODEC) | 
|  | a->profile.Global_Options |= 0x6; | 
|  | #if IMPLEMENT_DTMF | 
|  | a->profile.Global_Options |= 0x8; | 
|  | #endif				/* IMPLEMENT_DTMF */ | 
|  | a->profile.Global_Options |= 0x80; /* Line Interconnect */ | 
|  | #if IMPLEMENT_ECHO_CANCELLER | 
|  | a->profile.Global_Options |= 0x100; | 
|  | #endif				/* IMPLEMENT_ECHO_CANCELLER */ | 
|  | a->profile.B1_Protocols = 0xdf; | 
|  | a->profile.B2_Protocols = 0x1fdb; | 
|  | a->profile.B3_Protocols = 0xb7; | 
|  | a->manufacturer_features = MANUFACTURER_FEATURE_HARDDTMF; | 
|  | } else { | 
|  | a->profile.Global_Options = 0x71; | 
|  | if (card->d.features & DI_CODEC) | 
|  | a->profile.Global_Options |= 0x2; | 
|  | a->profile.B1_Protocols = 0x43; | 
|  | a->profile.B2_Protocols = 0x1f0f; | 
|  | a->profile.B3_Protocols = 0x07; | 
|  | a->manufacturer_features = 0; | 
|  | } | 
|  |  | 
|  | a->li_pri = (a->profile.Channels > 2); | 
|  | a->li_channels = a->li_pri ? MIXER_CHANNELS_PRI : MIXER_CHANNELS_BRI; | 
|  | a->li_base = 0; | 
|  | for (i = 0; &adapter[i] != a; i++) { | 
|  | if (adapter[i].request) | 
|  | a->li_base = adapter[i].li_base + adapter[i].li_channels; | 
|  | } | 
|  | k = li_total_channels + a->li_channels; | 
|  | new_li_config_table = | 
|  | (LI_CONFIG *) diva_os_malloc(0, ((k * sizeof(LI_CONFIG) + 3) & ~3) + (2 * k) * ((k + 3) & ~3)); | 
|  | if (new_li_config_table == NULL) { | 
|  | DBG_ERR(("diva_add_card: failed alloc li_config table.")) | 
|  | memset(a, 0, sizeof(DIVA_CAPI_ADAPTER)); | 
|  | return (0); | 
|  | } | 
|  |  | 
|  | /* Prevent access to line interconnect table in process update */ | 
|  | diva_os_enter_spin_lock(&api_lock, &old_irql, "add card"); | 
|  |  | 
|  | j = 0; | 
|  | for (i = 0; i < k; i++) { | 
|  | if ((i >= a->li_base) && (i < a->li_base + a->li_channels)) | 
|  | memset(&new_li_config_table[i], 0, sizeof(LI_CONFIG)); | 
|  | else | 
|  | memcpy(&new_li_config_table[i], &li_config_table[j], sizeof(LI_CONFIG)); | 
|  | new_li_config_table[i].flag_table = | 
|  | ((byte *) new_li_config_table) + (((k * sizeof(LI_CONFIG) + 3) & ~3) + (2 * i) * ((k + 3) & ~3)); | 
|  | new_li_config_table[i].coef_table = | 
|  | ((byte *) new_li_config_table) + (((k * sizeof(LI_CONFIG) + 3) & ~3) + (2 * i + 1) * ((k + 3) & ~3)); | 
|  | if ((i >= a->li_base) && (i < a->li_base + a->li_channels)) { | 
|  | new_li_config_table[i].adapter = a; | 
|  | memset(&new_li_config_table[i].flag_table[0], 0, k); | 
|  | memset(&new_li_config_table[i].coef_table[0], 0, k); | 
|  | } else { | 
|  | if (a->li_base != 0) { | 
|  | memcpy(&new_li_config_table[i].flag_table[0], | 
|  | &li_config_table[j].flag_table[0], | 
|  | a->li_base); | 
|  | memcpy(&new_li_config_table[i].coef_table[0], | 
|  | &li_config_table[j].coef_table[0], | 
|  | a->li_base); | 
|  | } | 
|  | memset(&new_li_config_table[i].flag_table[a->li_base], 0, a->li_channels); | 
|  | memset(&new_li_config_table[i].coef_table[a->li_base], 0, a->li_channels); | 
|  | if (a->li_base + a->li_channels < k) { | 
|  | memcpy(&new_li_config_table[i].flag_table[a->li_base + | 
|  | a->li_channels], | 
|  | &li_config_table[j].flag_table[a->li_base], | 
|  | k - (a->li_base + a->li_channels)); | 
|  | memcpy(&new_li_config_table[i].coef_table[a->li_base + | 
|  | a->li_channels], | 
|  | &li_config_table[j].coef_table[a->li_base], | 
|  | k - (a->li_base + a->li_channels)); | 
|  | } | 
|  | j++; | 
|  | } | 
|  | } | 
|  | li_total_channels = k; | 
|  |  | 
|  | mem_to_free = li_config_table; | 
|  |  | 
|  | li_config_table = new_li_config_table; | 
|  | for (i = card->Id; i < max_adapter; i++) { | 
|  | if (adapter[i].request) | 
|  | adapter[i].li_base += a->li_channels; | 
|  | } | 
|  |  | 
|  | if (a == &adapter[max_adapter]) | 
|  | max_adapter++; | 
|  |  | 
|  | list_add(&(card->list), &cards); | 
|  | AutomaticLaw(a); | 
|  |  | 
|  | diva_os_leave_spin_lock(&api_lock, &old_irql, "add card"); | 
|  |  | 
|  | if (mem_to_free) { | 
|  | diva_os_free (0, mem_to_free); | 
|  | } | 
|  |  | 
|  | i = 0; | 
|  | while (i++ < 30) { | 
|  | if (a->automatic_law > 3) | 
|  | break; | 
|  | diva_os_sleep(10); | 
|  | } | 
|  |  | 
|  | /* profile information */ | 
|  | PUT_WORD(&ctrl->profile.nbchannel, card->d.channels); | 
|  | ctrl->profile.goptions = a->profile.Global_Options; | 
|  | ctrl->profile.support1 = a->profile.B1_Protocols; | 
|  | ctrl->profile.support2 = a->profile.B2_Protocols; | 
|  | ctrl->profile.support3 = a->profile.B3_Protocols; | 
|  | /* manufacturer profile information */ | 
|  | ctrl->profile.manu[0] = a->man_profile.private_options; | 
|  | ctrl->profile.manu[1] = a->man_profile.rtp_primary_payloads; | 
|  | ctrl->profile.manu[2] = a->man_profile.rtp_additional_payloads; | 
|  | ctrl->profile.manu[3] = 0; | 
|  | ctrl->profile.manu[4] = 0; | 
|  |  | 
|  | capi_ctr_ready(ctrl); | 
|  |  | 
|  | DBG_TRC(("adapter added, max_adapter=%d", max_adapter)); | 
|  | return (1); | 
|  | } | 
|  |  | 
|  | /* | 
|  | *  register appl | 
|  | */ | 
|  | static void diva_register_appl(struct capi_ctr *ctrl, __u16 appl, | 
|  | capi_register_params * rp) | 
|  | { | 
|  | APPL *this; | 
|  | word bnum, xnum; | 
|  | int i = 0; | 
|  | unsigned char *p; | 
|  | void *DataNCCI, *DataFlags, *ReceiveBuffer, *xbuffer_used; | 
|  | void **xbuffer_ptr, **xbuffer_internal; | 
|  | diva_os_spin_lock_magic_t old_irql; | 
|  | unsigned int mem_len; | 
|  | int nconn = rp->level3cnt; | 
|  |  | 
|  |  | 
|  | if (diva_os_in_irq()) { | 
|  | DBG_ERR(("CAPI_REGISTER - in irq context !")) | 
|  | return; | 
|  | } | 
|  |  | 
|  | DBG_TRC(("application register Id=%d", appl)) | 
|  |  | 
|  | if (appl > MAX_APPL) { | 
|  | DBG_ERR(("CAPI_REGISTER - appl.Id exceeds MAX_APPL")) | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (nconn <= 0) | 
|  | nconn = ctrl->profile.nbchannel * -nconn; | 
|  |  | 
|  | if (nconn == 0) | 
|  | nconn = ctrl->profile.nbchannel; | 
|  |  | 
|  | DBG_LOG(("CAPI_REGISTER - Id = %d", appl)) | 
|  | DBG_LOG(("  MaxLogicalConnections = %d(%d)", nconn, rp->level3cnt)) | 
|  | DBG_LOG(("  MaxBDataBuffers       = %d", rp->datablkcnt)) | 
|  | DBG_LOG(("  MaxBDataLength        = %d", rp->datablklen)) | 
|  |  | 
|  | if (nconn < 1 || | 
|  | nconn > 255 || | 
|  | rp->datablklen < 80 || | 
|  | rp->datablklen > 2150 || rp->datablkcnt > 255) { | 
|  | DBG_ERR(("CAPI_REGISTER - invalid parameters")) | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (application[appl - 1].Id == appl) { | 
|  | DBG_LOG(("CAPI_REGISTER - appl already registered")) | 
|  | return;	/* appl already registered */ | 
|  | } | 
|  |  | 
|  | /* alloc memory */ | 
|  |  | 
|  | bnum = nconn * rp->datablkcnt; | 
|  | xnum = nconn * MAX_DATA_B3; | 
|  |  | 
|  | mem_len  = bnum * sizeof(word);		/* DataNCCI */ | 
|  | mem_len += bnum * sizeof(word);		/* DataFlags */ | 
|  | mem_len += bnum * rp->datablklen;	/* ReceiveBuffer */ | 
|  | mem_len += xnum;			/* xbuffer_used */ | 
|  | mem_len += xnum * sizeof(void *);	/* xbuffer_ptr */ | 
|  | mem_len += xnum * sizeof(void *);	/* xbuffer_internal */ | 
|  | mem_len += xnum * rp->datablklen;	/* xbuffer_ptr[xnum] */ | 
|  |  | 
|  | DBG_LOG(("  Allocated Memory      = %d", mem_len)) | 
|  | if (!(p = diva_os_malloc(0, mem_len))) { | 
|  | DBG_ERR(("CAPI_REGISTER - memory allocation failed")) | 
|  | return; | 
|  | } | 
|  | memset(p, 0, mem_len); | 
|  |  | 
|  | DataNCCI = (void *)p; | 
|  | p += bnum * sizeof(word); | 
|  | DataFlags = (void *)p; | 
|  | p += bnum * sizeof(word); | 
|  | ReceiveBuffer = (void *)p; | 
|  | p += bnum * rp->datablklen; | 
|  | xbuffer_used = (void *)p; | 
|  | p += xnum; | 
|  | xbuffer_ptr = (void **)p; | 
|  | p += xnum * sizeof(void *); | 
|  | xbuffer_internal = (void **)p; | 
|  | p += xnum * sizeof(void *); | 
|  | for (i = 0; i < xnum; i++) { | 
|  | xbuffer_ptr[i] = (void *)p; | 
|  | p += rp->datablklen; | 
|  | } | 
|  |  | 
|  | /* initialize application data */ | 
|  | diva_os_enter_spin_lock(&api_lock, &old_irql, "register_appl"); | 
|  |  | 
|  | this = &application[appl - 1]; | 
|  | memset(this, 0, sizeof(APPL)); | 
|  |  | 
|  | this->Id = appl; | 
|  |  | 
|  | for (i = 0; i < max_adapter; i++) { | 
|  | adapter[i].CIP_Mask[appl - 1] = 0; | 
|  | } | 
|  |  | 
|  | this->queue_size = 1000; | 
|  |  | 
|  | this->MaxNCCI = (byte) nconn; | 
|  | this->MaxNCCIData = (byte) rp->datablkcnt; | 
|  | this->MaxBuffer = bnum; | 
|  | this->MaxDataLength = rp->datablklen; | 
|  |  | 
|  | this->DataNCCI = DataNCCI; | 
|  | this->DataFlags = DataFlags; | 
|  | this->ReceiveBuffer = ReceiveBuffer; | 
|  | this->xbuffer_used = xbuffer_used; | 
|  | this->xbuffer_ptr = xbuffer_ptr; | 
|  | this->xbuffer_internal = xbuffer_internal; | 
|  | for (i = 0; i < xnum; i++) { | 
|  | this->xbuffer_ptr[i] = xbuffer_ptr[i]; | 
|  | } | 
|  |  | 
|  | CapiRegister(this->Id); | 
|  | diva_os_leave_spin_lock(&api_lock, &old_irql, "register_appl"); | 
|  |  | 
|  | } | 
|  |  | 
|  | /* | 
|  | *  release appl | 
|  | */ | 
|  | static void diva_release_appl(struct capi_ctr *ctrl, __u16 appl) | 
|  | { | 
|  | diva_os_spin_lock_magic_t old_irql; | 
|  | APPL *this = &application[appl - 1]; | 
|  | void *mem_to_free = NULL; | 
|  |  | 
|  | DBG_TRC(("application %d(%d) cleanup", this->Id, appl)) | 
|  |  | 
|  | if (diva_os_in_irq()) { | 
|  | DBG_ERR(("CAPI_RELEASE - in irq context !")) | 
|  | return; | 
|  | } | 
|  |  | 
|  | diva_os_enter_spin_lock(&api_lock, &old_irql, "release_appl"); | 
|  | if (this->Id) { | 
|  | CapiRelease(this->Id); | 
|  | mem_to_free = this->DataNCCI; | 
|  | this->DataNCCI = NULL; | 
|  | this->Id = 0; | 
|  | } | 
|  | diva_os_leave_spin_lock(&api_lock, &old_irql, "release_appl"); | 
|  |  | 
|  | if (mem_to_free) | 
|  | diva_os_free(0, mem_to_free); | 
|  |  | 
|  | } | 
|  |  | 
|  | /* | 
|  | *  send message | 
|  | */ | 
|  | static u16 diva_send_message(struct capi_ctr *ctrl, | 
|  | diva_os_message_buffer_s * dmb) | 
|  | { | 
|  | int i = 0; | 
|  | word ret = 0; | 
|  | diva_os_spin_lock_magic_t old_irql; | 
|  | CAPI_MSG *msg = (CAPI_MSG *) DIVA_MESSAGE_BUFFER_DATA(dmb); | 
|  | APPL *this = &application[GET_WORD(&msg->header.appl_id) - 1]; | 
|  | diva_card *card = ctrl->driverdata; | 
|  | __u32 length = DIVA_MESSAGE_BUFFER_LEN(dmb); | 
|  | word clength = GET_WORD(&msg->header.length); | 
|  | word command = GET_WORD(&msg->header.command); | 
|  | u16 retval = CAPI_NOERROR; | 
|  |  | 
|  | if (diva_os_in_irq()) { | 
|  | DBG_ERR(("CAPI_SEND_MSG - in irq context !")) | 
|  | return CAPI_REGOSRESOURCEERR; | 
|  | } | 
|  | DBG_PRV1(("Write - appl = %d, cmd = 0x%x", this->Id, command)) | 
|  |  | 
|  | if (card->remove_in_progress) { | 
|  | DBG_ERR(("CAPI_SEND_MSG - remove in progress!")) | 
|  | return CAPI_REGOSRESOURCEERR; | 
|  | } | 
|  |  | 
|  | diva_os_enter_spin_lock(&api_lock, &old_irql, "send message"); | 
|  |  | 
|  | if (!this->Id) { | 
|  | diva_os_leave_spin_lock(&api_lock, &old_irql, "send message"); | 
|  | return CAPI_ILLAPPNR; | 
|  | } | 
|  |  | 
|  | /* patch controller number */ | 
|  | msg->header.controller = ControllerMap[card->Id] | 
|  | | (msg->header.controller & 0x80);	/* preserve external controller bit */ | 
|  |  | 
|  | switch (command) { | 
|  | default: | 
|  | xlog("\x00\x02", msg, 0x80, clength); | 
|  | break; | 
|  |  | 
|  | case _DATA_B3_I | RESPONSE: | 
|  | #ifndef DIVA_NO_DEBUGLIB | 
|  | if (myDriverDebugHandle.dbgMask & DL_BLK) | 
|  | xlog("\x00\x02", msg, 0x80, clength); | 
|  | #endif | 
|  | break; | 
|  |  | 
|  | case _DATA_B3_R: | 
|  | #ifndef DIVA_NO_DEBUGLIB | 
|  | if (myDriverDebugHandle.dbgMask & DL_BLK) | 
|  | xlog("\x00\x02", msg, 0x80, clength); | 
|  | #endif | 
|  |  | 
|  | if (clength == 24) | 
|  | clength = 22;	/* workaround for PPcom bug */ | 
|  | /* header is always 22      */ | 
|  | if (GET_WORD(&msg->info.data_b3_req.Data_Length) > | 
|  | this->MaxDataLength | 
|  | || GET_WORD(&msg->info.data_b3_req.Data_Length) > | 
|  | (length - clength)) { | 
|  | DBG_ERR(("Write - invalid message size")) | 
|  | retval = CAPI_ILLCMDORSUBCMDORMSGTOSMALL; | 
|  | goto write_end; | 
|  | } | 
|  |  | 
|  | for (i = 0; i < (MAX_DATA_B3 * this->MaxNCCI) | 
|  | && this->xbuffer_used[i]; i++); | 
|  | if (i == (MAX_DATA_B3 * this->MaxNCCI)) { | 
|  | DBG_ERR(("Write - too many data pending")) | 
|  | retval = CAPI_SENDQUEUEFULL; | 
|  | goto write_end; | 
|  | } | 
|  | msg->info.data_b3_req.Data = i; | 
|  |  | 
|  | this->xbuffer_internal[i] = NULL; | 
|  | memcpy(this->xbuffer_ptr[i], &((__u8 *) msg)[clength], | 
|  | GET_WORD(&msg->info.data_b3_req.Data_Length)); | 
|  |  | 
|  | #ifndef DIVA_NO_DEBUGLIB | 
|  | if ((myDriverDebugHandle.dbgMask & DL_BLK) | 
|  | && (myDriverDebugHandle.dbgMask & DL_XLOG)) { | 
|  | int j; | 
|  | for (j = 0; j < | 
|  | GET_WORD(&msg->info.data_b3_req.Data_Length); | 
|  | j += 256) { | 
|  | DBG_BLK((((char *) this->xbuffer_ptr[i]) + j, | 
|  | ((GET_WORD(&msg->info.data_b3_req.Data_Length) - j) < | 
|  | 256) ? (GET_WORD(&msg->info.data_b3_req.Data_Length) - j) : 256)) | 
|  | if (!(myDriverDebugHandle.dbgMask & DL_PRV0)) | 
|  | break;	/* not more if not explicitly requested */ | 
|  | } | 
|  | } | 
|  | #endif | 
|  | break; | 
|  | } | 
|  |  | 
|  | memcpy(mapped_msg, msg, (__u32) clength); | 
|  | mapped_msg->header.controller = MapController(mapped_msg->header.controller); | 
|  | mapped_msg->header.length = clength; | 
|  | mapped_msg->header.command = command; | 
|  | mapped_msg->header.number = GET_WORD(&msg->header.number); | 
|  |  | 
|  | ret = api_put(this, mapped_msg); | 
|  | switch (ret) { | 
|  | case 0: | 
|  | break; | 
|  | case _BAD_MSG: | 
|  | DBG_ERR(("Write - bad message")) | 
|  | retval = CAPI_ILLCMDORSUBCMDORMSGTOSMALL; | 
|  | break; | 
|  | case _QUEUE_FULL: | 
|  | DBG_ERR(("Write - queue full")) | 
|  | retval = CAPI_SENDQUEUEFULL; | 
|  | break; | 
|  | default: | 
|  | DBG_ERR(("Write - api_put returned unknown error")) | 
|  | retval = CAPI_UNKNOWNNOTPAR; | 
|  | break; | 
|  | } | 
|  |  | 
|  | write_end: | 
|  | diva_os_leave_spin_lock(&api_lock, &old_irql, "send message"); | 
|  | if (retval == CAPI_NOERROR) | 
|  | diva_os_free_message_buffer(dmb); | 
|  | return retval; | 
|  | } | 
|  |  | 
|  |  | 
|  | /* | 
|  | * cards request function | 
|  | */ | 
|  | static void DIRequest(ENTITY * e) | 
|  | { | 
|  | DIVA_CAPI_ADAPTER *a = &(adapter[(byte) e->user[0]]); | 
|  | diva_card *os_card = (diva_card *) a->os_card; | 
|  |  | 
|  | if (e->Req && (a->FlowControlIdTable[e->ReqCh] == e->Id)) { | 
|  | a->FlowControlSkipTable[e->ReqCh] = 1; | 
|  | } | 
|  |  | 
|  | (*(os_card->d.request)) (e); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * callback function from didd | 
|  | */ | 
|  | static void didd_callback(void *context, DESCRIPTOR * adapter, int removal) | 
|  | { | 
|  | if (adapter->type == IDI_DADAPTER) { | 
|  | DBG_ERR(("Notification about IDI_DADAPTER change ! Oops.")); | 
|  | return; | 
|  | } else if (adapter->type == IDI_DIMAINT) { | 
|  | if (removal) { | 
|  | stop_dbg(); | 
|  | } else { | 
|  | memcpy(&MAdapter, adapter, sizeof(MAdapter)); | 
|  | dprintf = (DIVA_DI_PRINTF) MAdapter.request; | 
|  | DbgRegister("CAPI20", DRIVERRELEASE_CAPI, DBG_DEFAULT); | 
|  | } | 
|  | } else if ((adapter->type > 0) && (adapter->type < 16)) {	/* IDI Adapter */ | 
|  | if (removal) { | 
|  | divacapi_remove_card(adapter); | 
|  | } else { | 
|  | diva_add_card(adapter); | 
|  | } | 
|  | } | 
|  | return; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * connect to didd | 
|  | */ | 
|  | static int divacapi_connect_didd(void) | 
|  | { | 
|  | int x = 0; | 
|  | int dadapter = 0; | 
|  | IDI_SYNC_REQ req; | 
|  | DESCRIPTOR DIDD_Table[MAX_DESCRIPTORS]; | 
|  |  | 
|  | DIVA_DIDD_Read(DIDD_Table, sizeof(DIDD_Table)); | 
|  |  | 
|  | for (x = 0; x < MAX_DESCRIPTORS; x++) { | 
|  | if (DIDD_Table[x].type == IDI_DIMAINT) {	/* MAINT found */ | 
|  | memcpy(&MAdapter, &DIDD_Table[x], sizeof(DAdapter)); | 
|  | dprintf = (DIVA_DI_PRINTF) MAdapter.request; | 
|  | DbgRegister("CAPI20", DRIVERRELEASE_CAPI, DBG_DEFAULT); | 
|  | break; | 
|  | } | 
|  | } | 
|  | for (x = 0; x < MAX_DESCRIPTORS; x++) { | 
|  | if (DIDD_Table[x].type == IDI_DADAPTER) {	/* DADAPTER found */ | 
|  | dadapter = 1; | 
|  | memcpy(&DAdapter, &DIDD_Table[x], sizeof(DAdapter)); | 
|  | req.didd_notify.e.Req = 0; | 
|  | req.didd_notify.e.Rc = | 
|  | IDI_SYNC_REQ_DIDD_REGISTER_ADAPTER_NOTIFY; | 
|  | req.didd_notify.info.callback = (void *)didd_callback; | 
|  | req.didd_notify.info.context = NULL; | 
|  | DAdapter.request((ENTITY *) & req); | 
|  | if (req.didd_notify.e.Rc != 0xff) { | 
|  | stop_dbg(); | 
|  | return (0); | 
|  | } | 
|  | notify_handle = req.didd_notify.info.handle; | 
|  | } | 
|  | else if ((DIDD_Table[x].type > 0) && (DIDD_Table[x].type < 16)) {	/* IDI Adapter found */ | 
|  | diva_add_card(&DIDD_Table[x]); | 
|  | } | 
|  | } | 
|  |  | 
|  | if (!dadapter) { | 
|  | stop_dbg(); | 
|  | } | 
|  |  | 
|  | return (dadapter); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * diconnect from didd | 
|  | */ | 
|  | static void divacapi_disconnect_didd(void) | 
|  | { | 
|  | IDI_SYNC_REQ req; | 
|  |  | 
|  | stop_dbg(); | 
|  |  | 
|  | req.didd_notify.e.Req = 0; | 
|  | req.didd_notify.e.Rc = IDI_SYNC_REQ_DIDD_REMOVE_ADAPTER_NOTIFY; | 
|  | req.didd_notify.info.handle = notify_handle; | 
|  | DAdapter.request((ENTITY *) & req); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * we do not provide date/time here, | 
|  | * the application should do this. | 
|  | */ | 
|  | int fax_head_line_time(char *buffer) | 
|  | { | 
|  | return (0); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * init (alloc) main structures | 
|  | */ | 
|  | static int DIVA_INIT_FUNCTION init_main_structs(void) | 
|  | { | 
|  | if (!(mapped_msg = (CAPI_MSG *) diva_os_malloc(0, MAX_MSG_SIZE))) { | 
|  | DBG_ERR(("init: failed alloc mapped_msg.")) | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | if (!(adapter = diva_os_malloc(0, sizeof(DIVA_CAPI_ADAPTER) * MAX_DESCRIPTORS))) { | 
|  | DBG_ERR(("init: failed alloc adapter struct.")) | 
|  | diva_os_free(0, mapped_msg); | 
|  | return 0; | 
|  | } | 
|  | memset(adapter, 0, sizeof(DIVA_CAPI_ADAPTER) * MAX_DESCRIPTORS); | 
|  |  | 
|  | if (!(application = diva_os_malloc(0, sizeof(APPL) * MAX_APPL))) { | 
|  | DBG_ERR(("init: failed alloc application struct.")) | 
|  | diva_os_free(0, mapped_msg); | 
|  | diva_os_free(0, adapter); | 
|  | return 0; | 
|  | } | 
|  | memset(application, 0, sizeof(APPL) * MAX_APPL); | 
|  |  | 
|  | return (1); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * remove (free) main structures | 
|  | */ | 
|  | static void remove_main_structs(void) | 
|  | { | 
|  | if (application) | 
|  | diva_os_free(0, application); | 
|  | if (adapter) | 
|  | diva_os_free(0, adapter); | 
|  | if (mapped_msg) | 
|  | diva_os_free(0, mapped_msg); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * api_remove_start | 
|  | */ | 
|  | static void do_api_remove_start(void) | 
|  | { | 
|  | diva_os_spin_lock_magic_t old_irql; | 
|  | int ret = 1, count = 100; | 
|  |  | 
|  | do { | 
|  | diva_os_enter_spin_lock(&api_lock, &old_irql, "api remove start"); | 
|  | ret = api_remove_start(); | 
|  | diva_os_leave_spin_lock(&api_lock, &old_irql, "api remove start"); | 
|  |  | 
|  | diva_os_sleep(10); | 
|  | } while (ret && count--); | 
|  |  | 
|  | if (ret) | 
|  | DBG_ERR(("could not remove signaling ID's")) | 
|  | } | 
|  |  | 
|  | /* | 
|  | * init | 
|  | */ | 
|  | int DIVA_INIT_FUNCTION init_capifunc(void) | 
|  | { | 
|  | diva_os_initialize_spin_lock(&api_lock, "capifunc"); | 
|  | memset(ControllerMap, 0, MAX_DESCRIPTORS + 1); | 
|  | max_adapter = 0; | 
|  |  | 
|  |  | 
|  | if (!init_main_structs()) { | 
|  | DBG_ERR(("init: failed to init main structs.")) | 
|  | diva_os_destroy_spin_lock(&api_lock, "capifunc"); | 
|  | return (0); | 
|  | } | 
|  |  | 
|  | if (!divacapi_connect_didd()) { | 
|  | DBG_ERR(("init: failed to connect to DIDD.")) | 
|  | do_api_remove_start(); | 
|  | divacapi_remove_cards(); | 
|  | remove_main_structs(); | 
|  | diva_os_destroy_spin_lock(&api_lock, "capifunc"); | 
|  | return (0); | 
|  | } | 
|  |  | 
|  | return (1); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * finit | 
|  | */ | 
|  | void DIVA_EXIT_FUNCTION finit_capifunc(void) | 
|  | { | 
|  | do_api_remove_start(); | 
|  | divacapi_disconnect_didd(); | 
|  | divacapi_remove_cards(); | 
|  | remove_main_structs(); | 
|  | diva_os_destroy_spin_lock(&api_lock, "capifunc"); | 
|  | } |