darwin-xnu/bsd/netat/adsp_Read.c
<<
>>
Prefs
   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 */
  59extern int adsp_check;
  60
  61int 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 */
 256int 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 */
 320int 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 */
 393int 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 */
 420
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.