0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #include <linux/module.h>
0014 #include <linux/string.h>
0015 #include <linux/ctype.h>
0016 #include <linux/stddef.h>
0017 #include <linux/kernel.h>
0018 #include <linux/mm.h>
0019 #include <linux/init.h>
0020 #include <linux/isdn/capiutil.h>
0021 #include <linux/slab.h>
0022
0023 #include "kcapi.h"
0024
0025
0026
0027 typedef struct {
0028 int typ;
0029 size_t off;
0030 } _cdef;
0031
0032 #define _CBYTE 1
0033 #define _CWORD 2
0034 #define _CDWORD 3
0035 #define _CSTRUCT 4
0036 #define _CMSTRUCT 5
0037 #define _CEND 6
0038
0039 static _cdef cdef[] =
0040 {
0041
0042 {_CEND},
0043
0044 {_CEND},
0045
0046 {_CEND},
0047
0048 {_CDWORD, offsetof(_cmsg, adr.adrController)},
0049
0050 {_CMSTRUCT, offsetof(_cmsg, AdditionalInfo)},
0051
0052 {_CSTRUCT, offsetof(_cmsg, B1configuration)},
0053
0054 {_CWORD, offsetof(_cmsg, B1protocol)},
0055
0056 {_CSTRUCT, offsetof(_cmsg, B2configuration)},
0057
0058 {_CWORD, offsetof(_cmsg, B2protocol)},
0059
0060 {_CSTRUCT, offsetof(_cmsg, B3configuration)},
0061
0062 {_CWORD, offsetof(_cmsg, B3protocol)},
0063
0064 {_CSTRUCT, offsetof(_cmsg, BC)},
0065
0066 {_CSTRUCT, offsetof(_cmsg, BChannelinformation)},
0067
0068 {_CMSTRUCT, offsetof(_cmsg, BProtocol)},
0069
0070 {_CSTRUCT, offsetof(_cmsg, CalledPartyNumber)},
0071
0072 {_CSTRUCT, offsetof(_cmsg, CalledPartySubaddress)},
0073
0074 {_CSTRUCT, offsetof(_cmsg, CallingPartyNumber)},
0075
0076 {_CSTRUCT, offsetof(_cmsg, CallingPartySubaddress)},
0077
0078 {_CDWORD, offsetof(_cmsg, CIPmask)},
0079
0080 {_CDWORD, offsetof(_cmsg, CIPmask2)},
0081
0082 {_CWORD, offsetof(_cmsg, CIPValue)},
0083
0084 {_CDWORD, offsetof(_cmsg, Class)},
0085
0086 {_CSTRUCT, offsetof(_cmsg, ConnectedNumber)},
0087
0088 {_CSTRUCT, offsetof(_cmsg, ConnectedSubaddress)},
0089
0090 {_CDWORD, offsetof(_cmsg, Data)},
0091
0092 {_CWORD, offsetof(_cmsg, DataHandle)},
0093
0094 {_CWORD, offsetof(_cmsg, DataLength)},
0095
0096 {_CSTRUCT, offsetof(_cmsg, FacilityConfirmationParameter)},
0097
0098 {_CSTRUCT, offsetof(_cmsg, Facilitydataarray)},
0099
0100 {_CSTRUCT, offsetof(_cmsg, FacilityIndicationParameter)},
0101
0102 {_CSTRUCT, offsetof(_cmsg, FacilityRequestParameter)},
0103
0104 {_CWORD, offsetof(_cmsg, FacilitySelector)},
0105
0106 {_CWORD, offsetof(_cmsg, Flags)},
0107
0108 {_CDWORD, offsetof(_cmsg, Function)},
0109
0110 {_CSTRUCT, offsetof(_cmsg, HLC)},
0111
0112 {_CWORD, offsetof(_cmsg, Info)},
0113
0114 {_CSTRUCT, offsetof(_cmsg, InfoElement)},
0115
0116 {_CDWORD, offsetof(_cmsg, InfoMask)},
0117
0118 {_CWORD, offsetof(_cmsg, InfoNumber)},
0119
0120 {_CSTRUCT, offsetof(_cmsg, Keypadfacility)},
0121
0122 {_CSTRUCT, offsetof(_cmsg, LLC)},
0123
0124 {_CSTRUCT, offsetof(_cmsg, ManuData)},
0125
0126 {_CDWORD, offsetof(_cmsg, ManuID)},
0127
0128 {_CSTRUCT, offsetof(_cmsg, NCPI)},
0129
0130 {_CWORD, offsetof(_cmsg, Reason)},
0131
0132 {_CWORD, offsetof(_cmsg, Reason_B3)},
0133
0134 {_CWORD, offsetof(_cmsg, Reject)},
0135
0136 {_CSTRUCT, offsetof(_cmsg, Useruserdata)}
0137 };
0138
0139 static unsigned char *cpars[] =
0140 {
0141 [0x01] = "\x03\x04\x0c\x27\x2f\x1c\x01\x01",
0142 [0x02] = "\x03\x14\x0e\x10\x0f\x11\x0d\x06\x08\x0a\x05\x07\x09\x01\x0b\x28\x22\x04\x0c\x27\x2f\x1c\x01\x01",
0143 [0x04] = "\x03\x04\x0c\x27\x2f\x1c\x01\x01",
0144 [0x05] = "\x03\x25\x12\x13\x10\x11\x01",
0145 [0x08] = "\x03\x0e\x04\x0c\x27\x2f\x1c\x01\x01",
0146 [0x09] = "\x03\x1f\x1e\x01",
0147 [0x0a] = "\x03\x0d\x06\x08\x0a\x05\x07\x09\x01\x01",
0148 [0x0b] = "\x03\x2b\x01",
0149 [0x0d] = "\x03\x2b\x01",
0150 [0x0f] = "\x03\x18\x1a\x19\x20\x01",
0151 [0x10] = "\x03\x2b\x01",
0152 [0x13] = "\x03\x23\x01",
0153 [0x14] = "\x03\x23\x01",
0154 [0x16] = "\x03\x23\x01",
0155 [0x17] = "\x03\x23\x01",
0156 [0x18] = "\x03\x2a\x15\x21\x29\x01",
0157 [0x1a] = "\x03\x23\x01",
0158 [0x1b] = "\x03\x23\x1f\x1b\x01",
0159 [0x1c] = "\x03\x23\x01",
0160 [0x1d] = "\x03\x23\x01",
0161 [0x1f] = "\x03\x23\x01",
0162 [0x21] = "\x03\x19\x23\x01",
0163 [0x22] = "\x03\x23\x01",
0164 [0x26] = "\x03\x14\x0e\x10\x0f\x11\x0b\x28\x22\x04\x0c\x27\x2f\x1c\x01\x01",
0165 [0x27] = "\x03\x16\x17\x28\x01",
0166 [0x28] = "\x03\x2c\x01",
0167 [0x2a] = "\x03\x2a\x15\x21\x29\x01",
0168 [0x2c] = "\x03\x26\x24\x01",
0169 [0x2d] = "\x03\x1f\x1d\x01",
0170 [0x2f] = "\x03\x2b\x01",
0171 [0x30] = "\x03\x2b\x01",
0172 [0x31] = "\x03\x2d\x2b\x01",
0173 [0x33] = "\x03\x18\x1a\x19\x20\x01",
0174 [0x34] = "\x03\x2b\x01",
0175 [0x35] = "\x03\x2b\x01",
0176 [0x38] = "\x03\x2e\x0d\x06\x08\x0a\x05\x07\x09\x01\x16\x17\x28\x04\x0c\x27\x2f\x1c\x01\x01",
0177 [0x39] = "\x03\x01",
0178 [0x3a] = "\x03\x01",
0179 [0x3c] = "\x03\x2a\x15\x21\x29\x01",
0180 [0x3e] = "\x03\x01",
0181 [0x3f] = "\x03\x1f\x01",
0182 [0x41] = "\x03\x2e\x2b\x01",
0183 [0x42] = "\x03\x01",
0184 [0x43] = "\x03\x01",
0185 [0x45] = "\x03\x19\x01",
0186 [0x46] = "\x03\x01",
0187 [0x47] = "\x03\x01",
0188 [0x4e] = "\x03\x2a\x15\x21\x29\x01",
0189 };
0190
0191
0192
0193 #define byteTLcpy(x, y) *(u8 *)(x) = *(u8 *)(y);
0194 #define wordTLcpy(x, y) *(u16 *)(x) = *(u16 *)(y);
0195 #define dwordTLcpy(x, y) memcpy(x, y, 4);
0196 #define structTLcpy(x, y, l) memcpy(x, y, l)
0197 #define structTLcpyovl(x, y, l) memmove(x, y, l)
0198
0199 #define byteTRcpy(x, y) *(u8 *)(y) = *(u8 *)(x);
0200 #define wordTRcpy(x, y) *(u16 *)(y) = *(u16 *)(x);
0201 #define dwordTRcpy(x, y) memcpy(y, x, 4);
0202 #define structTRcpy(x, y, l) memcpy(y, x, l)
0203 #define structTRcpyovl(x, y, l) memmove(y, x, l)
0204
0205
0206 static unsigned command_2_index(u8 c, u8 sc)
0207 {
0208 if (c & 0x80)
0209 c = 0x9 + (c & 0x0f);
0210 else if (c == 0x41)
0211 c = 0x9 + 0x1;
0212 if (c > 0x18)
0213 c = 0x00;
0214 return (sc & 3) * (0x9 + 0x9) + c;
0215 }
0216
0217
0218
0219
0220
0221
0222
0223
0224
0225 static unsigned char *capi_cmd2par(u8 cmd, u8 subcmd)
0226 {
0227 return cpars[command_2_index(cmd, subcmd)];
0228 }
0229
0230
0231 #define TYP (cdef[cmsg->par[cmsg->p]].typ)
0232 #define OFF (((u8 *)cmsg) + cdef[cmsg->par[cmsg->p]].off)
0233
0234 static void jumpcstruct(_cmsg *cmsg)
0235 {
0236 unsigned layer;
0237 for (cmsg->p++, layer = 1; layer;) {
0238
0239 cmsg->p++;
0240 switch (TYP) {
0241 case _CMSTRUCT:
0242 layer++;
0243 break;
0244 case _CEND:
0245 layer--;
0246 break;
0247 }
0248 }
0249 }
0250
0251
0252
0253 static char *mnames[] =
0254 {
0255 [0x01] = "ALERT_REQ",
0256 [0x02] = "CONNECT_REQ",
0257 [0x04] = "DISCONNECT_REQ",
0258 [0x05] = "LISTEN_REQ",
0259 [0x08] = "INFO_REQ",
0260 [0x09] = "FACILITY_REQ",
0261 [0x0a] = "SELECT_B_PROTOCOL_REQ",
0262 [0x0b] = "CONNECT_B3_REQ",
0263 [0x0d] = "DISCONNECT_B3_REQ",
0264 [0x0f] = "DATA_B3_REQ",
0265 [0x10] = "RESET_B3_REQ",
0266 [0x13] = "ALERT_CONF",
0267 [0x14] = "CONNECT_CONF",
0268 [0x16] = "DISCONNECT_CONF",
0269 [0x17] = "LISTEN_CONF",
0270 [0x18] = "MANUFACTURER_REQ",
0271 [0x1a] = "INFO_CONF",
0272 [0x1b] = "FACILITY_CONF",
0273 [0x1c] = "SELECT_B_PROTOCOL_CONF",
0274 [0x1d] = "CONNECT_B3_CONF",
0275 [0x1f] = "DISCONNECT_B3_CONF",
0276 [0x21] = "DATA_B3_CONF",
0277 [0x22] = "RESET_B3_CONF",
0278 [0x26] = "CONNECT_IND",
0279 [0x27] = "CONNECT_ACTIVE_IND",
0280 [0x28] = "DISCONNECT_IND",
0281 [0x2a] = "MANUFACTURER_CONF",
0282 [0x2c] = "INFO_IND",
0283 [0x2d] = "FACILITY_IND",
0284 [0x2f] = "CONNECT_B3_IND",
0285 [0x30] = "CONNECT_B3_ACTIVE_IND",
0286 [0x31] = "DISCONNECT_B3_IND",
0287 [0x33] = "DATA_B3_IND",
0288 [0x34] = "RESET_B3_IND",
0289 [0x35] = "CONNECT_B3_T90_ACTIVE_IND",
0290 [0x38] = "CONNECT_RESP",
0291 [0x39] = "CONNECT_ACTIVE_RESP",
0292 [0x3a] = "DISCONNECT_RESP",
0293 [0x3c] = "MANUFACTURER_IND",
0294 [0x3e] = "INFO_RESP",
0295 [0x3f] = "FACILITY_RESP",
0296 [0x41] = "CONNECT_B3_RESP",
0297 [0x42] = "CONNECT_B3_ACTIVE_RESP",
0298 [0x43] = "DISCONNECT_B3_RESP",
0299 [0x45] = "DATA_B3_RESP",
0300 [0x46] = "RESET_B3_RESP",
0301 [0x47] = "CONNECT_B3_T90_ACTIVE_RESP",
0302 [0x4e] = "MANUFACTURER_RESP"
0303 };
0304
0305
0306
0307
0308
0309
0310
0311
0312
0313 char *capi_cmd2str(u8 cmd, u8 subcmd)
0314 {
0315 char *result;
0316
0317 result = mnames[command_2_index(cmd, subcmd)];
0318 if (result == NULL)
0319 result = "INVALID_COMMAND";
0320 return result;
0321 }
0322
0323
0324
0325
0326 #ifdef CONFIG_CAPI_TRACE
0327
0328
0329
0330 static char *pnames[] =
0331 {
0332 NULL,
0333 NULL,
0334 NULL,
0335 "Controller/PLCI/NCCI",
0336 "AdditionalInfo",
0337 "B1configuration",
0338 "B1protocol",
0339 "B2configuration",
0340 "B2protocol",
0341 "B3configuration",
0342 "B3protocol",
0343 "BC",
0344 "BChannelinformation",
0345 "BProtocol",
0346 "CalledPartyNumber",
0347 "CalledPartySubaddress",
0348 "CallingPartyNumber",
0349 "CallingPartySubaddress",
0350 "CIPmask",
0351 "CIPmask2",
0352 "CIPValue",
0353 "Class",
0354 "ConnectedNumber",
0355 "ConnectedSubaddress",
0356 "Data32",
0357 "DataHandle",
0358 "DataLength",
0359 "FacilityConfirmationParameter",
0360 "Facilitydataarray",
0361 "FacilityIndicationParameter",
0362 "FacilityRequestParameter",
0363 "FacilitySelector",
0364 "Flags",
0365 "Function",
0366 "HLC",
0367 "Info",
0368 "InfoElement",
0369 "InfoMask",
0370 "InfoNumber",
0371 "Keypadfacility",
0372 "LLC",
0373 "ManuData",
0374 "ManuID",
0375 "NCPI",
0376 "Reason",
0377 "Reason_B3",
0378 "Reject",
0379 "Useruserdata"
0380 };
0381
0382 #include <linux/stdarg.h>
0383
0384
0385 static _cdebbuf *bufprint(_cdebbuf *cdb, char *fmt, ...)
0386 {
0387 va_list f;
0388 size_t n, r;
0389
0390 if (!cdb)
0391 return NULL;
0392 va_start(f, fmt);
0393 r = cdb->size - cdb->pos;
0394 n = vsnprintf(cdb->p, r, fmt, f);
0395 va_end(f);
0396 if (n >= r) {
0397
0398 size_t ns = 2 * cdb->size;
0399 u_char *nb;
0400
0401 while ((ns - cdb->pos) <= n)
0402 ns *= 2;
0403 nb = kmalloc(ns, GFP_ATOMIC);
0404 if (!nb) {
0405 cdebbuf_free(cdb);
0406 return NULL;
0407 }
0408 memcpy(nb, cdb->buf, cdb->pos);
0409 kfree(cdb->buf);
0410 nb[cdb->pos] = 0;
0411 cdb->buf = nb;
0412 cdb->p = cdb->buf + cdb->pos;
0413 cdb->size = ns;
0414 va_start(f, fmt);
0415 r = cdb->size - cdb->pos;
0416 n = vsnprintf(cdb->p, r, fmt, f);
0417 va_end(f);
0418 }
0419 cdb->p += n;
0420 cdb->pos += n;
0421 return cdb;
0422 }
0423
0424 static _cdebbuf *printstructlen(_cdebbuf *cdb, u8 *m, unsigned len)
0425 {
0426 unsigned hex = 0;
0427
0428 if (!cdb)
0429 return NULL;
0430 for (; len; len--, m++)
0431 if (isalnum(*m) || *m == ' ') {
0432 if (hex)
0433 cdb = bufprint(cdb, ">");
0434 cdb = bufprint(cdb, "%c", *m);
0435 hex = 0;
0436 } else {
0437 if (!hex)
0438 cdb = bufprint(cdb, "<%02x", *m);
0439 else
0440 cdb = bufprint(cdb, " %02x", *m);
0441 hex = 1;
0442 }
0443 if (hex)
0444 cdb = bufprint(cdb, ">");
0445 return cdb;
0446 }
0447
0448 static _cdebbuf *printstruct(_cdebbuf *cdb, u8 *m)
0449 {
0450 unsigned len;
0451
0452 if (m[0] != 0xff) {
0453 len = m[0];
0454 m += 1;
0455 } else {
0456 len = ((u16 *) (m + 1))[0];
0457 m += 3;
0458 }
0459 cdb = printstructlen(cdb, m, len);
0460 return cdb;
0461 }
0462
0463
0464 #define NAME (pnames[cmsg->par[cmsg->p]])
0465
0466 static _cdebbuf *protocol_message_2_pars(_cdebbuf *cdb, _cmsg *cmsg, int level)
0467 {
0468 if (!cmsg->par)
0469 return NULL;
0470
0471 for (; TYP != _CEND; cmsg->p++) {
0472 int slen = 29 + 3 - level;
0473 int i;
0474
0475 if (!cdb)
0476 return NULL;
0477 cdb = bufprint(cdb, " ");
0478 for (i = 0; i < level - 1; i++)
0479 cdb = bufprint(cdb, " ");
0480
0481 switch (TYP) {
0482 case _CBYTE:
0483 cdb = bufprint(cdb, "%-*s = 0x%x\n", slen, NAME, *(u8 *) (cmsg->m + cmsg->l));
0484 cmsg->l++;
0485 break;
0486 case _CWORD:
0487 cdb = bufprint(cdb, "%-*s = 0x%x\n", slen, NAME, *(u16 *) (cmsg->m + cmsg->l));
0488 cmsg->l += 2;
0489 break;
0490 case _CDWORD:
0491 cdb = bufprint(cdb, "%-*s = 0x%lx\n", slen, NAME, *(u32 *) (cmsg->m + cmsg->l));
0492 cmsg->l += 4;
0493 break;
0494 case _CSTRUCT:
0495 cdb = bufprint(cdb, "%-*s = ", slen, NAME);
0496 if (cmsg->m[cmsg->l] == '\0')
0497 cdb = bufprint(cdb, "default");
0498 else
0499 cdb = printstruct(cdb, cmsg->m + cmsg->l);
0500 cdb = bufprint(cdb, "\n");
0501 if (cmsg->m[cmsg->l] != 0xff)
0502 cmsg->l += 1 + cmsg->m[cmsg->l];
0503 else
0504 cmsg->l += 3 + *(u16 *) (cmsg->m + cmsg->l + 1);
0505
0506 break;
0507
0508 case _CMSTRUCT:
0509
0510 if (cmsg->m[cmsg->l] == '\0') {
0511 cdb = bufprint(cdb, "%-*s = default\n", slen, NAME);
0512 cmsg->l++;
0513 jumpcstruct(cmsg);
0514 } else {
0515 char *name = NAME;
0516 unsigned _l = cmsg->l;
0517 cdb = bufprint(cdb, "%-*s\n", slen, name);
0518 cmsg->l = (cmsg->m + _l)[0] == 255 ? cmsg->l + 3 : cmsg->l + 1;
0519 cmsg->p++;
0520 cdb = protocol_message_2_pars(cdb, cmsg, level + 1);
0521 }
0522 break;
0523 }
0524 }
0525 return cdb;
0526 }
0527
0528
0529 static _cdebbuf *g_debbuf;
0530 static u_long g_debbuf_lock;
0531 static _cmsg *g_cmsg;
0532
0533 static _cdebbuf *cdebbuf_alloc(void)
0534 {
0535 _cdebbuf *cdb;
0536
0537 if (likely(!test_and_set_bit(1, &g_debbuf_lock))) {
0538 cdb = g_debbuf;
0539 goto init;
0540 } else
0541 cdb = kmalloc(sizeof(_cdebbuf), GFP_ATOMIC);
0542 if (!cdb)
0543 return NULL;
0544 cdb->buf = kmalloc(CDEBUG_SIZE, GFP_ATOMIC);
0545 if (!cdb->buf) {
0546 kfree(cdb);
0547 return NULL;
0548 }
0549 cdb->size = CDEBUG_SIZE;
0550 init:
0551 cdb->buf[0] = 0;
0552 cdb->p = cdb->buf;
0553 cdb->pos = 0;
0554 return cdb;
0555 }
0556
0557
0558
0559
0560
0561
0562 void cdebbuf_free(_cdebbuf *cdb)
0563 {
0564 if (likely(cdb == g_debbuf)) {
0565 test_and_clear_bit(1, &g_debbuf_lock);
0566 return;
0567 }
0568 if (likely(cdb))
0569 kfree(cdb->buf);
0570 kfree(cdb);
0571 }
0572
0573
0574
0575
0576
0577
0578
0579
0580
0581
0582
0583
0584 _cdebbuf *capi_message2str(u8 *msg)
0585 {
0586 _cdebbuf *cdb;
0587 _cmsg *cmsg;
0588
0589 cdb = cdebbuf_alloc();
0590 if (unlikely(!cdb))
0591 return NULL;
0592 if (likely(cdb == g_debbuf))
0593 cmsg = g_cmsg;
0594 else
0595 cmsg = kmalloc(sizeof(_cmsg), GFP_ATOMIC);
0596 if (unlikely(!cmsg)) {
0597 cdebbuf_free(cdb);
0598 return NULL;
0599 }
0600 cmsg->m = msg;
0601 cmsg->l = 8;
0602 cmsg->p = 0;
0603 byteTRcpy(cmsg->m + 4, &cmsg->Command);
0604 byteTRcpy(cmsg->m + 5, &cmsg->Subcommand);
0605 cmsg->par = capi_cmd2par(cmsg->Command, cmsg->Subcommand);
0606
0607 cdb = bufprint(cdb, "%-26s ID=%03d #0x%04x LEN=%04d\n",
0608 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
0609 ((unsigned short *) msg)[1],
0610 ((unsigned short *) msg)[3],
0611 ((unsigned short *) msg)[0]);
0612
0613 cdb = protocol_message_2_pars(cdb, cmsg, 1);
0614 if (unlikely(cmsg != g_cmsg))
0615 kfree(cmsg);
0616 return cdb;
0617 }
0618
0619 int __init cdebug_init(void)
0620 {
0621 g_cmsg = kmalloc(sizeof(_cmsg), GFP_KERNEL);
0622 if (!g_cmsg)
0623 return -ENOMEM;
0624 g_debbuf = kmalloc(sizeof(_cdebbuf), GFP_KERNEL);
0625 if (!g_debbuf) {
0626 kfree(g_cmsg);
0627 return -ENOMEM;
0628 }
0629 g_debbuf->buf = kmalloc(CDEBUG_GSIZE, GFP_KERNEL);
0630 if (!g_debbuf->buf) {
0631 kfree(g_cmsg);
0632 kfree(g_debbuf);
0633 return -ENOMEM;
0634 }
0635 g_debbuf->size = CDEBUG_GSIZE;
0636 g_debbuf->buf[0] = 0;
0637 g_debbuf->p = g_debbuf->buf;
0638 g_debbuf->pos = 0;
0639 return 0;
0640 }
0641
0642 void cdebug_exit(void)
0643 {
0644 if (g_debbuf)
0645 kfree(g_debbuf->buf);
0646 kfree(g_debbuf);
0647 kfree(g_cmsg);
0648 }
0649
0650 #else
0651
0652 static _cdebbuf g_debbuf = {"CONFIG_CAPI_TRACE not enabled", NULL, 0, 0};
0653
0654 _cdebbuf *capi_message2str(u8 *msg)
0655 {
0656 return &g_debbuf;
0657 }
0658
0659 _cdebbuf *capi_cmsg2str(_cmsg *cmsg)
0660 {
0661 return &g_debbuf;
0662 }
0663
0664 void cdebbuf_free(_cdebbuf *cdb)
0665 {
0666 }
0667
0668 int __init cdebug_init(void)
0669 {
0670 return 0;
0671 }
0672
0673 void cdebug_exit(void)
0674 {
0675 }
0676
0677 #endif