Files
dosemu2/src/base/dev/misc/lpt.c
geos_one 17bb5d7efa
Some checks failed
Build / build (push) Has been cancelled
New upstream version 2.0-0.9
2025-08-14 09:28:49 +02:00

362 lines
8.6 KiB
C

/* for the Linux dos emulator versions 0.49 and newer
*
*/
#define LPT_C 1
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include "emu.h"
#include "bios.h"
#include "port.h"
#include "timers.h"
#include "lpt.h"
#include "utilities.h"
#include "dos2linux.h"
/* status bits, Centronics */
#define CTS_STAT_NOIOERR LPT_STAT_NOIOERR
#define CTS_STAT_ONLINE LPT_STAT_ONLINE
#define CTS_STAT_NOPAPER LPT_STAT_NOPAPER
#define CTS_STAT_NOT_ACKing LPT_STAT_NOT_ACK
#define CTS_STAT_BUSY LPT_STAT_NOT_BUSY
/* control bits, Centronics */
#define CTS_CTRL_NOT_SELECT LPT_CTRL_SELECT
#define CTS_CTRL_NOT_INIT LPT_CTRL_NOT_INIT
#define CTS_CTRL_NOT_AUTOLF LPT_CTRL_AUTOLF
#define CTS_CTRL_NOT_STROBE LPT_CTRL_STROBE
/* inversion masks to convert LPT<-->Centronics */
#define LPT_STAT_INV_MASK (CTS_STAT_BUSY)
#define LPT_CTRL_INV_MASK (CTS_CTRL_NOT_STROBE | CTS_CTRL_NOT_AUTOLF | \
CTS_CTRL_NOT_SELECT)
#define DEFAULT_STAT (CTS_STAT_ONLINE | CTS_STAT_NOIOERR | \
CTS_STAT_NOT_ACKing | LPT_STAT_NOT_IRQ)
#define DEFAULT_CTRL (CTS_CTRL_NOT_INIT | CTS_CTRL_NOT_AUTOLF | \
CTS_CTRL_NOT_STROBE)
#define NUM_PRINTERS 9
static struct printer lpt[NUM_PRINTERS] =
{
{NULL, NULL, 5, 0x378, .control = DEFAULT_CTRL, .status = DEFAULT_STAT},
{NULL, NULL, 5, 0x278, .control = DEFAULT_CTRL, .status = DEFAULT_STAT},
{NULL, NULL, 10, 0x3bc, .control = DEFAULT_CTRL, .status = DEFAULT_STAT}
};
ioport_t get_lpt_base(int lptnum)
{
if (lptnum >= NUM_LPTS)
return -1;
return lpt[lptnum].base_port;
}
static int get_printer(ioport_t port)
{
int i;
for (i = 0; i < NUM_LPTS; i++)
if (lpt[i].base_port <= port && port <= lpt[i].base_port + 2)
return i;
return -1;
}
static Bit8u printer_io_read(ioport_t port)
{
int i = get_printer(port);
Bit8u val;
if (i == -1)
return 0xff;
switch (port - lpt[i].base_port) {
case 0:
val = lpt[i].data; /* simple unidirectional port */
if (debug_level('p') >= 5)
p_printf("LPT%d: Reading data byte %#x\n", i+1, val);
break;
case 1: /* status port, r/o */
val = lpt[i].status ^ LPT_STAT_INV_MASK;
/* we should really set ACK after 5 us but here we just
use the fact that the BIOS only checks this once */
lpt[i].status |= CTS_STAT_NOT_ACKing | LPT_STAT_NOT_IRQ;
lpt[i].status &= ~CTS_STAT_BUSY;
if (debug_level('p') >= 5)
p_printf("LPT%d: Reading status byte %#x\n", i+1, val);
break;
case 2:
val = lpt[i].control ^ LPT_CTRL_INV_MASK;
if (debug_level('p') >= 5)
p_printf("LPT%d: Reading control byte %#x\n", i+1, val);
break;
default:
val = 0xff;
break;
}
return val;
}
static void printer_io_write(ioport_t port, Bit8u value)
{
int i = get_printer(port);
if (i == -1)
return;
switch (port - lpt[i].base_port) {
case 0:
if (debug_level('p') >= 5)
p_printf("LPT%d: Writing data byte %#x\n", i+1, value);
lpt[i].data = value;
break;
case 1: /* status port, r/o */
break;
case 2:
if (debug_level('p') >= 5)
p_printf("LPT%d: Writing control byte %#x\n", i+1, value);
value ^= LPT_CTRL_INV_MASK; // convert to Centronics
if (((lpt[i].control & (CTS_CTRL_NOT_STROBE | CTS_CTRL_NOT_SELECT)) == 0)
&& (value & CTS_CTRL_NOT_STROBE)) {
/* STROBE rising */
if (debug_level('p') >= 9)
p_printf("LPT%d: STROBE, sending %#x (%c)\n", i+1, lpt[i].data,
lpt[i].data);
printer_write(i, lpt[i].data);
lpt[i].status &= ~CTS_STAT_NOT_ACKing;
lpt[i].status |= CTS_STAT_BUSY;
}
lpt[i].control = value;
break;
}
}
static int dev_printer_open(int prnum)
{
int um = umask(026);
lpt[prnum].dev_fd = open(lpt[prnum].dev, O_WRONLY);
umask(um);
if (lpt[prnum].dev_fd == -1) {
error("LPT%i: error opening %s: %s\n", prnum+1, lpt[prnum].dev,
strerror(errno));
return -1;
}
p_printf("LPT: opened printer %d to %s\n", prnum, lpt[prnum].dev);
return 0;
}
static void pipe_callback(void *arg)
{
char buf[1024];
int num = (long)arg;
int n = read(lpt[num].file.from_child, buf, sizeof(buf));
if (n > 0) {
buf[n] = 0;
error("LPT%i: %s\n", num+1, buf);
}
}
static int pipe_printer_open(int prnum)
{
int err;
err = popen2(lpt[prnum].prtcmd, &lpt[prnum].file);
if (err) {
error("system(\"%s\") in lpt.c failed, cannot print! "
"Command returned error %s\n", lpt[prnum].prtcmd, strerror(errno));
return err;
}
p_printf("LPT: doing printer command ..%s..\n", lpt[prnum].prtcmd);
add_to_io_select(lpt[prnum].file.from_child, pipe_callback, (void *)(long)prnum);
return err;
}
int printer_open(int prnum)
{
int rc;
if (!lpt[prnum].initialized)
return -1;
if (lpt[prnum].opened) {
dosemu_error("opening printer %i twice\n", prnum);
return 0;
}
rc = lpt[prnum].fops.open(prnum);
if (!rc)
lpt[prnum].opened = 1;
else
error("Error opening printer %i\n", prnum);
return rc;
}
static int dev_printer_close(int prnum)
{
return close(lpt[prnum].dev_fd);
}
static int pipe_printer_close(int prnum)
{
remove_from_io_select(lpt[prnum].file.from_child);
return pclose2(&lpt[prnum].file);
}
int printer_close(int prnum)
{
if (lpt[prnum].opened && lpt[prnum].fops.close) {
p_printf("LPT%i: closing printer\n", prnum+1);
lpt[prnum].fops.close(prnum);
lpt[prnum].remaining = 0;
}
lpt[prnum].opened = 0;
return 0;
}
static int dev_printer_write(int prnum, Bit8u outchar)
{
return write(lpt[prnum].dev_fd, &outchar, 1);
}
static int pipe_printer_write(int prnum, Bit8u outchar)
{
return write(lpt[prnum].file.to_child, &outchar, 1);
}
int printer_write(int prnum, Bit8u outchar)
{
if (!lpt[prnum].initialized)
return -1;
if (!lpt[prnum].opened)
printer_open(prnum);
lpt[prnum].remaining = lpt[prnum].delay;
if (debug_level('p') >= 9)
p_printf("LPT%d: writing %#x (%c)\n", prnum+1, outchar, outchar);
return lpt[prnum].fops.write(prnum, outchar);
}
/* DANG_BEGIN_FUNCTION printer_init
*
* description:
* Initialize printer control structures
*
* DANG_END_FUNCTIONS
*/
static struct p_fops dev_pfops =
{
dev_printer_open,
dev_printer_write,
dev_printer_close,
};
static struct p_fops pipe_pfops =
{
pipe_printer_open,
pipe_printer_write,
pipe_printer_close,
};
void
printer_init(void)
{
int i;
emu_iodev_t io_device;
io_device.read_portb = printer_io_read;
io_device.write_portb = printer_io_write;
io_device.read_portw = NULL;
io_device.write_portw = NULL;
io_device.read_portd = NULL;
io_device.write_portd = NULL;
io_device.handler_name = "Parallel printer";
io_device.irq = EMU_NO_IRQ;
io_device.fd = -1;
for (i = 0; i < NUM_PRINTERS; i++) {
lpt[i].initialized = 0;
lpt[i].opened = 0;
lpt[i].remaining = 0; /* mark not accessed yet */
if (!lpt[i].dev && !lpt[i].prtcmd)
continue;
p_printf("LPT%i: initializing printer %s\n", i+1,
lpt[i].dev ? lpt[i].dev : lpt[i].prtcmd);
if (lpt[i].dev)
lpt[i].fops = dev_pfops;
else if (lpt[i].prtcmd)
lpt[i].fops = pipe_pfops;
if (i >= _min(config.num_lpt, NUM_LPTS)) lpt[i].base_port = 0;
if (lpt[i].base_port != 0) {
io_device.start_addr = lpt[i].base_port;
io_device.end_addr = lpt[i].base_port + 2;
port_register_handler(io_device, 0);
}
lpt[i].initialized = 1;
}
}
void
close_all_printers(void)
{
int loop;
for (loop = 0; loop < NUM_PRINTERS; loop++) {
if (!lpt[loop].opened)
continue;
p_printf("LPT: closing printer %d (%s)\n", loop,
lpt[loop].dev ? lpt[loop].dev : lpt[loop].prtcmd);
printer_close(loop);
}
}
int
printer_tick(u_long secno)
{
int i;
for (i = 0; i < NUM_PRINTERS; i++) {
if (lpt[i].remaining > 0) {
if (debug_level('p') >= 9)
p_printf("LPT%i: doing tick %d\n", i+1, lpt[i].remaining);
if (lpt[i].remaining) {
reset_idle(2);
lpt[i].remaining--;
if (!lpt[i].remaining)
printer_close(i);
}
}
}
return 0;
}
void printer_config(int prnum, struct printer *pptr)
{
struct printer *destptr;
if (prnum < NUM_PRINTERS) {
destptr = &lpt[prnum];
destptr->prtcmd = pptr->prtcmd;
destptr->dev = pptr->dev;
destptr->delay = pptr->delay;
}
}
void printer_print_config(int prnum, void (*print)(const char *, ...))
{
struct printer *pptr = &lpt[prnum];
(*print)("LPT%d command \"%s\" timeout %d device \"%s\" baseport 0x%03x\n",
prnum+1, (pptr->prtcmd ? pptr->prtcmd : ""), pptr->delay,
(pptr->dev ? pptr->dev : ""), pptr->base_port);
}
int lpt_get_max(void)
{
return NUM_PRINTERS;
}
int lpt_is_configured(int num)
{
return lpt[num].initialized;
}