/* Copyright 2000 (c) by David Schweikert, 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/Drivers/Ethertap.c,v $ Author(s): Affiliation: ETH Zuerich, TIK Version: $Revision: 1.3 $ Creation Date: Last Date of Change: $Date: 2000/06/05 14:06:27 $ by: $Author: gfa $ $Log: Ethertap.c,v $ Revision 1.3 2000/06/05 14:06:27 gfa *** empty log message *** Revision 1.2 2000/04/05 12:04:57 gfa *** empty log message *** Revision 1.1 2000/03/31 17:50:32 gfa Merged with /Net from several term projects */ #include "Drivers/Ethertap.h" #include "Messages.h" #include "IODevice.h" #include "TMIPC.h" #include #define CONTROL_SEND 1 #define CONTROL_READ 2 void ethertap_interruptHandler(IODevice this) { Ethertap dev; unsigned short *rxlen; unsigned char *control; dev = (Ethertap) this->extension; if(dev->subscribed != 0) { /* Send notify message to subscribed thread. */ Message msg; msg.from=this->threadId; msg.id =IO_NOTIFY; msg.msg.ioNotify.deviceNumber = IO_ETHERTAP; rxlen = (unsigned short *) ((unsigned long)(this->base) +ETHERTAP_RX_SIZE); msg.msg.ioNotify.length = *rxlen; if(kSend(dev->subscribed, &msg)==TM_OK) return; // kSend failed... ioConsolePutString("Ethertap interrupt: kSend failed.\n"); } // packet is lost. set control_read... control = (unsigned char *) ((unsigned long)(this->base)+ETHERTAP_CONTROL_REGISTER); *control |= CONTROL_READ; } Error ethertap_init(IODevice this) { Ethertap dev; unsigned char *control; if (!this->isInitialised) { Ethertap tmp; tmp = this->extension; hmAlloc(&(this->extension), sizeof(EthertapDesc)); dev = (Ethertap)this->extension; this->isInitialised = TRUE; } else { dev = (Ethertap)this->extension; } control = (unsigned char *) ((unsigned long)(this->base)+ETHERTAP_CONTROL_REGISTER); *control |= CONTROL_READ; dev->subscribed=0; dev->fragment=0; return IO_INITOK; } /* - Control register (8 bit): * * Offset (bit) Description * ------------ -------------------------------- * 0 (LSM) Send data * 1 Data read * * * - Status register (8 bit): * * Offset (bit) Description * ------------ -------------------------------- * 0 (LSM) Received data */ Error ethertap_read(IODevice this, ThreadId threadId, char* buffer, long int* size) { unsigned short *rxlen; unsigned char *data; unsigned char *control; unsigned char *status; rxlen = (unsigned short *) ((unsigned long)(this->base)+ETHERTAP_RX_SIZE); data = (unsigned char *) ((unsigned long)(this->base)+ETHERTAP_RX_DATA); control = (unsigned char *) ((unsigned long)(this->base)+ETHERTAP_CONTROL_REGISTER); status = (unsigned char *) ((unsigned long)(this->base)+ETHERTAP_STATUS_REGISTER); if(*size < *rxlen || (*status & 1)==0) return IO_READFAILED; /* Copy from device to user memory */ byteCopy(buffer,data,*rxlen); *size = *rxlen; *control |= CONTROL_READ; return IO_READOK; } Error ethertap_write(IODevice this, ThreadId threadId, char* buffer, long int* size) { Ethertap dev; unsigned short *txlen; unsigned char *data; unsigned char *control; unsigned char *status; dev = (Ethertap) this->extension; txlen = (unsigned short *) ((unsigned long)(this->base)+ETHERTAP_TX_SIZE); data = (unsigned char *) ((unsigned long)(this->base)+ETHERTAP_TX_DATA); control = (unsigned char *) ((unsigned long)(this->base)+ETHERTAP_CONTROL_REGISTER); status = (unsigned char *) ((unsigned long)(this->base)+ETHERTAP_STATUS_REGISTER); if(*control & CONTROL_SEND) return IO_WRITEFAILED; if(!dev->fragment) { *txlen=0; } /* Copy from user memory to device */ byteCopy(data+*txlen,buffer,*size); *txlen += *size; if(!(dev->flags & ETHERTAP_FLAG_FRAGMENT)) { *control |= CONTROL_SEND; dev->fragment=0; } else { dev->fragment=1; } return IO_WRITEOK; } Error ethertap_close(IODevice this) { return IO_CLOSEOK; } void ethertap_handleMsg(IODevice this, Message *msg) { Message reply; Ethertap dev; unsigned char *addr; reply.from = this->threadId; dev = (Ethertap) this->extension; addr = (unsigned char *) ((unsigned long)(this->base)+ETHERTAP_HW_ADDRESS); switch (msg->id) { case IO_SUBSCRIBE: reply.id = IO_SUBSCRIBEREPLY; if(dev->subscribed == 0) { reply.msg.ioSubscribeReply.errorCode = IO_SUBSCRIBEOK; dev->subscribed = msg->from; } else { reply.msg.ioSubscribeReply.errorCode = IO_SUBSCRIBEFAILED; } kSend(msg->from, &reply); break; case IO_GETADDR: reply.id = IO_GETADDRREPLY; reply.msg.ioGetAddrReply.addr[0] = addr[0]; reply.msg.ioGetAddrReply.addr[1] = addr[1]; reply.msg.ioGetAddrReply.addr[2] = addr[2]; reply.msg.ioGetAddrReply.addr[3] = addr[3]; reply.msg.ioGetAddrReply.addr[4] = addr[4]; reply.msg.ioGetAddrReply.addr[5] = addr[5]; kSend(msg->from, &reply); break; default: reply.id = UNKNOWN_SYSCALL; kSend(msg->from, &reply); break; } }