⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ibmcom3.c

📁 IBMCOM_C serial port library
💻 C
📖 第 1 页 / 共 2 页
字号:
/*****************************************************************************

 *                                 ibmcom.c                                  *

 *****************************************************************************

 * DESCRIPTION: This file contains a set of routines for doing low-level     *

 *              serial communications on the IBM PC.  It was translated      *

 *              directly from Wayne Conrad's IBMCOM.PAS version 3.1, with    *

 *              the goal of near-perfect functional correspondence between   *

 *              the Pascal and C versions.                                   *

 *                                                                           *

 * REVISIONS:   18 OCT 89 - RAC - Original translation from IBMCOM.PAS, with *

 *                                liberal plagiarism of comments from the    *

 *                                Pascal.                                    *

 *****************************************************************************/



#include        <stdio.h>

#include        <dos.h>

#include        "ibmcom3.h"



/*****************************************************************************

 *                             8250 Definitions                              *

 *****************************************************************************/



/*      Offsets to various 8250 registers.  Taken from IBM Technical         */

/*      Reference Manual, p. 1-225                                           */



#define TXBUFF  0                       /* Transmit buffer register */

#define RXBUFF  0                       /* Receive buffer register */

#define DLLSB   0                       /* Divisor latch LS byte */

#define DLMSB   1                       /* Divisor latch MS byte */

#define IER     1                       /* Interrupt enable register */

#define IIR     2                       /* Interrupt ID register */

#define LCR     3                       /* Line control register */

#define MCR     4                       /* Modem control register */

#define LSR     5                       /* Line status register */

#define MSR     6                       /* Modem status register */



/*      Modem control register bits                                          */



#define DTR     0x01                    /* Data terminal ready */

#define RTS     0x02                    /* Request to send */

#define OUT1    0x04                    /* Output #1 */

#define OUT2    0x08                    /* Output #2 */

#define LPBK    0x10                    /* Loopback mode bit */



/*      Modem status register bits                                           */



#define DCTS    0x01                    /* Delta clear to send */

#define DDSR    0x02                    /* Delta data set ready */

#define TERI    0x04                    /* Trailing edge ring indicator */

#define DRLSD   0x08                    /* Delta Rx line signal detect */

#define CTS     0x10                    /* Clear to send */

#define DSR     0x20                    /* Data set ready */

#define RI      0x40                    /* Ring indicator */

#define RLSD    0x80                    /* Receive line signal detect */



/*      Line control register bits                                           */



#define DATA5   0x00                    /* 5 Data bits */

#define DATA6   0x01                    /* 6 Data bits */

#define DATA7   0x02                    /* 7 Data bits */

#define DATA8   0x03                    /* 8 Data bits */



#define STOP1   0x00                    /* 1 Stop bit */

#define STOP2   0x04                    /* 2 Stop bits */



#define NOPAR   0x00                    /* No parity */

#define ODDPAR  0x08                    /* Odd parity */

#define EVNPAR  0x18                    /* Even parity */

#define STKPAR  0x28                    /* Stick parity */

#define ZROPAR  0x38                    /* Zero parity */



/*      Line status register bits                                            */



#define RDR     0x01                    /* Receive data ready */

#define ERRS    0x1E                    /* All the error bits */

#define TXR     0x20                    /* Transmitter ready */



/*      Interrupt enable register bits                                       */



#define DR      0x01                    /* Data ready */

#define THRE    0x02                    /* Tx buffer empty */

#define RLS     0x04                    /* Receive line status */



/*****************************************************************************

 *                             Names for Numbers                             *

 *****************************************************************************/



#define MAX_PORT        4



#define TRUE            1

#define FALSE           0



/*****************************************************************************

 *                                Global Data                                *

 *****************************************************************************/



/*  UART i/o addresses.  Values depend upon which COMM port is selected  */



int     uart_data;              /* Data register */

int     uart_ier;               /* Interrupt enable register */

int     uart_iir;               /* Interrupt identification register */

int     uart_lcr;               /* Line control register */

int     uart_mcr;               /* Modem control register */

int     uart_lsr;               /* Line status register */

int     uart_msr;               /* Modem status register */



char    com_installed;          /* Flag: Communications routines installed */

int     intnum;                 /* Interrupt vector number for chosen port */

char    i8259bit;               /* 8259 bit mask */

char    old_i8259_mask;         /* Copy as it was when we were called */

char    old_ier;                /* Modem register contents saved for */

char    old_mcr;                /*  restoring when we're done */

void interrupt (*old_vector)(); /* Place to save COM1 vector */

void interrupt com_interrupt_driver(void);



/*  Transmit queue.  Characters to be transmitted are held here until the  */

/*  UART is ready to transmit them.  */



#define TX_QUEUE_SIZE   256     /* Transmit queue size.  Change to suit */



char    tx_queue[TX_QUEUE_SIZE];

int     tx_in;                  /* Index of where to store next character */

int     tx_out;                 /* Index of where to retrieve next character */

int     tx_chars;               /* Count of characters in queue */



/*  Receive queue.  Received characters are held here until retrieved by  */

/*  com_rx()  */



#define RX_QUEUE_SIZE   4096    /* Receive queue size.  Change to suit */



char    rx_queue[RX_QUEUE_SIZE];

int     rx_in;                  /* Index of where to store next character */

int     rx_out;                 /* Index of where to retrieve next character */

int     rx_chars;               /* Count of characters in queue */



