]> pd.if.org Git - mmurtl/blob - ossource/rs232.c
autocommit for file dated 2003-12-29 17:36:54
[mmurtl] / ossource / rs232.c
1 /*  RS232 Device Driver (2 channel v1.0).\r
2     Next version adds flow control XON/XOFF & CTS/RTS   */\r
3 \r
4 /*  Copyright 1991,1992,1993,1994 R.A. Burgess  */\r
5 \r
6 \r
7 #define U32 unsigned long\r
8 #define S32 long\r
9 #define U16 unsigned int\r
10 #define S16 int\r
11 #define U8 unsigned char\r
12 #define S8 char\r
13 #define TRUE   1\r
14 #define FALSE  0\r
15 \r
16 #include "RS232.h"\r
17 \r
18 /* MMURTL OS Prototypes */\r
19 \r
20 extern far U32 AllocExch(U32 *pExchRet);\r
21 \r
22 extern far U32 InitDevDr(U32 dDevNum,\r
23                                           S8  *pDCBs,\r
24                                                   U32 nDevices,\r
25                                                   U32 dfReplace);\r
26 \r
27 extern far U32 AllocOSPage(U32 nPages, U8 **ppMemRet);\r
28 extern far U32 DeAllocPage(U8 *pOrigMem, U32 nPages);\r
29 \r
30 extern far U32 UnMaskIRQ(U32 IRQNum);\r
31 extern far U32 MaskIRQ(U32 IRQNum);\r
32 extern far U32 SetIRQVector(U32 IRQNum, S8  *pIRQ);\r
33 extern far U32 EndOfIRQ(U32 IRQNum);\r
34 extern far U32 SendMsg(U32 Exch, U32 msg1, U32 msg2);\r
35 extern far U32 ISendMsg(U32 Exch, U32 msg1, U32 msg2);\r
36 extern far U32 WaitMsg(U32 Exch, S8  *pMsgRet);\r
37 extern far U32 CheckMsg(U32 Exch, S8  *pMsgRet);\r
38 extern far U32 GetTimerTick(U32 *pTickRet);\r
39 extern far U32 Alarm(U32 Exch, U32 count);\r
40 extern far U32 KillAlarm(U32 Exch);\r
41 extern far U32 Sleep(U32 count);\r
42 extern far void MicroDelay(U32 us15count);\r
43 extern far void OutByte(U8 Byte, U16 wPort);\r
44 extern far U8 InByte(U16 wPort);\r
45 extern far void CopyData(U8 *pSource, U8 *pDestination, U32 dBytes);\r
46 \r
47 extern far long GetJobNum(long *pJobNumRet);\r
48 \r
49 /* local prototypes. These will be called form the device driver interface. */\r
50 \r
51 static U32 comdev_stat(U32  dDevice,\r
52                           S8  *pStatRet,\r
53                           U32 dStatusMax,\r
54                           U32 *pdStatusRet);\r
55 \r
56 static S32 comdev_init(U32  dDevice,\r
57                          S8  *pInitData,\r
58                          U32  sdInitData);\r
59 \r
60 static U32 comdev_op(U32 dDevice,\r
61                     U32 dOpNum,\r
62                     U32 dLBA,\r
63                     U32 dnBlocks,\r
64                     U8  *pData);\r
65 \r
66 \r
67 #define CmdReadRec   1                          /* Read one or more bytes */\r
68 #define CmdWriteRec  2                          /* Write one or more bytes */\r
69 \r
70 #define CmdOpenC    10                          /* Open Comm Channel */\r
71 #define CmdCloseC   11                          /* Close Comm Channel */\r
72 #define CmdDiscardRcv 12\r
73 #define CmdSetRTO       13\r
74 #define CmdSetXTO       14\r
75 #define CmdSetDTR   15                          /* Set DTR (On) */\r
76 #define CmdSetRTS       16                              /* Set CTS (On) */\r
77 #define CmdReSetDTR 17                          /* Set DTR (On) */\r
78 #define CmdReSetRTS 18                          /* Set CTS (On) */\r
79 #define CmdBreak        19\r
80 #define CmdGetDC        20\r
81 #define CmdGetDSR       21\r
82 #define CmdGetCTS       22\r
83 #define CmdGetRI        23\r
84 \r
85 #define CmdReadB        31\r
86 #define CmdWriteB       32\r
87 \r
88 /* The following definitions are used to identify, set\r
89    and reset signal line condition and functions.\r
90 */\r
91 \r
92 #define CTS         0x10                /* Clear To Send       */\r
93 #define DSR         0x20                /* Data Set Ready      */\r
94 #define RI          0x40                /* Ring Indicator      */\r
95 #define CD          0x80                /* Carrier Detect      */\r
96 \r
97 #define DTR         0x01                /* Data Terminal Ready */\r
98 #define RTS         0x02                /* Request To Send     */\r
99 #define OUT2            0x08            /* Not used */\r
100 \r
101 /* Values from IIR register */\r
102 \r
103 #define MDMSTAT         0x00\r
104 #define NOINT           0x01\r
105 #define TXEMPTY         0x02\r
106 #define RVCDATA         0x04\r
107 #define RCVSTAT         0x06\r
108 \r
109 /* For errors returned from Comms calls see COMMDRV.H */\r
110 \r
111 #define SSENDBUF 4096           /* 1 Page Send Buf Default */\r
112 #define SRECVBUF 4096           /* 1 Page Recv Buf Default */\r
113 \r
114 static U32  recv_timeout[2] = 1;        /* 10ms intervals */\r
115 static U32  xmit_timeout[2] = 10;       /* 10ms intervals */\r
116 \r
117 /* variables for ISRs */\r
118 \r
119 static U8       f16550[2];\r
120 static U8       stat_byte[2];\r
121 static U8       mstat_byte[2];\r
122 static U8       int_id[2];\r
123 static U8       fExpectInt[2];\r
124 \r
125 static U32 recv_error[2];       /* NON-ZERO = an error has occurred */\r
126 \r
127 static U8   *pSendBuf[2];       /* pointers to Xmit bufs */\r
128 static U32  head_send[2];       /* Next char to send */\r
129 static U32  tail_send[2];       /* Where next char goes in buf */\r
130 static U32  cSendBuf[2];        /* Count of bytes in buf */\r
131 static U32  sSendBuf[2];        /* Size of buffer (allocated) */\r
132 \r
133 static U8   *pRecvBuf[2];       /* pointers to Recv bufs */\r
134 static U32  head_recv[2];       /* Next char from chip */\r
135 static U32  tail_recv[2];       /* Next char to read for caller */\r
136 static U32  cRecvBuf[2];        /* Count of bytes in buf */\r
137 static U32  sRecvBuf[2];        /* Size of buffer (allocated) */\r
138 \r
139 static U8   control_byte[2] = 0;\r
140 \r
141  /* array of registers from port base for each channel */\r
142 \r
143 static U16      THR[2];         /* Transmitter Holding Register */\r
144 static U16      IER[2];         /* Interrupt Enable Register */\r
145 static U16      IIR[2];         /* Interrupt Id Register */\r
146 static U16      FCR[2];         /* FIFO control for 16550 */\r
147 static U16      LCR[2];         /* Line Control Register */\r
148 static U16      MCR[2];         /* Modem Control Register */\r
149 static U16      LSR[2];         /* Line Status Register */\r
150 static U16      MSR[2];         /* Modem Status Register */\r
151 static U16      DLAB_LO[2];     /* same address as THR  */\r
152 static U16      DLAB_HI[2];   /* same address as IER  */\r
153 \r
154 /* Complete description of Register bits follows:\r
155 \r
156         THR -- TX data, RX data, Divisor Latch LSB\r
157 \r
158         IER -- Interrupt Enable, Divisor Latch MSB\r
159 \r
160                             7 6 5 4 3 2 1 0\r
161                             | | | | | | |  \_ Data Available\r
162                             | | | | | |  \___ Xmit Holding Reg Empty\r
163                             | | | | |  \_____ Receiver Line Status\r
164                             | | | |  \_______ Modem Status\r
165                             \ _ _ _\_________ Always 0000\r
166 \r
167         IIR -- Interrupt Identification Register\r
168 \r
169                             7 6 5 4 3 2 1 0\r
170                             | | | | \_\_\_\__________ 0001 = no interrupt\r
171                             | | | |                     0110 = rcvr status\r
172                             | | | |                     0100 = rcvd data\r
173                             | | | |                     0010 = THR empty\r
174                             | | | |                     0000 = Modem status\r
175                             | | | |                     1101 = Rcv Fifo Timeout (16550)\r
176                             | | |  \_________ = 0.\r
177                             | |  \___________ = 0.\r
178                              \ \_____________ = (16550 only)\r
179                                                 00 = FIFOs disabled\r
180                                                 non-zero = 16550 enabled\r
181 \r
182         FCR -- FIFO Control Register (16550 only)\r
183                         This is a write only port at the same\r
184                         address as the IIR on an 8250/16450\r
185 \r
186                             7 6 5 4 3 2 1 0\r
187                             | | | | | | |  \__= 1 = FIFO Enable\r
188                             | | | | | |  \___ = 1 = Recv FIFO Reset\r
189                             | | | | |  \_____ = 1 = Xmit FIFO Reset\r
190                             | | | |  \_______ = (DMA) 0 = Single char, 1 = Multichar\r
191                             | | |  \_________ = 0.\r
192                             | |  \___________ = 0.\r
193                             \__\_____________ = FIFO Rcv Trigger Level\r
194                                                                 00 - 1 char\r
195                                                                 01 - 2 chars\r
196                                                                 10 - 4 chars\r
197                                                                 11 - 8 chars\r
198 \r
199         LCR --  Line Control Register\r
200 \r
201                             7 6 5 4 3 2 1 0\r
202                             | | | | | | |  \_ Word Length Select Bit 0.\r
203                             | | | | | |  \___ Word Length Select Bit 1.\r
204                             | | | | |  \_____ Number Stop Bits (0=1, 1=2)\r
205                             | | | |  \_______ Parity Enable\r
206                             | | |  \_________ Even Parity Select\r
207                             | |  \___________ Stick Parity\r
208                             |  \_____________ Set Break\r
209                              \_______________ Divisor Latch Access Bit\r
210 \r
211         MCR -- Modem Control Register\r
212 \r
213                             7 6 5 4 3 2 1 0\r
214                             | | | | | | |  \_ Data Terminal Ready\r
215                             | | | | | |  \___ Request to Send\r
216                             | | | | |  \_____ Out 1\r
217                             | | | |  \_______ Out 2  (= 1 to enable ints.)\r
218                             | | |  \_________ Loop\r
219                             \ _ _\___________ = Always 0\r
220 \r
221         LSR -- Line Status Register\r
222 \r
223                             7 6 5 4 3 2 1 0\r
224                             | | | | | | |  \_ Data Ready\r
225                             | | | | | |  \___ Overrun Error\r
226                             | | | | |  \_____ Parity Error\r
227                             | | | |  \_______ Framing Error\r
228                             | | |  \_________ Break interrupt\r
229                             | |  \___________ Transmitter Holding Reg Empty\r
230                             |  \_____________ Transmitter Shift Reg Empty\r
231                              \_______________ Recv FIFO Error (16550 Only)\r
232 \r
233         MSR -- Modem Status Register\r
234 \r
235                             7 6 5 4 3 2 1 0\r
236                             | | | | | | |  \_ Delta Clear to Send\r
237                             | | | | | |  \___ Delta Data Set Ready\r
238                             | | | | |  \_____ Trailing Edge Ring Indicator\r
239                             | | | |  \_______ Delta Rx Line Signal Detect\r
240                             | | |  \_________ Clear to Send\r
241                             | |  \___________ Data Set Ready\r
242                             |  \_____________ Ring Indicator\r
243                              \_______________ Receive Line Signal Detect\r
244 \r
245 */\r
246 \r
247 \r
248 /* Record for 64 byte status and init record */\r
249 /* This structure is peculiar to the comms driver */\r
250 \r
251 #define sStatus 64\r
252 \r
253 static struct statRecC comstat[2];\r
254 static struct statRecC *pCS;\r
255 \r
256 static struct dcbtype \r
257 {\r
258         S8   Name[12];\r
259         S8   sbName;\r
260         S8   type;\r
261         S16  nBPB;\r
262         U32  last_erc;\r
263         U32  nBlocks;\r
264         S8  *pDevOp;\r
265         S8  *pDevInit;\r
266         S8  *pDevSt;\r
267         S8   fDevReent;\r
268         S8   fSingleUser;\r
269         S16  wJob;\r
270         U32  OS1;\r
271         U32  OS2;\r
272         U32  OS3;\r
273         U32  OS4;\r
274         U32  OS5;\r
275         U32  OS6;\r
276         };\r
277 \r
278 static struct dcbtype comdcb[2];                /* Two RS-232 ports */\r
279 \r
280 \r
281 /* THE COMMS INTERRUPT FUNCTION PROTOTYPES */\r
282 \r
283 static void interrupt comISR0(void);\r
284 static void interrupt comISR1(void);\r
285 \r
286 \r
287 /*********************************************************\r
288     This is called ONCE to initialize the 2 default\r
289     comms channels with the OS device driver interface.\r
290     It sets up defaults for both channels to 9600, 8N1.\r
291 *********************************************************/\r
292 \r
293 U32  coms_setup(void)\r
294 {\r
295 U32  erc;\r
296 \r
297   /* first we set up the 2 DCBs in anticipation of calling InitDevDr */\r
298 \r
299         comdcb[0].Name[0]  = 'C';\r
300         comdcb[0].Name[1]  = 'O';\r
301         comdcb[0].Name[2]  = 'M';\r
302         comdcb[0].Name[3]  = '1';\r
303         comdcb[0].sbName   = 4;\r
304         comdcb[0].type     = 2;                 /* Sequential */\r
305         comdcb[0].nBPB     = 1;                 /* 1 byte per block */\r
306         comdcb[0].nBlocks  = 0;                 /* 0 for Sequential devices */\r
307         comdcb[0].pDevOp   = &comdev_op;\r
308         comdcb[0].pDevInit = &comdev_init;\r
309         comdcb[0].pDevSt   = &comdev_stat;\r
310 \r
311         comdcb[1].Name[0]  = 'C';\r
312         comdcb[1].Name[1]  = 'O';\r
313         comdcb[1].Name[2]  = 'M';\r
314         comdcb[1].Name[3]  = '2';\r
315         comdcb[1].sbName   = 4;\r
316         comdcb[1].type     = 2;                 /* Sequential */\r
317         comdcb[1].nBPB     = 1;                 /* 1 byte per block */\r
318         comdcb[1].nBlocks  = 0;                 /* 0 for Sequential devices */\r
319         comdcb[1].pDevOp   = &comdev_op;\r
320         comdcb[1].pDevInit = &comdev_init;\r
321         comdcb[1].pDevSt   = &comdev_stat;\r
322 \r
323         /* Set default comms params in stat records */\r
324 \r
325         comstat[0].Baudrate = 9600;\r
326         comstat[0].parity   = 0;        /* none */\r
327         comstat[0].databits = 8;\r
328         comstat[0].stopbits = 1;\r
329         comstat[0].XTimeOut = 100;\r
330         comstat[0].RTimeOut = 2;\r
331         comstat[0].IOBase = 0x3F8;\r
332         comstat[0].IRQNum = 4;\r
333         comstat[0].XBufSize = 4096;\r
334         comstat[0].RBufSize = 4096;\r
335         sSendBuf[0] = 4096;\r
336         sRecvBuf[0] = 4096;\r
337 \r
338         comstat[1].Baudrate = 9600;\r
339         comstat[1].parity   = 0;        /* none */\r
340         comstat[1].databits = 8;\r
341         comstat[1].stopbits = 1;\r
342         comstat[1].XTimeOut = 100;\r
343         comstat[1].RTimeOut = 2;\r
344         comstat[1].IOBase = 0x2F8;\r
345         comstat[1].IRQNum = 3;\r
346         comstat[1].XBufSize = 4096;\r
347         comstat[1].RBufSize = 4096;\r
348         sSendBuf[1] = 4096;\r
349         sRecvBuf[1] = 4096;\r
350 \r
351         MaskIRQ(4);\r
352         MaskIRQ(3);\r
353 \r
354         SetIRQVector(4, &comISR0);      /* COM1 */\r
355         SetIRQVector(3, &comISR1);      /* COM2 */\r
356 \r
357         return(erc = InitDevDr(5, &comdcb, 2, 1));\r
358 \r
359 }\r
360 \r
361 /*********************************************************\r
362   This does the grunt work for each of the two ISRs\r
363   This MUST remain reentrant for two ISRs.\r
364 *********************************************************/\r
365 \r
366 static void handleISR(U32 i)            /* i is the device */\r
367 {\r
368 U8 *pRBuf, *pXBuf;\r
369 \r
370 pRBuf = pRecvBuf[i];\r
371 pXBuf = pSendBuf[i];\r
372 \r
373 while (TRUE) \r
374 {\r
375         int_id[i] = InByte (IIR[i]);            /* Get ID Byte from IIR */\r
376         switch (int_id[i]) \r
377         {\r
378                 case RCVSTAT:\r
379                     stat_byte[i] = InByte(LSR[i]);  /* clear error conditions */\r
380                         break;\r
381 \r
382                 case RVCDATA:\r
383                 if (cRecvBuf[i] == sRecvBuf[i]) \r
384                 {               /* Overflow!! */\r
385                                 recv_error[i] = ErcRcvBufOvr;           /* Do not put in buf */\r
386                     InByte (THR[i]);                                    /* trash the byte */\r
387                         }\r
388                         else \r
389                         {\r
390 #asm\r
391         CLI\r
392 #endasm\r
393                         pRBuf[head_recv[i]] =\r
394                                 InByte (THR[i]);        /* Get the byte */\r
395                                 ++cRecvBuf[i];\r
396                 if (++head_recv[i] == SRECVBUF)\r
397                             head_recv[i] = 0;\r
398 #asm\r
399         STI\r
400 #endasm\r
401                                 recv_error[i] = 0;\r
402                     }\r
403             break;\r
404 \r
405                 case TXEMPTY:\r
406 #asm\r
407         CLI\r
408 #endasm\r
409                 if (cSendBuf[i]) \r
410                 {\r
411                     OutByte(pXBuf[tail_send[i]], THR[i]);  /* Send the byte */\r
412                     if (++tail_send[i] == sSendBuf[i])\r
413                                 tail_send[i] = 0;\r
414                         --cSendBuf[i];\r
415                                 fExpectInt[i] = TRUE;\r
416                         }\r
417                         else\r
418                                 fExpectInt[i] = FALSE;\r
419 #asm\r
420         STI\r
421 #endasm\r
422                 break;\r
423 \r
424                 case MDMSTAT:\r
425             mstat_byte[i] = InByte (MSR[i]);   /* Get Modem Status */\r
426                 break;\r
427 \r
428                 case NOINT:\r
429             stat_byte[i] = InByte(LSR[i]);  /* clear error conditions */\r
430                 default:\r
431         return;\r
432         }\r
433 }\r
434 }\r
435 \r
436 \r
437 static void interrupt comISR0(void)\r
438 {\r
439 ;               /* ; needed if asm is first in function */\r
440 #asm\r
441         STI\r
442 #endasm\r
443         handleISR(0);\r
444         EndOfIRQ(4);\r
445         return;\r
446 }\r
447 \r
448 \r
449 static void interrupt comISR1(void)\r
450 {\r
451 ;               /* ; needed if asm is first in function */\r
452 #asm\r
453         STI\r
454 #endasm\r
455         handleISR(1);\r
456         EndOfIRQ(3);\r
457         return;\r
458 }\r
459 \r
460 /********************************************/\r
461 \r
462 \r
463 static long ReadByteC(U32 device, unsigned char *pByteRet)\r
464 {\r
465 U32 counter;\r
466 U8 *pRBuf;\r
467 \r
468         pRBuf = pRecvBuf[device];\r
469         if (recv_error[device]) return (recv_error[device]);\r
470 \r
471         if (cRecvBuf[device]) \r
472         {\r
473         *pByteRet = pRBuf[tail_recv[device]];\r
474         if (++tail_recv[device] == sRecvBuf[device])\r
475                 tail_recv[device] = 0;\r
476         --cRecvBuf[device];\r
477                 return (0);\r
478         }\r
479 \r
480         counter = comstat[device].RTimeOut;             /* set up for timeout */\r
481         while (counter--) \r
482         {\r
483                 Sleep(1);\r
484                 if (cRecvBuf[device]) \r
485                 {\r
486                 *pByteRet = pRBuf[tail_recv[device]];\r
487                 if (++tail_recv[device] == sRecvBuf[device])\r
488                         tail_recv[device] = 0;\r
489                 --cRecvBuf[device];\r
490                         return (0);\r
491                 }\r
492         }\r
493         return (ErcRecvTimeout);\r
494 }\r
495 \r
496 /********************************************/\r
497 \r
498 \r
499 static long ReadRecordC(U32 device,\r
500                                 unsigned char *pDataRet,\r
501                 unsigned int  sDataMax,\r
502                 unsigned int *pcbRet)\r
503 {\r
504 int  erc, cb;\r
505 \r
506         erc = 0;\r
507         cb = 0;\r
508         while ((cb < sDataMax) && (!erc)) \r
509         {\r
510                 erc = ReadByteC(device, pDataRet++);\r
511                 if (!erc) ++cb;\r
512         }\r
513         *pcbRet = cb;           /* tell em how many bytes */\r
514     return (erc);\r
515 }\r
516 \r
517 \r
518 \r
519 /********************************************/\r
520 static long WriteByteC(U32 device, unsigned char b)\r
521 {\r
522 \r
523 U32 erc, counter;\r
524 U8 *pXBuf;\r
525 \r
526         erc = 0;\r
527         pXBuf = pSendBuf[device];\r
528         counter = comstat[device].XTimeOut;             /* set up for timeout */\r
529 \r
530         while (cSendBuf[device] == sSendBuf[device]) \r
531         {\r
532                 Sleep(1);\r
533                 counter--;\r
534                 if  (!counter)\r
535                         return (ErcXmitTimeout);                /* never got sent */\r
536         }\r
537 \r
538 #asm\r
539         CLI\r
540 #endasm\r
541 \r
542         if (!fExpectInt[device])\r
543         {                       /* Xmit buf empty, send ourself */\r
544         OutByte(b, THR[device]);\r
545                 fExpectInt[device] = TRUE;\r
546                 }\r
547         else \r
548         {\r
549         pXBuf[head_send[device]] = b;\r
550         if (++head_send[device] == sSendBuf[device])\r
551             head_send[device]  = 0;\r
552                 ++cSendBuf[device];                             /* one more in buf */\r
553         }\r
554 #asm\r
555         STI\r
556 #endasm\r
557         return (erc);\r
558 }\r
559 \r
560 \r
561 /********************************************/\r
562 static long WriteRecordC(U32 device,\r
563                                  unsigned char *pSendData,\r
564                  unsigned int cbSendData)\r
565 {\r
566 int erc;\r
567 \r
568         erc = 0;\r
569     while ((cbSendData) && (!erc)) \r
570     {\r
571                 erc = WriteByteC(device, *pSendData++);\r
572                 --cbSendData;\r
573         }\r
574         return (erc);\r
575 }\r
576 \r
577 \r
578 /********************************************/\r
579 \r
580 static long DiscardRecvC(U32 device)\r
581 {\r
582 U32     saveto, erc;\r
583 U8  b;\r
584 \r
585         saveto = comstat[device].RTimeOut;\r
586         comstat[device].RTimeOut = 1;\r
587         erc = 0;\r
588         while (!erc)\r
589                 erc = ReadByteC(device, &b);\r
590         comstat[device].RTimeOut = saveto;\r
591         return (0);\r
592 }\r
593 \r
594 \r
595 \r
596 /********************************************\r
597  This sets comms params prior to opening, or\r
598  while a channel is in use.\r
599 ********************************************/\r
600 \r
601 static U32 SetParams(U32 device)\r
602 \r
603 {\r
604 U32  divisor, speed;\r
605 U8   c, parity, bits, stop_bit, temp;\r
606 \r
607         parity = comstat[device].parity;\r
608         bits = comstat[device].databits;\r
609         stop_bit = comstat[device].stopbits;\r
610         speed = comstat[device].Baudrate;\r
611 \r
612         /* Set up baud rate */\r
613 \r
614     divisor = 115200/speed;\r
615 \r
616 #asm\r
617         CLI\r
618 #endasm\r
619     c=InByte (LCR[device]);\r
620     OutByte  ((c | 0x80), LCR[device]);\r
621     OutByte  ((divisor & 0x00ff), DLAB_LO[device]);\r
622     OutByte  (((divisor>>8) & 0x00ff), DLAB_HI[device]);\r
623     OutByte  (c, LCR[device]);\r
624 #asm\r
625         STI\r
626 #endasm\r
627 \r
628         /* set coms params */\r
629 \r
630     temp = bits - 5;\r
631     temp |= ((stop_bit == 1) ? 0x00 : 0x04);\r
632 \r
633     switch (parity)\r
634     {\r
635        case NO_PAR : temp |= 0x00; break;\r
636        case OD_PAR : temp |= 0x08; break;\r
637        case EV_PAR : temp |= 0x18; break;\r
638     }\r
639 \r
640 #asm\r
641         CLI\r
642 #endasm\r
643     OutByte (temp, LCR[device]);\r
644 #asm\r
645         STI\r
646 #endasm\r
647 \r
648         return (0);\r
649 }\r
650 \r
651 \r
652 /********************************************\r
653  This allocates buffers, sets up the ISR\r
654  and IRQ values and open the channel for use.\r
655 *********************************************/\r
656 \r
657 static U32  OpenCommC(U32 device)\r
658 \r
659 {\r
660 U32  erc;\r
661 U16  port_base;\r
662 U8   c;\r
663 \r
664         if (comstat[device].commJob)\r
665                 return(ErcChannelOpen);\r
666 \r
667         GetJobNum(&comstat[device].commJob);\r
668 \r
669         erc = AllocOSPage(comstat[device].XBufSize/4096,\r
670                                           &pSendBuf[device]);\r
671 \r
672         if (!erc) \r
673         {\r
674                 erc = AllocOSPage(comstat[device].RBufSize/4096,\r
675                                                   &pRecvBuf[device]);\r
676 \r
677                 if (erc)  /* get rid of Xmit buf if we can't recv */\r
678             DeAllocPage(pSendBuf[device],\r
679                                 comstat[device].XBufSize/4096);\r
680         }\r
681 \r
682         if (erc)\r
683         {\r
684                 comstat[device].commJob = 0;\r
685                 return (erc);\r
686         }\r
687 \r
688         port_base = comstat[device].IOBase;\r
689 \r
690         /* Set up buffer variables for this port */\r
691 \r
692         cSendBuf[device] = 0;\r
693         head_send[device] = 0;\r
694         tail_send[device] = 0;\r
695 \r
696         cRecvBuf[device] = 0;\r
697         head_recv[device] = 0;\r
698         tail_recv[device] = 0;\r
699         recv_error[device] = 0;\r
700 \r
701 \r
702     THR[device]     = port_base;\r
703     IER[device]     = port_base + 1;\r
704     IIR[device]     = port_base + 2;\r
705     FCR[device]     = port_base + 2;\r
706     LCR[device]     = port_base + 3;\r
707     MCR[device]     = port_base + 4;\r
708     LSR[device]     = port_base + 5;\r
709     MSR[device]     = port_base + 6;\r
710     DLAB_HI[device] = port_base + 1;\r
711     DLAB_LO[device] = port_base;\r
712 \r
713     InByte(THR[device]);        /* reset any pending ints on chip */\r
714     InByte(LSR[device]);\r
715 \r
716 #asm\r
717         CLI\r
718 #endasm\r
719         control_byte[device] = RTS | DTR | OUT2;\r
720     OutByte(control_byte[device], MCR[device]); /* Mod Ctrl Reg   */\r
721     OutByte(0x0F, IER[device]);                                 /* Int Enable Reg */\r
722 \r
723         /* See if we have a 16550 and set it up if we do!! */\r
724 \r
725     OutByte(0x03, FCR[device]);\r
726     c = InByte(IIR[device]);\r
727         if (c & 0xC0)           /* we have a 16550 and it's set to go! */\r
728                 f16550[device] = 1;\r
729         else\r
730                 f16550[device] = 0;             /* 8250 or 16450 */\r
731 \r
732 #asm\r
733         STI\r
734 #endasm\r
735 \r
736         SetParams(device);\r
737 \r
738         UnMaskIRQ(comstat[device].IRQNum);\r
739         return (0);\r
740 }\r
741 \r
742 /********************************************\r
743  This closes the port, sets the owner to 0\r
744  and deallocates the buffers.\r
745 ********************************************/\r
746 \r
747 static int  CloseCommC (U32 device)\r
748 {\r
749 U32 erc;\r
750 \r
751         MaskIRQ(comstat[device].IRQNum);\r
752     OutByte(0, MCR[device]);\r
753     OutByte(0, IER[device]);\r
754     erc = DeAllocPage(pSendBuf[device],\r
755                                 comstat[device].XBufSize/4096);\r
756     erc = DeAllocPage(pRecvBuf[device],\r
757                                 comstat[device].RBufSize/4096);\r
758         comstat[device].commJob = 0;\r
759     return (erc);\r
760 }\r
761 \r
762 /***************************************************************************\r
763 Now begins the PUBLIC routines that are interfaced to for all DEVICE DRIVERS\r
764 ****************************************************************************/\r
765 \r
766 /******************************************\r
767 Called for all device operations.  This\r
768 assigns physical device from logical number\r
769 that outside callers use. For RS-232, 5=0\r
770 and 6=1.\r
771 *******************************************/\r
772 \r
773 static U32 comdev_op(U32 dDevice,\r
774                     U32 dOpNum,\r
775                     U32 dLBA,\r
776                     U32 dnBlocks,\r
777                     U8  *pData)\r
778 {\r
779 U32 erc;\r
780 U32 Job, device;\r
781 U8 c;\r
782 \r
783 /* Set internal drive number */\r
784 /* 5    RS-232 1        COM1    (OS built-in) */\r
785 /* 6    RS-232 2        COM2    (OS built-in) */\r
786 \r
787         if (dDevice == 5)\r
788                 device = 0;\r
789         else\r
790                 device = 1;\r
791 \r
792         GetJobNum(&Job);\r
793 \r
794         if ((!comstat[device].commJob) && (dOpNum != CmdOpenC))\r
795                 return(ErcNotOpen);\r
796 \r
797         if (comstat[device].commJob) \r
798         {\r
799                 if ((comstat[device].commJob != Job) &&\r
800                         (Job != 1))\r
801                         return(ErcNotOwner);\r
802         }\r
803 \r
804         erc = 0;                /* default error */\r
805 \r
806         switch(dOpNum) \r
807         {\r
808 \r
809                 case(0):\r
810                         break;                          /* Null Command */\r
811                 case CmdReadB:\r
812                         erc = ReadByteC(device, pData);\r
813                         break;\r
814                 case CmdWriteB:\r
815                         erc = WriteByteC(device, *pData);\r
816                         break;\r
817                 case CmdReadRec:\r
818                         erc = ReadRecordC(device, pData, dnBlocks,\r
819                                                 &comstat[device].LastTotal);\r
820                         break;\r
821                 case CmdWriteRec:\r
822                         erc = WriteRecordC(device, pData, dnBlocks);\r
823                         break;\r
824                 case CmdSetRTO:\r
825                         comstat[device].RTimeOut = dLBA;                /* 10ms intervals */\r
826                         break;\r
827                 case CmdSetXTO:\r
828                         comstat[device].XTimeOut = dLBA;                /* 10ms intervals */\r
829                         break;\r
830                 case CmdOpenC:\r
831                         erc =  OpenCommC(device);\r
832                         break;\r
833                 case CmdCloseC:\r
834                         erc =  CloseCommC(device);\r
835                         break;\r
836                 case CmdDiscardRcv:\r
837                         erc = DiscardRecvC(device);\r
838                         break;\r
839                 case CmdSetDTR:\r
840                         control_byte[device] |= DTR;\r
841                     OutByte(control_byte[device], LCR[device]);\r
842                         break;\r
843                 case CmdSetRTS:\r
844                         control_byte[device] |= RTS;\r
845                         OutByte(control_byte[device], MCR[device]);\r
846                         break;\r
847                 case CmdReSetDTR:\r
848                         control_byte[device] &= ~DTR;\r
849                         OutByte(control_byte[device], LCR[device]);\r
850                 case CmdReSetRTS:\r
851                         control_byte[device] &= ~RTS;\r
852                     OutByte(control_byte[device], MCR[device]);\r
853                     break;\r
854                 case CmdBreak:\r
855                         c = InByte(LCR[device]);\r
856                         OutByte((c | 0x40), LCR[device]);\r
857                         Sleep(dLBA);\r
858                         OutByte(c, LCR[device]);\r
859                         break;\r
860                 case CmdGetDC:\r
861                     *pData = mstat_byte[device] & CD;\r
862                         break;\r
863                 case CmdGetDSR:\r
864                 *pData = mstat_byte[device] & DSR;\r
865                         break;\r
866                 case CmdGetCTS:\r
867                         *pData = mstat_byte[device] & CTS;\r
868                         break;\r
869                 case CmdGetRI:\r
870                         *pData = mstat_byte[device] & RI;\r
871                         break;\r
872                 default:\r
873                         break;\r
874         }\r
875 \r
876         comstat[device].LastErc = erc;\r
877         return(erc);\r
878 }\r
879 \r
880 \r
881 /******************************************\r
882 Called for status report on coms channel.\r
883 Returns 64 byte block for channel specified.\r
884 This is called by the PUBLIC call DeviceStat\r
885 *******************************************/\r
886 \r
887 static U32 comdev_stat(U32  dDevice,\r
888                           S8  *pStatRet,\r
889                           U32 dStatusMax,\r
890                           U32 *pdStatusRet)\r
891 {\r
892 U32 i, device;\r
893 \r
894         /* Set internal device number */\r
895         if (dDevice == 5)\r
896                 device = 0;\r
897         else device = 1;\r
898 \r
899         if (dStatusMax > 64)\r
900                 i = 64;\r
901         else\r
902             i = dStatusMax;\r
903 \r
904         if (!device)\r
905         {\r
906                 CopyData(&comstat[0], pStatRet, i);             /* copy the status data */\r
907         }\r
908         else\r
909         {\r
910                 CopyData(&comstat[1], pStatRet, i);             /* copy the status data */\r
911         }\r
912 \r
913         *pdStatusRet = dStatusMax;              /* give em the size returned */\r
914 \r
915         return(0);\r
916 }\r
917 \r
918 /******************************************\r
919 Called to set parameters for the comms\r
920 channels prior to opening or while in use.\r
921 If an invalid value is passed in, all params\r
922 remain the same as before.\r
923 Some comms channel params may not be changed\r
924 while the channel is in use.\r
925 This is called by the PUBLIC call DeviceInit.\r
926 *******************************************/\r
927 \r
928 static S32 comdev_init(U32  dDevice,\r
929                          S8  *pInitData,\r
930                          U32  sdInitData)\r
931 \r
932 {\r
933 U32  erc, Xbufsize, Rbufsize, device;\r
934 U32  speed, XTO, RTO;\r
935 U16  port_base;\r
936 U8   parity, bits, stop_bit, IRQNUM;\r
937 \r
938         if (dDevice == 5)\r
939                 device = 0;                     /* Set internal device number */\r
940         else\r
941                 device = 1;\r
942 \r
943         if (sdInitData < 40)\r
944                 return(ErcBadInitSize);\r
945 \r
946         pCS = pInitData;\r
947 \r
948         /* Get the callers new params */\r
949 \r
950         speed     = pCS->Baudrate;      /* Non Volatile */\r
951         parity    = pCS->parity;        /* Non Volatile */\r
952         bits      = pCS->databits;      /* Non Volatile */\r
953         stop_bit  = pCS->stopbits;      /* Non Volatile */\r
954         XTO       = pCS->XTimeOut;      /* Non Volatile */\r
955         RTO       = pCS->RTimeOut;      /* Non Volatile */\r
956 \r
957         port_base = pCS->IOBase;\r
958         Xbufsize  = pCS->XBufSize;\r
959         Rbufsize  = pCS->RBufSize;\r
960         IRQNUM    = pCS->IRQNum;\r
961 \r
962         /* Non Volatile params can be set whether or not the\r
963            channel is open. Do these first and return errors. */\r
964 \r
965     if ((speed > MAX_BAUD) || (speed < MIN_BAUD))\r
966        return (ErcBadBaud);\r
967 \r
968     if ((parity < NO_PAR) || (parity > OD_PAR))\r
969         return (ErcBadParity);\r
970 \r
971     if ((bits < 5) || (bits > 8))\r
972         return (ErcBadDataBits);\r
973 \r
974     if ((stop_bit < 1) || (stop_bit > 2))\r
975         return (ErcBadStopBits);\r
976 \r
977     if (!XTO)  XTO = 1;\r
978     if (!RTO)  RTO = 1;\r
979 \r
980         comstat[device].Baudrate = speed;\r
981         comstat[device].parity   = parity;\r
982         comstat[device].databits = bits;\r
983         comstat[device].stopbits = stop_bit;\r
984         comstat[device].XTimeOut = XTO;\r
985         comstat[device].RTimeOut = RTO;\r
986 \r
987         /* If we got here, the params are OK.  Now we check\r
988            to see if the channel is open and call SetParams\r
989            if so.  The channel is open if the JobNumber\r
990            in the commstat record is NON-ZERO.\r
991         */\r
992 \r
993         if (comstat[device].commJob)\r
994         {  /* Channel Open! */\r
995                 SetParams(device);\r
996         }\r
997 \r
998         /* Channel is not open so we check and set rest of params */\r
999 \r
1000         else\r
1001         {\r
1002 \r
1003             if (!port_base)\r
1004                 return (ErcBadIOBase);\r
1005             if (IRQNUM < 3)\r
1006                 return (ErcBadCommIRQ);\r
1007 \r
1008                 /* We now round up buffer sizes to whole pages */\r
1009 \r
1010                 Xbufsize = Xbufsize/4096 * 4096;\r
1011                 if (Xbufsize % 4096) Xbufsize+=4096; /* another page */\r
1012 \r
1013 \r
1014                 Rbufsize = Rbufsize/4096 * 4096;\r
1015                 if (Rbufsize % 4096) Rbufsize+=4096; /* another page */\r
1016 \r
1017 \r
1018                 comstat[device].IOBase = port_base;\r
1019                 comstat[device].IRQNum = IRQNUM;\r
1020                 comstat[device].XBufSize = Xbufsize;\r
1021                 comstat[device].RBufSize = Rbufsize;\r
1022 \r
1023                 /* Local copies so we don't work from a structure in ISR */\r
1024 \r
1025                 sSendBuf[device] = Xbufsize;    /* Size of buffer (allocated) */\r
1026                 sRecvBuf[device] = Rbufsize;    /* Size of buffer (allocated) */\r
1027 \r
1028                 erc = 0;\r
1029         }\r
1030 \r
1031  return(erc);\r
1032 }\r