2 Copyright © 1995-2014, The AROS Development Team. All rights reserved.
6 #include <hidd/unixio.h>
7 #include <proto/exec.h>
8 #include <proto/hostlib.h>
10 #include "unixio_device.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
])
33 else if (c
> unit
->termarray
[i
])
35 /* Speed optimization: the array is descending-ordered */
42 void unit_io(int fd
, int mode
, struct UnitData
*data
)
49 /* The unit is stopped. Ignore the interrupt. */
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
;
60 unsigned int readLength
;
62 if ((readLength
== -1) || data
->eofmode
))
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. */
77 done
= data
->ErrorCallback(req
, err
);
81 req
->io_Actual
+= len
;
83 if ((req
->io_Length
== -1) && (*ptr
== 0))
85 else if (data
->eofmode
&& is_eof(*ptr
, data
))
87 else if (req
->io_Actual
== req
->io_Length
)
93 /* The request is done, reply it */
96 ReplyMsg(&req
->io_Message
);
101 if (mode
& vHidd_UnixIO_Write
)
103 /* Write as much as we can */
104 while ((req
= GetHead(&data
->writeQueue
)))
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
;
115 char *ptr
= req
->io_Data
;
118 for (i
= 0; i
< data
->writeLen
; i
++)
120 if (is_eof(ptr
[i
], data
)
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. */
139 done
= data
->ErrorCallback(req
, err
);
143 req
->io_Actual
+= len
;
146 done
== (writeLength
== 0);
151 /* Active request is done, reply it */
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
;
178 AROS_LH1(void, beginio
,
179 AROS_LHA(struct IOStdReq
*, ioreq
, A1
),
180 struct UnixDevice
*, unixioDev
, 5, Unixio
)
184 struct UnitData
*data
= (struct UnitData
*)ioreq
->io_Unit
;
185 struct IoStdReq
*read
, *write
, *activeread
, *activewrite
;
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
)
196 D(bug("Queuing the read request.\n"));
197 ioreq
->io_Flags
&= ~IOF_QUICK
;
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
);
216 D(bug("Queuing the write request.\n"));
217 ioreq
->io_Flags
&= ~IOF_QUICK
;
220 ADDTAIL(&data
->writeQueue
, req
);
222 unixioDev
->raise(SIGIO
);
229 /* All IORequests, including the active ones, are aborted */
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;
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.
257 read
= GetInactive(&data
->readQueue
);
258 write
= GetInactive(&data
->writeQueue
);
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
);
281 data
->stopped
= TRUE
;
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"));
302 /****************************************************************************************/
304 AROS_LH1(LONG
, abortio
,
305 AROS_LHA(struct IOStdReq
*, ioreq
, A1
),
306 struct UnixDevice
*, unixioDev
, 6, Unixio
)
310 struct UnitData
*data
= (struct UnitData
*)ioreq
->io_Unit
;
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;
323 ioreq
->io_Error
= IOERR_ABORTED
;
324 ReplyMsg(&ioreq
->io_Message
);