/* sage_lp.c: Printer device for sage-II system | |
Copyright (c) 2009, Holger Veit | |
Permission is hereby granted, free of charge, to any person obtaining a | |
copy of this software and associated documentation files (the "Software"), | |
to deal in the Software without restriction, including without limitation | |
the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
and/or sell copies of the Software, and to permit persons to whom the | |
Software is furnished to do so, subject to the following conditions: | |
The above copyright notice and this permission notice shall be included in | |
all copies or substantial portions of the Software. | |
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
Holger Veit BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER | |
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
Except as contained in this notice, the name of Holger Veit et al shall not be | |
used in advertising or otherwise to promote the sale, use or other dealings | |
in this Software without prior written authorization from Holger Veit et al. | |
04-Oct-09 HV Initial version | |
*/ | |
#include "sage_defs.h" | |
#define UNIT_V_OFFLINE (UNIT_V_UF + 0) /* unit offline */ | |
#define UNIT_OFFLINE (1 << UNIT_V_OFFLINE) | |
static t_stat sagelp_reset(DEVICE* dptr); | |
static t_stat sagelp_attach(UNIT *uptr, char *cptr); | |
static t_stat sagelp_detach(UNIT *uptr); | |
static t_stat sagelp_output(UNIT *uptr); | |
static t_stat u39_reset(I8255* chip); | |
static t_stat u39_calla(I8255* chip,int rw); | |
static t_stat u39_callb(I8255* chip,int rw); | |
static t_stat u39_callc(I8255* chip,int rw); | |
static t_stat u39_ckmode(I8255* chip,uint32 data); | |
extern DEVICE sagelp_dev; | |
/* The LP Centronics device in sage is implemented by a 8255 with the following settings: | |
* port A output data | |
* port B input status from printer, and from misc devices | |
* B0 Floppy interrupt flag | |
* B1 Floppy write protect flag | |
* B2 Modem ringing indicator | |
* B3 Modem carrier detect | |
* B4 Printer BUSY flag | |
* B5 Printer PAPER flag | |
* B6 Printer SELECT flag (on/offline) | |
* B7 Printer FAULT flag | |
* port C lower half output control for misc devices | |
* C0 Parity error reset | |
* C1 IEEE enable | |
* C2 Interrupt level 7 | |
* C3 activity LED | |
* port C upper half input status from printers | |
* C4 printer STROBE flag | |
* C5 printer PRIME flag | |
* C6 printer ACK INT clear | |
* C7 modem Ringing/Carrier INT clear (MI) | |
*/ | |
static I8255 u39 = { | |
{ 0,0,U39_ADDR,8,2}, | |
&sagelp_dev, | |
i8255_write,i8255_read,u39_reset,u39_calla,u39_callb,u39_callc,u39_ckmode | |
}; | |
UNIT sagelp_unit = { | |
UDATA (NULL, UNIT_SEQ|UNIT_ATTABLE|UNIT_TEXT, 0), SERIAL_OUT_WAIT | |
}; | |
REG sagelp_reg[] = { | |
{ HRDATA(PORTA, u39.porta, 8) }, | |
{ HRDATA(PORTB, u39.portb, 8) }, | |
{ HRDATA(PORTC, u39.portc, 8) }, | |
{ HRDATA(CTRL, u39.ctrl, 8) }, | |
{ GRDATA (BUF, sagelp_unit.buf, 16, 8, 0) }, | |
{ DRDATA (POS, sagelp_unit.pos, T_ADDR_W), PV_LEFT }, | |
{ NULL } | |
}; | |
static MTAB sagelp_mod[] = { | |
{ MTAB_XTD|MTAB_VDV, 0, "IO", "IO", &set_iobase, &show_iobase, NULL }, | |
{ UNIT_OFFLINE, UNIT_OFFLINE, "offline", "OFFLINE", NULL }, | |
{ UNIT_OFFLINE, 0, "online", "ONLINE", NULL }, | |
{ 0 } | |
}; | |
DEBTAB sagelp_dt[] = { | |
{ "WRA", DBG_PP_WRA }, | |
{ "RDB", DBG_PP_RDB }, | |
{ "RDC", DBG_PP_RDC }, | |
{ "WRC", DBG_PP_WRC }, | |
{ "WRMODE", DBG_PP_MODE }, | |
{ NULL, 0 } | |
}; | |
DEVICE sagelp_dev = { | |
"LP", &sagelp_unit, sagelp_reg, sagelp_mod, | |
1, 16, 32, 2, 16, 16, | |
NULL, NULL, &sagelp_reset, | |
NULL, &sagelp_attach, &sagelp_detach, | |
&u39, (DEV_DISABLE|DEV_DEBUG), 0, | |
sagelp_dt, NULL, NULL | |
}; | |
t_stat sagelp_reset(DEVICE* dptr) | |
{ | |
t_stat rc; | |
if ((rc = (dptr->flags & DEV_DIS) ? /* Disconnect I/O Ports */ | |
del_iohandler(dptr->ctxt) : | |
add_iohandler(&sagelp_unit,dptr->ctxt,i8255_io)) != SCPE_OK) return rc; | |
return u39.reset(&u39); | |
} | |
/* we don't accept any mode and combination that a 8255 can do, because | |
* u39 is hardwired to porta=output, portb=input and portc=output | |
*/ | |
static t_stat u39_calla(I8255* chip, int rw) | |
{ | |
if (rw) { | |
sagelp_unit.buf = chip->porta; | |
TRACE_PRINT1(DBG_PP_WRA,"WR PortA = 0x%x",chip->porta); | |
} | |
return SCPE_OK; | |
} | |
static t_stat u39_callb(I8255* chip, int rw) | |
{ | |
if (rw==0) { /* only when reading port */ | |
/* propagate FDC Write Protect */ | |
int portb = 0; | |
I8272_DRIVE_INFO* dip = &u21.drive[u21.fdc_curdrv]; | |
if (dip->uptr && (dip->uptr->flags & UNIT_I8272_WLK)) { | |
portb |= U39B_WP; | |
TRACE_PRINT1(DBG_PP_RDB,"RD PortB: WP+=%d",(portb&U39B_WP)?1:0); | |
} | |
/* propagate FDC interrupt */ | |
if (u21.irqflag) { | |
portb |= U39B_FDI; | |
TRACE_PRINT0(DBG_PP_RDB,"RD PortB: FDI+=1"); | |
} else { | |
TRACE_PRINT0(DBG_PP_RDB,"RD PortB: FDI+=0"); | |
} | |
chip->portb = portb; | |
} | |
return SCPE_OK; | |
} | |
static t_stat u39_callc(I8255* chip,int rw) | |
{ | |
if (rw==1) { | |
if (I8255_FALLEDGE(portc,U39C_STROBE)) { | |
sagelp_output(&sagelp_unit); | |
TRACE_PRINT1(DBG_PP_RDC,"RD PortC: STROBE-=%d",chip->portc&U39C_STROBE?1:0); | |
} | |
if (I8255_RISEEDGE(portc,U39C_SI)) { | |
/* printf("rising edge on SI: PC=%x!\n",PCX);*/ | |
TRACE_PRINT1(DBG_PP_RDC,"RD PortC: SI+=%d",chip->portc&U39C_SI?1:0); | |
sage_raiseint(SI_PICINT); | |
} | |
} | |
return SCPE_OK; | |
} | |
static t_stat u39_ckmode(I8255* chip,uint32 data) | |
{ | |
TRACE_PRINT1(DBG_PP_MODE,"WR Mode: 0x%x",data); | |
/* BIOS initializes port A as input, later LP is initialized to output */ | |
if (!(data==0x82 || data==0x92)) { | |
/* hardwired: | |
* d7=1 -- mode set flag | |
* d6=0 -+ group a mode 0: basic I/O | |
* d5=0 -+ | |
* d4=0 -- port a = output / input | |
* d3=0 -- port c upper = output | |
* d2=0 -- group b mode 0: basic I/O | |
* d1=1 -- port b = input | |
* d0=0 -- port c lower = output | |
*/ | |
printf("u39_ckmode: unsupported ctrl=0x%02x\n",data); | |
return STOP_IMPL; | |
} | |
chip->portc = 0; /* reset port */ | |
return SCPE_OK; | |
} | |
static t_stat u39_reset(I8255* chip) | |
{ | |
sagelp_unit.buf = 0; | |
sim_cancel (&sagelp_unit); | |
return SCPE_OK; | |
} | |
static t_stat sagelp_attach (UNIT *uptr, char *cptr) | |
{ | |
t_stat rc; | |
rc = attach_unit(uptr, cptr); | |
if ((sagelp_unit.flags & UNIT_ATT) == 0) | |
u39.portb |= U39B_PAPER; /* no paper */ | |
return rc; | |
} | |
static t_stat sagelp_detach (UNIT *uptr) | |
{ | |
u39.portb |= U39B_PAPER; /* no paper */ | |
return detach_unit (uptr); | |
} | |
static t_stat sagelp_output(UNIT *uptr) | |
{ | |
if ((uptr->flags & UNIT_ATT)==0) { | |
u39.portb |= U39B_PAPER; /* unattached means: no paper */ | |
return SCPE_UNATT; | |
} else if (uptr->flags & UNIT_OFFLINE) { | |
u39.portb &= ~U39B_SEL; /* offline means: SEL = 0 */ | |
return STOP_OFFLINE; | |
} | |
u39.portb &= ~U39B_PAPER; /* has paper */ | |
u39.portb |= U39B_SEL; /* is online */ | |
u39.portb |= U39B_FAULT; /* no fault */ | |
u39.portb &= ~U39B_BUSY; /* not busy */ | |
if ((u39.portc & U39C_STROBE)==0) { /* strobe presented */ | |
fputc (uptr->buf & 0177, uptr->fileref); /* put out char */ | |
if (ferror (uptr->fileref)) { | |
sim_perror ("LP I/O error"); | |
clearerr (uptr->fileref); | |
return SCPE_IOERR; | |
} | |
sagelp_unit.pos = ftell(uptr->fileref); /* update pos */ | |
u39.portc |= U39C_STROBE; /* XXX reset strobe directly */ | |
sage_raiseint(LP_PICINT); | |
return SCPE_OK; | |
} | |
return SCPE_OK; | |
} |