/* * Copyright (C) 2012-2017, The AROS Development Team. All rights reserved. * Author: Jason S. McMullan * * Licensed under the AROS PUBLIC LICENSE (APL) Version 1.1 * * This file handles the creation of the per-unit driver task, * and the creation of the per-unit 'struct PrinterData', * and the pd_PWrite()/pd_PRead() etc IO functions. */ #include #include #include #include #include #include #include #include #include #define TPMATCHWORD 0xf10a57ef /* From turboprint's SDK */ #define CMD_OPENDEVICE (0x100) #define CMD_CLOSEDEVICE (0x101) #include LC_LIBDEFS_FILE #include "printer_intern.h" /* pd_Flags values */ #define PDF_IOREQ (1 << 0) /* IORequest 0 or 1 */ #define PDF_NOIO (1 << 1) /* PRTA_NoIO was true */ #define PDF_CONVERT (1 << 2) /* PRTA_ConvertSource was true */ #define PDF_8BITGUNS (1 << 3) /* PRTA_8BitGuns was true */ const TEXT driverID[] = "printer.driver"; const struct EasyStruct driverMisuse = { \ .es_StructSize = sizeof(struct EasyStruct), .es_Flags = 0, .es_Title = "Improper use of printer.device", .es_TextFormat = "\"%s\" attempted to use the private\n" "printer.driver method %s.\n" "Only CMD_RAWWRITE is supported.\n", .es_GadgetFormat = "Ok", }; /* Internal, private message */ struct PrinterMessage { struct Message mm_Message; ULONG mm_Magic; ULONG mm_Version; }; #define TASK_PRINTERDATA(pd) \ struct PrinterData *pd =(struct PrinterData *)FindTask(NULL)->tc_UserData; \ if (pd == NULL || \ pd->pd_Device.dd_Device.lib_Node.ln_Type != NT_DEVICE || \ pd->pd_Device.dd_Device.lib_IdString != driverID) { \ struct Library *IntuitionBase; \ if ((IntuitionBase = TaggedOpenLibrary(TAGGEDOPEN_INTUITION))) {\ CONST_STRPTR args[] = { FindTask(NULL)->tc_Node.ln_Name, \ __func__ }; \ EasyRequestArgs(NULL, (struct EasyStruct *)&driverMisuse, \ 0, (RAWARG)&args[0]); \ CloseLibrary(IntuitionBase); \ } \ return IOERR_NOCMD; \ } static BOOL initMsgPort(struct MsgPort *port) { BYTE sb = AllocSignal(-1); if (sb < 0) return FALSE; memset( port, 0, sizeof( *port ) ); port->mp_SigBit = sb; port->mp_SigTask = FindTask(NULL); port->mp_Flags = PA_SIGNAL; port->mp_Node.ln_Type = NT_MSGPORT; NEWLIST(&port->mp_MsgList); return TRUE; } STATIC AROS_LH3(LONG, OpenDevice, AROS_LHA(struct IORequest *, io, A1), AROS_LHA(IPTR, unitNumber, D0), AROS_LHA(ULONG, flags, D1), struct PrinterUnit *, pu, 1, PrinterUnit) { AROS_LIBFUNC_INIT struct MsgPort *mp; LONG ret = IOERR_OPENFAIL; if ((mp = CreateMsgPort())) { struct IORequest ior = *io; ior.io_Message.mn_ReplyPort = mp; ior.io_Command = CMD_OPENDEVICE; ret = DoIO(&ior); DeleteMsgPort(mp); } return ret; AROS_LIBFUNC_EXIT } STATIC AROS_LH1(BPTR, CloseDevice, AROS_LCA(struct IORequest *,io, A1), struct PrinterUnit *, pu, 2, PrinterUnit) { AROS_LIBFUNC_INIT BPTR ret = BNULL; struct MsgPort *mp; if ((mp = CreateMsgPort())) { struct IORequest ior = *io; ior.io_Message.mn_ReplyPort = mp; ior.io_Command = CMD_CLOSEDEVICE; DoIO(&ior); ret = AROS_LC1(BPTR, Expunge, AROS_LCA(struct PrinterUnit *, pu, D0), struct PrinterUnit *, pu, 3, PrinterUnit); DeleteMsgPort(mp); } return ret; AROS_LIBFUNC_EXIT } STATIC AROS_LH1(BPTR, Expunge, AROS_LHA(struct Library *, extralib, D0), struct PrinterUnit *, pu, 3, PrinterUnit) { AROS_LIBFUNC_INIT struct Library *lib = (struct Library *)pu; if (lib->lib_OpenCnt == 0) { BPTR seg = pu->pu_PrinterData.pd_PrinterSegment; Remove((struct Node *)lib); FreeMem((UBYTE *)lib - lib->lib_NegSize, (ULONG) (lib->lib_NegSize + lib->lib_PosSize)); D(bug("%s: Return segment %p\n", __func__, BADDR(seg))); return seg; } lib->lib_Flags |= LIBF_DELEXP; return BNULL; AROS_LIBFUNC_EXIT } STATIC AROS_LH1(void, BeginIO, AROS_LHA(union printerIO *, pio, A1), struct PrinterUnit *, pu, 5, PrinterUnit) { AROS_LIBFUNC_INIT struct IOStdReq *io = &pio->ios; struct PrinterData *pd = &pu->pu_PrinterData; D(bug("BeginIO: io_Command = %d, Unit Port %p\n", io->io_Command, &pd->pd_Unit)); io->io_Flags &= ~IOF_QUICK; PutMsg(&pd->pd_Unit, &io->io_Message); return; AROS_LIBFUNC_EXIT } STATIC AROS_LH1(LONG, AbortIO, AROS_LHA(struct IORequest *, pio, A1), struct PrinterUnit *, pd, 6, PrinterUnit) { AROS_LIBFUNC_INIT return IOERR_NOCMD; AROS_LIBFUNC_EXIT } /* These wrappers make sure that we don't * make WaitIO() hang or corrupt memory * if called on an already completed IO */ static inline LONG WaitIOStd(struct IOStdReq *io) { WaitIO((struct IORequest *)io); io->io_Message.mn_Node.ln_Type = 0; return io->io_Error; } static inline LONG DoIOStd(struct IOStdReq *io) { DoIO((struct IORequest *)io); io->io_Message.mn_Node.ln_Type = 0; return io->io_Error; } static LONG pd_PWrite(APTR data, LONG len) { struct IOStdReq *io; TASK_PRINTERDATA(pd); if (pd->pd_Flags & PDF_NOIO) return IOERR_OPENFAIL; io = (pd->pd_Flags & PDF_IOREQ) ? (struct IOStdReq *)&pd->pd_ior1 : (struct IOStdReq *)&pd->pd_ior0; WaitIOStd(io); /* TODO: Call error hook if there is an error */ io->io_Command = CMD_WRITE; io->io_Flags = 0; io->io_Actual = 0; io->io_Length = len; io->io_Data = data; io->io_Offset = 0; io->io_Message.mn_Length = sizeof(*io); SendIO((struct IORequest *)io); pd->pd_Flags ^= PDF_IOREQ; return 0; } static LONG pd_PBothReady(VOID) { TASK_PRINTERDATA(pd); D(bug("%s:\n", __func__)); if (pd->pd_Flags & PDF_NOIO) return IOERR_OPENFAIL; WaitIOStd((struct IOStdReq *)&pd->pd_ior0); WaitIOStd((struct IOStdReq *)&pd->pd_ior1); return 0; } static LONG pd_PRead(char * buffer, LONG *length, struct timeval *tv) { ULONG sigs; struct IOStdReq *io; LONG err; TASK_PRINTERDATA(pd); if (pd->pd_Flags & PDF_NOIO) return IOERR_OPENFAIL; D(bug("%s:\n", __func__)); io = (pd->pd_Flags & PDF_IOREQ) ? (struct IOStdReq *)&pd->pd_ior1 : (struct IOStdReq *)&pd->pd_ior0; WaitIOStd(io); /* TODO: Call error hook if there is an error */ pd->pd_TIOR.tr_node.io_Command = TR_ADDREQUEST; pd->pd_TIOR.tr_node.io_Flags = 0; pd->pd_TIOR.tr_node.io_Message.mn_Length = sizeof(pd->pd_TIOR); pd->pd_TIOR.tr_time.tv_secs = tv->tv_secs; pd->pd_TIOR.tr_time.tv_micro = tv->tv_micro; SendIO((struct IORequest *)&pd->pd_TIOR); io->io_Command = CMD_READ; io->io_Flags = 0; io->io_Actual = 0; io->io_Length = *length; io->io_Data = buffer; io->io_Offset = 0; io->io_Message.mn_Length = sizeof(*io); SendIO((struct IORequest *)io); sigs = Wait((1 << io->io_Message.mn_ReplyPort->mp_SigBit) | (1 << pd->pd_IORPort.mp_SigBit)); if (sigs & (1 << pd->pd_IORPort.mp_SigBit)) { WaitIO((struct IORequest *)&pd->pd_TIOR); if (!CheckIO((struct IORequest *)io)) AbortIO((struct IORequest *)io); } WaitIOStd(io); err = io->io_Error; if (err == 0) *length = io->io_Actual; /* No need to swap units, as this one has been completed */ return err; } static LONG pd_CallErrHook(struct Hook *hook, union printerIO *ior, struct PrtErrMsg *pem) { /* TODO */ return 0; } /* Only designed to work on the serial port. */ static LONG pd_PQuery(LONG *numofchars) { LONG err; struct IOStdReq *io; TASK_PRINTERDATA(pd); if (pd->pd_Flags & PDF_NOIO) return IOERR_OPENFAIL; D(bug("%s:\n", __func__)); io = (pd->pd_Flags & PDF_IOREQ) ? (struct IOStdReq *)&pd->pd_ior1 : (struct IOStdReq *)&pd->pd_ior0; WaitIOStd(io); /* TODO: Call error hook if there is an error */ io->io_Command = SDCMD_QUERY; io->io_Flags = 0; io->io_Actual = 0; io->io_Length = 0; io->io_Data = NULL; io->io_Offset = 0; io->io_Message.mn_Length = sizeof(*io); err = DoIOStd(io); if (err == 0) *numofchars = io->io_Actual; else *numofchars = 0; /* No need to swap units, as this one has been completed */ return err; } /* Only designed to work on the serial and parallel port. */ static LONG pd_Query(struct IOStdReq *sio) { LONG err; struct IOStdReq *io; TASK_PRINTERDATA(pd); D(bug("%s:\n", __func__)); if (pd->pd_PUnit->pu_Prefs.pp_Unit.pu_DeviceName[0] != 0 || (pd->pd_Flags & PDF_NOIO)) { sio->io_Actual = 0; return IOERR_OPENFAIL; } io = (pd->pd_Flags & PDF_IOREQ) ? (struct IOStdReq *)&pd->pd_ior1 : (struct IOStdReq *)&pd->pd_ior0; WaitIOStd(io); /* TODO: Call error hook if there is an error */ io->io_Command = SDCMD_QUERY; io->io_Flags = 0; io->io_Actual = 0; io->io_Length = 0; io->io_Data = NULL; io->io_Offset = 0; io->io_Message.mn_Length = sizeof(*io); err = DoIOStd(io); if (err == 0) { UBYTE *data = sio->io_Data; if (data) { UWORD status; switch (pd->pd_PUnit->pu_Prefs.pp_Txt.pt_Port) { case PP_SERIAL: status = ((struct IOExtSer *)io)->io_Status; break; case PP_PARALLEL: status = ((struct IOExtPar *)io)->io_Status; break; default: status = 0; break; } data[0] = (status >> 0) & 0xff; data[1] = (status >> 8) & 0xff; } sio->io_Actual = pd->pd_PUnit->pu_Prefs.pp_Txt.pt_Port + 1; } /* No need to swap units, as this one has been completed */ return err; } static LONG pd_Init(struct PrinterData *pd) { struct PrinterExtendedData *ped = &pd->pd_SegmentData->ps_PED; TEXT devname[sizeof(pd->pd_Preferences.PrtDevName) + 7 + 1]; /* Initialize the unit */ strcpy(devname, pd->pd_Preferences.PrtDevName); strcat(devname, ".device"); D(bug("%s: create msgport %p\n", __func__, &pd->pd_Unit)); if (initMsgPort(&pd->pd_Unit)) { D(bug("%s: Call ped_Init => %p\n", __func__, pd->pd_SegmentData->ps_PED.ped_Init)); if (0 == pd->pd_SegmentData->ps_PED.ped_Init(pd)) { if (pd->pd_Flags & PDF_NOIO) return 0; pd->pd_ior0.pd_p0.io_ParFlags = PARF_SHARED; if ((pd->pd_ior0.pd_p0.IOPar.io_Message.mn_ReplyPort=CreateMsgPort())) { if (0 == OpenDevice(devname, pd->pd_Preferences.DefaultPrtUnit, (struct IORequest *)&pd->pd_ior0, 0)) { D(bug("%s: open %s %d for io 0\n", __func__, devname, pd->pd_Preferences.DefaultPrtUnit)); pd->pd_ior0.pd_p0.IOPar.io_Message.mn_Node.ln_Type = 0; pd->pd_ior1.pd_p1.io_ParFlags = PARF_SHARED; if ((pd->pd_ior1.pd_p1.IOPar.io_Message.mn_ReplyPort=CreateMsgPort())) { if (0 == OpenDevice(devname, pd->pd_Preferences.DefaultPrtUnit, (struct IORequest *)&pd->pd_ior1, 0)) { pd->pd_ior1.pd_p1.IOPar.io_Message.mn_Node.ln_Type = 0; D(bug("%s: open %s %d for io 1\n", __func__, devname, pd->pd_Preferences.DefaultPrtUnit)); if (initMsgPort(&pd->pd_IORPort)) { pd->pd_TIOR.tr_node.io_Message.mn_ReplyPort=&pd->pd_IORPort; pd->pd_TIOR.tr_node.io_Message.mn_Length = sizeof(pd->pd_TIOR); if (0 == OpenDevice("timer.device", UNIT_VBLANK, (struct IORequest *)&pd->pd_TIOR, 0)) { D(bug("%s: open timer.device %d\n", __func__, UNIT_VBLANK)); if (ped->ped_Render) { LONG err = ped->ped_Render(0, 0, 0, PRS_PREINIT); if (err == 0) return 0; } else { return 0; } } FreeSignal(pd->pd_IORPort.mp_SigBit); } CloseDevice((struct IORequest *)&pd->pd_ior1); } DeleteMsgPort(pd->pd_ior1.pd_p1.IOPar.io_Message.mn_ReplyPort); } CloseDevice((struct IORequest *)&pd->pd_ior0); } DeleteMsgPort(pd->pd_ior0.pd_p0.IOPar.io_Message.mn_ReplyPort); } pd->pd_SegmentData->ps_PED.ped_Expunge(); } FreeSignal(pd->pd_Unit.mp_SigBit); } return -1; } static VOID pd_Close(struct PrinterData *pd, union printerIO *pio) { struct PrinterBase *PrinterBase = pd->pd_PUnit->pu_PrinterBase; struct PrinterExtendedData *ped = &pd->pd_SegmentData->ps_PED; LONG unitnum = pd->pd_PUnit->pu_Prefs.pp_DeviceUnit.pd_UnitNum; ped->ped_Close(pio); if (!(pd->pd_Flags & PDF_NOIO)) { CloseDevice((struct IORequest *)&pd->pd_TIOR); FreeSignal(pd->pd_IORPort.mp_SigBit); CloseDevice((struct IORequest *)&pd->pd_ior1); DeleteMsgPort(pd->pd_ior1.pd_p1.IOPar.io_Message.mn_ReplyPort); CloseDevice((struct IORequest *)&pd->pd_ior0); DeleteMsgPort(pd->pd_ior0.pd_p0.IOPar.io_Message.mn_ReplyPort); } FreeSignal(pd->pd_Unit.mp_SigBit); ped->ped_Expunge(); /* Remove from the parent printer.device */ ObtainSemaphore(&PrinterBase->pb_UnitLock[unitnum]); PrinterBase->pb_Unit[unitnum] = NULL; Forbid(); PrinterBase->pb_Device.dd_Library.lib_OpenCnt--; Permit(); ReleaseSemaphore(&PrinterBase->pb_UnitLock[unitnum]); } static LONG pd_DoPreferences(const union printerIO *pio, LONG command) { LONG err; TASK_PRINTERDATA(pd); if (pd->pd_SegmentData->ps_Version >= 44 && (pd->pd_SegmentData->ps_PED.ped_PrinterClass & PPCF_EXTENDED) && pd->pd_SegmentData->ps_PED.ped_DoPreferences != NULL) { err = pd->pd_SegmentData->ps_PED.ped_DoPreferences((union printerIO *)pio, command); } else { switch (command) { case PRD_RESETPREFS: case PRD_LOADPREFS: case PRD_USEPREFS: case PRD_SAVEPREFS: case PRD_READPREFS: case PRD_WRITEPREFS: case PRD_EDITPREFS: default: err = IOERR_NOCMD; break; } } return err; } /* A driver task is created on an OpenDevice() call, * and is killed by a CloseDevice() call. */ static LONG pd_DriverTask(VOID) { TASK_PRINTERDATA(pd); struct Process *me = (struct Process *)FindTask(NULL); struct PrinterExtendedData *ped = &pd->pd_SegmentData->ps_PED; struct PrinterMessage *msg = NULL; union printerIO *pio; UWORD cmd; BOOL stopped = FALSE; LONG ret; /* Wait for startup message - * we use the DOS port because the * pd_Unit has not been created yet */ D(bug("%s: Waiting for startup. pd=%p\n", __func__, pd)); WaitPort(&me->pr_MsgPort); msg = (struct PrinterMessage *)GetMsg(&me->pr_MsgPort); D(bug("%s: Initializing driver, Unit Port %p\n", __func__, &pd->pd_Unit)); ret = pd_Init(pd); /* We want to look like a TURBOPRINT driver * TPMATCHWORD is in the 3rd ULONG in pd_OldStk * TURBOPRINT was documented as using: * * (BOOL)TP_Installed = ( ((ULONG *)(PD->pd_OldStk))[2] == TPMATCHWORD) * * So the assumption is that this ULONG is in native endian format. */ { typedef union { UBYTE b[4]; ULONG l; } BL; BL *p = (BL*)(pd->pd_OldStk + (2 * sizeof(ULONG))); p->l = TPMATCHWORD; } D(bug("%s: Replying with %d\n", __func__, ret)); msg->mm_Version = ret; ReplyMsg(&msg->mm_Message); if (0 != ret) return ret; /* Wait for unit messages on the pd_Unit */ do { LONG err = 0; D(bug("%s: Waiting for command on port %p\n", __func__, &pd->pd_Unit)); WaitPort(&pd->pd_Unit); pio = (union printerIO *)GetMsg(&pd->pd_Unit); cmd = pio->ios.io_Command; D(bug("%s: Command = %d\n", __func__, cmd)); switch (cmd) { case CMD_OPENDEVICE: err = ped->ped_Open(pio); if (err == 0) Printer_Text_Write(pd, "\033#1", 3); /* aRIN */ break; case CMD_CLOSEDEVICE: pd_Close(pd, pio); break; case CMD_FLUSH: AbortIO((struct IORequest *)&pd->pd_ior0); WaitIOStd((struct IOStdReq *)&pd->pd_ior0); AbortIO((struct IORequest *)&pd->pd_ior1); WaitIOStd((struct IOStdReq *)&pd->pd_ior1); break; case CMD_RESET: if (stopped) err = PDERR_CANCEL; else { err = Printer_Text_Command(pd, aRIN, 0, 0, 0, 0); } break; case CMD_STOP: stopped = TRUE; break; case CMD_START: stopped = FALSE; break; case CMD_WRITE: if (stopped) err = PDERR_CANCEL; else { err = Printer_Text_Write(pd, pio->ios.io_Data, pio->ios.io_Length); if (err == 0) pio->ios.io_Actual = pio->ios.io_Length; } break; case PRD_RAWWRITE: if (stopped) err = PDERR_CANCEL; else { err = pd_PWrite(pio->ios.io_Data, pio->ios.io_Length); if (err == 0) pio->ios.io_Actual = pio->ios.io_Length; } break; case PRD_RESETPREFS: case PRD_LOADPREFS: case PRD_USEPREFS: case PRD_SAVEPREFS: case PRD_READPREFS: case PRD_EDITPREFS: err = pd_DoPreferences(pio, pio->ios.io_Command); break; case PRD_SETERRHOOK: pd->pd_PUnit->pu_ErrHook = ((struct IOPrtErrReq *)pio)->io_Hook; break; case PRD_DUMPRPORTTAGS: if (stopped) err = PDERR_CANCEL; else err = Printer_Gfx_DumpRPort((struct IODRPReq *)pio, ((struct IODRPTagsReq *)pio)->io_TagList); break; case PRD_DUMPRPORT: case PRD_TPEXTDUMPRPORT: if (stopped) err = PDERR_CANCEL; else err = Printer_Gfx_DumpRPort((struct IODRPReq *)pio, NULL); break; case PRD_QUERY: err = pd_Query(&pio->ios); break; default: err = IOERR_NOCMD; break; } pio->ios.io_Error = err; D(bug("%s: Command = %d, Result = %d\n", __func__, cmd, err)); ReplyMsg((struct Message *)pio); } while (cmd != CMD_CLOSEDEVICE); D(bug("%s: Shutting down\n", __func__)); return 0; } /* Synchronize old-style prefs with new style prefs */ static void pd_SyncPrefs(struct PrinterData *pd) { struct Preferences *dprefs = &pd->pd_Preferences; struct PrinterPrefs *uprefs = &pd->pd_PUnit->pu_Prefs; dprefs->PrinterType = pd->pd_PrinterType; strncpy(dprefs->PrinterFilename, uprefs->pp_Txt.pt_Driver, sizeof(dprefs->PrinterFilename)); dprefs->PrinterFilename[sizeof(dprefs->PrinterFilename)-1] = 0; dprefs->PrintPitch = uprefs->pp_Txt.pt_Pitch; dprefs->PrintQuality = uprefs->pp_Txt.pt_Quality; dprefs->PrintSpacing = uprefs->pp_Txt.pt_Spacing; dprefs->PrintLeftMargin = uprefs->pp_Txt.pt_LeftMargin; dprefs->PrintRightMargin = uprefs->pp_Txt.pt_RightMargin; dprefs->PrintImage = uprefs->pp_Gfx.pg_Image; dprefs->PrintAspect = uprefs->pp_Gfx.pg_Aspect; dprefs->PrintShade = uprefs->pp_Gfx.pg_Shade; dprefs->PrintThreshold = uprefs->pp_Gfx.pg_Threshold; dprefs->PaperSize = uprefs->pp_Txt.pt_PaperSize; dprefs->PaperType = uprefs->pp_Txt.pt_PaperType; dprefs->PaperLength = uprefs->pp_Txt.pt_PaperLength; if (uprefs->pp_Unit.pu_DeviceName[0] == 0) { if (uprefs->pp_Txt.pt_Port == PP_PARALLEL) { strcpy(dprefs->PrtDevName, "parallel"); } else if (uprefs->pp_Txt.pt_Port == PP_SERIAL) { strcpy(dprefs->PrtDevName, "serial"); } else { strcpy(dprefs->PrtDevName, "printtofile"); } } else { strncpy(dprefs->PrtDevName, uprefs->pp_Unit.pu_DeviceName, sizeof(dprefs->PrtDevName)); dprefs->PrtDevName[sizeof(dprefs->PrtDevName)-1]=0; } if (strcmp(dprefs->PrtDevName, "parallel") == 0 || strcmp(dprefs->PrtDevName, "usbparallel") == 0) { pd->pd_ior0.pd_p0.IOPar.io_Message.mn_Length = sizeof(pd->pd_ior0.pd_p0); pd->pd_ior0.pd_p0.io_ParFlags = PARF_SHARED; pd->pd_ior1.pd_p1.IOPar.io_Message.mn_Length = sizeof(pd->pd_ior1.pd_p1); pd->pd_ior1.pd_p1.io_ParFlags = PARF_SHARED; } else if (strcmp(dprefs->PrtDevName, "serial") == 0) { pd->pd_ior0.pd_s0.IOSer.io_Message.mn_Length = sizeof(pd->pd_ior0.pd_s0); pd->pd_ior0.pd_s0.io_SerFlags = SERF_SHARED; pd->pd_ior1.pd_s1.IOSer.io_Message.mn_Length = sizeof(pd->pd_ior1.pd_s1); pd->pd_ior1.pd_s1.io_SerFlags = SERF_SHARED; } else { pd->pd_ior0.pd_i0.io_Message.mn_Length = sizeof(pd->pd_ior0.pd_i0); pd->pd_ior1.pd_i1.io_Message.mn_Length = sizeof(pd->pd_ior1.pd_i1); } dprefs->DefaultPrtUnit = uprefs->pp_Unit.pu_UnitNum; dprefs->PrintFlags = uprefs->pp_Gfx.pg_GraphicFlags; dprefs->PrintMaxWidth = uprefs->pp_Gfx.pg_PrintMaxWidth; dprefs->PrintMaxHeight = uprefs->pp_Gfx.pg_PrintMaxHeight; dprefs->PrintDensity = uprefs->pp_Gfx.pg_PrintDensity; dprefs->PrintXOffset = uprefs->pp_Gfx.pg_PrintXOffset; } /* Create a PrinterData plugin */ struct PrinterUnit *Printer_Unit(struct PrinterBase *PrinterBase, LONG unitnum) { struct PrinterUnit *pu; struct PrinterPrefs prefs; BPTR olddir, dir, driverseg; if (!Printer_LoadPrefs(PrinterBase, unitnum, &prefs) || prefs.pp_Txt.pt_Driver[0] == 0) { D(bug("%s: No valid prefs for printer.device %d\n", __func__, unitnum)); return NULL; } if ((dir = Lock("DEVS:Printers", SHARED_LOCK)) != BNULL) { olddir = CurrentDir(dir); driverseg = LoadSeg(prefs.pp_Txt.pt_Driver); CurrentDir(olddir); UnLock(dir); D(bug("%s: %s => %p\n", __func__, prefs.pp_Txt.pt_Driver, BADDR(driverseg))); if (driverseg) { struct PrinterSegment *prtseg = BADDR(driverseg); D(bug("%s: magic 0x%08x, expect 0x%08x\n", __func__, prtseg->ps_runAlert, AROS_PRINTER_MAGIC)); if (prtseg->ps_runAlert == AROS_PRINTER_MAGIC) { APTR funcs[] = { AROS_SLIB_ENTRY(OpenDevice,PrinterUnit,1), AROS_SLIB_ENTRY(CloseDevice,PrinterUnit,2), AROS_SLIB_ENTRY(Expunge,PrinterUnit,3), NULL, AROS_SLIB_ENTRY(BeginIO,PrinterUnit,5), AROS_SLIB_ENTRY(AbortIO,PrinterUnit,6), (APTR)-1, }; if ((pu = (struct PrinterUnit *)MakeLibrary(funcs, NULL, NULL, sizeof(*pu), driverseg))) { struct Process *proc; struct PrinterData *pd = &pu->pu_PrinterData; struct Device *dev = (struct Device *)pu; /* Loop back to self */ pu->pu_PrinterBase = PrinterBase; pd->pd_PUnit = pu; /* Duplicate the prefs */ CopyMem(&prefs, &pu->pu_Prefs, sizeof(prefs)); /* Update pd->pd_Preferences from pu->pu_Prefs */ pd_SyncPrefs(pd); dev->dd_Library.lib_Node.ln_Name = pu->pu_Prefs.pp_DeviceUnit.pd_UnitName; dev->dd_Library.lib_Version = prtseg->ps_Version; dev->dd_Library.lib_Revision = prtseg->ps_Revision; /* Magic token for TASK_PRINTERDATA() macro */ dev->dd_Library.lib_IdString = (APTR)driverID; pd->pd_Device.dd_Segment = BADDR(driverseg); pd->pd_Device.dd_ExecBase = SysBase; pd->pd_Device.dd_CmdVectors = prtseg->ps_PED.ped_Commands; pd->pd_Device.dd_CmdBytes = NULL; pd->pd_Device.dd_NumCommands = aRAW + 1; pd->pd_PrinterSegment = driverseg; pd->pd_PrinterType = 0; pd->pd_SegmentData = prtseg; pd->pd_PWrite = pd_PWrite; pd->pd_PBothReady = pd_PBothReady; pd->pd_PRead = pd_PRead; pd->pd_CallErrHook = (APTR)pd_CallErrHook; pd->pd_PQuery = pd_PQuery; pd->pd_UnitNumber = unitnum; pd->pd_DriverName = &pd->pd_Preferences.PrinterFilename[0]; /* Make RemDevice() and friends happy */ AddDevice(dev); proc = CreateNewProcTags(NP_Entry, pd_DriverTask, NP_Name, prefs.pp_DeviceUnit.pd_UnitName, NP_Priority, 0, NP_Arguments, NULL, NP_UserData, pd); D(bug("%s: Driver process %p\n", __func__, proc)); if (proc != NULL) { struct MsgPort *port; /* Store the process here... */ pu->pu_Process = proc; if ((port = CreateMsgPort())) { struct PrinterMessage startup, *reply; D(bug("%s: Driver unit port %p\n", __func__, port)); startup.mm_Message.mn_ReplyPort=port; startup.mm_Message.mn_Length = sizeof(startup); startup.mm_Magic = AROS_MAKE_ID('p','r','u','n'); startup.mm_Version = 0; PutMsg(&proc->pr_MsgPort, (struct Message *)&startup); WaitPort(port); D(bug("%s: Driver replied\n", __func__)); reply = (struct PrinterMessage *)GetMsg(port); D(bug("%s: Driver reply = %p\n", __func__, reply)); DeleteMsgPort(port); D(bug("%s: Driver port %p gone\n", __func__, port)); if (reply == &startup && reply->mm_Message.mn_Length == sizeof(*reply) && reply->mm_Magic == AROS_MAKE_ID('p','r','u','n') && reply->mm_Version == 0) { /* Success! */ D(bug("%s: Driver started\n", __func__)); return pu; } D(bug("%s: Driver startup failed\n", __func__)); } /* pd_DriverTask will kill itself on failure */ } /* pd_Expunge() calls UnLoadSeg() automatically */ RemDevice((struct Device *)pd); driverseg = BNULL; } } if (driverseg) UnLoadSeg(driverseg); } } return NULL; }