Annotation of previous_trunk/src/printer.c, revision 1.1

1.1     ! root        1: /*  Previous - printer.c
        !             2:  
        !             3:  This file is distributed under the GNU Public License, version 2 or at
        !             4:  your option any later version. Read the file gpl.txt for details.
        !             5:  
        !             6:  NeXT Laser Printer emulation.
        !             7:  
        !             8:  */
        !             9: 
        !            10: #include "ioMem.h"
        !            11: #include "ioMemTables.h"
        !            12: #include "m68000.h"
        !            13: #include "configuration.h"
        !            14: #include "printer.h"
        !            15: #include "sysReg.h"
        !            16: #include "dma.h"
        !            17: #include "statusbar.h"
        !            18: #include "file.h"
        !            19: 
        !            20: #if HAVE_LIBPNG
        !            21: #include <png.h>
        !            22: #endif
        !            23: 
        !            24: #define IO_SEG_MASK 0x1FFFF
        !            25: 
        !            26: #define LOG_LP_REG_LEVEL    LOG_DEBUG
        !            27: #define LOG_LP_LEVEL        LOG_DEBUG
        !            28: 
        !            29: 
        !            30: struct {
        !            31:     /* Registers */
        !            32:     struct {
        !            33:         Uint8 dma;
        !            34:         Uint8 printer;
        !            35:         Uint8 interface;
        !            36:         Uint8 cmd;
        !            37:     } csr;
        !            38:     Uint32 data;
        !            39:     
        !            40:     /* Internal */
        !            41:     Uint8 stat;
        !            42:     Uint8 statmask;
        !            43:     Uint32 margins;
        !            44: } nlp;
        !            45: 
        !            46: void lp_power_on(void);
        !            47: void lp_power_off(void);
        !            48: void lp_set_interrupt(void);
        !            49: void lp_release_interrupt(void);
        !            50: Uint32 lp_data_read(void);
        !            51: void lp_boot_message(void);
        !            52: void lp_interface_command(Uint8 cmd, Uint32 data);
        !            53: void lp_interface_status(Uint8 stat, bool set);
        !            54: void lp_gpo_access(Uint8 data);
        !            55: void lp_printer_reset(void);
        !            56: 
        !            57: void lp_png_setup(Uint32 data);
        !            58: void lp_png_print(void);
        !            59: void lp_png_finish(void);
        !            60: 
        !            61: bool lp_data_transfer = false;
        !            62: 
        !            63: /* Laser Printer control and status register (0x0200F000)
        !            64:  *
        !            65:  * x--- ---- ---- ---- ---- ---- ---- ----  dma out enable (r/w)
        !            66:  * -x-- ---- ---- ---- ---- ---- ---- ----  dma out request (r)
        !            67:  * --x- ---- ---- ---- ---- ---- ---- ----  dma out underrun detected (r/w)
        !            68:  * ---- x--- ---- ---- ---- ---- ---- ----  dma in enable (r/w)
        !            69:  * ---- -x-- ---- ---- ---- ---- ---- ----  dma in request (r)
        !            70:  * ---- --x- ---- ---- ---- ---- ---- ----  dma in overrun detected (r/w)
        !            71:  * ---- ---x ---- ---- ---- ---- ---- ----  increment buffer read pointer (r/w)
        !            72:  *
        !            73:  * ---- ---- x--- ---- ---- ---- ---- ----  printer on/off (r/w)
        !            74:  * ---- ---- -x-- ---- ---- ---- ---- ----  behave like monitor interface (r/w)
        !            75:  * ---- ---- ---- x--- ---- ---- ---- ----  printer interrupt (r)
        !            76:  * ---- ---- ---- -x-- ---- ---- ---- ----  printer data available (r)
        !            77:  * ---- ---- ---- --x- ---- ---- ---- ----  printer data overrun (r/w)
        !            78:  *
        !            79:  * ---- ---- ---- ---- x--- ---- ---- ----  dma out transmit pending (r)
        !            80:  * ---- ---- ---- ---- -x-- ---- ---- ----  dma out transmit in progress (r)
        !            81:  * ---- ---- ---- ---- --x- ---- ---- ----  cpu data transmit pending (r)
        !            82:  * ---- ---- ---- ---- ---x ---- ---- ----  cpu data transmit in progress (r)
        !            83:  * ---- ---- ---- ---- ---- --x- ---- ----  printer interface enable (return from reset state) (r/w)
        !            84:  * ---- ---- ---- ---- ---- ---x ---- ----  loop back transmitter data (r/w)
        !            85:  *
        !            86:  * ---- ---- ---- ---- ---- ---- xxxx xxxx  command to append on printer data (r/w)
        !            87:  *
        !            88:  * ---x ---- --xx ---x ---- xx-- ---- ----  zero bits
        !            89:  */
        !            90: 
        !            91: #define LP_DMA_OUT_EN   0x80
        !            92: #define LP_DMA_OUT_REQ  0x40
        !            93: #define LP_DMA_OUT_UNDR 0x20
        !            94: #define LP_DMA_IN_EN    0x08
        !            95: #define LP_DMA_IN_REQ   0x04
        !            96: #define LP_DMA_IN_OVR   0x02
        !            97: #define LP_DMA_INCR     0x01
        !            98: 
        !            99: #define LP_ON           0x80
        !           100: #define LP_NDI          0x40
        !           101: #define LP_INT          0x08
        !           102: #define LP_DATA         0x04
        !           103: #define LP_DATA_OVR     0x02
        !           104: 
        !           105: #define LP_TX_DMA_PEND  0x80
        !           106: #define LP_TX_DMA       0x40
        !           107: #define LP_TX_CPU_PEND  0x20
        !           108: #define LP_TX_CPU       0x10
        !           109: #define LP_TX_EN        0x02
        !           110: #define LP_TX_LOOP      0x01
        !           111: 
        !           112: 
        !           113: void LP_CSR0_Read(void) { // 0x0200F000
        !           114:     IoMem[IoAccessCurrentAddress & IO_SEG_MASK] = nlp.csr.dma;
        !           115:     Log_Printf(LOG_LP_REG_LEVEL,"[LP] CSR0 read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc());
        !           116: }
        !           117: 
        !           118: void LP_CSR0_Write(void) {
        !           119:     Uint8 val = IoMem[IoAccessCurrentAddress & IO_SEG_MASK];
        !           120:     Log_Printf(LOG_LP_REG_LEVEL,"[LP] CSR0 write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc());
        !           121:     
        !           122:     if (val&LP_DMA_OUT_UNDR) {
        !           123:         nlp.csr.dma &= ~(LP_DMA_OUT_UNDR|LP_DMA_OUT_REQ);
        !           124:         lp_release_interrupt();
        !           125:     }
        !           126:     if (val&LP_DMA_IN_OVR) {
        !           127:         nlp.csr.dma &= ~(LP_DMA_IN_OVR|LP_DMA_IN_REQ);
        !           128:         lp_release_interrupt();
        !           129:     }
        !           130: }
        !           131: 
        !           132: void LP_CSR1_Read(void) { // 0x0200F001
        !           133:     IoMem[IoAccessCurrentAddress & IO_SEG_MASK] = nlp.csr.printer;
        !           134:     Log_Printf(LOG_LP_REG_LEVEL,"[LP] CSR1 read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc());
        !           135: }
        !           136: 
        !           137: void LP_CSR1_Write(void) {
        !           138:     Uint8 val = IoMem[IoAccessCurrentAddress & IO_SEG_MASK];
        !           139:     Log_Printf(LOG_LP_REG_LEVEL,"[LP] CSR1 write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc());
        !           140:     
        !           141:     if (((val&LP_ON) != (nlp.csr.printer&LP_ON)) && ConfigureParams.Printer.bPrinterConnected) {
        !           142:         if (val&LP_ON) {
        !           143:             Statusbar_AddMessage("Switching Laser Printer ON.", 0);
        !           144:             lp_power_on();
        !           145:         } else {
        !           146:             Statusbar_AddMessage("Switching Laser Printer OFF.", 0);
        !           147:             lp_power_off();
        !           148:         }
        !           149:     }
        !           150:     nlp.csr.printer = val;
        !           151:     
        !           152:     if (val&LP_DATA_OVR) {
        !           153:         nlp.csr.printer &= ~(LP_DATA_OVR|LP_DATA);
        !           154:         lp_release_interrupt();
        !           155:     }
        !           156: }
        !           157: 
        !           158: void LP_CSR2_Read(void) { // 0x0200F002
        !           159:     IoMem[IoAccessCurrentAddress & IO_SEG_MASK] = nlp.csr.interface;
        !           160:     Log_Printf(LOG_LP_REG_LEVEL,"[LP] CSR2 read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc());
        !           161: }
        !           162: 
        !           163: void LP_CSR2_Write(void) {
        !           164:     Uint8 val = IoMem[IoAccessCurrentAddress & IO_SEG_MASK];
        !           165:     Log_Printf(LOG_LP_REG_LEVEL,"[LP] CSR2 write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc());
        !           166:     
        !           167:     if ((val&LP_TX_EN) != (nlp.csr.interface&LP_TX_EN)) {
        !           168:         if (val&LP_TX_EN) {
        !           169:             Log_Printf(LOG_LP_LEVEL,"[LP] Enable serial interface.");
        !           170:             if (ConfigureParams.Printer.bPrinterConnected) {
        !           171:                 lp_boot_message();
        !           172:             }
        !           173:         } else {
        !           174:             Log_Printf(LOG_LP_LEVEL,"[LP] Disable serial interface.");
        !           175:         }
        !           176:     }
        !           177:     nlp.csr.interface = val;
        !           178: }
        !           179: 
        !           180: void LP_CSR3_Read(void) { // 0x0200F003
        !           181:     IoMem[IoAccessCurrentAddress & IO_SEG_MASK] = nlp.csr.cmd;
        !           182:     Log_Printf(LOG_LP_REG_LEVEL,"[LP] CSR3 read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc());
        !           183: }
        !           184: 
        !           185: void LP_CSR3_Write(void) {
        !           186:     nlp.csr.cmd=IoMem[IoAccessCurrentAddress & IO_SEG_MASK];
        !           187:     Log_Printf(LOG_LP_REG_LEVEL,"[LP] CSR3 write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc());
        !           188: }
        !           189: 
        !           190: void LP_Data_Read(void) { // 0x0200F004 (access must be 32-bit)
        !           191:     nlp.data = lp_data_read();
        !           192:     IoMem_WriteLong(IoAccessCurrentAddress&IO_SEG_MASK, nlp.data);
        !           193:     Log_Printf(LOG_LP_REG_LEVEL,"[LP] Data read at $%08x val=$%08x PC=$%08x\n", IoAccessCurrentAddress, nlp.data, m68k_getpc());
        !           194: }
        !           195: 
        !           196: void LP_Data_Write(void) {
        !           197:     nlp.data = IoMem_ReadLong(IoAccessCurrentAddress&IO_SEG_MASK);
        !           198:     Log_Printf(LOG_LP_REG_LEVEL,"[LP] Data write at $%08x val=$%08x PC=$%08x\n", IoAccessCurrentAddress, nlp.data, m68k_getpc());
        !           199: 
        !           200:     if (ConfigureParams.Printer.bPrinterConnected) {
        !           201:         lp_interface_command(nlp.csr.cmd, nlp.data);
        !           202:     }
        !           203: }
        !           204: 
        !           205: 
        !           206: /* Printer interrupt functions */
        !           207: void lp_set_interrupt(void) {
        !           208:     nlp.csr.printer |= LP_INT;
        !           209:     set_interrupt(INT_PRINTER, SET_INT);
        !           210: }
        !           211: 
        !           212: void lp_release_interrupt(void) {
        !           213:     if ((nlp.csr.printer&(LP_DATA|LP_DATA_OVR)) || (nlp.csr.dma&(LP_DMA_OUT_UNDR|LP_DMA_IN_OVR))) {
        !           214:         return;
        !           215:     }
        !           216:     nlp.csr.printer &= ~LP_INT;
        !           217:     set_interrupt(INT_PRINTER, RELEASE_INT);
        !           218: }
        !           219: 
        !           220: 
        !           221: /* Commands from CPU to Printer */
        !           222: #define LP_CMD_RESET    0xff
        !           223: #define LP_CMD_DATA_OUT 0xc7
        !           224: #define LP_CMD_GPO      0xc4
        !           225: #define LP_CMD_GPI_MASK 0xc5
        !           226: #define LP_CMD_GPI_REQ  0x04
        !           227: #define LP_CMD_MARGINS  0xc2
        !           228: 
        !           229: #define LP_CMD_MASK     0xc7
        !           230: #define LP_CMD_NODATA   0x07
        !           231: #define LP_CMD_DATA_EN  0x08
        !           232: #define LP_CMD_300DPI   0x10
        !           233: #define LP_CMD_NORMAL   0x20
        !           234: 
        !           235: /* Responses from Printer to CPU */
        !           236: #define LP_RES_DATA_IN  0xc7
        !           237: #define LP_RES_GPI      0xc4
        !           238: #define LP_RES_COPY     0xe7
        !           239: #define LP_RES_DATA_REQ 0x07
        !           240: #define LP_RES_UNDERRUN 0x0f
        !           241: 
        !           242: 
        !           243: /* Data for commands */
        !           244: #define LP_GPI_PWR_RDY  0x10
        !           245: #define LP_GPI_RDY      0x08
        !           246: #define LP_GPI_VSREQ    0x04
        !           247: #define LP_GPI_BUSY     0x02
        !           248: #define LP_GPI_STAT_BIT 0x01
        !           249: 
        !           250: #define LP_GPO_DENSITY  0x40
        !           251: #define LP_GPO_VSYNC    0x20
        !           252: #define LP_GPO_ENABLE   0x10
        !           253: #define LP_GPO_PWR_RDY  0x08
        !           254: #define LP_GPO_CLOCK    0x04
        !           255: #define LP_GPO_CMD_BIT  0x02
        !           256: #define LP_GPO_BUSY     0x01
        !           257: 
        !           258: static void lp_gpo(Uint8 cmd) {
        !           259:     if (cmd&LP_GPO_DENSITY) {
        !           260:         Log_Printf(LOG_LP_LEVEL,"[LP] Printer 300 DPI mode");
        !           261:     }
        !           262:     if (cmd&LP_GPO_VSYNC) {
        !           263:         Log_Printf(LOG_LP_LEVEL,"[LP] Printer VSYNC enable");
        !           264:         lp_interface_status(LP_GPI_VSREQ, false);
        !           265:     }
        !           266:     if (cmd&LP_GPO_ENABLE) {
        !           267:         Log_Printf(LOG_LP_LEVEL,"[LP] Printer enable");
        !           268:         lp_interface_status(LP_GPI_VSREQ, true);
        !           269:     }
        !           270:     if (cmd&LP_GPO_PWR_RDY) {
        !           271:         Log_Printf(LOG_LP_LEVEL,"[LP] Printer controller power ready");
        !           272:     }
        !           273:     if (cmd&LP_GPO_CLOCK) {
        !           274:         Log_Printf(LOG_LP_LEVEL,"[LP] Printer serial data clock");
        !           275:     }
        !           276:     if (cmd&LP_GPO_CMD_BIT) {
        !           277:         Log_Printf(LOG_LP_LEVEL,"[LP] Printer serial data command bits");
        !           278:     }
        !           279:     if (cmd&LP_GPO_BUSY) {
        !           280:         Log_Printf(LOG_LP_LEVEL,"[LP] Printer controller busy");
        !           281:     }
        !           282:     lp_gpo_access(cmd);
        !           283: }
        !           284: 
        !           285: static void lp_gpi(void) {
        !           286:     nlp.data = (~nlp.stat)<<24;
        !           287:     
        !           288:     nlp.csr.cmd = LP_RES_GPI;
        !           289:     
        !           290:     if (nlp.csr.printer&LP_DATA) {
        !           291:         nlp.csr.printer |= LP_DATA_OVR;
        !           292:     } else {
        !           293:         nlp.csr.printer |= LP_DATA;
        !           294:     }
        !           295:     
        !           296:     lp_set_interrupt();
        !           297: }
        !           298: 
        !           299: void lp_interface_status(Uint8 changed_bits, bool set) {
        !           300:     bool lp_gpi_message = false;
        !           301:     
        !           302:     Log_Printf(LOG_LP_LEVEL,"[LP] Interface status: %02X (mask: %02X)",nlp.stat,nlp.statmask);
        !           303: 
        !           304:     if ((changed_bits&nlp.statmask) != (nlp.stat&changed_bits&nlp.statmask)) {
        !           305:         lp_gpi_message = true;
        !           306:     }
        !           307:     
        !           308:     if (set) {
        !           309:         nlp.stat |= changed_bits;
        !           310:     } else {
        !           311:         nlp.stat &= ~changed_bits;
        !           312:     }
        !           313:     
        !           314:     if (lp_gpi_message) {
        !           315:         lp_gpi();
        !           316:     }
        !           317: }
        !           318: 
        !           319: void lp_interface_command(Uint8 cmd, Uint32 data) {
        !           320:     switch (cmd) {
        !           321:         case LP_CMD_RESET:
        !           322:             Log_Printf(LOG_LP_LEVEL,"[LP] Interface command: Reset (%08X)",data);
        !           323:             lp_printer_reset();
        !           324:             lp_boot_message();
        !           325:             break;
        !           326:         case LP_CMD_DATA_OUT:
        !           327:             Log_Printf(LOG_LP_LEVEL,"[LP] Interface command: Data out (%08X)",data);
        !           328:             lp_buffer.data[lp_buffer.size] = (data>>24)&0xFF;
        !           329:             lp_buffer.data[lp_buffer.size+1] = (data>>16)&0xFF;
        !           330:             lp_buffer.data[lp_buffer.size+2] = (data>>8)&0xFF;
        !           331:             lp_buffer.data[lp_buffer.size+3] = data&0xFF;
        !           332:             lp_buffer.size +=4;
        !           333:             break;
        !           334:         case LP_CMD_GPO:
        !           335:             Log_Printf(LOG_LP_LEVEL,"[LP] Interface command: General purpose out (%02X)",(~data)>>24);
        !           336:             lp_gpo((~data)>>24);
        !           337:             break;
        !           338:         case LP_CMD_GPI_MASK:
        !           339:             Log_Printf(LOG_LP_LEVEL,"[LP] Interface command: General purpose input mask (%02X)",(~data)>>24);
        !           340:             nlp.statmask = (~data)>>24;
        !           341:             break;
        !           342:         case LP_CMD_GPI_REQ:
        !           343:             Log_Printf(LOG_LP_LEVEL,"[LP] Interface command: General purpose input request");
        !           344:             lp_gpi();
        !           345:             break;
        !           346:         case LP_CMD_MARGINS:
        !           347:             Log_Printf(LOG_LP_LEVEL,"[LP] Interface command: Margins (%08X)",data);
        !           348:             nlp.margins = data;
        !           349:             break;
        !           350:             
        !           351:         default: /* Commands with no data */
        !           352:             if ((cmd&LP_CMD_MASK)==LP_CMD_NODATA) {
        !           353:                 Log_Printf(LOG_LP_LEVEL,"[LP] Interface command: No data command:");
        !           354: 
        !           355:                 if (cmd&LP_CMD_DATA_EN) {
        !           356:                     Log_Printf(LOG_LP_LEVEL,"[LP] Enable printer data transfer");
        !           357:                     /* Setup printing buffer */
        !           358:                     lp_png_setup(nlp.margins);
        !           359:                     lp_data_transfer = true;
        !           360:                     if (lp_buffer.size) {
        !           361:                         lp_png_print();
        !           362:                         lp_buffer.size = 0;
        !           363:                     }
        !           364:                     Statusbar_AddMessage("Laser Printer Printing Page.", 0);
        !           365:                     CycInt_AddRelativeInterruptUs(1000, 100, INTERRUPT_LP_IO);
        !           366:                 } else {
        !           367:                     Log_Printf(LOG_LP_LEVEL,"[LP] Disable printer data transfer");
        !           368:                     if (lp_data_transfer) {
        !           369:                         /* Save buffered printing data to image file */
        !           370:                         lp_png_finish();
        !           371:                     }
        !           372:                     lp_data_transfer = false;
        !           373:                 }
        !           374:                 if (cmd&LP_CMD_300DPI) {
        !           375:                     Log_Printf(LOG_LP_LEVEL,"[LP] 300 DPI mode");
        !           376:                 } else {
        !           377:                     Log_Printf(LOG_LP_LEVEL,"[LP] 400 DPI mode");
        !           378:                 }
        !           379:                 if (cmd&LP_CMD_NORMAL) {
        !           380:                     Log_Printf(LOG_LP_LEVEL,"[LP] Normal requests for data transfer");
        !           381:                 } else {
        !           382:                     Log_Printf(LOG_LP_LEVEL,"[LP] Early requests for data transfer");
        !           383:                 }
        !           384:             } else {
        !           385:                 Log_Printf(LOG_WARN,"[LP] Interface command: Unknown command!");
        !           386:             }
        !           387:             break;
        !           388:     }
        !           389: }
        !           390: 
        !           391: void lp_power_on(void) {
        !           392:     lp_interface_status(LP_GPI_PWR_RDY|LP_GPI_RDY,true);
        !           393: }
        !           394: 
        !           395: void lp_power_off(void) {
        !           396:     nlp.stat = 0x00;
        !           397: }
        !           398: 
        !           399: /* COPY. NeXT 1987 */
        !           400: Uint32 lp_copyright_message[4] = { 0x00434f50, 0x522e204e, 0x65585420, 0x31393837 };
        !           401: int lp_copyright_sequence = 0;
        !           402: 
        !           403: void lp_boot_message(void) {
        !           404:     lp_copyright_sequence = 4;
        !           405:     
        !           406:     nlp.csr.cmd = LP_RES_COPY;
        !           407:     
        !           408:     nlp.csr.printer |= LP_DATA;
        !           409:     lp_set_interrupt();
        !           410: }
        !           411: 
        !           412: Uint32 lp_data_read(void) {
        !           413:     Uint32 val = 0;
        !           414:     
        !           415:     if (lp_copyright_sequence>0) {
        !           416:         val = lp_copyright_message[4-lp_copyright_sequence];
        !           417:         lp_copyright_sequence--;
        !           418:     } else {
        !           419:         val = nlp.data;
        !           420:     }
        !           421:     
        !           422:     if (lp_copyright_sequence==0) {
        !           423:         nlp.csr.printer &= ~LP_DATA;
        !           424:         lp_release_interrupt();
        !           425:     }
        !           426: 
        !           427:     return val;
        !           428: }
        !           429: 
        !           430: 
        !           431: /* Printer internal command and status via serial interface */
        !           432: #define CMD_STATUS0     0x01
        !           433: #define CMD_STATUS1     0x02
        !           434: #define CMD_STATUS2     0x04
        !           435: #define CMD_STATUS4     0x08
        !           436: #define CMD_STATUS5     0x0b
        !           437: #define CMD_STATUS15    0x1f
        !           438: 
        !           439: #define CMD_EXT_CLK     0x40
        !           440: #define CMD_PRINTER_CLK 0x43
        !           441: #define CMD_PAUSE       0x45
        !           442: #define CMD_UNPAUSE     0x46
        !           443: #define CMD_DRUM_ON     0x49
        !           444: #define CMD_DRUM_OFF    0x4a
        !           445: #define CMD_CASSFEED    0x4c
        !           446: #define CMD_HANDFEED    0x4f
        !           447: #define CMD_RETRANSCANC 0x5d
        !           448: 
        !           449: #define STAT0_PRINTREQ  0x40
        !           450: #define STAT0_PAPERDLVR 0x20
        !           451: #define STAT0_DATARETR  0x10
        !           452: #define STAT0_WAIT      0x08
        !           453: #define STAT0_PAUSE     0x04
        !           454: #define STAT0_CALL      0x02
        !           455: 
        !           456: #define STAT1_NOCART    0x40
        !           457: #define STAT1_NOPAPER   0x10
        !           458: #define STAT1_JAM       0x08
        !           459: #define STAT1_DOOROPEN  0x04
        !           460: #define STAT1_TESTPRINT 0x02
        !           461: 
        !           462: #define STAT2_FIXINGASM 0x40
        !           463: #define STAT2_POORBDSIG 0x20
        !           464: #define STAT2_SCANMOTOR 0x10
        !           465: 
        !           466: #define STAT5_NOCASS    0x01
        !           467: #define STAT5_A4        0x02
        !           468: #define STAT5_LETTER    0x08
        !           469: #define STAT5_B5        0x13
        !           470: #define STAT5_LEGAL     0x19
        !           471: 
        !           472: #define STAT15_NOTONER  0x04
        !           473: 
        !           474: static Uint8 lp_serial_status[16] = {
        !           475:     0,0,0,0,
        !           476:     0,STAT5_A4,0,0,
        !           477:     0,0,0,0,
        !           478:     0,0,0,0
        !           479: };
        !           480: 
        !           481: static Uint8 lp_serial_phase = 0;
        !           482: 
        !           483: static Uint8 lp_printer_status(Uint8 num) {
        !           484:     int i;
        !           485:     Uint8 val;
        !           486:     
        !           487:     lp_serial_phase = 8;
        !           488:     lp_interface_status(LP_GPI_BUSY, true);
        !           489:     
        !           490:     if (num==5) {
        !           491:         switch (ConfigureParams.Printer.nPaperSize) {
        !           492:             case PAPER_A4: val = STAT5_A4; break;
        !           493:             case PAPER_LETTER: val = STAT5_LETTER; break;
        !           494:             case PAPER_B5: val = STAT5_B5; break;
        !           495:             case PAPER_LEGAL: val = STAT5_LEGAL; break;
        !           496:             default: val = PAPER_A4; break;
        !           497:         }
        !           498:     } else if (num<16) {
        !           499:         val = lp_serial_status[num];
        !           500:     } else {
        !           501:         val = 0x00;
        !           502:     }
        !           503:     
        !           504:     /* odd parity */
        !           505:     val |= 1;
        !           506:     for (i = 1; i < 8; i++) {
        !           507:         if (val & (1 << i)) {
        !           508:             val ^= 1;
        !           509:         }
        !           510:     }
        !           511:     return val;
        !           512: }
        !           513: 
        !           514: void lp_printer_reset(void) {
        !           515:     int i;
        !           516:     for (i = 0; i < 16; i++) {
        !           517:         lp_serial_status[i] = 0;
        !           518:     }
        !           519:     lp_serial_phase = 0;
        !           520: }
        !           521: 
        !           522: static Uint8 lp_printer_command(Uint8 cmd) {
        !           523:     switch (cmd) {
        !           524:         case CMD_STATUS0:
        !           525:             Log_Printf(LOG_LP_LEVEL, "[LP] Read status register 0");
        !           526:             return lp_printer_status(0);
        !           527:         case CMD_STATUS1:
        !           528:             Log_Printf(LOG_LP_LEVEL, "[LP] Read status register 1");
        !           529:             return lp_printer_status(1);
        !           530:         case CMD_STATUS2:
        !           531:             Log_Printf(LOG_LP_LEVEL, "[LP] Read status register 2");
        !           532:             return lp_printer_status(2);
        !           533:         case CMD_STATUS4:
        !           534:             Log_Printf(LOG_LP_LEVEL, "[LP] Read status register 4");
        !           535:             return lp_printer_status(4);
        !           536:         case CMD_STATUS5:
        !           537:             Log_Printf(LOG_LP_LEVEL, "[LP] Read status register 5");
        !           538:             return lp_printer_status(5);
        !           539:         case CMD_STATUS15:
        !           540:             Log_Printf(LOG_LP_LEVEL, "[LP] Read status register 15");
        !           541:             return lp_printer_status(15);
        !           542:         /* Commands with no status */
        !           543:         case CMD_EXT_CLK:
        !           544:             Log_Printf(LOG_LP_LEVEL, "[LP] External clock");
        !           545:             return lp_printer_status(16);
        !           546:         case CMD_PRINTER_CLK:
        !           547:             Log_Printf(LOG_LP_LEVEL, "[LP] Printer clock");
        !           548:             return lp_printer_status(16);
        !           549:         case CMD_PAUSE:
        !           550:             Log_Printf(LOG_LP_LEVEL, "[LP] Pause");
        !           551:             return lp_printer_status(16);
        !           552:         case CMD_UNPAUSE:
        !           553:             Log_Printf(LOG_LP_LEVEL, "[LP] Unpause");
        !           554:             return lp_printer_status(16);
        !           555:         case CMD_DRUM_ON:
        !           556:             Log_Printf(LOG_LP_LEVEL, "[LP] Drum on");
        !           557:             return lp_printer_status(16);
        !           558:         case CMD_DRUM_OFF:
        !           559:             Log_Printf(LOG_LP_LEVEL, "[LP] Drum off");
        !           560:             return lp_printer_status(16);
        !           561:         case CMD_CASSFEED:
        !           562:             Log_Printf(LOG_LP_LEVEL, "[LP] Cassette feed");
        !           563:             return lp_printer_status(16);
        !           564:         case CMD_HANDFEED:
        !           565:             Log_Printf(LOG_LP_LEVEL, "[LP] Hand feed");
        !           566:             return lp_printer_status(16);
        !           567:         case CMD_RETRANSCANC:
        !           568:             Log_Printf(LOG_LP_LEVEL, "[LP] Cancel retransmission");
        !           569:             return lp_printer_status(16);
        !           570: 
        !           571:         default:
        !           572:             Log_Printf(LOG_WARN, "[LP] Unknown command!");
        !           573:             return lp_printer_status(16);
        !           574:     }
        !           575: }
        !           576: 
        !           577: void lp_gpo_access(Uint8 data) {
        !           578:     static Uint8 lp_cmd = 0;
        !           579:     static Uint8 lp_stat = 0;
        !           580:     static Uint8 lp_old_data = 0;
        !           581: 
        !           582:     Log_Printf(LOG_LP_LEVEL, "[LP] Control logic access: %02X",data);
        !           583:     
        !           584:     if ((lp_old_data&LP_GPO_BUSY)!=(data&LP_GPO_BUSY)) {
        !           585:         if (!(data&LP_GPO_BUSY)) {
        !           586:             Log_Printf(LOG_LP_LEVEL, "[LP] Printer command: %02X",lp_cmd);
        !           587:             lp_stat = lp_printer_command(lp_cmd);
        !           588:         } else {
        !           589:             lp_cmd = 0;
        !           590:         }
        !           591:     }
        !           592:     if (data&LP_GPO_BUSY) {
        !           593:         if ((data&LP_GPO_CLOCK) && !(lp_old_data&LP_GPO_CLOCK)) {
        !           594:             lp_cmd <<= 1;
        !           595:             lp_cmd |= (data&LP_GPO_CMD_BIT)?1:0;
        !           596:         }
        !           597:     } else if (nlp.stat&LP_GPI_BUSY) {
        !           598:         if ((data&LP_GPO_CLOCK) && !(lp_old_data&LP_GPO_CLOCK)) {
        !           599:             lp_serial_phase--;
        !           600:             if (lp_serial_phase==0) {
        !           601:                 lp_interface_status(LP_GPI_BUSY, false);
        !           602:                 Log_Printf(LOG_LP_LEVEL, "[LP] Printer status: %02X",lp_stat);
        !           603:             }
        !           604:             lp_interface_status(LP_GPI_STAT_BIT,(lp_stat&(1<<lp_serial_phase))?true:false);
        !           605:         }
        !           606:     }
        !           607:     
        !           608:     lp_old_data = data;
        !           609: }
        !           610: 
        !           611: /* Printer DMA and printing function */
        !           612: void Printer_IO_Handler(void) {
        !           613:     CycInt_AcknowledgeInterrupt();
        !           614:     
        !           615:     if (lp_data_transfer) {
        !           616:         lp_buffer.limit = 4096;
        !           617:         dma_printer_read_memory();
        !           618:         
        !           619:         if (lp_buffer.size==0) {
        !           620:             Log_Printf(LOG_LP_LEVEL,"[LP] Printing done.");
        !           621:             nlp.csr.dma |= LP_DMA_OUT_UNDR;
        !           622:             lp_set_interrupt();
        !           623:             return;
        !           624:         }
        !           625:         /* Save data to printing buffer */
        !           626:         lp_png_print();
        !           627:         
        !           628:         lp_buffer.size = 0;
        !           629:         
        !           630:         CycInt_AddRelativeInterruptUs(10000, 1000, INTERRUPT_LP_IO);
        !           631:     }
        !           632: }
        !           633: 
        !           634: /* Printer reset function */
        !           635: void Printer_Reset(void) {
        !           636:     nlp.csr.dma = 0;
        !           637:     nlp.csr.printer = 0;
        !           638:     nlp.csr.interface = 0;
        !           639:     nlp.csr.cmd = 0;
        !           640:     nlp.data = 0;
        !           641:     nlp.stat = 0;
        !           642:     
        !           643:     lp_data_transfer = false;
        !           644:     
        !           645:     set_interrupt(INT_PRINTER, RELEASE_INT);
        !           646: }
        !           647: 
        !           648: 
        !           649: /* Helper function for building path and filename of output file */
        !           650: static const char *lp_get_filename(void) {
        !           651:     static const char *lp_outfile = NULL;
        !           652:     static char lp_filename[32];
        !           653:     static char lp_extension[16];
        !           654:     static int lp_pagecount = 0;
        !           655:     int lp_duplicate_count = 0;
        !           656:     
        !           657:     if (File_DirExists(ConfigureParams.Printer.szPrintToFileName)) {
        !           658:         sprintf(lp_filename, "%05d_next_printer", lp_pagecount);
        !           659:         
        !           660:         do {
        !           661:             if (lp_duplicate_count) {
        !           662:                 sprintf(lp_extension, "%i.png",lp_duplicate_count);
        !           663:             } else {
        !           664:                 sprintf(lp_extension, ".png");
        !           665:             }
        !           666:             lp_outfile = File_MakePath(ConfigureParams.Printer.szPrintToFileName,
        !           667:                                        lp_filename, lp_extension);
        !           668: 
        !           669:             lp_duplicate_count++;
        !           670:         } while (File_Exists(lp_outfile) && lp_duplicate_count<1000);
        !           671:     }
        !           672:     
        !           673:     if (lp_outfile==NULL) {
        !           674:         lp_outfile = "\0";
        !           675:     }
        !           676:     
        !           677:     lp_pagecount++;
        !           678:     lp_pagecount %= 100000;
        !           679:     
        !           680:     return lp_outfile;
        !           681: }
        !           682: 
        !           683: 
        !           684: /* PNG printing functions */
        !           685: #if HAVE_LIBPNG
        !           686: const int MAX_PAGE_LEN = 400 * 14; // 14 inches is the length of US legal paper, longest paper that fits into the NeXT printer cartridge
        !           687: png_structp png_ptr          = NULL;
        !           688: png_infop   png_info_ptr     = NULL;
        !           689: png_byte**  png_row_pointers = NULL;
        !           690: int         png_width;
        !           691: int         png_height;
        !           692: int         png_count;
        !           693: int         png_page_count   = 0;
        !           694: const char* png_path;
        !           695: #endif
        !           696: 
        !           697: void lp_png_setup(Uint32 data) {
        !           698: #if HAVE_LIBPNG
        !           699:     int i;
        !           700:     png_width = ((data >> 16) & 0x7F) * 32;
        !           701:     
        !           702:     if (png_ptr) {
        !           703:         for (i = 0; i < MAX_PAGE_LEN; i++) {
        !           704:             png_free(png_ptr, png_row_pointers[i]);
        !           705:         }
        !           706:         png_free(png_ptr, png_row_pointers);
        !           707:         png_destroy_write_struct(&png_ptr, &png_info_ptr);
        !           708:     }
        !           709:     
        !           710:     png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
        !           711:     if (png_ptr == NULL) {
        !           712:         return;
        !           713:     }
        !           714:     png_info_ptr = png_create_info_struct(png_ptr);
        !           715:     if (png_info_ptr == NULL) {
        !           716:         png_destroy_write_struct(&png_ptr, &png_info_ptr);
        !           717:         png_ptr = NULL;
        !           718:         return;
        !           719:     }
        !           720:     
        !           721:     png_row_pointers = png_malloc(png_ptr, MAX_PAGE_LEN * sizeof (png_byte *));
        !           722:     for (i = 0; i < MAX_PAGE_LEN; i++) {
        !           723:         png_row_pointers[i] = png_malloc(png_ptr, sizeof (uint8_t) * (png_width / 8));
        !           724:     }
        !           725:     png_count  = 0;
        !           726:     png_height = 0;
        !           727: #endif
        !           728: }
        !           729: 
        !           730: void lp_png_print(void) {
        !           731: #if HAVE_LIBPNG
        !           732:     int i;
        !           733:     
        !           734:     for (i = 0; i < lp_buffer.size; i++) {
        !           735:         png_row_pointers[png_count/png_width][(png_count%png_width)/8] = ~lp_buffer.data[i];
        !           736:         png_count += 8;
        !           737:     }
        !           738: #endif
        !           739: }
        !           740: 
        !           741: void lp_png_finish(void) {
        !           742: #if HAVE_LIBPNG
        !           743:     png_set_IHDR(png_ptr,
        !           744:                  png_info_ptr,
        !           745:                  png_width,
        !           746:                  png_count / png_width,
        !           747:                  1,
        !           748:                  PNG_COLOR_TYPE_GRAY,
        !           749:                  PNG_INTERLACE_NONE,
        !           750:                  PNG_COMPRESSION_TYPE_DEFAULT,
        !           751:                  PNG_FILTER_TYPE_DEFAULT);
        !           752:     
        !           753:     png_path = lp_get_filename();
        !           754:     
        !           755:     FILE* png_fp = File_Open(png_path, "wb");
        !           756:     
        !           757:     if (png_fp) {
        !           758:         png_init_io(png_ptr, png_fp);
        !           759:         png_set_rows(png_ptr, png_info_ptr, png_row_pointers);
        !           760:         png_write_png(png_ptr, png_info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
        !           761:     } else {
        !           762:         Statusbar_AddMessage("Laser Printer Error: Could not create output file!", 10000);
        !           763:     }
        !           764:     
        !           765:     File_Close(png_fp);
        !           766:     png_page_count++;
        !           767: #endif
        !           768: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.