linux/drivers/isdn/hardware/eicon/debug.c
<<
>>
Prefs
   1#include "platform.h"
   2#include "pc.h"
   3#include "di_defs.h"
   4#include "debug_if.h"
   5#include "divasync.h"
   6#include "kst_ifc.h"
   7#include "maintidi.h"
   8#include "man_defs.h"
   9
  10/*
  11  LOCALS
  12*/
  13#define DBG_MAGIC (0x47114711L)
  14
  15static void DI_register(void *arg);
  16static void DI_deregister(pDbgHandle hDbg);
  17static void DI_format(int do_lock, word id, int type, char *format, va_list argument_list);
  18static void DI_format_locked(word id, int type, char *format, va_list argument_list);
  19static void DI_format_old(word id, char *format, va_list ap) { }
  20static void DiProcessEventLog(unsigned short id, unsigned long msgID, va_list ap) { }
  21static void single_p(byte *P, word *PLength, byte Id);
  22static void diva_maint_xdi_cb(ENTITY *e);
  23static word SuperTraceCreateReadReq(byte *P, const char *path);
  24static int diva_mnt_cmp_nmbr(const char *nmbr);
  25static void diva_free_dma_descriptor(IDI_CALL request, int nr);
  26static int diva_get_dma_descriptor(IDI_CALL request, dword *dma_magic);
  27void diva_mnt_internal_dprintf(dword drv_id, dword type, char *p, ...);
  28
  29static dword MaxDumpSize = 256;
  30static dword MaxXlogSize = 2 + 128;
  31static char  TraceFilter[DIVA_MAX_SELECTIVE_FILTER_LENGTH + 1];
  32static int TraceFilterIdent   = -1;
  33static int TraceFilterChannel = -1;
  34
  35typedef struct _diva_maint_client {
  36        dword       sec;
  37        dword       usec;
  38        pDbgHandle  hDbg;
  39        char        drvName[128];
  40        dword       dbgMask;
  41        dword       last_dbgMask;
  42        IDI_CALL    request;
  43        _DbgHandle_ Dbg;
  44        int         logical;
  45        int         channels;
  46        diva_strace_library_interface_t *pIdiLib;
  47        BUFFERS     XData;
  48        char        xbuffer[2048 + 512];
  49        byte        *pmem;
  50        int         request_pending;
  51        int         dma_handle;
  52} diva_maint_client_t;
  53static diva_maint_client_t clients[MAX_DESCRIPTORS];
  54
  55static void diva_change_management_debug_mask(diva_maint_client_t *pC, dword old_mask);
  56
  57static void diva_maint_error(void *user_context,
  58                             diva_strace_library_interface_t *hLib,
  59                             int Adapter,
  60                             int error,
  61                             const char *file,
  62                             int line);
  63static void diva_maint_state_change_notify(void *user_context,
  64                                           diva_strace_library_interface_t *hLib,
  65                                           int Adapter,
  66                                           diva_trace_line_state_t *channel,
  67                                           int notify_subject);
  68static void diva_maint_trace_notify(void *user_context,
  69                                    diva_strace_library_interface_t *hLib,
  70                                    int Adapter,
  71                                    void *xlog_buffer,
  72                                    int length);
  73
  74
  75
  76typedef struct MSG_QUEUE {
  77        dword   Size;           /* total size of queue (constant)       */
  78        byte    *Base;          /* lowest address (constant)            */
  79        byte    *High;          /* Base + Size (constant)               */
  80        byte    *Head;          /* first message in queue (if any)      */
  81        byte    *Tail;          /* first free position                  */
  82        byte    *Wrap;          /* current wraparound position          */
  83        dword   Count;          /* current no of bytes in queue         */
  84} MSG_QUEUE;
  85
  86typedef struct MSG_HEAD {
  87        volatile dword  Size;           /* size of data following MSG_HEAD      */
  88#define MSG_INCOMPLETE  0x8000  /* ored to Size until queueCompleteMsg  */
  89} MSG_HEAD;
  90
  91#define queueCompleteMsg(p) do { ((MSG_HEAD *)p - 1)->Size &= ~MSG_INCOMPLETE; } while (0)
  92#define queueCount(q)   ((q)->Count)
  93#define MSG_NEED(size)                                                  \
  94        ((sizeof(MSG_HEAD) + size + sizeof(dword) - 1) & ~(sizeof(dword) - 1))
  95
  96static void queueInit(MSG_QUEUE *Q, byte *Buffer, dword sizeBuffer) {
  97        Q->Size = sizeBuffer;
  98        Q->Base = Q->Head = Q->Tail = Buffer;
  99        Q->High = Buffer + sizeBuffer;
 100        Q->Wrap = NULL;
 101        Q->Count = 0;
 102}
 103
 104static byte *queueAllocMsg(MSG_QUEUE *Q, word size) {
 105        /* Allocate 'size' bytes at tail of queue which will be filled later
 106         * directly with callers own message header info and/or message.
 107         * An 'alloced' message is marked incomplete by oring the 'Size' field
 108         * with MSG_INCOMPLETE.
 109         * This must be reset via queueCompleteMsg() after the message is filled.
 110         * As long as a message is marked incomplete queuePeekMsg() will return
 111         * a 'queue empty' condition when it reaches such a message.  */
 112
 113        MSG_HEAD *Msg;
 114        word need = MSG_NEED(size);
 115
 116        if (Q->Tail == Q->Head) {
 117                if (Q->Wrap || need > Q->Size) {
 118                        return NULL; /* full */
 119                }
 120                goto alloc; /* empty */
 121        }
 122
 123        if (Q->Tail > Q->Head) {
 124                if (Q->Tail + need <= Q->High) goto alloc; /* append */
 125                if (Q->Base + need > Q->Head) {
 126                        return NULL; /* too much */
 127                }
 128                /* wraparound the queue (but not the message) */
 129                Q->Wrap = Q->Tail;
 130                Q->Tail = Q->Base;
 131                goto alloc;
 132        }
 133
 134        if (Q->Tail + need > Q->Head) {
 135                return NULL; /* too much */
 136        }
 137
 138alloc:
 139        Msg = (MSG_HEAD *)Q->Tail;
 140
 141        Msg->Size = size | MSG_INCOMPLETE;
 142
 143        Q->Tail  += need;
 144        Q->Count += size;
 145
 146
 147
 148        return ((byte *)(Msg + 1));
 149}
 150
 151static void queueFreeMsg(MSG_QUEUE *Q) {
 152/* Free the message at head of queue */
 153
 154        word size = ((MSG_HEAD *)Q->Head)->Size & ~MSG_INCOMPLETE;
 155
 156        Q->Head  += MSG_NEED(size);
 157        Q->Count -= size;
 158
 159        if (Q->Wrap) {
 160                if (Q->Head >= Q->Wrap) {
 161                        Q->Head = Q->Base;
 162                        Q->Wrap = NULL;
 163                }
 164        } else if (Q->Head >= Q->Tail) {
 165                Q->Head = Q->Tail = Q->Base;
 166        }
 167}
 168
 169static byte *queuePeekMsg(MSG_QUEUE *Q, word *size) {
 170        /* Show the first valid message in queue BUT DON'T free the message.
 171         * After looking on the message contents it can be freed queueFreeMsg()
 172         * or simply remain in message queue.  */
 173
 174        MSG_HEAD *Msg = (MSG_HEAD *)Q->Head;
 175
 176        if (((byte *)Msg == Q->Tail && !Q->Wrap) ||
 177            (Msg->Size & MSG_INCOMPLETE)) {
 178                return NULL;
 179        } else {
 180                *size = Msg->Size;
 181                return ((byte *)(Msg + 1));
 182        }
 183}
 184
 185/*
 186  Message queue header
 187*/
 188static MSG_QUEUE *dbg_queue;
 189static byte *dbg_base;
 190static int                 external_dbg_queue;
 191static diva_os_spin_lock_t dbg_q_lock;
 192static diva_os_spin_lock_t dbg_adapter_lock;
 193static int                 dbg_q_busy;
 194static volatile dword      dbg_sequence;
 195static dword               start_sec;
 196static dword               start_usec;
 197
 198/*
 199  INTERFACE:
 200  Initialize run time queue structures.
 201  base:    base of the message queue
 202  length:  length of the message queue
 203  do_init: perfor queue reset
 204
 205  return:  zero on success, -1 on error
 206*/
 207int diva_maint_init(byte *base, unsigned long length, int do_init) {
 208        if (dbg_queue || (!base) || (length < (4096 * 4))) {
 209                return (-1);
 210        }
 211
 212        TraceFilter[0]     =  0;
 213        TraceFilterIdent   = -1;
 214        TraceFilterChannel = -1;
 215
 216        dbg_base = base;
 217
 218        diva_os_get_time(&start_sec, &start_usec);
 219
 220        *(dword *)base  = (dword)DBG_MAGIC; /* Store Magic */
 221        base   += sizeof(dword);
 222        length -= sizeof(dword);
 223
 224        *(dword *)base = 2048; /* Extension Field Length */
 225        base   += sizeof(dword);
 226        length -= sizeof(dword);
 227
 228        strcpy(base, "KERNEL MODE BUFFER\n");
 229        base   += 2048;
 230        length -= 2048;
 231
 232        *(dword *)base = 0; /* Terminate extension */
 233        base   += sizeof(dword);
 234        length -= sizeof(dword);
 235
 236        *(void **)base  =  (void *)(base + sizeof(void *)); /* Store Base  */
 237        base   += sizeof(void *);
 238        length -= sizeof(void *);
 239
 240        dbg_queue = (MSG_QUEUE *)base;
 241        queueInit(dbg_queue, base + sizeof(MSG_QUEUE), length - sizeof(MSG_QUEUE) - 512);
 242        external_dbg_queue = 0;
 243
 244        if (!do_init) {
 245                external_dbg_queue = 1; /* memory was located on the external device */
 246        }
 247
 248
 249        if (diva_os_initialize_spin_lock(&dbg_q_lock, "dbg_init")) {
 250                dbg_queue = NULL;
 251                dbg_base = NULL;
 252                external_dbg_queue = 0;
 253                return (-1);
 254        }
 255
 256        if (diva_os_initialize_spin_lock(&dbg_adapter_lock, "dbg_init")) {
 257                diva_os_destroy_spin_lock(&dbg_q_lock, "dbg_init");
 258                dbg_queue = NULL;
 259                dbg_base = NULL;
 260                external_dbg_queue = 0;
 261                return (-1);
 262        }
 263
 264        return (0);
 265}
 266
 267/*
 268  INTERFACE:
 269  Finit at unload time
 270  return address of internal queue or zero if queue
 271  was external
 272*/
 273void *diva_maint_finit(void) {
 274        void *ret = (void *)dbg_base;
 275        int i;
 276
 277        dbg_queue = NULL;
 278        dbg_base  = NULL;
 279
 280        if (ret) {
 281                diva_os_destroy_spin_lock(&dbg_q_lock, "dbg_finit");
 282                diva_os_destroy_spin_lock(&dbg_adapter_lock, "dbg_finit");
 283        }
 284
 285        if (external_dbg_queue) {
 286                ret = NULL;
 287        }
 288        external_dbg_queue = 0;
 289
 290        for (i = 1; i < ARRAY_SIZE(clients); i++) {
 291                if (clients[i].pmem) {
 292                        diva_os_free(0, clients[i].pmem);
 293                }
 294        }
 295
 296        return (ret);
 297}
 298
 299/*
 300  INTERFACE:
 301  Return amount of messages in debug queue
 302*/
 303dword diva_dbg_q_length(void) {
 304        return (dbg_queue ? queueCount(dbg_queue)       : 0);
 305}
 306
 307/*
 308  INTERFACE:
 309  Lock message queue and return the pointer to the first
 310  entry.
 311*/
 312diva_dbg_entry_head_t *diva_maint_get_message(word *size,
 313                                              diva_os_spin_lock_magic_t *old_irql) {
 314        diva_dbg_entry_head_t *pmsg = NULL;
 315
 316        diva_os_enter_spin_lock(&dbg_q_lock, old_irql, "read");
 317        if (dbg_q_busy) {
 318                diva_os_leave_spin_lock(&dbg_q_lock, old_irql, "read_busy");
 319                return NULL;
 320        }
 321        dbg_q_busy = 1;
 322
 323        if (!(pmsg = (diva_dbg_entry_head_t *)queuePeekMsg(dbg_queue, size))) {
 324                dbg_q_busy = 0;
 325                diva_os_leave_spin_lock(&dbg_q_lock, old_irql, "read_empty");
 326        }
 327
 328        return (pmsg);
 329}
 330
 331/*
 332  INTERFACE:
 333  acknowledge last message and unlock queue
 334*/
 335void diva_maint_ack_message(int do_release,
 336                            diva_os_spin_lock_magic_t *old_irql) {
 337        if (!dbg_q_busy) {
 338                return;
 339        }
 340        if (do_release) {
 341                queueFreeMsg(dbg_queue);
 342        }
 343        dbg_q_busy = 0;
 344        diva_os_leave_spin_lock(&dbg_q_lock, old_irql, "read_ack");
 345}
 346
 347
 348/*
 349  INTERFACE:
 350  PRT COMP function used to register
 351  with MAINT adapter or log in compatibility
 352  mode in case older driver version is connected too
 353*/
 354void diva_maint_prtComp(char *format, ...) {
 355        void    *hDbg;
 356        va_list ap;
 357
 358        if (!format)
 359                return;
 360
 361        va_start(ap, format);
 362
 363        /*
 364          register to new log driver functions
 365        */
 366        if ((format[0] == 0) && ((unsigned char)format[1] == 255)) {
 367                hDbg = va_arg(ap, void *); /* ptr to DbgHandle */
 368                DI_register(hDbg);
 369        }
 370
 371        va_end(ap);
 372}
 373
 374static void DI_register(void *arg) {
 375        diva_os_spin_lock_magic_t old_irql;
 376        dword sec, usec;
 377        pDbgHandle      hDbg;
 378        int id, free_id = -1, best_id = 0;
 379
 380        diva_os_get_time(&sec, &usec);
 381
 382        hDbg = (pDbgHandle)arg;
 383        /*
 384          Check for bad args, specially for the old obsolete debug handle
 385        */
 386        if ((hDbg == NULL) ||
 387            ((hDbg->id == 0) && (((_OldDbgHandle_ *)hDbg)->id == -1)) ||
 388            (hDbg->Registered != 0)) {
 389                return;
 390        }
 391
 392        diva_os_enter_spin_lock(&dbg_q_lock, &old_irql, "register");
 393
 394        for (id = 1; id < ARRAY_SIZE(clients); id++) {
 395                if (clients[id].hDbg == hDbg) {
 396                        /*
 397                          driver already registered
 398                        */
 399                        diva_os_leave_spin_lock(&dbg_q_lock, &old_irql, "register");
 400                        return;
 401                }
 402                if (clients[id].hDbg) { /* slot is busy */
 403                        continue;
 404                }
 405                free_id = id;
 406                if (!strcmp(clients[id].drvName, hDbg->drvName)) {
 407                        /*
 408                          This driver was already registered with this name
 409                          and slot is still free - reuse it
 410                        */
 411                        best_id = 1;
 412                        break;
 413                }
 414                if (!clients[id].hDbg) { /* slot is busy */
 415                        break;
 416                }
 417        }
 418
 419        if (free_id != -1) {
 420                diva_dbg_entry_head_t *pmsg = NULL;
 421                int len;
 422                char tmp[256];
 423                word size;
 424
 425                /*
 426                  Register new driver with id == free_id
 427                */
 428                clients[free_id].hDbg = hDbg;
 429                clients[free_id].sec  = sec;
 430                clients[free_id].usec = usec;
 431                strcpy(clients[free_id].drvName, hDbg->drvName);
 432
 433                clients[free_id].dbgMask = hDbg->dbgMask;
 434                if (best_id) {
 435                        hDbg->dbgMask |= clients[free_id].last_dbgMask;
 436                } else {
 437                        clients[free_id].last_dbgMask = 0;
 438                }
 439
 440                hDbg->Registered = DBG_HANDLE_REG_NEW;
 441                hDbg->id         = (byte)free_id;
 442                hDbg->dbg_end    = DI_deregister;
 443                hDbg->dbg_prt    = DI_format_locked;
 444                hDbg->dbg_ev     = DiProcessEventLog;
 445                hDbg->dbg_irq    = DI_format_locked;
 446                if (hDbg->Version > 0) {
 447                        hDbg->dbg_old  = DI_format_old;
 448                }
 449                hDbg->next       = (pDbgHandle)DBG_MAGIC;
 450
 451                /*
 452                  Log driver register, MAINT driver ID is '0'
 453                */
 454                len = sprintf(tmp, "DIMAINT - drv # %d = '%s' registered",
 455                              free_id, hDbg->drvName);
 456
 457                while (!(pmsg = (diva_dbg_entry_head_t *)queueAllocMsg(dbg_queue,
 458                                                                       (word)(len + 1 + sizeof(*pmsg))))) {
 459                        if ((pmsg = (diva_dbg_entry_head_t *)queuePeekMsg(dbg_queue, &size))) {
 460                                queueFreeMsg(dbg_queue);
 461                        } else {
 462                                break;
 463                        }
 464                }
 465
 466                if (pmsg) {
 467                        pmsg->sequence    = dbg_sequence++;
 468                        pmsg->time_sec    = sec;
 469                        pmsg->time_usec   = usec;
 470                        pmsg->facility    = MSG_TYPE_STRING;
 471                        pmsg->dli         = DLI_REG;
 472                        pmsg->drv_id      = 0; /* id 0 - DIMAINT */
 473                        pmsg->di_cpu      = 0;
 474                        pmsg->data_length = len + 1;
 475
 476                        memcpy(&pmsg[1], tmp, len + 1);
 477                        queueCompleteMsg(pmsg);
 478                        diva_maint_wakeup_read();
 479                }
 480        }
 481
 482        diva_os_leave_spin_lock(&dbg_q_lock, &old_irql, "register");
 483}
 484
 485static void DI_deregister(pDbgHandle hDbg) {
 486        diva_os_spin_lock_magic_t old_irql, old_irql1;
 487        dword sec, usec;
 488        int i;
 489        word size;
 490        byte *pmem = NULL;
 491
 492        diva_os_get_time(&sec, &usec);
 493
 494        diva_os_enter_spin_lock(&dbg_adapter_lock, &old_irql1, "read");
 495        diva_os_enter_spin_lock(&dbg_q_lock, &old_irql, "read");
 496
 497        for (i = 1; i < ARRAY_SIZE(clients); i++) {
 498                if (clients[i].hDbg == hDbg) {
 499                        diva_dbg_entry_head_t *pmsg;
 500                        char tmp[256];
 501                        int len;
 502
 503                        clients[i].hDbg = NULL;
 504
 505                        hDbg->id       = -1;
 506                        hDbg->dbgMask  = 0;
 507                        hDbg->dbg_end  = NULL;
 508                        hDbg->dbg_prt  = NULL;
 509                        hDbg->dbg_irq  = NULL;
 510                        if (hDbg->Version > 0)
 511                                hDbg->dbg_old = NULL;
 512                        hDbg->Registered = 0;
 513                        hDbg->next     = NULL;
 514
 515                        if (clients[i].pIdiLib) {
 516                                (*(clients[i].pIdiLib->DivaSTraceLibraryFinit))(clients[i].pIdiLib->hLib);
 517                                clients[i].pIdiLib = NULL;
 518
 519                                pmem = clients[i].pmem;
 520                                clients[i].pmem = NULL;
 521                        }
 522
 523                        /*
 524                          Log driver register, MAINT driver ID is '0'
 525                        */
 526                        len = sprintf(tmp, "DIMAINT - drv # %d = '%s' de-registered",
 527                                      i, hDbg->drvName);
 528
 529                        while (!(pmsg = (diva_dbg_entry_head_t *)queueAllocMsg(dbg_queue,
 530                                                                              (word)(len + 1 + sizeof(*pmsg))))) {
 531                                if ((pmsg = (diva_dbg_entry_head_t *)queuePeekMsg(dbg_queue, &size))) {
 532                                        queueFreeMsg(dbg_queue);
 533                                } else {
 534                                        break;
 535                                }
 536                        }
 537
 538                        if (pmsg) {
 539                                pmsg->sequence    = dbg_sequence++;
 540                                pmsg->time_sec    = sec;
 541                                pmsg->time_usec   = usec;
 542                                pmsg->facility    = MSG_TYPE_STRING;
 543                                pmsg->dli         = DLI_REG;
 544                                pmsg->drv_id      = 0; /* id 0 - DIMAINT */
 545                                pmsg->di_cpu      = 0;
 546                                pmsg->data_length = len + 1;
 547
 548                                memcpy(&pmsg[1], tmp, len + 1);
 549                                queueCompleteMsg(pmsg);
 550                                diva_maint_wakeup_read();
 551                        }
 552
 553                        break;
 554                }
 555        }
 556
 557        diva_os_leave_spin_lock(&dbg_q_lock, &old_irql, "read_ack");
 558        diva_os_leave_spin_lock(&dbg_adapter_lock, &old_irql1, "read_ack");
 559
 560        if (pmem) {
 561                diva_os_free(0, pmem);
 562        }
 563}
 564
 565static void DI_format_locked(unsigned short id,
 566                             int type,
 567                             char *format,
 568                             va_list argument_list) {
 569        DI_format(1, id, type, format, argument_list);
 570}
 571
 572static void DI_format(int do_lock,
 573                      unsigned short id,
 574                      int type,
 575                      char *format,
 576                      va_list ap) {
 577        diva_os_spin_lock_magic_t old_irql;
 578        dword sec, usec;
 579        diva_dbg_entry_head_t *pmsg = NULL;
 580        dword length;
 581        word size;
 582        static char fmtBuf[MSG_FRAME_MAX_SIZE + sizeof(*pmsg) + 1];
 583        char          *data;
 584        unsigned short code;
 585
 586        if (diva_os_in_irq()) {
 587                dbg_sequence++;
 588                return;
 589        }
 590
 591        if ((!format) ||
 592            ((TraceFilter[0] != 0) && ((TraceFilterIdent < 0) || (TraceFilterChannel < 0)))) {
 593                return;
 594        }
 595
 596
 597
 598        diva_os_get_time(&sec, &usec);
 599
 600        if (do_lock) {
 601                diva_os_enter_spin_lock(&dbg_q_lock, &old_irql, "format");
 602        }
 603
 604        switch (type) {
 605        case DLI_MXLOG:
 606        case DLI_BLK:
 607        case DLI_SEND:
 608        case DLI_RECV:
 609                if (!(length = va_arg(ap, unsigned long))) {
 610                        break;
 611                }
 612                if (length > MaxDumpSize) {
 613                        length = MaxDumpSize;
 614                }
 615                while (!(pmsg = (diva_dbg_entry_head_t *)queueAllocMsg(dbg_queue,
 616                                                                       (word)length + sizeof(*pmsg)))) {
 617                        if ((pmsg = (diva_dbg_entry_head_t *)queuePeekMsg(dbg_queue, &size))) {
 618                                queueFreeMsg(dbg_queue);
 619                        } else {
 620                                break;
 621                        }
 622                }
 623                if (pmsg) {
 624                        memcpy(&pmsg[1], format, length);
 625                        pmsg->sequence    = dbg_sequence++;
 626                        pmsg->time_sec    = sec;
 627                        pmsg->time_usec   = usec;
 628                        pmsg->facility    = MSG_TYPE_BINARY;
 629                        pmsg->dli         = type; /* DLI_XXX */
 630                        pmsg->drv_id      = id;   /* driver MAINT id */
 631                        pmsg->di_cpu      = 0;
 632                        pmsg->data_length = length;
 633                        queueCompleteMsg(pmsg);
 634                }
 635                break;
 636
 637        case DLI_XLOG: {
 638                byte *p;
 639                data    = va_arg(ap, char *);
 640                code    = (unsigned short)va_arg(ap, unsigned int);
 641                length  = (unsigned long)va_arg(ap, unsigned int);
 642
 643                if (length > MaxXlogSize)
 644                        length = MaxXlogSize;
 645
 646                while (!(pmsg = (diva_dbg_entry_head_t *)queueAllocMsg(dbg_queue,
 647                                                                      (word)length + sizeof(*pmsg) + 2))) {
 648                        if ((pmsg = (diva_dbg_entry_head_t *)queuePeekMsg(dbg_queue, &size))) {
 649                                queueFreeMsg(dbg_queue);
 650                        } else {
 651                                break;
 652                        }
 653                }
 654                if (pmsg) {
 655                        p = (byte *)&pmsg[1];
 656                        p[0] = (char)(code);
 657                        p[1] = (char)(code >> 8);
 658                        if (data && length) {
 659                                memcpy(&p[2], &data[0], length);
 660                        }
 661                        length += 2;
 662
 663                        pmsg->sequence    = dbg_sequence++;
 664                        pmsg->time_sec    = sec;
 665                        pmsg->time_usec   = usec;
 666                        pmsg->facility    = MSG_TYPE_BINARY;
 667                        pmsg->dli         = type; /* DLI_XXX */
 668                        pmsg->drv_id      = id;   /* driver MAINT id */
 669                        pmsg->di_cpu      = 0;
 670                        pmsg->data_length = length;
 671                        queueCompleteMsg(pmsg);
 672                }
 673        } break;
 674
 675        case DLI_LOG:
 676        case DLI_FTL:
 677        case DLI_ERR:
 678        case DLI_TRC:
 679        case DLI_REG:
 680        case DLI_MEM:
 681        case DLI_SPL:
 682        case DLI_IRP:
 683        case DLI_TIM:
 684        case DLI_TAPI:
 685        case DLI_NDIS:
 686        case DLI_CONN:
 687        case DLI_STAT:
 688        case DLI_PRV0:
 689        case DLI_PRV1:
 690        case DLI_PRV2:
 691        case DLI_PRV3:
 692                if ((length = (unsigned long)vsprintf(&fmtBuf[0], format, ap)) > 0) {
 693                        length += (sizeof(*pmsg) + 1);
 694
 695                        while (!(pmsg = (diva_dbg_entry_head_t *)queueAllocMsg(dbg_queue,
 696                                                                               (word)length))) {
 697                                if ((pmsg = (diva_dbg_entry_head_t *)queuePeekMsg(dbg_queue, &size))) {
 698                                        queueFreeMsg(dbg_queue);
 699                                } else {
 700                                        break;
 701                                }
 702                        }
 703
 704                        pmsg->sequence    = dbg_sequence++;
 705                        pmsg->time_sec    = sec;
 706                        pmsg->time_usec   = usec;
 707                        pmsg->facility    = MSG_TYPE_STRING;
 708                        pmsg->dli         = type; /* DLI_XXX */
 709                        pmsg->drv_id      = id;   /* driver MAINT id */
 710                        pmsg->di_cpu      = 0;
 711                        pmsg->data_length = length - sizeof(*pmsg);
 712
 713                        memcpy(&pmsg[1], fmtBuf, pmsg->data_length);
 714                        queueCompleteMsg(pmsg);
 715                }
 716                break;
 717
 718        } /* switch type */
 719
 720
 721        if (queueCount(dbg_queue)) {
 722                diva_maint_wakeup_read();
 723        }
 724
 725        if (do_lock) {
 726                diva_os_leave_spin_lock(&dbg_q_lock, &old_irql, "format");
 727        }
 728}
 729
 730/*
 731  Write driver ID and driver revision to callers buffer
 732*/
 733int diva_get_driver_info(dword id, byte *data, int data_length) {
 734        diva_os_spin_lock_magic_t old_irql;
 735        byte *p = data;
 736        int to_copy;
 737
 738        if (!data || !id || (data_length < 17) ||
 739            (id >= ARRAY_SIZE(clients))) {
 740                return (-1);
 741        }
 742
 743        diva_os_enter_spin_lock(&dbg_q_lock, &old_irql, "driver info");
 744
 745        if (clients[id].hDbg) {
 746                *p++ = 1;
 747                *p++ = (byte)clients[id].sec; /* save seconds */
 748                *p++ = (byte)(clients[id].sec >>  8);
 749                *p++ = (byte)(clients[id].sec >> 16);
 750                *p++ = (byte)(clients[id].sec >> 24);
 751
 752                *p++ = (byte)(clients[id].usec / 1000); /* save mseconds */
 753                *p++ = (byte)((clients[id].usec / 1000) >>  8);
 754                *p++ = (byte)((clients[id].usec / 1000) >> 16);
 755                *p++ = (byte)((clients[id].usec / 1000) >> 24);
 756
 757                data_length -= 9;
 758
 759                if ((to_copy = min(strlen(clients[id].drvName), (size_t)(data_length - 1)))) {
 760                        memcpy(p, clients[id].drvName, to_copy);
 761                        p += to_copy;
 762                        data_length -= to_copy;
 763                        if ((data_length >= 4) && clients[id].hDbg->drvTag[0]) {
 764                                *p++ = '(';
 765                                data_length -= 1;
 766                                if ((to_copy = min(strlen(clients[id].hDbg->drvTag), (size_t)(data_length - 2)))) {
 767                                        memcpy(p, clients[id].hDbg->drvTag, to_copy);
 768                                        p += to_copy;
 769                                        data_length -= to_copy;
 770                                        if (data_length >= 2) {
 771                                                *p++ = ')';
 772                                                data_length--;
 773                                        }
 774                                }
 775                        }
 776                }
 777        }
 778        *p++ = 0;
 779
 780        diva_os_leave_spin_lock(&dbg_q_lock, &old_irql, "driver info");
 781
 782        return (p - data);
 783}
 784
 785int diva_get_driver_dbg_mask(dword id, byte *data) {
 786        diva_os_spin_lock_magic_t old_irql;
 787        int ret = -1;
 788
 789        if (!data || !id || (id >= ARRAY_SIZE(clients))) {
 790                return (-1);
 791        }
 792        diva_os_enter_spin_lock(&dbg_q_lock, &old_irql, "driver info");
 793
 794        if (clients[id].hDbg) {
 795                ret = 4;
 796                *data++ = (byte)(clients[id].hDbg->dbgMask);
 797                *data++ = (byte)(clients[id].hDbg->dbgMask >>  8);
 798                *data++ = (byte)(clients[id].hDbg->dbgMask >> 16);
 799                *data++ = (byte)(clients[id].hDbg->dbgMask >> 24);
 800        }
 801
 802        diva_os_leave_spin_lock(&dbg_q_lock, &old_irql, "driver info");
 803
 804        return (ret);
 805}
 806
 807int diva_set_driver_dbg_mask(dword id, dword mask) {
 808        diva_os_spin_lock_magic_t old_irql, old_irql1;
 809        int ret = -1;
 810
 811
 812        if (!id || (id >= ARRAY_SIZE(clients))) {
 813                return (-1);
 814        }
 815
 816        diva_os_enter_spin_lock(&dbg_adapter_lock, &old_irql1, "dbg mask");
 817        diva_os_enter_spin_lock(&dbg_q_lock, &old_irql, "dbg mask");
 818
 819        if (clients[id].hDbg) {
 820                dword old_mask = clients[id].hDbg->dbgMask;
 821                mask &= 0x7fffffff;
 822                clients[id].hDbg->dbgMask = mask;
 823                clients[id].last_dbgMask = (clients[id].hDbg->dbgMask | clients[id].dbgMask);
 824                ret = 4;
 825                diva_change_management_debug_mask(&clients[id], old_mask);
 826        }
 827
 828
 829        diva_os_leave_spin_lock(&dbg_q_lock, &old_irql, "dbg mask");
 830
 831        if (clients[id].request_pending) {
 832                clients[id].request_pending = 0;
 833                (*(clients[id].request))((ENTITY *)(*(clients[id].pIdiLib->DivaSTraceGetHandle))(clients[id].pIdiLib->hLib));
 834        }
 835
 836        diva_os_leave_spin_lock(&dbg_adapter_lock, &old_irql1, "dbg mask");
 837
 838        return (ret);
 839}
 840
 841static int diva_get_idi_adapter_info(IDI_CALL request, dword *serial, dword *logical) {
 842        IDI_SYNC_REQ sync_req;
 843
 844        sync_req.xdi_logical_adapter_number.Req = 0;
 845        sync_req.xdi_logical_adapter_number.Rc = IDI_SYNC_REQ_XDI_GET_LOGICAL_ADAPTER_NUMBER;
 846        (*request)((ENTITY *)&sync_req);
 847        *logical = sync_req.xdi_logical_adapter_number.info.logical_adapter_number;
 848
 849        sync_req.GetSerial.Req = 0;
 850        sync_req.GetSerial.Rc = IDI_SYNC_REQ_GET_SERIAL;
 851        sync_req.GetSerial.serial = 0;
 852        (*request)((ENTITY *)&sync_req);
 853        *serial = sync_req.GetSerial.serial;
 854
 855        return (0);
 856}
 857
 858/*
 859  Register XDI adapter as MAINT compatible driver
 860*/
 861void diva_mnt_add_xdi_adapter(const DESCRIPTOR *d) {
 862        diva_os_spin_lock_magic_t old_irql, old_irql1;
 863        dword sec, usec, logical, serial, org_mask;
 864        int id, free_id = -1;
 865        char tmp[128];
 866        diva_dbg_entry_head_t *pmsg = NULL;
 867        int len;
 868        word size;
 869        byte *pmem;
 870
 871        diva_os_get_time(&sec, &usec);
 872        diva_get_idi_adapter_info(d->request, &serial, &logical);
 873        if (serial & 0xff000000) {
 874                sprintf(tmp, "ADAPTER:%d SN:%u-%d",
 875                        (int)logical,
 876                        serial & 0x00ffffff,
 877                        (byte)(((serial & 0xff000000) >> 24) + 1));
 878        } else {
 879                sprintf(tmp, "ADAPTER:%d SN:%u", (int)logical, serial);
 880        }
 881
 882        if (!(pmem = diva_os_malloc(0, DivaSTraceGetMemotyRequirement(d->channels)))) {
 883                return;
 884        }
 885        memset(pmem, 0x00, DivaSTraceGetMemotyRequirement(d->channels));
 886
 887        diva_os_enter_spin_lock(&dbg_adapter_lock, &old_irql1, "register");
 888        diva_os_enter_spin_lock(&dbg_q_lock, &old_irql, "register");
 889
 890        for (id = 1; id < ARRAY_SIZE(clients); id++) {
 891                if (clients[id].hDbg && (clients[id].request == d->request)) {
 892                        diva_os_leave_spin_lock(&dbg_q_lock, &old_irql, "register");
 893                        diva_os_leave_spin_lock(&dbg_adapter_lock, &old_irql1, "register");
 894                        diva_os_free(0, pmem);
 895                        return;
 896                }
 897                if (clients[id].hDbg) { /* slot is busy */
 898                        continue;
 899                }
 900                if (free_id < 0) {
 901                        free_id = id;
 902                }
 903                if (!strcmp(clients[id].drvName, tmp)) {
 904                        /*
 905                          This driver was already registered with this name
 906                          and slot is still free - reuse it
 907                        */
 908                        free_id = id;
 909                        break;
 910                }
 911        }
 912
 913        if (free_id < 0) {
 914                diva_os_leave_spin_lock(&dbg_q_lock, &old_irql, "register");
 915                diva_os_leave_spin_lock(&dbg_adapter_lock, &old_irql1, "register");
 916                diva_os_free(0, pmem);
 917                return;
 918        }
 919
 920        id = free_id;
 921        clients[id].request  = d->request;
 922        clients[id].request_pending = 0;
 923        clients[id].hDbg     = &clients[id].Dbg;
 924        clients[id].sec      = sec;
 925        clients[id].usec     = usec;
 926        strcpy(clients[id].drvName,     tmp);
 927        strcpy(clients[id].Dbg.drvName, tmp);
 928        clients[id].Dbg.drvTag[0] = 0;
 929        clients[id].logical  = (int)logical;
 930        clients[id].channels = (int)d->channels;
 931        clients[id].dma_handle = -1;
 932
 933        clients[id].Dbg.dbgMask    = 0;
 934        clients[id].dbgMask        = clients[id].Dbg.dbgMask;
 935        if (id) {
 936                clients[id].Dbg.dbgMask |= clients[free_id].last_dbgMask;
 937        } else {
 938                clients[id].last_dbgMask = 0;
 939        }
 940        clients[id].Dbg.Registered = DBG_HANDLE_REG_NEW;
 941        clients[id].Dbg.id         = (byte)id;
 942        clients[id].Dbg.dbg_end    = DI_deregister;
 943        clients[id].Dbg.dbg_prt    = DI_format_locked;
 944        clients[id].Dbg.dbg_ev     = DiProcessEventLog;
 945        clients[id].Dbg.dbg_irq    = DI_format_locked;
 946        clients[id].Dbg.next       = (pDbgHandle)DBG_MAGIC;
 947
 948        {
 949                diva_trace_library_user_interface_t diva_maint_user_ifc = { &clients[id],
 950                                                                            diva_maint_state_change_notify,
 951                                                                            diva_maint_trace_notify,
 952                                                                            diva_maint_error };
 953
 954                /*
 955                  Attach to adapter management interface
 956                */
 957                if ((clients[id].pIdiLib =
 958                     DivaSTraceLibraryCreateInstance((int)logical, &diva_maint_user_ifc, pmem))) {
 959                        if (((*(clients[id].pIdiLib->DivaSTraceLibraryStart))(clients[id].pIdiLib->hLib))) {
 960                                diva_mnt_internal_dprintf(0, DLI_ERR, "Adapter(%d) Start failed", (int)logical);
 961                                (*(clients[id].pIdiLib->DivaSTraceLibraryFinit))(clients[id].pIdiLib->hLib);
 962                                clients[id].pIdiLib = NULL;
 963                        }
 964                } else {
 965                        diva_mnt_internal_dprintf(0, DLI_ERR, "A(%d) management init failed", (int)logical);
 966                }
 967        }
 968
 969        if (!clients[id].pIdiLib) {
 970                clients[id].request = NULL;
 971                clients[id].request_pending = 0;
 972                clients[id].hDbg    = NULL;
 973                diva_os_leave_spin_lock(&dbg_q_lock, &old_irql, "register");
 974                diva_os_leave_spin_lock(&dbg_adapter_lock, &old_irql1, "register");
 975                diva_os_free(0, pmem);
 976                return;
 977        }
 978
 979        /*
 980          Log driver register, MAINT driver ID is '0'
 981        */
 982        len = sprintf(tmp, "DIMAINT - drv # %d = '%s' registered",
 983                      id, clients[id].Dbg.drvName);
 984
 985        while (!(pmsg = (diva_dbg_entry_head_t *)queueAllocMsg(dbg_queue,
 986                                                               (word)(len + 1 + sizeof(*pmsg))))) {
 987                if ((pmsg = (diva_dbg_entry_head_t *)queuePeekMsg(dbg_queue, &size))) {
 988                        queueFreeMsg(dbg_queue);
 989                } else {
 990                        break;
 991                }
 992        }
 993
 994        if (pmsg) {
 995                pmsg->sequence    = dbg_sequence++;
 996                pmsg->time_sec    = sec;
 997                pmsg->time_usec   = usec;
 998                pmsg->facility    = MSG_TYPE_STRING;
 999                pmsg->dli         = DLI_REG;
1000                pmsg->drv_id      = 0; /* id 0 - DIMAINT */
1001                pmsg->di_cpu      = 0;
1002                pmsg->data_length = len + 1;
1003
1004                memcpy(&pmsg[1], tmp, len + 1);
1005                queueCompleteMsg(pmsg);
1006                diva_maint_wakeup_read();
1007        }
1008
1009        org_mask = clients[id].Dbg.dbgMask;
1010        clients[id].Dbg.dbgMask = 0;
1011
1012        diva_os_leave_spin_lock(&dbg_q_lock, &old_irql, "register");
1013
1014        if (clients[id].request_pending) {
1015                clients[id].request_pending = 0;
1016                (*(clients[id].request))((ENTITY *)(*(clients[id].pIdiLib->DivaSTraceGetHandle))(clients[id].pIdiLib->hLib));
1017        }
1018
1019        diva_os_leave_spin_lock(&dbg_adapter_lock, &old_irql1, "register");
1020
1021        diva_set_driver_dbg_mask(id, org_mask);
1022}
1023
1024/*
1025  De-Register XDI adapter
1026*/
1027void diva_mnt_remove_xdi_adapter(const DESCRIPTOR *d) {
1028        diva_os_spin_lock_magic_t old_irql, old_irql1;
1029        dword sec, usec;
1030        int i;
1031        word size;
1032        byte *pmem = NULL;
1033
1034        diva_os_get_time(&sec, &usec);
1035
1036        diva_os_enter_spin_lock(&dbg_adapter_lock, &old_irql1, "read");
1037        diva_os_enter_spin_lock(&dbg_q_lock, &old_irql, "read");
1038
1039        for (i = 1; i < ARRAY_SIZE(clients); i++) {
1040                if (clients[i].hDbg && (clients[i].request == d->request)) {
1041                        diva_dbg_entry_head_t *pmsg;
1042                        char tmp[256];
1043                        int len;
1044
1045                        if (clients[i].pIdiLib) {
1046                                (*(clients[i].pIdiLib->DivaSTraceLibraryFinit))(clients[i].pIdiLib->hLib);
1047                                clients[i].pIdiLib = NULL;
1048
1049                                pmem = clients[i].pmem;
1050                                clients[i].pmem = NULL;
1051                        }
1052
1053                        clients[i].hDbg    = NULL;
1054                        clients[i].request_pending = 0;
1055                        if (clients[i].dma_handle >= 0) {
1056                                /*
1057                                  Free DMA handle
1058                                */
1059                                diva_free_dma_descriptor(clients[i].request, clients[i].dma_handle);
1060                                clients[i].dma_handle = -1;
1061                        }
1062                        clients[i].request = NULL;
1063
1064                        /*
1065                          Log driver register, MAINT driver ID is '0'
1066                        */
1067                        len = sprintf(tmp, "DIMAINT - drv # %d = '%s' de-registered",
1068                                      i, clients[i].Dbg.drvName);
1069
1070                        memset(&clients[i].Dbg, 0x00, sizeof(clients[i].Dbg));
1071
1072                        while (!(pmsg = (diva_dbg_entry_head_t *)queueAllocMsg(dbg_queue,
1073                                                                               (word)(len + 1 + sizeof(*pmsg))))) {
1074                                if ((pmsg = (diva_dbg_entry_head_t *)queuePeekMsg(dbg_queue, &size))) {
1075                                        queueFreeMsg(dbg_queue);
1076                                } else {
1077                                        break;
1078                                }
1079                        }
1080
1081                        if (pmsg) {
1082                                pmsg->sequence    = dbg_sequence++;
1083                                pmsg->time_sec    = sec;
1084                                pmsg->time_usec   = usec;
1085                                pmsg->facility    = MSG_TYPE_STRING;
1086                                pmsg->dli         = DLI_REG;
1087                                pmsg->drv_id      = 0; /* id 0 - DIMAINT */
1088                                pmsg->di_cpu      = 0;
1089                                pmsg->data_length = len + 1;
1090
1091                                memcpy(&pmsg[1], tmp, len + 1);
1092                                queueCompleteMsg(pmsg);
1093                                diva_maint_wakeup_read();
1094                        }
1095
1096                        break;
1097                }
1098        }
1099
1100        diva_os_leave_spin_lock(&dbg_q_lock, &old_irql, "read_ack");
1101        diva_os_leave_spin_lock(&dbg_adapter_lock, &old_irql1, "read_ack");
1102
1103        if (pmem) {
1104                diva_os_free(0, pmem);
1105        }
1106}
1107
1108/* ----------------------------------------------------------------
1109   Low level interface for management interface client
1110   ---------------------------------------------------------------- */
1111/*
1112  Return handle to client structure
1113*/
1114void *SuperTraceOpenAdapter(int AdapterNumber) {
1115        int i;
1116
1117        for (i = 1; i < ARRAY_SIZE(clients); i++) {
1118                if (clients[i].hDbg && clients[i].request && (clients[i].logical == AdapterNumber)) {
1119                        return (&clients[i]);
1120                }
1121        }
1122
1123        return NULL;
1124}
1125
1126int SuperTraceCloseAdapter(void *AdapterHandle) {
1127        return (0);
1128}
1129
1130int SuperTraceReadRequest(void *AdapterHandle, const char *name, byte *data) {
1131        diva_maint_client_t *pC = (diva_maint_client_t *)AdapterHandle;
1132
1133        if (pC && pC->pIdiLib && pC->request) {
1134                ENTITY *e = (ENTITY *)(*(pC->pIdiLib->DivaSTraceGetHandle))(pC->pIdiLib->hLib);
1135                byte *xdata = (byte *)&pC->xbuffer[0];
1136                char tmp = 0;
1137                word length;
1138
1139                if (!strcmp(name, "\\")) { /* Read ROOT */
1140                        name = &tmp;
1141                }
1142                length = SuperTraceCreateReadReq(xdata, name);
1143                single_p(xdata, &length, 0); /* End Of Message */
1144
1145                e->Req        = MAN_READ;
1146                e->ReqCh      = 0;
1147                e->X->PLength = length;
1148                e->X->P = (byte *)xdata;
1149
1150                pC->request_pending = 1;
1151
1152                return (0);
1153        }
1154
1155        return (-1);
1156}
1157
1158int SuperTraceGetNumberOfChannels(void *AdapterHandle) {
1159        if (AdapterHandle) {
1160                diva_maint_client_t *pC = (diva_maint_client_t *)AdapterHandle;
1161
1162                return (pC->channels);
1163        }
1164
1165        return (0);
1166}
1167
1168int SuperTraceASSIGN(void *AdapterHandle, byte *data) {
1169        diva_maint_client_t *pC = (diva_maint_client_t *)AdapterHandle;
1170
1171        if (pC && pC->pIdiLib && pC->request) {
1172                ENTITY *e = (ENTITY *)(*(pC->pIdiLib->DivaSTraceGetHandle))(pC->pIdiLib->hLib);
1173                IDI_SYNC_REQ *preq;
1174                char buffer[((sizeof(preq->xdi_extended_features) + 4) > sizeof(ENTITY)) ? (sizeof(preq->xdi_extended_features) + 4) : sizeof(ENTITY)];
1175                char features[4];
1176                word assign_data_length = 1;
1177
1178                features[0] = 0;
1179                pC->xbuffer[0] = 0;
1180                preq = (IDI_SYNC_REQ *)&buffer[0];
1181                preq->xdi_extended_features.Req = 0;
1182                preq->xdi_extended_features.Rc  = IDI_SYNC_REQ_XDI_GET_EXTENDED_FEATURES;
1183                preq->xdi_extended_features.info.buffer_length_in_bytes = sizeof(features);
1184                preq->xdi_extended_features.info.features = &features[0];
1185
1186                (*(pC->request))((ENTITY *)preq);
1187
1188                if ((features[0] & DIVA_XDI_EXTENDED_FEATURES_VALID) &&
1189                    (features[0] & DIVA_XDI_EXTENDED_FEATURE_MANAGEMENT_DMA)) {
1190                        dword uninitialized_var(rx_dma_magic);
1191                        if ((pC->dma_handle = diva_get_dma_descriptor(pC->request, &rx_dma_magic)) >= 0) {
1192                                pC->xbuffer[0] = LLI;
1193                                pC->xbuffer[1] = 8;
1194                                pC->xbuffer[2] = 0x40;
1195                                pC->xbuffer[3] = (byte)pC->dma_handle;
1196                                pC->xbuffer[4] = (byte)rx_dma_magic;
1197                                pC->xbuffer[5] = (byte)(rx_dma_magic >>  8);
1198                                pC->xbuffer[6] = (byte)(rx_dma_magic >> 16);
1199                                pC->xbuffer[7] = (byte)(rx_dma_magic >> 24);
1200                                pC->xbuffer[8] = (byte)(DIVA_MAX_MANAGEMENT_TRANSFER_SIZE & 0xFF);
1201                                pC->xbuffer[9] = (byte)(DIVA_MAX_MANAGEMENT_TRANSFER_SIZE >> 8);
1202                                pC->xbuffer[10] = 0;
1203
1204                                assign_data_length = 11;
1205                        }
1206                } else {
1207                        pC->dma_handle = -1;
1208                }
1209
1210                e->Id          = MAN_ID;
1211                e->callback    = diva_maint_xdi_cb;
1212                e->XNum        = 1;
1213                e->X           = &pC->XData;
1214                e->Req         = ASSIGN;
1215                e->ReqCh       = 0;
1216                e->X->PLength  = assign_data_length;
1217                e->X->P        = (byte *)&pC->xbuffer[0];
1218
1219                pC->request_pending = 1;
1220
1221                return (0);
1222        }
1223
1224        return (-1);
1225}
1226
1227int SuperTraceREMOVE(void *AdapterHandle) {
1228        diva_maint_client_t *pC = (diva_maint_client_t *)AdapterHandle;
1229
1230        if (pC && pC->pIdiLib && pC->request) {
1231                ENTITY *e = (ENTITY *)(*(pC->pIdiLib->DivaSTraceGetHandle))(pC->pIdiLib->hLib);
1232
1233                e->XNum        = 1;
1234                e->X           = &pC->XData;
1235                e->Req         = REMOVE;
1236                e->ReqCh       = 0;
1237                e->X->PLength  = 1;
1238                e->X->P        = (byte *)&pC->xbuffer[0];
1239                pC->xbuffer[0] = 0;
1240
1241                pC->request_pending = 1;
1242
1243                return (0);
1244        }
1245
1246        return (-1);
1247}
1248
1249int SuperTraceTraceOnRequest(void *hAdapter, const char *name, byte *data) {
1250        diva_maint_client_t *pC = (diva_maint_client_t *)hAdapter;
1251
1252        if (pC && pC->pIdiLib && pC->request) {
1253                ENTITY *e = (ENTITY *)(*(pC->pIdiLib->DivaSTraceGetHandle))(pC->pIdiLib->hLib);
1254                byte *xdata = (byte *)&pC->xbuffer[0];
1255                char tmp = 0;
1256                word length;
1257
1258                if (!strcmp(name, "\\")) { /* Read ROOT */
1259                        name = &tmp;
1260                }
1261                length = SuperTraceCreateReadReq(xdata, name);
1262                single_p(xdata, &length, 0); /* End Of Message */
1263                e->Req          = MAN_EVENT_ON;
1264                e->ReqCh        = 0;
1265                e->X->PLength   = length;
1266                e->X->P = (byte *)xdata;
1267
1268                pC->request_pending = 1;
1269
1270                return (0);
1271        }
1272
1273        return (-1);
1274}
1275
1276int SuperTraceWriteVar(void *AdapterHandle,
1277                       byte *data,
1278                       const char *name,
1279                       void *var,
1280                       byte type,
1281                       byte var_length) {
1282        diva_maint_client_t *pC = (diva_maint_client_t *)AdapterHandle;
1283
1284        if (pC && pC->pIdiLib && pC->request) {
1285                ENTITY *e = (ENTITY *)(*(pC->pIdiLib->DivaSTraceGetHandle))(pC->pIdiLib->hLib);
1286                diva_man_var_header_t *pVar = (diva_man_var_header_t *)&pC->xbuffer[0];
1287                word length = SuperTraceCreateReadReq((byte *)pVar, name);
1288
1289                memcpy(&pC->xbuffer[length], var, var_length);
1290                length += var_length;
1291                pVar->length += var_length;
1292                pVar->value_length = var_length;
1293                pVar->type = type;
1294                single_p((byte *)pVar, &length, 0); /* End Of Message */
1295
1296                e->Req = MAN_WRITE;
1297                e->ReqCh = 0;
1298                e->X->PLength   = length;
1299                e->X->P = (byte *)pVar;
1300
1301                pC->request_pending = 1;
1302
1303                return (0);
1304        }
1305
1306        return (-1);
1307}
1308
1309int SuperTraceExecuteRequest(void *AdapterHandle,
1310                             const char *name,
1311                             byte *data) {
1312        diva_maint_client_t *pC = (diva_maint_client_t *)AdapterHandle;
1313
1314        if (pC && pC->pIdiLib && pC->request) {
1315                ENTITY *e = (ENTITY *)(*(pC->pIdiLib->DivaSTraceGetHandle))(pC->pIdiLib->hLib);
1316                byte *xdata = (byte *)&pC->xbuffer[0];
1317                word length;
1318
1319                length = SuperTraceCreateReadReq(xdata, name);
1320                single_p(xdata, &length, 0); /* End Of Message */
1321
1322                e->Req = MAN_EXECUTE;
1323                e->ReqCh = 0;
1324                e->X->PLength = length;
1325                e->X->P = (byte *)xdata;
1326
1327                pC->request_pending = 1;
1328
1329                return (0);
1330        }
1331
1332        return (-1);
1333}
1334
1335static word SuperTraceCreateReadReq(byte *P, const char *path) {
1336        byte var_length;
1337        byte *plen;
1338
1339        var_length = (byte)strlen(path);
1340
1341        *P++ = ESC;
1342        plen = P++;
1343        *P++ = 0x80; /* MAN_IE */
1344        *P++ = 0x00; /* Type */
1345        *P++ = 0x00; /* Attribute */
1346        *P++ = 0x00; /* Status */
1347        *P++ = 0x00; /* Variable Length */
1348        *P++ = var_length;
1349        memcpy(P, path, var_length);
1350        P += var_length;
1351        *plen = var_length + 0x06;
1352
1353        return ((word)(var_length + 0x08));
1354}
1355
1356static void single_p(byte *P, word *PLength, byte Id) {
1357        P[(*PLength)++] = Id;
1358}
1359
1360static void diva_maint_xdi_cb(ENTITY *e) {
1361        diva_strace_context_t *pLib = DIVAS_CONTAINING_RECORD(e, diva_strace_context_t, e);
1362        diva_maint_client_t *pC;
1363        diva_os_spin_lock_magic_t old_irql, old_irql1;
1364
1365
1366        diva_os_enter_spin_lock(&dbg_adapter_lock, &old_irql1, "xdi_cb");
1367        diva_os_enter_spin_lock(&dbg_q_lock, &old_irql, "xdi_cb");
1368
1369        pC = (diva_maint_client_t *)pLib->hAdapter;
1370
1371        if ((e->complete == 255) || (pC->dma_handle < 0)) {
1372                if ((*(pLib->instance.DivaSTraceMessageInput))(&pLib->instance)) {
1373                        diva_mnt_internal_dprintf(0, DLI_ERR, "Trace internal library error");
1374                }
1375        } else {
1376                /*
1377                  Process combined management interface indication
1378                */
1379                if ((*(pLib->instance.DivaSTraceMessageInput))(&pLib->instance)) {
1380                        diva_mnt_internal_dprintf(0, DLI_ERR, "Trace internal library error (DMA mode)");
1381                }
1382        }
1383
1384        diva_os_leave_spin_lock(&dbg_q_lock, &old_irql, "xdi_cb");
1385
1386
1387        if (pC->request_pending) {
1388                pC->request_pending = 0;
1389                (*(pC->request))(e);
1390        }
1391
1392        diva_os_leave_spin_lock(&dbg_adapter_lock, &old_irql1, "xdi_cb");
1393}
1394
1395
1396static void diva_maint_error(void *user_context,
1397                             diva_strace_library_interface_t *hLib,
1398                             int Adapter,
1399                             int error,
1400                             const char *file,
1401                             int line) {
1402        diva_mnt_internal_dprintf(0, DLI_ERR,
1403                                  "Trace library error(%d) A(%d) %s %d", error, Adapter, file, line);
1404}
1405
1406static void print_ie(diva_trace_ie_t *ie, char *buffer, int length) {
1407        int i;
1408
1409        buffer[0] = 0;
1410
1411        if (length > 32) {
1412                for (i = 0; ((i < ie->length) && (length > 3)); i++) {
1413                        sprintf(buffer, "%02x", ie->data[i]);
1414                        buffer += 2;
1415                        length -= 2;
1416                        if (i < (ie->length - 1)) {
1417                                strcpy(buffer, " ");
1418                                buffer++;
1419                                length--;
1420                        }
1421                }
1422        }
1423}
1424
1425static void diva_maint_state_change_notify(void *user_context,
1426                                           diva_strace_library_interface_t *hLib,
1427                                           int Adapter,
1428                                           diva_trace_line_state_t *channel,
1429                                           int notify_subject) {
1430        diva_maint_client_t *pC = (diva_maint_client_t *)user_context;
1431        diva_trace_fax_state_t *fax = &channel->fax;
1432        diva_trace_modem_state_t *modem = &channel->modem;
1433        char tmp[256];
1434
1435        if (!pC->hDbg) {
1436                return;
1437        }
1438
1439        switch (notify_subject) {
1440        case DIVA_SUPER_TRACE_NOTIFY_LINE_CHANGE: {
1441                int view = (TraceFilter[0] == 0);
1442                /*
1443                  Process selective Trace
1444                */
1445                if (channel->Line[0] == 'I' && channel->Line[1] == 'd' &&
1446                    channel->Line[2] == 'l' && channel->Line[3] == 'e') {
1447                        if ((TraceFilterIdent == pC->hDbg->id) && (TraceFilterChannel == (int)channel->ChannelNumber)) {
1448                                (*(hLib->DivaSTraceSetBChannel))(hLib, (int)channel->ChannelNumber, 0);
1449                                (*(hLib->DivaSTraceSetAudioTap))(hLib, (int)channel->ChannelNumber, 0);
1450                                diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG, "Selective Trace OFF for Ch=%d",
1451                                                          (int)channel->ChannelNumber);
1452                                TraceFilterIdent   = -1;
1453                                TraceFilterChannel = -1;
1454                                view = 1;
1455                        }
1456                } else if (TraceFilter[0] && (TraceFilterIdent < 0) && !(diva_mnt_cmp_nmbr(&channel->RemoteAddress[0]) &&
1457                                                                         diva_mnt_cmp_nmbr(&channel->LocalAddress[0]))) {
1458
1459                        if ((pC->hDbg->dbgMask & DIVA_MGT_DBG_IFC_BCHANNEL) != 0) { /* Activate B-channel trace */
1460                                (*(hLib->DivaSTraceSetBChannel))(hLib, (int)channel->ChannelNumber, 1);
1461                        }
1462                        if ((pC->hDbg->dbgMask & DIVA_MGT_DBG_IFC_AUDIO) != 0) { /* Activate AudioTap Trace */
1463                                (*(hLib->DivaSTraceSetAudioTap))(hLib, (int)channel->ChannelNumber, 1);
1464                        }
1465
1466                        TraceFilterIdent   = pC->hDbg->id;
1467                        TraceFilterChannel = (int)channel->ChannelNumber;
1468
1469                        if (TraceFilterIdent >= 0) {
1470                                diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG, "Selective Trace ON for Ch=%d",
1471                                                          (int)channel->ChannelNumber);
1472                                view = 1;
1473                        }
1474                }
1475                if (view && (pC->hDbg->dbgMask & DIVA_MGT_DBG_LINE_EVENTS)) {
1476                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "L Ch     = %d",
1477                                                  (int)channel->ChannelNumber);
1478                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "L Status = <%s>", &channel->Line[0]);
1479                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "L Layer1 = <%s>", &channel->Framing[0]);
1480                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "L Layer2 = <%s>", &channel->Layer2[0]);
1481                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "L Layer3 = <%s>", &channel->Layer3[0]);
1482                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "L RAddr  = <%s>",
1483                                                  &channel->RemoteAddress[0]);
1484                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "L RSAddr = <%s>",
1485                                                  &channel->RemoteSubAddress[0]);
1486                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "L LAddr  = <%s>",
1487                                                  &channel->LocalAddress[0]);
1488                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "L LSAddr = <%s>",
1489                                                  &channel->LocalSubAddress[0]);
1490                        print_ie(&channel->call_BC, tmp, sizeof(tmp));
1491                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "L BC     = <%s>", tmp);
1492                        print_ie(&channel->call_HLC, tmp, sizeof(tmp));
1493                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "L HLC    = <%s>", tmp);
1494                        print_ie(&channel->call_LLC, tmp, sizeof(tmp));
1495                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "L LLC    = <%s>", tmp);
1496                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "L CR     = 0x%x", channel->CallReference);
1497                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "L Disc   = 0x%x",
1498                                                  channel->LastDisconnecCause);
1499                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "L Owner  = <%s>", &channel->UserID[0]);
1500                }
1501
1502        } break;
1503
1504        case DIVA_SUPER_TRACE_NOTIFY_MODEM_CHANGE:
1505                if (pC->hDbg->dbgMask & DIVA_MGT_DBG_MDM_PROGRESS) {
1506                        {
1507                                int ch = TraceFilterChannel;
1508                                int id = TraceFilterIdent;
1509
1510                                if ((id >= 0) && (ch >= 0) && (id < ARRAY_SIZE(clients)) &&
1511                                    (clients[id].Dbg.id == (byte)id) && (clients[id].pIdiLib == hLib)) {
1512                                        if (ch != (int)modem->ChannelNumber) {
1513                                                break;
1514                                        }
1515                                } else if (TraceFilter[0] != 0) {
1516                                        break;
1517                                }
1518                        }
1519
1520
1521                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM Ch    = %lu",
1522                                                  (int)modem->ChannelNumber);
1523                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM Event = %lu", modem->Event);
1524                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM Norm  = %lu", modem->Norm);
1525                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM Opts. = 0x%08x", modem->Options);
1526                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM Tx    = %lu Bps", modem->TxSpeed);
1527                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM Rx    = %lu Bps", modem->RxSpeed);
1528                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM RT    = %lu mSec",
1529                                                  modem->RoundtripMsec);
1530                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM Sr    = %lu", modem->SymbolRate);
1531                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM Rxl   = %d dBm", modem->RxLeveldBm);
1532                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM El    = %d dBm", modem->EchoLeveldBm);
1533                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM SNR   = %lu dB", modem->SNRdb);
1534                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM MAE   = %lu", modem->MAE);
1535                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM LRet  = %lu",
1536                                                  modem->LocalRetrains);
1537                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM RRet  = %lu",
1538                                                  modem->RemoteRetrains);
1539                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM LRes  = %lu", modem->LocalResyncs);
1540                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM RRes  = %lu",
1541                                                  modem->RemoteResyncs);
1542                        if (modem->Event == 3) {
1543                                diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM Disc  =  %lu", modem->DiscReason);
1544                        }
1545                }
1546                if ((modem->Event == 3) && (pC->hDbg->dbgMask & DIVA_MGT_DBG_MDM_STATISTICS)) {
1547                        (*(pC->pIdiLib->DivaSTraceGetModemStatistics))(pC->pIdiLib);
1548                }
1549                break;
1550
1551        case DIVA_SUPER_TRACE_NOTIFY_FAX_CHANGE:
1552                if (pC->hDbg->dbgMask & DIVA_MGT_DBG_FAX_PROGRESS) {
1553                        {
1554                                int ch = TraceFilterChannel;
1555                                int id = TraceFilterIdent;
1556
1557                                if ((id >= 0) && (ch >= 0) && (id < ARRAY_SIZE(clients)) &&
1558                                    (clients[id].Dbg.id == (byte)id) && (clients[id].pIdiLib == hLib)) {
1559                                        if (ch != (int)fax->ChannelNumber) {
1560                                                break;
1561                                        }
1562                                } else if (TraceFilter[0] != 0) {
1563                                        break;
1564                                }
1565                        }
1566
1567                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX Ch    = %lu", (int)fax->ChannelNumber);
1568                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX Event = %lu",     fax->Event);
1569                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX Pages = %lu",     fax->Page_Counter);
1570                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX Feat. = 0x%08x",  fax->Features);
1571                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX ID    = <%s>",    &fax->Station_ID[0]);
1572                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX Saddr = <%s>",    &fax->Subaddress[0]);
1573                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX Pwd   = <%s>",    &fax->Password[0]);
1574                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX Speed = %lu",     fax->Speed);
1575                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX Res.  = 0x%08x",  fax->Resolution);
1576                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX Width = %lu",     fax->Paper_Width);
1577                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX Length= %lu",     fax->Paper_Length);
1578                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX SLT   = %lu",     fax->Scanline_Time);
1579                        if (fax->Event == 3) {
1580                                diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX Disc  = %lu",     fax->Disc_Reason);
1581                        }
1582                }
1583                if ((fax->Event == 3) && (pC->hDbg->dbgMask & DIVA_MGT_DBG_FAX_STATISTICS)) {
1584                        (*(pC->pIdiLib->DivaSTraceGetFaxStatistics))(pC->pIdiLib);
1585                }
1586                break;
1587
1588        case DIVA_SUPER_TRACE_INTERFACE_CHANGE:
1589                if (pC->hDbg->dbgMask & DIVA_MGT_DBG_IFC_EVENTS) {
1590                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT,
1591                                                  "Layer 1 -> [%s]", channel->pInterface->Layer1);
1592                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT,
1593                                                  "Layer 2 -> [%s]", channel->pInterface->Layer2);
1594                }
1595                break;
1596
1597        case DIVA_SUPER_TRACE_NOTIFY_STAT_CHANGE:
1598                if (pC->hDbg->dbgMask & DIVA_MGT_DBG_IFC_STATISTICS) {
1599                        /*
1600                          Incoming Statistics
1601                        */
1602                        if (channel->pInterfaceStat->inc.Calls) {
1603                                diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1604                                                          "Inc Calls                     =%lu", channel->pInterfaceStat->inc.Calls);
1605                        }
1606                        if (channel->pInterfaceStat->inc.Connected) {
1607                                diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1608                                                          "Inc Connected                 =%lu", channel->pInterfaceStat->inc.Connected);
1609                        }
1610                        if (channel->pInterfaceStat->inc.User_Busy) {
1611                                diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1612                                                          "Inc Busy                      =%lu", channel->pInterfaceStat->inc.User_Busy);
1613                        }
1614                        if (channel->pInterfaceStat->inc.Call_Rejected) {
1615                                diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1616                                                          "Inc Rejected                  =%lu", channel->pInterfaceStat->inc.Call_Rejected);
1617                        }
1618                        if (channel->pInterfaceStat->inc.Wrong_Number) {
1619                                diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1620                                                          "Inc Wrong Nr                  =%lu", channel->pInterfaceStat->inc.Wrong_Number);
1621                        }
1622                        if (channel->pInterfaceStat->inc.Incompatible_Dst) {
1623                                diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1624                                                          "Inc Incomp. Dest              =%lu", channel->pInterfaceStat->inc.Incompatible_Dst);
1625                        }
1626                        if (channel->pInterfaceStat->inc.Out_of_Order) {
1627                                diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1628                                                          "Inc Out of Order              =%lu", channel->pInterfaceStat->inc.Out_of_Order);
1629                        }
1630                        if (channel->pInterfaceStat->inc.Ignored) {
1631                                diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1632                                                          "Inc Ignored                   =%lu", channel->pInterfaceStat->inc.Ignored);
1633                        }
1634
1635                        /*
1636                          Outgoing Statistics
1637                        */
1638                        if (channel->pInterfaceStat->outg.Calls) {
1639                                diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1640                                                          "Outg Calls                    =%lu", channel->pInterfaceStat->outg.Calls);
1641                        }
1642                        if (channel->pInterfaceStat->outg.Connected) {
1643                                diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1644                                                          "Outg Connected                =%lu", channel->pInterfaceStat->outg.Connected);
1645                        }
1646                        if (channel->pInterfaceStat->outg.User_Busy) {
1647                                diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1648                                                          "Outg Busy                     =%lu", channel->pInterfaceStat->outg.User_Busy);
1649                        }
1650                        if (channel->pInterfaceStat->outg.No_Answer) {
1651                                diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1652                                                          "Outg No Answer                =%lu", channel->pInterfaceStat->outg.No_Answer);
1653                        }
1654                        if (channel->pInterfaceStat->outg.Wrong_Number) {
1655                                diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1656                                                          "Outg Wrong Nr                 =%lu", channel->pInterfaceStat->outg.Wrong_Number);
1657                        }
1658                        if (channel->pInterfaceStat->outg.Call_Rejected) {
1659                                diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1660                                                          "Outg Rejected                 =%lu", channel->pInterfaceStat->outg.Call_Rejected);
1661                        }
1662                        if (channel->pInterfaceStat->outg.Other_Failures) {
1663                                diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1664                                                          "Outg Other Failures           =%lu", channel->pInterfaceStat->outg.Other_Failures);
1665                        }
1666                }
1667                break;
1668
1669        case DIVA_SUPER_TRACE_NOTIFY_MDM_STAT_CHANGE:
1670                if (channel->pInterfaceStat->mdm.Disc_Normal) {
1671                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1672                                                  "MDM Disc Normal        = %lu", channel->pInterfaceStat->mdm.Disc_Normal);
1673                }
1674                if (channel->pInterfaceStat->mdm.Disc_Unspecified) {
1675                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1676                                                  "MDM Disc Unsp.         = %lu", channel->pInterfaceStat->mdm.Disc_Unspecified);
1677                }
1678                if (channel->pInterfaceStat->mdm.Disc_Busy_Tone) {
1679                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1680                                                  "MDM Disc Busy Tone     = %lu", channel->pInterfaceStat->mdm.Disc_Busy_Tone);
1681                }
1682                if (channel->pInterfaceStat->mdm.Disc_Congestion) {
1683                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1684                                                  "MDM Disc Congestion    = %lu", channel->pInterfaceStat->mdm.Disc_Congestion);
1685                }
1686                if (channel->pInterfaceStat->mdm.Disc_Carr_Wait) {
1687                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1688                                                  "MDM Disc Carrier Wait  = %lu", channel->pInterfaceStat->mdm.Disc_Carr_Wait);
1689                }
1690                if (channel->pInterfaceStat->mdm.Disc_Trn_Timeout) {
1691                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1692                                                  "MDM Disc Trn. T.o.     = %lu", channel->pInterfaceStat->mdm.Disc_Trn_Timeout);
1693                }
1694                if (channel->pInterfaceStat->mdm.Disc_Incompat) {
1695                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1696                                                  "MDM Disc Incompatible  = %lu", channel->pInterfaceStat->mdm.Disc_Incompat);
1697                }
1698                if (channel->pInterfaceStat->mdm.Disc_Frame_Rej) {
1699                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1700                                                  "MDM Disc Frame Reject  = %lu", channel->pInterfaceStat->mdm.Disc_Frame_Rej);
1701                }
1702                if (channel->pInterfaceStat->mdm.Disc_V42bis) {
1703                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1704                                                  "MDM Disc V.42bis       = %lu", channel->pInterfaceStat->mdm.Disc_V42bis);
1705                }
1706                break;
1707
1708        case DIVA_SUPER_TRACE_NOTIFY_FAX_STAT_CHANGE:
1709                if (channel->pInterfaceStat->fax.Disc_Normal) {
1710                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1711                                                  "FAX Disc Normal        = %lu", channel->pInterfaceStat->fax.Disc_Normal);
1712                }
1713                if (channel->pInterfaceStat->fax.Disc_Not_Ident) {
1714                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1715                                                  "FAX Disc Not Ident.    = %lu", channel->pInterfaceStat->fax.Disc_Not_Ident);
1716                }
1717                if (channel->pInterfaceStat->fax.Disc_No_Response) {
1718                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1719                                                  "FAX Disc No Response   = %lu", channel->pInterfaceStat->fax.Disc_No_Response);
1720                }
1721                if (channel->pInterfaceStat->fax.Disc_Retries) {
1722                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1723                                                  "FAX Disc Max Retries   = %lu", channel->pInterfaceStat->fax.Disc_Retries);
1724                }
1725                if (channel->pInterfaceStat->fax.Disc_Unexp_Msg) {
1726                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1727                                                  "FAX Unexp. Msg.        = %lu", channel->pInterfaceStat->fax.Disc_Unexp_Msg);
1728                }
1729                if (channel->pInterfaceStat->fax.Disc_No_Polling) {
1730                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1731                                                  "FAX Disc No Polling    = %lu", channel->pInterfaceStat->fax.Disc_No_Polling);
1732                }
1733                if (channel->pInterfaceStat->fax.Disc_Training) {
1734                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1735                                                  "FAX Disc Training      = %lu", channel->pInterfaceStat->fax.Disc_Training);
1736                }
1737                if (channel->pInterfaceStat->fax.Disc_Unexpected) {
1738                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1739                                                  "FAX Disc Unexpected    = %lu", channel->pInterfaceStat->fax.Disc_Unexpected);
1740                }
1741                if (channel->pInterfaceStat->fax.Disc_Application) {
1742                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1743                                                  "FAX Disc Application   = %lu", channel->pInterfaceStat->fax.Disc_Application);
1744                }
1745                if (channel->pInterfaceStat->fax.Disc_Incompat) {
1746                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1747                                                  "FAX Disc Incompatible  = %lu", channel->pInterfaceStat->fax.Disc_Incompat);
1748                }
1749                if (channel->pInterfaceStat->fax.Disc_No_Command) {
1750                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1751                                                  "FAX Disc No Command    = %lu", channel->pInterfaceStat->fax.Disc_No_Command);
1752                }
1753                if (channel->pInterfaceStat->fax.Disc_Long_Msg) {
1754                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1755                                                  "FAX Disc Long Msg.     = %lu", channel->pInterfaceStat->fax.Disc_Long_Msg);
1756                }
1757                if (channel->pInterfaceStat->fax.Disc_Supervisor) {
1758                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1759                                                  "FAX Disc Supervisor    = %lu", channel->pInterfaceStat->fax.Disc_Supervisor);
1760                }
1761                if (channel->pInterfaceStat->fax.Disc_SUB_SEP_PWD) {
1762                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1763                                                  "FAX Disc SUP SEP PWD   = %lu", channel->pInterfaceStat->fax.Disc_SUB_SEP_PWD);
1764                }
1765                if (channel->pInterfaceStat->fax.Disc_Invalid_Msg) {
1766                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1767                                                  "FAX Disc Invalid Msg.  = %lu", channel->pInterfaceStat->fax.Disc_Invalid_Msg);
1768                }
1769                if (channel->pInterfaceStat->fax.Disc_Page_Coding) {
1770                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1771                                                  "FAX Disc Page Coding   = %lu", channel->pInterfaceStat->fax.Disc_Page_Coding);
1772                }
1773                if (channel->pInterfaceStat->fax.Disc_App_Timeout) {
1774                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1775                                                  "FAX Disc Appl. T.o.    = %lu", channel->pInterfaceStat->fax.Disc_App_Timeout);
1776                }
1777                if (channel->pInterfaceStat->fax.Disc_Unspecified) {
1778                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1779                                                  "FAX Disc Unspec.       = %lu", channel->pInterfaceStat->fax.Disc_Unspecified);
1780                }
1781                break;
1782        }
1783}
1784
1785/*
1786  Receive trace information from the Management Interface and store it in the
1787  internal trace buffer with MSG_TYPE_MLOG as is, without any filtering.
1788  Event Filtering and formatting is done in  Management Interface self.
1789*/
1790static void diva_maint_trace_notify(void *user_context,
1791                                    diva_strace_library_interface_t *hLib,
1792                                    int Adapter,
1793                                    void *xlog_buffer,
1794                                    int length) {
1795        diva_maint_client_t *pC = (diva_maint_client_t *)user_context;
1796        diva_dbg_entry_head_t *pmsg;
1797        word size;
1798        dword sec, usec;
1799        int ch = TraceFilterChannel;
1800        int id = TraceFilterIdent;
1801
1802        /*
1803          Selective trace
1804        */
1805        if ((id >= 0) && (ch >= 0) && (id < ARRAY_SIZE(clients)) &&
1806            (clients[id].Dbg.id == (byte)id) && (clients[id].pIdiLib == hLib)) {
1807                const char *p = NULL;
1808                int ch_value = -1;
1809                MI_XLOG_HDR *TrcData = (MI_XLOG_HDR *)xlog_buffer;
1810
1811                if (Adapter != clients[id].logical) {
1812                        return; /* Ignore all trace messages from other adapters */
1813                }
1814
1815                if (TrcData->code == 24) {
1816                        p = (char *)&TrcData->code;
1817                        p += 2;
1818                }
1819
1820                /*
1821                  All L1 messages start as [dsp,ch], so we can filter this information
1822                  and filter out all messages that use different channel
1823                */
1824                if (p && p[0] == '[') {
1825                        if (p[2] == ',') {
1826                                p += 3;
1827                                ch_value = *p - '0';
1828                        } else if (p[3] == ',') {
1829                                p += 4;
1830                                ch_value = *p - '0';
1831                        }
1832                        if (ch_value >= 0) {
1833                                if (p[2] == ']') {
1834                                        ch_value = ch_value * 10 + p[1] - '0';
1835                                }
1836                                if (ch_value != ch) {
1837                                        return; /* Ignore other channels */
1838                                }
1839                        }
1840                }
1841
1842        } else if (TraceFilter[0] != 0) {
1843                return; /* Ignore trace if trace filter is activated, but idle */
1844        }
1845
1846        diva_os_get_time(&sec, &usec);
1847
1848        while (!(pmsg = (diva_dbg_entry_head_t *)queueAllocMsg(dbg_queue,
1849                                                               (word)length + sizeof(*pmsg)))) {
1850                if ((pmsg = (diva_dbg_entry_head_t *)queuePeekMsg(dbg_queue, &size))) {
1851                        queueFreeMsg(dbg_queue);
1852                } else {
1853                        break;
1854                }
1855        }
1856        if (pmsg) {
1857                memcpy(&pmsg[1], xlog_buffer, length);
1858                pmsg->sequence    = dbg_sequence++;
1859                pmsg->time_sec    = sec;
1860                pmsg->time_usec   = usec;
1861                pmsg->facility    = MSG_TYPE_MLOG;
1862                pmsg->dli         = pC->logical;
1863                pmsg->drv_id      = pC->hDbg->id;
1864                pmsg->di_cpu      = 0;
1865                pmsg->data_length = length;
1866                queueCompleteMsg(pmsg);
1867                if (queueCount(dbg_queue)) {
1868                        diva_maint_wakeup_read();
1869                }
1870        }
1871}
1872
1873
1874/*
1875  Convert MAINT trace mask to management interface trace mask/work/facility and
1876  issue command to management interface
1877*/
1878static void diva_change_management_debug_mask(diva_maint_client_t *pC, dword old_mask) {
1879        if (pC->request && pC->hDbg && pC->pIdiLib) {
1880                dword changed = pC->hDbg->dbgMask ^ old_mask;
1881
1882                if (changed & DIVA_MGT_DBG_TRACE) {
1883                        (*(pC->pIdiLib->DivaSTraceSetInfo))(pC->pIdiLib,
1884                                                            (pC->hDbg->dbgMask & DIVA_MGT_DBG_TRACE) != 0);
1885                }
1886                if (changed & DIVA_MGT_DBG_DCHAN) {
1887                        (*(pC->pIdiLib->DivaSTraceSetDChannel))(pC->pIdiLib,
1888                                                                (pC->hDbg->dbgMask & DIVA_MGT_DBG_DCHAN) != 0);
1889                }
1890                if (!TraceFilter[0]) {
1891                        if (changed & DIVA_MGT_DBG_IFC_BCHANNEL) {
1892                                int i, state = ((pC->hDbg->dbgMask & DIVA_MGT_DBG_IFC_BCHANNEL) != 0);
1893
1894                                for (i = 0; i < pC->channels; i++) {
1895                                        (*(pC->pIdiLib->DivaSTraceSetBChannel))(pC->pIdiLib, i + 1, state);
1896                                }
1897                        }
1898                        if (changed & DIVA_MGT_DBG_IFC_AUDIO) {
1899                                int i, state = ((pC->hDbg->dbgMask & DIVA_MGT_DBG_IFC_AUDIO) != 0);
1900
1901                                for (i = 0; i < pC->channels; i++) {
1902                                        (*(pC->pIdiLib->DivaSTraceSetAudioTap))(pC->pIdiLib, i + 1, state);
1903                                }
1904                        }
1905                }
1906        }
1907}
1908
1909
1910void diva_mnt_internal_dprintf(dword drv_id, dword type, char *fmt, ...) {
1911        va_list ap;
1912
1913        va_start(ap, fmt);
1914        DI_format(0, (word)drv_id, (int)type, fmt, ap);
1915        va_end(ap);
1916}
1917
1918/*
1919  Shutdown all adapters before driver removal
1920*/
1921int diva_mnt_shutdown_xdi_adapters(void) {
1922        diva_os_spin_lock_magic_t old_irql, old_irql1;
1923        int i, fret = 0;
1924        byte *pmem;
1925
1926
1927        for (i = 1; i < ARRAY_SIZE(clients); i++) {
1928                pmem = NULL;
1929
1930                diva_os_enter_spin_lock(&dbg_adapter_lock, &old_irql1, "unload");
1931                diva_os_enter_spin_lock(&dbg_q_lock, &old_irql, "unload");
1932
1933                if (clients[i].hDbg && clients[i].pIdiLib && clients[i].request) {
1934                        if ((*(clients[i].pIdiLib->DivaSTraceLibraryStop))(clients[i].pIdiLib) == 1) {
1935                                /*
1936                                  Adapter removal complete
1937                                */
1938                                if (clients[i].pIdiLib) {
1939                                        (*(clients[i].pIdiLib->DivaSTraceLibraryFinit))(clients[i].pIdiLib->hLib);
1940                                        clients[i].pIdiLib = NULL;
1941
1942                                        pmem = clients[i].pmem;
1943                                        clients[i].pmem = NULL;
1944                                }
1945                                clients[i].hDbg    = NULL;
1946                                clients[i].request_pending = 0;
1947
1948                                if (clients[i].dma_handle >= 0) {
1949                                        /*
1950                                          Free DMA handle
1951                                        */
1952                                        diva_free_dma_descriptor(clients[i].request, clients[i].dma_handle);
1953                                        clients[i].dma_handle = -1;
1954                                }
1955                                clients[i].request = NULL;
1956                        } else {
1957                                fret = -1;
1958                        }
1959                }
1960
1961                diva_os_leave_spin_lock(&dbg_q_lock, &old_irql, "unload");
1962                if (clients[i].hDbg && clients[i].pIdiLib && clients[i].request && clients[i].request_pending) {
1963                        clients[i].request_pending = 0;
1964                        (*(clients[i].request))((ENTITY *)(*(clients[i].pIdiLib->DivaSTraceGetHandle))(clients[i].pIdiLib->hLib));
1965                        if (clients[i].dma_handle >= 0) {
1966                                diva_free_dma_descriptor(clients[i].request, clients[i].dma_handle);
1967                                clients[i].dma_handle = -1;
1968                        }
1969                }
1970                diva_os_leave_spin_lock(&dbg_adapter_lock, &old_irql1, "unload");
1971
1972                if (pmem) {
1973                        diva_os_free(0, pmem);
1974                }
1975        }
1976
1977        return (fret);
1978}
1979
1980/*
1981  Set/Read the trace filter used for selective tracing.
1982  Affects B- and Audio Tap trace mask at run time
1983*/
1984int diva_set_trace_filter(int filter_length, const char *filter) {
1985        diva_os_spin_lock_magic_t old_irql, old_irql1;
1986        int i, ch, on, client_b_on, client_atap_on;
1987
1988        diva_os_enter_spin_lock(&dbg_adapter_lock, &old_irql1, "dbg mask");
1989        diva_os_enter_spin_lock(&dbg_q_lock, &old_irql, "write_filter");
1990
1991        if (filter_length <= DIVA_MAX_SELECTIVE_FILTER_LENGTH) {
1992                memcpy(&TraceFilter[0], filter, filter_length);
1993                if (TraceFilter[filter_length]) {
1994                        TraceFilter[filter_length] = 0;
1995                }
1996                if (TraceFilter[0] == '*') {
1997                        TraceFilter[0] = 0;
1998                }
1999        } else {
2000                filter_length = -1;
2001        }
2002
2003        TraceFilterIdent   = -1;
2004        TraceFilterChannel = -1;
2005
2006        on = (TraceFilter[0] == 0);
2007
2008        for (i = 1; i < ARRAY_SIZE(clients); i++) {
2009                if (clients[i].hDbg && clients[i].pIdiLib && clients[i].request) {
2010                        client_b_on    = on && ((clients[i].hDbg->dbgMask & DIVA_MGT_DBG_IFC_BCHANNEL) != 0);
2011                        client_atap_on = on && ((clients[i].hDbg->dbgMask & DIVA_MGT_DBG_IFC_AUDIO)    != 0);
2012                        for (ch = 0; ch < clients[i].channels; ch++) {
2013                                (*(clients[i].pIdiLib->DivaSTraceSetBChannel))(clients[i].pIdiLib->hLib, ch + 1, client_b_on);
2014                                (*(clients[i].pIdiLib->DivaSTraceSetAudioTap))(clients[i].pIdiLib->hLib, ch + 1, client_atap_on);
2015                        }
2016                }
2017        }
2018
2019        for (i = 1; i < ARRAY_SIZE(clients); i++) {
2020                if (clients[i].hDbg && clients[i].pIdiLib && clients[i].request && clients[i].request_pending) {
2021                        diva_os_leave_spin_lock(&dbg_q_lock, &old_irql, "write_filter");
2022                        clients[i].request_pending = 0;
2023                        (*(clients[i].request))((ENTITY *)(*(clients[i].pIdiLib->DivaSTraceGetHandle))(clients[i].pIdiLib->hLib));
2024                        diva_os_enter_spin_lock(&dbg_q_lock, &old_irql, "write_filter");
2025                }
2026        }
2027
2028        diva_os_leave_spin_lock(&dbg_q_lock, &old_irql, "write_filter");
2029        diva_os_leave_spin_lock(&dbg_adapter_lock, &old_irql1, "dbg mask");
2030
2031        return (filter_length);
2032}
2033
2034int diva_get_trace_filter(int max_length, char *filter) {
2035        diva_os_spin_lock_magic_t old_irql;
2036        int len;
2037
2038        diva_os_enter_spin_lock(&dbg_q_lock, &old_irql, "read_filter");
2039        len = strlen(&TraceFilter[0]) + 1;
2040        if (max_length >= len) {
2041                memcpy(filter, &TraceFilter[0], len);
2042        }
2043        diva_os_leave_spin_lock(&dbg_q_lock, &old_irql, "read_filter");
2044
2045        return (len);
2046}
2047
2048static int diva_dbg_cmp_key(const char *ref, const char *key) {
2049        while (*key && (*ref++ == *key++));
2050        return (!*key && !*ref);
2051}
2052
2053/*
2054  In case trace filter starts with "C" character then
2055  all following characters are interpreted as command.
2056  Followings commands are available:
2057  - single, trace single call at time, independent from CPN/CiPN
2058*/
2059static int diva_mnt_cmp_nmbr(const char *nmbr) {
2060        const char *ref = &TraceFilter[0];
2061        int ref_len = strlen(&TraceFilter[0]), nmbr_len = strlen(nmbr);
2062
2063        if (ref[0] == 'C') {
2064                if (diva_dbg_cmp_key(&ref[1], "single")) {
2065                        return (0);
2066                }
2067                return (-1);
2068        }
2069
2070        if (!ref_len || (ref_len > nmbr_len)) {
2071                return (-1);
2072        }
2073
2074        nmbr = nmbr + nmbr_len - 1;
2075        ref  = ref  + ref_len  - 1;
2076
2077        while (ref_len--) {
2078                if (*nmbr-- != *ref--) {
2079                        return (-1);
2080                }
2081        }
2082
2083        return (0);
2084}
2085
2086static int diva_get_dma_descriptor(IDI_CALL request, dword *dma_magic) {
2087        ENTITY e;
2088        IDI_SYNC_REQ *pReq = (IDI_SYNC_REQ *)&e;
2089
2090        if (!request) {
2091                return (-1);
2092        }
2093
2094        pReq->xdi_dma_descriptor_operation.Req = 0;
2095        pReq->xdi_dma_descriptor_operation.Rc = IDI_SYNC_REQ_DMA_DESCRIPTOR_OPERATION;
2096
2097        pReq->xdi_dma_descriptor_operation.info.operation =     IDI_SYNC_REQ_DMA_DESCRIPTOR_ALLOC;
2098        pReq->xdi_dma_descriptor_operation.info.descriptor_number  = -1;
2099        pReq->xdi_dma_descriptor_operation.info.descriptor_address = NULL;
2100        pReq->xdi_dma_descriptor_operation.info.descriptor_magic   = 0;
2101
2102        (*request)((ENTITY *)pReq);
2103
2104        if (!pReq->xdi_dma_descriptor_operation.info.operation &&
2105            (pReq->xdi_dma_descriptor_operation.info.descriptor_number >= 0) &&
2106            pReq->xdi_dma_descriptor_operation.info.descriptor_magic) {
2107                *dma_magic = pReq->xdi_dma_descriptor_operation.info.descriptor_magic;
2108                return (pReq->xdi_dma_descriptor_operation.info.descriptor_number);
2109        } else {
2110                return (-1);
2111        }
2112}
2113
2114static void diva_free_dma_descriptor(IDI_CALL request, int nr) {
2115        ENTITY e;
2116        IDI_SYNC_REQ *pReq = (IDI_SYNC_REQ *)&e;
2117
2118        if (!request || (nr < 0)) {
2119                return;
2120        }
2121
2122        pReq->xdi_dma_descriptor_operation.Req = 0;
2123        pReq->xdi_dma_descriptor_operation.Rc = IDI_SYNC_REQ_DMA_DESCRIPTOR_OPERATION;
2124
2125        pReq->xdi_dma_descriptor_operation.info.operation = IDI_SYNC_REQ_DMA_DESCRIPTOR_FREE;
2126        pReq->xdi_dma_descriptor_operation.info.descriptor_number  = nr;
2127        pReq->xdi_dma_descriptor_operation.info.descriptor_address = NULL;
2128        pReq->xdi_dma_descriptor_operation.info.descriptor_magic   = 0;
2129
2130        (*request)((ENTITY *)pReq);
2131}
2132