Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | |
| 2 | /* |
| 3 | * |
| 4 | Copyright (c) Eicon Networks, 2002. |
| 5 | * |
| 6 | This source file is supplied for the use with |
| 7 | Eicon Networks range of DIVA Server Adapters. |
| 8 | * |
| 9 | Eicon File Revision : 2.1 |
| 10 | * |
| 11 | This program is free software; you can redistribute it and/or modify |
| 12 | it under the terms of the GNU General Public License as published by |
| 13 | the Free Software Foundation; either version 2, or (at your option) |
| 14 | any later version. |
| 15 | * |
| 16 | This program is distributed in the hope that it will be useful, |
| 17 | but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY |
| 18 | implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
| 19 | See the GNU General Public License for more details. |
| 20 | * |
| 21 | You should have received a copy of the GNU General Public License |
| 22 | along with this program; if not, write to the Free Software |
| 23 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
| 24 | * |
| 25 | */ |
| 26 | #include "platform.h" |
| 27 | #include "pc.h" |
| 28 | #include "pr_pc.h" |
| 29 | #include "di_defs.h" |
| 30 | #include "di.h" |
| 31 | #if !defined USE_EXTENDED_DEBUGS |
| 32 | #include "dimaint.h" |
| 33 | #else |
| 34 | #define dprintf |
| 35 | #endif |
| 36 | #include "io.h" |
| 37 | #include "dfifo.h" |
| 38 | #define PR_RAM ((struct pr_ram *)0) |
| 39 | #define RAM ((struct dual *)0) |
| 40 | /*------------------------------------------------------------------*/ |
| 41 | /* local function prototypes */ |
| 42 | /*------------------------------------------------------------------*/ |
| 43 | void pr_out(ADAPTER * a); |
| 44 | byte pr_dpc(ADAPTER * a); |
| 45 | static byte pr_ready(ADAPTER * a); |
| 46 | static byte isdn_rc(ADAPTER *, byte, byte, byte, word, dword, dword); |
| 47 | static byte isdn_ind(ADAPTER *, byte, byte, byte, PBUFFER *, byte, word); |
| 48 | /* ----------------------------------------------------------------- |
| 49 | Functions used for the extended XDI Debug |
| 50 | macros |
| 51 | global convergence counter (used by all adapters) |
| 52 | Look by the implementation part of the functions |
| 53 | about the parameters. |
| 54 | If you change the dubugging parameters, then you should update |
| 55 | the aididbg.doc in the IDI doc's. |
| 56 | ----------------------------------------------------------------- */ |
| 57 | #if defined(XDI_USE_XLOG) |
| 58 | #define XDI_A_NR(_x_) ((byte)(((ISDN_ADAPTER *)(_x_->io))->ANum)) |
| 59 | static void xdi_xlog (byte *msg, word code, int length); |
| 60 | static byte xdi_xlog_sec = 0; |
| 61 | #else |
| 62 | #define XDI_A_NR(_x_) ((byte)0) |
| 63 | #endif |
| 64 | static void xdi_xlog_rc_event (byte Adapter, |
| 65 | byte Id, byte Ch, byte Rc, byte cb, byte type); |
| 66 | static void xdi_xlog_request (byte Adapter, byte Id, |
| 67 | byte Ch, byte Req, byte type); |
| 68 | static void xdi_xlog_ind (byte Adapter, |
| 69 | byte Id, |
| 70 | byte Ch, |
| 71 | byte Ind, |
| 72 | byte rnr_valid, |
| 73 | byte rnr, |
| 74 | byte type); |
| 75 | /*------------------------------------------------------------------*/ |
| 76 | /* output function */ |
| 77 | /*------------------------------------------------------------------*/ |
| 78 | void pr_out(ADAPTER * a) |
| 79 | { |
| 80 | byte e_no; |
| 81 | ENTITY * this = NULL; |
| 82 | BUFFERS *X; |
| 83 | word length; |
| 84 | word i; |
| 85 | word clength; |
| 86 | REQ * ReqOut; |
| 87 | byte more; |
| 88 | byte ReadyCount; |
| 89 | byte ReqCount; |
| 90 | byte Id; |
| 91 | dtrc(dprintf("pr_out")); |
| 92 | /* while a request is pending ... */ |
| 93 | e_no = look_req(a); |
| 94 | if(!e_no) |
| 95 | { |
| 96 | dtrc(dprintf("no_req")); |
| 97 | return; |
| 98 | } |
| 99 | ReadyCount = pr_ready(a); |
| 100 | if(!ReadyCount) |
| 101 | { |
| 102 | dtrc(dprintf("not_ready")); |
| 103 | return; |
| 104 | } |
| 105 | ReqCount = 0; |
| 106 | while(e_no && ReadyCount) { |
| 107 | next_req(a); |
| 108 | this = entity_ptr(a, e_no); |
| 109 | #ifdef USE_EXTENDED_DEBUGS |
| 110 | if ( !this ) |
| 111 | { |
| 112 | DBG_FTL(("XDI: [%02x] !A%d ==> NULL entity ptr - try to ignore", |
| 113 | xdi_xlog_sec++, (int)((ISDN_ADAPTER *)a->io)->ANum)) |
| 114 | e_no = look_req(a) ; |
| 115 | ReadyCount-- ; |
| 116 | continue ; |
| 117 | } |
| 118 | { |
| 119 | DBG_TRC((">A%d Id=0x%x Req=0x%x", ((ISDN_ADAPTER *)a->io)->ANum, this->Id, this->Req)) |
| 120 | } |
| 121 | #else |
| 122 | dbug(dprintf("out:Req=%x,Id=%x,Ch=%x",this->Req,this->Id,this->ReqCh)); |
| 123 | #endif |
| 124 | /* get address of next available request buffer */ |
| 125 | ReqOut = (REQ *)&PR_RAM->B[a->ram_inw(a, &PR_RAM->NextReq)]; |
| 126 | #if defined(DIVA_ISTREAM) |
| 127 | if (!(a->tx_stream[this->Id] && |
| 128 | this->Req == N_DATA)) { |
| 129 | #endif |
| 130 | /* now copy the data from the current data buffer into the */ |
| 131 | /* adapters request buffer */ |
| 132 | length = 0; |
| 133 | i = this->XCurrent; |
| 134 | X = PTR_X(a,this); |
| 135 | while(i<this->XNum && length<270) { |
| 136 | clength = MIN((word)(270-length),X[i].PLength-this->XOffset); |
| 137 | a->ram_out_buffer(a, |
| 138 | &ReqOut->XBuffer.P[length], |
| 139 | PTR_P(a,this,&X[i].P[this->XOffset]), |
| 140 | clength); |
| 141 | length +=clength; |
| 142 | this->XOffset +=clength; |
| 143 | if(this->XOffset==X[i].PLength) { |
| 144 | this->XCurrent = (byte)++i; |
| 145 | this->XOffset = 0; |
| 146 | } |
| 147 | } |
| 148 | #if defined(DIVA_ISTREAM) |
| 149 | } else { /* Use CMA extension in order to transfer data to the card */ |
| 150 | i = this->XCurrent; |
| 151 | X = PTR_X(a,this); |
| 152 | while (i < this->XNum) { |
| 153 | diva_istream_write (a, |
| 154 | this->Id, |
| 155 | PTR_P(a,this,&X[i].P[0]), |
| 156 | X[i].PLength, |
| 157 | ((i+1) == this->XNum), |
| 158 | 0, 0); |
| 159 | this->XCurrent = (byte)++i; |
| 160 | } |
| 161 | length = 0; |
| 162 | } |
| 163 | #endif |
| 164 | a->ram_outw(a, &ReqOut->XBuffer.length, length); |
| 165 | a->ram_out(a, &ReqOut->ReqId, this->Id); |
| 166 | a->ram_out(a, &ReqOut->ReqCh, this->ReqCh); |
| 167 | /* if it's a specific request (no ASSIGN) ... */ |
| 168 | if(this->Id &0x1f) { |
| 169 | /* if buffers are left in the list of data buffers do */ |
| 170 | /* do chaining (LL_MDATA, N_MDATA) */ |
| 171 | this->More++; |
| 172 | if(i<this->XNum && this->MInd) { |
| 173 | xdi_xlog_request (XDI_A_NR(a), this->Id, this->ReqCh, this->MInd, |
| 174 | a->IdTypeTable[this->No]); |
| 175 | a->ram_out(a, &ReqOut->Req, this->MInd); |
| 176 | more = TRUE; |
| 177 | } |
| 178 | else { |
| 179 | xdi_xlog_request (XDI_A_NR(a), this->Id, this->ReqCh, this->Req, |
| 180 | a->IdTypeTable[this->No]); |
| 181 | this->More |=XMOREF; |
| 182 | a->ram_out(a, &ReqOut->Req, this->Req); |
| 183 | more = FALSE; |
| 184 | if (a->FlowControlIdTable[this->ReqCh] == this->Id) |
| 185 | a->FlowControlSkipTable[this->ReqCh] = TRUE; |
| 186 | /* |
| 187 | Note that remove request was sent to the card |
| 188 | */ |
| 189 | if (this->Req == REMOVE) { |
| 190 | a->misc_flags_table[e_no] |= DIVA_MISC_FLAGS_REMOVE_PENDING; |
| 191 | } |
| 192 | } |
| 193 | /* if we did chaining, this entity is put back into the */ |
| 194 | /* request queue */ |
| 195 | if(more) { |
| 196 | req_queue(a,this->No); |
| 197 | } |
| 198 | } |
| 199 | /* else it's a ASSIGN */ |
| 200 | else { |
| 201 | /* save the request code used for buffer chaining */ |
| 202 | this->MInd = 0; |
| 203 | if (this->Id==BLLC_ID) this->MInd = LL_MDATA; |
| 204 | if (this->Id==NL_ID || |
| 205 | this->Id==TASK_ID || |
| 206 | this->Id==MAN_ID |
| 207 | ) this->MInd = N_MDATA; |
| 208 | /* send the ASSIGN */ |
| 209 | a->IdTypeTable[this->No] = this->Id; |
| 210 | xdi_xlog_request (XDI_A_NR(a),this->Id,this->ReqCh,this->Req, this->Id); |
| 211 | this->More |=XMOREF; |
| 212 | a->ram_out(a, &ReqOut->Req, this->Req); |
| 213 | /* save the reference of the ASSIGN */ |
| 214 | assign_queue(a, this->No, a->ram_inw(a, &ReqOut->Reference)); |
| 215 | } |
| 216 | a->ram_outw(a, &PR_RAM->NextReq, a->ram_inw(a, &ReqOut->next)); |
| 217 | ReadyCount--; |
| 218 | ReqCount++; |
| 219 | e_no = look_req(a); |
| 220 | } |
| 221 | /* send the filled request buffers to the ISDN adapter */ |
| 222 | a->ram_out(a, &PR_RAM->ReqInput, |
| 223 | (byte)(a->ram_in(a, &PR_RAM->ReqInput) + ReqCount)); |
| 224 | /* if it is a 'unreturncoded' UREMOVE request, remove the */ |
| 225 | /* Id from our table after sending the request */ |
| 226 | if(this && (this->Req==UREMOVE) && this->Id) { |
| 227 | Id = this->Id; |
| 228 | e_no = a->IdTable[Id]; |
| 229 | free_entity(a, e_no); |
| 230 | for (i = 0; i < 256; i++) |
| 231 | { |
| 232 | if (a->FlowControlIdTable[i] == Id) |
| 233 | a->FlowControlIdTable[i] = 0; |
| 234 | } |
| 235 | a->IdTable[Id] = 0; |
| 236 | this->Id = 0; |
| 237 | } |
| 238 | } |
| 239 | static byte pr_ready(ADAPTER * a) |
| 240 | { |
| 241 | byte ReadyCount; |
| 242 | ReadyCount = (byte)(a->ram_in(a, &PR_RAM->ReqOutput) - |
| 243 | a->ram_in(a, &PR_RAM->ReqInput)); |
| 244 | if(!ReadyCount) { |
| 245 | if(!a->ReadyInt) { |
| 246 | a->ram_inc(a, &PR_RAM->ReadyInt); |
| 247 | a->ReadyInt++; |
| 248 | } |
| 249 | } |
| 250 | return ReadyCount; |
| 251 | } |
| 252 | /*------------------------------------------------------------------*/ |
| 253 | /* isdn interrupt handler */ |
| 254 | /*------------------------------------------------------------------*/ |
| 255 | byte pr_dpc(ADAPTER * a) |
| 256 | { |
| 257 | byte Count; |
| 258 | RC * RcIn; |
| 259 | IND * IndIn; |
| 260 | byte c; |
| 261 | byte RNRId; |
| 262 | byte Rc; |
| 263 | byte Ind; |
| 264 | /* if return codes are available ... */ |
| 265 | if((Count = a->ram_in(a, &PR_RAM->RcOutput)) != 0) { |
| 266 | dtrc(dprintf("#Rc=%x",Count)); |
| 267 | /* get the buffer address of the first return code */ |
| 268 | RcIn = (RC *)&PR_RAM->B[a->ram_inw(a, &PR_RAM->NextRc)]; |
| 269 | /* for all return codes do ... */ |
| 270 | while(Count--) { |
| 271 | if((Rc=a->ram_in(a, &RcIn->Rc)) != 0) { |
| 272 | dword tmp[2]; |
| 273 | /* |
| 274 | Get extended information, associated with return code |
| 275 | */ |
| 276 | a->ram_in_buffer(a, |
| 277 | &RcIn->Reserved2[0], |
| 278 | (byte*)&tmp[0], |
| 279 | 8); |
| 280 | /* call return code handler, if it is not our return code */ |
| 281 | /* the handler returns 2 */ |
| 282 | /* for all return codes we process, we clear the Rc field */ |
| 283 | isdn_rc(a, |
| 284 | Rc, |
| 285 | a->ram_in(a, &RcIn->RcId), |
| 286 | a->ram_in(a, &RcIn->RcCh), |
| 287 | a->ram_inw(a, &RcIn->Reference), |
| 288 | tmp[0], /* type of extended informtion */ |
| 289 | tmp[1]); /* extended information */ |
| 290 | a->ram_out(a, &RcIn->Rc, 0); |
| 291 | } |
| 292 | /* get buffer address of next return code */ |
| 293 | RcIn = (RC *)&PR_RAM->B[a->ram_inw(a, &RcIn->next)]; |
| 294 | } |
| 295 | /* clear all return codes (no chaining!) */ |
| 296 | a->ram_out(a, &PR_RAM->RcOutput ,0); |
| 297 | /* call output function */ |
| 298 | pr_out(a); |
| 299 | } |
| 300 | /* clear RNR flag */ |
| 301 | RNRId = 0; |
| 302 | /* if indications are available ... */ |
| 303 | if((Count = a->ram_in(a, &PR_RAM->IndOutput)) != 0) { |
| 304 | dtrc(dprintf("#Ind=%x",Count)); |
| 305 | /* get the buffer address of the first indication */ |
| 306 | IndIn = (IND *)&PR_RAM->B[a->ram_inw(a, &PR_RAM->NextInd)]; |
| 307 | /* for all indications do ... */ |
| 308 | while(Count--) { |
| 309 | /* if the application marks an indication as RNR, all */ |
| 310 | /* indications from the same Id delivered in this interrupt */ |
| 311 | /* are marked RNR */ |
| 312 | if(RNRId && RNRId==a->ram_in(a, &IndIn->IndId)) { |
| 313 | a->ram_out(a, &IndIn->Ind, 0); |
| 314 | a->ram_out(a, &IndIn->RNR, TRUE); |
| 315 | } |
| 316 | else { |
| 317 | Ind = a->ram_in(a, &IndIn->Ind); |
| 318 | if(Ind) { |
| 319 | RNRId = 0; |
| 320 | /* call indication handler, a return value of 2 means chain */ |
| 321 | /* a return value of 1 means RNR */ |
| 322 | /* for all indications we process, we clear the Ind field */ |
| 323 | c = isdn_ind(a, |
| 324 | Ind, |
| 325 | a->ram_in(a, &IndIn->IndId), |
| 326 | a->ram_in(a, &IndIn->IndCh), |
| 327 | &IndIn->RBuffer, |
| 328 | a->ram_in(a, &IndIn->MInd), |
| 329 | a->ram_inw(a, &IndIn->MLength)); |
| 330 | if(c==1) { |
| 331 | dtrc(dprintf("RNR")); |
| 332 | a->ram_out(a, &IndIn->Ind, 0); |
| 333 | RNRId = a->ram_in(a, &IndIn->IndId); |
| 334 | a->ram_out(a, &IndIn->RNR, TRUE); |
| 335 | } |
| 336 | } |
| 337 | } |
| 338 | /* get buffer address of next indication */ |
| 339 | IndIn = (IND *)&PR_RAM->B[a->ram_inw(a, &IndIn->next)]; |
| 340 | } |
| 341 | a->ram_out(a, &PR_RAM->IndOutput, 0); |
| 342 | } |
| 343 | return FALSE; |
| 344 | } |
| 345 | byte scom_test_int(ADAPTER * a) |
| 346 | { |
| 347 | return a->ram_in(a,(void *)0x3fe); |
| 348 | } |
| 349 | void scom_clear_int(ADAPTER * a) |
| 350 | { |
| 351 | a->ram_out(a,(void *)0x3fe,0); |
| 352 | } |
| 353 | /*------------------------------------------------------------------*/ |
| 354 | /* return code handler */ |
| 355 | /*------------------------------------------------------------------*/ |
| 356 | byte isdn_rc(ADAPTER * a, |
| 357 | byte Rc, |
| 358 | byte Id, |
| 359 | byte Ch, |
| 360 | word Ref, |
| 361 | dword extended_info_type, |
| 362 | dword extended_info) |
| 363 | { |
| 364 | ENTITY * this; |
| 365 | byte e_no; |
| 366 | word i; |
| 367 | int cancel_rc; |
| 368 | #ifdef USE_EXTENDED_DEBUGS |
| 369 | { |
| 370 | DBG_TRC(("<A%d Id=0x%x Rc=0x%x", ((ISDN_ADAPTER *)a->io)->ANum, Id, Rc)) |
| 371 | } |
| 372 | #else |
| 373 | dbug(dprintf("isdn_rc(Rc=%x,Id=%x,Ch=%x)",Rc,Id,Ch)); |
| 374 | #endif |
| 375 | /* check for ready interrupt */ |
| 376 | if(Rc==READY_INT) { |
| 377 | xdi_xlog_rc_event (XDI_A_NR(a), Id, Ch, Rc, 0, 0); |
| 378 | if(a->ReadyInt) { |
| 379 | a->ReadyInt--; |
| 380 | return 0; |
| 381 | } |
| 382 | return 2; |
| 383 | } |
| 384 | /* if we know this Id ... */ |
| 385 | e_no = a->IdTable[Id]; |
| 386 | if(e_no) { |
| 387 | this = entity_ptr(a,e_no); |
| 388 | xdi_xlog_rc_event (XDI_A_NR(a), Id, Ch, Rc, 0, a->IdTypeTable[this->No]); |
| 389 | this->RcCh = Ch; |
| 390 | /* if it is a return code to a REMOVE request, remove the */ |
| 391 | /* Id from our table */ |
| 392 | if ((a->misc_flags_table[e_no] & DIVA_MISC_FLAGS_REMOVE_PENDING) && |
| 393 | (Rc==OK)) { |
| 394 | if (a->IdTypeTable[e_no] == NL_ID) { |
| 395 | if (a->RcExtensionSupported && |
| 396 | (extended_info_type != DIVA_RC_TYPE_REMOVE_COMPLETE)) { |
| 397 | dtrc(dprintf("XDI: N-REMOVE, A(%02x) Id:%02x, ignore RC=OK", |
| 398 | XDI_A_NR(a),Id)); |
| 399 | return (0); |
| 400 | } |
| 401 | if (extended_info_type == DIVA_RC_TYPE_REMOVE_COMPLETE) |
| 402 | a->RcExtensionSupported = TRUE; |
| 403 | } |
| 404 | a->misc_flags_table[e_no] &= ~DIVA_MISC_FLAGS_REMOVE_PENDING; |
| 405 | a->misc_flags_table[e_no] &= ~DIVA_MISC_FLAGS_NO_RC_CANCELLING; |
| 406 | free_entity(a, e_no); |
| 407 | for (i = 0; i < 256; i++) |
| 408 | { |
| 409 | if (a->FlowControlIdTable[i] == Id) |
| 410 | a->FlowControlIdTable[i] = 0; |
| 411 | } |
| 412 | a->IdTable[Id] = 0; |
| 413 | this->Id = 0; |
| 414 | /* --------------------------------------------------------------- |
| 415 | If we send N_DISC or N_DISK_ACK after we have received OK_FC |
| 416 | then the card will respond with OK_FC and later with RC==OK. |
| 417 | If we send N_REMOVE in this state we will receive only RC==OK |
| 418 | This will create the state in that the XDI is waiting for the |
| 419 | additional RC and does not delivery the RC to the client. This |
| 420 | code corrects the counter of outstanding RC's in this case. |
| 421 | --------------------------------------------------------------- */ |
| 422 | if ((this->More & XMOREC) > 1) { |
| 423 | this->More &= ~XMOREC; |
| 424 | this->More |= 1; |
| 425 | dtrc(dprintf("XDI: correct MORE on REMOVE A(%02x) Id:%02x", |
| 426 | XDI_A_NR(a),Id)); |
| 427 | } |
| 428 | } |
| 429 | if (Rc==OK_FC) { |
| 430 | a->FlowControlIdTable[Ch] = Id; |
| 431 | a->FlowControlSkipTable[Ch] = FALSE; |
| 432 | this->Rc = Rc; |
| 433 | this->More &= ~(XBUSY | XMOREC); |
| 434 | this->complete=0xff; |
| 435 | xdi_xlog_rc_event (XDI_A_NR(a), Id, Ch, Rc, 1, a->IdTypeTable[this->No]); |
| 436 | CALLBACK(a, this); |
| 437 | return 0; |
| 438 | } |
| 439 | /* |
| 440 | New protocol code sends return codes that comes from release |
| 441 | of flow control condition marked with DIVA_RC_TYPE_OK_FC extended |
| 442 | information element type. |
| 443 | If like return code arrives then application is able to process |
| 444 | all return codes self and XDI should not cances return codes. |
| 445 | This return code does not decrement XMOREC partial return code |
| 446 | counter due to fact that it was no request for this return code, |
| 447 | also XMOREC was not incremented. |
| 448 | */ |
| 449 | if (extended_info_type == DIVA_RC_TYPE_OK_FC) { |
| 450 | a->misc_flags_table[e_no] |= DIVA_MISC_FLAGS_NO_RC_CANCELLING; |
| 451 | this->Rc = Rc; |
| 452 | this->complete=0xff; |
| 453 | xdi_xlog_rc_event (XDI_A_NR(a), Id, Ch, Rc, 1, a->IdTypeTable[this->No]); |
| 454 | DBG_TRC(("XDI OK_FC A(%02x) Id:%02x Ch:%02x Rc:%02x", |
| 455 | XDI_A_NR(a), Id, Ch, Rc)) |
| 456 | CALLBACK(a, this); |
| 457 | return 0; |
| 458 | } |
| 459 | cancel_rc = !(a->misc_flags_table[e_no] & DIVA_MISC_FLAGS_NO_RC_CANCELLING); |
| 460 | if (cancel_rc && (a->FlowControlIdTable[Ch] == Id)) |
| 461 | { |
| 462 | a->FlowControlIdTable[Ch] = 0; |
| 463 | if ((Rc != OK) || !a->FlowControlSkipTable[Ch]) |
| 464 | { |
| 465 | this->Rc = Rc; |
| 466 | if (Ch == this->ReqCh) |
| 467 | { |
| 468 | this->More &=~(XBUSY | XMOREC); |
| 469 | this->complete=0xff; |
| 470 | } |
| 471 | xdi_xlog_rc_event (XDI_A_NR(a), Id, Ch, Rc, 1, a->IdTypeTable[this->No]); |
| 472 | CALLBACK(a, this); |
| 473 | } |
| 474 | return 0; |
| 475 | } |
| 476 | if (this->More &XMOREC) |
| 477 | this->More--; |
| 478 | /* call the application callback function */ |
| 479 | if (((!cancel_rc) || (this->More & XMOREF)) && !(this->More & XMOREC)) { |
| 480 | this->Rc = Rc; |
| 481 | this->More &=~XBUSY; |
| 482 | this->complete=0xff; |
| 483 | xdi_xlog_rc_event (XDI_A_NR(a), Id, Ch, Rc, 1, a->IdTypeTable[this->No]); |
| 484 | CALLBACK(a, this); |
| 485 | } |
| 486 | return 0; |
| 487 | } |
| 488 | /* if it's an ASSIGN return code check if it's a return */ |
| 489 | /* code to an ASSIGN request from us */ |
| 490 | if((Rc &0xf0)==ASSIGN_RC) { |
| 491 | e_no = get_assign(a, Ref); |
| 492 | if(e_no) { |
| 493 | this = entity_ptr(a,e_no); |
| 494 | this->Id = Id; |
| 495 | xdi_xlog_rc_event (XDI_A_NR(a), Id, Ch, Rc, 2, a->IdTypeTable[this->No]); |
| 496 | /* call the application callback function */ |
| 497 | this->Rc = Rc; |
| 498 | this->More &=~XBUSY; |
| 499 | this->complete=0xff; |
| 500 | #if defined(DIVA_ISTREAM) /* { */ |
| 501 | if ((Rc == ASSIGN_OK) && a->ram_offset && |
| 502 | (a->IdTypeTable[this->No] == NL_ID) && |
| 503 | ((extended_info_type == DIVA_RC_TYPE_RX_DMA) || |
| 504 | (extended_info_type == DIVA_RC_TYPE_CMA_PTR)) && |
| 505 | extended_info) { |
| 506 | dword offset = (*(a->ram_offset)) (a); |
| 507 | dword tmp[2]; |
| 508 | extended_info -= offset; |
| 509 | #ifdef PLATFORM_GT_32BIT |
| 510 | a->ram_in_dw(a, (void*)ULongToPtr(extended_info), (dword*)&tmp[0], 2); |
| 511 | #else |
| 512 | a->ram_in_dw(a, (void*)extended_info, (dword*)&tmp[0], 2); |
| 513 | #endif |
| 514 | a->tx_stream[Id] = tmp[0]; |
| 515 | a->rx_stream[Id] = tmp[1]; |
| 516 | if (extended_info_type == DIVA_RC_TYPE_RX_DMA) { |
| 517 | DBG_TRC(("Id=0x%x RxDMA=%08x:%08x", |
| 518 | Id, a->tx_stream[Id], a->rx_stream[Id])) |
| 519 | a->misc_flags_table[this->No] |= DIVA_MISC_FLAGS_RX_DMA; |
| 520 | } else { |
| 521 | DBG_TRC(("Id=0x%x CMA=%08x:%08x", |
| 522 | Id, a->tx_stream[Id], a->rx_stream[Id])) |
| 523 | a->misc_flags_table[this->No] &= ~DIVA_MISC_FLAGS_RX_DMA; |
| 524 | a->rx_pos[Id] = 0; |
| 525 | a->rx_stream[Id] -= offset; |
| 526 | } |
| 527 | a->tx_pos[Id] = 0; |
| 528 | a->tx_stream[Id] -= offset; |
| 529 | } else { |
| 530 | a->tx_stream[Id] = 0; |
| 531 | a->rx_stream[Id] = 0; |
| 532 | a->misc_flags_table[this->No] &= ~DIVA_MISC_FLAGS_RX_DMA; |
| 533 | } |
| 534 | #endif /* } */ |
| 535 | CALLBACK(a, this); |
| 536 | if(Rc==ASSIGN_OK) { |
| 537 | a->IdTable[Id] = e_no; |
| 538 | } |
| 539 | else |
| 540 | { |
| 541 | free_entity(a, e_no); |
| 542 | for (i = 0; i < 256; i++) |
| 543 | { |
| 544 | if (a->FlowControlIdTable[i] == Id) |
| 545 | a->FlowControlIdTable[i] = 0; |
| 546 | } |
| 547 | a->IdTable[Id] = 0; |
| 548 | this->Id = 0; |
| 549 | } |
| 550 | return 1; |
| 551 | } |
| 552 | } |
| 553 | return 2; |
| 554 | } |
| 555 | /*------------------------------------------------------------------*/ |
| 556 | /* indication handler */ |
| 557 | /*------------------------------------------------------------------*/ |
| 558 | byte isdn_ind(ADAPTER * a, |
| 559 | byte Ind, |
| 560 | byte Id, |
| 561 | byte Ch, |
| 562 | PBUFFER * RBuffer, |
| 563 | byte MInd, |
| 564 | word MLength) |
| 565 | { |
| 566 | ENTITY * this; |
| 567 | word clength; |
| 568 | word offset; |
| 569 | BUFFERS *R; |
| 570 | byte* cma = NULL; |
| 571 | #ifdef USE_EXTENDED_DEBUGS |
| 572 | { |
| 573 | DBG_TRC(("<A%d Id=0x%x Ind=0x%x", ((ISDN_ADAPTER *)a->io)->ANum, Id, Ind)) |
| 574 | } |
| 575 | #else |
| 576 | dbug(dprintf("isdn_ind(Ind=%x,Id=%x,Ch=%x)",Ind,Id,Ch)); |
| 577 | #endif |
| 578 | if(a->IdTable[Id]) { |
| 579 | this = entity_ptr(a,a->IdTable[Id]); |
| 580 | this->IndCh = Ch; |
| 581 | xdi_xlog_ind (XDI_A_NR(a), Id, Ch, Ind, |
| 582 | 0/* rnr_valid */, 0 /* rnr */, a->IdTypeTable[this->No]); |
| 583 | /* if the Receive More flag is not yet set, this is the */ |
| 584 | /* first buffer of the packet */ |
| 585 | if(this->RCurrent==0xff) { |
| 586 | /* check for receive buffer chaining */ |
| 587 | if(Ind==this->MInd) { |
| 588 | this->complete = 0; |
| 589 | this->Ind = MInd; |
| 590 | } |
| 591 | else { |
| 592 | this->complete = 1; |
| 593 | this->Ind = Ind; |
| 594 | } |
| 595 | /* call the application callback function for the receive */ |
| 596 | /* look ahead */ |
| 597 | this->RLength = MLength; |
| 598 | #if defined(DIVA_ISTREAM) |
| 599 | if ((a->rx_stream[this->Id] || |
| 600 | (a->misc_flags_table[this->No] & DIVA_MISC_FLAGS_RX_DMA)) && |
| 601 | ((Ind == N_DATA) || |
| 602 | (a->protocol_capabilities & PROTCAP_CMA_ALLPR))) { |
| 603 | PISDN_ADAPTER IoAdapter = (PISDN_ADAPTER)a->io ; |
| 604 | if (a->misc_flags_table[this->No] & DIVA_MISC_FLAGS_RX_DMA) { |
| 605 | #if defined(DIVA_IDI_RX_DMA) |
| 606 | dword d; |
| 607 | diva_get_dma_map_entry (\ |
| 608 | (struct _diva_dma_map_entry*)IoAdapter->dma_map, |
| 609 | (int)a->rx_stream[this->Id], (void**)&cma, &d); |
| 610 | #else |
| 611 | cma = &a->stream_buffer[0]; |
| 612 | cma[0] = cma[1] = cma[2] = cma[3] = 0; |
| 613 | #endif |
| 614 | this->RLength = MLength = (word)*(dword*)cma; |
| 615 | cma += 4; |
| 616 | } else { |
| 617 | int final = 0; |
| 618 | cma = &a->stream_buffer[0]; |
| 619 | this->RLength = MLength = (word)diva_istream_read (a, |
| 620 | Id, |
| 621 | cma, |
| 622 | sizeof(a->stream_buffer), |
| 623 | &final, NULL, NULL); |
| 624 | } |
| 625 | IoAdapter->RBuffer.length = MIN(MLength, 270); |
| 626 | if (IoAdapter->RBuffer.length != MLength) { |
| 627 | this->complete = 0; |
| 628 | } else { |
| 629 | this->complete = 1; |
| 630 | } |
| 631 | memcpy (IoAdapter->RBuffer.P, cma, IoAdapter->RBuffer.length) ; |
| 632 | this->RBuffer = (DBUFFER *)&IoAdapter->RBuffer ; |
| 633 | } |
| 634 | #endif |
| 635 | if (!cma) { |
| 636 | a->ram_look_ahead(a, RBuffer, this); |
| 637 | } |
| 638 | this->RNum = 0; |
| 639 | CALLBACK(a, this); |
| 640 | /* map entity ptr, selector could be re-mapped by call to */ |
| 641 | /* IDI from within callback */ |
| 642 | this = entity_ptr(a,a->IdTable[Id]); |
| 643 | xdi_xlog_ind (XDI_A_NR(a), Id, Ch, Ind, |
| 644 | 1/* rnr_valid */, this->RNR/* rnr */, a->IdTypeTable[this->No]); |
| 645 | /* check for RNR */ |
| 646 | if(this->RNR==1) { |
| 647 | this->RNR = 0; |
| 648 | return 1; |
| 649 | } |
| 650 | /* if no buffers are provided by the application, the */ |
| 651 | /* application want to copy the data itself including */ |
| 652 | /* N_MDATA/LL_MDATA chaining */ |
| 653 | if(!this->RNR && !this->RNum) { |
| 654 | xdi_xlog_ind (XDI_A_NR(a), Id, Ch, Ind, |
| 655 | 2/* rnr_valid */, 0/* rnr */, a->IdTypeTable[this->No]); |
| 656 | return 0; |
| 657 | } |
| 658 | /* if there is no RNR, set the More flag */ |
| 659 | this->RCurrent = 0; |
| 660 | this->ROffset = 0; |
| 661 | } |
| 662 | if(this->RNR==2) { |
| 663 | if(Ind!=this->MInd) { |
| 664 | this->RCurrent = 0xff; |
| 665 | this->RNR = 0; |
| 666 | } |
| 667 | return 0; |
| 668 | } |
| 669 | /* if we have received buffers from the application, copy */ |
| 670 | /* the data into these buffers */ |
| 671 | offset = 0; |
| 672 | R = PTR_R(a,this); |
| 673 | do { |
| 674 | if(this->ROffset==R[this->RCurrent].PLength) { |
| 675 | this->ROffset = 0; |
| 676 | this->RCurrent++; |
| 677 | } |
| 678 | if (cma) { |
| 679 | clength = MIN(MLength, R[this->RCurrent].PLength-this->ROffset); |
| 680 | } else { |
| 681 | clength = MIN(a->ram_inw(a, &RBuffer->length)-offset, |
| 682 | R[this->RCurrent].PLength-this->ROffset); |
| 683 | } |
| 684 | if(R[this->RCurrent].P) { |
| 685 | if (cma) { |
| 686 | memcpy (PTR_P(a,this,&R[this->RCurrent].P[this->ROffset]), |
| 687 | &cma[offset], |
| 688 | clength); |
| 689 | } else { |
| 690 | a->ram_in_buffer(a, |
| 691 | &RBuffer->P[offset], |
| 692 | PTR_P(a,this,&R[this->RCurrent].P[this->ROffset]), |
| 693 | clength); |
| 694 | } |
| 695 | } |
| 696 | offset +=clength; |
| 697 | this->ROffset +=clength; |
| 698 | if (cma) { |
| 699 | if (offset >= MLength) { |
| 700 | break; |
| 701 | } |
| 702 | continue; |
| 703 | } |
| 704 | } while(offset<(a->ram_inw(a, &RBuffer->length))); |
| 705 | /* if it's the last buffer of the packet, call the */ |
| 706 | /* application callback function for the receive complete */ |
| 707 | /* call */ |
| 708 | if(Ind!=this->MInd) { |
| 709 | R[this->RCurrent].PLength = this->ROffset; |
| 710 | if(this->ROffset) this->RCurrent++; |
| 711 | this->RNum = this->RCurrent; |
| 712 | this->RCurrent = 0xff; |
| 713 | this->Ind = Ind; |
| 714 | this->complete = 2; |
| 715 | xdi_xlog_ind (XDI_A_NR(a), Id, Ch, Ind, |
| 716 | 3/* rnr_valid */, 0/* rnr */, a->IdTypeTable[this->No]); |
| 717 | CALLBACK(a, this); |
| 718 | } |
| 719 | return 0; |
| 720 | } |
| 721 | return 2; |
| 722 | } |
| 723 | #if defined(XDI_USE_XLOG) |
| 724 | /* ----------------------------------------------------------- |
| 725 | This function works in the same way as xlog on the |
| 726 | active board |
| 727 | ----------------------------------------------------------- */ |
| 728 | static void xdi_xlog (byte *msg, word code, int length) { |
| 729 | xdi_dbg_xlog ("\x00\x02", msg, code, length); |
| 730 | } |
| 731 | #endif |
| 732 | /* ----------------------------------------------------------- |
| 733 | This function writes the information about the Return Code |
| 734 | processing in the trace buffer. Trace ID is 221. |
| 735 | INPUT: |
| 736 | Adapter - system unicue adapter number (0 ... 255) |
| 737 | Id - Id of the entity that had sent this return code |
| 738 | Ch - Channel of the entity that had sent this return code |
| 739 | Rc - return code value |
| 740 | cb: (0...2) |
| 741 | switch (cb) { |
| 742 | case 0: printf ("DELIVERY"); break; |
| 743 | case 1: printf ("CALLBACK"); break; |
| 744 | case 2: printf ("ASSIGN"); break; |
| 745 | } |
| 746 | DELIVERY - have entered isdn_rc with this RC |
| 747 | CALLBACK - about to make callback to the application |
| 748 | for this RC |
| 749 | ASSIGN - about to make callback for RC that is result |
| 750 | of ASSIGN request. It is no DELIVERY message |
| 751 | before of this message |
| 752 | type - the Id that was sent by the ASSIGN of this entity. |
| 753 | This should be global Id like NL_ID, DSIG_ID, MAN_ID. |
| 754 | An unknown Id will cause "?-" in the front of the request. |
| 755 | In this case the log.c is to be extended. |
| 756 | ----------------------------------------------------------- */ |
| 757 | static void xdi_xlog_rc_event (byte Adapter, |
| 758 | byte Id, byte Ch, byte Rc, byte cb, byte type) { |
| 759 | #if defined(XDI_USE_XLOG) |
| 760 | word LogInfo[4]; |
| 761 | PUT_WORD(&LogInfo[0], ((word)Adapter | (word)(xdi_xlog_sec++ << 8))); |
| 762 | PUT_WORD(&LogInfo[1], ((word)Id | (word)(Ch << 8))); |
| 763 | PUT_WORD(&LogInfo[2], ((word)Rc | (word)(type << 8))); |
| 764 | PUT_WORD(&LogInfo[3], cb); |
| 765 | xdi_xlog ((byte*)&LogInfo[0], 221, sizeof(LogInfo)); |
| 766 | #endif |
| 767 | } |
| 768 | /* ------------------------------------------------------------------------ |
| 769 | This function writes the information about the request processing |
| 770 | in the trace buffer. Trace ID is 220. |
| 771 | INPUT: |
| 772 | Adapter - system unicue adapter number (0 ... 255) |
| 773 | Id - Id of the entity that had sent this request |
| 774 | Ch - Channel of the entity that had sent this request |
| 775 | Req - Code of the request |
| 776 | type - the Id that was sent by the ASSIGN of this entity. |
| 777 | This should be global Id like NL_ID, DSIG_ID, MAN_ID. |
| 778 | An unknown Id will cause "?-" in the front of the request. |
| 779 | In this case the log.c is to be extended. |
| 780 | ------------------------------------------------------------------------ */ |
| 781 | static void xdi_xlog_request (byte Adapter, byte Id, |
| 782 | byte Ch, byte Req, byte type) { |
| 783 | #if defined(XDI_USE_XLOG) |
| 784 | word LogInfo[3]; |
| 785 | PUT_WORD(&LogInfo[0], ((word)Adapter | (word)(xdi_xlog_sec++ << 8))); |
| 786 | PUT_WORD(&LogInfo[1], ((word)Id | (word)(Ch << 8))); |
| 787 | PUT_WORD(&LogInfo[2], ((word)Req | (word)(type << 8))); |
| 788 | xdi_xlog ((byte*)&LogInfo[0], 220, sizeof(LogInfo)); |
| 789 | #endif |
| 790 | } |
| 791 | /* ------------------------------------------------------------------------ |
| 792 | This function writes the information about the indication processing |
| 793 | in the trace buffer. Trace ID is 222. |
| 794 | INPUT: |
| 795 | Adapter - system unicue adapter number (0 ... 255) |
| 796 | Id - Id of the entity that had sent this indication |
| 797 | Ch - Channel of the entity that had sent this indication |
| 798 | Ind - Code of the indication |
| 799 | rnr_valid: (0 .. 3) supported |
| 800 | switch (rnr_valid) { |
| 801 | case 0: printf ("DELIVERY"); break; |
| 802 | case 1: printf ("RNR=%d", rnr); |
| 803 | case 2: printf ("RNum=0"); |
| 804 | case 3: printf ("COMPLETE"); |
| 805 | } |
| 806 | DELIVERY - indication entered isdn_rc function |
| 807 | RNR=... - application had returned RNR=... after the |
| 808 | look ahead callback |
| 809 | RNum=0 - aplication had not returned any buffer to copy |
| 810 | this indication and will copy it self |
| 811 | COMPLETE - XDI had copied the data to the buffers provided |
| 812 | bu the application and is about to issue the |
| 813 | final callback |
| 814 | rnr: Look case 1 of the rnr_valid |
| 815 | type: the Id that was sent by the ASSIGN of this entity. This should |
| 816 | be global Id like NL_ID, DSIG_ID, MAN_ID. An unknown Id will |
| 817 | cause "?-" in the front of the request. In this case the |
| 818 | log.c is to be extended. |
| 819 | ------------------------------------------------------------------------ */ |
| 820 | static void xdi_xlog_ind (byte Adapter, |
| 821 | byte Id, |
| 822 | byte Ch, |
| 823 | byte Ind, |
| 824 | byte rnr_valid, |
| 825 | byte rnr, |
| 826 | byte type) { |
| 827 | #if defined(XDI_USE_XLOG) |
| 828 | word LogInfo[4]; |
| 829 | PUT_WORD(&LogInfo[0], ((word)Adapter | (word)(xdi_xlog_sec++ << 8))); |
| 830 | PUT_WORD(&LogInfo[1], ((word)Id | (word)(Ch << 8))); |
| 831 | PUT_WORD(&LogInfo[2], ((word)Ind | (word)(type << 8))); |
| 832 | PUT_WORD(&LogInfo[3], ((word)rnr | (word)(rnr_valid << 8))); |
| 833 | xdi_xlog ((byte*)&LogInfo[0], 222, sizeof(LogInfo)); |
| 834 | #endif |
| 835 | } |