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