Path: blob/master/drivers/isdn/hardware/eicon/capifunc.c
15115 views
/* $Id: capifunc.c,v 1.61.4.7 2005/02/11 19:40:25 armin Exp $1*2* ISDN interface module for Eicon active cards DIVA.3* CAPI Interface common functions4*5* Copyright 2000-2003 by Armin Schindler ([email protected])6* Copyright 2000-2003 Cytronics & Melware ([email protected])7*8* This software may be used and distributed according to the terms9* of the GNU General Public License, incorporated herein by reference.10*11*/1213#include "platform.h"14#include "os_capi.h"15#include "di_defs.h"16#include "capi20.h"17#include "divacapi.h"18#include "divasync.h"19#include "capifunc.h"2021#define DBG_MINIMUM (DL_LOG + DL_FTL + DL_ERR)22#define DBG_DEFAULT (DBG_MINIMUM + DL_XLOG + DL_REG)2324DIVA_CAPI_ADAPTER *adapter = (DIVA_CAPI_ADAPTER *) NULL;25APPL *application = (APPL *) NULL;26byte max_appl = MAX_APPL;27byte max_adapter = 0;28static CAPI_MSG *mapped_msg = (CAPI_MSG *) NULL;2930byte UnMapController(byte);31char DRIVERRELEASE_CAPI[32];3233extern void AutomaticLaw(DIVA_CAPI_ADAPTER *);34extern void callback(ENTITY *);35extern word api_remove_start(void);36extern word CapiRelease(word);37extern word CapiRegister(word);38extern word api_put(APPL *, CAPI_MSG *);3940static diva_os_spin_lock_t api_lock;4142static LIST_HEAD(cards);4344static dword notify_handle;45static void DIRequest(ENTITY * e);46static DESCRIPTOR MAdapter;47static DESCRIPTOR DAdapter;48static byte ControllerMap[MAX_DESCRIPTORS + 1];495051static void diva_register_appl(struct capi_ctr *, __u16,52capi_register_params *);53static void diva_release_appl(struct capi_ctr *, __u16);54static char *diva_procinfo(struct capi_ctr *);55static u16 diva_send_message(struct capi_ctr *,56diva_os_message_buffer_s *);57extern void diva_os_set_controller_struct(struct capi_ctr *);5859extern void DIVA_DIDD_Read(DESCRIPTOR *, int);6061/*62* debug63*/64static void no_printf(unsigned char *, ...);65#include "debuglib.c"66static void xlog(char *x, ...)67{68#ifndef DIVA_NO_DEBUGLIB69va_list ap;70if (myDriverDebugHandle.dbgMask & DL_XLOG) {71va_start(ap, x);72if (myDriverDebugHandle.dbg_irq) {73myDriverDebugHandle.dbg_irq(myDriverDebugHandle.id,74DLI_XLOG, x, ap);75} else if (myDriverDebugHandle.dbg_old) {76myDriverDebugHandle.dbg_old(myDriverDebugHandle.id,77x, ap);78}79va_end(ap);80}81#endif82}8384/*85* info for proc86*/87static char *diva_procinfo(struct capi_ctr *ctrl)88{89return (ctrl->serial);90}9192/*93* stop debugging94*/95static void stop_dbg(void)96{97DbgDeregister();98memset(&MAdapter, 0, sizeof(MAdapter));99dprintf = no_printf;100}101102/*103* dummy debug function104*/105static void no_printf(unsigned char *x, ...)106{107}108109/*110* Controller mapping111*/112byte MapController(byte Controller)113{114byte i;115byte MappedController = 0;116byte ctrl = Controller & 0x7f; /* mask external controller bit off */117118for (i = 1; i < max_adapter + 1; i++) {119if (ctrl == ControllerMap[i]) {120MappedController = (byte) i;121break;122}123}124if (i > max_adapter) {125ControllerMap[0] = ctrl;126MappedController = 0;127}128return (MappedController | (Controller & 0x80)); /* put back external controller bit */129}130131/*132* Controller unmapping133*/134byte UnMapController(byte MappedController)135{136byte Controller;137byte ctrl = MappedController & 0x7f; /* mask external controller bit off */138139if (ctrl <= max_adapter) {140Controller = ControllerMap[ctrl];141} else {142Controller = 0;143}144145return (Controller | (MappedController & 0x80)); /* put back external controller bit */146}147148/*149* find a new free id150*/151static int find_free_id(void)152{153int num = 0;154DIVA_CAPI_ADAPTER *a;155156while (num < MAX_DESCRIPTORS) {157a = &adapter[num];158if (!a->Id)159break;160num++;161}162return(num + 1);163}164165/*166* find a card structure by controller number167*/168static diva_card *find_card_by_ctrl(word controller)169{170struct list_head *tmp;171diva_card *card;172173list_for_each(tmp, &cards) {174card = list_entry(tmp, diva_card, list);175if (ControllerMap[card->Id] == controller) {176if (card->remove_in_progress)177card = NULL;178return(card);179}180}181return (diva_card *) 0;182}183184/*185* Buffer RX/TX186*/187void *TransmitBufferSet(APPL * appl, dword ref)188{189appl->xbuffer_used[ref] = true;190DBG_PRV1(("%d:xbuf_used(%d)", appl->Id, ref + 1))191return (void *)(long)ref;192}193194void *TransmitBufferGet(APPL * appl, void *p)195{196if (appl->xbuffer_internal[(dword)(long)p])197return appl->xbuffer_internal[(dword)(long)p];198199return appl->xbuffer_ptr[(dword)(long)p];200}201202void TransmitBufferFree(APPL * appl, void *p)203{204appl->xbuffer_used[(dword)(long)p] = false;205DBG_PRV1(("%d:xbuf_free(%d)", appl->Id, ((dword)(long)p) + 1))206}207208void *ReceiveBufferGet(APPL * appl, int Num)209{210return &appl->ReceiveBuffer[Num * appl->MaxDataLength];211}212213/*214* api_remove_start/complete for cleanup215*/216void api_remove_complete(void)217{218DBG_PRV1(("api_remove_complete"))219}220221/*222* main function called by message.c223*/224void sendf(APPL * appl, word command, dword Id, word Number, byte * format, ...)225{226word i, j;227word length = 12, dlength = 0;228byte *write;229CAPI_MSG msg;230byte *string = NULL;231va_list ap;232diva_os_message_buffer_s *dmb;233diva_card *card = NULL;234dword tmp;235236if (!appl)237return;238239DBG_PRV1(("sendf(a=%d,cmd=%x,format=%s)",240appl->Id, command, (byte *) format))241242PUT_WORD(&msg.header.appl_id, appl->Id);243PUT_WORD(&msg.header.command, command);244if ((byte) (command >> 8) == 0x82)245Number = appl->Number++;246PUT_WORD(&msg.header.number, Number);247248PUT_DWORD(&msg.header.controller, Id);249write = (byte *) & msg;250write += 12;251252va_start(ap, format);253for (i = 0; format[i]; i++) {254switch (format[i]) {255case 'b':256tmp = va_arg(ap, dword);257*(byte *) write = (byte) (tmp & 0xff);258write += 1;259length += 1;260break;261case 'w':262tmp = va_arg(ap, dword);263PUT_WORD(write, (tmp & 0xffff));264write += 2;265length += 2;266break;267case 'd':268tmp = va_arg(ap, dword);269PUT_DWORD(write, tmp);270write += 4;271length += 4;272break;273case 's':274case 'S':275string = va_arg(ap, byte *);276length += string[0] + 1;277for (j = 0; j <= string[0]; j++)278*write++ = string[j];279break;280}281}282va_end(ap);283284PUT_WORD(&msg.header.length, length);285msg.header.controller = UnMapController(msg.header.controller);286287if (command == _DATA_B3_I)288dlength = GET_WORD(289((byte *) & msg.info.data_b3_ind.Data_Length));290291if (!(dmb = diva_os_alloc_message_buffer(length + dlength,292(void **) &write))) {293DBG_ERR(("sendf: alloc_message_buffer failed, incoming msg dropped."))294return;295}296297/* copy msg header to sk_buff */298memcpy(write, (byte *) & msg, length);299300/* if DATA_B3_IND, copy data too */301if (command == _DATA_B3_I) {302dword data = GET_DWORD(&msg.info.data_b3_ind.Data);303memcpy(write + length, (void *)(long)data, dlength);304}305306#ifndef DIVA_NO_DEBUGLIB307if (myDriverDebugHandle.dbgMask & DL_XLOG) {308switch (command) {309default:310xlog("\x00\x02", &msg, 0x81, length);311break;312case _DATA_B3_R | CONFIRM:313if (myDriverDebugHandle.dbgMask & DL_BLK)314xlog("\x00\x02", &msg, 0x81, length);315break;316case _DATA_B3_I:317if (myDriverDebugHandle.dbgMask & DL_BLK) {318xlog("\x00\x02", &msg, 0x81, length);319for (i = 0; i < dlength; i += 256) {320DBG_BLK((((char *)(long)GET_DWORD(&msg.info.data_b3_ind.Data)) + i,321((dlength - i) < 256) ? (dlength - i) : 256))322if (!(myDriverDebugHandle.dbgMask & DL_PRV0))323break; /* not more if not explicitly requested */324}325}326break;327}328}329#endif330331/* find the card structure for this controller */332if (!(card = find_card_by_ctrl(write[8] & 0x7f))) {333DBG_ERR(("sendf - controller %d not found, incoming msg dropped",334write[8] & 0x7f))335diva_os_free_message_buffer(dmb);336return;337}338/* send capi msg to capi layer */339capi_ctr_handle_message(&card->capi_ctrl, appl->Id, dmb);340}341342/*343* cleanup adapter344*/345static void clean_adapter(int id, struct list_head *free_mem_q)346{347DIVA_CAPI_ADAPTER *a;348int i, k;349350a = &adapter[id];351k = li_total_channels - a->li_channels;352if (k == 0) {353if (li_config_table) {354list_add((struct list_head *)li_config_table, free_mem_q);355li_config_table = NULL;356}357} else {358if (a->li_base < k) {359memmove(&li_config_table[a->li_base],360&li_config_table[a->li_base + a->li_channels],361(k - a->li_base) * sizeof(LI_CONFIG));362for (i = 0; i < k; i++) {363memmove(&li_config_table[i].flag_table[a->li_base],364&li_config_table[i].flag_table[a->li_base + a->li_channels],365k - a->li_base);366memmove(&li_config_table[i].367coef_table[a->li_base],368&li_config_table[i].coef_table[a->li_base + a->li_channels],369k - a->li_base);370}371}372}373li_total_channels = k;374for (i = id; i < max_adapter; i++) {375if (adapter[i].request)376adapter[i].li_base -= a->li_channels;377}378if (a->plci)379list_add((struct list_head *)a->plci, free_mem_q);380381memset(a, 0x00, sizeof(DIVA_CAPI_ADAPTER));382while ((max_adapter != 0) && !adapter[max_adapter - 1].request)383max_adapter--;384}385386/*387* remove a card, but ensures consistent state of LI tables388* in the time adapter is removed389*/390static void divacapi_remove_card(DESCRIPTOR * d)391{392diva_card *card = NULL;393diva_os_spin_lock_magic_t old_irql;394LIST_HEAD(free_mem_q);395struct list_head *link;396struct list_head *tmp;397398/*399* Set "remove in progress flag".400* Ensures that there is no call from sendf to CAPI in401* the time CAPI controller is about to be removed.402*/403diva_os_enter_spin_lock(&api_lock, &old_irql, "remove card");404list_for_each(tmp, &cards) {405card = list_entry(tmp, diva_card, list);406if (card->d.request == d->request) {407card->remove_in_progress = 1;408list_del(tmp);409break;410}411}412diva_os_leave_spin_lock(&api_lock, &old_irql, "remove card");413414if (card) {415/*416* Detach CAPI. Sendf cannot call to CAPI any more.417* After detach no call to send_message() is done too.418*/419detach_capi_ctr(&card->capi_ctrl);420421/*422* Now get API lock (to ensure stable state of LI tables)423* and update the adapter map/LI table.424*/425diva_os_enter_spin_lock(&api_lock, &old_irql, "remove card");426427clean_adapter(card->Id - 1, &free_mem_q);428DBG_TRC(("DelAdapterMap (%d) -> (%d)",429ControllerMap[card->Id], card->Id))430ControllerMap[card->Id] = 0;431DBG_TRC(("adapter remove, max_adapter=%d",432max_adapter));433diva_os_leave_spin_lock(&api_lock, &old_irql, "remove card");434435/* After releasing the lock, we can free the memory */436diva_os_free (0, card);437}438439/* free queued memory areas */440list_for_each_safe(link, tmp, &free_mem_q) {441list_del(link);442diva_os_free(0, link);443}444}445446/*447* remove cards448*/449static void divacapi_remove_cards(void)450{451DESCRIPTOR d;452struct list_head *tmp;453diva_card *card;454diva_os_spin_lock_magic_t old_irql;455456rescan:457diva_os_enter_spin_lock(&api_lock, &old_irql, "remove cards");458list_for_each(tmp, &cards) {459card = list_entry(tmp, diva_card, list);460diva_os_leave_spin_lock(&api_lock, &old_irql, "remove cards");461d.request = card->d.request;462divacapi_remove_card(&d);463goto rescan;464}465diva_os_leave_spin_lock(&api_lock, &old_irql, "remove cards");466}467468/*469* sync_callback470*/471static void sync_callback(ENTITY * e)472{473diva_os_spin_lock_magic_t old_irql;474475DBG_TRC(("cb:Id=%x,Rc=%x,Ind=%x", e->Id, e->Rc, e->Ind))476477diva_os_enter_spin_lock(&api_lock, &old_irql, "sync_callback");478callback(e);479diva_os_leave_spin_lock(&api_lock, &old_irql, "sync_callback");480}481482/*483* add a new card484*/485static int diva_add_card(DESCRIPTOR * d)486{487int k = 0, i = 0;488diva_os_spin_lock_magic_t old_irql;489diva_card *card = NULL;490struct capi_ctr *ctrl = NULL;491DIVA_CAPI_ADAPTER *a = NULL;492IDI_SYNC_REQ sync_req;493char serial[16];494void* mem_to_free;495LI_CONFIG *new_li_config_table;496int j;497498if (!(card = (diva_card *) diva_os_malloc(0, sizeof(diva_card)))) {499DBG_ERR(("diva_add_card: failed to allocate card struct."))500return (0);501}502memset((char *) card, 0x00, sizeof(diva_card));503memcpy(&card->d, d, sizeof(DESCRIPTOR));504sync_req.GetName.Req = 0;505sync_req.GetName.Rc = IDI_SYNC_REQ_GET_NAME;506card->d.request((ENTITY *) & sync_req);507strlcpy(card->name, sync_req.GetName.name, sizeof(card->name));508ctrl = &card->capi_ctrl;509strcpy(ctrl->name, card->name);510ctrl->register_appl = diva_register_appl;511ctrl->release_appl = diva_release_appl;512ctrl->send_message = diva_send_message;513ctrl->procinfo = diva_procinfo;514ctrl->driverdata = card;515diva_os_set_controller_struct(ctrl);516517if (attach_capi_ctr(ctrl)) {518DBG_ERR(("diva_add_card: failed to attach controller."))519diva_os_free(0, card);520return (0);521}522523diva_os_enter_spin_lock(&api_lock, &old_irql, "find id");524card->Id = find_free_id();525diva_os_leave_spin_lock(&api_lock, &old_irql, "find id");526527strlcpy(ctrl->manu, M_COMPANY, sizeof(ctrl->manu));528ctrl->version.majorversion = 2;529ctrl->version.minorversion = 0;530ctrl->version.majormanuversion = DRRELMAJOR;531ctrl->version.minormanuversion = DRRELMINOR;532sync_req.GetSerial.Req = 0;533sync_req.GetSerial.Rc = IDI_SYNC_REQ_GET_SERIAL;534sync_req.GetSerial.serial = 0;535card->d.request((ENTITY *) & sync_req);536if ((i = ((sync_req.GetSerial.serial & 0xff000000) >> 24))) {537sprintf(serial, "%ld-%d",538sync_req.GetSerial.serial & 0x00ffffff, i + 1);539} else {540sprintf(serial, "%ld", sync_req.GetSerial.serial);541}542serial[CAPI_SERIAL_LEN - 1] = 0;543strlcpy(ctrl->serial, serial, sizeof(ctrl->serial));544545a = &adapter[card->Id - 1];546card->adapter = a;547a->os_card = card;548ControllerMap[card->Id] = (byte) (ctrl->cnr);549550DBG_TRC(("AddAdapterMap (%d) -> (%d)", ctrl->cnr, card->Id))551552sync_req.xdi_capi_prms.Req = 0;553sync_req.xdi_capi_prms.Rc = IDI_SYNC_REQ_XDI_GET_CAPI_PARAMS;554sync_req.xdi_capi_prms.info.structure_length =555sizeof(diva_xdi_get_capi_parameters_t);556card->d.request((ENTITY *) & sync_req);557a->flag_dynamic_l1_down =558sync_req.xdi_capi_prms.info.flag_dynamic_l1_down;559a->group_optimization_enabled =560sync_req.xdi_capi_prms.info.group_optimization_enabled;561a->request = DIRequest; /* card->d.request; */562a->max_plci = card->d.channels + 30;563a->max_listen = (card->d.channels > 2) ? 8 : 2;564if (!565(a->plci =566(PLCI *) diva_os_malloc(0, sizeof(PLCI) * a->max_plci))) {567DBG_ERR(("diva_add_card: failed alloc plci struct."))568memset(a, 0, sizeof(DIVA_CAPI_ADAPTER));569return (0);570}571memset(a->plci, 0, sizeof(PLCI) * a->max_plci);572573for (k = 0; k < a->max_plci; k++) {574a->Id = (byte) card->Id;575a->plci[k].Sig.callback = sync_callback;576a->plci[k].Sig.XNum = 1;577a->plci[k].Sig.X = a->plci[k].XData;578a->plci[k].Sig.user[0] = (word) (card->Id - 1);579a->plci[k].Sig.user[1] = (word) k;580a->plci[k].NL.callback = sync_callback;581a->plci[k].NL.XNum = 1;582a->plci[k].NL.X = a->plci[k].XData;583a->plci[k].NL.user[0] = (word) ((card->Id - 1) | 0x8000);584a->plci[k].NL.user[1] = (word) k;585a->plci[k].adapter = a;586}587588a->profile.Number = card->Id;589a->profile.Channels = card->d.channels;590if (card->d.features & DI_FAX3) {591a->profile.Global_Options = 0x71;592if (card->d.features & DI_CODEC)593a->profile.Global_Options |= 0x6;594#if IMPLEMENT_DTMF595a->profile.Global_Options |= 0x8;596#endif /* IMPLEMENT_DTMF */597a->profile.Global_Options |= 0x80; /* Line Interconnect */598#if IMPLEMENT_ECHO_CANCELLER599a->profile.Global_Options |= 0x100;600#endif /* IMPLEMENT_ECHO_CANCELLER */601a->profile.B1_Protocols = 0xdf;602a->profile.B2_Protocols = 0x1fdb;603a->profile.B3_Protocols = 0xb7;604a->manufacturer_features = MANUFACTURER_FEATURE_HARDDTMF;605} else {606a->profile.Global_Options = 0x71;607if (card->d.features & DI_CODEC)608a->profile.Global_Options |= 0x2;609a->profile.B1_Protocols = 0x43;610a->profile.B2_Protocols = 0x1f0f;611a->profile.B3_Protocols = 0x07;612a->manufacturer_features = 0;613}614615a->li_pri = (a->profile.Channels > 2);616a->li_channels = a->li_pri ? MIXER_CHANNELS_PRI : MIXER_CHANNELS_BRI;617a->li_base = 0;618for (i = 0; &adapter[i] != a; i++) {619if (adapter[i].request)620a->li_base = adapter[i].li_base + adapter[i].li_channels;621}622k = li_total_channels + a->li_channels;623new_li_config_table =624(LI_CONFIG *) diva_os_malloc(0, ((k * sizeof(LI_CONFIG) + 3) & ~3) + (2 * k) * ((k + 3) & ~3));625if (new_li_config_table == NULL) {626DBG_ERR(("diva_add_card: failed alloc li_config table."))627memset(a, 0, sizeof(DIVA_CAPI_ADAPTER));628return (0);629}630631/* Prevent access to line interconnect table in process update */632diva_os_enter_spin_lock(&api_lock, &old_irql, "add card");633634j = 0;635for (i = 0; i < k; i++) {636if ((i >= a->li_base) && (i < a->li_base + a->li_channels))637memset(&new_li_config_table[i], 0, sizeof(LI_CONFIG));638else639memcpy(&new_li_config_table[i], &li_config_table[j], sizeof(LI_CONFIG));640new_li_config_table[i].flag_table =641((byte *) new_li_config_table) + (((k * sizeof(LI_CONFIG) + 3) & ~3) + (2 * i) * ((k + 3) & ~3));642new_li_config_table[i].coef_table =643((byte *) new_li_config_table) + (((k * sizeof(LI_CONFIG) + 3) & ~3) + (2 * i + 1) * ((k + 3) & ~3));644if ((i >= a->li_base) && (i < a->li_base + a->li_channels)) {645new_li_config_table[i].adapter = a;646memset(&new_li_config_table[i].flag_table[0], 0, k);647memset(&new_li_config_table[i].coef_table[0], 0, k);648} else {649if (a->li_base != 0) {650memcpy(&new_li_config_table[i].flag_table[0],651&li_config_table[j].flag_table[0],652a->li_base);653memcpy(&new_li_config_table[i].coef_table[0],654&li_config_table[j].coef_table[0],655a->li_base);656}657memset(&new_li_config_table[i].flag_table[a->li_base], 0, a->li_channels);658memset(&new_li_config_table[i].coef_table[a->li_base], 0, a->li_channels);659if (a->li_base + a->li_channels < k) {660memcpy(&new_li_config_table[i].flag_table[a->li_base +661a->li_channels],662&li_config_table[j].flag_table[a->li_base],663k - (a->li_base + a->li_channels));664memcpy(&new_li_config_table[i].coef_table[a->li_base +665a->li_channels],666&li_config_table[j].coef_table[a->li_base],667k - (a->li_base + a->li_channels));668}669j++;670}671}672li_total_channels = k;673674mem_to_free = li_config_table;675676li_config_table = new_li_config_table;677for (i = card->Id; i < max_adapter; i++) {678if (adapter[i].request)679adapter[i].li_base += a->li_channels;680}681682if (a == &adapter[max_adapter])683max_adapter++;684685list_add(&(card->list), &cards);686AutomaticLaw(a);687688diva_os_leave_spin_lock(&api_lock, &old_irql, "add card");689690if (mem_to_free) {691diva_os_free (0, mem_to_free);692}693694i = 0;695while (i++ < 30) {696if (a->automatic_law > 3)697break;698diva_os_sleep(10);699}700701/* profile information */702PUT_WORD(&ctrl->profile.nbchannel, card->d.channels);703ctrl->profile.goptions = a->profile.Global_Options;704ctrl->profile.support1 = a->profile.B1_Protocols;705ctrl->profile.support2 = a->profile.B2_Protocols;706ctrl->profile.support3 = a->profile.B3_Protocols;707/* manufacturer profile information */708ctrl->profile.manu[0] = a->man_profile.private_options;709ctrl->profile.manu[1] = a->man_profile.rtp_primary_payloads;710ctrl->profile.manu[2] = a->man_profile.rtp_additional_payloads;711ctrl->profile.manu[3] = 0;712ctrl->profile.manu[4] = 0;713714capi_ctr_ready(ctrl);715716DBG_TRC(("adapter added, max_adapter=%d", max_adapter));717return (1);718}719720/*721* register appl722*/723static void diva_register_appl(struct capi_ctr *ctrl, __u16 appl,724capi_register_params * rp)725{726APPL *this;727word bnum, xnum;728int i = 0;729unsigned char *p;730void *DataNCCI, *DataFlags, *ReceiveBuffer, *xbuffer_used;731void **xbuffer_ptr, **xbuffer_internal;732diva_os_spin_lock_magic_t old_irql;733unsigned int mem_len;734int nconn = rp->level3cnt;735736737if (diva_os_in_irq()) {738DBG_ERR(("CAPI_REGISTER - in irq context !"))739return;740}741742DBG_TRC(("application register Id=%d", appl))743744if (appl > MAX_APPL) {745DBG_ERR(("CAPI_REGISTER - appl.Id exceeds MAX_APPL"))746return;747}748749if (nconn <= 0)750nconn = ctrl->profile.nbchannel * -nconn;751752if (nconn == 0)753nconn = ctrl->profile.nbchannel;754755DBG_LOG(("CAPI_REGISTER - Id = %d", appl))756DBG_LOG((" MaxLogicalConnections = %d(%d)", nconn, rp->level3cnt))757DBG_LOG((" MaxBDataBuffers = %d", rp->datablkcnt))758DBG_LOG((" MaxBDataLength = %d", rp->datablklen))759760if (nconn < 1 ||761nconn > 255 ||762rp->datablklen < 80 ||763rp->datablklen > 2150 || rp->datablkcnt > 255) {764DBG_ERR(("CAPI_REGISTER - invalid parameters"))765return;766}767768if (application[appl - 1].Id == appl) {769DBG_LOG(("CAPI_REGISTER - appl already registered"))770return; /* appl already registered */771}772773/* alloc memory */774775bnum = nconn * rp->datablkcnt;776xnum = nconn * MAX_DATA_B3;777778mem_len = bnum * sizeof(word); /* DataNCCI */779mem_len += bnum * sizeof(word); /* DataFlags */780mem_len += bnum * rp->datablklen; /* ReceiveBuffer */781mem_len += xnum; /* xbuffer_used */782mem_len += xnum * sizeof(void *); /* xbuffer_ptr */783mem_len += xnum * sizeof(void *); /* xbuffer_internal */784mem_len += xnum * rp->datablklen; /* xbuffer_ptr[xnum] */785786DBG_LOG((" Allocated Memory = %d", mem_len))787if (!(p = diva_os_malloc(0, mem_len))) {788DBG_ERR(("CAPI_REGISTER - memory allocation failed"))789return;790}791memset(p, 0, mem_len);792793DataNCCI = (void *)p;794p += bnum * sizeof(word);795DataFlags = (void *)p;796p += bnum * sizeof(word);797ReceiveBuffer = (void *)p;798p += bnum * rp->datablklen;799xbuffer_used = (void *)p;800p += xnum;801xbuffer_ptr = (void **)p;802p += xnum * sizeof(void *);803xbuffer_internal = (void **)p;804p += xnum * sizeof(void *);805for (i = 0; i < xnum; i++) {806xbuffer_ptr[i] = (void *)p;807p += rp->datablklen;808}809810/* initialize application data */811diva_os_enter_spin_lock(&api_lock, &old_irql, "register_appl");812813this = &application[appl - 1];814memset(this, 0, sizeof(APPL));815816this->Id = appl;817818for (i = 0; i < max_adapter; i++) {819adapter[i].CIP_Mask[appl - 1] = 0;820}821822this->queue_size = 1000;823824this->MaxNCCI = (byte) nconn;825this->MaxNCCIData = (byte) rp->datablkcnt;826this->MaxBuffer = bnum;827this->MaxDataLength = rp->datablklen;828829this->DataNCCI = DataNCCI;830this->DataFlags = DataFlags;831this->ReceiveBuffer = ReceiveBuffer;832this->xbuffer_used = xbuffer_used;833this->xbuffer_ptr = xbuffer_ptr;834this->xbuffer_internal = xbuffer_internal;835for (i = 0; i < xnum; i++) {836this->xbuffer_ptr[i] = xbuffer_ptr[i];837}838839CapiRegister(this->Id);840diva_os_leave_spin_lock(&api_lock, &old_irql, "register_appl");841842}843844/*845* release appl846*/847static void diva_release_appl(struct capi_ctr *ctrl, __u16 appl)848{849diva_os_spin_lock_magic_t old_irql;850APPL *this = &application[appl - 1];851void *mem_to_free = NULL;852853DBG_TRC(("application %d(%d) cleanup", this->Id, appl))854855if (diva_os_in_irq()) {856DBG_ERR(("CAPI_RELEASE - in irq context !"))857return;858}859860diva_os_enter_spin_lock(&api_lock, &old_irql, "release_appl");861if (this->Id) {862CapiRelease(this->Id);863mem_to_free = this->DataNCCI;864this->DataNCCI = NULL;865this->Id = 0;866}867diva_os_leave_spin_lock(&api_lock, &old_irql, "release_appl");868869if (mem_to_free)870diva_os_free(0, mem_to_free);871872}873874/*875* send message876*/877static u16 diva_send_message(struct capi_ctr *ctrl,878diva_os_message_buffer_s * dmb)879{880int i = 0;881word ret = 0;882diva_os_spin_lock_magic_t old_irql;883CAPI_MSG *msg = (CAPI_MSG *) DIVA_MESSAGE_BUFFER_DATA(dmb);884APPL *this = &application[GET_WORD(&msg->header.appl_id) - 1];885diva_card *card = ctrl->driverdata;886__u32 length = DIVA_MESSAGE_BUFFER_LEN(dmb);887word clength = GET_WORD(&msg->header.length);888word command = GET_WORD(&msg->header.command);889u16 retval = CAPI_NOERROR;890891if (diva_os_in_irq()) {892DBG_ERR(("CAPI_SEND_MSG - in irq context !"))893return CAPI_REGOSRESOURCEERR;894}895DBG_PRV1(("Write - appl = %d, cmd = 0x%x", this->Id, command))896897if (card->remove_in_progress) {898DBG_ERR(("CAPI_SEND_MSG - remove in progress!"))899return CAPI_REGOSRESOURCEERR;900}901902diva_os_enter_spin_lock(&api_lock, &old_irql, "send message");903904if (!this->Id) {905diva_os_leave_spin_lock(&api_lock, &old_irql, "send message");906return CAPI_ILLAPPNR;907}908909/* patch controller number */910msg->header.controller = ControllerMap[card->Id]911| (msg->header.controller & 0x80); /* preserve external controller bit */912913switch (command) {914default:915xlog("\x00\x02", msg, 0x80, clength);916break;917918case _DATA_B3_I | RESPONSE:919#ifndef DIVA_NO_DEBUGLIB920if (myDriverDebugHandle.dbgMask & DL_BLK)921xlog("\x00\x02", msg, 0x80, clength);922#endif923break;924925case _DATA_B3_R:926#ifndef DIVA_NO_DEBUGLIB927if (myDriverDebugHandle.dbgMask & DL_BLK)928xlog("\x00\x02", msg, 0x80, clength);929#endif930931if (clength == 24)932clength = 22; /* workaround for PPcom bug */933/* header is always 22 */934if (GET_WORD(&msg->info.data_b3_req.Data_Length) >935this->MaxDataLength936|| GET_WORD(&msg->info.data_b3_req.Data_Length) >937(length - clength)) {938DBG_ERR(("Write - invalid message size"))939retval = CAPI_ILLCMDORSUBCMDORMSGTOSMALL;940goto write_end;941}942943for (i = 0; i < (MAX_DATA_B3 * this->MaxNCCI)944&& this->xbuffer_used[i]; i++);945if (i == (MAX_DATA_B3 * this->MaxNCCI)) {946DBG_ERR(("Write - too many data pending"))947retval = CAPI_SENDQUEUEFULL;948goto write_end;949}950msg->info.data_b3_req.Data = i;951952this->xbuffer_internal[i] = NULL;953memcpy(this->xbuffer_ptr[i], &((__u8 *) msg)[clength],954GET_WORD(&msg->info.data_b3_req.Data_Length));955956#ifndef DIVA_NO_DEBUGLIB957if ((myDriverDebugHandle.dbgMask & DL_BLK)958&& (myDriverDebugHandle.dbgMask & DL_XLOG)) {959int j;960for (j = 0; j <961GET_WORD(&msg->info.data_b3_req.Data_Length);962j += 256) {963DBG_BLK((((char *) this->xbuffer_ptr[i]) + j,964((GET_WORD(&msg->info.data_b3_req.Data_Length) - j) <965256) ? (GET_WORD(&msg->info.data_b3_req.Data_Length) - j) : 256))966if (!(myDriverDebugHandle.dbgMask & DL_PRV0))967break; /* not more if not explicitly requested */968}969}970#endif971break;972}973974memcpy(mapped_msg, msg, (__u32) clength);975mapped_msg->header.controller = MapController(mapped_msg->header.controller);976mapped_msg->header.length = clength;977mapped_msg->header.command = command;978mapped_msg->header.number = GET_WORD(&msg->header.number);979980ret = api_put(this, mapped_msg);981switch (ret) {982case 0:983break;984case _BAD_MSG:985DBG_ERR(("Write - bad message"))986retval = CAPI_ILLCMDORSUBCMDORMSGTOSMALL;987break;988case _QUEUE_FULL:989DBG_ERR(("Write - queue full"))990retval = CAPI_SENDQUEUEFULL;991break;992default:993DBG_ERR(("Write - api_put returned unknown error"))994retval = CAPI_UNKNOWNNOTPAR;995break;996}997998write_end:999diva_os_leave_spin_lock(&api_lock, &old_irql, "send message");1000if (retval == CAPI_NOERROR)1001diva_os_free_message_buffer(dmb);1002return retval;1003}100410051006/*1007* cards request function1008*/1009static void DIRequest(ENTITY * e)1010{1011DIVA_CAPI_ADAPTER *a = &(adapter[(byte) e->user[0]]);1012diva_card *os_card = (diva_card *) a->os_card;10131014if (e->Req && (a->FlowControlIdTable[e->ReqCh] == e->Id)) {1015a->FlowControlSkipTable[e->ReqCh] = 1;1016}10171018(*(os_card->d.request)) (e);1019}10201021/*1022* callback function from didd1023*/1024static void didd_callback(void *context, DESCRIPTOR * adapter, int removal)1025{1026if (adapter->type == IDI_DADAPTER) {1027DBG_ERR(("Notification about IDI_DADAPTER change ! Oops."));1028return;1029} else if (adapter->type == IDI_DIMAINT) {1030if (removal) {1031stop_dbg();1032} else {1033memcpy(&MAdapter, adapter, sizeof(MAdapter));1034dprintf = (DIVA_DI_PRINTF) MAdapter.request;1035DbgRegister("CAPI20", DRIVERRELEASE_CAPI, DBG_DEFAULT);1036}1037} else if ((adapter->type > 0) && (adapter->type < 16)) { /* IDI Adapter */1038if (removal) {1039divacapi_remove_card(adapter);1040} else {1041diva_add_card(adapter);1042}1043}1044return;1045}10461047/*1048* connect to didd1049*/1050static int divacapi_connect_didd(void)1051{1052int x = 0;1053int dadapter = 0;1054IDI_SYNC_REQ req;1055DESCRIPTOR DIDD_Table[MAX_DESCRIPTORS];10561057DIVA_DIDD_Read(DIDD_Table, sizeof(DIDD_Table));10581059for (x = 0; x < MAX_DESCRIPTORS; x++) {1060if (DIDD_Table[x].type == IDI_DIMAINT) { /* MAINT found */1061memcpy(&MAdapter, &DIDD_Table[x], sizeof(DAdapter));1062dprintf = (DIVA_DI_PRINTF) MAdapter.request;1063DbgRegister("CAPI20", DRIVERRELEASE_CAPI, DBG_DEFAULT);1064break;1065}1066}1067for (x = 0; x < MAX_DESCRIPTORS; x++) {1068if (DIDD_Table[x].type == IDI_DADAPTER) { /* DADAPTER found */1069dadapter = 1;1070memcpy(&DAdapter, &DIDD_Table[x], sizeof(DAdapter));1071req.didd_notify.e.Req = 0;1072req.didd_notify.e.Rc =1073IDI_SYNC_REQ_DIDD_REGISTER_ADAPTER_NOTIFY;1074req.didd_notify.info.callback = (void *)didd_callback;1075req.didd_notify.info.context = NULL;1076DAdapter.request((ENTITY *) & req);1077if (req.didd_notify.e.Rc != 0xff) {1078stop_dbg();1079return (0);1080}1081notify_handle = req.didd_notify.info.handle;1082}1083else if ((DIDD_Table[x].type > 0) && (DIDD_Table[x].type < 16)) { /* IDI Adapter found */1084diva_add_card(&DIDD_Table[x]);1085}1086}10871088if (!dadapter) {1089stop_dbg();1090}10911092return (dadapter);1093}10941095/*1096* diconnect from didd1097*/1098static void divacapi_disconnect_didd(void)1099{1100IDI_SYNC_REQ req;11011102stop_dbg();11031104req.didd_notify.e.Req = 0;1105req.didd_notify.e.Rc = IDI_SYNC_REQ_DIDD_REMOVE_ADAPTER_NOTIFY;1106req.didd_notify.info.handle = notify_handle;1107DAdapter.request((ENTITY *) & req);1108}11091110/*1111* we do not provide date/time here,1112* the application should do this.1113*/1114int fax_head_line_time(char *buffer)1115{1116return (0);1117}11181119/*1120* init (alloc) main structures1121*/1122static int DIVA_INIT_FUNCTION init_main_structs(void)1123{1124if (!(mapped_msg = (CAPI_MSG *) diva_os_malloc(0, MAX_MSG_SIZE))) {1125DBG_ERR(("init: failed alloc mapped_msg."))1126return 0;1127}11281129if (!(adapter = diva_os_malloc(0, sizeof(DIVA_CAPI_ADAPTER) * MAX_DESCRIPTORS))) {1130DBG_ERR(("init: failed alloc adapter struct."))1131diva_os_free(0, mapped_msg);1132return 0;1133}1134memset(adapter, 0, sizeof(DIVA_CAPI_ADAPTER) * MAX_DESCRIPTORS);11351136if (!(application = diva_os_malloc(0, sizeof(APPL) * MAX_APPL))) {1137DBG_ERR(("init: failed alloc application struct."))1138diva_os_free(0, mapped_msg);1139diva_os_free(0, adapter);1140return 0;1141}1142memset(application, 0, sizeof(APPL) * MAX_APPL);11431144return (1);1145}11461147/*1148* remove (free) main structures1149*/1150static void remove_main_structs(void)1151{1152if (application)1153diva_os_free(0, application);1154if (adapter)1155diva_os_free(0, adapter);1156if (mapped_msg)1157diva_os_free(0, mapped_msg);1158}11591160/*1161* api_remove_start1162*/1163static void do_api_remove_start(void)1164{1165diva_os_spin_lock_magic_t old_irql;1166int ret = 1, count = 100;11671168do {1169diva_os_enter_spin_lock(&api_lock, &old_irql, "api remove start");1170ret = api_remove_start();1171diva_os_leave_spin_lock(&api_lock, &old_irql, "api remove start");11721173diva_os_sleep(10);1174} while (ret && count--);11751176if (ret)1177DBG_ERR(("could not remove signaling ID's"))1178}11791180/*1181* init1182*/1183int DIVA_INIT_FUNCTION init_capifunc(void)1184{1185diva_os_initialize_spin_lock(&api_lock, "capifunc");1186memset(ControllerMap, 0, MAX_DESCRIPTORS + 1);1187max_adapter = 0;118811891190if (!init_main_structs()) {1191DBG_ERR(("init: failed to init main structs."))1192diva_os_destroy_spin_lock(&api_lock, "capifunc");1193return (0);1194}11951196if (!divacapi_connect_didd()) {1197DBG_ERR(("init: failed to connect to DIDD."))1198do_api_remove_start();1199divacapi_remove_cards();1200remove_main_structs();1201diva_os_destroy_spin_lock(&api_lock, "capifunc");1202return (0);1203}12041205return (1);1206}12071208/*1209* finit1210*/1211void DIVA_EXIT_FUNCTION finit_capifunc(void)1212{1213do_api_remove_start();1214divacapi_disconnect_didd();1215divacapi_remove_cards();1216remove_main_structs();1217diva_os_destroy_spin_lock(&api_lock, "capifunc");1218}121912201221