/*****************************************************************************

 *                               com_install()                               *

 *****************************************************************************

 * DESCRIPTION: Installs the communications drivers.                         *

 *                                                                           *

 * SYNOPSIS:    status = com_install(int portnum);                           *

 *              int     portnum;        Desired port number                  *

 *              int     status;         0 = Successful installation          *

 *                                      1 = Invalid port number              *

 *                                      2 = No UART for specified port       *

 *                                      3 = Drivers already installed        *

 *                                                                           *

 * REVISIONS:   18 OCT 89 - RAC - Translated from IBMCOM.PAS                 *

 *****************************************************************************/



const int       uart_base[] =   { 0x3F8, 0x2F8, 0x3E8, 0x2E8 };

const char      intnums[] =     { 0x0C,  0x0B,  0x0C,  0x0B };

const char      i8259levels[] = { 4,     3,     4,     3 };



int com_install(int portnum) {



    if (com_installed)                          /* Drivers already installed */

        return 3;

    if ((portnum < 1) || (portnum > MAX_PORT))  /* Port number out of bounds */

        return 1;



    uart_data = uart_base[portnum-1];           /* Set UART I/O addresses */

    uart_ier  = uart_data + IER;                /*  for the selected comm */

    uart_iir  = uart_data + IIR;                /*  port */

    uart_lcr  = uart_data + LCR;

    uart_mcr  = uart_data + MCR;

    uart_lsr  = uart_data + LSR;

    uart_msr  = uart_data + MSR;

    intnum    = intnums[portnum-1];             /* Ditto for interrupt */

    i8259bit  = 1 << i8259levels[portnum-1];    /*  vector and 8259 bit mask */



    old_ier = inportb(uart_ier);                /* Return an error if we */

    outportb(uart_ier, 0);                      /*  can't access the UART */

    if (inportb(uart_ier) != 0)

        return 2;



    disable();                                  /* Save the original 8259 */

    old_i8259_mask = inportb(0x21);             /*  mask, then disable the */

    outportb(0x21, old_i8259_mask | i8259bit);  /*  8259 for this interrupt */

    enable();



    com_flush_tx();                             /* Clear the transmit and */

    com_flush_rx();                             /*  receive queues */



    old_vector = getvect(intnum);               /* Save old COMM vector, */

    setvect(intnum, &com_interrupt_driver);     /*  then install a new one, */

    com_installed = TRUE;                       /*  and note that we did */



    outportb(uart_lcr, DATA8 + NOPAR + STOP1);  /* 8 data, no parity, 1 stop */



    disable();                                  /* Save MCR, then enable */

    old_mcr = inportb(uart_mcr);                /*  interrupts onto the bus, */

    outportb(uart_mcr,                          /*  activate RTS and leave */

             (old_mcr & DTR) | (OUT2 + RTS));   /*  DTR the way it was */

    enable();



    outportb(uart_ier, DR);                     /* Enable receive interrupts */



    disable();                                  /* Now enable the 8259 for */

    outportb(0x21, inportb(0x21) & ~i8259bit);  /*  this interrupt */

    enable();

    return 0;                                   /* Successful installation */

    }                                           /* End com_install() */



/*****************************************************************************

 *                               com_install()                               *

 *****************************************************************************

 * DESCRIPTION: Denstalls the communications drivers completely, without     *

 *              changing the baud rate or DTR.  It tries to leave the        *

 *              interrupt vectors and enables and everything else as they    *

 *              were when the driver was installed.                          *

 *                                                                           *

 * NOTE:        This function MUST be called before returning to DOS, so the *

 *              interrupt vector won't point to our driver anymore, since it *

 *              will surely get overwritten by some other transient program  *

 *              eventually.                                                  *

 *                                                                           *

 * REVISIONS:   18 OCT 89 - RAC - Translated from IBMCOM.PAS                 *

 *****************************************************************************/



void com_deinstall(void) {



    if (com_installed) {                        /* Don't de-install twice! */

        outportb(uart_mcr, old_mcr);            /* Restore the UART */

        outportb(uart_ier, old_ier);            /*  registers ... */

        disable();

        outportb(0x21,                          /*  ... the 8259 interrupt */

                 (inportb(0x21)  & ~i8259bit) | /*  mask ... */

                 (old_i8259_mask &  i8259bit));

        enable();

        setvect(intnum, old_vector);            /*  ... and the comm */

        com_installed = FALSE;                  /*  interrupt vector */

        }                                       /* End com_installed */

    }                                           /* End com_deinstall() */



/*****************************************************************************

 *                              com_set_speed()                              *

 *****************************************************************************

 * DESCRIPTION: Sets the baud rate.                                          *

 *                                                                           *

 * SYNOPSIS:    void com_set_speed(unsigned speed);                          *

 *              unsigned speed;                 Desired baud rate            *

 *                                                                           *

 * NOTES:       The input parameter can be anything between 2 and 65535.     *

 *              However, I (Wayne) am not sure that extremely high speeds    *

 *              (those above 19200) will always work, since the baud rate    *

 *              divisor will be six or less, where a difference of one can   *

 *              represent a difference in baud rate of 3840 bits per second  *

 *              or more.)                                                    *

 *                                                                           *

 * REVISIONS:   18 OCT 89 - RAC - Translated from IBMCOM.PAS                 *

 *****************************************************************************/



void com_set_speed(long speed) {



    unsigned    divisor;                        /* A local temp */



    if (com_installed) {

        if (speed < 2) speed = 2;               /* Force proper input */

        divisor = 115200L / speed;              /* Recond baud rate divisor */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -