]>
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
;
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
);
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) {
86 KERNEL_DEBUG(DBG_ADSP_READ
, 2, pb
, pb
->gref
, pb
->ioc
, 0);
87 adspioc_ack(0, pb
->ioc
, pb
->gref
);
89 KERNEL_DEBUG(DBG_ADSP_READ
, 3, pb
, pb
->gref
, 0, 0);
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
);
101 } else if (mp
= sp
->crbuf_mb
) {
102 KERNEL_DEBUG(DBG_ADSP_READ
, 5, pb
, mp
, gbuf_msgsize(mp
), gbuf_next(mp
));
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
))) {
119 gbuf_next(tmp
) = sp
->rbuf_mb
;
126 pb
->u
.ioParams
.actCount
+= cnt
;
127 gbuf_linkb(pb
->mp
, mp
);
130 pb
->u
.ioParams
.eom
= eom
;
132 * Now clean up receive buffer to remove all of the data
135 if ((sp
->rbuf_mb
== 0) &&
136 (sp
->crbuf_mb
== 0)) /* no more data blocks */
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.
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.
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
));
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
);
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
);
179 if (sp
->state
== sClosed
) {
181 KERNEL_DEBUG(DBG_ADSP_READ
, 0x0E, pb
, sp
, pb
->ioc
, 0);
183 pb
->u
.ioParams
.actCount
= 0;
184 pb
->u
.ioParams
.eom
= 0;
187 adspioc_ack(0, pb
->ioc
, pb
->gref
);
193 } else if (pb
->ioc
) { /* if request not complete and this
194 * is an active ioctl, release user */
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 */
205 gbuf_cont(pb
->mp
) = tmp
; /* reattach data */
206 pb
->qLink
= sp
->rpb
; /* requeue the duplicate at the head */
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
214 KERNEL_DEBUG(DBG_ADSP_READ
, 0x10, pb
, sp
, pb
->mp
, 0);
219 pb
->ioResult
= errDSPQueueSize
;
220 adspioc_ack(ENOBUFS
, pb
->ioc
, pb
->gref
);
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.
231 if (sp
->rbufFull
&& (CalcRecvWdw(sp
) > (sp
->rbuflen
>> 2))) {
236 ATENABLE(s
, sp
->lock
);
238 KERNEL_DEBUG(DBG_ADSP_READ
, 0x11, sp
, 0, 0, 0);
239 trace_mbufs(D_M_ADSP_LOW
, " eCQR m", sp
->rbuf_mb
);
246 * Checks to see if there is any attention data and passes the data back
247 * in the passed in pb.
256 int CheckAttn(sp
, pb
) /* (CCBPtr sp) */
258 register struct adspcmd
*pb
;
264 dPrintf(D_M_ADSP
, D_L_TRACE
,
265 ("CheckAttn: sp=0x%x, pb=0x%x\n", (unsigned)sp
, (unsigned)pb
));
267 ATDISABLE(s
, sp
->lock
);
268 if (mp
= sp
->attn_mb
) {
271 * Deliver the attention data to the user.
273 gref
= (gref_t
*)pb
->gref
;
274 pb
->u
.attnParams
.attnSize
= sp
->attnSize
;
275 pb
->u
.attnParams
.attnCode
= sp
->attnCode
;
280 sp
->userFlags
&= ~eAttention
;
282 * Now clean up receive buffer to remove all of the data
291 pb
->u
.attnParams
.attnSize
= 0;
292 pb
->u
.attnParams
.attnCode
= 0;
293 pb
->ioResult
= 1; /* not done */
295 adspioc_ack(0, pb
->ioc
, pb
->gref
);
299 ATENABLE(s
, sp
->lock
);
307 * --> sp stream pointer
308 * --> pb user request parameter block
311 * <-- actCount actual number of bytes read
312 * <-- eom one if end-of-message, zero otherwise
315 * errRefNum bad connection refnum
317 * errFwdReset read terminated by forward reset
318 * errAborted request aborted by Remove or Close call
320 int adspRead(sp
, pb
) /* (DSPPBPtr pb) */
322 register struct adspcmd
*pb
;
327 dPrintf(D_M_ADSP
, D_L_TRACE
,
328 ("adspRead: sp=0x%x, pb=0x%x\n", (unsigned)sp
, (unsigned)pb
));
330 KERNEL_DEBUG(DBG_ADSP_READ
, 0x12, sp
, pb
, sp
->state
, sp
->rData
);
333 pb
->ioResult
= errRefNum
;
338 * It's OK to read on a closed, or closing session
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
;
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
);
350 } else if ((pb
->u
.ioParams
.reqCount
== 0) && (sp
->rpb
== 0)) {
352 ATENABLE(s
, sp
->lock
);
354 adspioc_ack(0, pb
->ioc
, pb
->gref
);
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 */
363 qAddToEnd(&sp
->rpb
, pb
); /* and queue it for later */
364 ATENABLE(s
, sp
->lock
);
366 ATENABLE(s
, sp
->lock
);
367 pb
->ioResult
= errDSPQueueSize
;
373 CheckSend(sp
); /* If recv window opened, we might */
374 /* send an unsolicited ACK. */
383 * --> sp stream pointer
384 * --> pb user request parameter block
390 * errRefNum bad connection refnum
391 * errState connection is not in the right state
393 int adspReadAttention(sp
, pb
) /* (DSPPBPtr pb) */
395 register struct adspcmd
*pb
;
397 dPrintf(D_M_ADSP
, D_L_TRACE
,
398 ("adspReadAttention: sp=0x%x, pb=0x%x\n", (unsigned)sp
, (unsigned)pb
));
400 pb
->ioResult
= errRefNum
;
405 * It's OK to read on a closed, or closing session
407 if (sp
->state
!= sOpen
&& sp
->state
!= sClosing
&& sp
->state
!= sClosed
) {
408 pb
->ioResult
= errState
;
412 CheckAttn(sp
, pb
); /* Anything in the attention queue */
413 CheckReadQueue(sp
); /* check to see if receive window has opened */
415 CheckSend(sp
); /* If recv window opened, we might */
416 /* send an unsolicited ACK. */
419 } /* adspReadAttention */