/************************************************************************/ /* */ /* ***** ***** */ /* ***** ***** */ /* ***** ***** */ /* ***** ***** */ /* *************** *************** */ /* ***************** ***************** */ /* *************** *************** */ /* ***** ***** TheNetNode */ /* ***** ***** Portable */ /* ***** ***** Network */ /* ***** ***** Software */ /* */ /* File os/go32/16550.c (maintained by: ???) */ /* */ /* This file is part of "TheNetNode" - Software Package */ /* */ /* Copyright (C) 1998 - 2008 NORD>base; if (!ap->is_16550) { /********************************************************************* * <<<<<<<<<<< interrupt function for 8250 and 16450 >>>>>>>>>>>>>>> * *********************************************************************/ while ((iir = inportb(IIR)) != 1) { /* while interrup pending */ switch (iir) { case 0x04: /************************************************************* * interrupt type is - Receiver data available * * interrupt reset with : read rx buffer register * ************************************************************/ /* read data + clear interrupt */ ap->in_buffer[ap->in_buffer_in++] = inportb(TRX); if (ap->in_buffer_in == ap->in_buffersize) ap->in_buffer_in = 0; break; case 0x02: /************************************************************* * interrupt type is - Transmitter Holding Registre Empty * * source int. is - Transmitter Holding Registre Empty * * interrupt reset with : reading iir if source * * or write in tx holding register * ************************************************************/ if (ap->out_buffer_in != ap->out_buffer_out) { outportb(TRX, ap->out_buffer[ap->out_buffer_out++]); if (ap->out_buffer_out == ap->out_buffersize) ap->out_buffer_out = 0; } else ap->out_aktiv = FALSE; break; case 0x06: /************************************************************* * interrupt type is - receiver line status * * source int is - Overun error or - Parity erorr * * - framming error or - Break interrupt * * interrupt reset with : reading the Line Status Register * ************************************************************/ ap->in_buffer[ap->in_buffer_in++] = 0xdb; if (ap->in_buffer_in == ap->in_buffersize) ap->in_buffer_in = 0; ap->in_buffer[ap->in_buffer_in++] = 0x00; /* erzeugt Bad Frame*/ if (ap->in_buffer_in == ap->in_buffersize) ap->in_buffer_in = 0; inportb(LSR); /* reset this interupt */ break; case 0x00: /************************************************************* * interrupt type is - Modem status (normal never activ) * * source int is - CTS or DSR or Ring or DCD * * interrupt reset with : reading Modem Status Register * ************************************************************/ inportb(MSR); /* reset interrupt */ break; } /* end switch */ } /* end while */ } /* end if */ else { /********************************************************************* * <<<<<<<<<<<<<<<<< interrupt function for 16550 >>>>>>>>>>>>>>>>>> * ********************************************************************/ while ((iir = inportb(IIR)&0x8f) != 0x81){ /* while interrup pending */ switch (iir) { case 0x84: case 0x8C: /************************************************************* * interrupt type is - Receiver data available (0x84) or * * - Caractere timeout (0x8C) * * interrupt reset with : read rx buffer register Drops * * below the trigger Level (0x84) * * : read all the caracter in rx buffer * ************************************************************/ /* while data ready ? */ while((inportb(LSR) & 0x01) == 0x01) { ap->in_buffer[ap->in_buffer_in++] = inportb(TRX); if (ap->in_buffer_in == ap->in_buffersize) ap->in_buffer_in = 0; } break; case 0x82: /************************************************************* * interrupt type is - Transmitter Holding Register Empty * * source int. is - Transmitter Holding Register Empty * * interrupt reset with : reading iir if source * * or write in tx holding register * ************************************************************/ if (ap->out_buffer_in == ap->out_buffer_out ) ap->out_aktiv = FALSE; else { do { outportb(TRX, ap->out_buffer[ap->out_buffer_out++]); if (ap->out_buffer_out == ap->out_buffersize) ap->out_buffer_out = 0; } while((ap->out_buffer_in != ap->out_buffer_out) && (--i > 0)); } break; case 0x86: /************************************************************* * interrupt type is - receiver line status * * source int is - Overun error or - Parity erorr * * - framming error or - Break interrupt * * interrupt reset with : reading the Line Status Register * ************************************************************/ ap->in_buffer[ap->in_buffer_in++] = 0xdb; if (ap->in_buffer_in == ap->in_buffersize) ap->in_buffer_in = 0; ap->in_buffer[ap->in_buffer_in++] = 0x00; /* erzeugt Bad Frame */ if (ap->in_buffer_in == ap->in_buffersize) ap->in_buffer_in = 0; inportb(LSR); /* reset this interupt */ break; case 0x80: /************************************************************* * interrupt type is - Modem status (normal never activ) * * source int is - CTS or DSR or Ring or DCD * * interrupt reset with : reading Modem Status Register * ************************************************************/ inportb(MSR); /* reset interrupt */ break; } /* end switch */ } /* end while int */ } /* end else 8250 16450 / 16550 */ } /* end function */ void clear_sio(int dev) { int oldier; int c = 1; __com_struct *ap = &asydev[dev]; register int base; base = ap->base; /* Empfangs-Overrun loeschen */ while (inportb(LSR) != 0x60 && (c++ <= 1600)) inportb(TRX); /* Interruptfehlerquellen loeschen */ oldier = inportb(IER); /* alle Interrupts sperren */ outportb(IER, 0); c = 1; while (inportb(IIR) == 0 && c <= 10) { if ((inportb(IIR) & 6) == 6) { inportb(LSR); eoi(); } if ((inportb(IIR) & 4) == 4) { inportb(TRX); eoi(); } if (inportb(IIR) == 0) { inportb(MSR); eoi(); } c++; } outportb(IER, oldier); } void clear_rs232(int dev) { __com_struct *ap = &asydev[dev]; register int base; if (!ap->active) return; base = ap->base; clear_sio(dev); disable(); /* Int vorsichtshalber abschalten */ if (ap->is_16550) { outportb(FCR, 0x87); /* FIFO ON , reset rx and tx FIFO */ outportb(FCR, 0x81); /* trigger level = 14 bytes */ } do { inportb(TRX); /* Datenregister leeren */ } while((inportb(LSR) & 0x01) == 0x01); ap->in_buffer_in = ap->in_buffer_out = ap->out_buffer_in = ap->out_buffer_out = 0; ap->out_aktiv = FALSE; enable(); /* int wieder an */ } /*----------------------------------------------------------------------*/ /* Initialisieren der Schnittstelle, OHNE Baudrate setzen! */ /* Buffer initialisieren, Interrupt Vektoren setzen */ /* */ /* 16550A-FIFO-Bits (Portadresse [Basis+2]) */ /* ================ */ /* */ /* Bit Read: IIR Write: FIFO Control */ /* --------------------------------------------------- */ /* 0 Interrupt Pending FIFO enable */ /* 1 ID-Bit 1 FIFO Reset Receive */ /* 2 ID-Bit 2 FIFO Reset Transmit */ /* 3 ID-Bit 3 (Timeout) 0 (im PC/AT) */ /* 4 0 0 */ /* 5 0 0 */ /* 6 FIFO ON (nur 16550A) Trigger Level TL0 */ /* 7 FIFO ON Trigger Level TL1 */ /* */ /* TL1 TL0 Trigger-Level */ /* 0 0 1 Byte */ /* 0 1 4 Bytes */ /* 1 0 8 Bytes */ /* 1 1 14 Bytes */ /*----------------------------------------------------------------------*/ int open_rs232(int dev, int base, int irq, int insize, int outsize) { __com_struct *ap = &asydev[dev]; if (ap->active) { printf("*** WARNING: COM%u is already in use!\n",dev+1); return(-1); } ap->active = TRUE; ap->base = base; ap->irq = irq; clear_sio(dev); outportb(FCR, 0x01); /* enable FIFO mode (16550) */ printf("--- /dev/COM%u (0x%03X,IRQ%u), UART is ", dev+1, base, irq); if ((inportb(FCR) & 0x80) == 0x80) { /* test if FIFO enabled */ ap->is_16550 = TRUE; printf("16550A"); outportb(FCR,0x87); /* FIFO ON, clear rx and tx FIFO */ } else { ap->is_16550 = FALSE; printf("8250/16450"); } do { inportb(TRX); /* Datenregister leeren */ } while((inportb(LSR) & 0x01) == 0x01); outportb(LCR, 0x07); /* 8bit + 2 stop, DLAB auf 0 */ outportb(IER, 0x07); /* Interrupt: Rx, TX, RLS */ outportb(MCR, 0x08); /* Interrupt frei (out2) */ ap->in_buffer_in = ap->in_buffer_out = ap->out_buffer_in = ap->out_buffer_out = 0; ap->out_aktiv = FALSE; disable(); allocirq(irq, 0, rs232_int, dev); /* Vektor setzen */ ap->oldmask = getmask(irq); maskon(irq); ap->out_buffer = malloc(ap->in_buffersize = insize); ap->in_buffer = malloc(ap->out_buffersize = outsize); enable(); /* Interrupt frei */ return(dev); } /*----------------------------------------------------------------------*/ /* Schnittstelle sperren */ /*----------------------------------------------------------------------*/ void close_rs232(int dev) { __com_struct *ap = &asydev[dev]; register int base; if (!ap->active) return; base = ap->base; clear_sio(dev); disable(); if (!ap->oldmask) maskoff(ap->irq); outportb(IER, 0x00); /* keine Interrupt Freigabe */ outportb(MCR, 0x08); /* Out2 sperrt Interrupt */ if (ap->is_16550) outportb(FCR,0x00); /* FIFO OFF */ freeirq(ap->irq); enable(); } /*----------------------------------------------------------------------*/ /* Neuer Syntax nach DL1XAO, Implementierung DB7KG: */ /* Setzt die naechstbeste Baudrate und liefert die gesetzte zurueck. */ /*----------------------------------------------------------------------*/ int setbaud(int dev, int argu) { __com_struct *ap = &asydev[dev]; register int base; int baudtab[] = {12,24,48,96,192,384,576,1152,0}, *i, lsb; if (!ap->active) return(0); base = ap->base; clear_sio(dev); for (i = baudtab; *i; i++) if (argu <= *i) break; if (*i) argu = *i; /* wenn mehr als Maximalwert gewuenscht,*/ else argu = 1152; /* dann begrenzen */ lsb = 1152 / argu; /* Teiler berechnen */ outportb(LCR, 0x87); /* auf Baudraten Register 2 stop bit */ outportb(TRX, lsb ); /* LSB Teilerfaktor */ outportb(IER, 0x00); /* MSB */ outportb(LCR, 0x07); /* 8 Bit, keine Paritaet, 2 Stop */ return(argu); } /*----------------------------------------------------------------------*/ /* Anzahl der Stopbits setzen */ /*----------------------------------------------------------------------*/ void setstopbits(int dev, int stops) { __com_struct *ap = &asydev[dev]; register int base; base = ap->base; if (!ap->active) return; clear_sio(dev); if (stops == 2) outportb(LCR, 0x07); /* 8 Bit, keine Paritaet, 2 Stop */ else outportb(LCR, 0x03); /* 8 Bit, k. Paritaet, 1 Stop */ clear_sio(dev); } /*----------------------------------------------------------------------*/ /* Zeichen aus Buffer an Programm liefern */ /*----------------------------------------------------------------------*/ int rs232_in(int dev) { char c; register __com_struct *ap = &asydev[dev]; if (!ap->active) return(-1); if (ap->in_buffer_in != ap->in_buffer_out) { c = ap->in_buffer[ap->in_buffer_out++]; if (ap->in_buffer_out == ap->in_buffersize) ap->in_buffer_out = 0; return(c); } return(-1); } /*----------------------------------------------------------------------*/ /* Zeichen an Schnittstelle geben, ggfs im Buffer speichern */ /*----------------------------------------------------------------------*/ void rs232_out(int dev, int c) { register __com_struct *ap = &asydev[dev]; if (!ap->active) return; disable(); if (ap->out_aktiv) { ap->out_buffer[ap->out_buffer_in++] = c; if (ap->out_buffer_in == ap->out_buffersize) ap->out_buffer_in = 0; } else { ap->out_aktiv = TRUE; outportb(ap->base,c); } enable(); } /*----------------------------------------------------------------------*/ /* Blockweise von der Schnittstelle lesen */ /*----------------------------------------------------------------------*/ int rs232_read(int dev, UBYTE *buf, int max) { register __com_struct *ap = &asydev[dev]; int n; if (!ap->active) return(-1); disable(); for (n = 0; n < max; n++) { if (ap->in_buffer_in != ap->in_buffer_out) { *buf++ = ap->in_buffer[ap->in_buffer_out++]; if (ap->in_buffer_out == ap->in_buffersize) ap->in_buffer_out = 0; } else { enable(); return(n); } } enable(); return(n); } /*----------------------------------------------------------------------*/ /* Speicherblock an Schnittstelle geben, ggfs im Buffer speichern */ /*----------------------------------------------------------------------*/ void rs232_write(int dev, UBYTE *start, UBYTE *end) { register __com_struct *ap = &asydev[dev]; if (!ap->active) return; disable(); if (!ap->out_aktiv) { ap->out_aktiv = TRUE; outportb(ap->base, *start++); } while((end - start) > 0L) { ap->out_buffer[ap->out_buffer_in++] = *start++; if (ap->out_buffer_in == ap->out_buffersize) ap->out_buffer_in = 0; } enable(); } /*----------------------------------------------------------------------*/ /* Status Eingabe */ /*----------------------------------------------------------------------*/ int rs232_in_status(int dev) { __com_struct *ap = &asydev[dev]; if (!ap->active) return(0); return(!(ap->in_buffer_in == ap->in_buffer_out)); } /*----------------------------------------------------------------------*/ /* Status Eingabe */ /*----------------------------------------------------------------------*/ int rs232_out_status(int dev) { __com_struct *ap = &asydev[dev]; if (!ap->active) return(0); /*#ifndef no_db7kg_fast_and_dirty_hack_for_db0fd if (ap->out_buffer_in == ap->out_buffer_out) ap->out_aktiv = FALSE; #endif*/ return(ap->out_aktiv); } void init_rs232(void) { int i; for (i = 0; i < MAXCOMS; i++) asydev[i].active = FALSE; } void exit_rs232(void) { int i; for (i = 0; i < MAXCOMS; i++) if (asydev[i].active) close_rs232(i); } /*----------------------------------------------------------------------*/ /* End of os/go32/16550.c */