Annotation of previous_trunk/src/printer.c, revision 1.1.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.