|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* ! 23: * ! 24: * dspRead.c ! 25: * ! 26: * From v01.17 08/22/90 mbs ! 27: * Modified for MP, 1996 by Tuyen Nguyen ! 28: * Modified, April 9, 1997 by Tuyen Nguyen for MacOSX. ! 29: */ ! 30: ! 31: #include <sys/errno.h> ! 32: #include <sys/types.h> ! 33: #include <sys/param.h> ! 34: #include <machine/spl.h> ! 35: #include <sys/systm.h> ! 36: #include <sys/kernel.h> ! 37: #include <sys/proc.h> ! 38: #include <sys/filedesc.h> ! 39: #include <sys/fcntl.h> ! 40: #include <sys/mbuf.h> ! 41: #include <sys/socket.h> ! 42: #include <sys/socketvar.h> ! 43: ! 44: #include <netat/sysglue.h> ! 45: #include <netat/appletalk.h> ! 46: #include <netat/at_pcb.h> ! 47: #include <netat/debug.h> ! 48: #include <netat/adsp.h> ! 49: #include <netat/adsp_internal.h> ! 50: ! 51: /* ! 52: * CheckReadQueue ! 53: * ! 54: * Checks to see if there is any data in the receive queue. If there ! 55: * is data, a pb and the data are queued to the user. ! 56: * ! 57: * ! 58: */ ! 59: extern int adsp_check; ! 60: ! 61: int CheckReadQueue(sp) /* (CCBPtr sp) */ ! 62: register CCBPtr sp; ! 63: { ! 64: register struct adspcmd *pb; ! 65: int s; ! 66: unsigned short cnt; ! 67: char eom = 0; ! 68: register gbuf_t *mp; ! 69: register gbuf_t *tmp; ! 70: gref_t *gref; ! 71: ! 72: dPrintf(D_M_ADSP, D_L_TRACE, ("CheckReadQueue: sp=0x%x\n", (unsigned)sp)); ! 73: KERNEL_DEBUG(DBG_ADSP_READ, 0, sp, sp->rbuf_mb, sp->rpb, sp->delay); ! 74: trace_mbufs(D_M_ADSP_LOW, " bCQR m", sp->rbuf_mb); ! 75: ATDISABLE(s, sp->lock); ! 76: ! 77: while (sp->rData && (pb = sp->rpb)) { /* have data */ ! 78: dPrintf(D_M_ADSP, D_L_TRACE, ! 79: (" pb=0x%x, gref=0x%x, ioc=0x%x, reqCount=%d (have data)\n", ! 80: pb, pb->gref, pb->ioc, pb->u.ioParams.reqCount)); ! 81: KERNEL_DEBUG(DBG_ADSP_READ, 1, pb, pb->gref, pb->ioc, pb->u.ioParams.reqCount); ! 82: if (pb->u.ioParams.reqCount == 0) { ! 83: pb->ioResult = 0; ! 84: sp->rpb = pb->qLink; ! 85: if (pb->ioc) { ! 86: KERNEL_DEBUG(DBG_ADSP_READ, 2, pb, pb->gref, pb->ioc, 0); ! 87: adspioc_ack(0, pb->ioc, pb->gref); ! 88: } else { ! 89: KERNEL_DEBUG(DBG_ADSP_READ, 3, pb, pb->gref, 0, 0); ! 90: completepb(sp, pb); ! 91: } ! 92: continue; ! 93: } ! 94: ! 95: /* take the first packet off of sp->rbuf_mb or sp->crbuf_mb */ ! 96: if (mp = sp->rbuf_mb) { /* Get header for oldest data */ ! 97: KERNEL_DEBUG(DBG_ADSP_READ, 4, pb, mp, gbuf_msgsize(mp), gbuf_next(mp)); ! 98: sp->rbuf_mb = gbuf_next(mp); ! 99: gbuf_next(mp) = 0; ! 100: eom = 1; ! 101: } else if (mp = sp->crbuf_mb) { ! 102: KERNEL_DEBUG(DBG_ADSP_READ, 5, pb, mp, gbuf_msgsize(mp), gbuf_next(mp)); ! 103: sp->crbuf_mb = 0; ! 104: eom = 0; ! 105: } ! 106: ! 107: /* Get the first (reqCount-actCount) bytes and tack them onto ! 108: the end of pb->mp. If eom is set, put the remainder of the ! 109: data onto the front of sp->rbuf_mb, otherwise sp->crbuf_mb. */ ! 110: cnt = gbuf_msgsize(mp); /* # of data bytes in it. */ ! 111: if (cnt > (unsigned short)(pb->u.ioParams.reqCount - pb->u.ioParams.actCount)) { ! 112: cnt = pb->u.ioParams.reqCount - pb->u.ioParams.actCount; ! 113: /* m_split returns the tail */ ! 114: if (!(tmp = (gbuf_t *)m_split(mp, cnt, M_DONTWAIT))) { ! 115: cnt = 0; ! 116: tmp = mp; ! 117: } ! 118: if (eom) { ! 119: gbuf_next(tmp) = sp->rbuf_mb; ! 120: sp->rbuf_mb = tmp; ! 121: eom = 0; ! 122: } else ! 123: sp->crbuf_mb = tmp; ! 124: } ! 125: if (cnt) { ! 126: pb->u.ioParams.actCount += cnt; ! 127: gbuf_linkb(pb->mp, mp); ! 128: } ! 129: ! 130: pb->u.ioParams.eom = eom; ! 131: /* ! 132: * Now clean up receive buffer to remove all of the data ! 133: * we just copied ! 134: */ ! 135: if ((sp->rbuf_mb == 0) && ! 136: (sp->crbuf_mb == 0)) /* no more data blocks */ ! 137: sp->rData = 0; ! 138: /* ! 139: * If we've filled the parameter block, unlink it from read ! 140: * queue and complete it. We also need to do this if the connection ! 141: * is closed && there is no more stuff to read. ! 142: */ ! 143: if (eom || (pb->u.ioParams.actCount >= pb->u.ioParams.reqCount) || ! 144: ((sp->state == sClosed) && (!sp->rData)) ) { ! 145: /* end of message, message is full, connection ! 146: * is closed and all data has been delivered, ! 147: * or we are not to "delay" data delivery. ! 148: */ ! 149: pb->ioResult = 0; ! 150: sp->rpb = pb->qLink; /* dequeue request */ ! 151: if (pb->ioc) { /* data to be delivered at the time of the */ ! 152: mp = gbuf_cont(pb->mp); /* ioctl call */ ! 153: gbuf_cont(pb->mp) = 0; ! 154: gref = (gref_t *)pb->gref; ! 155: adspioc_ack(0, pb->ioc, pb->gref); ! 156: dPrintf(D_M_ADSP, D_L_TRACE, (" (pb->ioc) mp=%x\n", mp)); ! 157: KERNEL_DEBUG(DBG_ADSP_READ, 0x0A, pb, mp, ! 158: gbuf_next(mp), gbuf_cont(mp)); ! 159: SndMsgUp(gref, mp); ! 160: dPrintf(D_M_ADSP, D_L_TRACE, ! 161: (" (data) size req=%d\n", pb->u.ioParams.actCount)); ! 162: KERNEL_DEBUG(DBG_ADSP_READ, 0x0B, pb, pb->ioc, ! 163: pb->u.ioParams.reqCount, pb->u.ioParams.actCount); ! 164: } else { /* complete an queued async request */ ! 165: KERNEL_DEBUG(DBG_ADSP_READ, 0x0C, pb, sp, ! 166: pb->u.ioParams.actCount, sp->delay); ! 167: completepb(sp, pb); ! 168: } ! 169: } ! 170: } /* while */ ! 171: ! 172: if (pb = sp->rpb) { /* if there is an outstanding request */ ! 173: dPrintf(D_M_ADSP, D_L_TRACE, ! 174: (" pb=0x%x, ioc=0x%x, reqCount=%d (no more data)\n", ! 175: pb, pb->ioc, pb->u.ioParams.reqCount)); ! 176: KERNEL_DEBUG(DBG_ADSP_READ, 0x0D, pb, pb->ioc, ! 177: pb->u.ioParams.reqCount, pb->u.ioParams.actCount); ! 178: ! 179: if (sp->state == sClosed) { ! 180: while (pb) { ! 181: KERNEL_DEBUG(DBG_ADSP_READ, 0x0E, pb, sp, pb->ioc, 0); ! 182: pb->ioResult = 0; ! 183: pb->u.ioParams.actCount = 0; ! 184: pb->u.ioParams.eom = 0; ! 185: sp->rpb = pb->qLink; ! 186: if (pb->ioc) { ! 187: adspioc_ack(0, pb->ioc, pb->gref); ! 188: } else { ! 189: completepb(sp, pb); ! 190: } ! 191: pb = sp->rpb; ! 192: } ! 193: } else if (pb->ioc) { /* if request not complete and this ! 194: * is an active ioctl, release user */ ! 195: sp->rpb = pb->qLink; ! 196: pb->ioResult = 1; ! 197: tmp = gbuf_cont(pb->mp); /* detatch perhaps delayed data */ ! 198: gbuf_cont(pb->mp) = 0; ! 199: if (mp = gbuf_copym(pb->mp)) { /* otherwise, duplicate user request */ ! 200: KERNEL_DEBUG(DBG_ADSP_READ, 0x0F, pb, sp, pb->mp, 0); ! 201: adspioc_ack(0, pb->ioc, pb->gref); /* release user */ ! 202: pb = (struct adspcmd *)gbuf_rptr(mp); /* get new parameter block */ ! 203: pb->ioc = 0; ! 204: pb->mp = mp; ! 205: gbuf_cont(pb->mp) = tmp; /* reattach data */ ! 206: pb->qLink = sp->rpb; /* requeue the duplicate at the head */ ! 207: sp->rpb = pb; ! 208: } else { /* there is no data left, but no space ! 209: * to duplicate the parameter block, so ! 210: * put what must be a non EOM message ! 211: * back on the current receive queue, and ! 212: * error out the user ! 213: */ ! 214: KERNEL_DEBUG(DBG_ADSP_READ, 0x10, pb, sp, pb->mp, 0); ! 215: if (tmp) { ! 216: sp->crbuf_mb = tmp; ! 217: sp->rData = 1; ! 218: } ! 219: pb->ioResult = errDSPQueueSize; ! 220: adspioc_ack(ENOBUFS, pb->ioc, pb->gref); ! 221: } ! 222: } ! 223: } ! 224: /* ! 225: * The receive window has opened. If was previously closed, then we ! 226: * need to notify the other guy that we now have room to receive more ! 227: * data. But, in order to cut down on lots of small data packets, ! 228: * we'll wait until the recieve buffer is /14 empy before telling ! 229: * him that there's room in our receive buffer. ! 230: */ ! 231: if (sp->rbufFull && (CalcRecvWdw(sp) > (sp->rbuflen >> 2))) { ! 232: sp->rbufFull = 0; ! 233: sp->sendDataAck = 1; ! 234: sp->callSend = 1; ! 235: } ! 236: ATENABLE(s, sp->lock); ! 237: ! 238: KERNEL_DEBUG(DBG_ADSP_READ, 0x11, sp, 0, 0, 0); ! 239: trace_mbufs(D_M_ADSP_LOW, " eCQR m", sp->rbuf_mb); ! 240: return 0; ! 241: } ! 242: ! 243: /* ! 244: * CheckAttn ! 245: * ! 246: * Checks to see if there is any attention data and passes the data back ! 247: * in the passed in pb. ! 248: * ! 249: * INPUTS: ! 250: * sp ! 251: * pb ! 252: * ! 253: * OUTPUTS: ! 254: * ! 255: */ ! 256: int CheckAttn(sp, pb) /* (CCBPtr sp) */ ! 257: register CCBPtr sp; ! 258: register struct adspcmd *pb; ! 259: { ! 260: int s; ! 261: gbuf_t *mp; ! 262: gref_t *gref; ! 263: ! 264: dPrintf(D_M_ADSP, D_L_TRACE, ! 265: ("CheckAttn: sp=0x%x, pb=0x%x\n", (unsigned)sp, (unsigned)pb)); ! 266: ! 267: ATDISABLE(s, sp->lock); ! 268: if (mp = sp->attn_mb) { ! 269: ! 270: /* ! 271: * Deliver the attention data to the user. ! 272: */ ! 273: gref = (gref_t *)pb->gref; ! 274: pb->u.attnParams.attnSize = sp->attnSize; ! 275: pb->u.attnParams.attnCode = sp->attnCode; ! 276: if (!sp->attnSize) { ! 277: gbuf_freem(mp); ! 278: mp = 0; ! 279: } ! 280: sp->userFlags &= ~eAttention; ! 281: /* ! 282: * Now clean up receive buffer to remove all of the data ! 283: * we just copied ! 284: */ ! 285: sp->attn_mb = 0; ! 286: pb->ioResult = 0; ! 287: } else { ! 288: /* ! 289: * No data... ! 290: */ ! 291: pb->u.attnParams.attnSize = 0; ! 292: pb->u.attnParams.attnCode = 0; ! 293: pb->ioResult = 1; /* not done */ ! 294: } ! 295: adspioc_ack(0, pb->ioc, pb->gref); ! 296: if (mp) { ! 297: SndMsgUp(gref, mp); ! 298: } ! 299: ATENABLE(s, sp->lock); ! 300: return 0; ! 301: } ! 302: ! 303: /* ! 304: * adspRead ! 305: * ! 306: * INPUTS: ! 307: * --> sp stream pointer ! 308: * --> pb user request parameter block ! 309: * ! 310: * OUTPUTS: ! 311: * <-- actCount actual number of bytes read ! 312: * <-- eom one if end-of-message, zero otherwise ! 313: * ! 314: * ERRORS: ! 315: * errRefNum bad connection refnum ! 316: * errState ! 317: * errFwdReset read terminated by forward reset ! 318: * errAborted request aborted by Remove or Close call ! 319: */ ! 320: int adspRead(sp, pb) /* (DSPPBPtr pb) */ ! 321: register CCBPtr sp; ! 322: register struct adspcmd *pb; ! 323: { ! 324: register gbuf_t *mp; ! 325: int s; ! 326: ! 327: dPrintf(D_M_ADSP, D_L_TRACE, ! 328: ("adspRead: sp=0x%x, pb=0x%x\n", (unsigned)sp, (unsigned)pb)); ! 329: ! 330: KERNEL_DEBUG(DBG_ADSP_READ, 0x12, sp, pb, sp->state, sp->rData); ! 331: ! 332: if (sp == 0) { ! 333: pb->ioResult = errRefNum; ! 334: return EINVAL; ! 335: } ! 336: ! 337: /* ! 338: * It's OK to read on a closed, or closing session ! 339: */ ! 340: ATDISABLE(s, sp->lock); ! 341: if (sp->state != sOpen && sp->state != sClosing && sp->state != sClosed) { ! 342: ATENABLE(s, sp->lock); ! 343: pb->ioResult = errState; ! 344: return EINVAL; ! 345: } ! 346: if (sp->rData && (sp->rpb == 0)) { /* if data, and no queue of pbs */ ! 347: qAddToEnd(&sp->rpb, pb); /* deliver data to user directly */ ! 348: ATENABLE(s, sp->lock); ! 349: CheckReadQueue(sp); ! 350: } else if ((pb->u.ioParams.reqCount == 0) && (sp->rpb == 0)) { ! 351: /* empty read */ ! 352: ATENABLE(s, sp->lock); ! 353: pb->ioResult = 0; ! 354: adspioc_ack(0, pb->ioc, pb->gref); ! 355: return 0; ! 356: } else { ! 357: pb->ioResult = 1; ! 358: if (mp = gbuf_copym(pb->mp)) { /* otherwise, duplicate user request */ ! 359: adspioc_ack(0, pb->ioc, pb->gref); /* release user */ ! 360: pb = (struct adspcmd *)gbuf_rptr(mp); /* get new parameter block */ ! 361: pb->ioc = 0; ! 362: pb->mp = mp; ! 363: qAddToEnd(&sp->rpb, pb); /* and queue it for later */ ! 364: ATENABLE(s, sp->lock); ! 365: } else { ! 366: ATENABLE(s, sp->lock); ! 367: pb->ioResult = errDSPQueueSize; ! 368: return ENOBUFS; ! 369: } ! 370: } ! 371: ! 372: if (sp->callSend) { ! 373: CheckSend(sp); /* If recv window opened, we might */ ! 374: /* send an unsolicited ACK. */ ! 375: } ! 376: return 0; ! 377: } ! 378: ! 379: /* ! 380: * dspReadAttention ! 381: * ! 382: * INPUTS: ! 383: * --> sp stream pointer ! 384: * --> pb user request parameter block ! 385: * ! 386: * OUTPUTS: ! 387: * <-- NONE ! 388: * ! 389: * ERRORS: ! 390: * errRefNum bad connection refnum ! 391: * errState connection is not in the right state ! 392: */ ! 393: int adspReadAttention(sp, pb) /* (DSPPBPtr pb) */ ! 394: register CCBPtr sp; ! 395: register struct adspcmd *pb; ! 396: { ! 397: dPrintf(D_M_ADSP, D_L_TRACE, ! 398: ("adspReadAttention: sp=0x%x, pb=0x%x\n", (unsigned)sp, (unsigned)pb)); ! 399: if (sp == 0) { ! 400: pb->ioResult = errRefNum; ! 401: return EINVAL; ! 402: } ! 403: ! 404: /* ! 405: * It's OK to read on a closed, or closing session ! 406: */ ! 407: if (sp->state != sOpen && sp->state != sClosing && sp->state != sClosed) { ! 408: pb->ioResult = errState; ! 409: return EINVAL; ! 410: } ! 411: ! 412: CheckAttn(sp, pb); /* Anything in the attention queue */ ! 413: CheckReadQueue(sp); /* check to see if receive window has opened */ ! 414: if (sp->callSend) { ! 415: CheckSend(sp); /* If recv window opened, we might */ ! 416: /* send an unsolicited ACK. */ ! 417: } ! 418: return 0; ! 419: } /* adspReadAttention */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.