alsa.audio: build the bridge link lib only for linux architecture
[AROS.git] / arch / all-unix / devs / unixio / deviceio.c
blob2291a1d28166691a70b73ccf2b904a43da0ae70f
1 /*
2 Copyright © 1995-2014, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 #include <hidd/unixio.h>
7 #include <proto/exec.h>
8 #include <proto/hostlib.h>
10 #include "unixio_device.h"
12 #include <signal.h>
14 static void Flush(struct IoStdReq *req)
16 struct IoStdReq *next;
18 for (; req->io_Message.mn_Node.ln_Succ; req = next)
20 next = (struct IoStdReq *)req->io_Message.mn_Node.ln_Succ
22 ireq->io_Error = IOERR_ABORTED;
23 ReplyMsg(&req->io_Message);
27 static BOOL is_eof(char c, struct UnitData *unit)
29 for (i = 0; i < 8; i++)
31 if (c == unit->termarray[i])
32 return TRUE;
33 else if (c > unit->termarray[i])
35 /* Speed optimization: the array is descending-ordered */
36 return FALSE;
39 return FALSE;
42 void unit_io(int fd, int mode, struct UnitData *data)
44 struct IOStdReq *req;
45 int err, len;
47 if (data->stopped)
49 /* The unit is stopped. Ignore the interrupt. */
50 return;
53 if (mode & vHidd_UnixIO_Read)
55 /* Read as much as we can */
56 while ((req = GetHead(&data->readQueue)))
58 char *ptr = req->io_Data + req->io_Actual;
59 BOOL done = FALSE;
60 unsigned int readLength;
62 if ((readLength == -1) || data->eofmode))
63 readLength = 1;
64 else
65 readLength = req->io_Length - req->io_Actual;
67 len = Hidd_UnixIO_ReadFile(data->unixio, data->fd, ptr, readLength, &err);
69 if ((len == -1) && (err == EWOULDBLOCK))
71 /* There are no more data to read, but we need to read more. Wait for the next interrupt. */
72 break;
75 if (len == -1)
77 done = data->ErrorCallback(req, err);
79 else
81 req->io_Actual += len;
83 if ((req->io_Length == -1) && (*ptr == 0))
84 done = TRUE;
85 else if (data->eofmode && is_eof(*ptr, data))
86 done = TRUE;
87 else if (req->io_Actual == req->io_Length)
88 done = TRUE;
91 if (done)
93 /* The request is done, reply it */
94 REMOVE(req);
95 req->io_Error = 0;
96 ReplyMsg(&req->io_Message);
101 if (mode & vHidd_UnixIO_Write)
103 /* Write as much as we can */
104 while ((req = GetHead(&data->writeQueue)))
106 BOOL done = FALSE;
108 if (data->writeLen == 0)
110 /* This request is being served for the first time, length is not determined yet */
112 data->writeLen = (req->io_Length == -1) ? strlen(req->io_Data) : req->io_Length;
113 if (data->eofmode)
115 char *ptr = req->io_Data;
116 unsigned int i;
118 for (i = 0; i < data->writeLen; i++)
120 if (is_eof(ptr[i], data)
122 data->wrireLen = i;
123 break;
129 len = Hidd_UnixIO_WriteFile(data->unixio, data->fd, req->io_Data + req->io_Actual, data->writeLength, &err);
131 if ((len == -1) && (err == EWOULDBLOCK))
133 /* Output buffer filled up. Wait for the next interrupt. */
134 break;
137 if (len == -1)
139 done = data->ErrorCallback(req, err);
141 else
143 req->io_Actual += len;
144 writeLength -= len;
146 done == (writeLength == 0);
149 if (done)
151 /* Active request is done, reply it */
152 REMOVE(req);
153 req->io_Error = 0;
154 ReplyMsg(&req->io_Message);
160 struct IOStdReq *GetInactive(struct MinList *l)
162 struct MinNode *n = l->mlh_Head.mln_Succ;
164 if (n && n->mln_Succ)
167 * The list has more than one node. 'n' points to the second one.
168 * Unlink 'n' and following nodes from the list, leave only the first node.
170 l->mlh_TailPred = l->mlh_Head;
171 l->mlh_Head->mln_Succ = &l->mlh_Tail;
173 return n;
175 return NULL;
178 AROS_LH1(void, beginio,
179 AROS_LHA(struct IOStdReq *, ioreq, A1),
180 struct UnixDevice *, unixioDev, 5, Unixio)
182 AROS_LIBFUNC_INIT
184 struct UnitData *data = (struct UnitData *)ioreq->io_Unit;
185 struct IoStdReq *read, *write, *activeread, *activewrite;
186 BOOL stopped;
188 D(bug("unixio.device: beginio(0x%p)\n", ioreq));
190 /* WaitIO will look into this */
191 ioreq->io_Message.mn_Node.ln_Type=NT_MESSAGE;
193 switch (ioreq->io_Command)
195 case CMD_READ:
196 D(bug("Queuing the read request.\n"));
197 ioreq->io_Flags &= ~IOF_QUICK;
199 Disable();
200 ADDTAIL(&data->readQueue, req);
203 * Artificially cause SIGIO in order to recheck all fd's and start I/O on ready ones.
204 * Without this the I/O can stall. For example, some fd might go write-ready while we have
205 * nothing to write. In this case the issued SIGIO will be consumed, and there will be no
206 * other SIGIO on the same fd until we write something to it.
207 * No HostLib_Lock() here, single-threaded by Disable()
209 unixioDev->raise(SIGIO);
210 AROS_HOST_BARRIER
212 Enable();
213 return;
215 case CMD_WRITE:
216 D(bug("Queuing the write request.\n"));
217 ioreq->io_Flags &= ~IOF_QUICK;
219 Disable();
220 ADDTAIL(&data->writeQueue, req);
222 unixioDev->raise(SIGIO);
223 AROS_HOST_BARRIER
225 Enable();
226 return;
228 case CMD_RESET:
229 /* All IORequests, including the active ones, are aborted */
230 Disable();
233 * An optimization trick: in order not to hold Disable()'d state for a while,
234 * we just detach chains of requests from queue lists and reinitialize
235 * lists. After this we can Enable(), then reply all requests in our chains.
237 read = (struct IOStdReq *)data->readQueue.mlh_Head;
238 write = (struct IOStdReq *)data->writeQueue.mlh_Head;
239 NEWLIST(&data->readQueue);
240 NEWLIST(&data->writeQueue);
241 data->writeLength = 0;
243 Enable();
245 Flush(read);
246 Flush(write);
247 ioreq->io_Error = 0;
248 break;
250 case CMD_FLUSH:
252 * Clear all queued IO request for the given unit except for the active ones.
253 * Techniques are the same as in CMD_RESET, just don't touch writeLength.
255 Disable();
257 read = GetInactive(&data->readQueue);
258 write = GetInactive(&data->writeQueue);
260 Enable();
262 Flush(read);
263 Flush(write);
264 ioreq->io_Error = 0;
265 break;
267 case CMD_START:
268 data->stopped = FALSE;
270 if (!(IsListEmpty(&data->readQueue) && IsListEmpty(&data->writeQueue)))
272 /* Force-start I/O if there's something queued */
273 unixioDev->raise(SIGIO);
274 AROS_HOST_BARRIER;
277 ioreq->io_Error = 0;
278 break;
280 case CMD_STOP:
281 data->stopped = TRUE;
282 ioreq->io_Error = 0;
283 break;
285 default:
286 /* unknown command */
287 ioreq->io_Error = IOERR_NOCMD;
291 * The request could be completed immediately.
292 * Check if I have to reply the message
294 if (!(ioreq->io_Flags & IOF_QUICK))
295 ReplyMsg(&ioreq->IOPar.io_Message);
297 D(bug("id: Return from BeginIO()\n"));
299 AROS_LIBFUNC_EXIT
302 /****************************************************************************************/
304 AROS_LH1(LONG, abortio,
305 AROS_LHA(struct IOStdReq *, ioreq, A1),
306 struct UnixDevice *, unixioDev, 6, Unixio)
308 AROS_LIBFUNC_INIT
310 struct UnitData *data = (struct UnitData *)ioreq->io_Unit;
312 Disable();
314 if (data->writeQueue.mlh_Head == (struct MinNode *)ioreq)
316 /* Reset writeLength to zero so it's re-calculated when the next request is picked up */
317 data->writeLength = 0;
319 REMOVE(ioreq);
321 Enable();
323 ioreq->io_Error = IOERR_ABORTED;
324 ReplyMsg(&ioreq->io_Message);
326 return 0;
328 AROS_LIBFUNC_EXIT