]>
git.saurik.com Git - apple/xnu.git/blob - bsd/netat/adsp_Read.c
2 * Copyright (c) 2000-2007 Apple 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
;
77 dPrintf(D_M_ADSP
, D_L_TRACE
, ("CheckReadQueue: sp=0x%x\n", (unsigned)sp
));
78 KERNEL_DEBUG(DBG_ADSP_READ
, 0, sp
, sp
->rbuf_mb
, sp
->rpb
, sp
->delay
);
79 trace_mbufs(D_M_ADSP_LOW
, " bCQR m", sp
->rbuf_mb
);
81 while (sp
->rData
&& (pb
= sp
->rpb
)) { /* have data */
82 dPrintf(D_M_ADSP
, D_L_TRACE
,
83 (" pb=0x%p, gref=0x%p, ioc=0x%p, reqCount=%d (have data)\n",
84 pb
, pb
->gref
, pb
->ioc
, pb
->u
.ioParams
.reqCount
));
85 KERNEL_DEBUG(DBG_ADSP_READ
, 1, pb
, pb
->gref
, pb
->ioc
, pb
->u
.ioParams
.reqCount
);
86 if (pb
->u
.ioParams
.reqCount
== 0) {
90 KERNEL_DEBUG(DBG_ADSP_READ
, 2, pb
, pb
->gref
, pb
->ioc
, 0);
91 adspioc_ack(0, (gbuf_t
*)pb
->ioc
, pb
->gref
);
93 KERNEL_DEBUG(DBG_ADSP_READ
, 3, pb
, pb
->gref
, 0, 0);
99 /* take the first packet off of sp->rbuf_mb or sp->crbuf_mb */
100 if ((mp
= sp
->rbuf_mb
)) { /* Get header for oldest data */
101 KERNEL_DEBUG(DBG_ADSP_READ
, 4, pb
, mp
, gbuf_msgsize(mp
), gbuf_next(mp
));
102 sp
->rbuf_mb
= gbuf_next(mp
);
105 } else if ((mp
= sp
->crbuf_mb
)) {
106 KERNEL_DEBUG(DBG_ADSP_READ
, 5, pb
, mp
, gbuf_msgsize(mp
), gbuf_next(mp
));
111 /* Get the first (reqCount-actCount) bytes and tack them onto
112 the end of pb->mp. If eom is set, put the remainder of the
113 data onto the front of sp->rbuf_mb, otherwise sp->crbuf_mb. */
114 cnt
= gbuf_msgsize(mp
); /* # of data bytes in it. */
115 if (cnt
> (unsigned short)(pb
->u
.ioParams
.reqCount
- pb
->u
.ioParams
.actCount
)) {
116 cnt
= pb
->u
.ioParams
.reqCount
- pb
->u
.ioParams
.actCount
;
117 /* m_split returns the tail */
118 if (!(tmp
= (gbuf_t
*)m_split(mp
, cnt
, M_DONTWAIT
))) {
123 gbuf_next(tmp
) = sp
->rbuf_mb
;
130 pb
->u
.ioParams
.actCount
+= cnt
;
131 gbuf_linkb(pb
->mp
, mp
);
134 pb
->u
.ioParams
.eom
= eom
;
136 * Now clean up receive buffer to remove all of the data
139 if ((sp
->rbuf_mb
== 0) &&
140 (sp
->crbuf_mb
== 0)) /* no more data blocks */
143 * If we've filled the parameter block, unlink it from read
144 * queue and complete it. We also need to do this if the connection
145 * is closed && there is no more stuff to read.
147 if (eom
|| (pb
->u
.ioParams
.actCount
>= pb
->u
.ioParams
.reqCount
) ||
148 ((sp
->state
== sClosed
) && (!sp
->rData
)) ) {
149 /* end of message, message is full, connection
150 * is closed and all data has been delivered,
151 * or we are not to "delay" data delivery.
154 sp
->rpb
= pb
->qLink
; /* dequeue request */
155 if (pb
->ioc
) { /* data to be delivered at the time of the */
156 mp
= gbuf_cont(pb
->mp
); /* ioctl call */
157 gbuf_cont(pb
->mp
) = 0;
158 gref
= (gref_t
*)pb
->gref
;
159 adspioc_ack(0, (gbuf_t
*)pb
->ioc
, pb
->gref
);
160 dPrintf(D_M_ADSP
, D_L_TRACE
, (" (pb->ioc) mp=%p\n", mp
));
161 KERNEL_DEBUG(DBG_ADSP_READ
, 0x0A, pb
, mp
,
162 gbuf_next(mp
), gbuf_cont(mp
));
164 dPrintf(D_M_ADSP
, D_L_TRACE
,
165 (" (data) size req=%d\n", pb
->u
.ioParams
.actCount
));
166 KERNEL_DEBUG(DBG_ADSP_READ
, 0x0B, pb
, pb
->ioc
,
167 pb
->u
.ioParams
.reqCount
, pb
->u
.ioParams
.actCount
);
168 } else { /* complete an queued async request */
169 KERNEL_DEBUG(DBG_ADSP_READ
, 0x0C, pb
, sp
,
170 pb
->u
.ioParams
.actCount
, sp
->delay
);
176 if ((pb
= sp
->rpb
)) { /* if there is an outstanding request */
177 dPrintf(D_M_ADSP
, D_L_TRACE
,
178 (" pb=0x%p, ioc=0x%p, reqCount=%d (no more data)\n",
179 pb
, pb
->ioc
, pb
->u
.ioParams
.reqCount
));
180 KERNEL_DEBUG(DBG_ADSP_READ
, 0x0D, pb
, pb
->ioc
,
181 pb
->u
.ioParams
.reqCount
, pb
->u
.ioParams
.actCount
);
183 if (sp
->state
== sClosed
) {
185 KERNEL_DEBUG(DBG_ADSP_READ
, 0x0E, pb
, sp
, pb
->ioc
, 0);
187 pb
->u
.ioParams
.actCount
= 0;
188 pb
->u
.ioParams
.eom
= 0;
191 adspioc_ack(0, (gbuf_t
*)pb
->ioc
, pb
->gref
);
197 } else if (pb
->ioc
) { /* if request not complete and this
198 * is an active ioctl, release user */
201 tmp
= gbuf_cont(pb
->mp
); /* detatch perhaps delayed data */
202 gbuf_cont(pb
->mp
) = 0;
203 if ((mp
= gbuf_copym(pb
->mp
))) { /* otherwise, duplicate user request */
204 KERNEL_DEBUG(DBG_ADSP_READ
, 0x0F, pb
, sp
, pb
->mp
, 0);
205 adspioc_ack(0, (gbuf_t
*)pb
->ioc
, pb
->gref
); /* release user */
206 pb
= (struct adspcmd
*)gbuf_rptr(mp
); /* get new parameter block */
209 gbuf_cont(pb
->mp
) = tmp
; /* reattach data */
210 pb
->qLink
= sp
->rpb
; /* requeue the duplicate at the head */
212 } else { /* there is no data left, but no space
213 * to duplicate the parameter block, so
214 * put what must be a non EOM message
215 * back on the current receive queue, and
218 KERNEL_DEBUG(DBG_ADSP_READ
, 0x10, pb
, sp
, pb
->mp
, 0);
223 pb
->ioResult
= errDSPQueueSize
;
224 adspioc_ack(ENOBUFS
, (gbuf_t
*)pb
->ioc
, pb
->gref
);
229 * The receive window has opened. If was previously closed, then we
230 * need to notify the other guy that we now have room to receive more
231 * data. But, in order to cut down on lots of small data packets,
232 * we'll wait until the recieve buffer is /14 empy before telling
233 * him that there's room in our receive buffer.
235 if (sp
->rbufFull
&& (CalcRecvWdw(sp
) > (sp
->rbuflen
>> 2))) {
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(CCBPtr
, struct adspcmd
*);
261 int CheckAttn(sp
, pb
) /* (CCBPtr sp) */
263 register struct adspcmd
*pb
;
268 dPrintf(D_M_ADSP
, D_L_TRACE
,
269 ("CheckAttn: sp=0x%x, pb=0x%x\n", (unsigned)sp
, (unsigned)pb
));
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, (gbuf_t
*)pb
->ioc
, pb
->gref
);
309 * --> sp stream pointer
310 * --> pb user request parameter block
313 * <-- actCount actual number of bytes read
314 * <-- eom one if end-of-message, zero otherwise
317 * errRefNum bad connection refnum
319 * errFwdReset read terminated by forward reset
320 * errAborted request aborted by Remove or Close call
322 int adspRead(sp
, pb
) /* (DSPPBPtr pb) */
324 register struct adspcmd
*pb
;
328 dPrintf(D_M_ADSP
, D_L_TRACE
,
329 ("adspRead: sp=0x%x, pb=0x%x\n", (unsigned)sp
, (unsigned)pb
));
331 KERNEL_DEBUG(DBG_ADSP_READ
, 0x12, sp
, pb
, sp
->state
, sp
->rData
);
334 pb
->ioResult
= errRefNum
;
339 * It's OK to read on a closed, or closing session
341 if (sp
->state
!= sOpen
&& sp
->state
!= sClosing
&& sp
->state
!= sClosed
) {
342 pb
->ioResult
= errState
;
345 if (sp
->rData
&& (sp
->rpb
== 0)) { /* if data, and no queue of pbs */
346 qAddToEnd((struct qlink
**)&sp
->rpb
, (struct qlink
*)pb
); /* deliver data to user directly */
348 } else if ((pb
->u
.ioParams
.reqCount
== 0) && (sp
->rpb
== 0)) {
351 adspioc_ack(0, (gbuf_t
*)pb
->ioc
, pb
->gref
);
355 if ((mp
= gbuf_copym(pb
->mp
))) { /* otherwise, duplicate user request */
356 adspioc_ack(0, (gbuf_t
*)pb
->ioc
, pb
->gref
); /* release user */
357 pb
= (struct adspcmd
*)gbuf_rptr(mp
); /* get new parameter block */
360 qAddToEnd((struct qlink
**)&sp
->rpb
, (struct qlink
*)pb
); /* and queue it for later */
362 pb
->ioResult
= errDSPQueueSize
;
368 CheckSend(sp
); /* If recv window opened, we might */
369 /* send an unsolicited ACK. */
378 * --> sp stream pointer
379 * --> pb user request parameter block
385 * errRefNum bad connection refnum
386 * errState connection is not in the right state
388 int adspReadAttention(sp
, pb
) /* (DSPPBPtr pb) */
390 register struct adspcmd
*pb
;
392 dPrintf(D_M_ADSP
, D_L_TRACE
,
393 ("adspReadAttention: sp=0x%x, pb=0x%x\n", (unsigned)sp
, (unsigned)pb
));
395 pb
->ioResult
= errRefNum
;
400 * It's OK to read on a closed, or closing session
402 if (sp
->state
!= sOpen
&& sp
->state
!= sClosing
&& sp
->state
!= sClosed
) {
403 pb
->ioResult
= errState
;
407 CheckAttn(sp
, pb
); /* Anything in the attention queue */
408 CheckReadQueue(sp
); /* check to see if receive window has opened */
410 CheckSend(sp
); /* If recv window opened, we might */
411 /* send an unsolicited ACK. */
414 } /* adspReadAttention */