217 lines
6.7 KiB
C
217 lines
6.7 KiB
C
// lpt.c - Parallel port support for KPCOMM.DRV
|
|
//
|
|
// The stock COMM.DRV also serves LPT1-LPT3 (cid 0x80-0x82), and Windows
|
|
// routes direct-to-port printing through it. Output is polled through
|
|
// BIOS INT 17h, which Windows reflects to the real-mode BIOS in both
|
|
// standard and enhanced mode. Printers have no input, events, or line
|
|
// settings; those calls succeed without doing anything.
|
|
|
|
#include "commdrv.h"
|
|
|
|
#define BIOS_PRINTER_INT 0x17
|
|
#define PRN_WRITE 0x00 // AH: print the character in AL
|
|
#define PRN_INIT 0x01 // AH: initialize (reset) the printer
|
|
#define PRN_TIMEOUT 0x01 // Status: timed out
|
|
#define PRN_IO_ERROR 0x08 // Status: I/O error
|
|
#define PRN_SELECTED 0x10 // Status: printer selected (online)
|
|
#define PRN_OUT_OF_PAPER 0x20 // Status: out of paper
|
|
#define PRN_FAILED (PRN_TIMEOUT | PRN_IO_ERROR | PRN_OUT_OF_PAPER)
|
|
#define LPT1_IRQ 7 // Conventional IRQs reported by GETBASEIRQ
|
|
#define LPTN_IRQ 5
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Prototypes (public functions are declared in commdrv.h)
|
|
// -----------------------------------------------------------------------
|
|
static uint8_t biosPrinter(uint8_t func, uint8_t data, uint16_t index);
|
|
static uint16_t lptBase(uint16_t index);
|
|
static uint16_t lptErrors(uint8_t status);
|
|
|
|
static LptStateT lpts[MAX_LPTS];
|
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
// biosPrinter - Call BIOS INT 17h; returns the printer status byte
|
|
// -----------------------------------------------------------------------
|
|
static uint8_t biosPrinter(uint8_t func, uint8_t data, uint16_t index) {
|
|
uint8_t status;
|
|
|
|
_asm {
|
|
mov ah, func
|
|
mov al, data
|
|
mov dx, index
|
|
int BIOS_PRINTER_INT
|
|
mov status, ah
|
|
}
|
|
return status;
|
|
}
|
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
// getOpenLpt - Parallel port state for an open LPT cid, or NULL
|
|
// -----------------------------------------------------------------------
|
|
LptStateT *getOpenLpt(int16_t commId) {
|
|
LptStateT *lpt;
|
|
|
|
if (!isLptId(commId)) {
|
|
return NULL;
|
|
}
|
|
lpt = &lpts[commId & LPT_INDEX_MASK];
|
|
return lpt->isOpen ? lpt : NULL;
|
|
}
|
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
// isLptId - True if commId names LPT1-LPT3
|
|
// -----------------------------------------------------------------------
|
|
bool isLptId(int16_t commId) {
|
|
return ((uint16_t)commId & ~LPT_INDEX_MASK) == LPT_ID_FLAG && ((uint16_t)commId & LPT_INDEX_MASK) < MAX_LPTS;
|
|
}
|
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
// lptBase - I/O address of a parallel port from the BIOS (0 = none)
|
|
// -----------------------------------------------------------------------
|
|
static uint16_t lptBase(uint16_t index) {
|
|
return readBiosWord(BDA_LPT_BASES + index * sizeof(uint16_t));
|
|
}
|
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
// lptBaseIrq - GETBASEIRQ for a parallel port
|
|
// -----------------------------------------------------------------------
|
|
int32_t lptBaseIrq(int16_t commId) {
|
|
uint16_t index;
|
|
uint16_t base;
|
|
|
|
if (!isLptId(commId)) {
|
|
return BASEIRQ_NO_PORT;
|
|
}
|
|
|
|
index = commId & LPT_INDEX_MASK;
|
|
base = lptBase(index);
|
|
if (base == 0) {
|
|
return BASEIRQ_NO_PORT;
|
|
}
|
|
return MAKELONG(base, (index == 0) ? LPT1_IRQ : LPTN_IRQ);
|
|
}
|
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
// lptClose - Close a parallel port (trmcom); CE_MODE if it was not open
|
|
// -----------------------------------------------------------------------
|
|
int16_t lptClose(int16_t commId) {
|
|
LptStateT *lpt;
|
|
|
|
lpt = getOpenLpt(commId);
|
|
if (!lpt) {
|
|
return (int16_t)CE_MODE;
|
|
}
|
|
lpt->isOpen = false;
|
|
return 0;
|
|
}
|
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
// lptCloseAll - Close every parallel port (WEP)
|
|
// -----------------------------------------------------------------------
|
|
void lptCloseAll(void) {
|
|
uint16_t i;
|
|
|
|
for (i = 0; i < MAX_LPTS; i++) {
|
|
lpts[i].isOpen = false;
|
|
}
|
|
}
|
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
// lptErrors - CE_* flags for a failing printer status
|
|
// -----------------------------------------------------------------------
|
|
static uint16_t lptErrors(uint8_t status) {
|
|
uint16_t errors;
|
|
|
|
errors = 0;
|
|
if (status & PRN_TIMEOUT) {
|
|
errors |= CE_PTO;
|
|
}
|
|
if (status & PRN_IO_ERROR) {
|
|
errors |= CE_IOE;
|
|
}
|
|
if (!(status & PRN_SELECTED)) {
|
|
errors |= CE_DNS;
|
|
}
|
|
if (status & PRN_OUT_OF_PAPER) {
|
|
errors |= CE_OOP;
|
|
}
|
|
return errors;
|
|
}
|
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
// lptMaxId - GETMAXLPT: highest LPT cid the BIOS reports (LPT1 if none)
|
|
// -----------------------------------------------------------------------
|
|
int16_t lptMaxId(void) {
|
|
uint16_t count;
|
|
|
|
count = 0;
|
|
while (count < MAX_LPTS && lptBase(count) != 0) {
|
|
count++;
|
|
}
|
|
return (int16_t)(LPT_ID_FLAG + ((count > 0) ? count - 1 : 0));
|
|
}
|
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
// lptOpen - Open a parallel port (inicom); returns 0 or IE_*
|
|
// -----------------------------------------------------------------------
|
|
int16_t lptOpen(const DCB FAR *dcb) {
|
|
LptStateT *lpt;
|
|
uint16_t index;
|
|
|
|
if (!isLptId(dcb->Id)) {
|
|
return IE_BADID;
|
|
}
|
|
|
|
index = dcb->Id & LPT_INDEX_MASK;
|
|
lpt = &lpts[index];
|
|
if (lpt->isOpen) {
|
|
return IE_OPEN;
|
|
}
|
|
if (lptBase(index) == 0) {
|
|
return IE_HARDWARE;
|
|
}
|
|
|
|
_fmemset(lpt, 0, sizeof(LptStateT));
|
|
_fmemcpy(&lpt->dcb, dcb, sizeof(DCB));
|
|
lpt->isOpen = true;
|
|
return 0;
|
|
}
|
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
// lptReset - Pulse the printer's reset line (RESETDEV)
|
|
// -----------------------------------------------------------------------
|
|
void lptReset(LptStateT *lpt) {
|
|
(void)biosPrinter(PRN_INIT, 0, (uint16_t)(lpt - lpts));
|
|
}
|
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
// lptWrite - Print up to len bytes; returns the number accepted
|
|
//
|
|
// Stops at the first failure and records it for stacom.
|
|
// -----------------------------------------------------------------------
|
|
int16_t lptWrite(LptStateT *lpt, const uint8_t FAR *buf, int16_t len) {
|
|
uint16_t index;
|
|
int16_t i;
|
|
uint8_t status;
|
|
|
|
index = (uint16_t)(lpt - lpts);
|
|
for (i = 0; i < len; i++) {
|
|
status = biosPrinter(PRN_WRITE, buf[i], index);
|
|
if (status & PRN_FAILED) {
|
|
lpt->errorFlags |= lptErrors(status);
|
|
break;
|
|
}
|
|
}
|
|
return i;
|
|
}
|