]> icculus.org git repositories - btb/d2x.git/blob - arch/dos/comm/dzcomm.c
This commit was generated by cvs2svn to compensate for changes in r2,
[btb/d2x.git] / arch / dos / comm / dzcomm.c
1 /*
2  * DZcomm : serial communication add-on for Allegro.
3  * version : 0.6
4  * Copyright (c) 1997 Dim Zegebart, Moscow Russia.
5  * zager@post.comstar.ru
6  * file : dzcomm.c
7  *
8  */
9
10 #include <stdio.h>
11 #include <sys/movedata.h>
12 #include <stdlib.h>
13 #include <dos.h>
14 #include <conio.h>
15 #include <string.h>
16 #include <io.h>
17 #include <ctype.h>
18 #include "dzcomm.h"
19 #include "allegro.h"
20
21 typedef unsigned int uint;
22 typedef unsigned short int usint;
23 typedef unsigned char byte;
24
25 #define com_(N) comm_port *com##N
26
27 com_(1);
28 com_(2);
29 com_(3);
30 com_(4);
31 com_(5);
32 com_(6);
33 com_(7);
34 com_(8);
35
36 #define com_wrapper_(N) static int com##N##_wrapper(void) \
37                        { DISABLE(); /* adb -- why this? */ \
38                           dz_comm_port_interrupt_handler(com##N##); \
39                           return(0); \
40                         } \
41                         END_OF_FUNCTION(com##N##_wrapper);
42
43 com_wrapper_(1);
44 com_wrapper_(2);
45 com_wrapper_(3);
46 com_wrapper_(4);
47 com_wrapper_(5);
48 com_wrapper_(6);
49 com_wrapper_(7);
50 com_wrapper_(8);
51
52 static comm_port *irq_bot_com_port[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
53 static int (*com_wrapper[8])();
54 static comm_port **com_port[8];
55
56 char szDZCommErr[50];
57 inline void dz_make_comm_err(char *szErr) {strcpy(szDZCommErr,szErr);}
58 //comm port functions
59 static inline void comm_port_rdr(comm_port *port);
60 static inline void comm_port_trx(comm_port *port);
61 static inline void interrupt_on(comm_port *port,byte _interrupt_);
62 static inline void interrupt_off(comm_port *port,byte _interrupt_);
63 extern void lock_queue_functions(void);
64 void comm_port_fifo_init(comm_port *port);
65 inline void comm_port_rtmout(comm_port *port);
66 void comm_port_uninstall(comm_port *port);
67
68 //const byte THREOFF=0xfd;
69 const byte THREINT=0x02;
70 const byte RDAINT=0x04;
71
72 //-------------------------- PRINT BIN --------------------------
73
74 void print_bin_s(int c,char *s)
75 { int i,j;
76   int mask=0x01;
77   sprintf (s,"%c : ",c);
78   for (i=0;i<4;i++)
79    { for(j=0;j<8;j++)
80       if (c&(mask<<(j+i*8))) strcat(s,"1");
81       else strcat(s,"0");
82       strcat(s,".");
83    }
84 }
85
86 //------------------------- INTERRUPT ON -----------------------------
87
88 static inline void interrupt_on(comm_port *port,byte _interrupt_)
89 { byte i;
90   i=inportb(port->IER);
91   if (!(i&_interrupt_)) outportb(port->IER,i|_interrupt_);
92 }
93 END_OF_FUNCTION(interrupt_on);
94
95 //------------------------- INTERRUPT OFF -----------------------------
96
97 static inline void interrupt_off(comm_port *port,byte _interrupt_)
98 { byte i;
99   i=inportb(port->IER);
100   if (i&_interrupt_) outportb(port->IER,i&~_interrupt_);
101 }
102 END_OF_FUNCTION(interrupt_off);
103
104 //------------------------- COMM PORT INIT --------------------------
105
106 comm_port *comm_port_init(comm com)
107 { comm_port *port=(comm_port*)malloc(sizeof(comm_port));
108
109   szDZCommErr[0]=0;
110
111   if (port==NULL)
112    { dz_make_comm_err("Out of memory !");
113      return(NULL);
114    }
115
116   if ((port->InBuf=queue_new_(4096,1))==NULL)
117    { dz_make_comm_err("Out of memory !");
118      return(NULL);
119    }
120   if ((port->OutBuf=queue_new_(4096,1))==NULL)
121    { dz_make_comm_err("Out of memory !");
122      queue_delete(port->InBuf);
123      return(NULL);
124    }
125
126   port->nPort=0;
127   //getting comport base address
128   //0x400+com*2 - memory address where stored default comm base address
129   dosmemget(0x400+com*2,2,&port->nPort);
130   if (port->nPort==0) //probably you have notebook or some brand named PC
131    { if (com==_com1||com==_com3||com==_com5||com==_com7) port->nPort=0x3f8; //default I/O address for com1 or com3
132      else port->nPort=0x2f8; //com2 or com4
133    }
134
135 //set default values (user may change it later)
136
137   if (com==_com1||com==_com3||com==_com5||com==_com7) port->nIRQ=4;
138   else port->nIRQ=3; //com2 or com4
139
140   strcpy(port->szName,"COM ");
141   port->szName[3]=com+49;
142   port->installed=NO;
143   port->nComm=com;
144   port->nBaud=_2400;
145   port->nData=BITS_8;
146   port->nStop=STOP_1;
147   port->nParity=NO_PARITY;
148   port->comm_handler=com_wrapper[com];
149   port->control_type=XON_XOFF;
150   port->msr_handler=NULL; //#d#pointer to modem status register handler.
151   port->lsr_handler=NULL; //#d#pointer to line status register handler.
152
153   _go32_dpmi_lock_data(port,sizeof(comm_port));
154   *(com_port[com])=port;
155
156   return(port);
157 }
158
159 //-------------------- COMM_PORT_FIFO_INIT ----------------------
160
161 void comm_port_fifo_init(comm_port *port)
162 {
163 //setting up FIFO if possible
164   int c=inportb(port->SCR);
165   outportb(port->SCR,0x55);
166   port->fifo = 0;
167   if(inportb(port->SCR)==0x55)  // greater then 8250
168    { outportb(port->SCR,c);
169      outportb(port->FCR,0x87);//try to enable FIFO with 8 byte trigger level
170      if ((c=inportb(port->IIR)&0xc0)!=0xc0) //If not 16550A
171        outportb(port->FCR,c&0xfe); //Disable FIFO
172        else port->fifo = 1;
173 //     else printf("\nFIFO OK\n");
174    }
175
176 }
177
178 //----------------------- COMM PORT INSTALL HANDLER ------------------
179 //modifyed by Neil Townsend to support IRQ sharing
180 int comm_port_install_handler(comm_port *port)
181 {
182   if (port==NULL)
183    { dz_make_comm_err("Set up comm parametrs first ! Call comm_port_new() first.");
184      return(0);
185    }
186   if (port->installed==YES)
187    { dz_make_comm_err("Comm already installed !");
188      return(0);
189    }
190   if (port->nIRQ>15)
191    { dz_make_comm_err("IRQ number out of range ! Must be 0 ... 15 .");
192      return(0);
193    }
194   if (port->comm_handler==NULL)
195    { dz_make_comm_err("Specify comm's handler (see 'comm_handler' member's description) !");
196      return(0);
197    }
198   if (port->nBaud==0)
199    { dz_make_comm_err("Invalid baud rate !");
200      return(0);
201    }
202
203   switch(port->control_type)
204    { case XON_XOFF :
205        port->xon=0;
206        port->xoff=0;
207        port->xonxoff_rcvd=XON_RCVD;
208        port->xonxoff_send=XON_SENT;
209        break;
210      case RTS_CTS :
211        port->cts=CTS_ON;
212        port->rts=RTS_ON; //fixed by SET (was RTS_OFF)
213        break;
214      default :
215        break;
216    }
217
218   port->THR=port->nPort;
219   port->RDR=port->nPort;
220   port->BRDL=port->nPort;
221   port->BRDH=1+port->nPort;
222   port->IER=1+port->nPort;
223   port->IIR=2+port->nPort;
224   port->FCR=2+port->nPort;
225   port->LCR=3+port->nPort;
226   port->MCR=4+port->nPort;
227   port->LSR=5+port->nPort;
228   port->MSR=6+port->nPort;
229   port->SCR=7+port->nPort;
230   { byte i;
231     for(i=0;i<8;i++) outportb(port->RDR+i,0);
232   }
233
234   comm_port_fifo_init(port);
235
236   { unsigned char temp;
237     do
238      { temp=inportb(port->RDR);
239        temp=inportb(port->LSR);
240        temp=inportb(port->MSR);
241        temp=inportb(port->IIR);
242      }
243     while(!(temp & 1));
244   }
245
246
247 //set communication parametrs
248 //MOVED forwards so done before interupts enabled
249   { int divisor=115200/port->nBaud;
250     byte divlow,divhigh;
251     byte comm_param=port->nData|(port->nStop<<2)|(port->nParity<<3);
252     // Set Port Toggle to BRDL/BRDH registers
253     outportb(port->LCR,comm_param|0x80);
254     divlow=divisor&0x000000ff;
255     divhigh=(divisor>>8)&0x000000ff;
256     outportb(port->BRDL,divlow); // Set Baud Rate
257     outportb(port->BRDH,divhigh);
258     outportb(port->LCR,comm_param&0x7F); // Set LCR and Port Toggle
259   }
260   
261 //set interrupt parametrs
262   { const byte IMR_8259_0=0x21;
263     const byte IMR_8259_1=0xa1;
264     const byte ISR_8259_0=0x20;
265     const byte ISR_8259_1=0xa0;
266     const byte IERALL = 0x0f; //mask for all communications interrupts
267     const byte MCRALL = 0x0f; //DTR,RTS,OUT1=OUT2=1 is ON
268     //calculating mask for 8259 controller's IMR
269     //and number of interrupt hadler for given irq level
270     if (port->nIRQ<=7) //if 0<=irq<=7 first IMR address used
271      { port->interrupt_enable_mask=~(0x01<<port->nIRQ);
272        port->nIRQVector=port->nIRQ+8;
273        port->IMR_8259=IMR_8259_0;
274        port->ISR_8259=ISR_8259_0;
275      }
276     else
277      { port->interrupt_enable_mask=~(0x01<<(port->nIRQ%8));
278        port->nIRQVector=0x70+(port->nIRQ-8);
279        port->IMR_8259=IMR_8259_1;
280        port->ISR_8259=ISR_8259_1;
281      }
282
283     port->next_port = NULL;
284     port->last_port = irq_bot_com_port[port->nIRQ];
285     if (irq_bot_com_port[port->nIRQ] != NULL) irq_bot_com_port[port->nIRQ]->next_port = port;
286     irq_bot_com_port[port->nIRQ] = port;
287     DISABLE();
288     if (port->last_port == NULL)
289      { // DZ orig lines in here
290        _install_irq(port->nIRQVector,port->comm_handler);
291        //enable interrupt port->nIRQ level
292        outportb(port->IMR_8259,inportb(port->IMR_8259)&
293                 port->interrupt_enable_mask);
294      }
295        
296     // DZ again:
297     outportb(port->MCR,MCRALL); //setup modem
298     outportb(port->IER,IERALL); //enable all communication's interrupts
299     // to here
300     ENABLE();
301   }
302
303   port->installed=YES;
304   return(1);
305 }
306
307 //------------------ DZ COMM PORT INTERRUPT HANDLER ---------------
308 // always return zero
309 inline int dz_comm_port_interrupt_handler(comm_port *port)
310 { int int_id;
311   int c;
312 //  putch('1');
313
314   while (1) //loop while !end of all interrupts
315    { int_id=inportb(port->IIR); //get interrupt id
316         //next loop added by Neil Townsend
317      while ((int_id&0x01)==1) //no interrupts (left) to handle on this port
318       { if (port->next_port==NULL)
319          { outportb(0x20,0x20);
320            if (port->nIRQ>7) //Thanks for SET for this fix
321              outportb(0xA0,0x20); //now IRQ8-IRQ15 handled properly.
322
323            return(0);
324          }
325         port=(comm_port*)port->next_port;
326         int_id=inportb(port->IIR);
327       }
328
329       switch (int_id)
330         {
331           case 0xcc: //Character Timeout Indication N.Lohmann 6.3.98
332                      // only possible if FiFo's are enabled.
333             comm_port_rtmout(port);
334             break;
335           case 0xc6: //FiFo LSINT
336           case 0x06: //LSINT:
337             c=inportb(port->LSR);
338             if (port->lsr_handler!=NULL) port->lsr_handler(c);
339             break;
340           case 0xc4: //FiFo RDAINT
341           case 0x04: //RDAINT
342             comm_port_rdr(port);
343             break;
344           case 0xc2: //FiFo THREINT
345           case 0x02: //THREINT :
346             comm_port_trx(port);
347             break;
348           case 0xc0: //FiFo MSINT
349           case 0x00: //MSINT :
350             c=inportb(port->MSR);
351             if (port->msr_handler!=NULL) port->msr_handler(c);
352
353             if (port->control_type==RTS_CTS)
354              { if (port->cts==CTS_OFF && c&0x10)
355                 { port->cts=CTS_ON;
356                   if (port->rts==RTS_ON)
357                     interrupt_on(port,THREINT);
358                 }
359                else
360                  if (port->cts==CTS_ON && !c&0x10)
361                   { port->cts=CTS_OFF;
362                     interrupt_off(port,THREINT);
363                   }
364               }
365             break;
366          }//end case
367    } //end while 1
368
369   return(0);
370 }
371 END_OF_FUNCTION(dz_comm_port_interrupt_handler);
372
373 //----------------------- COMM PORT RTMOUT  ------------------------
374 //Nils Lohmann 8.3.98
375 //Time Out Indication, service routine  triggered after 4 Char-times
376 //if there is at least one Byte in FiFo and no read-Cykle happened.
377
378 inline void comm_port_rtmout(comm_port *port)
379 {
380   comm_port_rdr(port);
381 }
382 END_OF_FUNCTION(comm_port_rtmout);
383
384 //----------------------- COMM PORT DELETE ------------------------
385
386 void comm_port_delete(comm_port *port)
387 {
388   if (port->installed==NO) return;
389  
390   comm_port_uninstall(port);
391
392   free(port);
393 }
394
395 //------------------------- COMM PORT OUT -----------------------------
396
397 inline void comm_port_out(comm_port *port,byte c)
398 {
399
400   queue_put_(port->OutBuf,&c);
401   switch (port->control_type)
402    { case NO_CONTROL :
403       interrupt_on(port,THREINT);
404       break;
405      case XON_XOFF : // XON/XOFF
406       if (port->xonxoff_rcvd!=XOFF_RCVD)
407         { interrupt_on(port,THREINT);
408         }
409      case RTS_CTS : // RTS_CTR
410       if (port->cts==CTS_ON) //modem is 'clear to send'
411        { if (port->rts==RTS_ON) //Fixed by SET (was RTS_OFF)
412           { interrupt_on(port,THREINT);
413           }
414       }
415       break;
416      default:
417       break;
418    }
419 }
420
421 //------------------------- COMM PORT TEST -----------------------------
422
423 inline int comm_port_test(comm_port *port)
424 { byte c;
425
426   switch (port->control_type)
427    { case NO_CONTROL :
428       break;
429      case XON_XOFF : // XON/XOFF
430       if (((port->InBuf)->tail<(port->InBuf)->fill_level)&&(port->xonxoff_send!=XON_SENT))
431         { port->xon=1;
432           interrupt_on(port,THREINT);
433         }
434       break;
435      case RTS_CTS :
436       if (((port->InBuf)->tail<(port->InBuf)->fill_level)&&(port->rts==RTS_OFF))
437         { outportb(port->MCR,inportb(port->MCR)|0x02); //setting RTS
438           port->rts=RTS_ON;
439           interrupt_on(port,THREINT);
440        }
441       break;
442      default:
443       break;
444    }
445   if (queue_empty(port->InBuf))
446    { return(-1);
447    }
448   queue_get_(port->InBuf, &c);
449   return(c);
450 }
451
452 //----------------------- COMM PORT STRING SEND -------------------------
453
454 void comm_port_string_send(comm_port *port,char *s)
455 {
456   int i;
457
458   if (s==NULL) return;
459   for (i=0;s[i]!=0;i++) comm_port_out(port,s[i]);
460 }
461
462 //---------------------- COMM PORT COMMAND SEND -------------------------
463
464 void comm_port_command_send(comm_port *port,char *s)
465 {
466   int i;
467
468   if (s==NULL) return;
469   for (i=0;s[i]!=0;i++)comm_port_out(port,s[i]);
470   comm_port_out(port,'\r');
471 }
472
473 //------------------- MODEM HANG UP -----------------
474
475 void modem_hangup(comm_port *port)
476 {
477   comm_port_out(port,2);
478   delay(3000);
479   comm_port_string_send(port,"+++");
480   delay(3000);
481   comm_port_string_send(port,"ATH0\r");
482 }
483
484 //---------------------- COMM PORT HAND ---------------------------
485
486 void comm_port_hand(comm_port *port,int m)
487 { int c;
488   c=inportb(port->MCR);
489   outportb(port->MCR,c&m);
490 }
491
492 inline int comm_port_send_xoff(comm_port *port)
493 {
494   if (port->xonxoff_send!=XOFF_SENT)
495    { port->xoff=1;
496      interrupt_on(port,THREINT);
497    }
498   return(1);
499 }
500
501 inline int comm_port_send_xon(comm_port *port)
502 {
503   if (port->xonxoff_send!=XON_SENT)
504    { port->xon=1;
505      interrupt_on(port,THREINT);
506    }
507   return(1);
508 }
509
510 //-------------------- COMM PORT LOAD SETTINGS ---------------------
511
512 #ifdef __DEVICE__
513 int comm_port_load_settings(device *dev,char *ini_name)
514 #else
515 int comm_port_load_settings(comm_port *port,char *ini_name)
516 #endif
517 {
518   #ifdef __DEVICE__
519   comm_port *port=dev->device_user_data;
520   #endif
521   FILE *ini;
522   int l,i;
523   char *buf,*buf_end,*s,v[64];
524   comm com=port->nComm;
525   char com_name[7]={'[','c','o','m',com+49,']',0};
526   char com_end[11]={'[','c','o','m',com+49,' ','e','n','d',']',0};
527
528   if ((ini=fopen(ini_name,"rt"))==NULL) return(0);
529   l=filelength(fileno(ini));
530   if ((buf=(char*)alloca(l))==NULL)
531     { fclose(ini);
532       return(0);
533     }
534
535   l=fread(buf,1,l,ini);
536   fclose(ini);
537   buf[l]=0;
538   strlwr(buf);
539
540   s=strstr(buf,com_name);
541   buf_end=strstr(buf,com_end);
542
543   if (s==NULL||buf_end==NULL) return(-1);
544   *buf_end=0;
545
546   //get baud rate
547   if ((s=strstr(buf,"baud"))!=NULL)
548    { if (not_commented(s)&&(s=strchr(s,'='))!=NULL)
549       { s++;i=0;
550         while ((*s!=';')&&(*s!='\n')&&(*s!=0)&&(i<9))
551          if (!isspace(*s)) v[i++]=*s++;
552
553         v[i]=0;
554         if ((i=atoi(v))!=0) port->nBaud=i;
555       }
556    }
557
558   //get irq number
559   if ((s=strstr(buf,"irq"))!=NULL)
560    { if (not_commented(s)&&(s=strchr(s,'='))!=NULL)
561       { s++;i=0;
562         while ((*s!=';')&&(*s!='\n')&&(*s!=0)&&(i<9))
563          if (!isspace(*s)) v[i++]=*s++;
564
565         v[i]=0;
566         if ((i=atoi(v))!=0) port->nIRQ=i;
567       }
568    }
569
570   //get comm address
571   if ((s=strstr(buf,"address"))!=NULL)
572    { if (not_commented(s)&&(s=strchr(s,'='))!=NULL)
573       { s++;i=0;
574         while ((*s!=';')&&(*s!='\n')&&(*s!=0)&&(i<9))
575          if (!isspace(*s)) v[i++]=*s++;
576
577         v[i]=0;
578         if ((i=strtol(v,NULL,0))!=0) port->nPort=strtol(v,NULL,0);
579       }
580    }
581
582   //get data bits
583   if ((s=strstr(buf,"data"))!=NULL)
584    { if (not_commented(s)&&(s=strchr(s,'='))!=NULL)
585        { s++;i=0;
586          while ((*s!=';')&&(*s!='\n')&&(*s!=0)&&(i<9))
587           if (!isspace(*s)) v[i++]=*s++;
588
589          v[i]=0;
590          if ((i=atoi(v))!=0)
591           switch (i)
592            { case 8 :
593               port->nData=BITS_8;
594               break;
595              case 7 :
596               port->nData=BITS_7;
597               break;
598              case 6 :
599               port->nData=BITS_6;
600               break;
601              case 5 :
602               port->nData=BITS_5;
603               break;
604            }
605        }
606    }
607
608   //get parity bits
609   if ((s=strstr(buf,"parity"))!=NULL)
610    { if (not_commented(s)&&(s=strchr(s,'='))!=NULL)
611        { s++;i=0;
612          while ((*s!=';')&&(*s!='\n')&&(*s!=0)&&(i<9))
613           if (!isspace(*s)) v[i++]=*s++;
614          v[i]=0;
615
616          if (strcmp(v,"even")==0) port->nParity=EVEN_PARITY;
617          else
618         if (strcmp(v,"odd")==0) port->nParity=ODD_PARITY;
619          else
620          if (strcmp(v,"no")==0||strcmp(v,"none")==0) port->nParity=NO_PARITY;
621        }
622    }
623
624   //get control type
625   if ((s=strstr(buf,"control"))!=NULL)
626    { if (not_commented(s)&&(s=strchr(s,'='))!=NULL)
627        { s++;i=0;
628          while ((*s!=';')&&(*s!='\n')&&(*s!=0)&&(i<9))
629           if (!isspace(*s)) v[i++]=*s++;
630          v[i]=0;
631
632          if (strcmp(v,"xon_xoff")==0||strcmp(v,"xon/xoff")==0) port->control_type=XON_XOFF;
633          else
634           if (strcmp(v,"no")==0||strcmp(v,"none")==0) port->control_type=NO_CONTROL;
635           else
636           if (strcmp(v,"rts_cts")==0||strcmp(v,"rts/cts")==0) port->control_type=RTS_CTS;
637       }
638    }
639
640   if ((s=strstr(buf,"stop"))!=NULL) //get stop bits
641    { if (not_commented(s)&&(s=strchr(s,'='))!=NULL)
642        { s++;i=0;
643          while ((*s!=';')&&(*s!='\n')&&(*s!=0)&&(i<9))
644           if (!isspace(*s)) v[i++]=*s++;
645
646          v[i]=0;
647          if ((i=atoi(v))!=0)
648           switch (i)
649            { case 1 :
650               port->nStop=STOP_1;
651               break;
652              case 2 :
653               port->nStop=STOP_2;
654               break;
655            }
656        }
657    }
658
659   if ((s=strstr(buf,"name"))!=NULL)
660    { if (not_commented(s)&&(s=strchr(s,'='))!=NULL)
661       { s++;i=0;
662         while ((*s!=';')&&(*s!='\n')&&(*s!=0)&&(i<64))
663          v[i++]=*s++;
664
665         v[i]=0;
666         strcpy(port->szName,v);
667       }
668    }
669
670   return(1);
671 }
672
673
674 //----------------------- COMM PORT RDR ------------------------
675
676 static inline void comm_port_rdr(comm_port *port)
677 { byte c;
678   int n;
679
680   do {
681     c = inportb(port->RDR);
682     switch (port->control_type)
683      { case NO_CONTROL :
684        queue_put_(port->InBuf,&c);
685        port->in_cnt++;
686        break;
687        case XON_XOFF : // XON/XOFF
688        if (c==XON_ASCII)
689         { port->xonxoff_rcvd=XON_RCVD;
690           interrupt_on(port,THREINT);
691           return;
692         }
693        if (c==XOFF_ASCII)
694         { port->xonxoff_rcvd=XOFF_RCVD;
695           interrupt_off(port,THREINT);
696           return;
697         }
698        n=queue_put_(port->InBuf,&c);
699        port->in_cnt++;
700        if (n) //buffer is near full
701         { if (port->xonxoff_send!=XOFF_SENT)
702            { port->xoff=1;
703              interrupt_on(port,THREINT);
704            }
705         }
706        break;
707        case RTS_CTS:
708       n=queue_put_(port->InBuf,&c);
709        port->in_cnt++;
710        if (n) //buffer is near full
711         { outportb(port->MCR,inportb(port->MCR)&(~0x02)); //dropping RTS
712           port->rts=RTS_OFF;
713         }
714        break;
715        default :
716        break;
717      }
718      c =inportb(port->LSR);
719   } while (c & 1);
720   // these lines are a cure for the well-known problem of TX interrupt
721   // lock-ups when receiving and transmitting at the same time
722   if (c & 0x40)
723     comm_port_trx(port);
724 }
725 static END_OF_FUNCTION(comm_port_rdr)
726
727 //----------------------- COMM PORT TRX ------------------------
728
729 static inline void comm_port_trx(comm_port *port)
730 { byte c;
731   int i, count = port->fifo ? 16 : 1;
732
733   for (i = count; i--; ) {
734     switch (port->control_type)
735      { case NO_CONTROL :
736        if (queue_empty(port->OutBuf))//queue empty, nothig to send
737         { interrupt_off(port,THREINT);
738           return;
739         }
740        queue_get_(port->OutBuf, &c);
741        port->out_cnt++;
742        outportb(port->THR,c);
743        break;
744        case XON_XOFF : // XON/XOFF
745        if (port->xoff==1)
746         { outportb(port->THR,XOFF_ASCII);
747           port->xoff=0;
748           port->xonxoff_send=XOFF_SENT;
749         }
750        else if (port->xon==1)
751         { outportb(port->THR,XON_ASCII);
752           port->xon=0;
753           port->xonxoff_send=XON_SENT;
754           return;
755         }
756        if (queue_empty(port->OutBuf))//queue empty, nothig to send
757         { interrupt_off(port,THREINT);
758           return;
759         }
760        queue_get_(port->OutBuf, &c);
761        outportb(port->THR,c);
762        port->out_cnt++;
763        break;
764        case RTS_CTS:
765        if (port->cts==CTS_OFF)
766         { return;
767         }
768        if (port->rts==RTS_OFF)
769         { port->rts=RTS_ON;
770           outportb(port->MCR,inportb(port->MCR)|0x02); //setting RTS
771         }
772        if (queue_empty(port->OutBuf))//queue empty, nothig to send
773         { outportb(port->MCR,inportb(port->MCR)&(~0x02)); //dropping RTS
774           port->rts=RTS_OFF;
775           interrupt_off(port,THREINT);
776           return;
777         }
778        queue_get_(port->OutBuf, &c);
779        outportb(port->THR,c);
780        port->out_cnt++;
781        break;
782        default :
783        break;
784      }
785   }
786 }
787 static END_OF_FUNCTION(comm_port_trx);
788
789 //------------------------- COMM PORT INIT -----------------------------
790
791 void dzcomm_init(void)
792 {
793   LOCK_FUNCTION(dz_comm_port_interrupt_handler);
794   LOCK_FUNCTION(comm_port_rdr);
795   LOCK_FUNCTION(comm_port_trx);
796   LOCK_FUNCTION(interrupt_on);
797   LOCK_FUNCTION(interrupt_off);
798   LOCK_FUNCTION(com1_wrapper);
799   LOCK_FUNCTION(com2_wrapper);
800   LOCK_FUNCTION(com3_wrapper);
801   LOCK_FUNCTION(com4_wrapper);
802   LOCK_FUNCTION(com5_wrapper);
803   LOCK_FUNCTION(com6_wrapper);
804   LOCK_FUNCTION(com7_wrapper);
805   LOCK_FUNCTION(com8_wrapper);
806   LOCK_VARIABLE(com1);
807   LOCK_VARIABLE(com2);
808   LOCK_VARIABLE(com3);
809   LOCK_VARIABLE(com4);
810   LOCK_VARIABLE(com5);
811   LOCK_VARIABLE(com6);
812   LOCK_VARIABLE(com7);
813   LOCK_VARIABLE(com8);
814   com1=NULL;
815   com2=NULL;
816   com3=NULL;
817   com4=NULL;
818   com5=NULL;
819   com6=NULL;
820   com7=NULL;
821   com8=NULL;
822   com_wrapper[0]=com1_wrapper;
823   com_wrapper[1]=com2_wrapper;
824   com_wrapper[2]=com3_wrapper;
825   com_wrapper[3]=com4_wrapper;
826   com_wrapper[4]=com5_wrapper;
827   com_wrapper[5]=com6_wrapper;
828   com_wrapper[6]=com7_wrapper;
829   com_wrapper[7]=com8_wrapper;
830   com_port[0]=&com1;
831   com_port[1]=&com2;
832   com_port[2]=&com3;
833   com_port[3]=&com4;
834   com_port[4]=&com5;
835   com_port[5]=&com6;
836   com_port[6]=&com7;
837   com_port[7]=&com8;
838
839 }
840
841 //----------------------- COMM PORT UNINSTALL ---------------------
842 // New routine to allow uninstalling without deleting
843 // and to simplyfy _delete and _reinstall
844 // by Neil Townsend
845 void comm_port_uninstall(comm_port *port)
846 { comm_port *i_port;
847
848   if (port->installed==NO) return;
849   i_port = irq_bot_com_port[port->nIRQ];
850
851   DISABLE();
852   if (i_port == port)
853    { irq_bot_com_port[port->nIRQ] = (comm_port *) port->last_port;
854      if (irq_bot_com_port[port->nIRQ]) irq_bot_com_port[port->nIRQ]->next_port = NULL;
855      i_port = NULL;
856    }
857   else i_port = (comm_port *) i_port->last_port;
858   while (i_port)
859    { if (i_port == port)
860       { if (i_port->last_port) ((comm_port *)i_port->last_port)->next_port = i_port->next_port;
861         if (i_port->next_port) ((comm_port *)i_port->next_port)->last_port = i_port->last_port;
862         i_port = NULL;
863       }
864      if (i_port) i_port = i_port->last_port;
865    }
866
867   if (irq_bot_com_port[port->nIRQ] == NULL) _remove_irq(port->nIRQVector);
868
869   { const byte IEROFF=0x00;
870     const byte MCROFF=0x00;
871     outportb(port->IER,IEROFF);
872     outportb(port->MCR,MCROFF);
873     outportb(port->IMR_8259,inportb(port->IMR_8259)&~(port->interrupt_enable_mask));
874   }
875   ENABLE();
876   port->installed = NO;
877
878 }
879
880
881 //----------------------- COMM PORT REINSTALL ---------------------------
882
883 int comm_port_reinstall(comm_port *port)
884 {
885   if (port->installed==NO) return(0);
886
887   comm_port_uninstall(port);
888   return (comm_port_install_handler(port));
889 }