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