progress on all fronts
[com32] / src / serial.c
index f9ee14c..6954508 100644 (file)
@@ -17,6 +17,7 @@ along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
 #include <stdio.h>
 #include <string.h>
+#include <assert.h>
 #include "config.h"
 #include "serial.h"
 #include "asmops.h"
@@ -113,16 +114,19 @@ along with this program.  If not, see <https://www.gnu.org/licenses/>.
 #define COM_FMT_8N1            LCTL_8N1
 #define COM_FMT_8N2            LCTL_8N2
 
+#define INBUF_SIZE     16
+#define BNEXT(x)       (((x) + 1) & (INBUF_SIZE - 1))
+#define BEMPTY(b)      (b##_ridx == b##_widx)
+
 struct serial_port {
        int base, intr;
        int blocking;
+       int ref;
 
-       char inbuf[256];
+       char inbuf[INBUF_SIZE];
        int inbuf_ridx, inbuf_widx;
 };
 
-#define BNEXT(x)       (((x) + 1) & 0xff)
-#define BEMPTY(b)      (b##_ridx == b##_widx)
 
 static int have_recv(int base);
 static void recv_intr();
@@ -136,7 +140,7 @@ static int uart_irq[] = {UART1_IRQ, UART2_IRQ};
 int ser_open(int pidx, int baud, unsigned int mode)
 {
        unsigned short div = 115200 / baud;
-       int base, intr;
+       int i, fd, base, intr;
        unsigned int fmt;
 
        if(pidx < 0 || pidx > 1) {
@@ -144,11 +148,16 @@ int ser_open(int pidx, int baud, unsigned int mode)
                return -1;
        }
 
-       if(ports[pidx].base) {
-               printf("ser_open: port %d already open!\n", pidx);
-               return -1;
+       for(i=0; i<num_open; i++) {
+               if(ports[i].base == uart_base[pidx]) {
+                       /* the port is already open, return the same fd and increment ref */
+                       ports[i].ref++;
+                       return i;
+               }
        }
-       memset(ports + pidx, 0, sizeof ports[pidx]);
+
+       fd = num_open++;
+       memset(ports + fd, 0, sizeof ports[pidx]);
 
        base = uart_base[pidx];
        intr = uart_irq[pidx];
@@ -169,21 +178,22 @@ int ser_open(int pidx, int baud, unsigned int mode)
        outp(base + UART_MCTL, MCTL_DTR | MCTL_RTS | MCTL_OUT2);
        outp(base + UART_INTR, INTR_RECV);
 
-       ports[pidx].base = base;
-       ports[pidx].intr = intr;
-       ports[pidx].blocking = 1;
-       ++num_open;
-       return pidx;
+       ports[fd].base = base;
+       ports[fd].intr = intr;
+       ports[fd].blocking = 1;
+       ports[fd].ref = 1;
+       return fd;
 }
 
 void ser_close(int fd)
 {
-       if(--num_open == 0) {
+       if(!ports[fd].ref) return;
+
+       if(--ports[fd].ref == 0) {
                outp(ports[fd].base + UART_INTR, 0);
                outp(ports[fd].base + UART_MCTL, 0);
+               ports[fd].base = 0;
        }
-
-       ports[fd].base = 0;
 }
 
 int ser_block(int fd)
@@ -271,8 +281,8 @@ int ser_read(int fd, char *buf, int count)
 
 char *ser_getline(int fd, char *buf, int bsz)
 {
-       static char linebuf[512];
        static int widx;
+       char linebuf[512];
        int i, rd, size, offs;
 
        size = sizeof linebuf - widx;