@@ -41,7 +41,7 @@ add_library(dev OBJECT
|
|||||||
keyboard.c
|
keyboard.c
|
||||||
keyboard_at.c
|
keyboard_at.c
|
||||||
keyboard_xt.c
|
keyboard_xt.c
|
||||||
../lpt.c
|
lpt.c
|
||||||
mouse.c
|
mouse.c
|
||||||
mouse_bus.c
|
mouse_bus.c
|
||||||
mouse_microtouch_touchscreen.c
|
mouse_microtouch_touchscreen.c
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#define HAVE_STDARG_H
|
#define HAVE_STDARG_H
|
||||||
#include <86box/86box.h>
|
#include <86box/86box.h>
|
||||||
|
#include <86box/timer.h>
|
||||||
#include <86box/lpt.h>
|
#include <86box/lpt.h>
|
||||||
#include <86box/device.h>
|
#include <86box/device.h>
|
||||||
|
|
||||||
@@ -340,7 +341,10 @@ const lpt_device_t lpt_hasp_savquest_device = {
|
|||||||
.close = hasp_close,
|
.close = hasp_close,
|
||||||
.write_data = hasp_write_data,
|
.write_data = hasp_write_data,
|
||||||
.write_ctrl = NULL,
|
.write_ctrl = NULL,
|
||||||
.read_data = NULL,
|
.autofeed = NULL,
|
||||||
|
.strobe = NULL,
|
||||||
.read_status = hasp_read_status,
|
.read_status = hasp_read_status,
|
||||||
.read_ctrl = NULL
|
.read_ctrl = NULL,
|
||||||
|
.epp_write_data = NULL,
|
||||||
|
.epp_request_read = NULL
|
||||||
};
|
};
|
||||||
|
|||||||
837
src/device/lpt.c
Normal file
837
src/device/lpt.c
Normal file
@@ -0,0 +1,837 @@
|
|||||||
|
/* Copyright holders: Sarah Walker
|
||||||
|
see COPYING for more details
|
||||||
|
*/
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <wchar.h>
|
||||||
|
#define HAVE_STDARG_H
|
||||||
|
#include <86box/86box.h>
|
||||||
|
#include <86box/io.h>
|
||||||
|
#include <86box/fifo.h>
|
||||||
|
#include <86box/timer.h>
|
||||||
|
#include <86box/dma.h>
|
||||||
|
#include <86box/lpt.h>
|
||||||
|
#include <86box/pic.h>
|
||||||
|
#include <86box/sound.h>
|
||||||
|
#include <86box/prt_devs.h>
|
||||||
|
#include <86box/thread.h>
|
||||||
|
#include <86box/device.h>
|
||||||
|
#include <86box/machine.h>
|
||||||
|
#include <86box/network.h>
|
||||||
|
|
||||||
|
lpt_port_t lpt_ports[PARALLEL_MAX];
|
||||||
|
|
||||||
|
const lpt_device_t lpt_none_device = {
|
||||||
|
.name = "None",
|
||||||
|
.internal_name = "none",
|
||||||
|
.init = NULL,
|
||||||
|
.close = NULL,
|
||||||
|
.write_data = NULL,
|
||||||
|
.write_ctrl = NULL,
|
||||||
|
.read_status = NULL,
|
||||||
|
.read_ctrl = NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct {
|
||||||
|
const char *internal_name;
|
||||||
|
const lpt_device_t *device;
|
||||||
|
} lpt_devices[] = {
|
||||||
|
// clang-format off
|
||||||
|
{"none", &lpt_none_device },
|
||||||
|
{"dss", &dss_device },
|
||||||
|
{"lpt_dac", &lpt_dac_device },
|
||||||
|
{"lpt_dac_stereo", &lpt_dac_stereo_device },
|
||||||
|
{"text_prt", &lpt_prt_text_device },
|
||||||
|
{"dot_matrix", &lpt_prt_escp_device },
|
||||||
|
{"postscript", &lpt_prt_ps_device },
|
||||||
|
{"pcl", &lpt_prt_pcl_device },
|
||||||
|
{"plip", &lpt_plip_device },
|
||||||
|
{"dongle_savquest", &lpt_hasp_savquest_device },
|
||||||
|
{"", NULL }
|
||||||
|
// clang-format on
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef ENABLE_LPT_LOG
|
||||||
|
int lpt_do_log = ENABLE_LPT_LOG;
|
||||||
|
|
||||||
|
static void
|
||||||
|
lpt_log(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
if (lpt_do_log) {
|
||||||
|
va_start(ap, fmt);
|
||||||
|
pclog_ex(fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
# define lpt_log(fmt, ...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const char *
|
||||||
|
lpt_device_get_name(const int id)
|
||||||
|
{
|
||||||
|
if (strlen(lpt_devices[id].internal_name) == 0)
|
||||||
|
return NULL;
|
||||||
|
if (lpt_devices[id].device == NULL)
|
||||||
|
return "None";
|
||||||
|
return lpt_devices[id].device->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
lpt_device_get_internal_name(const int id)
|
||||||
|
{
|
||||||
|
if (strlen(lpt_devices[id].internal_name) == 0)
|
||||||
|
return NULL;
|
||||||
|
return lpt_devices[id].internal_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
lpt_device_get_from_internal_name(const char *s)
|
||||||
|
{
|
||||||
|
int c = 0;
|
||||||
|
|
||||||
|
while (strlen(lpt_devices[c].internal_name) != 0) {
|
||||||
|
if (strcmp(lpt_devices[c].internal_name, s) == 0)
|
||||||
|
return c;
|
||||||
|
c++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
lpt_devices_init(void)
|
||||||
|
{
|
||||||
|
for (uint8_t i = 0; i < PARALLEL_MAX; i++) {
|
||||||
|
lpt_ports[i].dt = (lpt_device_t *) lpt_devices[lpt_ports[i].device].device;
|
||||||
|
|
||||||
|
if (lpt_ports[i].dt && lpt_ports[i].dt->init)
|
||||||
|
lpt_ports[i].priv = lpt_ports[i].dt->init(&lpt_ports[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
lpt_devices_close(void)
|
||||||
|
{
|
||||||
|
for (uint8_t i = 0; i < PARALLEL_MAX; i++) {
|
||||||
|
lpt_port_t *dev = &lpt_ports[i];
|
||||||
|
|
||||||
|
if (lpt_ports[i].dt && lpt_ports[i].dt->close)
|
||||||
|
dev->dt->close(dev->priv);
|
||||||
|
|
||||||
|
dev->dt = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t
|
||||||
|
lpt_get_ctrl_raw(const lpt_port_t *dev)
|
||||||
|
{
|
||||||
|
uint8_t ret;
|
||||||
|
|
||||||
|
if (dev->dt && dev->dt->read_ctrl && dev->priv)
|
||||||
|
ret = (dev->dt->read_ctrl(dev->priv) & 0xef) | dev->enable_irq;
|
||||||
|
else
|
||||||
|
ret = 0xc0 | dev->ctrl | dev->enable_irq;
|
||||||
|
|
||||||
|
return ret & 0xdf;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t
|
||||||
|
lpt_is_epp(const lpt_port_t *dev)
|
||||||
|
{
|
||||||
|
return (dev->epp || ((dev->ecp) && ((dev->ecr & 0xe0) == 0x80)));
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t
|
||||||
|
lpt_get_ctrl(const lpt_port_t *dev)
|
||||||
|
{
|
||||||
|
uint8_t ret = lpt_get_ctrl_raw(dev);
|
||||||
|
|
||||||
|
if (!dev->ecp && !dev->epp)
|
||||||
|
ret |= 0x20;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
lpt_write_fifo(lpt_port_t *dev, const uint8_t val, const uint8_t tag)
|
||||||
|
{
|
||||||
|
if (!fifo_get_full(dev->fifo)) {
|
||||||
|
fifo_write_evt_tagged(tag, val, dev->fifo);
|
||||||
|
|
||||||
|
if (!timer_is_enabled(&dev->fifo_out_timer))
|
||||||
|
timer_set_delay_u64(&dev->fifo_out_timer, (uint64_t) ((1000000.0 / 2500000.0) * (double) TIMER_USEC));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
lpt_ecp_update_irq(lpt_port_t *dev)
|
||||||
|
{
|
||||||
|
if (!(dev->ecr & 0x04) && ((dev->fifo_stat | dev->dma_stat) & 0x04))
|
||||||
|
picintlevel(1 << dev->irq, &dev->irq_state);
|
||||||
|
else
|
||||||
|
picintclevel(1 << dev->irq, &dev->irq_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
lpt_autofeed(lpt_port_t *dev, const uint8_t val)
|
||||||
|
{
|
||||||
|
if (dev->dt && dev->dt->autofeed && dev->priv)
|
||||||
|
dev->dt->autofeed(val, dev->priv);
|
||||||
|
|
||||||
|
dev->autofeed = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
lpt_strobe(lpt_port_t *dev, const uint8_t val)
|
||||||
|
{
|
||||||
|
if (dev->dt && dev->dt->strobe && dev->priv)
|
||||||
|
dev->dt->strobe(dev->strobe, val, dev->priv);
|
||||||
|
|
||||||
|
dev->strobe = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
lpt_fifo_out_callback(void *priv)
|
||||||
|
{
|
||||||
|
lpt_port_t *dev = (lpt_port_t *) priv;
|
||||||
|
|
||||||
|
switch (dev->state) {
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LPT_STATE_READ_DMA:
|
||||||
|
;
|
||||||
|
int ret = 0xff;
|
||||||
|
|
||||||
|
if (dev->dma == 0xff)
|
||||||
|
ret = DMA_NODATA;
|
||||||
|
else
|
||||||
|
ret = dma_channel_read(dev->dma);
|
||||||
|
|
||||||
|
lpt_log("DMA %02X: %08X\n", dev->dma, ret);
|
||||||
|
|
||||||
|
if (ret != DMA_NODATA) {
|
||||||
|
fifo_write_evt_tagged(0x01, (uint8_t) (ret & 0xff), dev->fifo);
|
||||||
|
|
||||||
|
if (ret & DMA_OVER)
|
||||||
|
/* Internal flag to indicate we have finished the DMA reads. */
|
||||||
|
dev->dma_stat = 0x08;
|
||||||
|
}
|
||||||
|
|
||||||
|
timer_advance_u64(&dev->fifo_out_timer,
|
||||||
|
(uint64_t) ((1000000.0 / 2500000.0) * (double) TIMER_USEC));
|
||||||
|
|
||||||
|
if (dev->dma_stat || fifo_get_full(dev->fifo))
|
||||||
|
dev->state = LPT_STATE_WRITE_FIFO;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LPT_STATE_WRITE_FIFO:
|
||||||
|
if (!fifo_get_empty(dev->fifo)) {
|
||||||
|
uint8_t tag = 0x00;
|
||||||
|
const uint8_t val = fifo_read_evt_tagged(&tag, dev->fifo);
|
||||||
|
|
||||||
|
lpt_log("FIFO: %02X, TAG = %02X\n", val, tag);
|
||||||
|
|
||||||
|
/* We do not currently support sending commands. */
|
||||||
|
if (tag == 0x01) {
|
||||||
|
if (dev->dt && dev->dt->write_data && dev->priv)
|
||||||
|
dev->dt->write_data(val, dev->priv);
|
||||||
|
|
||||||
|
lpt_strobe(dev, 1);
|
||||||
|
lpt_strobe(dev, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dev->ecr & 0x08) {
|
||||||
|
if (fifo_get_empty(dev->fifo)) {
|
||||||
|
if (dev->dma_stat) {
|
||||||
|
/* Now actually set the external flag. */
|
||||||
|
dev->dma_stat = 0x04;
|
||||||
|
dev->state = LPT_STATE_IDLE;
|
||||||
|
lpt_ecp_update_irq(dev);
|
||||||
|
lpt_autofeed(dev, 0);
|
||||||
|
} else {
|
||||||
|
dev->state = LPT_STATE_READ_DMA;
|
||||||
|
|
||||||
|
timer_advance_u64(&dev->fifo_out_timer,
|
||||||
|
(uint64_t) ((1000000.0 / 2500000.0) * (double) TIMER_USEC));
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
timer_advance_u64(&dev->fifo_out_timer,
|
||||||
|
(uint64_t) ((1000000.0 / 2500000.0) * (double) TIMER_USEC));
|
||||||
|
} else if (!fifo_get_empty(dev->fifo))
|
||||||
|
timer_advance_u64(&dev->fifo_out_timer,
|
||||||
|
(uint64_t) ((1000000.0 / 2500000.0) * (double) TIMER_USEC));
|
||||||
|
else
|
||||||
|
lpt_autofeed(dev, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
lpt_write(const uint16_t port, const uint8_t val, void *priv)
|
||||||
|
{
|
||||||
|
lpt_port_t *dev = (lpt_port_t *) priv;
|
||||||
|
uint16_t mask = 0x0407;
|
||||||
|
|
||||||
|
lpt_log("[W] %04X = %02X\n", port, val);
|
||||||
|
|
||||||
|
/* This is needed so the parallel port at 3BC works. */
|
||||||
|
if (dev->addr & 0x0004)
|
||||||
|
mask = 0x0403;
|
||||||
|
|
||||||
|
switch (port & mask) {
|
||||||
|
case 0x0000:
|
||||||
|
if (dev->ecp) {
|
||||||
|
if ((dev->ecr & 0xe0) == 0x60)
|
||||||
|
/* AFIFO */
|
||||||
|
lpt_write_fifo(dev, val, 0x00);
|
||||||
|
else if (!(dev->ecr & 0xc0) && (!(dev->ecr & 0x20) || !(lpt_get_ctrl_raw(dev) & 0x20)) &&
|
||||||
|
dev->dt && dev->dt->write_data && dev->priv)
|
||||||
|
/* DATAR */
|
||||||
|
dev->dt->write_data(val, dev->priv);
|
||||||
|
dev->dat = val;
|
||||||
|
} else {
|
||||||
|
/* DTR */
|
||||||
|
if ((!dev->ext || !(lpt_get_ctrl_raw(dev) & 0x20)) && dev->dt &&
|
||||||
|
dev->dt->write_data && dev->priv)
|
||||||
|
dev->dt->write_data(val, dev->priv);
|
||||||
|
dev->dat = val;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x0001:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x0002:
|
||||||
|
if (dev->dt && dev->dt->write_ctrl && dev->priv) {
|
||||||
|
if (dev->ecp)
|
||||||
|
dev->dt->write_ctrl((val & 0xfc) | dev->autofeed | dev->strobe, dev->priv);
|
||||||
|
else
|
||||||
|
dev->dt->write_ctrl(val, dev->priv);
|
||||||
|
}
|
||||||
|
dev->ctrl = val;
|
||||||
|
dev->enable_irq = val & 0x10;
|
||||||
|
if (!(val & 0x10) && (dev->irq != 0xff))
|
||||||
|
picintc(1 << dev->irq);
|
||||||
|
dev->irq_state = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x0003:
|
||||||
|
if (lpt_is_epp(dev)) {
|
||||||
|
if (dev->dt && dev->dt->epp_write_data && dev->priv)
|
||||||
|
dev->dt->epp_write_data(1, val, dev->priv);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x0004 ... 0x0007:
|
||||||
|
if (lpt_is_epp(dev)) {
|
||||||
|
if (dev->dt && dev->dt->epp_write_data && dev->priv)
|
||||||
|
dev->dt->epp_write_data(0, val, dev->priv);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x0400: case 0x0404:
|
||||||
|
switch (dev->ecr >> 5) {
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
lpt_write_fifo(dev, val, 0x01);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
if (!(lpt_get_ctrl_raw(dev) & 0x20))
|
||||||
|
lpt_write_fifo(dev, val, 0x01);
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
/* TFIFO */
|
||||||
|
if (!fifo_get_full(dev->fifo))
|
||||||
|
fifo_write_evt(val, dev->fifo);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x0402: case 0x0406:
|
||||||
|
if (!(val & 0x0c))
|
||||||
|
lpt_autofeed(dev, 0x00);
|
||||||
|
else
|
||||||
|
lpt_autofeed(dev, 0x02);
|
||||||
|
|
||||||
|
if ((dev->ecr & 0x04) && !(val & 0x04)) {
|
||||||
|
dev->dma_stat = 0x00;
|
||||||
|
fifo_reset(dev->fifo);
|
||||||
|
if (val & 0x08) {
|
||||||
|
dev->state = LPT_STATE_READ_DMA;
|
||||||
|
dev->fifo_stat = 0x00;
|
||||||
|
if (!timer_is_enabled(&dev->fifo_out_timer))
|
||||||
|
timer_set_delay_u64(&dev->fifo_out_timer, (uint64_t) ((1000000.0 / 2500000.0) * (double) TIMER_USEC));
|
||||||
|
} else {
|
||||||
|
dev->state = LPT_STATE_WRITE_FIFO;
|
||||||
|
if (lpt_get_ctrl_raw(dev) & 0x20)
|
||||||
|
dev->fifo_stat = fifo_get_ready(dev->fifo) ? 0x04 : 0x00;
|
||||||
|
else
|
||||||
|
dev->fifo_stat = fifo_get_ready(dev->fifo) ? 0x00 : 0x04;
|
||||||
|
}
|
||||||
|
} else if ((val & 0x04) && !(dev->ecr & 0x04)) {
|
||||||
|
if (timer_is_enabled(&dev->fifo_out_timer))
|
||||||
|
timer_disable(&dev->fifo_out_timer);
|
||||||
|
|
||||||
|
dev->state = LPT_STATE_IDLE;
|
||||||
|
}
|
||||||
|
dev->ecr = val;
|
||||||
|
lpt_ecp_update_irq(dev);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
lpt_fifo_d_ready_evt(void *priv)
|
||||||
|
{
|
||||||
|
lpt_port_t *dev = (lpt_port_t *) priv;
|
||||||
|
|
||||||
|
if (!(dev->ecr & 0x08)) {
|
||||||
|
if (lpt_get_ctrl_raw(dev) & 0x20)
|
||||||
|
dev->fifo_stat = fifo_get_ready(dev->fifo) ? 0x04 : 0x00;
|
||||||
|
else
|
||||||
|
dev->fifo_stat = fifo_get_ready(dev->fifo) ? 0x00 : 0x04;
|
||||||
|
}
|
||||||
|
|
||||||
|
lpt_ecp_update_irq(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
lpt_write_to_fifo(void *priv, const uint8_t val)
|
||||||
|
{
|
||||||
|
lpt_port_t *dev = (lpt_port_t *) priv;
|
||||||
|
|
||||||
|
if (dev->ecp) {
|
||||||
|
if (((dev->ecr & 0xe0) == 0x20) && (lpt_get_ctrl_raw(dev) & 0x20))
|
||||||
|
dev->dat = val;
|
||||||
|
else if (((dev->ecr & 0xe0) == 0x60) && (lpt_get_ctrl_raw(dev) & 0x20) &&
|
||||||
|
!fifo_get_full(dev->fifo))
|
||||||
|
fifo_write_evt_tagged(0x01, val, dev->fifo);
|
||||||
|
|
||||||
|
if (((dev->ecr & 0x0c) == 0x08) && (dev->dma != 0xff)) {
|
||||||
|
const int ret = dma_channel_write(dev->dma, val);
|
||||||
|
|
||||||
|
if (ret & DMA_OVER)
|
||||||
|
dev->dma_stat |= 0x04;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (dev->ext && (lpt_get_ctrl_raw(dev) & 0x20))
|
||||||
|
dev->dat = val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
lpt_write_to_dat(void *priv, const uint8_t val)
|
||||||
|
{
|
||||||
|
lpt_port_t *dev = (lpt_port_t *) priv;
|
||||||
|
|
||||||
|
dev->dat = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t
|
||||||
|
lpt_read_fifo(const lpt_port_t *dev)
|
||||||
|
{
|
||||||
|
uint8_t ret = 0xff;
|
||||||
|
|
||||||
|
if (!fifo_get_empty(dev->fifo))
|
||||||
|
ret = fifo_read(dev->fifo);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t
|
||||||
|
lpt_read_status(const int port)
|
||||||
|
{
|
||||||
|
lpt_port_t *dev = &lpt_ports[port];
|
||||||
|
uint8_t low_bits = 0x07;
|
||||||
|
uint8_t ret;
|
||||||
|
|
||||||
|
if (dev->ext) {
|
||||||
|
low_bits = 0x03 | (dev->irq_state ? 0x00 : 0x04);
|
||||||
|
if (dev->irq != 0xff)
|
||||||
|
picintclevel(1 << dev->irq, &dev->irq_state);
|
||||||
|
dev->irq_state = 0;
|
||||||
|
}
|
||||||
|
if (dev->epp || dev->ecp) {
|
||||||
|
low_bits = lpt_is_epp(dev) ? 0x02 : 0x03;
|
||||||
|
if (lpt_get_ctrl_raw(dev) & 0x10)
|
||||||
|
low_bits |= (dev->irq_state ? 0x00 : 0x04);
|
||||||
|
else
|
||||||
|
low_bits |= 0x04;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dev->dt && dev->dt->read_status && dev->priv)
|
||||||
|
ret = (dev->dt->read_status(dev->priv) & 0xf8) | low_bits;
|
||||||
|
else
|
||||||
|
ret = 0xd8 | low_bits;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t
|
||||||
|
lpt_read(const uint16_t port, void *priv)
|
||||||
|
{
|
||||||
|
const lpt_port_t *dev = (lpt_port_t *) priv;
|
||||||
|
uint16_t mask = 0x0407;
|
||||||
|
uint8_t ret = 0xff;
|
||||||
|
|
||||||
|
/* This is needed so the parallel port at 3BC works. */
|
||||||
|
if (dev->addr & 0x0004)
|
||||||
|
mask = 0x0403;
|
||||||
|
|
||||||
|
switch (port & mask) {
|
||||||
|
case 0x0000:
|
||||||
|
if (dev->ecp) {
|
||||||
|
if (!(dev->ecr & 0xc0))
|
||||||
|
ret = dev->dat;
|
||||||
|
} else {
|
||||||
|
/* DTR */
|
||||||
|
ret = dev->dat;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x0001:
|
||||||
|
ret = lpt_read_status(dev->id);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x0002:
|
||||||
|
ret = lpt_get_ctrl(dev);
|
||||||
|
if (dev->ecp)
|
||||||
|
ret = (ret & 0xfc) | (dev->ctrl & 0x03);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x0003:
|
||||||
|
if (lpt_is_epp(dev)) {
|
||||||
|
if (dev->dt && dev->dt->epp_request_read && dev->priv)
|
||||||
|
dev->dt->epp_request_read(1, dev->priv);
|
||||||
|
ret = dev->dat;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x0004 ... 0x0007:
|
||||||
|
if (lpt_is_epp(dev)) {
|
||||||
|
if (dev->dt && dev->dt->epp_request_read && dev->priv)
|
||||||
|
dev->dt->epp_request_read(0, dev->priv);
|
||||||
|
ret = dev->dat;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x0400: case 0x0404:
|
||||||
|
switch (dev->ecr >> 5) {
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
if (lpt_get_ctrl_raw(dev) & 0x20)
|
||||||
|
ret = lpt_read_fifo(dev);
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
/* TFIFO */
|
||||||
|
if (!fifo_get_empty(dev->fifo))
|
||||||
|
ret = fifo_read_evt(dev->fifo);
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
/* CNFGA */
|
||||||
|
ret = 0x14;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x0401: case 0x0405:
|
||||||
|
if ((dev->ecr & 0xe0) == 0xe0) {
|
||||||
|
/* CNFGB */
|
||||||
|
ret = 0x08;
|
||||||
|
ret |= (dev->irq_state ? 0x40 : 0x00);
|
||||||
|
ret |= ((dev->irq == 0x05) ? 0x30 : 0x00);
|
||||||
|
if ((dev->dma >= 1) && (dev->dma <= 3))
|
||||||
|
ret |= dev->dma;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x0402: case 0x0406:
|
||||||
|
ret = dev->ecr | dev->fifo_stat | (dev->dma_stat & 0x04);
|
||||||
|
ret |= (fifo_get_full(dev->fifo) ? 0x02 : 0x00);
|
||||||
|
ret |= (fifo_get_empty(dev->fifo) ? 0x01 : 0x00);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
lpt_log("[R] %04X = %02X\n", port, ret);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t
|
||||||
|
lpt_read_port(const int port, const uint16_t reg)
|
||||||
|
{
|
||||||
|
lpt_port_t *dev = &(lpt_ports[port]);
|
||||||
|
|
||||||
|
return lpt_read(reg, dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
lpt_irq(void *priv, const int raise)
|
||||||
|
{
|
||||||
|
lpt_port_t *dev = (lpt_port_t *) priv;
|
||||||
|
|
||||||
|
if (dev->enable_irq) {
|
||||||
|
if (dev->irq != 0xff) {
|
||||||
|
if (dev->ext) {
|
||||||
|
if (raise)
|
||||||
|
picintlevel(1 << dev->irq, &dev->irq_state);
|
||||||
|
else
|
||||||
|
picintclevel(1 << dev->irq, &dev->irq_state);
|
||||||
|
} else {
|
||||||
|
if (raise)
|
||||||
|
picint(1 << dev->irq);
|
||||||
|
else
|
||||||
|
picintc(1 << dev->irq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dev->ext || (dev->irq == 0xff))
|
||||||
|
dev->irq_state = raise;
|
||||||
|
} else {
|
||||||
|
if (dev->irq != 0xff) {
|
||||||
|
if (dev->ext)
|
||||||
|
picintclevel(1 << dev->irq, &dev->irq_state);
|
||||||
|
else
|
||||||
|
picintc(1 << dev->irq);
|
||||||
|
}
|
||||||
|
|
||||||
|
dev->irq_state = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
lpt_set_ext(const int port, const uint8_t ext)
|
||||||
|
{
|
||||||
|
if (lpt_ports[port].enabled)
|
||||||
|
lpt_ports[port].ext = ext;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
lpt_set_ecp(const int port, const uint8_t ecp)
|
||||||
|
{
|
||||||
|
if (lpt_ports[port].enabled) {
|
||||||
|
const uint16_t addr = lpt_ports[port].addr;
|
||||||
|
lpt_port_setup(port, 0xfff);
|
||||||
|
lpt_ports[port].ecp = ecp;
|
||||||
|
lpt_port_setup(port, addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
lpt_set_epp(const int port, const uint8_t epp)
|
||||||
|
{
|
||||||
|
if (lpt_ports[port].enabled) {
|
||||||
|
const uint16_t addr = lpt_ports[port].addr;
|
||||||
|
lpt_port_setup(port, 0xfff);
|
||||||
|
lpt_ports[port].epp = epp;
|
||||||
|
lpt_port_setup(port, addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
lpt_set_lv2(const int port, const uint8_t lv2)
|
||||||
|
{
|
||||||
|
if (lpt_ports[port].enabled) {
|
||||||
|
const uint16_t addr = lpt_ports[port].addr;
|
||||||
|
lpt_port_setup(port, 0xfff);
|
||||||
|
lpt_ports[port].lv2 = lv2;
|
||||||
|
lpt_port_setup(port, addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
lpt_close(void)
|
||||||
|
{
|
||||||
|
for (uint8_t i = 0; i < PARALLEL_MAX; i++) {
|
||||||
|
if (lpt_ports[i].enabled) {
|
||||||
|
fifo_close(lpt_ports[i].fifo);
|
||||||
|
lpt_ports[i].fifo = NULL;
|
||||||
|
|
||||||
|
timer_disable(&lpt_ports[i].fifo_out_timer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
lpt_port_zero(lpt_port_t *dev)
|
||||||
|
{
|
||||||
|
lpt_port_t temp = { 0 };
|
||||||
|
|
||||||
|
temp.irq = dev->irq;
|
||||||
|
temp.id = dev->id;
|
||||||
|
temp.device = dev->device;
|
||||||
|
temp.dt = dev->dt;
|
||||||
|
temp.priv = dev->priv;
|
||||||
|
temp.enabled = dev->enabled;
|
||||||
|
temp.fifo = dev->fifo;
|
||||||
|
temp.fifo_out_timer = dev->fifo_out_timer;
|
||||||
|
|
||||||
|
if (dev->enabled)
|
||||||
|
lpt_port_remove(dev->id);
|
||||||
|
|
||||||
|
memset(dev, 0x00, sizeof(lpt_port_t));
|
||||||
|
|
||||||
|
dev->addr = 0xffff;
|
||||||
|
dev->irq = temp.irq;
|
||||||
|
dev->id = temp.id;
|
||||||
|
dev->device = temp.device;
|
||||||
|
dev->dt = temp.dt;
|
||||||
|
dev->priv = temp.priv;
|
||||||
|
dev->enabled = temp.enabled;
|
||||||
|
dev->fifo = temp.fifo;
|
||||||
|
dev->fifo_out_timer = temp.fifo_out_timer;
|
||||||
|
|
||||||
|
if (machine_has_bus(machine, MACHINE_BUS_MCA))
|
||||||
|
dev->ext = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
lpt_reset(void)
|
||||||
|
{
|
||||||
|
for (uint8_t i = 0; i < PARALLEL_MAX; i++) {
|
||||||
|
if (lpt_ports[i].enabled)
|
||||||
|
if (timer_is_enabled(&lpt_ports[i].fifo_out_timer))
|
||||||
|
timer_disable(&lpt_ports[i].fifo_out_timer);
|
||||||
|
|
||||||
|
lpt_port_zero(&(lpt_ports[i]));
|
||||||
|
|
||||||
|
if (lpt_ports[i].enabled) {
|
||||||
|
if (lpt_ports[i].irq_state) {
|
||||||
|
if (lpt_ports[i].irq == 0xff)
|
||||||
|
lpt_ports[i].irq_state = 0x00;
|
||||||
|
else {
|
||||||
|
picintclevel(lpt_ports[i].irq, &lpt_ports[i].irq_state);
|
||||||
|
picintc(lpt_ports[i].irq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lpt_ports[i].enable_irq = 0x00;
|
||||||
|
lpt_ports[i].ext = !!(machine_has_bus(machine, MACHINE_BUS_MCA));
|
||||||
|
lpt_ports[i].epp = 0;
|
||||||
|
lpt_ports[i].ecp = 0;
|
||||||
|
lpt_ports[i].ecr = 0x15;
|
||||||
|
lpt_ports[i].dat = 0xff;
|
||||||
|
lpt_ports[i].fifo_stat = 0x00;
|
||||||
|
lpt_ports[i].dma_stat = 0x00;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
lpt_init(void)
|
||||||
|
{
|
||||||
|
const uint16_t default_ports[PARALLEL_MAX] = { LPT1_ADDR, LPT2_ADDR, LPT_MDA_ADDR, LPT4_ADDR };
|
||||||
|
const uint8_t default_irqs[PARALLEL_MAX] = { LPT1_IRQ, LPT2_IRQ, LPT_MDA_IRQ, LPT4_IRQ };
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < PARALLEL_MAX; i++) {
|
||||||
|
lpt_ports[i].id = i;
|
||||||
|
lpt_ports[i].dt = NULL;
|
||||||
|
lpt_ports[i].priv = NULL;
|
||||||
|
lpt_ports[i].fifo = NULL;
|
||||||
|
memset(&lpt_ports[i].fifo_out_timer, 0x00, sizeof(pc_timer_t));
|
||||||
|
|
||||||
|
lpt_port_zero(&(lpt_ports[i]));
|
||||||
|
|
||||||
|
lpt_ports[i].addr = 0xffff;
|
||||||
|
lpt_ports[i].irq = 0xff;
|
||||||
|
lpt_ports[i].dma = 0xff;
|
||||||
|
lpt_ports[i].enable_irq = 0x00;
|
||||||
|
lpt_ports[i].ext = 0;
|
||||||
|
lpt_ports[i].epp = 0;
|
||||||
|
lpt_ports[i].ecp = 0;
|
||||||
|
lpt_ports[i].ecr = 0x15;
|
||||||
|
|
||||||
|
if (lpt_ports[i].enabled) {
|
||||||
|
lpt_port_setup(i, default_ports[i]);
|
||||||
|
lpt_port_irq(i, default_irqs[i]);
|
||||||
|
|
||||||
|
lpt_ports[i].fifo = fifo16_init();
|
||||||
|
|
||||||
|
fifo_set_trigger_len(lpt_ports[i].fifo, 8);
|
||||||
|
|
||||||
|
fifo_set_d_ready_evt(lpt_ports[i].fifo, lpt_fifo_d_ready_evt);
|
||||||
|
fifo_set_priv(lpt_ports[i].fifo, &lpt_ports[i]);
|
||||||
|
|
||||||
|
timer_add(&lpt_ports[i].fifo_out_timer, lpt_fifo_out_callback, &lpt_ports[i], 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
lpt_port_setup(const int i, const uint16_t port)
|
||||||
|
{
|
||||||
|
if (lpt_ports[i].enabled) {
|
||||||
|
if (lpt_ports[i].addr != 0xffff) {
|
||||||
|
io_removehandler(lpt_ports[i].addr, 0x0007, lpt_read, NULL, NULL, lpt_write, NULL, NULL, &lpt_ports[i]);
|
||||||
|
io_removehandler(lpt_ports[i].addr + 0x0400, 0x0007, lpt_read, NULL, NULL, lpt_write, NULL, NULL, &lpt_ports[i]);
|
||||||
|
}
|
||||||
|
if (port != 0xffff) {
|
||||||
|
lpt_log("Set handler: %04X-%04X\n", port, port + 0x0003);
|
||||||
|
io_sethandler(port, 0x0003, lpt_read, NULL, NULL, lpt_write, NULL, NULL, &lpt_ports[i]);
|
||||||
|
if (lpt_ports[i].epp)
|
||||||
|
io_sethandler(lpt_ports[i].addr + 0x0003, 0x0003, lpt_read, NULL, NULL, lpt_write, NULL, NULL, &lpt_ports[i]);
|
||||||
|
if (lpt_ports[i].ecp || lpt_ports[i].lv2) {
|
||||||
|
io_sethandler(port + 0x0400, 0x0003, lpt_read, NULL, NULL, lpt_write, NULL, NULL, &lpt_ports[i]);
|
||||||
|
if (lpt_ports[i].epp)
|
||||||
|
io_sethandler(lpt_ports[i].addr + 0x0403, 0x0003, lpt_read, NULL, NULL, lpt_write, NULL, NULL, &lpt_ports[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lpt_ports[i].addr = port;
|
||||||
|
} else
|
||||||
|
lpt_ports[i].addr = 0xffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
lpt_port_irq(const int i, const uint8_t irq)
|
||||||
|
{
|
||||||
|
if (lpt_ports[i].enabled)
|
||||||
|
lpt_ports[i].irq = irq;
|
||||||
|
else
|
||||||
|
lpt_ports[i].irq = 0xff;
|
||||||
|
|
||||||
|
lpt_log("Port %i IRQ = %02X\n", i, irq);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
lpt_port_dma(const int i, const uint8_t dma)
|
||||||
|
{
|
||||||
|
if (lpt_ports[i].enabled)
|
||||||
|
lpt_ports[i].dma = dma;
|
||||||
|
else
|
||||||
|
lpt_ports[i].dma = 0xff;
|
||||||
|
|
||||||
|
lpt_log("Port %i DMA = %02X\n", i, dma);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
lpt_port_remove(const int i)
|
||||||
|
{
|
||||||
|
if (lpt_ports[i].enabled && (lpt_ports[i].addr != 0xffff)) {
|
||||||
|
io_removehandler(lpt_ports[i].addr, 0x0007, lpt_read, NULL, NULL, lpt_write, NULL, NULL, &lpt_ports[i]);
|
||||||
|
io_removehandler(lpt_ports[i].addr + 0x0400, 0x0007, lpt_read, NULL, NULL, lpt_write, NULL, NULL, &lpt_ports[i]);
|
||||||
|
|
||||||
|
lpt_ports[i].addr = 0xffff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
lpt1_remove_ams(void)
|
||||||
|
{
|
||||||
|
if (lpt_ports[0].enabled)
|
||||||
|
io_removehandler(lpt_ports[0].addr + 1, 0x0002, lpt_read, NULL, NULL, lpt_write, NULL, NULL, &lpt_ports[0]);
|
||||||
|
}
|
||||||
@@ -25,14 +25,24 @@ typedef struct lpt_device_t {
|
|||||||
void (*close)(void *priv);
|
void (*close)(void *priv);
|
||||||
void (*write_data)(uint8_t val, void *priv);
|
void (*write_data)(uint8_t val, void *priv);
|
||||||
void (*write_ctrl)(uint8_t val, void *priv);
|
void (*write_ctrl)(uint8_t val, void *priv);
|
||||||
uint8_t (*read_data)(void *priv);
|
void (*autofeed)(uint8_t val,void *priv);
|
||||||
|
void (*strobe)(uint8_t old, uint8_t val,void *priv);
|
||||||
uint8_t (*read_status)(void *priv);
|
uint8_t (*read_status)(void *priv);
|
||||||
uint8_t (*read_ctrl)(void *priv);
|
uint8_t (*read_ctrl)(void *priv);
|
||||||
|
void (*epp_write_data)(uint8_t is_addr, uint8_t val, void *priv);
|
||||||
|
void (*epp_request_read)(uint8_t is_addr, void *priv);
|
||||||
} lpt_device_t;
|
} lpt_device_t;
|
||||||
|
|
||||||
|
extern void lpt_set_ext(int port, uint8_t ext);
|
||||||
|
extern void lpt_set_ecp(int port, uint8_t ecp);
|
||||||
|
extern void lpt_set_epp(int port, uint8_t epp);
|
||||||
|
extern void lpt_set_lv2(int port, uint8_t lv2);
|
||||||
|
extern void lpt_reset(void);
|
||||||
|
extern void lpt_close(void);
|
||||||
extern void lpt_init(void);
|
extern void lpt_init(void);
|
||||||
extern void lpt_port_setup(int i, uint16_t port);
|
extern void lpt_port_setup(int i, uint16_t port);
|
||||||
extern void lpt_port_irq(int i, uint8_t irq);
|
extern void lpt_port_irq(int i, uint8_t irq);
|
||||||
|
extern void lpt_port_dma(int i, uint8_t dma);
|
||||||
extern void lpt_port_remove(int i);
|
extern void lpt_port_remove(int i);
|
||||||
extern void lpt1_remove_ams(void);
|
extern void lpt1_remove_ams(void);
|
||||||
|
|
||||||
@@ -68,19 +78,50 @@ void lpt_devices_close(void);
|
|||||||
typedef struct lpt_port_t {
|
typedef struct lpt_port_t {
|
||||||
uint8_t enabled;
|
uint8_t enabled;
|
||||||
uint8_t irq;
|
uint8_t irq;
|
||||||
|
uint8_t irq_state;
|
||||||
|
uint8_t dma;
|
||||||
uint8_t dat;
|
uint8_t dat;
|
||||||
uint8_t ctrl;
|
uint8_t ctrl;
|
||||||
|
uint8_t ext;
|
||||||
|
uint8_t epp;
|
||||||
|
uint8_t ecp;
|
||||||
|
uint8_t ecr;
|
||||||
|
uint8_t in_dat;
|
||||||
|
uint8_t fifo_stat;
|
||||||
|
uint8_t dma_stat;
|
||||||
|
uint8_t state;
|
||||||
|
uint8_t autofeed;
|
||||||
|
uint8_t strobe;
|
||||||
|
uint8_t lv2;
|
||||||
|
uint8_t pad[7];
|
||||||
uint16_t addr;
|
uint16_t addr;
|
||||||
uint16_t pad0;
|
uint16_t id;
|
||||||
|
uint16_t pad0[2];
|
||||||
int device;
|
int device;
|
||||||
int enable_irq;
|
int enable_irq;
|
||||||
lpt_device_t *dt;
|
lpt_device_t *dt;
|
||||||
|
#ifdef FIFO_H
|
||||||
|
fifo16_t *fifo;
|
||||||
|
#else
|
||||||
|
void *fifo;
|
||||||
|
#endif
|
||||||
void *priv;
|
void *priv;
|
||||||
|
|
||||||
|
pc_timer_t fifo_out_timer;
|
||||||
} lpt_port_t;
|
} lpt_port_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
LPT_STATE_IDLE = 0,
|
||||||
|
LPT_STATE_READ_DMA,
|
||||||
|
LPT_STATE_WRITE_FIFO
|
||||||
|
} lpt_state_t;
|
||||||
|
|
||||||
extern lpt_port_t lpt_ports[PARALLEL_MAX];
|
extern lpt_port_t lpt_ports[PARALLEL_MAX];
|
||||||
|
|
||||||
extern void lpt_write(uint16_t port, uint8_t val, void *priv);
|
extern void lpt_write(uint16_t port, uint8_t val, void *priv);
|
||||||
|
|
||||||
|
extern void lpt_write_to_fifo(void *priv, uint8_t val);
|
||||||
|
|
||||||
extern uint8_t lpt_read(uint16_t port, void *priv);
|
extern uint8_t lpt_read(uint16_t port, void *priv);
|
||||||
|
|
||||||
extern uint8_t lpt_read_port(int port, uint16_t reg);
|
extern uint8_t lpt_read_port(int port, uint16_t reg);
|
||||||
@@ -88,11 +129,11 @@ extern uint8_t lpt_read_port(int port, uint16_t reg);
|
|||||||
extern uint8_t lpt_read_status(int port);
|
extern uint8_t lpt_read_status(int port);
|
||||||
extern void lpt_irq(void *priv, int raise);
|
extern void lpt_irq(void *priv, int raise);
|
||||||
|
|
||||||
|
extern int lpt_device_get_from_internal_name(const char *s);
|
||||||
|
|
||||||
extern const char *lpt_device_get_name(int id);
|
extern const char *lpt_device_get_name(int id);
|
||||||
extern const char *lpt_device_get_internal_name(int id);
|
extern const char *lpt_device_get_internal_name(int id);
|
||||||
|
|
||||||
extern int lpt_device_get_from_internal_name(char *s);
|
|
||||||
|
|
||||||
extern const lpt_device_t lpt_dac_device;
|
extern const lpt_device_t lpt_dac_device;
|
||||||
extern const lpt_device_t lpt_dac_stereo_device;
|
extern const lpt_device_t lpt_dac_stereo_device;
|
||||||
|
|
||||||
|
|||||||
264
src/lpt.c
264
src/lpt.c
@@ -1,264 +0,0 @@
|
|||||||
/* Copyright holders: Sarah Walker
|
|
||||||
see COPYING for more details
|
|
||||||
*/
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <wchar.h>
|
|
||||||
#include <86box/86box.h>
|
|
||||||
#include <86box/io.h>
|
|
||||||
#include <86box/lpt.h>
|
|
||||||
#include <86box/pic.h>
|
|
||||||
#include <86box/sound.h>
|
|
||||||
#include <86box/prt_devs.h>
|
|
||||||
#include <86box/thread.h>
|
|
||||||
#include <86box/timer.h>
|
|
||||||
#include <86box/device.h>
|
|
||||||
#include <86box/network.h>
|
|
||||||
|
|
||||||
lpt_port_t lpt_ports[PARALLEL_MAX];
|
|
||||||
|
|
||||||
const lpt_device_t lpt_none_device = {
|
|
||||||
.name = "None",
|
|
||||||
.internal_name = "none",
|
|
||||||
.init = NULL,
|
|
||||||
.close = NULL,
|
|
||||||
.write_data = NULL,
|
|
||||||
.write_ctrl = NULL,
|
|
||||||
.read_data = NULL,
|
|
||||||
.read_status = NULL,
|
|
||||||
.read_ctrl = NULL
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct {
|
|
||||||
const char *internal_name;
|
|
||||||
const lpt_device_t *device;
|
|
||||||
} lpt_devices[] = {
|
|
||||||
// clang-format off
|
|
||||||
{"none", &lpt_none_device },
|
|
||||||
{"dss", &dss_device },
|
|
||||||
{"lpt_dac", &lpt_dac_device },
|
|
||||||
{"lpt_dac_stereo", &lpt_dac_stereo_device },
|
|
||||||
{"text_prt", &lpt_prt_text_device },
|
|
||||||
{"dot_matrix", &lpt_prt_escp_device },
|
|
||||||
{"postscript", &lpt_prt_ps_device },
|
|
||||||
#ifdef USE_PCL
|
|
||||||
{"pcl", &lpt_prt_pcl_device },
|
|
||||||
#endif
|
|
||||||
{"plip", &lpt_plip_device },
|
|
||||||
{"dongle_savquest", &lpt_hasp_savquest_device },
|
|
||||||
{"", NULL }
|
|
||||||
// clang-format on
|
|
||||||
};
|
|
||||||
|
|
||||||
const char *
|
|
||||||
lpt_device_get_name(int id)
|
|
||||||
{
|
|
||||||
if (strlen(lpt_devices[id].internal_name) == 0)
|
|
||||||
return NULL;
|
|
||||||
if (!lpt_devices[id].device)
|
|
||||||
return "None";
|
|
||||||
return lpt_devices[id].device->name;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *
|
|
||||||
lpt_device_get_internal_name(int id)
|
|
||||||
{
|
|
||||||
if (strlen(lpt_devices[id].internal_name) == 0)
|
|
||||||
return NULL;
|
|
||||||
return lpt_devices[id].internal_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
lpt_device_get_from_internal_name(char *s)
|
|
||||||
{
|
|
||||||
int c = 0;
|
|
||||||
|
|
||||||
while (strlen(lpt_devices[c].internal_name) != 0) {
|
|
||||||
if (strcmp(lpt_devices[c].internal_name, s) == 0)
|
|
||||||
return c;
|
|
||||||
c++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
lpt_devices_init(void)
|
|
||||||
{
|
|
||||||
for (uint8_t i = 0; i < PARALLEL_MAX; i++) {
|
|
||||||
lpt_ports[i].dt = (lpt_device_t *) lpt_devices[lpt_ports[i].device].device;
|
|
||||||
|
|
||||||
if (lpt_ports[i].dt && lpt_ports[i].dt->init)
|
|
||||||
lpt_ports[i].priv = lpt_ports[i].dt->init(&lpt_ports[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
lpt_devices_close(void)
|
|
||||||
{
|
|
||||||
lpt_port_t *dev;
|
|
||||||
|
|
||||||
for (uint8_t i = 0; i < PARALLEL_MAX; i++) {
|
|
||||||
dev = &lpt_ports[i];
|
|
||||||
|
|
||||||
if (lpt_ports[i].dt && lpt_ports[i].dt->close)
|
|
||||||
dev->dt->close(dev->priv);
|
|
||||||
|
|
||||||
dev->dt = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
lpt_write(uint16_t port, uint8_t val, void *priv)
|
|
||||||
{
|
|
||||||
lpt_port_t *dev = (lpt_port_t *) priv;
|
|
||||||
|
|
||||||
switch (port & 3) {
|
|
||||||
case 0:
|
|
||||||
if (dev->dt && dev->dt->write_data && dev->priv)
|
|
||||||
dev->dt->write_data(val, dev->priv);
|
|
||||||
dev->dat = val;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 1:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2:
|
|
||||||
if (dev->dt && dev->dt->write_ctrl && dev->priv)
|
|
||||||
dev->dt->write_ctrl(val, dev->priv);
|
|
||||||
dev->ctrl = val;
|
|
||||||
dev->enable_irq = val & 0x10;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t
|
|
||||||
lpt_read(uint16_t port, void *priv)
|
|
||||||
{
|
|
||||||
uint8_t ret = 0xff;
|
|
||||||
lpt_port_t *dev = (lpt_port_t *) priv;
|
|
||||||
|
|
||||||
switch (port & 3) {
|
|
||||||
case 0:
|
|
||||||
if (dev->dt && dev->dt->read_data && dev->priv)
|
|
||||||
ret = dev->dt->read_data(dev->priv);
|
|
||||||
else
|
|
||||||
ret = dev->dat;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 1:
|
|
||||||
if (dev->dt && dev->dt->read_status && dev->priv)
|
|
||||||
ret = dev->dt->read_status(dev->priv) | 0x07;
|
|
||||||
else
|
|
||||||
ret = 0xdf;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2:
|
|
||||||
if (dev->dt && dev->dt->read_ctrl && dev->priv)
|
|
||||||
ret = (dev->dt->read_ctrl(dev->priv) & 0xef) | dev->enable_irq;
|
|
||||||
else
|
|
||||||
ret = 0xe0 | dev->ctrl | dev->enable_irq;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t
|
|
||||||
lpt_read_port(int port, uint16_t reg)
|
|
||||||
{
|
|
||||||
lpt_port_t *dev = &(lpt_ports[port]);
|
|
||||||
uint8_t ret = lpt_read(reg, dev);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t
|
|
||||||
lpt_read_status(int port)
|
|
||||||
{
|
|
||||||
lpt_port_t *dev = &(lpt_ports[port]);
|
|
||||||
uint8_t ret = 0xff;
|
|
||||||
|
|
||||||
if (dev->dt && dev->dt->read_status && dev->priv)
|
|
||||||
ret = dev->dt->read_status(dev->priv) | 0x07;
|
|
||||||
else
|
|
||||||
ret = 0xdf;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
lpt_irq(void *priv, int raise)
|
|
||||||
{
|
|
||||||
const lpt_port_t *dev = (lpt_port_t *) priv;
|
|
||||||
|
|
||||||
if (dev->enable_irq && (dev->irq != 0xff)) {
|
|
||||||
if (raise)
|
|
||||||
picint(1 << dev->irq);
|
|
||||||
else
|
|
||||||
picintc(1 << dev->irq);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
lpt_init(void)
|
|
||||||
{
|
|
||||||
uint16_t default_ports[PARALLEL_MAX] = { LPT1_ADDR, LPT2_ADDR, LPT_MDA_ADDR, LPT4_ADDR };
|
|
||||||
uint8_t default_irqs[PARALLEL_MAX] = { LPT1_IRQ, LPT2_IRQ, LPT_MDA_IRQ, LPT4_IRQ };
|
|
||||||
|
|
||||||
for (uint8_t i = 0; i < PARALLEL_MAX; i++) {
|
|
||||||
lpt_ports[i].addr = 0xffff;
|
|
||||||
lpt_ports[i].irq = 0xff;
|
|
||||||
lpt_ports[i].enable_irq = 0x10;
|
|
||||||
|
|
||||||
if (lpt_ports[i].enabled) {
|
|
||||||
lpt_port_setup(i, default_ports[i]);
|
|
||||||
lpt_port_irq(i, default_irqs[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
lpt_port_setup(int i, uint16_t port)
|
|
||||||
{
|
|
||||||
if (lpt_ports[i].enabled) {
|
|
||||||
if ((lpt_ports[i].addr != 0xffff) && (lpt_ports[i].addr != 0x0000))
|
|
||||||
io_removehandler(lpt_ports[i].addr, 0x0003, lpt_read, NULL, NULL, lpt_write, NULL, NULL, &lpt_ports[i]);
|
|
||||||
if ((port != 0xffff) && (port != 0x0000))
|
|
||||||
io_sethandler(port, 0x0003, lpt_read, NULL, NULL, lpt_write, NULL, NULL, &lpt_ports[i]);
|
|
||||||
lpt_ports[i].addr = port;
|
|
||||||
} else
|
|
||||||
lpt_ports[i].addr = 0xffff;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
lpt_port_irq(int i, uint8_t irq)
|
|
||||||
{
|
|
||||||
if (lpt_ports[i].enabled)
|
|
||||||
lpt_ports[i].irq = irq;
|
|
||||||
else
|
|
||||||
lpt_ports[i].irq = 0xff;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
lpt_port_remove(int i)
|
|
||||||
{
|
|
||||||
if (lpt_ports[i].enabled && (lpt_ports[i].addr != 0xffff)) {
|
|
||||||
io_removehandler(lpt_ports[i].addr, 0x0003, lpt_read, NULL, NULL, lpt_write, NULL, NULL, &lpt_ports[i]);
|
|
||||||
lpt_ports[i].addr = 0xffff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
lpt1_remove_ams(void)
|
|
||||||
{
|
|
||||||
if (lpt_ports[0].enabled)
|
|
||||||
io_removehandler(lpt_ports[0].addr + 1, 0x0002, lpt_read, NULL, NULL, lpt_write, NULL, NULL, &lpt_ports[0]);
|
|
||||||
}
|
|
||||||
@@ -494,9 +494,12 @@ const lpt_device_t lpt_plip_device = {
|
|||||||
.close = plip_close,
|
.close = plip_close,
|
||||||
.write_data = plip_write_data,
|
.write_data = plip_write_data,
|
||||||
.write_ctrl = plip_write_ctrl,
|
.write_ctrl = plip_write_ctrl,
|
||||||
.read_data = NULL,
|
.autofeed = NULL,
|
||||||
|
.strobe = NULL,
|
||||||
.read_status = plip_read_status,
|
.read_status = plip_read_status,
|
||||||
.read_ctrl = NULL
|
.read_ctrl = NULL,
|
||||||
|
.epp_write_data = NULL,
|
||||||
|
.epp_request_read = NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
const device_t plip_device = {
|
const device_t plip_device = {
|
||||||
|
|||||||
@@ -1881,6 +1881,39 @@ write_data(uint8_t val, void *priv)
|
|||||||
dev->data = val;
|
dev->data = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
autofeed(uint8_t val, void *priv)
|
||||||
|
{
|
||||||
|
escp_t *dev = (escp_t *) priv;
|
||||||
|
|
||||||
|
if (dev == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
dev->autofeed = ((val & 0x02) > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
strobe(uint8_t old, uint8_t val, void *priv)
|
||||||
|
{
|
||||||
|
escp_t *dev = (escp_t *) priv;
|
||||||
|
|
||||||
|
if (dev == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Data is strobed to the parallel printer on the falling edge of the
|
||||||
|
strobe bit. */
|
||||||
|
if (!(val & 0x01) && (old & 0x01)) {
|
||||||
|
/* Process incoming character. */
|
||||||
|
handle_char(dev, dev->data);
|
||||||
|
|
||||||
|
/* ACK it, will be read on next READ STATUS. */
|
||||||
|
dev->ack = 1;
|
||||||
|
timer_set_delay_u64(&dev->pulse_timer, ISACONST);
|
||||||
|
|
||||||
|
timer_set_delay_u64(&dev->timeout_timer, 5000000 * TIMER_USEC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
write_ctrl(uint8_t val, void *priv)
|
write_ctrl(uint8_t val, void *priv)
|
||||||
{
|
{
|
||||||
@@ -1919,14 +1952,6 @@ write_ctrl(uint8_t val, void *priv)
|
|||||||
dev->autofeed = ((val & 0x02) > 0);
|
dev->autofeed = ((val & 0x02) > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t
|
|
||||||
read_data(void *priv)
|
|
||||||
{
|
|
||||||
const escp_t *dev = (escp_t *) priv;
|
|
||||||
|
|
||||||
return dev->data;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t
|
static uint8_t
|
||||||
read_ctrl(void *priv)
|
read_ctrl(void *priv)
|
||||||
{
|
{
|
||||||
@@ -2058,13 +2083,16 @@ escp_close(void *priv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
const lpt_device_t lpt_prt_escp_device = {
|
const lpt_device_t lpt_prt_escp_device = {
|
||||||
.name = "Generic ESC/P Dot-Matrix Printer",
|
.name = "Generic ESC/P Dot-Matrix",
|
||||||
.internal_name = "dot_matrix",
|
.internal_name = "dot_matrix",
|
||||||
.init = escp_init,
|
.init = escp_init,
|
||||||
.close = escp_close,
|
.close = escp_close,
|
||||||
.write_data = write_data,
|
.write_data = write_data,
|
||||||
.write_ctrl = write_ctrl,
|
.write_ctrl = write_ctrl,
|
||||||
.read_data = read_data,
|
.autofeed = autofeed,
|
||||||
|
.strobe = strobe,
|
||||||
.read_status = read_status,
|
.read_status = read_status,
|
||||||
.read_ctrl = read_ctrl
|
.read_ctrl = read_ctrl,
|
||||||
|
.epp_write_data = NULL,
|
||||||
|
.epp_request_read = NULL
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -319,6 +319,35 @@ process_data(ps_t *dev)
|
|||||||
dev->buffer[dev->buffer_pos] = 0;
|
dev->buffer[dev->buffer_pos] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ps_autofeed(uint8_t val, void *priv)
|
||||||
|
{
|
||||||
|
ps_t *dev = (ps_t *) priv;
|
||||||
|
|
||||||
|
if (dev == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
dev->autofeed = val & 0x02 ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ps_strobe(uint8_t old, uint8_t val, void *priv)
|
||||||
|
{
|
||||||
|
ps_t *dev = (ps_t *) priv;
|
||||||
|
|
||||||
|
if (dev == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!(val & 0x01) && (old & 0x01)) {
|
||||||
|
process_data(dev);
|
||||||
|
|
||||||
|
dev->ack = true;
|
||||||
|
|
||||||
|
timer_set_delay_u64(&dev->pulse_timer, ISACONST);
|
||||||
|
timer_set_delay_u64(&dev->timeout_timer, 5000000 * TIMER_USEC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ps_write_ctrl(uint8_t val, void *priv)
|
ps_write_ctrl(uint8_t val, void *priv)
|
||||||
{
|
{
|
||||||
@@ -485,9 +514,12 @@ const lpt_device_t lpt_prt_ps_device = {
|
|||||||
.close = ps_close,
|
.close = ps_close,
|
||||||
.write_data = ps_write_data,
|
.write_data = ps_write_data,
|
||||||
.write_ctrl = ps_write_ctrl,
|
.write_ctrl = ps_write_ctrl,
|
||||||
.read_data = NULL,
|
.autofeed = ps_autofeed,
|
||||||
|
.strobe = ps_strobe,
|
||||||
.read_status = ps_read_status,
|
.read_status = ps_read_status,
|
||||||
.read_ctrl = NULL
|
.read_ctrl = NULL,
|
||||||
|
.epp_write_data = NULL,
|
||||||
|
.epp_request_read = NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef USE_PCL
|
#ifdef USE_PCL
|
||||||
@@ -498,8 +530,11 @@ const lpt_device_t lpt_prt_pcl_device = {
|
|||||||
.close = ps_close,
|
.close = ps_close,
|
||||||
.write_data = ps_write_data,
|
.write_data = ps_write_data,
|
||||||
.write_ctrl = ps_write_ctrl,
|
.write_ctrl = ps_write_ctrl,
|
||||||
.read_data = NULL,
|
.autofeed = ps_autofeed,
|
||||||
|
.strobe = ps_strobe,
|
||||||
.read_status = ps_read_status,
|
.read_status = ps_read_status,
|
||||||
.read_ctrl = NULL
|
.read_ctrl = NULL,
|
||||||
|
.epp_write_data = NULL,
|
||||||
|
.epp_request_read = NULL
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -367,6 +367,38 @@ write_data(uint8_t val, void *priv)
|
|||||||
dev->data = val;
|
dev->data = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
autofeed(uint8_t val, void *priv)
|
||||||
|
{
|
||||||
|
prnt_t *dev = (prnt_t *) priv;
|
||||||
|
|
||||||
|
if (dev == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* set autofeed value */
|
||||||
|
dev->autofeed = val & 0x02 ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
strobe(uint8_t old, uint8_t val, void *priv)
|
||||||
|
{
|
||||||
|
prnt_t *dev = (prnt_t *) priv;
|
||||||
|
|
||||||
|
if (dev == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!(val & 0x01) && (old & 0x01)) { /* STROBE */
|
||||||
|
/* Process incoming character. */
|
||||||
|
handle_char(dev);
|
||||||
|
|
||||||
|
/* ACK it, will be read on next READ STATUS. */
|
||||||
|
dev->ack = 1;
|
||||||
|
|
||||||
|
timer_set_delay_u64(&dev->pulse_timer, ISACONST);
|
||||||
|
timer_set_delay_u64(&dev->timeout_timer, 5000000 * TIMER_USEC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
write_ctrl(uint8_t val, void *priv)
|
write_ctrl(uint8_t val, void *priv)
|
||||||
{
|
{
|
||||||
@@ -471,7 +503,10 @@ const lpt_device_t lpt_prt_text_device = {
|
|||||||
.close = prnt_close,
|
.close = prnt_close,
|
||||||
.write_data = write_data,
|
.write_data = write_data,
|
||||||
.write_ctrl = write_ctrl,
|
.write_ctrl = write_ctrl,
|
||||||
.read_data = NULL,
|
.autofeed = autofeed,
|
||||||
|
.strobe = strobe,
|
||||||
.read_status = read_status,
|
.read_status = read_status,
|
||||||
.read_ctrl = NULL
|
.read_ctrl = NULL,
|
||||||
|
.epp_write_data = NULL,
|
||||||
|
.epp_request_read = NULL
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -85,11 +85,18 @@ ali5123_lpt_handler(ali5123_t *dev)
|
|||||||
uint8_t global_enable = !(dev->regs[0x22] & (1 << 3));
|
uint8_t global_enable = !(dev->regs[0x22] & (1 << 3));
|
||||||
uint8_t local_enable = !!dev->ld_regs[3][0x30];
|
uint8_t local_enable = !!dev->ld_regs[3][0x30];
|
||||||
uint8_t lpt_irq = dev->ld_regs[3][0x70];
|
uint8_t lpt_irq = dev->ld_regs[3][0x70];
|
||||||
|
uint8_t lpt_dma = dev->ld_regs[3][0x74];
|
||||||
|
|
||||||
if (lpt_irq > 15)
|
if (lpt_irq > 15)
|
||||||
lpt_irq = 0xff;
|
lpt_irq = 0xff;
|
||||||
|
|
||||||
|
if (lpt_dma == 4)
|
||||||
|
lpt_dma = 0xff;
|
||||||
|
|
||||||
lpt1_remove();
|
lpt1_remove();
|
||||||
|
lpt_set_epp(0, !!(dev->ld_regs[3][0xf0] & 0x01));
|
||||||
|
lpt_set_ecp(0, !!(dev->ld_regs[3][0xf0] & 0x02));
|
||||||
|
lpt_set_ext(0, !(dev->ld_regs[3][0xf0] & 0x04) || !!(dev->ld_regs[3][0xf1] & 0x80));
|
||||||
if (global_enable && local_enable) {
|
if (global_enable && local_enable) {
|
||||||
ld_port = make_port(dev, 3) & 0xFFFC;
|
ld_port = make_port(dev, 3) & 0xFFFC;
|
||||||
if ((ld_port >= 0x0100) && (ld_port <= 0x0FFC))
|
if ((ld_port >= 0x0100) && (ld_port <= 0x0FFC))
|
||||||
@@ -247,7 +254,7 @@ ali5123_write(uint16_t port, uint8_t val, void *priv)
|
|||||||
dev->regs[dev->cur_reg] = val;
|
dev->regs[dev->cur_reg] = val;
|
||||||
} else {
|
} else {
|
||||||
valxor = val ^ dev->ld_regs[cur_ld][dev->cur_reg];
|
valxor = val ^ dev->ld_regs[cur_ld][dev->cur_reg];
|
||||||
if (((dev->cur_reg & 0xf0) == 0x70) && (cur_ld < 4))
|
if (((dev->cur_reg & 0xf0) == 0x70) && (cur_ld < 4) && (cur_ld != 3))
|
||||||
return;
|
return;
|
||||||
/* Block writes to some logical devices. */
|
/* Block writes to some logical devices. */
|
||||||
if (cur_ld > 0x0c)
|
if (cur_ld > 0x0c)
|
||||||
@@ -357,6 +364,9 @@ ali5123_write(uint16_t port, uint8_t val, void *priv)
|
|||||||
case 0x60:
|
case 0x60:
|
||||||
case 0x61:
|
case 0x61:
|
||||||
case 0x70:
|
case 0x70:
|
||||||
|
case 0x74:
|
||||||
|
case 0xf0:
|
||||||
|
case 0xf1:
|
||||||
if ((dev->cur_reg == 0x30) && (val & 0x01))
|
if ((dev->cur_reg == 0x30) && (val & 0x01))
|
||||||
dev->regs[0x22] &= ~0x08;
|
dev->regs[0x22] &= ~0x08;
|
||||||
if (valxor)
|
if (valxor)
|
||||||
|
|||||||
@@ -121,6 +121,10 @@ lpt1_handler(pc87306_t *dev)
|
|||||||
uint16_t lptba;
|
uint16_t lptba;
|
||||||
uint16_t lpt_port = LPT1_ADDR;
|
uint16_t lpt_port = LPT1_ADDR;
|
||||||
uint8_t lpt_irq = LPT2_IRQ;
|
uint8_t lpt_irq = LPT2_IRQ;
|
||||||
|
uint8_t lpt_dma = ((dev->regs[0x18] & 0x06) >> 1);
|
||||||
|
|
||||||
|
if (lpt_dma == 0x00)
|
||||||
|
lpt_dma = 0xff;
|
||||||
|
|
||||||
temp = dev->regs[0x01] & 3;
|
temp = dev->regs[0x01] & 3;
|
||||||
lptba = ((uint16_t) dev->regs[0x19]) << 2;
|
lptba = ((uint16_t) dev->regs[0x19]) << 2;
|
||||||
@@ -157,6 +161,13 @@ lpt1_handler(pc87306_t *dev)
|
|||||||
lpt1_setup(lpt_port);
|
lpt1_setup(lpt_port);
|
||||||
|
|
||||||
lpt1_irq(lpt_irq);
|
lpt1_irq(lpt_irq);
|
||||||
|
|
||||||
|
lpt_port_dma(0, lpt_dma);
|
||||||
|
|
||||||
|
lpt_set_ext(0, !!(dev->regs[0x02] & 0x80));
|
||||||
|
|
||||||
|
lpt_set_epp(0, !!(dev->regs[0x04] & 0x01));
|
||||||
|
lpt_set_ecp(0, !!(dev->regs[0x04] & 0x04));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -169,7 +180,7 @@ serial_handler(pc87306_t *dev, int uart)
|
|||||||
uint8_t pnp_shift;
|
uint8_t pnp_shift;
|
||||||
uint8_t irq;
|
uint8_t irq;
|
||||||
|
|
||||||
temp = (dev->regs[1] >> (2 << uart)) & 3;
|
temp = (dev->regs[0x01] >> (2 << uart)) & 3;
|
||||||
|
|
||||||
fer_shift = 2 << uart; /* 2 for UART 1, 4 for UART 2 */
|
fer_shift = 2 << uart; /* 2 for UART 1, 4 for UART 2 */
|
||||||
pnp_shift = 2 + (uart << 2); /* 2 for UART 1, 6 for UART 2 */
|
pnp_shift = 2 + (uart << 2); /* 2 for UART 1, 6 for UART 2 */
|
||||||
@@ -188,7 +199,7 @@ serial_handler(pc87306_t *dev, int uart)
|
|||||||
serial_setup(dev->uart[uart], COM2_ADDR, irq);
|
serial_setup(dev->uart[uart], COM2_ADDR, irq);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
switch ((dev->regs[1] >> 6) & 3) {
|
switch ((dev->regs[0x01] >> 6) & 3) {
|
||||||
case 0:
|
case 0:
|
||||||
serial_setup(dev->uart[uart], COM3_ADDR, irq);
|
serial_setup(dev->uart[uart], COM3_ADDR, irq);
|
||||||
break;
|
break;
|
||||||
@@ -207,7 +218,7 @@ serial_handler(pc87306_t *dev, int uart)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
switch ((dev->regs[1] >> 6) & 3) {
|
switch ((dev->regs[0x01] >> 6) & 3) {
|
||||||
case 0:
|
case 0:
|
||||||
serial_setup(dev->uart[uart], COM4_ADDR, irq);
|
serial_setup(dev->uart[uart], COM4_ADDR, irq);
|
||||||
break;
|
break;
|
||||||
@@ -264,41 +275,41 @@ pc87306_write(uint16_t port, uint8_t val, void *priv)
|
|||||||
|
|
||||||
switch (dev->cur_reg) {
|
switch (dev->cur_reg) {
|
||||||
case 0x00:
|
case 0x00:
|
||||||
if (valxor & 1) {
|
if (valxor & 0x01) {
|
||||||
lpt1_remove();
|
lpt1_remove();
|
||||||
if ((val & 1) && !(dev->regs[2] & 1))
|
if ((val & 1) && !(dev->regs[0x02] & 1))
|
||||||
lpt1_handler(dev);
|
lpt1_handler(dev);
|
||||||
}
|
}
|
||||||
if (valxor & 2) {
|
if (valxor & 0x02) {
|
||||||
serial_remove(dev->uart[0]);
|
serial_remove(dev->uart[0x00]);
|
||||||
if ((val & 2) && !(dev->regs[2] & 1))
|
if ((val & 2) && !(dev->regs[0x02] & 1))
|
||||||
serial_handler(dev, 0);
|
serial_handler(dev, 0);
|
||||||
}
|
}
|
||||||
if (valxor & 4) {
|
if (valxor & 0x04) {
|
||||||
serial_remove(dev->uart[1]);
|
serial_remove(dev->uart[0x01]);
|
||||||
if ((val & 4) && !(dev->regs[2] & 1))
|
if ((val & 4) && !(dev->regs[0x02] & 1))
|
||||||
serial_handler(dev, 1);
|
serial_handler(dev, 1);
|
||||||
}
|
}
|
||||||
if (valxor & 0x28) {
|
if (valxor & 0x28) {
|
||||||
fdc_remove(dev->fdc);
|
fdc_remove(dev->fdc);
|
||||||
if ((val & 8) && !(dev->regs[2] & 1))
|
if ((val & 8) && !(dev->regs[0x02] & 1))
|
||||||
fdc_set_base(dev->fdc, (val & 0x20) ? FDC_SECONDARY_ADDR : FDC_PRIMARY_ADDR);
|
fdc_set_base(dev->fdc, (val & 0x20) ? FDC_SECONDARY_ADDR : FDC_PRIMARY_ADDR);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x01:
|
case 0x01:
|
||||||
if (valxor & 3) {
|
if (valxor & 0x03) {
|
||||||
lpt1_remove();
|
lpt1_remove();
|
||||||
if ((dev->regs[0] & 1) && !(dev->regs[2] & 1))
|
if ((dev->regs[0x00] & 1) && !(dev->regs[0x02] & 1))
|
||||||
lpt1_handler(dev);
|
lpt1_handler(dev);
|
||||||
}
|
}
|
||||||
if (valxor & 0xcc) {
|
if (valxor & 0xcc) {
|
||||||
serial_remove(dev->uart[0]);
|
serial_remove(dev->uart[0x00]);
|
||||||
if ((dev->regs[0] & 2) && !(dev->regs[2] & 1))
|
if ((dev->regs[0x00] & 2) && !(dev->regs[0x02] & 1))
|
||||||
serial_handler(dev, 0);
|
serial_handler(dev, 0);
|
||||||
}
|
}
|
||||||
if (valxor & 0xf0) {
|
if (valxor & 0xf0) {
|
||||||
serial_remove(dev->uart[1]);
|
serial_remove(dev->uart[0x01]);
|
||||||
if ((dev->regs[0] & 4) && !(dev->regs[2] & 1))
|
if ((dev->regs[0x00] & 4) && !(dev->regs[0x02] & 1))
|
||||||
serial_handler(dev, 1);
|
serial_handler(dev, 1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -327,6 +338,11 @@ pc87306_write(uint16_t port, uint8_t val, void *priv)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x04:
|
case 0x04:
|
||||||
|
if (valxor & (0x05)) {
|
||||||
|
lpt1_remove();
|
||||||
|
if ((dev->regs[0x00] & 0x01) && !(dev->regs[0x02] & 0x01))
|
||||||
|
lpt1_handler(dev);
|
||||||
|
}
|
||||||
if (valxor & 0x80)
|
if (valxor & 0x80)
|
||||||
nvr_lock_set(0x00, 256, !!(val & 0x80), dev->nvr);
|
nvr_lock_set(0x00, 256, !!(val & 0x80), dev->nvr);
|
||||||
break;
|
break;
|
||||||
@@ -352,10 +368,17 @@ pc87306_write(uint16_t port, uint8_t val, void *priv)
|
|||||||
if (valxor & 0x30)
|
if (valxor & 0x30)
|
||||||
pc87306_gpio_handler(dev);
|
pc87306_gpio_handler(dev);
|
||||||
break;
|
break;
|
||||||
|
case 0x18:
|
||||||
|
if (valxor & (0x06)) {
|
||||||
|
lpt1_remove();
|
||||||
|
if ((dev->regs[0x00] & 0x01) && !(dev->regs[0x02] & 0x01))
|
||||||
|
lpt1_handler(dev);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 0x19:
|
case 0x19:
|
||||||
if (valxor) {
|
if (valxor) {
|
||||||
lpt1_remove();
|
lpt1_remove();
|
||||||
if ((dev->regs[0] & 1) && !(dev->regs[2] & 1))
|
if ((dev->regs[0x00] & 1) && !(dev->regs[0x02] & 1))
|
||||||
lpt1_handler(dev);
|
lpt1_handler(dev);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -364,18 +387,18 @@ pc87306_write(uint16_t port, uint8_t val, void *priv)
|
|||||||
lpt1_remove();
|
lpt1_remove();
|
||||||
if (!(val & 0x40))
|
if (!(val & 0x40))
|
||||||
dev->regs[0x19] = 0xEF;
|
dev->regs[0x19] = 0xEF;
|
||||||
if ((dev->regs[0] & 1) && !(dev->regs[2] & 1))
|
if ((dev->regs[0x00] & 1) && !(dev->regs[0x02] & 1))
|
||||||
lpt1_handler(dev);
|
lpt1_handler(dev);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x1c:
|
case 0x1c:
|
||||||
if (valxor) {
|
if (valxor) {
|
||||||
serial_remove(dev->uart[0]);
|
serial_remove(dev->uart[0x00]);
|
||||||
serial_remove(dev->uart[1]);
|
serial_remove(dev->uart[0x01]);
|
||||||
|
|
||||||
if ((dev->regs[0] & 2) && !(dev->regs[2] & 1))
|
if ((dev->regs[0x00] & 2) && !(dev->regs[0x02] & 1))
|
||||||
serial_handler(dev, 0);
|
serial_handler(dev, 0);
|
||||||
if ((dev->regs[0] & 4) && !(dev->regs[2] & 1))
|
if ((dev->regs[0x00] & 4) && !(dev->regs[0x02] & 1))
|
||||||
serial_handler(dev, 1);
|
serial_handler(dev, 1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -432,8 +455,8 @@ pc87306_reset_common(void *priv)
|
|||||||
*/
|
*/
|
||||||
lpt1_remove();
|
lpt1_remove();
|
||||||
lpt1_handler(dev);
|
lpt1_handler(dev);
|
||||||
serial_remove(dev->uart[0]);
|
serial_remove(dev->uart[0x00]);
|
||||||
serial_remove(dev->uart[1]);
|
serial_remove(dev->uart[0x01]);
|
||||||
serial_handler(dev, 0);
|
serial_handler(dev, 0);
|
||||||
serial_handler(dev, 1);
|
serial_handler(dev, 1);
|
||||||
fdc_reset(dev->fdc);
|
fdc_reset(dev->fdc);
|
||||||
@@ -471,8 +494,8 @@ pc87306_init(UNUSED(const device_t *info))
|
|||||||
|
|
||||||
dev->fdc = device_add(&fdc_at_nsc_device);
|
dev->fdc = device_add(&fdc_at_nsc_device);
|
||||||
|
|
||||||
dev->uart[0] = device_add_inst(&ns16550_device, 1);
|
dev->uart[0x00] = device_add_inst(&ns16550_device, 1);
|
||||||
dev->uart[1] = device_add_inst(&ns16550_device, 2);
|
dev->uart[0x01] = device_add_inst(&ns16550_device, 2);
|
||||||
|
|
||||||
dev->nvr = device_add(&at_mb_nvr_device);
|
dev->nvr = device_add(&at_mb_nvr_device);
|
||||||
|
|
||||||
|
|||||||
@@ -50,6 +50,14 @@ dac_write_data(uint8_t val, void *priv)
|
|||||||
dac_update(lpt_dac);
|
dac_update(lpt_dac);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
dac_strobe(uint8_t old, uint8_t val, void *priv)
|
||||||
|
{
|
||||||
|
lpt_dac_t *lpt_dac = (lpt_dac_t *) priv;
|
||||||
|
|
||||||
|
lpt_dac->channel = val;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
dac_write_ctrl(uint8_t val, void *priv)
|
dac_write_ctrl(uint8_t val, void *priv)
|
||||||
{
|
{
|
||||||
@@ -115,9 +123,12 @@ const lpt_device_t lpt_dac_device = {
|
|||||||
.close = dac_close,
|
.close = dac_close,
|
||||||
.write_data = dac_write_data,
|
.write_data = dac_write_data,
|
||||||
.write_ctrl = dac_write_ctrl,
|
.write_ctrl = dac_write_ctrl,
|
||||||
.read_data = NULL,
|
.autofeed = NULL,
|
||||||
|
.strobe = dac_strobe,
|
||||||
.read_status = dac_read_status,
|
.read_status = dac_read_status,
|
||||||
.read_ctrl = NULL
|
.read_ctrl = NULL,
|
||||||
|
.epp_write_data = NULL,
|
||||||
|
.epp_request_read = NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
const lpt_device_t lpt_dac_stereo_device = {
|
const lpt_device_t lpt_dac_stereo_device = {
|
||||||
@@ -127,7 +138,10 @@ const lpt_device_t lpt_dac_stereo_device = {
|
|||||||
.close = dac_close,
|
.close = dac_close,
|
||||||
.write_data = dac_write_data,
|
.write_data = dac_write_data,
|
||||||
.write_ctrl = dac_write_ctrl,
|
.write_ctrl = dac_write_ctrl,
|
||||||
.read_data = NULL,
|
.autofeed = NULL,
|
||||||
|
.strobe = dac_strobe,
|
||||||
.read_status = dac_read_status,
|
.read_status = dac_read_status,
|
||||||
.read_ctrl = NULL
|
.read_ctrl = NULL,
|
||||||
|
.epp_write_data = NULL,
|
||||||
|
.epp_request_read = NULL
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -138,8 +138,11 @@ const lpt_device_t dss_device = {
|
|||||||
.init = dss_init,
|
.init = dss_init,
|
||||||
.close = dss_close,
|
.close = dss_close,
|
||||||
.write_data = dss_write_data,
|
.write_data = dss_write_data,
|
||||||
|
.autofeed = NULL,
|
||||||
|
.strobe = NULL,
|
||||||
.write_ctrl = dss_write_ctrl,
|
.write_ctrl = dss_write_ctrl,
|
||||||
.read_data = NULL,
|
|
||||||
.read_status = dss_read_status,
|
.read_status = dss_read_status,
|
||||||
.read_ctrl = NULL
|
.read_ctrl = NULL,
|
||||||
|
.epp_write_data = NULL,
|
||||||
|
.epp_request_read = NULL
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user