|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.