// 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; }