|
|
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.