/* IODevice.c, Copyright (c) by George Fankhauser, Swiss Federal Institute of Technology, Computer Engineering and Networks Laboratory. TOPSY -- A Teachable Operating System. Implementation of a tiny and simple micro kernel for teaching purposes. For further information, please visit http://www.tik.ee.ethz.ch/~topsy This software is provided under the terms of the GNU General Public Licence. A full copy of the GNU GPL is provided in the file COPYING found in the development root of Topsy. */ /* File: $Source: /usr/drwho/vault/cvs/topsy/Topsy/IO/IODevice.c,v $ Author(s): George Fankhauser Affiliation: ETH Zuerich, TIK Version: $Revision: 1.21 $ Creation Date: Last Date of Change: $Date: 2000/01/23 17:52:05 $ by: $Author: gfa $ $Log: IODevice.c,v $ Revision 1.21 2000/01/23 17:52:05 gfa support async IO by returning IO_LATER from read/write, return messages later from interrupt. Revision 1.20 1999/12/13 21:48:25 ruf GNU General Public Licence Update Revision 1.19 1999/01/06 17:47:34 cjeker code cleaning Revision 1.18 1998/06/08 21:14:14 gfa changed limits to Limits Revision 1.17 1997/04/18 16:27:47 conrad *** empty log message *** * Revision 1.16 1997/04/17 11:01:07 conrad * adding of ioDelayAtLeastCycles() function * * Revision 1.15 1997/04/13 15:30:53 gfa * fixed reply.id = UNKNOWN_SYSCALL * * Revision 1.14 1997/04/12 17:26:26 gfa * *** empty log message *** * * Revision 1.13 1997/04/12 15:57:40 gfa * address check now with overflow test * * Revision 1.12 1997/04/07 13:26:25 gfa * adapted framework * * Revision 1.11 97/04/07 07:49:59 gfa * added driver dummy function (used for consecutive writes to the same * address in optimized code) * * Revision 1.10 97/04/06 18:58:38 gfa * added address checks for user calls * * Revision 1.9 1997/03/23 12:45:08 gfa * *** empty log message *** * * Revision 1.8 1997/03/17 08:34:41 gfa * changed driver init message and location (moved to be after init) * * Revision 1.7 1997/03/16 22:15:15 gfa * *** empty log message *** * * Revision 1.6 1997/03/14 14:14:29 gfa * fixed expectedFrom (int/int*) type conflict in tmMsgRecv * * Revision 1.5 1997/02/21 08:57:47 conrad * Adding of ANYMSGTYPE parameter to tmMsgRecv() * * Revision 1.4 1997/02/17 16:51:34 gfa * first implementation * * Revision 1.3 1997/02/13 15:46:18 conrad * First compilation/linking of complete environment (all modules) * * Revision 1.2 1997/02/12 15:29:16 gfa * full interface defined, msg handler framework * * Revision 1.1 1997/02/04 11:20:51 topsy * Initial revision * */ #include "IODevice.h" #include "Messages.h" #include "Syscall.h" #include "Threads.h" #include "MMMapping.h" #include "Limits.h" /* This function introduces an artificial delay of at least nbLoops (actually * almost three times more) to cope with timing problems between cpu and devices */ int ioDelayAtLeastCycles( int nbLoops) { int i, k=0; for (i=0; i (unsigned long)spaceFrom + spaceSize || ULONG_MAX - (unsigned long)address < size) return FALSE; else return TRUE; } /* IO device main procedure. * Every device driver loops here and passes messages to its * driver implementation. * * If a driver handles special messages (other than read/write/close/init) * they are forwarded to its handleMsg function. */ void ioDeviceMain(IODevice this) { Message msg, reply; ThreadId expectedFrom; DriverMessage* driverMsg; int ret; while (TRUE) { expectedFrom = ANY; tmMsgRecv(&expectedFrom, ANYMSGTYPE, &msg, INFINITY); switch (msg.id) { case IO_READ: reply.id = IO_READREPLY; if (ioCheckBufferAddress(msg.from, msg.msg.ioRead.buffer, msg.msg.ioRead.size)) { ret = this->read(this, msg.from, msg.msg.ioRead.buffer, &(msg.msg.ioRead.size)); if (ret != IO_LATER) { reply.msg.ioReadReply.errorCode = IO_READOK; reply.msg.ioReadReply.bytesRead = msg.msg.ioRead.size; tmMsgSend(msg.from, &reply); } } else { reply.msg.ioReadReply.errorCode = IO_READFAILED; tmMsgSend(msg.from, &reply); } break; case IO_WRITE: reply.id = IO_WRITEREPLY; if (ioCheckBufferAddress(msg.from, msg.msg.ioWrite.buffer, msg.msg.ioWrite.size)) { ret = this->write(this, msg.from, msg.msg.ioWrite.buffer, &(msg.msg.ioWrite.size)); if (ret != IO_LATER) { reply.msg.ioWriteReply.errorCode = IO_WRITEOK; reply.msg.ioWriteReply.bytesWritten = msg.msg.ioWrite.size; tmMsgSend(msg.from, &reply); } } else { reply.msg.ioReadReply.errorCode = IO_WRITEFAILED; tmMsgSend(msg.from, &reply); } break; case IO_DRIVERCLOSE: /* check sender: we do not accept others than ioThread */ if (msg.from != IOTHREADID) { reply.id = UNKNOWN_SYSCALL; tmMsgSend(msg.from, &reply); break; } reply.id = IO_CLOSEREPLY; if (this->close != NULL) { ret = this->close(this); reply.msg.ioCloseReply.errorCode = ret; } else { reply.msg.ioCloseReply.errorCode = IO_CLOSEFAILED; } driverMsg = (DriverMessage*)&msg; tmMsgSend(driverMsg->clientThreadId, &reply); break; case IO_INIT: reply.id = IO_INITREPLY; if (this->init != NULL) { ret = this->init(this); reply.msg.ioInitReply.errorCode = ret; } else { reply.msg.ioInitReply.errorCode = IO_INITFAILED; } tmMsgSend(msg.from, &reply); break; default: if (this->handleMsg != NULL) { this->handleMsg(this, &msg); } else { reply.id = UNKNOWN_SYSCALL; tmMsgSend(msg.from, &reply); } } } }