]>
git.saurik.com Git - apple/xnu.git/blob - bsd/netat/adsp_Read.c
ca6cbf87442336b2c048ccd743eebd678f356ccf
2 * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
4 * @APPLE_LICENSE_OSREFERENCE_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
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
34 * From v01.17 08/22/90 mbs
35 * Modified for MP, 1996 by Tuyen Nguyen
36 * Modified, April 9, 1997 by Tuyen Nguyen for MacOSX.
39 #include <sys/errno.h>
40 #include <sys/types.h>
41 #include <sys/param.h>
42 #include <machine/spl.h>
43 #include <sys/systm.h>
44 #include <sys/kernel.h>
46 #include <sys/filedesc.h>
47 #include <sys/fcntl.h>
49 #include <sys/socket.h>
50 #include <sys/socketvar.h>
52 #include <netat/sysglue.h>
53 #include <netat/appletalk.h>
54 #include <netat/at_pcb.h>
55 #include <netat/debug.h>
56 #include <netat/adsp.h>
57 #include <netat/adsp_internal.h>
62 * Checks to see if there is any data in the receive queue. If there
63 * is data, a pb and the data are queued to the user.
67 extern int adsp_check
;
69 int CheckReadQueue(sp
) /* (CCBPtr sp) */
72 register struct adspcmd
*pb
;
80 dPrintf(D_M_ADSP
, D_L_TRACE
, ("CheckReadQueue: sp=0x%x\n", (unsigned)sp
));
81 KERNEL_DEBUG(DBG_ADSP_READ
, 0, sp
, sp
->rbuf_mb
, sp
->rpb
, sp
->delay
);
82 trace_mbufs(D_M_ADSP_LOW
, " bCQR m", sp
->rbuf_mb
);
83 ATDISABLE(s
, sp
->lock
);
85 while (sp
->rData
&& (pb
= sp
->rpb
)) { /* have data */
86 dPrintf(D_M_ADSP
, D_L_TRACE
,
87 (" pb=0x%x, gref=0x%x, ioc=0x%x, reqCount=%d (have data)\n",
88 pb
, pb
->gref
, pb
->ioc
, pb
->u
.ioParams
.reqCount
));
89 KERNEL_DEBUG(DBG_ADSP_READ
, 1, pb
, pb
->gref
, pb
->ioc
, pb
->u
.ioParams
.reqCount
);
90 if (pb
->u
.ioParams
.reqCount
== 0) {
94 KERNEL_DEBUG(DBG_ADSP_READ
, 2, pb
, pb
->gref
, pb
->ioc
, 0);
95 adspioc_ack(0, pb
->ioc
, pb
->gref
);
97 KERNEL_DEBUG(DBG_ADSP_READ
, 3, pb
, pb
->gref
, 0, 0);
103 /* take the first packet off of sp->rbuf_mb or sp->crbuf_mb */
104 if (mp
= sp
->rbuf_mb
) { /* Get header for oldest data */
105 KERNEL_DEBUG(DBG_ADSP_READ
, 4, pb
, mp
, gbuf_msgsize(mp
), gbuf_next(mp
));
106 sp
->rbuf_mb
= gbuf_next(mp
);
109 } else if (mp
= sp
->crbuf_mb
) {
110 KERNEL_DEBUG(DBG_ADSP_READ
, 5, pb
, mp
, gbuf_msgsize(mp
), gbuf_next(mp
));
115 /* Get the first (reqCount-actCount) bytes and tack them onto
116 the end of pb->mp. If eom is set, put the remainder of the
117 data onto the front of sp->rbuf_mb, otherwise sp->crbuf_mb. */
118 cnt
= gbuf_msgsize(mp
); /* # of data bytes in it. */
119 if (cnt
> (unsigned short)(pb
->u
.ioParams
.reqCount
- pb
->u
.ioParams
.actCount
)) {
120 cnt
= pb
->u
.ioParams
.reqCount
- pb
->u
.ioParams
.actCount
;
121 /* m_split returns the tail */
122 if (!(tmp
= (gbuf_t
*)m_split(mp
, cnt
, M_DONTWAIT
))) {
127 gbuf_next(tmp
) = sp
->rbuf_mb
;
134 pb
->u
.ioParams
.actCount
+= cnt
;
135 gbuf_linkb(pb
->mp
, mp
);
138 pb
->u
.ioParams
.eom
= eom
;
140 * Now clean up receive buffer to remove all of the data
143 if ((sp
->rbuf_mb
== 0) &&
144 (sp
->crbuf_mb
== 0)) /* no more data blocks */
147 * If we've filled the parameter block, unlink it from read
148 * queue and complete it. We also need to do this if the connection
149 * is closed && there is no more stuff to read.
151 if (eom
|| (pb
->u
.ioParams
.actCount
>= pb
->u
.ioParams
.reqCount
) ||
152 ((sp
->state
== sClosed
) && (!sp
->rData
)) ) {
153 /* end of message, message is full, connection
154 * is closed and all data has been delivered,
155 * or we are not to "delay" data delivery.
158 sp
->rpb
= pb
->qLink
; /* dequeue request */
159 if (pb
->ioc
) { /* data to be delivered at the time of the */
160 mp
= gbuf_cont(pb
->mp
); /* ioctl call */
161 gbuf_cont(pb
->mp
) = 0;
162 gref
= (gref_t
*)pb
->gref
;
163 adspioc_ack(0, pb
->ioc
, pb
->gref
);
164 dPrintf(D_M_ADSP
, D_L_TRACE
, (" (pb->ioc) mp=%x\n", mp
));
165 KERNEL_DEBUG(DBG_ADSP_READ
, 0x0A, pb
, mp
,
166 gbuf_next(mp
), gbuf_cont(mp
));
168 dPrintf(D_M_ADSP
, D_L_TRACE
,
169 (" (data) size req=%d\n", pb
->u
.ioParams
.actCount
));
170 KERNEL_DEBUG(DBG_ADSP_READ
, 0x0B, pb
, pb
->ioc
,
171 pb
->u
.ioParams
.reqCount
, pb
->u
.ioParams
.actCount
);
172 } else { /* complete an queued async request */
173 KERNEL_DEBUG(DBG_ADSP_READ
, 0x0C, pb
, sp
,
174 pb
->u
.ioParams
.actCount
, sp
->delay
);
180 if (pb
= sp
->rpb
) { /* if there is an outstanding request */
181 dPrintf(D_M_ADSP
, D_L_TRACE
,
182 (" pb=0x%x, ioc=0x%x, reqCount=%d (no more data)\n",
183 pb
, pb
->ioc
, pb
->u
.ioParams
.reqCount
));
184 KERNEL_DEBUG(DBG_ADSP_READ
, 0x0D, pb
, pb
->ioc
,
185 pb
->u
.ioParams
.reqCount
, pb
->u
.ioParams
.actCount
);
187 if (sp
->state
== sClosed
) {
189 KERNEL_DEBUG(DBG_ADSP_READ
, 0x0E, pb
, sp
, pb
->ioc
, 0);
191 pb
->u
.ioParams
.actCount
= 0;
192 pb
->u
.ioParams
.eom
= 0;
195 adspioc_ack(0, pb
->ioc
, pb
->gref
);
201 } else if (pb
->ioc
) { /* if request not complete and this
202 * is an active ioctl, release user */
205 tmp
= gbuf_cont(pb
->mp
); /* detatch perhaps delayed data */
206 gbuf_cont(pb
->mp
) = 0;
207 if (mp
= gbuf_copym(pb
->mp
)) { /* otherwise, duplicate user request */
208 KERNEL_DEBUG(DBG_ADSP_READ
, 0x0F, pb
, sp
, pb
->mp
, 0);
209 adspioc_ack(0, pb
->ioc
, pb
->gref
); /* release user */
210 pb
= (struct adspcmd
*)gbuf_rptr(mp
); /* get new parameter block */
213 gbuf_cont(pb
->mp
) = tmp
; /* reattach data */
214 pb
->qLink
= sp
->rpb
; /* requeue the duplicate at the head */
216 } else { /* there is no data left, but no space
217 * to duplicate the parameter block, so
218 * put what must be a non EOM message
219 * back on the current receive queue, and
222 KERNEL_DEBUG(DBG_ADSP_READ
, 0x10, pb
, sp
, pb
->mp
, 0);
227 pb
->ioResult
= errDSPQueueSize
;
228 adspioc_ack(ENOBUFS
, pb
->ioc
, pb
->gref
);
233 * The receive window has opened. If was previously closed, then we
234 * need to notify the other guy that we now have room to receive more
235 * data. But, in order to cut down on lots of small data packets,
236 * we'll wait until the recieve buffer is /14 empy before telling
237 * him that there's room in our receive buffer.
239 if (sp
->rbufFull
&& (CalcRecvWdw(sp
) > (sp
->rbuflen
>> 2))) {
244 ATENABLE(s
, sp
->lock
);
246 KERNEL_DEBUG(DBG_ADSP_READ
, 0x11, sp
, 0, 0, 0);
247 trace_mbufs(D_M_ADSP_LOW
, " eCQR m", sp
->rbuf_mb
);
254 * Checks to see if there is any attention data and passes the data back
255 * in the passed in pb.
264 int CheckAttn(sp
, pb
) /* (CCBPtr sp) */
266 register struct adspcmd
*pb
;
272 dPrintf(D_M_ADSP
, D_L_TRACE
,
273 ("CheckAttn: sp=0x%x, pb=0x%x\n", (unsigned)sp
, (unsigned)pb
));
275 ATDISABLE(s
, sp
->lock
);
276 if (mp
= sp
->attn_mb
) {
279 * Deliver the attention data to the user.
281 gref
= (gref_t
*)pb
->gref
;
282 pb
->u
.attnParams
.attnSize
= sp
->attnSize
;
283 pb
->u
.attnParams
.attnCode
= sp
->attnCode
;
288 sp
->userFlags
&= ~eAttention
;
290 * Now clean up receive buffer to remove all of the data
299 pb
->u
.attnParams
.attnSize
= 0;
300 pb
->u
.attnParams
.attnCode
= 0;
301 pb
->ioResult
= 1; /* not done */
303 adspioc_ack(0, pb
->ioc
, pb
->gref
);
307 ATENABLE(s
, sp
->lock
);
315 * --> sp stream pointer
316 * --> pb user request parameter block
319 * <-- actCount actual number of bytes read
320 * <-- eom one if end-of-message, zero otherwise
323 * errRefNum bad connection refnum
325 * errFwdReset read terminated by forward reset
326 * errAborted request aborted by Remove or Close call
328 int adspRead(sp
, pb
) /* (DSPPBPtr pb) */
330 register struct adspcmd
*pb
;
335 dPrintf(D_M_ADSP
, D_L_TRACE
,
336 ("adspRead: sp=0x%x, pb=0x%x\n", (unsigned)sp
, (unsigned)pb
));
338 KERNEL_DEBUG(DBG_ADSP_READ
, 0x12, sp
, pb
, sp
->state
, sp
->rData
);
341 pb
->ioResult
= errRefNum
;
346 * It's OK to read on a closed, or closing session
348 ATDISABLE(s
, sp
->lock
);
349 if (sp
->state
!= sOpen
&& sp
->state
!= sClosing
&& sp
->state
!= sClosed
) {
350 ATENABLE(s
, sp
->lock
);
351 pb
->ioResult
= errState
;
354 if (sp
->rData
&& (sp
->rpb
== 0)) { /* if data, and no queue of pbs */
355 qAddToEnd(&sp
->rpb
, pb
); /* deliver data to user directly */
356 ATENABLE(s
, sp
->lock
);
358 } else if ((pb
->u
.ioParams
.reqCount
== 0) && (sp
->rpb
== 0)) {
360 ATENABLE(s
, sp
->lock
);
362 adspioc_ack(0, pb
->ioc
, pb
->gref
);
366 if (mp
= gbuf_copym(pb
->mp
)) { /* otherwise, duplicate user request */
367 adspioc_ack(0, pb
->ioc
, pb
->gref
); /* release user */
368 pb
= (struct adspcmd
*)gbuf_rptr(mp
); /* get new parameter block */
371 qAddToEnd(&sp
->rpb
, pb
); /* and queue it for later */
372 ATENABLE(s
, sp
->lock
);
374 ATENABLE(s
, sp
->lock
);
375 pb
->ioResult
= errDSPQueueSize
;
381 CheckSend(sp
); /* If recv window opened, we might */
382 /* send an unsolicited ACK. */
391 * --> sp stream pointer
392 * --> pb user request parameter block
398 * errRefNum bad connection refnum
399 * errState connection is not in the right state
401 int adspReadAttention(sp
, pb
) /* (DSPPBPtr pb) */
403 register struct adspcmd
*pb
;
405 dPrintf(D_M_ADSP
, D_L_TRACE
,
406 ("adspReadAttention: sp=0x%x, pb=0x%x\n", (unsigned)sp
, (unsigned)pb
));
408 pb
->ioResult
= errRefNum
;
413 * It's OK to read on a closed, or closing session
415 if (sp
->state
!= sOpen
&& sp
->state
!= sClosing
&& sp
->state
!= sClosed
) {
416 pb
->ioResult
= errState
;
420 CheckAttn(sp
, pb
); /* Anything in the attention queue */
421 CheckReadQueue(sp
); /* check to see if receive window has opened */
423 CheckSend(sp
); /* If recv window opened, we might */
424 /* send an unsolicited ACK. */
427 } /* adspReadAttention */