unixio.hidd: Add interface for raw packet I/O
[AROS.git] / arch / all-unix / hidd / unixio / unixio_class.c
blobe0e17f4a95db187c66cb01e5ffb6d5253074cbe3
1 /*
2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Unix filedescriptor/socket IO
6 Lang: english
7 */
9 /* Unix includes */
10 #define timeval sys_timeval /* We don't want the unix timeval to interfere with the AROS one */
11 #include <sys/types.h>
12 #include <fcntl.h>
13 #include <unistd.h>
14 #include <sys/stat.h>
15 #include <sys/ioctl.h>
16 #include <signal.h>
17 #include <string.h>
18 #include <errno.h>
20 #undef timeval
22 #define SDEBUG 0
23 #define DEBUG 0
24 #include <aros/debug.h>
26 #define __OOP_NOATTRBASES__
28 #include <exec/types.h>
29 #include <exec/lists.h>
30 #include <exec/interrupts.h>
31 #include <exec/execbase.h>
32 #include <exec/semaphores.h>
33 #include <exec/memory.h>
34 #include <exec/resident.h>
35 #include <exec/tasks.h>
36 #include <exec/ports.h>
37 #include <exec/nodes.h>
38 #include <intuition/intuition.h>
39 #include <utility/tagitem.h>
40 #include <utility/hooks.h>
41 #include <hidd/unixio.h>
42 #include <aros/asmcall.h>
43 #include <aros/symbolsets.h>
45 #include <oop/oop.h>
46 #include <proto/exec.h>
47 #include <proto/hostlib.h>
48 #include <proto/intuition.h>
49 #include <proto/kernel.h>
50 #include <proto/oop.h>
51 #include <proto/utility.h>
52 #include <proto/alib.h>
54 #include <devices/timer.h>
56 #include "unixio.h"
58 #include LC_LIBDEFS_FILE
60 #include <aros/asmcall.h>
62 /*****************************************************************************************
64 NAME
65 --background--
67 LOCATION
68 unixio.hidd
70 NOTES
71 unixio.hidd is a simple driver for host-side I/O on UNIX system. Its primary
72 purpose is to handle non-blocking I/O on AROS task level. Also it provides
73 common file access operations (open, close, read, write and ioctl) in order
74 to avoid code duplication.
76 I/O operations you perform must never block. The whole AROS with all its tasks
77 is just one process from host OS' point of view, so blocking operation would
78 halt all the system. In order to avoid this you need to make sure that the
79 file descriptor is actually ready to perform I/O. If this is not the case,
80 your task needs to wait until file descriptor becomes available. unixio.hidd
81 offers a simple way of doing it by adding an interrupt handler to the file
82 descriptor using moHidd_UnixIO_AddInterrupt method. The interrupt handler
83 will be called whenever SIGIO arrives from the specified descriptor and specified
84 conditions are met. You do not need to explicitly enable asynchronous I/O
85 on the file descriptor, unixio.hidd takes care about all this itself.
87 There's also a convenience moHidd_UnixIO_Wait method. It allows you to simulate
88 a normal blocking I/O in a simple way.
90 Starting from v42 unixio.hidd is a singletone. This means that all calls to
91 OOP_NewObject() will actually return the same object which is never really
92 disposed. This object pointer can be freely transferred between tasks. It's
93 not necessary t call OOP_DisposeObject() on it. It is safe, but will do nothing.
94 Usage counter is maintained by OpenLibrary()/CloseLibrary() calls.
96 Remember that all values (like file mode flags and errno values) are host-specific!
97 Different hosts may use different values, and even different structure layouts
98 (especially this affects ioctl). When opening unixio.hidd it is adviced to check
99 that host OS matches what is expected (what your client program/driver/whatever
100 is compiled for). Use aoHidd_UnixIO_Architecture attribute for this.
102 *****************************************************************************************/
104 static int poll_fd(int fd, int req_mode, struct unixio_base *ud)
106 struct pollfd pfd = {fd, 0, 0};
107 int mode = 0;
108 int res;
110 if (req_mode & vHidd_UnixIO_Read)
111 pfd.events |= POLLIN;
112 if (req_mode & vHidd_UnixIO_Write)
113 pfd.events |= POLLOUT;
115 res = ud->SysIFace->poll(&pfd, 1, 0);
116 AROS_HOST_BARRIER
118 if (res > 0)
120 if (pfd.revents & POLLIN)
121 mode |= vHidd_UnixIO_Read;
122 if (pfd.revents & POLLOUT)
123 mode |= vHidd_UnixIO_Write;
124 if (pfd.revents & (POLLERR|POLLHUP))
125 mode |= vHidd_UnixIO_Error;
127 else if (res < 0)
128 mode = -1;
130 return mode;
133 static void SigIO_IntServer(struct unixio_base *ud, void *unused)
135 struct uioInterrupt *intnode;
137 /* Walk through the list of installed handlers and de-multiplex our SIGIO */
138 for (intnode = (struct uioInterrupt *)ud->intList.mlh_Head; intnode->Node.mln_Succ;
139 intnode = (struct uioInterrupt *)intnode->Node.mln_Succ)
141 int mode = poll_fd(intnode->fd, intnode->mode, ud);
143 if (mode > 0)
145 D(bug("[UnixIO] Events 0x%02X for fd %d\n", mode, intnode->fd));
147 intnode->handler(intnode->fd, mode, intnode->handlerData);
152 static void WaitIntHandler(int fd, int mode, void *data)
154 struct UnixIO_Waiter *w = data;
155 Signal(w->task, 1 << w->signal);
158 static BOOL CheckArch(struct unixio_base *data, STRPTR Component, STRPTR MyArch)
160 STRPTR arg[3] = {Component, MyArch, data->SystemArch};
162 D(bug("[UnixIO] My architecture: %s, kernel architecture: %s\n", arg[1], arg[2]));
164 if (strcmp(arg[1], arg[2]))
166 struct IntuitionBase *IntuitionBase;
168 IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library", 36);
169 if (IntuitionBase)
171 struct EasyStruct es = {
172 sizeof (struct EasyStruct),
174 "Incompatible architecture",
175 "Used version of %s is built for use\n"
176 "with %s architecture, but your\n"
177 "system architecture is %s.",
178 "Ok",
181 EasyRequestArgs(NULL, &es, NULL, (IPTR *)arg);
183 CloseLibrary(&IntuitionBase->LibNode);
185 return FALSE;
188 D(bug("[UnixIO] Architecture check done\n"));
189 return TRUE;
192 #define HostLibBase data->HostLibBase
193 #define KernelBase data->KernelBase
195 #undef HiddUnixIOAttrBase
196 #define HiddUnixIOAttrBase data->UnixIOAB
198 /*****************************************************************************************
200 NAME
201 aoHidd_UnixIO_Opener
203 SYNOPSIS
204 [I..], STRPTR
206 LOCATION
207 unixio.hidd
209 FUNCTION
210 Specifiers opener name for architecture check routine.
212 NOTES
213 This attribute's sole purpose is to be presented to the user in an error requester
214 if the architecture check fails. For example if you specify "tap.device" here,
215 the user will see a requester telling that "This version of tap.device is built
216 for XXX architecture, while current system architecture is YYY".
218 If this attribute is not specified, but architecture check is requested using
219 aoHidd_UnixIO_Architecture, current task's name will be used. This can be not
220 always approptiate, so it's adviced to always specify your driver or program
221 name here.
223 EXAMPLE
225 BUGS
227 SEE ALSO
228 aoHidd_UnixIO_Architecture
230 INTERNALS
232 *****************************************************************************************/
233 /*****************************************************************************************
235 NAME
236 aoHidd_UnixIO_Architecture
238 SYNOPSIS
239 [I..], STRPTR
241 LOCATION
242 unixio.hidd
244 FUNCTION
245 Specifiers architecture name to match against current system's architecture.
246 Architecture name needs to be supplied in the form "arch-cpu", for example
247 "linux-ppc" or "darwin-i386". Usually this comes from a definition when
248 you compile your module.
250 NOTES
251 This attribute allows you to ensure that your module is running on the same
252 architecture it was compiled for. This is needed because unixio.hidd by its
253 nature works with host OS structures and values (especially ioctl operation).
254 Different host OSes (for example Linux and Darwin) are not binary compatible
255 even on the same CPU. This is why the architecture check is generally needed,
256 especially for disk-based components.
258 It is adviced to specify your module name using aoHidd_UnixIO_Opener. This needed
259 in order to display the correct name to the user if the check fails, so the user
260 will see what module causes the error.
262 EXAMPLE
264 struct TagItem tags = {
265 {aHidd_UnixIO_Opener, "tap.device"},
266 {aHidd_UnixIO_Architecture, "linux-i386"},
267 {TAG_DONE, 0}
269 uio = OOP_NewObject(CLID_Hidd_UnixIO, tags);
270 // If uio == NULL, the system you're running on is not linux-i386. The error
271 // requester has been already presented to the user.
273 BUGS
275 SEE ALSO
276 aoHidd_UnixIO_Opener
278 INTERNALS
280 *****************************************************************************************/
281 /* The following are methods of the UnixIO HIDD class. */
283 /********************
284 ** UnixIO::New() **
285 ********************/
286 OOP_Object *UXIO__Root__New(OOP_Class *cl, OOP_Object *o, struct pRoot_New *msg)
288 struct unixio_base *data = UD(cl);
289 STRPTR archName;
291 EnterFunc(bug("UnixIO::New(cl=%s)\n", cl->ClassNode.ln_Name));
293 archName = (STRPTR)GetTagData(aHidd_UnixIO_Architecture, 0, msg->attrList);
294 if (archName)
296 struct Task *t = FindTask(NULL);
297 STRPTR moduleName = (STRPTR)GetTagData(aHidd_UnixIO_Opener, (IPTR)t->tc_Node.ln_Name, msg->attrList);
299 if (!CheckArch(data, moduleName, archName))
300 return NULL;
303 /* We are a true singletone */
304 ObtainSemaphore(&data->lock);
306 if (!data->obj)
308 D(bug("[UnixIO] Creating object\n"));
309 data->obj = (OOP_Object *)OOP_DoSuperMethod(cl, o, (OOP_Msg)msg);
312 ReleaseSemaphore(&data->lock);
314 ReturnPtr("UnixIO::New", OOP_Object *, data->obj);
317 /***********************
318 ** UnixIO::Dispose() **
319 ***********************/
320 void UXIO__Root__Dispose(OOP_Class *cl, OOP_Object *o, OOP_Msg msg)
323 * Do nothing here.
324 * We can't just omit this method because in this case Dispose() will be called
325 * on our superclass, which is not what we want.
329 /*****************************************************************************************
331 NAME
332 moHidd_UnixIO_Wait
334 SYNOPSIS
335 OOP_DoMethod(OOP_Object *obj, struct pHidd_UnixIO_ *msg);
337 IPTR Hidd_UnixIO_Wait(OOP_Object *obj, ULONG fd, ULONG mode);
339 LOCATION
340 unixio.hidd
342 FUNCTION
343 Wait for an event on the file descriptor.
345 INPUTS
346 obj - A pointer to a UnixIO object
347 fd - A file descriptor to wait on
348 mode - A combination of two flags:
349 - vHidd_UnixIO_Read - to request waiting until read is permitted
350 - vHidd_UnixIO_Write - to request waiting until write is permitted
352 RESULT
353 0 in case of success or UNIX errno value in case if the operation failed.
355 NOTES
357 EXAMPLE
359 BUGS
361 SEE ALSO
363 INTERNALS
365 TODO
367 *****************************************************************************************/
368 IPTR UXIO__Hidd_UnixIO__Wait(OOP_Class *cl, OOP_Object *o, struct pHidd_UnixIO_Wait *msg)
370 int retval = 0;
371 int mode;
372 struct uioInterrupt myInt;
373 struct UnixIO_Waiter w;
375 /* Check if the fd is already ready. In this case we don't need to wait for anything. */
376 mode = Hidd_UnixIO_Poll(o, msg->FD, msg->Mode, &retval);
377 if (mode)
378 return (mode == -1) ? retval : 0;
380 w.signal = AllocSignal(-1);
381 if (w.signal == -1)
382 return ENOMEM;
384 w.task = FindTask(NULL);
386 myInt.fd = msg->FD;
387 myInt.mode = msg->Mode;
388 myInt.handler = WaitIntHandler;
389 myInt.handlerData = &w;
391 D(bug("[UnixIO] Adding interrupt 0x%P\n", &myInt));
393 retval = Hidd_UnixIO_AddInterrupt(o, &myInt);
394 D(bug("[UnixIO] Result: %d\n", retval));
396 if (!retval)
398 D(bug("[UnixIO] Waiting for signal...\n"));
399 Wait(1 << w.signal);
400 Hidd_UnixIO_RemInterrupt(o, &myInt);
403 FreeSignal(w.signal);
405 return retval;
408 /*****************************************************************************************
410 NAME
411 moHidd_UnixIO_OpenFile
413 SYNOPSIS
414 OOP_DoMethod(OOP_Object *obj, struct pHidd_UnixIO_OpenFile *msg);
416 int Hidd_UnixIO_OpenFile (OOP_Object *obj, const char *filename, int flags, int mode, int *errno_ptr);
418 LOCATION
419 unixio.hidd
421 FUNCTION
422 Open a UNIX file descriptor
424 INPUTS
425 obj - An pointer to a UnixIO object
426 filename - File name to open. File name should meet host OS conventions.
427 flags - Flags specifying open mode. These are the same flags as for
428 open() C function. Note that this value is passed directly to
429 the host OS, and its definition can differ from AROS one.
430 errno_ptr - An optional pointer to a location where error code (value of
431 UNIX errno variable) will be written
433 RESULT
434 A number of the opened file descriptor or -1 for an error.
436 NOTES
438 EXAMPLE
440 BUGS
442 SEE ALSO
443 moHidd_UnixIO_CloseFile
445 INTERNALS
447 TODO
449 *****************************************************************************************/
451 APTR UXIO__Hidd_UnixIO__OpenFile(OOP_Class *cl, OOP_Object *o, struct pHidd_UnixIO_OpenFile *msg)
453 struct unixio_base *data = UD(cl);
454 APTR retval;
456 D(bug("[UnixIO] OpenFile(%s, 0x%04X, %o)\n", msg->FileName, msg->Flags, msg->Mode));
458 HostLib_Lock();
460 retval = (APTR)(unsigned long)data->SysIFace->open(msg->FileName, (int)msg->Flags, (int)msg->Mode);
461 AROS_HOST_BARRIER
463 if (msg->ErrNoPtr)
464 *msg->ErrNoPtr = *data->uio_Public.uio_ErrnoPtr;
466 HostLib_Unlock();
468 D(bug("[UnixIO] FD is %d, errno is %d\n", retval, *data->uio_Public.uio_ErrnoPtr));
470 return retval;
473 /*****************************************************************************************
475 NAME
476 moHidd_UnixIO_CloseFile
478 SYNOPSIS
479 OOP_DoMethod(OOP_Object *obj, struct pHidd_UnixIO_CloseFile *msg);
481 int Hidd_UnixIO_CloseFile (OOP_Object *obj, int fd, int *errno_ptr);
483 LOCATION
484 unixio.hidd
486 FUNCTION
487 Close a UNIX file descriptor.
489 INPUTS
490 obj - A pointer to a UnixIO object.
491 fd - A file descriptor to close.
492 errno_ptr - An optional pointer to a location where error code (a value of UNIX
493 errno variable) will be written.
495 RESULT
496 0 in case of success and -1 on failure.
498 NOTES
499 Despite there's no return value, error code still can be set.
501 EXAMPLE
503 BUGS
505 SEE ALSO
506 moHidd_UnixIO_OpenFile
508 INTERNALS
510 TODO
512 *****************************************************************************************/
513 int UXIO__Hidd_UnixIO__CloseFile(OOP_Class *cl, OOP_Object *o, struct pHidd_UnixIO_CloseFile *msg)
515 struct unixio_base *data = UD(cl);
516 int ret = 0;
518 if (msg->FD != -1)
520 HostLib_Lock();
522 ret = data->SysIFace->close((long)msg->FD);
523 AROS_HOST_BARRIER
525 if (msg->ErrNoPtr)
526 *msg->ErrNoPtr = *data->uio_Public.uio_ErrnoPtr;
528 HostLib_Unlock();
531 return ret;
534 /*****************************************************************************************
536 NAME
537 moHidd_UnixIO_ReadFile
539 SYNOPSIS
540 OOP_DoMethod(OOP_Object *obj, struct pHidd_UnixIO_ReadFile *msg);
542 int Hidd_UnixIO_ReadFile(OOP_Object *obj, int fd, void *buffer, int count, int *errno_ptr);
544 LOCATION
545 unixio.hidd
547 FUNCTION
548 Read data from a UNIX file descriptor.
550 INPUTS
551 obj - A pointer to a UnixIO object.
552 fd - A file descriptor to read from.
553 buffer - A pointer to a buffer for data.
554 count - Number of bytes to read.
555 errno_ptr - An optional pointer to a location where error code (a value of UNIX
556 errno variable) will be written.
558 RESULT
559 Number of bytes actually read or -1 if error happened.
561 NOTES
562 If there's no errno pointer supplied read operation will be automatically repeated if one
563 of EINTR or EAGAIN error happens. If you supplied valid own errno_ptr you should be ready
564 to handle these conditions yourself.
566 This method can be called from within interrupts.
568 EXAMPLE
570 BUGS
572 SEE ALSO
573 moHidd_UnixIO_WriteFile
575 INTERNALS
577 TODO
579 *****************************************************************************************/
580 IPTR UXIO__Hidd_UnixIO__ReadFile(OOP_Class *cl, OOP_Object *o, struct pHidd_UnixIO_ReadFile *msg)
582 struct unixio_base *data = UD(cl);
583 int retval = -1;
584 volatile int err = EINVAL;
586 if (msg->FD != -1)
588 int user = !KrnIsSuper();
590 if (user)
591 HostLib_Lock();
595 retval = data->SysIFace->read((long)msg->FD, (void *)msg->Buffer, (size_t)msg->Count);
596 AROS_HOST_BARRIER
598 err = *data->uio_Public.uio_ErrnoPtr;
599 D(kprintf(" UXIO__Hidd_UnixIO__ReadFile: retval %d errno %d buff %x count %d\n", retval, err, msg->Buffer, msg->Count));
601 if (msg->ErrNoPtr)
602 break;
604 } while((err == EINTR) || (err == EAGAIN));
606 if (user)
607 HostLib_Unlock();
610 if (msg->ErrNoPtr)
611 *msg->ErrNoPtr = err;
613 D(if (retval == -1) kprintf("UXIO__Hidd_UnixIO__ReadFile: errno %d buff %x count %d\n", err, msg->Buffer, msg->Count));
615 return retval;
618 /*****************************************************************************************
620 NAME
621 moHidd_UnixIO_WriteFile
623 SYNOPSIS
624 OOP_DoMethod(OOP_Object *obj, struct pHidd_UnixIO_WriteFile *msg);
626 int Hidd_UnixIO_WriteFile(OOP_Object *obj, int fd, void *buffer, int count, int *errno_ptr);
628 LOCATION
629 unixio.hidd
631 FUNCTION
632 Write data to a UNIX file descriptor.
634 INPUTS
635 obj - A pointer to a UnixIO object.
636 fd - A file descriptor to write to.
637 buffer - A pointer to a buffer containing data.
638 count - Number of bytes to write.
639 errno_ptr - An optional pointer to a location where error code (a value of UNIX
640 errno variable) will be written.
642 RESULT
643 Number of bytes actually written or -1 if error happened.
645 NOTES
646 If there's no errno pointer supplied read operation will be automatically repeated if one
647 of EINTR or EAGAIN error happens. If you supplied valid own errno_ptr you should be ready
648 to handle these conditions yourself.
650 This method can be called from within interrupts.
652 EXAMPLE
654 BUGS
656 SEE ALSO
657 moHidd_UnixIO_ReadFile
659 INTERNALS
661 TODO
663 *****************************************************************************************/
664 IPTR UXIO__Hidd_UnixIO__WriteFile(OOP_Class *cl, OOP_Object *o, struct pHidd_UnixIO_WriteFile *msg)
666 struct unixio_base *data = UD(cl);
667 int retval = -1;
668 volatile int err = EINVAL;
670 if (msg->FD != -1)
672 int user = !KrnIsSuper();
674 if (user)
675 HostLib_Lock();
679 retval = data->SysIFace->write((long)msg->FD, (const void *)msg->Buffer, (size_t)msg->Count);
680 AROS_HOST_BARRIER
682 err = *data->uio_Public.uio_ErrnoPtr;
683 D(kprintf(" UXIO__Hidd_UnixIO__WriteFile: retval %d errno %d buff %x count %d\n", retval, err, msg->Buffer, msg->Count));
685 if (msg->ErrNoPtr)
686 break;
688 } while((retval < 1) && ((err == EINTR) || (err == EAGAIN) || (err == 0)));
690 if (user)
691 HostLib_Unlock();
694 if (msg->ErrNoPtr)
695 *msg->ErrNoPtr = err;
697 D(if (retval == -1) kprintf("UXIO__Hidd_UnixIO__WriteFile: errno %d buff %x count %d\n", err, msg->Buffer, msg->Count));
699 return retval;
702 /*****************************************************************************************
704 NAME
705 moHidd_UnixIO_IOControlFile
707 SYNOPSIS
708 OOP_DoMethod(OOP_Object *obj, struct pHidd_UnixIO_IOControlFile *msg);
710 int Hidd_UnixIO_IOControlFile(OOP_Object *obj, int fd, int request, void *param, int *errno_ptr);
712 LOCATION
713 unixio.hidd
715 FUNCTION
716 Perform a special operation (ioctl) on a UNIX file descriptor.
718 INPUTS
719 obj - A pointer to a UnixIO object.
720 fd - A file descriptor to operate on.
721 request - A device-specific operation code.
722 param - A pointer to a request-specific parameter block.
723 errno_ptr - An optional pointer to a location where error code (a value of UNIX
724 errno variable) will be written.
726 RESULT
727 Operation-specific value (actually a return value of ioctl() function called).
729 NOTES
730 This method can be called from within interrupts.
732 EXAMPLE
734 BUGS
736 SEE ALSO
738 INTERNALS
740 TODO
742 *****************************************************************************************/
743 IPTR UXIO__Hidd_UnixIO__IOControlFile(OOP_Class *cl, OOP_Object *o, struct pHidd_UnixIO_IOControlFile *msg)
745 struct unixio_base *data = UD(cl);
746 int err = EINVAL;
747 int retval = -1;
749 if (msg->FD != -1)
751 int user = !KrnIsSuper();
753 if (user)
754 HostLib_Lock();
756 retval = data->SysIFace->ioctl((long)msg->FD, (int)msg->Request, msg->Param);
757 AROS_HOST_BARRIER
759 err = *data->uio_Public.uio_ErrnoPtr;
761 if (user)
762 HostLib_Unlock();
765 if (msg->ErrNoPtr)
766 *msg->ErrNoPtr = err;
768 return retval;
771 /*****************************************************************************************
773 NAME
774 moHidd_UnixIO_AddInterrupt
776 SYNOPSIS
777 OOP_DoMethod(OOP_Object *obj, struct pHidd_UnixIO_AddInterrupt *msg);
779 int Hidd_UnixIO_AddInterrupt(OOP_Object *obj, struct uioInterrupt *interrupt);
781 LOCATION
782 unixio.hidd
784 FUNCTION
785 Install a filedescriptor-specific event interrupt handler
787 INPUTS
788 obj - An pointer to a UnixIO object
789 interrupt - A pointer to an interrupt descriptor structure initialized as follows:
790 fd - Number of file descriptor to watch
791 mode - one or more of mode flags
792 handler - A pointer to a handler routine.
793 handlerData - User-specified data for the interrupt handler
795 The interrupt handler routine will be called using C calling convention:
797 void handler(int fd, int mode, void *data)
799 where:
800 fd - File descriptor number
801 mode - Flags reflecting set of occured events
802 data - User data (specified in handlerData member of uioInterrupt structure)
804 RESULT
805 Zero if interrupt was succesfully installed and UNIX errno value if there was en error
806 during setting up the filedescriptor.
808 NOTES
810 EXAMPLE
812 BUGS
814 SEE ALSO
815 moHidd_UnixIO_RemInterrupt
817 INTERNALS
819 TODO
821 *****************************************************************************************/
822 int UXIO__Hidd_UnixIO__AddInterrupt(OOP_Class *cl, OOP_Object *o, struct pHidd_UnixIO_AddInterrupt *msg)
824 struct unixio_base *data = UD(cl);
825 int res;
826 int err;
828 Disable();
829 AddTail((struct List *)&data->intList, (struct Node *)msg->Int);
830 Enable();
832 /* Now own the filedescriptor and enable SIGIO on it */
833 HostLib_Lock();
835 res = data->SysIFace->fcntl(msg->Int->fd, F_SETOWN, data->aros_PID);
836 AROS_HOST_BARRIER
838 if (res != -1)
840 res = data->SysIFace->fcntl(msg->Int->fd, F_GETFL);
841 AROS_HOST_BARRIER
842 res = data->SysIFace->fcntl(msg->Int->fd, F_SETFL, res|O_ASYNC);
843 AROS_HOST_BARRIER
845 err = *data->uio_Public.uio_ErrnoPtr;
847 HostLib_Unlock();
849 if (res != -1)
850 return 0;
852 /* Remove the interrupt if something went wrong */
853 Hidd_UnixIO_RemInterrupt(o, msg->Int);
855 return err;
858 /*****************************************************************************************
860 NAME
861 moHidd_UnixIO_RemInterrupt
863 SYNOPSIS
864 OOP_DoMethod(OOP_Object *obj, struct pHidd_UnixIO_RemInterrupt *msg);
866 void Hidd_UnixIO_RemInterrupt(OOP_Object *obj, struct uioInterrupt *interrupt);
868 LOCATION
869 unixio.hidd
871 FUNCTION
872 Remove previously installed file descriptor event interrupt structure
874 INPUTS
875 obj - An pointer to a UnixIO object
876 interrupt - A pointer to a previously installed interrupt descriptor structure
878 RESULT
879 None.
881 NOTES
883 EXAMPLE
885 BUGS
887 SEE ALSO
888 moHidd_UnixIO_AddInterrupt
890 INTERNALS
892 TODO
894 *****************************************************************************************/
895 void UXIO__Hidd_UnixIO__RemInterrupt(OOP_Class *cl, OOP_Object *o, struct pHidd_UnixIO_RemInterrupt *msg)
897 Disable();
899 Remove((struct Node *)msg->Int);
901 Enable();
903 * We do not disable O_ASYNC because theoretically we can have more
904 * than one interrupt on a single fd.
905 * Anyway typically removing interrupt handler means the fd is not
906 * going to be used any more and will be closed soon.
910 /*****************************************************************************************
912 NAME
913 moHidd_UnixIO_Poll
915 SYNOPSIS
916 OOP_DoMethod(OOP_Object *obj, struct pHidd_UnixIO_Poll *msg);
918 int Hidd_UnixIO_Poll(OOP_Object *obj, int fd, int mode, int *errno_ptr);
920 LOCATION
921 unixio.hidd
923 FUNCTION
924 Check current status of UNIX file descriptor or -1 if an error occured.
926 INPUTS
927 obj - A pointer to a UnixIO object.
928 fd - A file descriptor to check.
929 mode - Mask of modes we are interested in.
930 errno_ptr - An optional pointer to a location where error code (a value of UNIX
931 errno variable) will be written.
933 RESULT
934 Current set of filedescriptor modes.
936 NOTES
937 This method can be called from within interrupts.
939 EXAMPLE
941 BUGS
943 SEE ALSO
945 INTERNALS
947 TODO
949 *****************************************************************************************/
950 ULONG UXIO__Hidd_UnixIO__Poll(OOP_Class *cl, OOP_Object *o, struct pHidd_UnixIO_Poll *msg)
952 struct unixio_base *data = UD(cl);
953 int user = !KrnIsSuper();
954 int ret;
956 if (user)
957 HostLib_Lock();
959 ret = poll_fd((int)(IPTR)msg->FD, msg->Mode, data);
960 if (msg->ErrNoPtr)
961 *msg->ErrNoPtr = *data->uio_Public.uio_ErrnoPtr;
963 if (user)
964 HostLib_Unlock();
966 return ret;
969 /*****************************************************************************************
971 NAME
972 moHidd_UnixIO_MemoryMap
974 SYNOPSIS
975 OOP_DoMethod(OOP_Object *obj, struct pHidd_UnixIO_MemoryMap *msg);
977 int Hidd_UnixIO_MemoryMap(OOP_Object *obj, OOP_Object *o, void *addr, int len, int prot, int flags, int fd, int offset, int *errno_ptr);
979 LOCATION
980 unixio.hidd
982 FUNCTION
983 Maps address into file descriptor.
985 INPUTS
986 obj - A pointer to a UnixIO object.
987 fd - A file descriptor to check.
988 errno_ptr - An optional pointer to a location where error code (a value of UNIX
989 errno variable) will be written.
991 RESULT
992 Actuall mapping address or MAP_FAILED for errors.
994 NOTES
995 This method can be called from within interrupts.
997 EXAMPLE
999 BUGS
1001 SEE ALSO
1003 INTERNALS
1005 TODO
1007 *****************************************************************************************/
1008 APTR UXIO__Hidd_UnixIO__MemoryMap(OOP_Class *cl, OOP_Object *o, struct pHidd_UnixIO_MemoryMap *msg)
1010 struct unixio_base *data = UD(cl);
1011 int user = !KrnIsSuper();
1012 APTR ret;
1014 if (user)
1015 HostLib_Lock();
1017 ret = data->SysIFace->mmap(msg->Address, msg->Length, msg->Prot, msg->Flags, (int)(IPTR)msg->FD, msg->Offset);
1018 if (msg->ErrNoPtr)
1019 *msg->ErrNoPtr = *data->uio_Public.uio_ErrnoPtr;
1021 if (user)
1022 HostLib_Unlock();
1024 return ret;
1027 /*****************************************************************************************
1029 NAME
1030 moHidd_UnixIO_MemoryUnMap
1032 SYNOPSIS
1033 OOP_DoMethod(OOP_Object *obj, struct pHidd_UnixIO_MemoryUnMap *msg);
1035 int Hidd_UnixIO_MemoryUnMap(OOP_Object *obj, OOP_Object *o, void *addr, int len, int *errno_ptr);
1037 LOCATION
1038 unixio.hidd
1040 FUNCTION
1041 Unmaps memory
1043 INPUTS
1044 obj - A pointer to a UnixIO object.
1045 errno_ptr - An optional pointer to a location where error code (a value of UNIX
1046 errno variable) will be written.
1048 RESULT
1049 0 for success, -1 for failure
1051 NOTES
1052 This method can be called from within interrupts.
1054 EXAMPLE
1056 BUGS
1058 SEE ALSO
1060 INTERNALS
1062 TODO
1064 *****************************************************************************************/
1065 IPTR UXIO__Hidd_UnixIO__MemoryUnMap(OOP_Class *cl, OOP_Object *o, struct pHidd_UnixIO_MemoryUnMap *msg)
1067 struct unixio_base *data = UD(cl);
1068 int user = !KrnIsSuper();
1069 IPTR ret;
1071 if (user)
1072 HostLib_Lock();
1074 ret = data->SysIFace->munmap(msg->Address, msg->Length);
1075 if (msg->ErrNoPtr)
1076 *msg->ErrNoPtr = *data->uio_Public.uio_ErrnoPtr;
1078 if (user)
1079 HostLib_Unlock();
1081 return ret;
1084 /* This is the initialisation code for the HIDD class itself. */
1086 static const char *libc_symbols[] =
1088 "open",
1089 "close",
1090 "ioctl",
1091 "fcntl",
1092 "poll",
1093 "read",
1094 "write",
1095 "getpid",
1096 #ifdef HOST_OS_linux
1097 "__errno_location",
1098 #else
1099 #ifdef HOST_OS_android
1100 "__errno",
1101 #else
1102 "__error",
1103 #endif
1104 #endif
1105 "mmap",
1106 "munmap",
1107 "socket",
1108 "sendto",
1109 "recvfrom",
1110 "bind",
1111 NULL
1114 #undef HostLibBase
1115 #undef KernelBase
1116 #define KernelBase LIBBASE->KernelBase
1117 #define HostLibBase LIBBASE->HostLibBase
1119 static int UXIO_Init(LIBBASETYPEPTR LIBBASE)
1121 ULONG i;
1123 D(bug("[UnixIO] Init\n"));
1125 KernelBase = OpenResource("kernel.resource");
1126 if (!KernelBase)
1127 return FALSE;
1129 HostLibBase = OpenResource("hostlib.resource");
1130 if (!HostLibBase)
1131 return FALSE;
1133 LIBBASE->SystemArch = (STRPTR)KrnGetSystemAttr(KATTR_Architecture);
1134 if (!LIBBASE->SystemArch)
1135 return FALSE;
1137 if (!CheckArch(LIBBASE, "unixio.hidd", AROS_ARCHITECTURE))
1138 return FALSE;
1140 LIBBASE->UnixIOAB = OOP_ObtainAttrBase(IID_Hidd_UnixIO);
1141 if (!LIBBASE->UnixIOAB)
1142 return FALSE;
1144 LIBBASE->uio_Public.uio_LibcHandle = HostLib_Open(LIBC_NAME, NULL);
1145 if (!LIBBASE->uio_Public.uio_LibcHandle)
1146 return FALSE;
1148 LIBBASE->SysIFace = (struct LibCInterface *)HostLib_GetInterface(LIBBASE->uio_Public.uio_LibcHandle, libc_symbols, &i);
1149 if ((!LIBBASE->SysIFace) || i)
1150 return FALSE;
1152 LIBBASE->irqHandle = KrnAddIRQHandler(SIGIO, SigIO_IntServer, LIBBASE, NULL);
1153 if (!LIBBASE->irqHandle)
1154 return FALSE;
1156 NewList((struct List *)&LIBBASE->intList);
1157 InitSemaphore(&LIBBASE->lock);
1159 LIBBASE->uio_Public.uio_ErrnoPtr = LIBBASE->SysIFace->__error();
1160 AROS_HOST_BARRIER
1161 LIBBASE->aros_PID = LIBBASE->SysIFace->getpid();
1162 AROS_HOST_BARRIER
1164 return TRUE;
1167 static int UXIO_Cleanup(struct unixio_base *LIBBASE)
1169 D(bug("[UnixIO] Expunging\n"));
1171 if ((!KernelBase) || (!HostLibBase))
1172 return TRUE;
1174 if (LIBBASE->irqHandle)
1175 KrnRemIRQHandler(LIBBASE->irqHandle);
1177 if (LIBBASE->SysIFace)
1178 HostLib_DropInterface ((APTR *)LIBBASE->SysIFace);
1180 if (LIBBASE->uio_Public.uio_LibcHandle)
1181 HostLib_Close(LIBBASE->uio_Public.uio_LibcHandle, NULL);
1183 if (LIBBASE->UnixIOAB)
1184 OOP_ReleaseAttrBase(IID_Hidd_UnixIO);
1186 return TRUE;
1189 /* The singleton gets really disposed only when we expunge its library */
1190 static int UXIO_Dispose(struct unixio_base *LIBBASE)
1192 if (LIBBASE->obj)
1194 OOP_MethodID mid = OOP_GetMethodID(IID_Root, moRoot_Dispose);
1196 D(bug("[UnixIO] Disposing object\n"));
1198 OOP_DoSuperMethod(LIBBASE->uio_unixioclass, LIBBASE->obj, &mid);
1199 LIBBASE->obj = NULL;
1202 return TRUE;
1205 ADD2INITLIB(UXIO_Init, 0)
1206 ADD2EXPUNGELIB(UXIO_Cleanup, 0)
1207 ADD2SET(UXIO_Dispose, CLASSESEXPUNGE, 0)