/* * UUSER.C UUSER:devicename/unitnumber/options * UUSER:serial.device/0/R1000 * * options: * Rn Set read timeout when no data available to n millisecs * C0 Ignore carrier detect * * features: * 1K asynchronous write capability (write 0 bytes to sync up) * programmable read-timeout (Getty starts procs up w/ 1sec to) * * combined together, you can easily implement 100% efficient * protocols even with that 1 second read timeout! */ #include #include #include #include #include #include #include #include #include #define WRITEBUFSIZE 1024 #define MPC (MEMF_PUBLIC|MEMF_CLEAR) /* options to AllocMem() */ #define BTOC(x, type) ((type *)((long)x << 2)) #define CTOB(x) ((BPTR)((long)x >> 2)) #define DOS_FALSE 0 #define DOS_TRUE -1 typedef struct IOExtSer IOS; typedef struct timerequest IOT; typedef struct IORequest IOR; typedef struct timeval TimeVal; typedef struct FileLock LOCK; typedef struct DosPacket Packet; typedef struct Process PROC; typedef struct DeviceNode DEVNODE; typedef struct FileHandle FH; typedef struct Message MSG; typedef struct Node NODE; typedef struct List LIST; typedef struct MsgPort PORT; typedef struct SHandle { NODE Node; IOT Iot; /* wait-for-char and read req */ IOS Ios; IOS Iosr; /* 1005 */ IOS Iosw; /* 1005,1006 */ char IotIP; char IosrIP; char IoswIP; char RxIn[1]; /* one char buffer */ char *TxOut; /* asynch write buffer */ Packet *RPacket; /* current pending read packet */ Packet *WPacket; /* current pending write packet */ short Flags; LIST RxWait; /* requests waiting for data */ LIST TxWait; /* requests waiting to write */ LIST CxWait; /* wait for char */ TimeVal ReadTo; } SHandle; #define HF_IGNORECD 0x01 #define HF_CDLOST 0x02 #define HF_RTO 0x04 #define HF_DONTLOCK 0x08 /* if G option for from-getty */ extern Packet *taskwait(); /* wait for a message */ long SysBase; /* required to make Exec calls */ char ScrBuf[256]; /* Scratch buffer */ PORT *IoSink; LIST HanList; LIST NodList; IOT Iot; /* Iot master, also used for CD */ char IotIP; void AttemptRead(); void AttemptWrite(); void AbortPackets(); void StartTimer(); __saveds void _dummy() { PROC *myproc; DEVNODE *mynode; UBYTE notdone; long mask; SysBase = *(long *)4; IoSink = CreatePort(NULL, 0); NewList(&HanList); NewList(&NodList); Iot.tr_node.io_Message.mn_ReplyPort = IoSink; OpenDevice("timer.device", UNIT_VBLANK, &Iot, 0); Iot.tr_node.io_Command = TR_ADDREQUEST; Iot.tr_time.tv_secs = 4; Iot.tr_time.tv_micro= 0; SendIO(&Iot); IotIP = 1; myproc = (PROC *)FindTask(0L); /* * INITIAL STARTUP MESSAGE */ { Packet *mypkt; mypkt = taskwait(myproc); mynode = BTOC(mypkt->dp_Arg3, DEVNODE); mynode->dn_Task = &myproc->pr_MsgPort; returnpkt(mypkt, myproc, DOS_TRUE, 0); } loop: notdone = 1; mask = (1 << IoSink->mp_SigBit) | (1 << myproc->pr_MsgPort.mp_SigBit); while (notdone) { Packet *mypkt; /* dos packet received */ IOR *ior; SHandle *handle; long type; /* type of packet */ ior = (IOR *)GetMsg(IoSink); mypkt = (Packet *)GetMsg(&myproc->pr_MsgPort); if (mypkt) mypkt = (Packet *)(((MSG *)mypkt)->mn_Node.ln_Name); while (mypkt == NULL && ior == NULL) { Wait(mask); ior = (IOR *)GetMsg(IoSink); mypkt = (Packet *)GetMsg(&myproc->pr_MsgPort); if (mypkt) mypkt = (Packet *)(((MSG *)mypkt)->mn_Node.ln_Name); } /* * Make sure there is at least one free node in node list */ if (NodList.lh_Head == (NODE *)&NodList.lh_Tail) { NODE *pknode = AllocMem(sizeof(NODE), MPC); AddTail(&NodList, pknode); } /* * Returned IO request, sift through lists to find it. */ if (ior) { if (ior == &Iot) { /* Check for carrier lost */ for (handle = (SHandle *)HanList.lh_Head; handle != (SHandle *)&HanList.lh_Tail; handle = (SHandle *)handle->Node.ln_Succ) { if (!(handle->Flags & HF_IGNORECD) && !(handle->Flags & HF_CDLOST)) { handle->Ios.IOSer.io_Command = SDCMD_QUERY; DoIO(&handle->Ios); if (handle->Ios.io_Status & CIAF_COMCD) { handle->Flags |= HF_CDLOST; AbortPackets(handle, myproc); } } } if (HanList.lh_Head == (NODE *)&HanList.lh_Tail) { IotIP = 0; } else { Iot.tr_time.tv_secs = 4; Iot.tr_time.tv_micro= 0; SendIO(&Iot); IotIP = 1; } } else for (handle = (SHandle *)HanList.lh_Head; handle != (SHandle *)&HanList.lh_Tail; handle = (SHandle *)handle->Node.ln_Succ) { if (ior == (IOR *)&handle->Iosr) { returnpkt(handle->RPacket, myproc, handle->Iosr.IOSer.io_Actual, 0); handle->IosrIP = 0; handle->RPacket = NULL; if (handle->IotIP) { AbortIO(&handle->Iot); WaitIO(&handle->Iot); handle->IotIP = 0; } AttemptRead(handle, myproc); } if (ior == (IOR *)&handle->Iosw) { handle->IoswIP = 0; if (handle->WPacket) { handle->Iosw.IOSer.io_Data = (APTR)handle->TxOut; handle->Iosw.IOSer.io_Length= handle->WPacket->dp_Arg3 - handle->WPacket->dp_Res1; SendIO(&handle->Iosw); handle->IoswIP = 1; handle->WPacket->dp_Res1 = handle->WPacket->dp_Arg3; returnpktplain(handle->WPacket, myproc); handle->WPacket = NULL; } else { AttemptWrite(handle, myproc); } } if (ior == (IOR *)&handle->Iot) { handle->IotIP = 0; if ((handle->Flags & HF_RTO) && handle->IosrIP) { AbortIO(&handle->Iosr); } } } } if (mypkt) { mypkt->dp_Res1 = DOS_TRUE; /* default return value */ mypkt->dp_Res2 = 0; /* default no error */ type = mypkt->dp_Type; /* packet type */ /* * Extract pipe pointer (only applies to read/write) */ handle = (SHandle *)mypkt->dp_Arg1; /* READ/WRITE only */ switch(type) { case ACTION_FINDINPUT: case ACTION_FINDOUTPUT: case ACTION_FINDUPDATE: if (IotIP == 0) StartTimer(4); { FH *fh = BTOC(mypkt->dp_Arg1, FH); char *path = BTOC(mypkt->dp_Arg3, char); char *unit; long n; movmem(path + 1, ScrBuf, *path); ScrBuf[*path] = 0; path = ScrBuf; handle = AllocMem(sizeof(SHandle), MPC); if (strcmp(ScrBuf, "*") == 0) strcpy(ScrBuf, "serial.device/0"); for (unit = path; *unit && *unit != '/'; ++unit) { if (*unit == ':') path = unit + 1; } if (*unit == '/') { char *opts; *unit = 0; ++unit; for (opts = unit; *opts && *opts != '/'; ++opts); while (*opts) { n = atoi(opts + 1); switch(*opts) { case '/': break; case 'R': handle->ReadTo.tv_secs = n / 1000; handle->ReadTo.tv_micro= (n % 1000) * 1000; handle->Flags |= HF_RTO; break; case 'C': handle->Flags |= HF_IGNORECD; break; case 'G': if (n) handle->Flags |= HF_DONTLOCK; break; } ++opts; } } /* proc = (PROC *)mypkt->dp_Port->mp_SigTask; */ /* * Open the device */ handle->Ios.IOSer.io_Message.mn_ReplyPort = IoSink; handle->Ios.io_SerFlags = SERF_XDISABLED | SERF_RAD_BOOGIE | SERF_SHARED; if (OpenDevice(path, atoi(unit), &handle->Ios, 0)) { FreeMem(handle, sizeof(SHandle)); mypkt->dp_Res1 = DOS_FALSE; mypkt->dp_Res2 = ERROR_OBJECT_NOT_FOUND; returnpktplain(mypkt, myproc); break; } fh->fh_Arg1 = (long)handle; fh->fh_Port = (struct MsgPort *)DOS_TRUE; handle->Iosr = handle->Ios; handle->Iosw = handle->Ios; handle->Iosr.IOSer.io_Command = CMD_READ; handle->Iosw.IOSer.io_Command = CMD_WRITE; handle->Iot = Iot; NewList(&handle->RxWait); NewList(&handle->TxWait); NewList(&handle->CxWait); AddTail(&HanList, handle); returnpktplain(mypkt, myproc); } break; case ACTION_END: Remove(handle); if (handle->IosrIP) { AbortIO(&handle->Iosr); WaitIO(&handle->Iosr); } if (handle->IoswIP) { WaitIO(&handle->Iosw); } if (handle->IotIP) { AbortIO(&handle->Iot); WaitIO(&handle->Iot); } AbortPackets(handle, myproc); CloseDevice(&handle->Ios); returnpktplain(mypkt, myproc); if (handle->TxOut) FreeMem(handle->TxOut, WRITEBUFSIZE); FreeMem(handle, sizeof(SHandle)); break; case ACTION_READ: { NODE *pknode = RemHead(&NodList); mypkt->dp_Res1 = 0; pknode->ln_Name = (char *)mypkt; AddTail(&handle->RxWait, pknode); AttemptRead(handle, myproc); } break; case ACTION_WRITE: { NODE *pknode = RemHead(&NodList); mypkt->dp_Res1 = 0; pknode->ln_Name = (char *)mypkt; AddTail(&handle->TxWait, pknode); AttemptWrite(handle, myproc); } break; case ACTION_WAIT_CHAR: default: returnpkt(mypkt, myproc, DOS_FALSE, ERROR_ACTION_NOT_KNOWN); break; } } } /* * Can only exit if no messages pending. There might be a window * here, but there is nothing that can be done about it. */ Forbid(); if (taskpktrdy(myproc)) { Permit(); goto loop; } mynode->dn_Task = FALSE; Permit(); if (IotIP) { AbortIO(&Iot); WaitIO(&Iot); } CloseDevice(&Iot); /* we are a process "so we fall off the end of the world" */ /* MUST fall through */ } void AttemptRead(handle, myproc) SHandle *handle; PROC *myproc; { Packet *mypkt; NODE *pknode; if (handle->Flags & HF_CDLOST) { AbortPackets(handle, myproc); return; } loop: if (handle->IosrIP == 0 && (pknode = RemHead(&handle->RxWait))) { long n; AddTail(&NodList, pknode); mypkt = (Packet *)pknode->ln_Name; /* * special case. If you read 0 bytes, 0 is returned if data * is pending, else -1, and NO timeout occurs. */ handle->Ios.IOSer.io_Command = SDCMD_QUERY; DoIO(&handle->Ios); if (mypkt->dp_Arg3 == 0) { if (handle->Ios.IOSer.io_Actual > 0) returnpkt(mypkt, myproc, 0, 0); /* 0=data rdy */ else returnpkt(mypkt, myproc, -1, 0); /* -1=data not rdy */ goto loop; } if ((n = handle->Ios.IOSer.io_Actual) > 0) { if (n > mypkt->dp_Arg3) n = mypkt->dp_Arg3; handle->Iosr.IOSer.io_Data = (APTR)mypkt->dp_Arg2; handle->Iosr.IOSer.io_Length = n; DoIO(&handle->Iosr); mypkt->dp_Res1 = handle->Iosr.IOSer.io_Actual; returnpktplain(mypkt, myproc); goto loop; } handle->Iosr.IOSer.io_Data = (APTR)mypkt->dp_Arg2; handle->Iosr.IOSer.io_Length = 1; SendIO(&handle->Iosr); handle->IosrIP = 1; handle->RPacket = mypkt; if (handle->Flags & HF_RTO) { if (handle->IotIP) { AbortIO(&handle->Iot); WaitIO(&handle->Iot); } handle->Iot.tr_time = handle->ReadTo; SendIO(&handle->Iot); handle->IotIP = 1; } } } void AttemptWrite(handle, myproc) SHandle *handle; PROC *myproc; { Packet *mypkt; NODE *pknode; if (handle->Flags & HF_CDLOST) { AbortPackets(handle, myproc); return; } if (handle->IoswIP == 0 && (pknode = RemHead(&handle->TxWait))) { AddTail(&NodList, pknode); mypkt = (Packet *)pknode->ln_Name; if (handle->TxOut == NULL) handle->TxOut = AllocMem(WRITEBUFSIZE, MPC); if (mypkt->dp_Arg3 <= WRITEBUFSIZE) { /* fully asynch */ movmem((char *)mypkt->dp_Arg2, handle->TxOut, mypkt->dp_Arg3); handle->Iosw.IOSer.io_Data = (APTR)handle->TxOut; handle->Iosw.IOSer.io_Length = mypkt->dp_Arg3; SendIO(&handle->Iosw); mypkt->dp_Res1 = mypkt->dp_Arg3; returnpktplain(mypkt, myproc); handle->WPacket = NULL; } else { /* semi-asynch */ long n = mypkt->dp_Arg3 - WRITEBUFSIZE; handle->Iosw.IOSer.io_Data = (APTR)mypkt->dp_Arg2; handle->Iosw.IOSer.io_Length = n; SendIO(&handle->Iosw); movmem((char *)mypkt->dp_Arg2 + n, handle->TxOut, WRITEBUFSIZE); mypkt->dp_Res1 += n; handle->WPacket = mypkt; } handle->IoswIP = 1; } } void AbortPackets(handle, myproc) SHandle *handle; { NODE *pknode; Packet *mypkt; if (handle->RPacket) returnpktplain(handle->RPacket, myproc); if (handle->WPacket) returnpktplain(handle->RPacket, myproc); handle->RPacket = NULL; handle->WPacket = NULL; while (pknode = RemHead(&handle->RxWait)) { mypkt = (Packet *)pknode->ln_Name; if (mypkt->dp_Arg3 == 0) mypkt->dp_Res1 = 0; /* for poll, return data rdy */ else mypkt->dp_Res1 = -1; returnpktplain(mypkt, myproc); AddTail(&NodList, pknode); } while (pknode = RemHead(&handle->TxWait)) { mypkt = (Packet *)pknode->ln_Name; mypkt->dp_Res1 = -1; returnpktplain(mypkt, myproc); AddTail(&NodList, pknode); } } void StartTimer(secs) { if (IotIP) { AbortIO(&Iot); WaitIO(&Iot); } Iot.tr_time.tv_secs = secs; Iot.tr_time.tv_micro= 0; SendIO(&Iot); IotIP = 1; }