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