2018-02-20 21:44:51 -05:00
|
|
|
/*
|
2018-03-08 15:58:46 -05:00
|
|
|
* VARCem Virtual ARchaeological Computer EMulator.
|
2018-02-20 21:44:51 -05:00
|
|
|
* An emulator of (mostly) x86-based PC systems and devices,
|
|
|
|
|
* using the ISA,EISA,VLB,MCA and PCI system buses, roughly
|
|
|
|
|
* spanning the era between 1981 and 1995.
|
|
|
|
|
*
|
|
|
|
|
* This file is part of the VARCem Project.
|
|
|
|
|
*
|
|
|
|
|
* Implementation of 8250-style serial port.
|
|
|
|
|
*
|
2018-05-06 22:47:14 -04:00
|
|
|
* Version: @(#)serial.c 1.0.7 2018/05/06
|
2018-02-20 21:44:51 -05:00
|
|
|
*
|
|
|
|
|
* Authors: Fred N. van Kempen, <decwiz@yahoo.com>
|
|
|
|
|
* Miran Grca, <mgrca8@gmail.com>
|
|
|
|
|
* Sarah Walker, <tommowalker@tommowalker.co.uk>
|
|
|
|
|
*
|
|
|
|
|
* Copyright 2017,2018 Fred N. van Kempen.
|
|
|
|
|
* Copyright 2016-2018 Miran Grca.
|
|
|
|
|
* Copyright 2008-2018 Sarah Walker.
|
|
|
|
|
*
|
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
|
* (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful, but
|
|
|
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
|
* General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
* along with this program; if not, write to the:
|
|
|
|
|
*
|
|
|
|
|
* Free Software Foundation, Inc.
|
|
|
|
|
* 59 Temple Place - Suite 330
|
|
|
|
|
* Boston, MA 02111-1307
|
|
|
|
|
* USA.
|
|
|
|
|
*/
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdint.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <stdlib.h>
|
2018-04-30 17:43:18 -04:00
|
|
|
#include <stdarg.h>
|
2018-02-20 21:44:51 -05:00
|
|
|
#include <wchar.h>
|
2018-04-30 17:43:18 -04:00
|
|
|
#define HAVE_STDARG_H
|
2018-05-06 22:47:14 -04:00
|
|
|
#include "../../emu.h"
|
|
|
|
|
#include "../../machines/machine.h"
|
|
|
|
|
#include "../../io.h"
|
|
|
|
|
#include "../../mem.h"
|
|
|
|
|
#include "../../rom.h"
|
|
|
|
|
#include "../../timer.h"
|
|
|
|
|
#include "../../device.h"
|
|
|
|
|
#include "../../devices/system/pic.h"
|
2018-04-20 04:16:43 -04:00
|
|
|
#include "serial.h"
|
2018-02-20 21:44:51 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
enum {
|
|
|
|
|
SERIAL_INT_LSR = 1,
|
|
|
|
|
SERIAL_INT_RECEIVE = 2,
|
|
|
|
|
SERIAL_INT_TRANSMIT = 4,
|
|
|
|
|
SERIAL_INT_MSR = 8
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2018-04-20 04:16:43 -04:00
|
|
|
#ifdef ENABLE_SERIAL_LOG
|
|
|
|
|
int serial_do_log = ENABLE_SERIAL_LOG;
|
|
|
|
|
#endif
|
2018-02-20 21:44:51 -05:00
|
|
|
|
|
|
|
|
|
2018-04-20 04:16:43 -04:00
|
|
|
static const struct {
|
|
|
|
|
uint16_t addr;
|
|
|
|
|
int8_t irq;
|
|
|
|
|
int8_t pad;
|
|
|
|
|
} addr_list[] = { /* valid port addresses */
|
|
|
|
|
{ SERIAL1_ADDR, 4 },
|
|
|
|
|
{ SERIAL2_ADDR, 3 }
|
|
|
|
|
};
|
|
|
|
|
static SERIAL ports[SERIAL_MAX]; /* the ports */
|
2018-02-20 21:44:51 -05:00
|
|
|
|
|
|
|
|
|
2018-04-30 17:43:18 -04:00
|
|
|
static void
|
|
|
|
|
serlog(const char *fmt, ...)
|
|
|
|
|
{
|
|
|
|
|
#ifdef ENABLE_SERIAL_LOG
|
|
|
|
|
va_list ap;
|
|
|
|
|
|
|
|
|
|
if (serial_do_log) {
|
|
|
|
|
va_start(ap, fmt);
|
|
|
|
|
pclog_ex(fmt, ap);
|
|
|
|
|
va_end(ap);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2018-04-20 04:16:43 -04:00
|
|
|
static void
|
|
|
|
|
update_ints(SERIAL *dev)
|
2018-02-20 21:44:51 -05:00
|
|
|
{
|
|
|
|
|
int stat = 0;
|
|
|
|
|
|
2018-04-20 04:16:43 -04:00
|
|
|
dev->iir = 1;
|
2018-02-20 21:44:51 -05:00
|
|
|
|
2018-04-20 04:16:43 -04:00
|
|
|
if ((dev->ier & 4) && (dev->int_status & SERIAL_INT_LSR)) {
|
|
|
|
|
/*Line status interrupt*/
|
2018-02-20 21:44:51 -05:00
|
|
|
stat = 1;
|
2018-04-20 04:16:43 -04:00
|
|
|
dev->iir = 6;
|
|
|
|
|
} else if ((dev->ier & 1) && (dev->int_status & SERIAL_INT_RECEIVE)) {
|
|
|
|
|
/*Recieved data available*/
|
2018-02-20 21:44:51 -05:00
|
|
|
stat = 1;
|
2018-04-20 04:16:43 -04:00
|
|
|
dev->iir = 4;
|
|
|
|
|
} else if ((dev->ier & 2) && (dev->int_status & SERIAL_INT_TRANSMIT)) {
|
|
|
|
|
/*Transmit data empty*/
|
2018-02-20 21:44:51 -05:00
|
|
|
stat = 1;
|
2018-04-20 04:16:43 -04:00
|
|
|
dev->iir = 2;
|
|
|
|
|
} else if ((dev->ier & 8) && (dev->int_status & SERIAL_INT_MSR)) {
|
|
|
|
|
/*Modem status interrupt*/
|
2018-02-20 21:44:51 -05:00
|
|
|
stat = 1;
|
2018-04-20 04:16:43 -04:00
|
|
|
dev->iir = 0;
|
2018-02-20 21:44:51 -05:00
|
|
|
}
|
|
|
|
|
|
2018-04-20 04:16:43 -04:00
|
|
|
if (stat && ((dev->mcr & 8) || PCJR))
|
|
|
|
|
picintlevel(1 << dev->irq);
|
2018-02-20 21:44:51 -05:00
|
|
|
else
|
2018-04-20 04:16:43 -04:00
|
|
|
picintc(1 << dev->irq);
|
2018-02-20 21:44:51 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2018-04-20 04:16:43 -04:00
|
|
|
static void
|
|
|
|
|
clear_fifo(SERIAL *dev)
|
2018-02-20 21:44:51 -05:00
|
|
|
{
|
2018-04-20 04:16:43 -04:00
|
|
|
memset(dev->fifo, 0x00, 256);
|
|
|
|
|
dev->fifo_read = dev->fifo_write = 0;
|
2018-02-20 21:44:51 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2018-04-20 04:16:43 -04:00
|
|
|
static void
|
2018-04-20 15:10:05 -04:00
|
|
|
write_fifo(SERIAL *dev, uint8_t *ptr, uint8_t len)
|
2018-02-20 21:44:51 -05:00
|
|
|
{
|
2018-04-20 15:10:05 -04:00
|
|
|
while (len-- > 0) {
|
|
|
|
|
dev->fifo[dev->fifo_write] = *ptr++;
|
|
|
|
|
dev->fifo_write = (dev->fifo_write + 1) & 0xff;
|
|
|
|
|
/*OVERFLOW NOT DETECTED*/
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-20 04:16:43 -04:00
|
|
|
if (! (dev->lsr & 1)) {
|
|
|
|
|
dev->lsr |= 1;
|
|
|
|
|
dev->int_status |= SERIAL_INT_RECEIVE;
|
|
|
|
|
update_ints(dev);
|
2018-02-20 21:44:51 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2018-04-20 04:16:43 -04:00
|
|
|
static uint8_t
|
|
|
|
|
read_fifo(SERIAL *dev)
|
2018-02-20 21:44:51 -05:00
|
|
|
{
|
2018-04-20 04:16:43 -04:00
|
|
|
if (dev->fifo_read != dev->fifo_write) {
|
|
|
|
|
dev->dat = dev->fifo[dev->fifo_read];
|
|
|
|
|
dev->fifo_read = (dev->fifo_read + 1) & 0xff;
|
2018-02-20 21:44:51 -05:00
|
|
|
}
|
|
|
|
|
|
2018-04-20 04:16:43 -04:00
|
|
|
return(dev->dat);
|
2018-02-20 21:44:51 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2018-04-20 04:16:43 -04:00
|
|
|
static void
|
|
|
|
|
receive_callback(void *priv)
|
|
|
|
|
{
|
|
|
|
|
SERIAL *dev = (SERIAL *)priv;
|
|
|
|
|
|
|
|
|
|
dev->delay = 0;
|
|
|
|
|
|
|
|
|
|
if (dev->fifo_read != dev->fifo_write) {
|
|
|
|
|
dev->lsr |= 1;
|
|
|
|
|
dev->int_status |= SERIAL_INT_RECEIVE;
|
|
|
|
|
update_ints(dev);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
reset_port(SERIAL *dev)
|
2018-02-20 21:44:51 -05:00
|
|
|
{
|
2018-04-20 04:16:43 -04:00
|
|
|
dev->iir = dev->ier = dev->lcr = 0;
|
|
|
|
|
dev->fifo_read = dev->fifo_write = 0;
|
|
|
|
|
|
|
|
|
|
dev->int_status = 0x00;
|
|
|
|
|
}
|
2018-02-20 21:44:51 -05:00
|
|
|
|
2018-04-20 04:16:43 -04:00
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
serial_write(uint16_t addr, uint8_t val, void *priv)
|
|
|
|
|
{
|
|
|
|
|
SERIAL *dev = (SERIAL *)priv;
|
|
|
|
|
|
|
|
|
|
switch (addr & 7) {
|
2018-02-20 21:44:51 -05:00
|
|
|
case 0:
|
2018-04-20 04:16:43 -04:00
|
|
|
if (dev->lcr & 0x80) {
|
|
|
|
|
dev->dlab1 = val;
|
2018-02-20 21:44:51 -05:00
|
|
|
return;
|
|
|
|
|
}
|
2018-04-20 04:16:43 -04:00
|
|
|
dev->thr = val;
|
|
|
|
|
dev->lsr |= 0x20;
|
|
|
|
|
dev->int_status |= SERIAL_INT_TRANSMIT;
|
|
|
|
|
update_ints(dev);
|
|
|
|
|
if (dev->mcr & 0x10)
|
2018-04-20 15:10:05 -04:00
|
|
|
write_fifo(dev, &val, 1);
|
2018-02-20 21:44:51 -05:00
|
|
|
break;
|
2018-04-20 04:16:43 -04:00
|
|
|
|
2018-02-20 21:44:51 -05:00
|
|
|
case 1:
|
2018-04-20 04:16:43 -04:00
|
|
|
if (dev->lcr & 0x80) {
|
|
|
|
|
dev->dlab2 = val;
|
2018-02-20 21:44:51 -05:00
|
|
|
return;
|
|
|
|
|
}
|
2018-04-20 04:16:43 -04:00
|
|
|
dev->ier = val & 0xf;
|
|
|
|
|
update_ints(dev);
|
2018-02-20 21:44:51 -05:00
|
|
|
break;
|
2018-04-20 04:16:43 -04:00
|
|
|
|
2018-02-20 21:44:51 -05:00
|
|
|
case 2:
|
2018-04-20 04:16:43 -04:00
|
|
|
dev->fcr = val;
|
2018-02-20 21:44:51 -05:00
|
|
|
break;
|
2018-04-20 04:16:43 -04:00
|
|
|
|
2018-02-20 21:44:51 -05:00
|
|
|
case 3:
|
2018-04-20 04:16:43 -04:00
|
|
|
dev->lcr = val;
|
2018-02-20 21:44:51 -05:00
|
|
|
break;
|
2018-04-20 04:16:43 -04:00
|
|
|
|
2018-02-20 21:44:51 -05:00
|
|
|
case 4:
|
2018-04-20 04:16:43 -04:00
|
|
|
if ((val & 2) && !(dev->mcr & 2)) {
|
|
|
|
|
if (dev->rts_callback)
|
|
|
|
|
dev->rts_callback(dev, dev->rts_callback_p);
|
2018-02-20 21:44:51 -05:00
|
|
|
}
|
2018-04-20 04:16:43 -04:00
|
|
|
dev->mcr = val;
|
2018-02-20 21:44:51 -05:00
|
|
|
if (val & 0x10) {
|
|
|
|
|
uint8_t new_msr;
|
2018-04-20 04:16:43 -04:00
|
|
|
|
2018-02-20 21:44:51 -05:00
|
|
|
new_msr = (val & 0x0c) << 4;
|
|
|
|
|
new_msr |= (val & 0x02) ? 0x10: 0;
|
|
|
|
|
new_msr |= (val & 0x01) ? 0x20: 0;
|
2018-04-20 04:16:43 -04:00
|
|
|
|
|
|
|
|
if ((dev->msr ^ new_msr) & 0x10)
|
2018-02-20 21:44:51 -05:00
|
|
|
new_msr |= 0x01;
|
2018-04-20 04:16:43 -04:00
|
|
|
if ((dev->msr ^ new_msr) & 0x20)
|
2018-02-20 21:44:51 -05:00
|
|
|
new_msr |= 0x02;
|
2018-04-20 04:16:43 -04:00
|
|
|
if ((dev->msr ^ new_msr) & 0x80)
|
2018-02-20 21:44:51 -05:00
|
|
|
new_msr |= 0x08;
|
2018-04-20 04:16:43 -04:00
|
|
|
if ((dev->msr & 0x40) && !(new_msr & 0x40))
|
2018-02-20 21:44:51 -05:00
|
|
|
new_msr |= 0x04;
|
|
|
|
|
|
2018-04-20 04:16:43 -04:00
|
|
|
dev->msr = new_msr;
|
2018-02-20 21:44:51 -05:00
|
|
|
}
|
|
|
|
|
break;
|
2018-04-20 04:16:43 -04:00
|
|
|
|
2018-02-20 21:44:51 -05:00
|
|
|
case 5:
|
2018-04-20 04:16:43 -04:00
|
|
|
dev->lsr = val;
|
|
|
|
|
if (dev->lsr & 0x01)
|
|
|
|
|
dev->int_status |= SERIAL_INT_RECEIVE;
|
|
|
|
|
if (dev->lsr & 0x1e)
|
|
|
|
|
dev->int_status |= SERIAL_INT_LSR;
|
|
|
|
|
if (dev->lsr & 0x20)
|
|
|
|
|
dev->int_status |= SERIAL_INT_TRANSMIT;
|
|
|
|
|
update_ints(dev);
|
2018-02-20 21:44:51 -05:00
|
|
|
break;
|
2018-04-20 04:16:43 -04:00
|
|
|
|
2018-02-20 21:44:51 -05:00
|
|
|
case 6:
|
2018-04-20 04:16:43 -04:00
|
|
|
dev->msr = val;
|
|
|
|
|
if (dev->msr & 0x0f)
|
|
|
|
|
dev->int_status |= SERIAL_INT_MSR;
|
|
|
|
|
update_ints(dev);
|
2018-02-20 21:44:51 -05:00
|
|
|
break;
|
2018-04-20 04:16:43 -04:00
|
|
|
|
2018-02-20 21:44:51 -05:00
|
|
|
case 7:
|
2018-04-20 04:16:43 -04:00
|
|
|
dev->scratch = val;
|
2018-02-20 21:44:51 -05:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2018-04-20 04:16:43 -04:00
|
|
|
static uint8_t
|
|
|
|
|
serial_read(uint16_t addr, void *priv)
|
2018-02-20 21:44:51 -05:00
|
|
|
{
|
2018-04-20 04:16:43 -04:00
|
|
|
SERIAL *dev = (SERIAL *)priv;
|
|
|
|
|
uint8_t ret = 0x00;
|
2018-02-20 21:44:51 -05:00
|
|
|
|
2018-04-20 04:16:43 -04:00
|
|
|
switch (addr & 7) {
|
2018-02-20 21:44:51 -05:00
|
|
|
case 0:
|
2018-04-20 04:16:43 -04:00
|
|
|
if (dev->lcr & 0x80) {
|
|
|
|
|
ret = dev->dlab1;
|
2018-02-20 21:44:51 -05:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-20 04:16:43 -04:00
|
|
|
dev->lsr &= ~1;
|
|
|
|
|
dev->int_status &= ~SERIAL_INT_RECEIVE;
|
|
|
|
|
update_ints(dev);
|
|
|
|
|
ret = read_fifo(dev);
|
|
|
|
|
if (dev->fifo_read != dev->fifo_write) {
|
|
|
|
|
dev->delay = 1000LL * TIMER_USEC;
|
2018-02-20 21:44:51 -05:00
|
|
|
}
|
|
|
|
|
break;
|
2018-04-20 04:16:43 -04:00
|
|
|
|
2018-02-20 21:44:51 -05:00
|
|
|
case 1:
|
2018-04-20 04:16:43 -04:00
|
|
|
if (dev->lcr & 0x80)
|
|
|
|
|
ret = dev->dlab2;
|
2018-02-20 21:44:51 -05:00
|
|
|
else
|
2018-04-20 04:16:43 -04:00
|
|
|
ret = dev->ier;
|
2018-02-20 21:44:51 -05:00
|
|
|
break;
|
2018-04-20 04:16:43 -04:00
|
|
|
|
2018-02-20 21:44:51 -05:00
|
|
|
case 2:
|
2018-04-20 04:16:43 -04:00
|
|
|
ret = dev->iir;
|
|
|
|
|
if ((ret & 0xe) == 2) {
|
|
|
|
|
dev->int_status &= ~SERIAL_INT_TRANSMIT;
|
|
|
|
|
update_ints(dev);
|
2018-02-20 21:44:51 -05:00
|
|
|
}
|
2018-04-20 04:16:43 -04:00
|
|
|
if (dev->fcr & 1)
|
|
|
|
|
ret |= 0xc0;
|
2018-02-20 21:44:51 -05:00
|
|
|
break;
|
2018-04-20 04:16:43 -04:00
|
|
|
|
2018-02-20 21:44:51 -05:00
|
|
|
case 3:
|
2018-04-20 04:16:43 -04:00
|
|
|
ret = dev->lcr;
|
2018-02-20 21:44:51 -05:00
|
|
|
break;
|
2018-04-20 04:16:43 -04:00
|
|
|
|
2018-02-20 21:44:51 -05:00
|
|
|
case 4:
|
2018-04-20 04:16:43 -04:00
|
|
|
ret = dev->mcr;
|
2018-02-20 21:44:51 -05:00
|
|
|
break;
|
2018-04-20 04:16:43 -04:00
|
|
|
|
2018-02-20 21:44:51 -05:00
|
|
|
case 5:
|
2018-04-20 04:16:43 -04:00
|
|
|
if (dev->lsr & 0x20)
|
|
|
|
|
dev->lsr |= 0x40;
|
|
|
|
|
dev->lsr |= 0x20;
|
|
|
|
|
ret = dev->lsr;
|
|
|
|
|
if (dev->lsr & 0x1f)
|
|
|
|
|
dev->lsr &= ~0x1e;
|
|
|
|
|
dev->int_status &= ~SERIAL_INT_LSR;
|
|
|
|
|
update_ints(dev);
|
2018-02-20 21:44:51 -05:00
|
|
|
break;
|
2018-04-20 04:16:43 -04:00
|
|
|
|
2018-02-20 21:44:51 -05:00
|
|
|
case 6:
|
2018-04-20 04:16:43 -04:00
|
|
|
ret = dev->msr;
|
|
|
|
|
dev->msr &= ~0x0f;
|
|
|
|
|
dev->int_status &= ~SERIAL_INT_MSR;
|
|
|
|
|
update_ints(dev);
|
2018-02-20 21:44:51 -05:00
|
|
|
break;
|
2018-04-20 04:16:43 -04:00
|
|
|
|
2018-02-20 21:44:51 -05:00
|
|
|
case 7:
|
2018-04-20 04:16:43 -04:00
|
|
|
ret = dev->scratch;
|
2018-02-20 21:44:51 -05:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-20 04:16:43 -04:00
|
|
|
return(ret);
|
2018-02-20 21:44:51 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2018-04-20 04:16:43 -04:00
|
|
|
static void *
|
|
|
|
|
serial_init(const device_t *info)
|
2018-02-20 21:44:51 -05:00
|
|
|
{
|
2018-04-20 04:16:43 -04:00
|
|
|
SERIAL *dev;
|
2018-02-20 21:44:51 -05:00
|
|
|
|
2018-04-20 04:16:43 -04:00
|
|
|
/* Get the correct device. */
|
|
|
|
|
dev = &ports[info->local - 1];
|
2018-02-20 21:44:51 -05:00
|
|
|
|
2018-04-20 04:16:43 -04:00
|
|
|
/* Set up callback functions. */
|
|
|
|
|
dev->clear_fifo = clear_fifo;
|
|
|
|
|
dev->write_fifo = write_fifo;
|
2018-02-20 21:44:51 -05:00
|
|
|
|
2018-04-20 04:16:43 -04:00
|
|
|
/* Clear port. */
|
|
|
|
|
reset_port(dev);
|
2018-02-20 21:44:51 -05:00
|
|
|
|
2018-04-20 04:16:43 -04:00
|
|
|
/* Enable the I/O handler for this port. */
|
|
|
|
|
io_sethandler(dev->base, 8,
|
|
|
|
|
serial_read,NULL,NULL, serial_write,NULL,NULL, dev);
|
|
|
|
|
|
|
|
|
|
timer_add(receive_callback, &dev->delay, &dev->delay, dev);
|
2018-02-20 21:44:51 -05:00
|
|
|
|
2018-04-20 04:16:43 -04:00
|
|
|
pclog("SERIAL: COM%d (I/O=%04X, IRQ=%d)\n",
|
|
|
|
|
info->local, dev->base, dev->irq);
|
2018-02-20 21:44:51 -05:00
|
|
|
|
2018-04-20 04:16:43 -04:00
|
|
|
return(dev);
|
|
|
|
|
}
|
2018-02-20 21:44:51 -05:00
|
|
|
|
|
|
|
|
|
2018-04-20 04:16:43 -04:00
|
|
|
static void
|
|
|
|
|
serial_close(void *priv)
|
|
|
|
|
{
|
|
|
|
|
SERIAL *dev = (SERIAL *)priv;
|
|
|
|
|
|
|
|
|
|
/* Remove the I/O handler. */
|
|
|
|
|
io_removehandler(dev->base, 8,
|
|
|
|
|
serial_read,NULL,NULL, serial_write,NULL,NULL, dev);
|
|
|
|
|
|
|
|
|
|
/* Clear port. */
|
|
|
|
|
reset_port(dev);
|
2018-02-20 21:44:51 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2018-04-20 04:16:43 -04:00
|
|
|
const device_t serial_1_device = {
|
|
|
|
|
"COM1:",
|
|
|
|
|
0,
|
|
|
|
|
1,
|
|
|
|
|
serial_init, serial_close, NULL,
|
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
|
NULL
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const device_t serial_2_device = {
|
|
|
|
|
"COM2:",
|
|
|
|
|
0,
|
|
|
|
|
2,
|
|
|
|
|
serial_init, serial_close, NULL,
|
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* (Re-)initialize all serial ports. */
|
2018-02-20 21:44:51 -05:00
|
|
|
void
|
2018-04-20 04:16:43 -04:00
|
|
|
serial_reset(void)
|
2018-02-20 21:44:51 -05:00
|
|
|
{
|
2018-04-20 04:16:43 -04:00
|
|
|
SERIAL *dev;
|
|
|
|
|
int i;
|
2018-02-20 21:44:51 -05:00
|
|
|
|
2018-04-23 15:32:35 -04:00
|
|
|
#ifdef ENABLE_SERIAL_LOG
|
2018-04-30 17:43:18 -04:00
|
|
|
serlog("SERIAL: reset ([%d] [%d])\n", serial_enabled[0], serial_enabled[1]);
|
2018-04-23 15:32:35 -04:00
|
|
|
#endif
|
2018-02-20 21:44:51 -05:00
|
|
|
|
2018-04-20 04:16:43 -04:00
|
|
|
for (i = 0; i < SERIAL_MAX; i++) {
|
|
|
|
|
dev = &ports[i];
|
2018-02-20 21:44:51 -05:00
|
|
|
|
2018-04-20 04:16:43 -04:00
|
|
|
memset(dev, 0x00, sizeof(SERIAL));
|
2018-02-20 21:44:51 -05:00
|
|
|
|
2018-04-20 04:16:43 -04:00
|
|
|
dev->base = addr_list[i].addr;
|
|
|
|
|
dev->irq = addr_list[i].irq;
|
2018-02-20 21:44:51 -05:00
|
|
|
|
2018-04-20 04:16:43 -04:00
|
|
|
/* Clear port. */
|
|
|
|
|
reset_port(dev);
|
2018-02-20 21:44:51 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2018-04-20 04:16:43 -04:00
|
|
|
/* Set up (the address/IRQ of) one of the serial ports. */
|
2018-02-20 21:44:51 -05:00
|
|
|
void
|
2018-04-20 04:16:43 -04:00
|
|
|
serial_setup(int id, uint16_t port, int8_t irq)
|
2018-02-20 21:44:51 -05:00
|
|
|
{
|
2018-04-20 04:16:43 -04:00
|
|
|
SERIAL *dev = &ports[id-1];
|
2018-02-20 21:44:51 -05:00
|
|
|
|
2018-04-23 15:32:35 -04:00
|
|
|
#if defined(ENABLE_SERIAL_LOG) && defined(_DEBUG)
|
2018-04-30 17:43:18 -04:00
|
|
|
serlog("SERIAL: setting up COM%d as %04X [enabled=%d]\n",
|
2018-04-20 04:16:43 -04:00
|
|
|
id, port, serial_enabled[id-1]);
|
|
|
|
|
#endif
|
|
|
|
|
if (! serial_enabled[id-1]) return;
|
|
|
|
|
|
|
|
|
|
dev->base = port;
|
|
|
|
|
dev->irq = irq;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Attach another device (MOUSE) to a serial port. */
|
|
|
|
|
SERIAL *
|
|
|
|
|
serial_attach(int port, void *func, void *arg)
|
|
|
|
|
{
|
|
|
|
|
SERIAL *dev;
|
|
|
|
|
|
|
|
|
|
/* No can do if port not enabled. */
|
|
|
|
|
if (! serial_enabled[port-1]) return(NULL);
|
|
|
|
|
|
|
|
|
|
/* Grab the desired port block. */
|
|
|
|
|
dev = &ports[port-1];
|
|
|
|
|
|
|
|
|
|
/* Set up callback info. */
|
|
|
|
|
dev->rts_callback = func;
|
|
|
|
|
dev->rts_callback_p = arg;
|
|
|
|
|
|
|
|
|
|
return(dev);
|
2018-02-20 21:44:51 -05:00
|
|
|
}
|