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