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