]>
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 * 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.
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
20 * @APPLE_LICENSE_HEADER_END@
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.
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>
38 #include <sys/filedesc.h>
39 #include <sys/fcntl.h>
41 #include <sys/socket.h>
42 #include <sys/socketvar.h>
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>
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.
59 extern int adsp_check
;
61 int CheckReadQueue(sp
) /* (CCBPtr sp) */
64 register struct adspcmd
*pb
;
71 dPrintf(D_M_ADSP
, D_L_TRACE
, ("CheckReadQueue: sp=0x%x\n", (unsigned)sp
));
72 KERNEL_DEBUG(DBG_ADSP_READ
, 0, sp
, sp
->rbuf_mb
, sp
->rpb
, sp
->delay
);
73 trace_mbufs(D_M_ADSP_LOW
, " bCQR m", sp
->rbuf_mb
);
75 while (sp
->rData
&& (pb
= sp
->rpb
)) { /* have data */
76 dPrintf(D_M_ADSP
, D_L_TRACE
,
77 (" pb=0x%x, gref=0x%x, ioc=0x%x, reqCount=%d (have data)\n",
78 pb
, pb
->gref
, pb
->ioc
, pb
->u
.ioParams
.reqCount
));
79 KERNEL_DEBUG(DBG_ADSP_READ
, 1, pb
, pb
->gref
, pb
->ioc
, pb
->u
.ioParams
.reqCount
);
80 if (pb
->u
.ioParams
.reqCount
== 0) {
84 KERNEL_DEBUG(DBG_ADSP_READ
, 2, pb
, pb
->gref
, pb
->ioc
, 0);
85 adspioc_ack(0, pb
->ioc
, pb
->gref
);
87 KERNEL_DEBUG(DBG_ADSP_READ
, 3, pb
, pb
->gref
, 0, 0);
93 /* take the first packet off of sp->rbuf_mb or sp->crbuf_mb */
94 if (mp
= sp
->rbuf_mb
) { /* Get header for oldest data */
95 KERNEL_DEBUG(DBG_ADSP_READ
, 4, pb
, mp
, gbuf_msgsize(mp
), gbuf_next(mp
));
96 sp
->rbuf_mb
= gbuf_next(mp
);
99 } else if (mp
= sp
->crbuf_mb
) {
100 KERNEL_DEBUG(DBG_ADSP_READ
, 5, pb
, mp
, gbuf_msgsize(mp
), gbuf_next(mp
));
105 /* Get the first (reqCount-actCount) bytes and tack them onto
106 the end of pb->mp. If eom is set, put the remainder of the
107 data onto the front of sp->rbuf_mb, otherwise sp->crbuf_mb. */
108 cnt
= gbuf_msgsize(mp
); /* # of data bytes in it. */
109 if (cnt
> (unsigned short)(pb
->u
.ioParams
.reqCount
- pb
->u
.ioParams
.actCount
)) {
110 cnt
= pb
->u
.ioParams
.reqCount
- pb
->u
.ioParams
.actCount
;
111 /* m_split returns the tail */
112 if (!(tmp
= (gbuf_t
*)m_split(mp
, cnt
, M_DONTWAIT
))) {
117 gbuf_next(tmp
) = sp
->rbuf_mb
;
124 pb
->u
.ioParams
.actCount
+= cnt
;
125 gbuf_linkb(pb
->mp
, mp
);
128 pb
->u
.ioParams
.eom
= eom
;
130 * Now clean up receive buffer to remove all of the data
133 if ((sp
->rbuf_mb
== 0) &&
134 (sp
->crbuf_mb
== 0)) /* no more data blocks */
137 * If we've filled the parameter block, unlink it from read
138 * queue and complete it. We also need to do this if the connection
139 * is closed && there is no more stuff to read.
141 if (eom
|| (pb
->u
.ioParams
.actCount
>= pb
->u
.ioParams
.reqCount
) ||
142 ((sp
->state
== sClosed
) && (!sp
->rData
)) ) {
143 /* end of message, message is full, connection
144 * is closed and all data has been delivered,
145 * or we are not to "delay" data delivery.
148 sp
->rpb
= pb
->qLink
; /* dequeue request */
149 if (pb
->ioc
) { /* data to be delivered at the time of the */
150 mp
= gbuf_cont(pb
->mp
); /* ioctl call */
151 gbuf_cont(pb
->mp
) = 0;
152 gref
= (gref_t
*)pb
->gref
;
153 adspioc_ack(0, pb
->ioc
, pb
->gref
);
154 dPrintf(D_M_ADSP
, D_L_TRACE
, (" (pb->ioc) mp=%x\n", mp
));
155 KERNEL_DEBUG(DBG_ADSP_READ
, 0x0A, pb
, mp
,
156 gbuf_next(mp
), gbuf_cont(mp
));
158 dPrintf(D_M_ADSP
, D_L_TRACE
,
159 (" (data) size req=%d\n", pb
->u
.ioParams
.actCount
));
160 KERNEL_DEBUG(DBG_ADSP_READ
, 0x0B, pb
, pb
->ioc
,
161 pb
->u
.ioParams
.reqCount
, pb
->u
.ioParams
.actCount
);
162 } else { /* complete an queued async request */
163 KERNEL_DEBUG(DBG_ADSP_READ
, 0x0C, pb
, sp
,
164 pb
->u
.ioParams
.actCount
, sp
->delay
);
170 if (pb
= sp
->rpb
) { /* if there is an outstanding request */
171 dPrintf(D_M_ADSP
, D_L_TRACE
,
172 (" pb=0x%x, ioc=0x%x, reqCount=%d (no more data)\n",
173 pb
, pb
->ioc
, pb
->u
.ioParams
.reqCount
));
174 KERNEL_DEBUG(DBG_ADSP_READ
, 0x0D, pb
, pb
->ioc
,
175 pb
->u
.ioParams
.reqCount
, pb
->u
.ioParams
.actCount
);
177 if (sp
->state
== sClosed
) {
179 KERNEL_DEBUG(DBG_ADSP_READ
, 0x0E, pb
, sp
, pb
->ioc
, 0);
181 pb
->u
.ioParams
.actCount
= 0;
182 pb
->u
.ioParams
.eom
= 0;
185 adspioc_ack(0, pb
->ioc
, pb
->gref
);
191 } else if (pb
->ioc
) { /* if request not complete and this
192 * is an active ioctl, release user */
195 tmp
= gbuf_cont(pb
->mp
); /* detatch perhaps delayed data */
196 gbuf_cont(pb
->mp
) = 0;
197 if (mp
= gbuf_copym(pb
->mp
)) { /* otherwise, duplicate user request */
198 KERNEL_DEBUG(DBG_ADSP_READ
, 0x0F, pb
, sp
, pb
->mp
, 0);
199 adspioc_ack(0, pb
->ioc
, pb
->gref
); /* release user */
200 pb
= (struct adspcmd
*)gbuf_rptr(mp
); /* get new parameter block */
203 gbuf_cont(pb
->mp
) = tmp
; /* reattach data */
204 pb
->qLink
= sp
->rpb
; /* requeue the duplicate at the head */
206 } else { /* there is no data left, but no space
207 * to duplicate the parameter block, so
208 * put what must be a non EOM message
209 * back on the current receive queue, and
212 KERNEL_DEBUG(DBG_ADSP_READ
, 0x10, pb
, sp
, pb
->mp
, 0);
217 pb
->ioResult
= errDSPQueueSize
;
218 adspioc_ack(ENOBUFS
, pb
->ioc
, pb
->gref
);
223 * The receive window has opened. If was previously closed, then we
224 * need to notify the other guy that we now have room to receive more
225 * data. But, in order to cut down on lots of small data packets,
226 * we'll wait until the recieve buffer is /14 empy before telling
227 * him that there's room in our receive buffer.
229 if (sp
->rbufFull
&& (CalcRecvWdw(sp
) > (sp
->rbuflen
>> 2))) {
235 KERNEL_DEBUG(DBG_ADSP_READ
, 0x11, sp
, 0, 0, 0);
236 trace_mbufs(D_M_ADSP_LOW
, " eCQR m", sp
->rbuf_mb
);
243 * Checks to see if there is any attention data and passes the data back
244 * in the passed in pb.
253 int CheckAttn(sp
, pb
) /* (CCBPtr sp) */
255 register struct adspcmd
*pb
;
260 dPrintf(D_M_ADSP
, D_L_TRACE
,
261 ("CheckAttn: sp=0x%x, pb=0x%x\n", (unsigned)sp
, (unsigned)pb
));
263 if (mp
= sp
->attn_mb
) {
266 * Deliver the attention data to the user.
268 gref
= (gref_t
*)pb
->gref
;
269 pb
->u
.attnParams
.attnSize
= sp
->attnSize
;
270 pb
->u
.attnParams
.attnCode
= sp
->attnCode
;
275 sp
->userFlags
&= ~eAttention
;
277 * Now clean up receive buffer to remove all of the data
286 pb
->u
.attnParams
.attnSize
= 0;
287 pb
->u
.attnParams
.attnCode
= 0;
288 pb
->ioResult
= 1; /* not done */
290 adspioc_ack(0, pb
->ioc
, pb
->gref
);
301 * --> sp stream pointer
302 * --> pb user request parameter block
305 * <-- actCount actual number of bytes read
306 * <-- eom one if end-of-message, zero otherwise
309 * errRefNum bad connection refnum
311 * errFwdReset read terminated by forward reset
312 * errAborted request aborted by Remove or Close call
314 int adspRead(sp
, pb
) /* (DSPPBPtr pb) */
316 register struct adspcmd
*pb
;
320 dPrintf(D_M_ADSP
, D_L_TRACE
,
321 ("adspRead: sp=0x%x, pb=0x%x\n", (unsigned)sp
, (unsigned)pb
));
323 KERNEL_DEBUG(DBG_ADSP_READ
, 0x12, sp
, pb
, sp
->state
, sp
->rData
);
326 pb
->ioResult
= errRefNum
;
331 * It's OK to read on a closed, or closing session
333 if (sp
->state
!= sOpen
&& sp
->state
!= sClosing
&& sp
->state
!= sClosed
) {
334 pb
->ioResult
= errState
;
337 if (sp
->rData
&& (sp
->rpb
== 0)) { /* if data, and no queue of pbs */
338 qAddToEnd(&sp
->rpb
, pb
); /* deliver data to user directly */
340 } else if ((pb
->u
.ioParams
.reqCount
== 0) && (sp
->rpb
== 0)) {
343 adspioc_ack(0, pb
->ioc
, pb
->gref
);
347 if (mp
= gbuf_copym(pb
->mp
)) { /* otherwise, duplicate user request */
348 adspioc_ack(0, pb
->ioc
, pb
->gref
); /* release user */
349 pb
= (struct adspcmd
*)gbuf_rptr(mp
); /* get new parameter block */
352 qAddToEnd(&sp
->rpb
, pb
); /* and queue it for later */
354 pb
->ioResult
= errDSPQueueSize
;
360 CheckSend(sp
); /* If recv window opened, we might */
361 /* send an unsolicited ACK. */
370 * --> sp stream pointer
371 * --> pb user request parameter block
377 * errRefNum bad connection refnum
378 * errState connection is not in the right state
380 int adspReadAttention(sp
, pb
) /* (DSPPBPtr pb) */
382 register struct adspcmd
*pb
;
384 dPrintf(D_M_ADSP
, D_L_TRACE
,
385 ("adspReadAttention: sp=0x%x, pb=0x%x\n", (unsigned)sp
, (unsigned)pb
));
387 pb
->ioResult
= errRefNum
;
392 * It's OK to read on a closed, or closing session
394 if (sp
->state
!= sOpen
&& sp
->state
!= sClosing
&& sp
->state
!= sClosed
) {
395 pb
->ioResult
= errState
;
399 CheckAttn(sp
, pb
); /* Anything in the attention queue */
400 CheckReadQueue(sp
); /* check to see if receive window has opened */
402 CheckSend(sp
); /* If recv window opened, we might */
403 /* send an unsolicited ACK. */
406 } /* adspReadAttention */