2 * DZcomm : serial communication add-on for Allegro.
4 * Copyright (c) 1997 Dim Zegebart, Moscow Russia.
5 * zager@post.comstar.ru
11 #include <sys/movedata.h>
21 typedef unsigned int uint;
22 typedef unsigned short int usint;
23 typedef unsigned char byte;
25 #define com_(N) comm_port *com##N
36 #define com_wrapper_(N) static int com##N##_wrapper(void) \
37 { DISABLE(); /* adb -- why this? */ \
38 dz_comm_port_interrupt_handler(com##N##); \
41 END_OF_FUNCTION(com##N##_wrapper);
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];
57 inline void dz_make_comm_err(char *szErr) {strcpy(szDZCommErr,szErr);}
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);
68 //const byte THREOFF=0xfd;
69 const byte THREINT=0x02;
70 const byte RDAINT=0x04;
72 //-------------------------- PRINT BIN --------------------------
74 void print_bin_s(int c,char *s)
77 sprintf (s,"%c : ",c);
80 if (c&(mask<<(j+i*8))) strcat(s,"1");
86 //------------------------- INTERRUPT ON -----------------------------
88 static inline void interrupt_on(comm_port *port,byte _interrupt_)
91 if (!(i&_interrupt_)) outportb(port->IER,i|_interrupt_);
93 END_OF_FUNCTION(interrupt_on);
95 //------------------------- INTERRUPT OFF -----------------------------
97 static inline void interrupt_off(comm_port *port,byte _interrupt_)
100 if (i&_interrupt_) outportb(port->IER,i&~_interrupt_);
102 END_OF_FUNCTION(interrupt_off);
104 //------------------------- COMM PORT INIT --------------------------
106 comm_port *comm_port_init(comm com)
107 { comm_port *port=(comm_port*)malloc(sizeof(comm_port));
112 { dz_make_comm_err("Out of memory !");
116 if ((port->InBuf=queue_new_(4096,1))==NULL)
117 { dz_make_comm_err("Out of memory !");
120 if ((port->OutBuf=queue_new_(4096,1))==NULL)
121 { dz_make_comm_err("Out of memory !");
122 queue_delete(port->InBuf);
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
135 //set default values (user may change it later)
137 if (com==_com1||com==_com3||com==_com5||com==_com7) port->nIRQ=4;
138 else port->nIRQ=3; //com2 or com4
140 strcpy(port->szName,"COM ");
141 port->szName[3]=com+49;
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.
153 _go32_dpmi_lock_data(port,sizeof(comm_port));
154 *(com_port[com])=port;
159 //-------------------- COMM_PORT_FIFO_INIT ----------------------
161 void comm_port_fifo_init(comm_port *port)
163 //setting up FIFO if possible
164 int c=inportb(port->SCR);
165 outportb(port->SCR,0x55);
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
173 // else printf("\nFIFO OK\n");
178 //----------------------- COMM PORT INSTALL HANDLER ------------------
179 //modifyed by Neil Townsend to support IRQ sharing
180 int comm_port_install_handler(comm_port *port)
183 { dz_make_comm_err("Set up comm parametrs first ! Call comm_port_new() first.");
186 if (port->installed==YES)
187 { dz_make_comm_err("Comm already installed !");
191 { dz_make_comm_err("IRQ number out of range ! Must be 0 ... 15 .");
194 if (port->comm_handler==NULL)
195 { dz_make_comm_err("Specify comm's handler (see 'comm_handler' member's description) !");
199 { dz_make_comm_err("Invalid baud rate !");
203 switch(port->control_type)
207 port->xonxoff_rcvd=XON_RCVD;
208 port->xonxoff_send=XON_SENT;
212 port->rts=RTS_ON; //fixed by SET (was RTS_OFF)
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;
231 for(i=0;i<8;i++) outportb(port->RDR+i,0);
234 comm_port_fifo_init(port);
236 { unsigned char temp;
238 { temp=inportb(port->RDR);
239 temp=inportb(port->LSR);
240 temp=inportb(port->MSR);
241 temp=inportb(port->IIR);
247 //set communication parametrs
248 //MOVED forwards so done before interupts enabled
249 { int divisor=115200/port->nBaud;
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
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;
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;
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;
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);
297 outportb(port->MCR,MCRALL); //setup modem
298 outportb(port->IER,IERALL); //enable all communication's interrupts
307 //------------------ DZ COMM PORT INTERRUPT HANDLER ---------------
308 // always return zero
309 inline int dz_comm_port_interrupt_handler(comm_port *port)
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.
325 port=(comm_port*)port->next_port;
326 int_id=inportb(port->IIR);
331 case 0xcc: //Character Timeout Indication N.Lohmann 6.3.98
332 // only possible if FiFo's are enabled.
333 comm_port_rtmout(port);
335 case 0xc6: //FiFo LSINT
337 c=inportb(port->LSR);
338 if (port->lsr_handler!=NULL) port->lsr_handler(c);
340 case 0xc4: //FiFo RDAINT
344 case 0xc2: //FiFo THREINT
345 case 0x02: //THREINT :
348 case 0xc0: //FiFo MSINT
350 c=inportb(port->MSR);
351 if (port->msr_handler!=NULL) port->msr_handler(c);
353 if (port->control_type==RTS_CTS)
354 { if (port->cts==CTS_OFF && c&0x10)
356 if (port->rts==RTS_ON)
357 interrupt_on(port,THREINT);
360 if (port->cts==CTS_ON && !c&0x10)
362 interrupt_off(port,THREINT);
371 END_OF_FUNCTION(dz_comm_port_interrupt_handler);
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.
378 inline void comm_port_rtmout(comm_port *port)
382 END_OF_FUNCTION(comm_port_rtmout);
384 //----------------------- COMM PORT DELETE ------------------------
386 void comm_port_delete(comm_port *port)
388 if (port->installed==NO) return;
390 comm_port_uninstall(port);
395 //------------------------- COMM PORT OUT -----------------------------
397 inline void comm_port_out(comm_port *port,byte c)
400 queue_put_(port->OutBuf,&c);
401 switch (port->control_type)
403 interrupt_on(port,THREINT);
405 case XON_XOFF : // XON/XOFF
406 if (port->xonxoff_rcvd!=XOFF_RCVD)
407 { interrupt_on(port,THREINT);
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);
421 //------------------------- COMM PORT TEST -----------------------------
423 inline int comm_port_test(comm_port *port)
426 switch (port->control_type)
429 case XON_XOFF : // XON/XOFF
430 if (((port->InBuf)->tail<(port->InBuf)->fill_level)&&(port->xonxoff_send!=XON_SENT))
432 interrupt_on(port,THREINT);
436 if (((port->InBuf)->tail<(port->InBuf)->fill_level)&&(port->rts==RTS_OFF))
437 { outportb(port->MCR,inportb(port->MCR)|0x02); //setting RTS
439 interrupt_on(port,THREINT);
445 if (queue_empty(port->InBuf))
448 queue_get_(port->InBuf, &c);
452 //----------------------- COMM PORT STRING SEND -------------------------
454 void comm_port_string_send(comm_port *port,char *s)
459 for (i=0;s[i]!=0;i++) comm_port_out(port,s[i]);
462 //---------------------- COMM PORT COMMAND SEND -------------------------
464 void comm_port_command_send(comm_port *port,char *s)
469 for (i=0;s[i]!=0;i++)comm_port_out(port,s[i]);
470 comm_port_out(port,'\r');
473 //------------------- MODEM HANG UP -----------------
475 void modem_hangup(comm_port *port)
477 comm_port_out(port,2);
479 comm_port_string_send(port,"+++");
481 comm_port_string_send(port,"ATH0\r");
484 //---------------------- COMM PORT HAND ---------------------------
486 void comm_port_hand(comm_port *port,int m)
488 c=inportb(port->MCR);
489 outportb(port->MCR,c&m);
492 inline int comm_port_send_xoff(comm_port *port)
494 if (port->xonxoff_send!=XOFF_SENT)
496 interrupt_on(port,THREINT);
501 inline int comm_port_send_xon(comm_port *port)
503 if (port->xonxoff_send!=XON_SENT)
505 interrupt_on(port,THREINT);
510 //-------------------- COMM PORT LOAD SETTINGS ---------------------
513 int comm_port_load_settings(device *dev,char *ini_name)
515 int comm_port_load_settings(comm_port *port,char *ini_name)
519 comm_port *port=dev->device_user_data;
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};
528 if ((ini=fopen(ini_name,"rt"))==NULL) return(0);
529 l=filelength(fileno(ini));
530 if ((buf=(char*)alloca(l))==NULL)
535 l=fread(buf,1,l,ini);
540 s=strstr(buf,com_name);
541 buf_end=strstr(buf,com_end);
543 if (s==NULL||buf_end==NULL) return(-1);
547 if ((s=strstr(buf,"baud"))!=NULL)
548 { if (not_commented(s)&&(s=strchr(s,'='))!=NULL)
550 while ((*s!=';')&&(*s!='\n')&&(*s!=0)&&(i<9))
551 if (!isspace(*s)) v[i++]=*s++;
554 if ((i=atoi(v))!=0) port->nBaud=i;
559 if ((s=strstr(buf,"irq"))!=NULL)
560 { if (not_commented(s)&&(s=strchr(s,'='))!=NULL)
562 while ((*s!=';')&&(*s!='\n')&&(*s!=0)&&(i<9))
563 if (!isspace(*s)) v[i++]=*s++;
566 if ((i=atoi(v))!=0) port->nIRQ=i;
571 if ((s=strstr(buf,"address"))!=NULL)
572 { if (not_commented(s)&&(s=strchr(s,'='))!=NULL)
574 while ((*s!=';')&&(*s!='\n')&&(*s!=0)&&(i<9))
575 if (!isspace(*s)) v[i++]=*s++;
578 if ((i=strtol(v,NULL,0))!=0) port->nPort=strtol(v,NULL,0);
583 if ((s=strstr(buf,"data"))!=NULL)
584 { if (not_commented(s)&&(s=strchr(s,'='))!=NULL)
586 while ((*s!=';')&&(*s!='\n')&&(*s!=0)&&(i<9))
587 if (!isspace(*s)) v[i++]=*s++;
609 if ((s=strstr(buf,"parity"))!=NULL)
610 { if (not_commented(s)&&(s=strchr(s,'='))!=NULL)
612 while ((*s!=';')&&(*s!='\n')&&(*s!=0)&&(i<9))
613 if (!isspace(*s)) v[i++]=*s++;
616 if (strcmp(v,"even")==0) port->nParity=EVEN_PARITY;
618 if (strcmp(v,"odd")==0) port->nParity=ODD_PARITY;
620 if (strcmp(v,"no")==0||strcmp(v,"none")==0) port->nParity=NO_PARITY;
625 if ((s=strstr(buf,"control"))!=NULL)
626 { if (not_commented(s)&&(s=strchr(s,'='))!=NULL)
628 while ((*s!=';')&&(*s!='\n')&&(*s!=0)&&(i<9))
629 if (!isspace(*s)) v[i++]=*s++;
632 if (strcmp(v,"xon_xoff")==0||strcmp(v,"xon/xoff")==0) port->control_type=XON_XOFF;
634 if (strcmp(v,"no")==0||strcmp(v,"none")==0) port->control_type=NO_CONTROL;
636 if (strcmp(v,"rts_cts")==0||strcmp(v,"rts/cts")==0) port->control_type=RTS_CTS;
640 if ((s=strstr(buf,"stop"))!=NULL) //get stop bits
641 { if (not_commented(s)&&(s=strchr(s,'='))!=NULL)
643 while ((*s!=';')&&(*s!='\n')&&(*s!=0)&&(i<9))
644 if (!isspace(*s)) v[i++]=*s++;
659 if ((s=strstr(buf,"name"))!=NULL)
660 { if (not_commented(s)&&(s=strchr(s,'='))!=NULL)
662 while ((*s!=';')&&(*s!='\n')&&(*s!=0)&&(i<64))
666 strcpy(port->szName,v);
674 //----------------------- COMM PORT RDR ------------------------
676 static inline void comm_port_rdr(comm_port *port)
681 c = inportb(port->RDR);
682 switch (port->control_type)
684 queue_put_(port->InBuf,&c);
687 case XON_XOFF : // XON/XOFF
689 { port->xonxoff_rcvd=XON_RCVD;
690 interrupt_on(port,THREINT);
694 { port->xonxoff_rcvd=XOFF_RCVD;
695 interrupt_off(port,THREINT);
698 n=queue_put_(port->InBuf,&c);
700 if (n) //buffer is near full
701 { if (port->xonxoff_send!=XOFF_SENT)
703 interrupt_on(port,THREINT);
708 n=queue_put_(port->InBuf,&c);
710 if (n) //buffer is near full
711 { outportb(port->MCR,inportb(port->MCR)&(~0x02)); //dropping RTS
718 c =inportb(port->LSR);
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
725 static END_OF_FUNCTION(comm_port_rdr)
727 //----------------------- COMM PORT TRX ------------------------
729 static inline void comm_port_trx(comm_port *port)
731 int i, count = port->fifo ? 16 : 1;
733 for (i = count; i--; ) {
734 switch (port->control_type)
736 if (queue_empty(port->OutBuf))//queue empty, nothig to send
737 { interrupt_off(port,THREINT);
740 queue_get_(port->OutBuf, &c);
742 outportb(port->THR,c);
744 case XON_XOFF : // XON/XOFF
746 { outportb(port->THR,XOFF_ASCII);
748 port->xonxoff_send=XOFF_SENT;
750 else if (port->xon==1)
751 { outportb(port->THR,XON_ASCII);
753 port->xonxoff_send=XON_SENT;
756 if (queue_empty(port->OutBuf))//queue empty, nothig to send
757 { interrupt_off(port,THREINT);
760 queue_get_(port->OutBuf, &c);
761 outportb(port->THR,c);
765 if (port->cts==CTS_OFF)
768 if (port->rts==RTS_OFF)
770 outportb(port->MCR,inportb(port->MCR)|0x02); //setting RTS
772 if (queue_empty(port->OutBuf))//queue empty, nothig to send
773 { outportb(port->MCR,inportb(port->MCR)&(~0x02)); //dropping RTS
775 interrupt_off(port,THREINT);
778 queue_get_(port->OutBuf, &c);
779 outportb(port->THR,c);
787 static END_OF_FUNCTION(comm_port_trx);
789 //------------------------- COMM PORT INIT -----------------------------
791 void dzcomm_init(void)
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);
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;
841 //----------------------- COMM PORT UNINSTALL ---------------------
842 // New routine to allow uninstalling without deleting
843 // and to simplyfy _delete and _reinstall
845 void comm_port_uninstall(comm_port *port)
848 if (port->installed==NO) return;
849 i_port = irq_bot_com_port[port->nIRQ];
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;
857 else i_port = (comm_port *) i_port->last_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;
864 if (i_port) i_port = i_port->last_port;
867 if (irq_bot_com_port[port->nIRQ] == NULL) _remove_irq(port->nIRQVector);
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));
876 port->installed = NO;
881 //----------------------- COMM PORT REINSTALL ---------------------------
883 int comm_port_reinstall(comm_port *port)
885 if (port->installed==NO) return(0);
887 comm_port_uninstall(port);
888 return (comm_port_install_handler(port));