|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights ! 7: * Reserved. This file contains Original Code and/or Modifications of ! 8: * Original Code as defined in and that are subject to the Apple Public ! 9: * Source License Version 1.1 (the "License"). You may not use this file ! 10: * except in compliance with the License. Please obtain a copy of the ! 11: * License at http://www.apple.com/publicsource and read it before using ! 12: * this file. ! 13: * ! 14: * The Original Code and all software distributed under the License are ! 15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 19: * License for the specific language governing rights and limitations ! 20: * under the License. ! 21: * ! 22: * @APPLE_LICENSE_HEADER_END@ ! 23: */ ! 24: ! 25: /* ! 26: * Copyright (c) 1990, 1995-1998 Apple Computer, Inc. ! 27: * All Rights Reserved. ! 28: * ! 29: * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF APPLE COMPUTER, INC. ! 30: * The copyright notice above does not evidence any actual or ! 31: * intended publication of such source code. ! 32: */ ! 33: ! 34: #include <adsp_local.h> ! 35: ! 36: /* # of additional ticks to add to any timer that we're queuing up. For ! 37: * very short delays (1 and 2), the timer fires before the transmit ! 38: * even takes place */ ! 39: #define TX_DLY 2 ! 40: ! 41: int adsp_window = 1; ! 42: ! 43: /* ! 44: * CalcRecvWdw ! 45: * ! 46: * INPUTS: ! 47: * sp ADSP Stream ! 48: * OUTPUTS: ! 49: * # of bytes in avail in local receive queue ! 50: */ ! 51: int CalcRecvWdw(sp) /* (CCBPtr sp) */ ! 52: CCBPtr sp; ! 53: { ! 54: int bytes; ! 55: ! 56: bytes = calcRecvQ(sp); ! 57: bytes = sp->rbuflen - bytes; /* get what is left */ ! 58: ! 59: if (bytes <= 16) { /* %%% this should be zero */ ! 60: sp->rbufFull = 1; /* Save flag that our recv buf is full */ ! 61: return 0; ! 62: } ! 63: else ! 64: return ((bytes+bytes+bytes) >> 2) + 1; /* %%% */ ! 65: } ! 66: ! 67: calcRecvQ(sp) ! 68: CCBPtr sp; ! 69: { ! 70: int bytes = 0; ! 71: register gbuf_t *mb; ! 72: ! 73: if (sp->rData) { /* There is data in buffer */ ! 74: if (mb = sp->rbuf_mb) { ! 75: do { ! 76: bytes += gbuf_msgsize(mb); ! 77: mb = gbuf_next(mb); ! 78: } while (mb); ! 79: } ! 80: if (mb = sp->crbuf_mb) ! 81: bytes += gbuf_msgsize(mb); ! 82: } ! 83: ! 84: return bytes; ! 85: } ! 86: ! 87: /* ! 88: * CheckSend ! 89: * ! 90: * Check to see if the transmit PB is available and if there is anything ! 91: * to transmit. Start off any pending transmit. ! 92: * ! 93: * Normally called from the write completion routine ! 94: * ! 95: * INPUTS: ! 96: * sp Connection control block ! 97: * OUTPUTS: ! 98: * true if sent a packet ! 99: */ ! 100: void CheckSend(sp) /* (CCBPtr sp) */ ! 101: register CCBPtr sp; ! 102: { ! 103: int i; ! 104: int attnMsg; /* True if attention message */ ! 105: int s; ! 106: register gbuf_t *mp; /* send message block */ ! 107: #ifdef notdef ! 108: register gbuf_t *tmp; ! 109: u_char current; ! 110: #endif ! 111: char *dp; /* a data pointer */ ! 112: int use_attention_code; ! 113: int len; /* length used in allocd mblk */ ! 114: int datalen; /* amount of data attached to mblk */ ! 115: gbuf_t *mprev, *mlist = 0; ! 116: ! 117: top: ! 118: ! 119: if (sp->state == sClosed) ! 120: return; ! 121: ! 122: /* get a message block to hold DDP and ! 123: * ADSP headers + 2 bytes of attention ! 124: * code if necessary */ ! 125: if ((mp = gbuf_alloc(AT_WR_OFFSET + DDPL_FRAME_LEN + ADSP_FRAME_LEN + ADSP_OPEN_FRAME_LEN + 2, ! 126: PRI_LO)) == 0) { ! 127: if (mlist) ! 128: gbuf_freel(mlist); ! 129: return; /* can't get buffers... do nothing! */ ! 130: } ! 131: ATDISABLE(s, sp->lock); ! 132: sp->callSend = 0; /* Clear flag */ ! 133: use_attention_code = 0; ! 134: len = 0; ! 135: datalen = 0; ! 136: ! 137: gbuf_rinc(mp,AT_WR_OFFSET); ! 138: gbuf_wset(mp,DDPL_FRAME_LEN); /* leave room for DDP header */ ! 139: ! 140: if (sp->sendCtl) { ! 141: short mask; ! 142: ! 143: i = sp->sendCtl; /* get local copy bitmap of */ ! 144: /* which ctl packets to send. */ ! 145: attnMsg = 0; ! 146: ! 147: if (i & 0x1E) /* One of the open ctrl packets */ ! 148: { ! 149: ! 150: /* point past ADSP header (no attention) */ ! 151: dp = ((char *) gbuf_wptr(mp)) + ADSP_FRAME_LEN; ! 152: UAL_ASSIGN(sp->f.pktFirstByteSeq, netdw(sp->firstRtmtSeq)); ! 153: ! 154: UAS_ASSIGN(sp->of.version, netw(0x0100)); /* Fill in open connection parms */ ! 155: UAS_ASSIGN(sp->of.dstCID, sp->remCID); /* Destination CID */ ! 156: UAL_ASSIGN(sp->of.pktAttnRecvSeq, netdw(sp->attnRecvSeq)); ! 157: bcopy((caddr_t) &sp->of, (caddr_t) dp, ADSP_OPEN_FRAME_LEN); ! 158: len += ADSP_OPEN_FRAME_LEN; ! 159: ! 160: if (i & B_CTL_OREQ) { ! 161: UAS_ASSIGN(sp->f.CID, sp->locCID); ! 162: mask = B_CTL_OREQ; ! 163: sp->f.descriptor = ADSP_CONTROL_BIT | ADSP_CTL_OREQ; ! 164: } else if (i & B_CTL_OACK) { ! 165: UAS_ASSIGN(sp->f.CID, sp->locCID); ! 166: mask = B_CTL_OACK; ! 167: sp->f.descriptor = ADSP_CONTROL_BIT | ADSP_CTL_OACK; ! 168: } else if (i & B_CTL_OREQACK) { ! 169: UAS_ASSIGN(sp->f.CID, sp->locCID); ! 170: mask = B_CTL_OREQACK; ! 171: sp->f.descriptor = ADSP_CONTROL_BIT | ADSP_CTL_OREQACK; ! 172: } else /* Deny */ ! 173: { ! 174: UAS_ASSIGN(sp->f.CID, 0); ! 175: mask = B_CTL_ODENY; ! 176: sp->f.descriptor = ADSP_CONTROL_BIT | ADSP_CTL_ODENY; ! 177: UAL_ASSIGN(sp->f.pktFirstByteSeq, 0); ! 178: } ! 179: ! 180: if (i & (B_CTL_OREQ | B_CTL_OREQACK)) ! 181: /* Need to start up a timer for it */ ! 182: { ! 183: /* It's possible that we've received a duplicate ! 184: * open request. In this case, there will already be ! 185: * a timer queued up for the request+ack ! 186: * packet we sent the first time. So remove the timer ! 187: * and start another. ! 188: */ ! 189: RemoveTimerElem(&adspGlobal.slowTimers, &sp->ProbeTimer); ! 190: InsertTimerElem(&adspGlobal.slowTimers, &sp->ProbeTimer, ! 191: sp->openInterval+1); ! 192: } ! 193: } else { ! 194: /* seq # of next byte to send */ ! 195: UAL_ASSIGN(sp->f.pktFirstByteSeq, netdw(sp->sendSeq)); ! 196: ! 197: if (i & B_CTL_CLOSE) { ! 198: sp->state = sClosed; /* Now we're closed */ ! 199: mask = B_CTL_CLOSE; ! 200: sp->f.descriptor = ADSP_CONTROL_BIT | ADSP_CTL_CLOSE; ! 201: } else if (i & B_CTL_PROBE) { ! 202: mask = B_CTL_PROBE; ! 203: sp->f.descriptor = ! 204: ADSP_CONTROL_BIT | ADSP_CTL_PROBE | ADSP_ACK_REQ_BIT; ! 205: } else if (i & B_CTL_FRESET) { ! 206: mask = B_CTL_FRESET; ! 207: sp->f.descriptor = ADSP_CONTROL_BIT | ADSP_CTL_FRESET; ! 208: InsertTimerElem(&adspGlobal.fastTimers, ! 209: &sp->ResetTimer, sp->rtmtInterval+TX_DLY); ! 210: } else if (i & B_CTL_FRESETACK) { ! 211: mask = B_CTL_FRESETACK; ! 212: sp->f.descriptor = ADSP_CONTROL_BIT | ADSP_CTL_FRESET_ACK; ! 213: } ! 214: else if (i & B_CTL_RETRANSMIT) { ! 215: mask = B_CTL_RETRANSMIT; ! 216: sp->f.descriptor = ADSP_CONTROL_BIT | ADSP_CTL_RETRANSMIT; ! 217: } ! 218: else { ! 219: dPrintf(D_M_ADSP, D_L_ERROR, ("CheckSend: Control bit error\n")); ! 220: } ! 221: } /* non open control packet */ ! 222: ! 223: sp->sendCtl &= ~mask; ! 224: goto sendit; ! 225: } /* send control packet */ ! 226: ! 227: if (sp->sendAttnData) /* Send attn ready to go? */ ! 228: { ! 229: sp->sendAttnData = 0; /* Clear Flags */ ! 230: if (sp->sapb) { ! 231: sp->sendAttnAck = 0; /* This will also do an Attn Ack */ ! 232: ! 233: attnMsg = 1; ! 234: sp->f.descriptor = ADSP_ATTENTION_BIT | ADSP_ACK_REQ_BIT; ! 235: if (gbuf_cont(sp->sapb->mp)) { ! 236: gbuf_cont(mp) = gbuf_dupm(gbuf_cont(sp->sapb->mp)); ! 237: /* Major hack here. The ADSP Attn code is butted up against ! 238: * the end of the adsp packet header, and the length is ! 239: * increased by 2. (There is a pad field behind the adsp ! 240: * header in the CCB just for this purpose.) ! 241: */ ! 242: } ! 243: use_attention_code++; ! 244: ! 245: sp->f.data[0] = high(sp->sapb->u.attnParams.attnCode); ! 246: sp->f.data[1] = low(sp->sapb->u.attnParams.attnCode); ! 247: InsertTimerElem(&adspGlobal.fastTimers, &sp->AttnTimer, ! 248: sp->rtmtInterval+TX_DLY); ! 249: goto sendit; ! 250: } ! 251: } /* attn data */ ! 252: ! 253: if (sp->sendAttnAck) /* Send attn ack ready to go? */ ! 254: { ! 255: attnMsg = 1; ! 256: sp->f.descriptor = ADSP_CONTROL_BIT | ADSP_ATTENTION_BIT; ! 257: sp->sendAttnAck = 0; ! 258: goto sendit; ! 259: } /* attn ack */ ! 260: ! 261: if ((sp->state == sOpen || sp->state == sClosing) && /* Correct state */ ! 262: (!sp->waitingAck) && /* not waiting for an ACK */ ! 263: (sp->sData) && /* have data to send */ ! 264: (GTE(sp->sendWdwSeq,sp->sendSeq)) && /* he has room to accept it */ ! 265: (sp->pktSendCnt < sp->pktSendMax)) /* haven't sent too many pkts ! 266: * in a row. */ ! 267: { ! 268: attnMsg = 0; ! 269: if (datalen = attachData(sp, mp)) /* attach data to mp */ ! 270: goto sendit; /* if successful, sendit */ ! 271: } ! 272: ! 273: if (sp->sendDataAck) { ! 274: UAL_ASSIGN(sp->f.pktFirstByteSeq, netdw(sp->sendSeq)); /* seq # of next byte */ ! 275: attnMsg = 0; ! 276: sp->f.descriptor = ADSP_CONTROL_BIT; ! 277: goto sendit; ! 278: } ! 279: ! 280: /* ! 281: * Nothing left to do... ! 282: */ ! 283: if (mp) ! 284: gbuf_freem(mp); ! 285: ATENABLE(s, sp->lock); ! 286: if (mlist) ! 287: adsp_sendddp(sp, mlist, 0, &sp->remoteAddress, DDP_ADSP); ! 288: return; ! 289: ! 290: sendit: ! 291: ! 292: if (attnMsg) { ! 293: UAL_ASSIGN(sp->f.pktFirstByteSeq, netdw(sp->attnSendSeq)); ! 294: UAL_ASSIGN(sp->f.pktNextRecvSeq, netdw(sp->attnRecvSeq)); ! 295: UAS_ASSIGN(sp->f.pktRecvWdw, 0); /* Always zero in attn pkt */ ! 296: } else { ! 297: sp->sendDataAck = 0; ! 298: UAL_ASSIGN(sp->f.pktNextRecvSeq, netdw(sp->recvSeq)); ! 299: UAS_ASSIGN(sp->f.pktRecvWdw, netw(CalcRecvWdw(sp))); ! 300: } ! 301: if (use_attention_code) { ! 302: bcopy((caddr_t) &sp->f, (caddr_t) gbuf_wptr(mp), ADSP_FRAME_LEN + 2); ! 303: len += ADSP_FRAME_LEN + 2; ! 304: } else { ! 305: bcopy((caddr_t) &sp->f, (caddr_t) gbuf_wptr(mp), ADSP_FRAME_LEN); ! 306: len += ADSP_FRAME_LEN; ! 307: } ! 308: gbuf_winc(mp,len); /* update mblk length */ ! 309: if (mlist) ! 310: gbuf_next(mprev) = mp; ! 311: else ! 312: mlist = mp; ! 313: mprev = mp; ! 314: ! 315: if (sp->state == sClosed) { /* must have sent a close advice */ ! 316: /* send header + data */ ! 317: ATENABLE(s, sp->lock); ! 318: adsp_sendddp(sp, mlist, 0, &sp->remoteAddress, DDP_ADSP); ! 319: DoClose(sp, 0, -1); /* complete close! */ ! 320: return; ! 321: } ! 322: ATENABLE(s, sp->lock); ! 323: if (sp->state == sClosing) /* See if we were waiting on this write */ ! 324: CheckOkToClose(sp); ! 325: goto top; ! 326: } ! 327: ! 328: /* ! 329: * completepb delivers a paramater block with all its appropriate fields ! 330: * set back to the user. ! 331: * ! 332: * The assumptions here are that the PB is not linked to any queue, ! 333: * that the fields including ioResult are set, and that the ! 334: * kernel is no longer interested in the mblks that may or ! 335: * maynot be linked to this pb. ! 336: */ ! 337: completepb(sp, pb) ! 338: register CCBPtr sp; ! 339: register struct adspcmd *pb; ! 340: { ! 341: if (sp->gref && (sp->gref->info == (caddr_t)sp->sp_mp)) { ! 342: if (gbuf_len(pb->mp) > sizeof(struct adspcmd)) ! 343: gbuf_wset(pb->mp,sizeof(struct adspcmd)); ! 344: SndMsgUp(sp->gref, pb->mp); ! 345: NotifyUser(sp); ! 346: } else ! 347: gbuf_freem(pb->mp); ! 348: } ! 349: ! 350: attachData(sp, mp) ! 351: register CCBPtr sp; ! 352: register gbuf_t *mp; ! 353: { ! 354: int seq; ! 355: int cnt; ! 356: char eom = 0; ! 357: int bsize; ! 358: int diff; ! 359: char sendAckReq; ! 360: int partial = 0; /* flag for a partial send */ ! 361: int tcnt = 0; ! 362: register gbuf_t *smp; /* send data message block */ ! 363: register gbuf_t *psmp; /* previous message block */ ! 364: ! 365: sendAckReq = 0; ! 366: ! 367: if (LT(sp->sendSeq, sp->firstRtmtSeq)) /* Sanity check on send seq */ ! 368: sp->sendSeq = sp->firstRtmtSeq; /* seq must be oldest in buffer. */ ! 369: ! 370: /* This test and assignment was necessary because the retry VBL could ! 371: * have fired and reset send Seq to first Rtmt Seq, and then an ! 372: * expected ACK comes in that bumps first Rtmt Seq up. Then we ! 373: * have the problem that send Seq is less than first Rtmt Seq. ! 374: * The easiest fix to this timing dilemma seems to be to reset ! 375: * sendSeq to first Rtmt Seq if we're sending the first packet. ! 376: */ ! 377: UAL_ASSIGN(sp->f.pktFirstByteSeq, netdw(sp->sendSeq)); ! 378: ! 379: if (smp = sp->sbuf_mb) /* Get oldest header */ ! 380: eom = 1; ! 381: else if (smp = sp->csbuf_mb) ! 382: eom = 0; ! 383: ! 384: if (smp == 0) { /* this shouldn't happen... */ ! 385: sp->sData = 0; ! 386: return 0; ! 387: } ! 388: /* ! 389: * Must find next byte to transmit ! 390: */ ! 391: seq = sp->firstRtmtSeq; /* Seq # of oldest in buffer */ ! 392: while ((diff = (sp->sendSeq - seq)) >= ((bsize = gbuf_msgsize(smp)) + eom)) { ! 393: seq += bsize + eom; /* update sequence # */ ! 394: if (gbuf_next(smp)) { /* if another send buffer */ ! 395: smp = gbuf_next(smp); ! 396: eom = 1; ! 397: } else if (smp == sp->csbuf_mb) { /* seen the current one? */ ! 398: smp = 0; ! 399: break; ! 400: } else if (sp->csbuf_mb) { /* look at it */ ! 401: smp = sp->csbuf_mb; ! 402: eom = 0; ! 403: } else { /* no more buffers */ ! 404: smp = 0; ! 405: break; ! 406: } ! 407: } /* while */ ! 408: ! 409: if (smp) { ! 410: if (gbuf_next(smp) == 0) /* last block */ ! 411: sendAckReq = 1; ! 412: cnt = bsize - diff; /* # of bytes in this block */ ! 413: } else ! 414: cnt = 0; ! 415: ! 416: /* ! 417: * Check to see if the number of bytes is less than the 'send ! 418: * Blocking' setting. If so, then we won't send this data unless ! 419: * we're flushing. So we set up a timer to force a flush later. ! 420: */ ! 421: if ((cnt < sp->sendBlocking) && !sp->writeFlush) { ! 422: InsertTimerElem(&adspGlobal.fastTimers, &sp->FlushTimer, ! 423: sp->sendInterval); ! 424: return 0; /* no data to send */ ! 425: } ! 426: ! 427: if (cnt > ADSP_MAX_DATA_LEN) { /* truncate to one packet */ ! 428: cnt = ADSP_MAX_DATA_LEN; ! 429: eom = 0; ! 430: sendAckReq = 0; /* Won't send ack because end of data */ ! 431: partial++; ! 432: } ! 433: ! 434: if (smp) { ! 435: /* trim extra bytes off the beginning of the "block" before the copy */ ! 436: while (diff) { ! 437: if (gbuf_len(smp) > diff) ! 438: break; ! 439: else ! 440: diff -= gbuf_len(smp); ! 441: smp = gbuf_cont(smp); ! 442: } ! 443: if((gbuf_cont(mp) = gbuf_dupm(smp)) == 0) /* copy the data */ ! 444: return 0; ! 445: smp = gbuf_cont(mp); /* use the new message blocks */ ! 446: gbuf_rinc(smp,diff); /* and get to the first byte of data to send */ ! 447: } ! 448: /* ! 449: * Check to see if this many bytes will close the other end's ! 450: * receive window. If so, we need to send an ack request along ! 451: * with this. sendWdwSeq is the seq # of the last byte that ! 452: * the remote has room for ! 453: */ ! 454: if ((diff = sp->sendWdwSeq + 1 - sp->sendSeq) <= cnt) { ! 455: if (diff < cnt) { /* Won't fit exactly */ ! 456: eom = 0; /* so can't send EOM */ ! 457: cnt = diff; ! 458: partial++; ! 459: } ! 460: sendAckReq = 1; /* Make him tell us new recv. window */ ! 461: sp->noXmitFlow = 1; /* Don't do flow control calc. */ ! 462: } ! 463: ! 464: /* trim extra bytes off the tail of the "block" after the copy */ ! 465: if (partial && smp) { ! 466: psmp = smp; ! 467: tcnt = cnt; ! 468: while (tcnt && smp) { /* while there are message blocks and data */ ! 469: if (tcnt >= gbuf_len(smp)) { ! 470: tcnt -= gbuf_len(smp); ! 471: if (tcnt) { ! 472: psmp = smp; ! 473: smp = gbuf_cont(smp); ! 474: } else { ! 475: if (psmp != smp) { /* not the first item on the list */ ! 476: gbuf_cont(psmp) = 0; ! 477: gbuf_freem(smp); ! 478: smp = psmp; ! 479: } else { ! 480: gbuf_freem(gbuf_cont(smp)); ! 481: gbuf_cont(smp) = 0; ! 482: } ! 483: break; ! 484: } ! 485: } else { ! 486: gbuf_wset(smp,tcnt); ! 487: if (gbuf_cont(smp)) { ! 488: gbuf_freem(gbuf_cont(smp)); ! 489: gbuf_cont(smp) = 0; ! 490: } ! 491: break; ! 492: } ! 493: } ! 494: } ! 495: ! 496: sp->sendSeq += cnt + eom; /* Update sendSeq field */ ! 497: ! 498: if (GT(sp->sendSeq, sp->maxSendSeq)) /* Keep track of >st ever sent */ ! 499: sp->maxSendSeq = sp->sendSeq; ! 500: ! 501: if (eom) ! 502: sp->f.descriptor = ADSP_EOM_BIT; ! 503: else ! 504: sp->f.descriptor = 0; ! 505: ! 506: if (sendAckReq || (++sp->pktSendCnt >= sp->pktSendMax)) { ! 507: /* Last packet in a series */ ! 508: sp->f.descriptor |= ADSP_ACK_REQ_BIT; /* We want an ack to this */ ! 509: sp->waitingAck = 1; /* Flag that we're waiting */ ! 510: sp->sendStamp = SysTicks(); /* Save time we sent request */ ! 511: sp->timerSeq = sp->sendSeq; /* Save seq # we want acked */ ! 512: InsertTimerElem(&adspGlobal.fastTimers, &sp->RetryTimer, ! 513: sp->rtmtInterval+TX_DLY); ! 514: } ! 515: return cnt + eom; ! 516: } ! 517: ! 518: ! 519:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.