]> git.saurik.com Git - apple/xnu.git/blame - bsd/netat/adsp_Read.c
xnu-517.7.7.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 *
e5568f75
A
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.
1c79356b 11 *
e5568f75
A
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
1c79356b
A
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
e5568f75
A
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
1c79356b
A
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22/*
23 *
24 * dspRead.c
25 *
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.
29 */
30
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>
37#include <sys/proc.h>
38#include <sys/filedesc.h>
39#include <sys/fcntl.h>
40#include <sys/mbuf.h>
41#include <sys/socket.h>
42#include <sys/socketvar.h>
43
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>
50
51/*
52 * CheckReadQueue
53 *
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.
56 *
57 *
58 */
59extern int adsp_check;
60
61int CheckReadQueue(sp) /* (CCBPtr sp) */
62 register CCBPtr sp;
63{
64 register struct adspcmd *pb;
65 int s;
66 unsigned short cnt;
67 char eom = 0;
68 register gbuf_t *mp;
69 register gbuf_t *tmp;
70 gref_t *gref;
71
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);
76
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) {
83 pb->ioResult = 0;
84 sp->rpb = pb->qLink;
85 if (pb->ioc) {
86 KERNEL_DEBUG(DBG_ADSP_READ, 2, pb, pb->gref, pb->ioc, 0);
87 adspioc_ack(0, pb->ioc, pb->gref);
88 } else {
89 KERNEL_DEBUG(DBG_ADSP_READ, 3, pb, pb->gref, 0, 0);
90 completepb(sp, pb);
91 }
92 continue;
93 }
94
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);
99 gbuf_next(mp) = 0;
100 eom = 1;
101 } else if (mp = sp->crbuf_mb) {
102 KERNEL_DEBUG(DBG_ADSP_READ, 5, pb, mp, gbuf_msgsize(mp), gbuf_next(mp));
103 sp->crbuf_mb = 0;
104 eom = 0;
105 }
106
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))) {
115 cnt = 0;
116 tmp = mp;
117 }
118 if (eom) {
119 gbuf_next(tmp) = sp->rbuf_mb;
120 sp->rbuf_mb = tmp;
121 eom = 0;
122 } else
123 sp->crbuf_mb = tmp;
124 }
125 if (cnt) {
126 pb->u.ioParams.actCount += cnt;
127 gbuf_linkb(pb->mp, mp);
128 }
129
130 pb->u.ioParams.eom = eom;
131 /*
132 * Now clean up receive buffer to remove all of the data
133 * we just copied
134 */
135 if ((sp->rbuf_mb == 0) &&
136 (sp->crbuf_mb == 0)) /* no more data blocks */
137 sp->rData = 0;
138 /*
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.
142 */
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.
148 */
149 pb->ioResult = 0;
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));
159 SndMsgUp(gref, 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);
167 completepb(sp, pb);
168 }
169 }
170 } /* while */
171
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);
178
179 if (sp->state == sClosed) {
180 while (pb) {
181 KERNEL_DEBUG(DBG_ADSP_READ, 0x0E, pb, sp, pb->ioc, 0);
182 pb->ioResult = 0;
183 pb->u.ioParams.actCount = 0;
184 pb->u.ioParams.eom = 0;
185 sp->rpb = pb->qLink;
186 if (pb->ioc) {
187 adspioc_ack(0, pb->ioc, pb->gref);
188 } else {
189 completepb(sp, pb);
190 }
191 pb = sp->rpb;
192 }
193 } else if (pb->ioc) { /* if request not complete and this
194 * is an active ioctl, release user */
195 sp->rpb = pb->qLink;
196 pb->ioResult = 1;
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 */
203 pb->ioc = 0;
204 pb->mp = mp;
205 gbuf_cont(pb->mp) = tmp; /* reattach data */
206 pb->qLink = sp->rpb; /* requeue the duplicate at the head */
207 sp->rpb = pb;
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
212 * error out the user
213 */
214 KERNEL_DEBUG(DBG_ADSP_READ, 0x10, pb, sp, pb->mp, 0);
215 if (tmp) {
216 sp->crbuf_mb = tmp;
217 sp->rData = 1;
218 }
219 pb->ioResult = errDSPQueueSize;
220 adspioc_ack(ENOBUFS, pb->ioc, pb->gref);
221 }
222 }
223 }
224 /*
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.
230 */
231 if (sp->rbufFull && (CalcRecvWdw(sp) > (sp->rbuflen >> 2))) {
232 sp->rbufFull = 0;
233 sp->sendDataAck = 1;
234 sp->callSend = 1;
235 }
236 ATENABLE(s, sp->lock);
237
238 KERNEL_DEBUG(DBG_ADSP_READ, 0x11, sp, 0, 0, 0);
239 trace_mbufs(D_M_ADSP_LOW, " eCQR m", sp->rbuf_mb);
240 return 0;
241}
242
243/*
244 * CheckAttn
245 *
246 * Checks to see if there is any attention data and passes the data back
247 * in the passed in pb.
248 *
249 * INPUTS:
250 * sp
251 * pb
252 *
253 * OUTPUTS:
254 *
255 */
256int CheckAttn(sp, pb) /* (CCBPtr sp) */
257 register CCBPtr sp;
258 register struct adspcmd *pb;
259{
260 int s;
261 gbuf_t *mp;
262 gref_t *gref;
263
264 dPrintf(D_M_ADSP, D_L_TRACE,
265 ("CheckAttn: sp=0x%x, pb=0x%x\n", (unsigned)sp, (unsigned)pb));
266
267 ATDISABLE(s, sp->lock);
268 if (mp = sp->attn_mb) {
269
270 /*
271 * Deliver the attention data to the user.
272 */
273 gref = (gref_t *)pb->gref;
274 pb->u.attnParams.attnSize = sp->attnSize;
275 pb->u.attnParams.attnCode = sp->attnCode;
276 if (!sp->attnSize) {
277 gbuf_freem(mp);
278 mp = 0;
279 }
280 sp->userFlags &= ~eAttention;
281 /*
282 * Now clean up receive buffer to remove all of the data
283 * we just copied
284 */
285 sp->attn_mb = 0;
286 pb->ioResult = 0;
287 } else {
288 /*
289 * No data...
290 */
291 pb->u.attnParams.attnSize = 0;
292 pb->u.attnParams.attnCode = 0;
293 pb->ioResult = 1; /* not done */
294 }
295 adspioc_ack(0, pb->ioc, pb->gref);
296 if (mp) {
297 SndMsgUp(gref, mp);
298 }
299 ATENABLE(s, sp->lock);
300 return 0;
301}
302
303/*
304 * adspRead
305 *
306 * INPUTS:
307 * --> sp stream pointer
308 * --> pb user request parameter block
309 *
310 * OUTPUTS:
311 * <-- actCount actual number of bytes read
312 * <-- eom one if end-of-message, zero otherwise
313 *
314 * ERRORS:
315 * errRefNum bad connection refnum
316 * errState
317 * errFwdReset read terminated by forward reset
318 * errAborted request aborted by Remove or Close call
319 */
320int adspRead(sp, pb) /* (DSPPBPtr pb) */
321 register CCBPtr sp;
322 register struct adspcmd *pb;
323{
324 register gbuf_t *mp;
325 int s;
326
327 dPrintf(D_M_ADSP, D_L_TRACE,
328 ("adspRead: sp=0x%x, pb=0x%x\n", (unsigned)sp, (unsigned)pb));
329
330 KERNEL_DEBUG(DBG_ADSP_READ, 0x12, sp, pb, sp->state, sp->rData);
331
332 if (sp == 0) {
333 pb->ioResult = errRefNum;
334 return EINVAL;
335 }
336
337 /*
338 * It's OK to read on a closed, or closing session
339 */
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;
344 return EINVAL;
345 }
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);
349 CheckReadQueue(sp);
350 } else if ((pb->u.ioParams.reqCount == 0) && (sp->rpb == 0)) {
351 /* empty read */
352 ATENABLE(s, sp->lock);
353 pb->ioResult = 0;
354 adspioc_ack(0, pb->ioc, pb->gref);
355 return 0;
356 } else {
357 pb->ioResult = 1;
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 */
361 pb->ioc = 0;
362 pb->mp = mp;
363 qAddToEnd(&sp->rpb, pb); /* and queue it for later */
364 ATENABLE(s, sp->lock);
365 } else {
366 ATENABLE(s, sp->lock);
367 pb->ioResult = errDSPQueueSize;
368 return ENOBUFS;
369 }
370 }
371
372 if (sp->callSend) {
373 CheckSend(sp); /* If recv window opened, we might */
374 /* send an unsolicited ACK. */
375 }
376 return 0;
377}
378
379/*
380 * dspReadAttention
381 *
382 * INPUTS:
383 * --> sp stream pointer
384 * --> pb user request parameter block
385 *
386 * OUTPUTS:
387 * <-- NONE
388 *
389 * ERRORS:
390 * errRefNum bad connection refnum
391 * errState connection is not in the right state
392 */
393int adspReadAttention(sp, pb) /* (DSPPBPtr pb) */
394 register CCBPtr sp;
395 register struct adspcmd *pb;
396{
397 dPrintf(D_M_ADSP, D_L_TRACE,
398 ("adspReadAttention: sp=0x%x, pb=0x%x\n", (unsigned)sp, (unsigned)pb));
399 if (sp == 0) {
400 pb->ioResult = errRefNum;
401 return EINVAL;
402 }
403
404 /*
405 * It's OK to read on a closed, or closing session
406 */
407 if (sp->state != sOpen && sp->state != sClosing && sp->state != sClosed) {
408 pb->ioResult = errState;
409 return EINVAL;
410 }
411
412 CheckAttn(sp, pb); /* Anything in the attention queue */
413 CheckReadQueue(sp); /* check to see if receive window has opened */
414 if (sp->callSend) {
415 CheckSend(sp); /* If recv window opened, we might */
416 /* send an unsolicited ACK. */
417 }
418 return 0;
419} /* adspReadAttention */