]> git.saurik.com Git - apple/xnu.git/blame - bsd/netat/adsp_Read.c
xnu-792.21.3.tar.gz
[apple/xnu.git] / bsd / netat / adsp_Read.c
CommitLineData
1c79356b 1/*
5d5c5d0d
A
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
8f6c56a5 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 5 *
8f6c56a5
A
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.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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
8ad349bb 24 * limitations under the License.
8f6c56a5
A
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
27 */
28/*
29 *
30 * dspRead.c
31 *
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.
35 */
36
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>
43#include <sys/proc.h>
44#include <sys/filedesc.h>
45#include <sys/fcntl.h>
46#include <sys/mbuf.h>
47#include <sys/socket.h>
48#include <sys/socketvar.h>
49
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>
56
57/*
58 * CheckReadQueue
59 *
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.
62 *
63 *
64 */
65extern int adsp_check;
66
67int CheckReadQueue(sp) /* (CCBPtr sp) */
68 register CCBPtr sp;
69{
70 register struct adspcmd *pb;
21362eb3 71 int s;
1c79356b
A
72 unsigned short cnt;
73 char eom = 0;
74 register gbuf_t *mp;
75 register gbuf_t *tmp;
76 gref_t *gref;
77
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);
21362eb3 81 ATDISABLE(s, sp->lock);
1c79356b
A
82
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) {
89 pb->ioResult = 0;
90 sp->rpb = pb->qLink;
91 if (pb->ioc) {
92 KERNEL_DEBUG(DBG_ADSP_READ, 2, pb, pb->gref, pb->ioc, 0);
93 adspioc_ack(0, pb->ioc, pb->gref);
94 } else {
95 KERNEL_DEBUG(DBG_ADSP_READ, 3, pb, pb->gref, 0, 0);
96 completepb(sp, pb);
97 }
98 continue;
99 }
100
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);
105 gbuf_next(mp) = 0;
106 eom = 1;
107 } else if (mp = sp->crbuf_mb) {
108 KERNEL_DEBUG(DBG_ADSP_READ, 5, pb, mp, gbuf_msgsize(mp), gbuf_next(mp));
109 sp->crbuf_mb = 0;
110 eom = 0;
111 }
112
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))) {
121 cnt = 0;
122 tmp = mp;
123 }
124 if (eom) {
125 gbuf_next(tmp) = sp->rbuf_mb;
126 sp->rbuf_mb = tmp;
127 eom = 0;
128 } else
129 sp->crbuf_mb = tmp;
130 }
131 if (cnt) {
132 pb->u.ioParams.actCount += cnt;
133 gbuf_linkb(pb->mp, mp);
134 }
135
136 pb->u.ioParams.eom = eom;
137 /*
138 * Now clean up receive buffer to remove all of the data
139 * we just copied
140 */
141 if ((sp->rbuf_mb == 0) &&
142 (sp->crbuf_mb == 0)) /* no more data blocks */
143 sp->rData = 0;
144 /*
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.
148 */
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.
154 */
155 pb->ioResult = 0;
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));
165 SndMsgUp(gref, 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);
173 completepb(sp, pb);
174 }
175 }
176 } /* while */
177
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);
184
185 if (sp->state == sClosed) {
186 while (pb) {
187 KERNEL_DEBUG(DBG_ADSP_READ, 0x0E, pb, sp, pb->ioc, 0);
188 pb->ioResult = 0;
189 pb->u.ioParams.actCount = 0;
190 pb->u.ioParams.eom = 0;
191 sp->rpb = pb->qLink;
192 if (pb->ioc) {
193 adspioc_ack(0, pb->ioc, pb->gref);
194 } else {
195 completepb(sp, pb);
196 }
197 pb = sp->rpb;
198 }
199 } else if (pb->ioc) { /* if request not complete and this
200 * is an active ioctl, release user */
201 sp->rpb = pb->qLink;
202 pb->ioResult = 1;
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 */
209 pb->ioc = 0;
210 pb->mp = mp;
211 gbuf_cont(pb->mp) = tmp; /* reattach data */
212 pb->qLink = sp->rpb; /* requeue the duplicate at the head */
213 sp->rpb = pb;
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
218 * error out the user
219 */
220 KERNEL_DEBUG(DBG_ADSP_READ, 0x10, pb, sp, pb->mp, 0);
221 if (tmp) {
222 sp->crbuf_mb = tmp;
223 sp->rData = 1;
224 }
225 pb->ioResult = errDSPQueueSize;
226 adspioc_ack(ENOBUFS, pb->ioc, pb->gref);
227 }
228 }
229 }
230 /*
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.
236 */
237 if (sp->rbufFull && (CalcRecvWdw(sp) > (sp->rbuflen >> 2))) {
238 sp->rbufFull = 0;
239 sp->sendDataAck = 1;
240 sp->callSend = 1;
241 }
21362eb3 242 ATENABLE(s, sp->lock);
1c79356b
A
243
244 KERNEL_DEBUG(DBG_ADSP_READ, 0x11, sp, 0, 0, 0);
245 trace_mbufs(D_M_ADSP_LOW, " eCQR m", sp->rbuf_mb);
246 return 0;
247}
248
249/*
250 * CheckAttn
251 *
252 * Checks to see if there is any attention data and passes the data back
253 * in the passed in pb.
254 *
255 * INPUTS:
256 * sp
257 * pb
258 *
259 * OUTPUTS:
260 *
261 */
262int CheckAttn(sp, pb) /* (CCBPtr sp) */
263 register CCBPtr sp;
264 register struct adspcmd *pb;
265{
21362eb3 266 int s;
1c79356b
A
267 gbuf_t *mp;
268 gref_t *gref;
269
270 dPrintf(D_M_ADSP, D_L_TRACE,
271 ("CheckAttn: sp=0x%x, pb=0x%x\n", (unsigned)sp, (unsigned)pb));
272
21362eb3 273 ATDISABLE(s, sp->lock);
1c79356b
A
274 if (mp = sp->attn_mb) {
275
276 /*
277 * Deliver the attention data to the user.
278 */
279 gref = (gref_t *)pb->gref;
280 pb->u.attnParams.attnSize = sp->attnSize;
281 pb->u.attnParams.attnCode = sp->attnCode;
282 if (!sp->attnSize) {
283 gbuf_freem(mp);
284 mp = 0;
285 }
286 sp->userFlags &= ~eAttention;
287 /*
288 * Now clean up receive buffer to remove all of the data
289 * we just copied
290 */
291 sp->attn_mb = 0;
292 pb->ioResult = 0;
293 } else {
294 /*
295 * No data...
296 */
297 pb->u.attnParams.attnSize = 0;
298 pb->u.attnParams.attnCode = 0;
299 pb->ioResult = 1; /* not done */
300 }
301 adspioc_ack(0, pb->ioc, pb->gref);
302 if (mp) {
303 SndMsgUp(gref, mp);
304 }
21362eb3 305 ATENABLE(s, sp->lock);
1c79356b
A
306 return 0;
307}
308
309/*
310 * adspRead
311 *
312 * INPUTS:
313 * --> sp stream pointer
314 * --> pb user request parameter block
315 *
316 * OUTPUTS:
317 * <-- actCount actual number of bytes read
318 * <-- eom one if end-of-message, zero otherwise
319 *
320 * ERRORS:
321 * errRefNum bad connection refnum
322 * errState
323 * errFwdReset read terminated by forward reset
324 * errAborted request aborted by Remove or Close call
325 */
326int adspRead(sp, pb) /* (DSPPBPtr pb) */
327 register CCBPtr sp;
328 register struct adspcmd *pb;
329{
330 register gbuf_t *mp;
21362eb3 331 int s;
1c79356b
A
332
333 dPrintf(D_M_ADSP, D_L_TRACE,
334 ("adspRead: sp=0x%x, pb=0x%x\n", (unsigned)sp, (unsigned)pb));
335
336 KERNEL_DEBUG(DBG_ADSP_READ, 0x12, sp, pb, sp->state, sp->rData);
337
338 if (sp == 0) {
339 pb->ioResult = errRefNum;
340 return EINVAL;
341 }
342
343 /*
344 * It's OK to read on a closed, or closing session
345 */
21362eb3 346 ATDISABLE(s, sp->lock);
1c79356b 347 if (sp->state != sOpen && sp->state != sClosing && sp->state != sClosed) {
21362eb3 348 ATENABLE(s, sp->lock);
1c79356b
A
349 pb->ioResult = errState;
350 return EINVAL;
351 }
352 if (sp->rData && (sp->rpb == 0)) { /* if data, and no queue of pbs */
353 qAddToEnd(&sp->rpb, pb); /* deliver data to user directly */
21362eb3 354 ATENABLE(s, sp->lock);
1c79356b
A
355 CheckReadQueue(sp);
356 } else if ((pb->u.ioParams.reqCount == 0) && (sp->rpb == 0)) {
357 /* empty read */
21362eb3 358 ATENABLE(s, sp->lock);
1c79356b
A
359 pb->ioResult = 0;
360 adspioc_ack(0, pb->ioc, pb->gref);
361 return 0;
362 } else {
363 pb->ioResult = 1;
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 */
367 pb->ioc = 0;
368 pb->mp = mp;
369 qAddToEnd(&sp->rpb, pb); /* and queue it for later */
21362eb3 370 ATENABLE(s, sp->lock);
1c79356b 371 } else {
21362eb3 372 ATENABLE(s, sp->lock);
1c79356b
A
373 pb->ioResult = errDSPQueueSize;
374 return ENOBUFS;
375 }
376 }
377
378 if (sp->callSend) {
379 CheckSend(sp); /* If recv window opened, we might */
380 /* send an unsolicited ACK. */
381 }
382 return 0;
383}
384
385/*
386 * dspReadAttention
387 *
388 * INPUTS:
389 * --> sp stream pointer
390 * --> pb user request parameter block
391 *
392 * OUTPUTS:
393 * <-- NONE
394 *
395 * ERRORS:
396 * errRefNum bad connection refnum
397 * errState connection is not in the right state
398 */
399int adspReadAttention(sp, pb) /* (DSPPBPtr pb) */
400 register CCBPtr sp;
401 register struct adspcmd *pb;
402{
403 dPrintf(D_M_ADSP, D_L_TRACE,
404 ("adspReadAttention: sp=0x%x, pb=0x%x\n", (unsigned)sp, (unsigned)pb));
405 if (sp == 0) {
406 pb->ioResult = errRefNum;
407 return EINVAL;
408 }
409
410 /*
411 * It's OK to read on a closed, or closing session
412 */
413 if (sp->state != sOpen && sp->state != sClosing && sp->state != sClosed) {
414 pb->ioResult = errState;
415 return EINVAL;
416 }
417
418 CheckAttn(sp, pb); /* Anything in the attention queue */
419 CheckReadQueue(sp); /* check to see if receive window has opened */
420 if (sp->callSend) {
421 CheckSend(sp); /* If recv window opened, we might */
422 /* send an unsolicited ACK. */
423 }
424 return 0;
425} /* adspReadAttention */