]>
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_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
32 * From v01.17 08/22/90 mbs
33 * Modified for MP, 1996 by Tuyen Nguyen
34 * Modified, April 9, 1997 by Tuyen Nguyen for MacOSX.
37 #include <sys/errno.h>
38 #include <sys/types.h>
39 #include <sys/param.h>
40 #include <machine/spl.h>
41 #include <sys/systm.h>
42 #include <sys/kernel.h>
44 #include <sys/filedesc.h>
45 #include <sys/fcntl.h>
47 #include <sys/socket.h>
48 #include <sys/socketvar.h>
50 #include <netat/sysglue.h>
51 #include <netat/appletalk.h>
52 #include <netat/at_pcb.h>
53 #include <netat/debug.h>
54 #include <netat/adsp.h>
55 #include <netat/adsp_internal.h>
60 * Checks to see if there is any data in the receive queue. If there
61 * is data, a pb and the data are queued to the user.
65 extern int adsp_check
;
67 int CheckReadQueue(sp
) /* (CCBPtr sp) */
70 register struct adspcmd
*pb
;
78 dPrintf(D_M_ADSP
, D_L_TRACE
, ("CheckReadQueue: sp=0x%x\n", (unsigned)sp
));
79 KERNEL_DEBUG(DBG_ADSP_READ
, 0, sp
, sp
->rbuf_mb
, sp
->rpb
, sp
->delay
);
80 trace_mbufs(D_M_ADSP_LOW
, " bCQR m", sp
->rbuf_mb
);
81 ATDISABLE(s
, sp
->lock
);
83 while (sp
->rData
&& (pb
= sp
->rpb
)) { /* have data */
84 dPrintf(D_M_ADSP
, D_L_TRACE
,
85 (" pb=0x%x, gref=0x%x, ioc=0x%x, reqCount=%d (have data)\n",
86 pb
, pb
->gref
, pb
->ioc
, pb
->u
.ioParams
.reqCount
));
87 KERNEL_DEBUG(DBG_ADSP_READ
, 1, pb
, pb
->gref
, pb
->ioc
, pb
->u
.ioParams
.reqCount
);
88 if (pb
->u
.ioParams
.reqCount
== 0) {
92 KERNEL_DEBUG(DBG_ADSP_READ
, 2, pb
, pb
->gref
, pb
->ioc
, 0);
93 adspioc_ack(0, pb
->ioc
, pb
->gref
);
95 KERNEL_DEBUG(DBG_ADSP_READ
, 3, pb
, pb
->gref
, 0, 0);
101 /* take the first packet off of sp->rbuf_mb or sp->crbuf_mb */
102 if (mp
= sp
->rbuf_mb
) { /* Get header for oldest data */
103 KERNEL_DEBUG(DBG_ADSP_READ
, 4, pb
, mp
, gbuf_msgsize(mp
), gbuf_next(mp
));
104 sp
->rbuf_mb
= gbuf_next(mp
);
107 } else if (mp
= sp
->crbuf_mb
) {
108 KERNEL_DEBUG(DBG_ADSP_READ
, 5, pb
, mp
, gbuf_msgsize(mp
), gbuf_next(mp
));
113 /* Get the first (reqCount-actCount) bytes and tack them onto
114 the end of pb->mp. If eom is set, put the remainder of the
115 data onto the front of sp->rbuf_mb, otherwise sp->crbuf_mb. */
116 cnt
= gbuf_msgsize(mp
); /* # of data bytes in it. */
117 if (cnt
> (unsigned short)(pb
->u
.ioParams
.reqCount
- pb
->u
.ioParams
.actCount
)) {
118 cnt
= pb
->u
.ioParams
.reqCount
- pb
->u
.ioParams
.actCount
;
119 /* m_split returns the tail */
120 if (!(tmp
= (gbuf_t
*)m_split(mp
, cnt
, M_DONTWAIT
))) {
125 gbuf_next(tmp
) = sp
->rbuf_mb
;
132 pb
->u
.ioParams
.actCount
+= cnt
;
133 gbuf_linkb(pb
->mp
, mp
);
136 pb
->u
.ioParams
.eom
= eom
;
138 * Now clean up receive buffer to remove all of the data
141 if ((sp
->rbuf_mb
== 0) &&
142 (sp
->crbuf_mb
== 0)) /* no more data blocks */
145 * If we've filled the parameter block, unlink it from read
146 * queue and complete it. We also need to do this if the connection
147 * is closed && there is no more stuff to read.
149 if (eom
|| (pb
->u
.ioParams
.actCount
>= pb
->u
.ioParams
.reqCount
) ||
150 ((sp
->state
== sClosed
) && (!sp
->rData
)) ) {
151 /* end of message, message is full, connection
152 * is closed and all data has been delivered,
153 * or we are not to "delay" data delivery.
156 sp
->rpb
= pb
->qLink
; /* dequeue request */
157 if (pb
->ioc
) { /* data to be delivered at the time of the */
158 mp
= gbuf_cont(pb
->mp
); /* ioctl call */
159 gbuf_cont(pb
->mp
) = 0;
160 gref
= (gref_t
*)pb
->gref
;
161 adspioc_ack(0, pb
->ioc
, pb
->gref
);
162 dPrintf(D_M_ADSP
, D_L_TRACE
, (" (pb->ioc) mp=%x\n", mp
));
163 KERNEL_DEBUG(DBG_ADSP_READ
, 0x0A, pb
, mp
,
164 gbuf_next(mp
), gbuf_cont(mp
));
166 dPrintf(D_M_ADSP
, D_L_TRACE
,
167 (" (data) size req=%d\n", pb
->u
.ioParams
.actCount
));
168 KERNEL_DEBUG(DBG_ADSP_READ
, 0x0B, pb
, pb
->ioc
,
169 pb
->u
.ioParams
.reqCount
, pb
->u
.ioParams
.actCount
);
170 } else { /* complete an queued async request */
171 KERNEL_DEBUG(DBG_ADSP_READ
, 0x0C, pb
, sp
,
172 pb
->u
.ioParams
.actCount
, sp
->delay
);
178 if (pb
= sp
->rpb
) { /* if there is an outstanding request */
179 dPrintf(D_M_ADSP
, D_L_TRACE
,
180 (" pb=0x%x, ioc=0x%x, reqCount=%d (no more data)\n",
181 pb
, pb
->ioc
, pb
->u
.ioParams
.reqCount
));
182 KERNEL_DEBUG(DBG_ADSP_READ
, 0x0D, pb
, pb
->ioc
,
183 pb
->u
.ioParams
.reqCount
, pb
->u
.ioParams
.actCount
);
185 if (sp
->state
== sClosed
) {
187 KERNEL_DEBUG(DBG_ADSP_READ
, 0x0E, pb
, sp
, pb
->ioc
, 0);
189 pb
->u
.ioParams
.actCount
= 0;
190 pb
->u
.ioParams
.eom
= 0;
193 adspioc_ack(0, pb
->ioc
, pb
->gref
);
199 } else if (pb
->ioc
) { /* if request not complete and this
200 * is an active ioctl, release user */
203 tmp
= gbuf_cont(pb
->mp
); /* detatch perhaps delayed data */
204 gbuf_cont(pb
->mp
) = 0;
205 if (mp
= gbuf_copym(pb
->mp
)) { /* otherwise, duplicate user request */
206 KERNEL_DEBUG(DBG_ADSP_READ
, 0x0F, pb
, sp
, pb
->mp
, 0);
207 adspioc_ack(0, pb
->ioc
, pb
->gref
); /* release user */
208 pb
= (struct adspcmd
*)gbuf_rptr(mp
); /* get new parameter block */
211 gbuf_cont(pb
->mp
) = tmp
; /* reattach data */
212 pb
->qLink
= sp
->rpb
; /* requeue the duplicate at the head */
214 } else { /* there is no data left, but no space
215 * to duplicate the parameter block, so
216 * put what must be a non EOM message
217 * back on the current receive queue, and
220 KERNEL_DEBUG(DBG_ADSP_READ
, 0x10, pb
, sp
, pb
->mp
, 0);
225 pb
->ioResult
= errDSPQueueSize
;
226 adspioc_ack(ENOBUFS
, pb
->ioc
, pb
->gref
);
231 * The receive window has opened. If was previously closed, then we
232 * need to notify the other guy that we now have room to receive more
233 * data. But, in order to cut down on lots of small data packets,
234 * we'll wait until the recieve buffer is /14 empy before telling
235 * him that there's room in our receive buffer.
237 if (sp
->rbufFull
&& (CalcRecvWdw(sp
) > (sp
->rbuflen
>> 2))) {
242 ATENABLE(s
, sp
->lock
);
244 KERNEL_DEBUG(DBG_ADSP_READ
, 0x11, sp
, 0, 0, 0);
245 trace_mbufs(D_M_ADSP_LOW
, " eCQR m", sp
->rbuf_mb
);
252 * Checks to see if there is any attention data and passes the data back
253 * in the passed in pb.
262 int CheckAttn(sp
, pb
) /* (CCBPtr sp) */
264 register struct adspcmd
*pb
;
270 dPrintf(D_M_ADSP
, D_L_TRACE
,
271 ("CheckAttn: sp=0x%x, pb=0x%x\n", (unsigned)sp
, (unsigned)pb
));
273 ATDISABLE(s
, sp
->lock
);
274 if (mp
= sp
->attn_mb
) {
277 * Deliver the attention data to the user.
279 gref
= (gref_t
*)pb
->gref
;
280 pb
->u
.attnParams
.attnSize
= sp
->attnSize
;
281 pb
->u
.attnParams
.attnCode
= sp
->attnCode
;
286 sp
->userFlags
&= ~eAttention
;
288 * Now clean up receive buffer to remove all of the data
297 pb
->u
.attnParams
.attnSize
= 0;
298 pb
->u
.attnParams
.attnCode
= 0;
299 pb
->ioResult
= 1; /* not done */
301 adspioc_ack(0, pb
->ioc
, pb
->gref
);
305 ATENABLE(s
, sp
->lock
);
313 * --> sp stream pointer
314 * --> pb user request parameter block
317 * <-- actCount actual number of bytes read
318 * <-- eom one if end-of-message, zero otherwise
321 * errRefNum bad connection refnum
323 * errFwdReset read terminated by forward reset
324 * errAborted request aborted by Remove or Close call
326 int adspRead(sp
, pb
) /* (DSPPBPtr pb) */
328 register struct adspcmd
*pb
;
333 dPrintf(D_M_ADSP
, D_L_TRACE
,
334 ("adspRead: sp=0x%x, pb=0x%x\n", (unsigned)sp
, (unsigned)pb
));
336 KERNEL_DEBUG(DBG_ADSP_READ
, 0x12, sp
, pb
, sp
->state
, sp
->rData
);
339 pb
->ioResult
= errRefNum
;
344 * It's OK to read on a closed, or closing session
346 ATDISABLE(s
, sp
->lock
);
347 if (sp
->state
!= sOpen
&& sp
->state
!= sClosing
&& sp
->state
!= sClosed
) {
348 ATENABLE(s
, sp
->lock
);
349 pb
->ioResult
= errState
;
352 if (sp
->rData
&& (sp
->rpb
== 0)) { /* if data, and no queue of pbs */
353 qAddToEnd(&sp
->rpb
, pb
); /* deliver data to user directly */
354 ATENABLE(s
, sp
->lock
);
356 } else if ((pb
->u
.ioParams
.reqCount
== 0) && (sp
->rpb
== 0)) {
358 ATENABLE(s
, sp
->lock
);
360 adspioc_ack(0, pb
->ioc
, pb
->gref
);
364 if (mp
= gbuf_copym(pb
->mp
)) { /* otherwise, duplicate user request */
365 adspioc_ack(0, pb
->ioc
, pb
->gref
); /* release user */
366 pb
= (struct adspcmd
*)gbuf_rptr(mp
); /* get new parameter block */
369 qAddToEnd(&sp
->rpb
, pb
); /* and queue it for later */
370 ATENABLE(s
, sp
->lock
);
372 ATENABLE(s
, sp
->lock
);
373 pb
->ioResult
= errDSPQueueSize
;
379 CheckSend(sp
); /* If recv window opened, we might */
380 /* send an unsolicited ACK. */
389 * --> sp stream pointer
390 * --> pb user request parameter block
396 * errRefNum bad connection refnum
397 * errState connection is not in the right state
399 int adspReadAttention(sp
, pb
) /* (DSPPBPtr pb) */
401 register struct adspcmd
*pb
;
403 dPrintf(D_M_ADSP
, D_L_TRACE
,
404 ("adspReadAttention: sp=0x%x, pb=0x%x\n", (unsigned)sp
, (unsigned)pb
));
406 pb
->ioResult
= errRefNum
;
411 * It's OK to read on a closed, or closing session
413 if (sp
->state
!= sOpen
&& sp
->state
!= sClosing
&& sp
->state
!= sClosed
) {
414 pb
->ioResult
= errState
;
418 CheckAttn(sp
, pb
); /* Anything in the attention queue */
419 CheckReadQueue(sp
); /* check to see if receive window has opened */
421 CheckSend(sp
); /* If recv window opened, we might */
422 /* send an unsolicited ACK. */
425 } /* adspReadAttention */