]> pd.if.org Git - mmurtl/commitdiff
autocommit for file dated 1995-02-09 11:15:30
authorRichard Burgess <>
Thu, 9 Feb 1995 11:15:30 +0000 (11:15 +0000)
committerNathan Wagner <nw@hydaspes.if.org>
Mon, 17 Oct 2016 14:03:48 +0000 (14:03 +0000)
ossource/parallel.c [new file with mode: 0644]

diff --git a/ossource/parallel.c b/ossource/parallel.c
new file mode 100644 (file)
index 0000000..8843a9a
--- /dev/null
@@ -0,0 +1,557 @@
+/*  Centronics Parallel Device Driver (1 channel v1.0). */\r
+/*  Copyright 1991,1992,1993,1994 R.A. Burgess */\r
+/*  ALL RIGHTS RESERVED */\r
+\r
+/* This driver is NOT interrupt driven because documentation\r
+   on interrupt usage with the parallel I/O device is sketchy at best..\r
+   We compensate for this by creating a separate task that is a\r
+   loop which statuses and continues to try to send all the data\r
+   without eating too much processor bandwidth.\r
+*/\r
+\r
+#define U32 unsigned long\r
+#define S32 long\r
+#define U16 unsigned int\r
+#define S16 int\r
+#define U8 unsigned char\r
+#define S8 char\r
+#define TRUE   1\r
+#define FALSE  0\r
+\r
+#include "parallel.h"\r
+\r
+/* MMURTL OS Prototypes */\r
+\r
+extern far U32 AllocExch(U32 *pExchRet);\r
+\r
+extern far U32 InitDevDr(U32 dDevNum,\r
+                                         S8  *pDCBs,\r
+                                                 U32 nDevices,\r
+                                                 U32 dfReplace);\r
+\r
+\r
+extern far U32 UnMaskIRQ(U32 IRQNum);\r
+extern far U32 MaskIRQ(U32 IRQNum);\r
+extern far U32 SetIRQVector(U32 IRQNum, S8  *pIRQ);\r
+extern far U32 EndOfIRQ(U32 IRQNum);\r
+extern far U32 SendMsg(U32 Exch, U32 msg1, U32 msg2);\r
+extern far U32 ISendMsg(U32 Exch, U32 msg1, U32 msg2);\r
+extern far U32 WaitMsg(U32 Exch, S8  *pMsgRet);\r
+extern far U32 CheckMsg(U32 Exch, S8  *pMsgRet);\r
+extern far U32 GetTimerTick(U32 *pTickRet);\r
+extern far U32 Alarm(U32 Exch, U32 count);\r
+extern far U32 KillAlarm(U32 Exch);\r
+extern far U32 Sleep(U32 count);\r
+extern far void MicroDelay(U32 us15count);\r
+extern far void OutByte(U8 Byte, U16 wPort);\r
+extern far U8 InByte(U16 wPort);\r
+extern far void CopyData(U8 *pSource, U8 *pDestination, U32 dBytes);\r
+\r
+extern far SpawnTask(S8  *pEntry,\r
+                            U32 dPriority,\r
+                     U32 fDebug,\r
+                     S8  *pStack,\r
+                            U32 fOSCode);\r
+\r
+extern far long GetJobNum(long *pJobNumRet);\r
+\r
+/* local prototypes. These will be called form the device driver interface. */\r
+\r
+static U32 lptdev_stat(U32  dDevice,\r
+                       S8  *pStatRet,\r
+                       U32 dStatusMax,\r
+                       U32 *pdStatusRet);\r
+\r
+static S32 lptdev_init(U32  dDevice,\r
+                       S8  *pInitData,\r
+                       U32  sdInitData);\r
+\r
+static U32 lptdev_op(U32 dDevice,\r
+                     U32 dOpNum,\r
+                     U32 dLBA,\r
+                     U32 dnBlocks,\r
+                     U8  *pData);\r
+\r
+\r
+/* The following definitions are used to identify, set\r
+   and reset signal line conditions and functions.\r
+*/\r
+\r
+#define SSENDBUF 4096       /* 4K Send Buf */\r
+\r
+unsigned char SendBuf[SSENDBUF];\r
+\r
+static U32  xmit_timeout = 100; /* 10ms intervals - 1 second */\r
+\r
+static U32  head_send;  /* Next char to send */\r
+static U32  tail_send;  /* Where next char goes in buf */\r
+static U32  cSendBuf;   /* Count of bytes in buf */\r
+static U32  sSendBuf;   /* Size of buffer (allocated) */\r
+static U32  burstcount;  /* for burst of chars to lpt */\r
+static U32  strobecount; /* tries to strobe the char out */\r
+\r
+static U8   control_byte = 0;\r
+\r
+ /* Control, Data & Status Registers for port */\r
+\r
+static U16      DAT;        /* Data output register */\r
+static U16      STA;        /* Status Register */\r
+static U16      STC;        /* Status/Control Register */\r
+\r
+static U32 lptStk[200];  /* 800 byte stack for this task */\r
+static U32 lptStkTop;\r
+\r
+/* Complete description of Register bits follows:\r
+\r
+    DAT -- Bits 0-7 of data output pins\r
+\r
+                7 6 5 4 3 2 1 0\r
+                 \_\_\_\_\_\_\_\__ Data out Bits\r
+\r
+    STA -- Status Register\r
+                1 1 0 1 1 1 1 1\r
+                7 6 5 4 3 2 1 0\r
+                | | | | |  \_\_\_ Not Used\r
+                | | | |  \_______ Error Status (Input (P15)\r
+                | | |  \_________ Select Status (Input P13)\r
+                | |  \___________ Out of Paper Status (Input P12)\r
+                |  \_____________ Acknoledge Status (Input P10)\r
+                 \_______________ Busy Status (Input P11)\r
+\r
+\r
+    STC -- Status/Control Register\r
+\r
+                7 6 5 4 3 2 1 0\r
+                | | | | | | |  \_ Strobe Inverted (Input/Output P1)\r
+                | | | | | |  \___ AutoFeed Inverted (Input/Output P14)\r
+                | | | | |  \_____ Initialize (Input/Output P16)\r
+                | | | |  \_______ Select Inverted (Input/Output P17)\r
+                | | |  \_________ Status IRQ Enable (Input)\r
+                 \_\_\___________ Not Used\r
+\r
+*/\r
+\r
+\r
+/* Record for 64 byte status and init record */\r
+/* This structure is peculiar to the lpt driver */\r
+\r
+#define sStatus 64\r
+\r
+static struct statRecL lptstat;\r
+static struct statRecL *pPS;\r
+\r
+static struct dcbtype\r
+{\r
+    S8   Name[12];\r
+    S8   sbName;\r
+    S8   type;\r
+    S16  nBPB;\r
+    U32  last_erc;\r
+    U32  nBlocks;\r
+    S8  *pDevOp;\r
+    S8  *pDevInit;\r
+    S8  *pDevSt;\r
+    S8   fDevReent;\r
+    S8   fSingleUser;\r
+    S16  wJob;\r
+    U32  OS1;\r
+    U32  OS2;\r
+    U32  OS3;\r
+    U32  OS4;\r
+    U32  OS5;\r
+    U32  OS6;\r
+    };\r
+\r
+static struct dcbtype lptdcb;          /* One parallel port */\r
+\r
+\r
+/********************************************************************\r
+ This small function becomes a thread (task) to feel the printer.\r
+ It checks to see if there is data in the buffer, and if so it\r
+ sends the dat out in bursts of characters.  It also properly sets\r
+ the status byte in the lptstat block so proper errors can be\r
+ returned to callers of the device driver.\r
+**********************************************************************/\r
+\r
+static void lpt_task(void)\r
+{\r
+       while (1)\r
+       {\r
+               /* Get lpt status every half second even if no data\r
+               is in buffer for those that may want it.\r
+               */\r
+\r
+               control_byte = InByte(STA);  /* Get status Byte from STA */\r
+               lptstat.status = control_byte;\r
+\r
+               if (cSendBuf)\r
+               {\r
+            burstcount = 10;\r
+\r
+                       while ((cSendBuf) && (burstcount--))\r
+                       {\r
+                               /* see if port is busy. If so, sleep 20ms, else send burst */\r
+\r
+                               control_byte = InByte(STA);  /* Get status Byte from STA */\r
+                               lptstat.status = control_byte;\r
+\r
+                               if (control_byte & LPTBUSY)\r
+                           {\r
+#asm\r
+       CLI\r
+#endasm\r
+                           OutByte(SendBuf[tail_send], DAT);  /* Send the byte */\r
+                           if (++tail_send == sSendBuf)\r
+                                       tail_send = 0;\r
+                               --cSendBuf;\r
+#asm\r
+       STI\r
+#endasm\r
+                               OutByte(0x0d, STC); /* Strobe High */\r
+                               OutByte(0x0c, STC); /* Strobe Low */\r
+                               }\r
+                           else\r
+                                       Sleep(2);\r
+                       }\r
+                       Sleep(1);  /* eliminate busyloop... */\r
+               }\r
+               else\r
+                       Sleep(30);      /* sleep for a .3 seconds */\r
+       }\r
+}\r
+\r
+/*********************************************************\r
+    This is called ONCE to initialize the 1 default\r
+    lpt channel with the OS device driver interface.\r
+*********************************************************/\r
+\r
+U32  lpt_setup(void)\r
+{\r
+U32  erc;\r
+\r
+  /* first we set up the DCB in anticipation of calling InitDevDr */\r
+\r
+    lptdcb.Name[0]  = 'L';\r
+    lptdcb.Name[1]  = 'P';\r
+    lptdcb.Name[2]  = 'T';\r
+    lptdcb.sbName   = 3;\r
+    lptdcb.type     = 2;                       /* Sequential */\r
+    lptdcb.nBPB     = 1;                       /* 1 byte per block */\r
+    lptdcb.nBlocks  = 0;                       /* 0 for Sequential devices */\r
+    lptdcb.pDevOp   = &lptdev_op;\r
+    lptdcb.pDevInit = &lptdev_init;\r
+    lptdcb.pDevSt   = &lptdev_stat;\r
+\r
+    /* Set default lpt params in stat records */\r
+\r
+    lptstat.XTimeOut = 100;    /* 1 second */\r
+    lptstat.IOBase = 0x378;\r
+    lptstat.IRQNum = 7;                        /* Not used right now */\r
+    lptstat.XBufSize = 4096;\r
+    sSendBuf = 4096;\r
+\r
+       DAT = lptstat.IOBase;           /* Data output register */\r
+       STA = lptstat.IOBase +1;        /* Status Register */\r
+       STC = lptstat.IOBase +2;        /* Status/Control Register */\r
+\r
+       cSendBuf = 0;\r
+       head_send = 0;\r
+       tail_send = 0;\r
+\r
+    OutByte(0x08, STC); /* Reset (Init) Line Low */\r
+       MicroDelay(100);  /* 1500us ought to do it */\r
+    OutByte(0x0C, STC); /* No ints, No AutoLF, Init High */\r
+\r
+       erc = SpawnTask( &lpt_task, 19, 0, &lptStkTop, 1);\r
+       if (erc)\r
+               return(erc);\r
+\r
+    return(erc = InitDevDr(3, &lptdcb, 1, 1));\r
+}\r
+\r
+/********************************************/\r
+static long WriteByteL(unsigned char b)\r
+{\r
+\r
+U32 erc, counter;\r
+U8 *pXBuf;\r
+\r
+       erc = 0;\r
+       counter = lptstat.XTimeOut;             /* set up for timeout */\r
+\r
+       while (cSendBuf == sSendBuf)\r
+       {\r
+               Sleep(1);\r
+               counter--;\r
+               if  (!counter)\r
+                       return (ErcXmitTimeoutL);               /* never got sent */\r
+       }\r
+\r
+#asm\r
+       CLI\r
+#endasm\r
+\r
+    SendBuf[head_send] = b;\r
+    if (++head_send == sSendBuf)\r
+         head_send  = 0;\r
+       ++cSendBuf;                             /* one more in buf */\r
+\r
+#asm\r
+       STI\r
+#endasm\r
+       return (erc);\r
+}\r
+\r
+\r
+/********************************************/\r
+static long WriteRecordL(unsigned char *pSendData,\r
+                         unsigned int cbSendData)\r
+{\r
+int erc;\r
+\r
+       erc = 0;\r
+    while ((cbSendData) && (!erc))\r
+    {\r
+               erc = WriteByteL(*pSendData++);\r
+               --cbSendData;\r
+       }\r
+       return (erc);\r
+}\r
+\r
+/********************************************\r
+ This allocates a buffer for use driver use.\r
+*********************************************/\r
+\r
+static U32  OpenLPT(void)\r
+\r
+{\r
+U32  erc, Job;\r
+U16  port_base;\r
+U8   c;\r
+\r
+       GetJobNum(&Job);\r
+\r
+       if (lptstat.lptJob)\r
+       {\r
+               if (Job != lptstat.lptJob)\r
+                       return(ErcChannelOpenL);        /* differnet job */\r
+               else\r
+                       return(0); /* same job - already open */\r
+       }\r
+\r
+       lptstat.lptJob = Job;\r
+\r
+       /* Set up buffer variables for this job */\r
+\r
+       if (!cSendBuf)\r
+       {\r
+               cSendBuf = 0;\r
+               head_send = 0;\r
+               tail_send = 0;\r
+       }\r
+       port_base = lptstat.IOBase;\r
+\r
+       DAT = port_base;                /* Data output register */\r
+       STA = port_base +1;             /* Status Register */\r
+       STC = port_base +2;             /* Status/Control Register */\r
+\r
+       return (0);\r
+}\r
+\r
+/********************************************\r
+ This closes the port, sets the owner to 0\r
+ and deallocates the buffers.  If there is\r
+ still data to send, this diables ints,\r
+ kills the buffer, then closes it.\r
+********************************************/\r
+\r
+static int  CloseLPT (int fAbort)\r
+{\r
+U32 erc, Job;\r
+\r
+       GetJobNum(&Job);\r
+\r
+       if (lptstat.lptJob)\r
+       {\r
+               if (Job != lptstat.lptJob)\r
+                       return(ErcNotOwnerL);   /* differnet job */\r
+               else\r
+                       return(0); /* same job - already open */\r
+       }\r
+       else\r
+               return(ErcNotOpenL);    /* Ports not open! */\r
+\r
+       if (fAbort)\r
+       {\r
+               cSendBuf = 0;\r
+               head_send = 0;\r
+               tail_send = 0;\r
+       }\r
+\r
+       lptstat.lptJob = 0;\r
+       return(0);\r
+}\r
+\r
+/***************************************************************************\r
+Now begins the PUBLIC routines that are interfaced to for all DEVICE DRIVERS\r
+****************************************************************************/\r
+\r
+/******************************************\r
+Called for all device operations.  This\r
+assigns physical device from logical number\r
+that outside callers use. For RS-232, 5=0\r
+and 6=1.\r
+*******************************************/\r
+\r
+static U32 lptdev_op(U32 dDevice,\r
+                   U32 dOpNum,\r
+                   U32 dLBA,\r
+                   U32 dnBlocks,\r
+                   U8  *pData)\r
+{\r
+U32 erc;\r
+U32 Job;\r
+U8 c;\r
+\r
+       GetJobNum(&Job);\r
+\r
+       if ((!lptstat.lptJob) && (dOpNum != CmdOpenL))\r
+               return(ErcNotOpenL);\r
+\r
+       if (lptstat.lptJob)\r
+       {\r
+               if ((lptstat.lptJob != Job) &&\r
+                       (Job != 1))\r
+                       return(ErcNotOwnerL);\r
+       }\r
+\r
+       erc = 0;                /* default error */\r
+\r
+       switch(dOpNum)\r
+       {\r
+               case(0):\r
+                       break;                          /* Null Command */\r
+               case CmdWriteB:\r
+                       erc = WriteByteL(*pData);\r
+                       break;\r
+               case CmdWriteRec:\r
+                       erc = WriteRecordL(pData, dnBlocks);\r
+                       break;\r
+               case CmdSetXTO:\r
+                       lptstat.XTimeOut = dLBA;                /* 10ms intervals */\r
+                       break;\r
+               case CmdOpenL:\r
+                       erc =  OpenLPT();\r
+                       break;\r
+               case CmdCloseL:\r
+                       erc =  CloseLPT(0);\r
+                       break;\r
+               case CmdCloseLU:\r
+                       erc =  CloseLPT(1);\r
+                       break;\r
+               default:\r
+                       erc = ErcBadOpNum;              /* default error */\r
+                       break;\r
+       }\r
+\r
+       lptstat.LastErc = erc;\r
+       return(erc);\r
+}\r
+\r
+\r
+/******************************************\r
+Called for status report on lpt channel.\r
+Returns 64 byte block for channel specified.\r
+This is called by the PUBLIC call DeviceStat\r
+*******************************************/\r
+\r
+static U32 lptdev_stat(U32  dDevice,\r
+                         S8  *pStatRet,\r
+                         U32 dStatusMax,\r
+                         U32 *pdStatusRet)\r
+{\r
+U32 i;\r
+\r
+       if (dStatusMax > 64)\r
+               i = 64;\r
+       else\r
+           i = dStatusMax;\r
+\r
+    lptstat.BufCnt = cSendBuf;\r
+\r
+       CopyData(&lptstat, pStatRet, i);                /* copy the status data */\r
+       *pdStatusRet = dStatusMax;              /* give em the size returned */\r
+       return(0);\r
+}\r
+\r
+/******************************************\r
+Called to set parameters for the lpt\r
+channel prior to opening or while in use.\r
+If an invalid value is passed in, all params\r
+remain the same as before.\r
+This is called by the PUBLIC call DeviceInit.\r
+Only the timeout value may be changed while\r
+the port is open.\r
+*******************************************/\r
+\r
+static S32 lptdev_init(U32  dDevice,\r
+                        S8  *pInitData,\r
+                        U32  sdInitData)\r
+\r
+{\r
+U32  erc, Xbufsize,    XTO, job;\r
+U16  port_base;\r
+U8   IRQNUM;\r
+\r
+       erc = 0;\r
+\r
+       GetJobNum(&job);\r
+       if ((lptstat.lptJob) && (lptstat.lptJob != job))\r
+               return(ErcNotOwnerL);   /* Port is in use, and not by you! */\r
+\r
+       if (sdInitData < 40)\r
+               return(ErcBadInitSizeL);\r
+\r
+       pPS = pInitData;\r
+\r
+       /* Get the callers new params into local vars */\r
+\r
+       XTO       = pPS->XTimeOut;      /* Non Volatile */\r
+       port_base = pPS->IOBase;\r
+\r
+       /* Volatile params can not change while port is open. */\r
+\r
+       if (lptstat.lptJob)             /* Port is in use */\r
+       {\r
+       if (lptstat.IOBase != port_base)\r
+               erc = ErcChannelOpenL;\r
+       }\r
+\r
+       /* Non Volatile params can be set whether or not the\r
+          channel is open. */\r
+\r
+    if (!XTO)  XTO = 100;\r
+       lptstat.XTimeOut = XTO;\r
+\r
+    if (!port_base)\r
+               return (ErcBadIOBaseL);\r
+\r
+       lptstat.IOBase = port_base;\r
+       DAT = lptstat.IOBase;           /* Data output register */\r
+       STA = lptstat.IOBase +1;        /* Status Register */\r
+       STC = lptstat.IOBase +2;        /* Status/Control Register */\r
+\r
+       /* If in use and no data in buf, or no one is using\r
+          lpt channel then do a HARD reset on it.\r
+       */\r
+\r
+       if ( ((lptstat.lptJob) && (!cSendBuf)) || (!lptstat.lptJob) )\r
+       {\r
+           OutByte(0x08, STC); /* Reset Line Low */\r
+               MicroDelay(100);        /* 1.5 ms ought to do it */\r
+           OutByte(0x0C, STC); /* No ints, No AutoLF, Init High */\r
+       }\r
+\r
+       erc = 0;\r
+       return(erc);\r
+}\r