]> git.saurik.com Git - apple/xnu.git/blame - bsd/netat/adsp_Read.c
xnu-792.6.56.tar.gz
[apple/xnu.git] / bsd / netat / adsp_Read.c
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
ff6e181a
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. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
1c79356b 12 *
ff6e181a
A
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
1c79356b
A
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
ff6e181a
A
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
1c79356b
A
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23/*
24 *
25 * dspRead.c
26 *
27 * From v01.17 08/22/90 mbs
28 * Modified for MP, 1996 by Tuyen Nguyen
29 * Modified, April 9, 1997 by Tuyen Nguyen for MacOSX.
30 */
31
32#include <sys/errno.h>
33#include <sys/types.h>
34#include <sys/param.h>
35#include <machine/spl.h>
36#include <sys/systm.h>
37#include <sys/kernel.h>
38#include <sys/proc.h>
39#include <sys/filedesc.h>
40#include <sys/fcntl.h>
41#include <sys/mbuf.h>
42#include <sys/socket.h>
43#include <sys/socketvar.h>
44
45#include <netat/sysglue.h>
46#include <netat/appletalk.h>
47#include <netat/at_pcb.h>
48#include <netat/debug.h>
49#include <netat/adsp.h>
50#include <netat/adsp_internal.h>
51
52/*
53 * CheckReadQueue
54 *
55 * Checks to see if there is any data in the receive queue. If there
56 * is data, a pb and the data are queued to the user.
57 *
58 *
59 */
60extern int adsp_check;
61
62int CheckReadQueue(sp) /* (CCBPtr sp) */
63 register CCBPtr sp;
64{
65 register struct adspcmd *pb;
66 int s;
67 unsigned short cnt;
68 char eom = 0;
69 register gbuf_t *mp;
70 register gbuf_t *tmp;
71 gref_t *gref;
72
73 dPrintf(D_M_ADSP, D_L_TRACE, ("CheckReadQueue: sp=0x%x\n", (unsigned)sp));
74 KERNEL_DEBUG(DBG_ADSP_READ, 0, sp, sp->rbuf_mb, sp->rpb, sp->delay);
75 trace_mbufs(D_M_ADSP_LOW, " bCQR m", sp->rbuf_mb);
76 ATDISABLE(s, sp->lock);
77
78 while (sp->rData && (pb = sp->rpb)) { /* have data */
79 dPrintf(D_M_ADSP, D_L_TRACE,
80 (" pb=0x%x, gref=0x%x, ioc=0x%x, reqCount=%d (have data)\n",
81 pb, pb->gref, pb->ioc, pb->u.ioParams.reqCount));
82 KERNEL_DEBUG(DBG_ADSP_READ, 1, pb, pb->gref, pb->ioc, pb->u.ioParams.reqCount);
83 if (pb->u.ioParams.reqCount == 0) {
84 pb->ioResult = 0;
85 sp->rpb = pb->qLink;
86 if (pb->ioc) {
87 KERNEL_DEBUG(DBG_ADSP_READ, 2, pb, pb->gref, pb->ioc, 0);
88 adspioc_ack(0, pb->ioc, pb->gref);
89 } else {
90 KERNEL_DEBUG(DBG_ADSP_READ, 3, pb, pb->gref, 0, 0);
91 completepb(sp, pb);
92 }
93 continue;
94 }
95
96 /* take the first packet off of sp->rbuf_mb or sp->crbuf_mb */
97 if (mp = sp->rbuf_mb) { /* Get header for oldest data */
98 KERNEL_DEBUG(DBG_ADSP_READ, 4, pb, mp, gbuf_msgsize(mp), gbuf_next(mp));
99 sp->rbuf_mb = gbuf_next(mp);
100 gbuf_next(mp) = 0;
101 eom = 1;
102 } else if (mp = sp->crbuf_mb) {
103 KERNEL_DEBUG(DBG_ADSP_READ, 5, pb, mp, gbuf_msgsize(mp), gbuf_next(mp));
104 sp->crbuf_mb = 0;
105 eom = 0;
106 }
107
108 /* Get the first (reqCount-actCount) bytes and tack them onto
109 the end of pb->mp. If eom is set, put the remainder of the
110 data onto the front of sp->rbuf_mb, otherwise sp->crbuf_mb. */
111 cnt = gbuf_msgsize(mp); /* # of data bytes in it. */
112 if (cnt > (unsigned short)(pb->u.ioParams.reqCount - pb->u.ioParams.actCount)) {
113 cnt = pb->u.ioParams.reqCount - pb->u.ioParams.actCount;
114 /* m_split returns the tail */
115 if (!(tmp = (gbuf_t *)m_split(mp, cnt, M_DONTWAIT))) {
116 cnt = 0;
117 tmp = mp;
118 }
119 if (eom) {
120 gbuf_next(tmp) = sp->rbuf_mb;
121 sp->rbuf_mb = tmp;
122 eom = 0;
123 } else
124 sp->crbuf_mb = tmp;
125 }
126 if (cnt) {
127 pb->u.ioParams.actCount += cnt;
128 gbuf_linkb(pb->mp, mp);
129 }
130
131 pb->u.ioParams.eom = eom;
132 /*
133 * Now clean up receive buffer to remove all of the data
134 * we just copied
135 */
136 if ((sp->rbuf_mb == 0) &&
137 (sp->crbuf_mb == 0)) /* no more data blocks */
138 sp->rData = 0;
139 /*
140 * If we've filled the parameter block, unlink it from read
141 * queue and complete it. We also need to do this if the connection
142 * is closed && there is no more stuff to read.
143 */
144 if (eom || (pb->u.ioParams.actCount >= pb->u.ioParams.reqCount) ||
145 ((sp->state == sClosed) && (!sp->rData)) ) {
146 /* end of message, message is full, connection
147 * is closed and all data has been delivered,
148 * or we are not to "delay" data delivery.
149 */
150 pb->ioResult = 0;
151 sp->rpb = pb->qLink; /* dequeue request */
152 if (pb->ioc) { /* data to be delivered at the time of the */
153 mp = gbuf_cont(pb->mp); /* ioctl call */
154 gbuf_cont(pb->mp) = 0;
155 gref = (gref_t *)pb->gref;
156 adspioc_ack(0, pb->ioc, pb->gref);
157 dPrintf(D_M_ADSP, D_L_TRACE, (" (pb->ioc) mp=%x\n", mp));
158 KERNEL_DEBUG(DBG_ADSP_READ, 0x0A, pb, mp,
159 gbuf_next(mp), gbuf_cont(mp));
160 SndMsgUp(gref, mp);
161 dPrintf(D_M_ADSP, D_L_TRACE,
162 (" (data) size req=%d\n", pb->u.ioParams.actCount));
163 KERNEL_DEBUG(DBG_ADSP_READ, 0x0B, pb, pb->ioc,
164 pb->u.ioParams.reqCount, pb->u.ioParams.actCount);
165 } else { /* complete an queued async request */
166 KERNEL_DEBUG(DBG_ADSP_READ, 0x0C, pb, sp,
167 pb->u.ioParams.actCount, sp->delay);
168 completepb(sp, pb);
169 }
170 }
171 } /* while */
172
173 if (pb = sp->rpb) { /* if there is an outstanding request */
174 dPrintf(D_M_ADSP, D_L_TRACE,
175 (" pb=0x%x, ioc=0x%x, reqCount=%d (no more data)\n",
176 pb, pb->ioc, pb->u.ioParams.reqCount));
177 KERNEL_DEBUG(DBG_ADSP_READ, 0x0D, pb, pb->ioc,
178 pb->u.ioParams.reqCount, pb->u.ioParams.actCount);
179
180 if (sp->state == sClosed) {
181 while (pb) {
182 KERNEL_DEBUG(DBG_ADSP_READ, 0x0E, pb, sp, pb->ioc, 0);
183 pb->ioResult = 0;
184 pb->u.ioParams.actCount = 0;
185 pb->u.ioParams.eom = 0;
186 sp->rpb = pb->qLink;
187 if (pb->ioc) {
188 adspioc_ack(0, pb->ioc, pb->gref);
189 } else {
190 completepb(sp, pb);
191 }
192 pb = sp->rpb;
193 }
194 } else if (pb->ioc) { /* if request not complete and this
195 * is an active ioctl, release user */
196 sp->rpb = pb->qLink;
197 pb->ioResult = 1;
198 tmp = gbuf_cont(pb->mp); /* detatch perhaps delayed data */
199 gbuf_cont(pb->mp) = 0;
200 if (mp = gbuf_copym(pb->mp)) { /* otherwise, duplicate user request */
201 KERNEL_DEBUG(DBG_ADSP_READ, 0x0F, pb, sp, pb->mp, 0);
202 adspioc_ack(0, pb->ioc, pb->gref); /* release user */
203 pb = (struct adspcmd *)gbuf_rptr(mp); /* get new parameter block */
204 pb->ioc = 0;
205 pb->mp = mp;
206 gbuf_cont(pb->mp) = tmp; /* reattach data */
207 pb->qLink = sp->rpb; /* requeue the duplicate at the head */
208 sp->rpb = pb;
209 } else { /* there is no data left, but no space
210 * to duplicate the parameter block, so
211 * put what must be a non EOM message
212 * back on the current receive queue, and
213 * error out the user
214 */
215 KERNEL_DEBUG(DBG_ADSP_READ, 0x10, pb, sp, pb->mp, 0);
216 if (tmp) {
217 sp->crbuf_mb = tmp;
218 sp->rData = 1;
219 }
220 pb->ioResult = errDSPQueueSize;
221 adspioc_ack(ENOBUFS, pb->ioc, pb->gref);
222 }
223 }
224 }
225 /*
226 * The receive window has opened. If was previously closed, then we
227 * need to notify the other guy that we now have room to receive more
228 * data. But, in order to cut down on lots of small data packets,
229 * we'll wait until the recieve buffer is /14 empy before telling
230 * him that there's room in our receive buffer.
231 */
232 if (sp->rbufFull && (CalcRecvWdw(sp) > (sp->rbuflen >> 2))) {
233 sp->rbufFull = 0;
234 sp->sendDataAck = 1;
235 sp->callSend = 1;
236 }
237 ATENABLE(s, sp->lock);
238
239 KERNEL_DEBUG(DBG_ADSP_READ, 0x11, sp, 0, 0, 0);
240 trace_mbufs(D_M_ADSP_LOW, " eCQR m", sp->rbuf_mb);
241 return 0;
242}
243
244/*
245 * CheckAttn
246 *
247 * Checks to see if there is any attention data and passes the data back
248 * in the passed in pb.
249 *
250 * INPUTS:
251 * sp
252 * pb
253 *
254 * OUTPUTS:
255 *
256 */
257int CheckAttn(sp, pb) /* (CCBPtr sp) */
258 register CCBPtr sp;
259 register struct adspcmd *pb;
260{
261 int s;
262 gbuf_t *mp;
263 gref_t *gref;
264
265 dPrintf(D_M_ADSP, D_L_TRACE,
266 ("CheckAttn: sp=0x%x, pb=0x%x\n", (unsigned)sp, (unsigned)pb));
267
268 ATDISABLE(s, sp->lock);
269 if (mp = sp->attn_mb) {
270
271 /*
272 * Deliver the attention data to the user.
273 */
274 gref = (gref_t *)pb->gref;
275 pb->u.attnParams.attnSize = sp->attnSize;
276 pb->u.attnParams.attnCode = sp->attnCode;
277 if (!sp->attnSize) {
278 gbuf_freem(mp);
279 mp = 0;
280 }
281 sp->userFlags &= ~eAttention;
282 /*
283 * Now clean up receive buffer to remove all of the data
284 * we just copied
285 */
286 sp->attn_mb = 0;
287 pb->ioResult = 0;
288 } else {
289 /*
290 * No data...
291 */
292 pb->u.attnParams.attnSize = 0;
293 pb->u.attnParams.attnCode = 0;
294 pb->ioResult = 1; /* not done */
295 }
296 adspioc_ack(0, pb->ioc, pb->gref);
297 if (mp) {
298 SndMsgUp(gref, mp);
299 }
300 ATENABLE(s, sp->lock);
301 return 0;
302}
303
304/*
305 * adspRead
306 *
307 * INPUTS:
308 * --> sp stream pointer
309 * --> pb user request parameter block
310 *
311 * OUTPUTS:
312 * <-- actCount actual number of bytes read
313 * <-- eom one if end-of-message, zero otherwise
314 *
315 * ERRORS:
316 * errRefNum bad connection refnum
317 * errState
318 * errFwdReset read terminated by forward reset
319 * errAborted request aborted by Remove or Close call
320 */
321int adspRead(sp, pb) /* (DSPPBPtr pb) */
322 register CCBPtr sp;
323 register struct adspcmd *pb;
324{
325 register gbuf_t *mp;
326 int s;
327
328 dPrintf(D_M_ADSP, D_L_TRACE,
329 ("adspRead: sp=0x%x, pb=0x%x\n", (unsigned)sp, (unsigned)pb));
330
331 KERNEL_DEBUG(DBG_ADSP_READ, 0x12, sp, pb, sp->state, sp->rData);
332
333 if (sp == 0) {
334 pb->ioResult = errRefNum;
335 return EINVAL;
336 }
337
338 /*
339 * It's OK to read on a closed, or closing session
340 */
341 ATDISABLE(s, sp->lock);
342 if (sp->state != sOpen && sp->state != sClosing && sp->state != sClosed) {
343 ATENABLE(s, sp->lock);
344 pb->ioResult = errState;
345 return EINVAL;
346 }
347 if (sp->rData && (sp->rpb == 0)) { /* if data, and no queue of pbs */
348 qAddToEnd(&sp->rpb, pb); /* deliver data to user directly */
349 ATENABLE(s, sp->lock);
350 CheckReadQueue(sp);
351 } else if ((pb->u.ioParams.reqCount == 0) && (sp->rpb == 0)) {
352 /* empty read */
353 ATENABLE(s, sp->lock);
354 pb->ioResult = 0;
355 adspioc_ack(0, pb->ioc, pb->gref);
356 return 0;
357 } else {
358 pb->ioResult = 1;
359 if (mp = gbuf_copym(pb->mp)) { /* otherwise, duplicate user request */
360 adspioc_ack(0, pb->ioc, pb->gref); /* release user */
361 pb = (struct adspcmd *)gbuf_rptr(mp); /* get new parameter block */
362 pb->ioc = 0;
363 pb->mp = mp;
364 qAddToEnd(&sp->rpb, pb); /* and queue it for later */
365 ATENABLE(s, sp->lock);
366 } else {
367 ATENABLE(s, sp->lock);
368 pb->ioResult = errDSPQueueSize;
369 return ENOBUFS;
370 }
371 }
372
373 if (sp->callSend) {
374 CheckSend(sp); /* If recv window opened, we might */
375 /* send an unsolicited ACK. */
376 }
377 return 0;
378}
379
380/*
381 * dspReadAttention
382 *
383 * INPUTS:
384 * --> sp stream pointer
385 * --> pb user request parameter block
386 *
387 * OUTPUTS:
388 * <-- NONE
389 *
390 * ERRORS:
391 * errRefNum bad connection refnum
392 * errState connection is not in the right state
393 */
394int adspReadAttention(sp, pb) /* (DSPPBPtr pb) */
395 register CCBPtr sp;
396 register struct adspcmd *pb;
397{
398 dPrintf(D_M_ADSP, D_L_TRACE,
399 ("adspReadAttention: sp=0x%x, pb=0x%x\n", (unsigned)sp, (unsigned)pb));
400 if (sp == 0) {
401 pb->ioResult = errRefNum;
402 return EINVAL;
403 }
404
405 /*
406 * It's OK to read on a closed, or closing session
407 */
408 if (sp->state != sOpen && sp->state != sClosing && sp->state != sClosed) {
409 pb->ioResult = errState;
410 return EINVAL;
411 }
412
413 CheckAttn(sp, pb); /* Anything in the attention queue */
414 CheckReadQueue(sp); /* check to see if receive window has opened */
415 if (sp->callSend) {
416 CheckSend(sp); /* If recv window opened, we might */
417 /* send an unsolicited ACK. */
418 }
419 return 0;
420} /* adspReadAttention */