]>
git.saurik.com Git - apple/xnu.git/blob - bsd/netat/adsp_Read.c
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
29 * From v01.17 08/22/90 mbs
30 * Modified for MP, 1996 by Tuyen Nguyen
31 * Modified, April 9, 1997 by Tuyen Nguyen for MacOSX.
34 #include <sys/errno.h>
35 #include <sys/types.h>
36 #include <sys/param.h>
37 #include <machine/spl.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
41 #include <sys/filedesc.h>
42 #include <sys/fcntl.h>
44 #include <sys/socket.h>
45 #include <sys/socketvar.h>
47 #include <netat/sysglue.h>
48 #include <netat/appletalk.h>
49 #include <netat/at_pcb.h>
50 #include <netat/debug.h>
51 #include <netat/adsp.h>
52 #include <netat/adsp_internal.h>
57 * Checks to see if there is any data in the receive queue. If there
58 * is data, a pb and the data are queued to the user.
62 extern int adsp_check
;
64 int CheckReadQueue(sp
) /* (CCBPtr sp) */
67 register struct adspcmd
*pb
;
75 dPrintf(D_M_ADSP
, D_L_TRACE
, ("CheckReadQueue: sp=0x%x\n", (unsigned)sp
));
76 KERNEL_DEBUG(DBG_ADSP_READ
, 0, sp
, sp
->rbuf_mb
, sp
->rpb
, sp
->delay
);
77 trace_mbufs(D_M_ADSP_LOW
, " bCQR m", sp
->rbuf_mb
);
78 ATDISABLE(s
, sp
->lock
);
80 while (sp
->rData
&& (pb
= sp
->rpb
)) { /* have data */
81 dPrintf(D_M_ADSP
, D_L_TRACE
,
82 (" pb=0x%x, gref=0x%x, ioc=0x%x, reqCount=%d (have data)\n",
83 pb
, pb
->gref
, pb
->ioc
, pb
->u
.ioParams
.reqCount
));
84 KERNEL_DEBUG(DBG_ADSP_READ
, 1, pb
, pb
->gref
, pb
->ioc
, pb
->u
.ioParams
.reqCount
);
85 if (pb
->u
.ioParams
.reqCount
== 0) {
89 KERNEL_DEBUG(DBG_ADSP_READ
, 2, pb
, pb
->gref
, pb
->ioc
, 0);
90 adspioc_ack(0, pb
->ioc
, pb
->gref
);
92 KERNEL_DEBUG(DBG_ADSP_READ
, 3, pb
, pb
->gref
, 0, 0);
98 /* take the first packet off of sp->rbuf_mb or sp->crbuf_mb */
99 if (mp
= sp
->rbuf_mb
) { /* Get header for oldest data */
100 KERNEL_DEBUG(DBG_ADSP_READ
, 4, pb
, mp
, gbuf_msgsize(mp
), gbuf_next(mp
));
101 sp
->rbuf_mb
= gbuf_next(mp
);
104 } else if (mp
= sp
->crbuf_mb
) {
105 KERNEL_DEBUG(DBG_ADSP_READ
, 5, pb
, mp
, gbuf_msgsize(mp
), gbuf_next(mp
));
110 /* Get the first (reqCount-actCount) bytes and tack them onto
111 the end of pb->mp. If eom is set, put the remainder of the
112 data onto the front of sp->rbuf_mb, otherwise sp->crbuf_mb. */
113 cnt
= gbuf_msgsize(mp
); /* # of data bytes in it. */
114 if (cnt
> (unsigned short)(pb
->u
.ioParams
.reqCount
- pb
->u
.ioParams
.actCount
)) {
115 cnt
= pb
->u
.ioParams
.reqCount
- pb
->u
.ioParams
.actCount
;
116 /* m_split returns the tail */
117 if (!(tmp
= (gbuf_t
*)m_split(mp
, cnt
, M_DONTWAIT
))) {
122 gbuf_next(tmp
) = sp
->rbuf_mb
;
129 pb
->u
.ioParams
.actCount
+= cnt
;
130 gbuf_linkb(pb
->mp
, mp
);
133 pb
->u
.ioParams
.eom
= eom
;
135 * Now clean up receive buffer to remove all of the data
138 if ((sp
->rbuf_mb
== 0) &&
139 (sp
->crbuf_mb
== 0)) /* no more data blocks */
142 * If we've filled the parameter block, unlink it from read
143 * queue and complete it. We also need to do this if the connection
144 * is closed && there is no more stuff to read.
146 if (eom
|| (pb
->u
.ioParams
.actCount
>= pb
->u
.ioParams
.reqCount
) ||
147 ((sp
->state
== sClosed
) && (!sp
->rData
)) ) {
148 /* end of message, message is full, connection
149 * is closed and all data has been delivered,
150 * or we are not to "delay" data delivery.
153 sp
->rpb
= pb
->qLink
; /* dequeue request */
154 if (pb
->ioc
) { /* data to be delivered at the time of the */
155 mp
= gbuf_cont(pb
->mp
); /* ioctl call */
156 gbuf_cont(pb
->mp
) = 0;
157 gref
= (gref_t
*)pb
->gref
;
158 adspioc_ack(0, pb
->ioc
, pb
->gref
);
159 dPrintf(D_M_ADSP
, D_L_TRACE
, (" (pb->ioc) mp=%x\n", mp
));
160 KERNEL_DEBUG(DBG_ADSP_READ
, 0x0A, pb
, mp
,
161 gbuf_next(mp
), gbuf_cont(mp
));
163 dPrintf(D_M_ADSP
, D_L_TRACE
,
164 (" (data) size req=%d\n", pb
->u
.ioParams
.actCount
));
165 KERNEL_DEBUG(DBG_ADSP_READ
, 0x0B, pb
, pb
->ioc
,
166 pb
->u
.ioParams
.reqCount
, pb
->u
.ioParams
.actCount
);
167 } else { /* complete an queued async request */
168 KERNEL_DEBUG(DBG_ADSP_READ
, 0x0C, pb
, sp
,
169 pb
->u
.ioParams
.actCount
, sp
->delay
);
175 if (pb
= sp
->rpb
) { /* if there is an outstanding request */
176 dPrintf(D_M_ADSP
, D_L_TRACE
,
177 (" pb=0x%x, ioc=0x%x, reqCount=%d (no more data)\n",
178 pb
, pb
->ioc
, pb
->u
.ioParams
.reqCount
));
179 KERNEL_DEBUG(DBG_ADSP_READ
, 0x0D, pb
, pb
->ioc
,
180 pb
->u
.ioParams
.reqCount
, pb
->u
.ioParams
.actCount
);
182 if (sp
->state
== sClosed
) {
184 KERNEL_DEBUG(DBG_ADSP_READ
, 0x0E, pb
, sp
, pb
->ioc
, 0);
186 pb
->u
.ioParams
.actCount
= 0;
187 pb
->u
.ioParams
.eom
= 0;
190 adspioc_ack(0, pb
->ioc
, pb
->gref
);
196 } else if (pb
->ioc
) { /* if request not complete and this
197 * is an active ioctl, release user */
200 tmp
= gbuf_cont(pb
->mp
); /* detatch perhaps delayed data */
201 gbuf_cont(pb
->mp
) = 0;
202 if (mp
= gbuf_copym(pb
->mp
)) { /* otherwise, duplicate user request */
203 KERNEL_DEBUG(DBG_ADSP_READ
, 0x0F, pb
, sp
, pb
->mp
, 0);
204 adspioc_ack(0, pb
->ioc
, pb
->gref
); /* release user */
205 pb
= (struct adspcmd
*)gbuf_rptr(mp
); /* get new parameter block */
208 gbuf_cont(pb
->mp
) = tmp
; /* reattach data */
209 pb
->qLink
= sp
->rpb
; /* requeue the duplicate at the head */
211 } else { /* there is no data left, but no space
212 * to duplicate the parameter block, so
213 * put what must be a non EOM message
214 * back on the current receive queue, and
217 KERNEL_DEBUG(DBG_ADSP_READ
, 0x10, pb
, sp
, pb
->mp
, 0);
222 pb
->ioResult
= errDSPQueueSize
;
223 adspioc_ack(ENOBUFS
, pb
->ioc
, pb
->gref
);
228 * The receive window has opened. If was previously closed, then we
229 * need to notify the other guy that we now have room to receive more
230 * data. But, in order to cut down on lots of small data packets,
231 * we'll wait until the recieve buffer is /14 empy before telling
232 * him that there's room in our receive buffer.
234 if (sp
->rbufFull
&& (CalcRecvWdw(sp
) > (sp
->rbuflen
>> 2))) {
239 ATENABLE(s
, sp
->lock
);
241 KERNEL_DEBUG(DBG_ADSP_READ
, 0x11, sp
, 0, 0, 0);
242 trace_mbufs(D_M_ADSP_LOW
, " eCQR m", sp
->rbuf_mb
);
249 * Checks to see if there is any attention data and passes the data back
250 * in the passed in pb.
259 int CheckAttn(sp
, pb
) /* (CCBPtr sp) */
261 register struct adspcmd
*pb
;
267 dPrintf(D_M_ADSP
, D_L_TRACE
,
268 ("CheckAttn: sp=0x%x, pb=0x%x\n", (unsigned)sp
, (unsigned)pb
));
270 ATDISABLE(s
, sp
->lock
);
271 if (mp
= sp
->attn_mb
) {
274 * Deliver the attention data to the user.
276 gref
= (gref_t
*)pb
->gref
;
277 pb
->u
.attnParams
.attnSize
= sp
->attnSize
;
278 pb
->u
.attnParams
.attnCode
= sp
->attnCode
;
283 sp
->userFlags
&= ~eAttention
;
285 * Now clean up receive buffer to remove all of the data
294 pb
->u
.attnParams
.attnSize
= 0;
295 pb
->u
.attnParams
.attnCode
= 0;
296 pb
->ioResult
= 1; /* not done */
298 adspioc_ack(0, pb
->ioc
, pb
->gref
);
302 ATENABLE(s
, sp
->lock
);
310 * --> sp stream pointer
311 * --> pb user request parameter block
314 * <-- actCount actual number of bytes read
315 * <-- eom one if end-of-message, zero otherwise
318 * errRefNum bad connection refnum
320 * errFwdReset read terminated by forward reset
321 * errAborted request aborted by Remove or Close call
323 int adspRead(sp
, pb
) /* (DSPPBPtr pb) */
325 register struct adspcmd
*pb
;
330 dPrintf(D_M_ADSP
, D_L_TRACE
,
331 ("adspRead: sp=0x%x, pb=0x%x\n", (unsigned)sp
, (unsigned)pb
));
333 KERNEL_DEBUG(DBG_ADSP_READ
, 0x12, sp
, pb
, sp
->state
, sp
->rData
);
336 pb
->ioResult
= errRefNum
;
341 * It's OK to read on a closed, or closing session
343 ATDISABLE(s
, sp
->lock
);
344 if (sp
->state
!= sOpen
&& sp
->state
!= sClosing
&& sp
->state
!= sClosed
) {
345 ATENABLE(s
, sp
->lock
);
346 pb
->ioResult
= errState
;
349 if (sp
->rData
&& (sp
->rpb
== 0)) { /* if data, and no queue of pbs */
350 qAddToEnd(&sp
->rpb
, pb
); /* deliver data to user directly */
351 ATENABLE(s
, sp
->lock
);
353 } else if ((pb
->u
.ioParams
.reqCount
== 0) && (sp
->rpb
== 0)) {
355 ATENABLE(s
, sp
->lock
);
357 adspioc_ack(0, pb
->ioc
, pb
->gref
);
361 if (mp
= gbuf_copym(pb
->mp
)) { /* otherwise, duplicate user request */
362 adspioc_ack(0, pb
->ioc
, pb
->gref
); /* release user */
363 pb
= (struct adspcmd
*)gbuf_rptr(mp
); /* get new parameter block */
366 qAddToEnd(&sp
->rpb
, pb
); /* and queue it for later */
367 ATENABLE(s
, sp
->lock
);
369 ATENABLE(s
, sp
->lock
);
370 pb
->ioResult
= errDSPQueueSize
;
376 CheckSend(sp
); /* If recv window opened, we might */
377 /* send an unsolicited ACK. */
386 * --> sp stream pointer
387 * --> pb user request parameter block
393 * errRefNum bad connection refnum
394 * errState connection is not in the right state
396 int adspReadAttention(sp
, pb
) /* (DSPPBPtr pb) */
398 register struct adspcmd
*pb
;
400 dPrintf(D_M_ADSP
, D_L_TRACE
,
401 ("adspReadAttention: sp=0x%x, pb=0x%x\n", (unsigned)sp
, (unsigned)pb
));
403 pb
->ioResult
= errRefNum
;
408 * It's OK to read on a closed, or closing session
410 if (sp
->state
!= sOpen
&& sp
->state
!= sClosing
&& sp
->state
!= sClosed
) {
411 pb
->ioResult
= errState
;
415 CheckAttn(sp
, pb
); /* Anything in the attention queue */
416 CheckReadQueue(sp
); /* check to see if receive window has opened */
418 CheckSend(sp
); /* If recv window opened, we might */
419 /* send an unsolicited ACK. */
422 } /* adspReadAttention */