parallel.device: Clean up DEBUG
[AROS.git] / workbench / devs / printer / driver.c
blob445be1abed2f44520c8bec2a94a6799bf3d36cc6
1 /*
2 * Copyright (C) 2012, The AROS Development Team. All rights reserved.
3 * Author: Jason S. McMullan <jason.mcmullan@gmail.com>
5 * Licensed under the AROS PUBLIC LICENSE (APL) Version 1.1
7 * This file handles the creation of the per-unit driver task,
8 * and the creation of the per-unit 'struct PrinterData',
9 * and the pd_PWrite()/pd_PRead() etc IO functions.
12 #include <aros/debug.h>
13 #include <aros/printertag.h>
15 #include <exec/errors.h>
17 #include <proto/exec.h>
18 #include <proto/dos.h>
19 #include <proto/intuition.h>
21 #include <devices/printer.h>
22 #include <datatypes/datatypesclass.h>
24 #define TPMATCHWORD 0xf10a57ef /* From turboprint's SDK */
26 #define CMD_OPENDEVICE (0x100)
27 #define CMD_CLOSEDEVICE (0x101)
29 #include LC_LIBDEFS_FILE
31 #include "printer_intern.h"
33 /* pd_Flags values */
34 #define PDF_IOREQ (1 << 0) /* IORequest 0 or 1 */
35 #define PDF_NOIO (1 << 1) /* PRTA_NoIO was true */
36 #define PDF_CONVERT (1 << 2) /* PRTA_ConvertSource was true */
37 #define PDF_8BITGUNS (1 << 3) /* PRTA_8BitGuns was true */
39 const TEXT driverID[] = "printer.driver";
41 const struct EasyStruct driverMisuse = { \
42 .es_StructSize = sizeof(struct EasyStruct),
43 .es_Flags = 0,
44 .es_Title = "Improper use of printer.device",
45 .es_TextFormat = "\"%s\" attempted to use the private\n"
46 "printer.driver method %s.\n"
47 "Only CMD_RAWWRITE is supported.\n",
48 .es_GadgetFormat = "Ok",
51 /* Internal, private message
53 struct PrinterMessage {
54 struct Message mm_Message;
55 ULONG mm_Magic;
56 ULONG mm_Version;
59 #define TASK_PRINTERDATA(pd) \
60 struct PrinterData *pd =(struct PrinterData *)FindTask(NULL)->tc_UserData; \
61 if (pd == NULL || \
62 pd->pd_Device.dd_Device.lib_Node.ln_Type != NT_DEVICE || \
63 pd->pd_Device.dd_Device.lib_IdString != driverID) { \
64 struct Library *IntuitionBase; \
65 if ((IntuitionBase = TaggedOpenLibrary(TAGGEDOPEN_INTUITION))) { \
66 IPTR args[] = { (IPTR)FindTask(NULL)->tc_Node.ln_Name, \
67 (IPTR)__func__ }; \
68 EasyRequestArgs(NULL, (struct EasyStruct *)&driverMisuse, \
69 0, args); \
70 CloseLibrary(IntuitionBase); \
71 } \
72 return IOERR_NOCMD; \
76 static BOOL initMsgPort(struct MsgPort *port)
78 BYTE sb = AllocSignal(-1);
80 if (sb < 0)
81 return FALSE;
83 port->mp_SigBit = sb;
84 port->mp_SigTask = FindTask(NULL);
85 port->mp_Flags = PA_SIGNAL;
86 port->mp_Node.ln_Type = NT_MSGPORT;
87 NEWLIST(&port->mp_MsgList);
89 return TRUE;
92 STATIC AROS_LH3(LONG, OpenDevice,
93 AROS_LHA(struct IORequest *, io, A1),
94 AROS_LHA(IPTR, unitNumber, D0),
95 AROS_LHA(ULONG, flags, D1),
96 struct PrinterUnit *, pu, 1, PrinterUnit)
98 AROS_LIBFUNC_INIT
100 struct MsgPort *mp;
101 LONG ret = IOERR_OPENFAIL;
103 if ((mp = CreateMsgPort())) {
104 struct IORequest ior = *io;
105 ior.io_Message.mn_ReplyPort = mp;
106 ior.io_Command = CMD_OPENDEVICE;
107 ret = DoIO(&ior);
108 DeleteMsgPort(mp);
111 return ret;
113 AROS_LIBFUNC_EXIT
116 STATIC AROS_LH1(BPTR, CloseDevice,
117 AROS_LCA(struct IORequest *,io, A1),
118 struct PrinterUnit *, pu, 2, PrinterUnit)
120 AROS_LIBFUNC_INIT
122 BPTR ret = BNULL;
123 struct MsgPort *mp;
125 if ((mp = CreateMsgPort())) {
126 struct IORequest ior = *io;
127 ior.io_Message.mn_ReplyPort = mp;
128 ior.io_Command = CMD_CLOSEDEVICE;
129 DoIO(&ior);
130 ret = AROS_LC1(BPTR, Expunge,
131 AROS_LCA(struct PrinterUnit *, pu, D0),
132 struct PrinterUnit *, pu, 3, PrinterUnit);
133 DeleteMsgPort(mp);
136 return ret;
138 AROS_LIBFUNC_EXIT
141 STATIC AROS_LH1(BPTR, Expunge,
142 AROS_LHA(struct Library *, extralib, D0),
143 struct PrinterUnit *, pu, 3, PrinterUnit)
145 AROS_LIBFUNC_INIT
147 struct Library *lib = (struct Library *)pu;
149 if (lib->lib_OpenCnt == 0) {
150 BPTR seg = pu->pu_PrinterData.pd_PrinterSegment;
152 Remove((struct Node *)lib);
153 FreeMem((UBYTE *)lib - lib->lib_NegSize,
154 (ULONG) (lib->lib_NegSize +
155 lib->lib_PosSize));
157 D(bug("%s: Return segment %p\n", __func__, BADDR(seg)));
158 return seg;
161 lib->lib_Flags |= LIBF_DELEXP;
163 return BNULL;
165 AROS_LIBFUNC_EXIT
169 STATIC AROS_LH1(void, BeginIO,
170 AROS_LHA(union printerIO *, pio, A1),
171 struct PrinterUnit *, pu, 5, PrinterUnit)
173 AROS_LIBFUNC_INIT
175 struct IOStdReq *io = &pio->ios;
176 struct PrinterData *pd = &pu->pu_PrinterData;
178 D(bug("BeginIO: io_Command = %d, Unit Port %p\n", io->io_Command, &pd->pd_Unit));
180 io->io_Flags &= ~IOF_QUICK;
181 PutMsg(&pd->pd_Unit, &io->io_Message);
183 return;
185 AROS_LIBFUNC_EXIT
188 STATIC AROS_LH1(LONG, AbortIO,
189 AROS_LHA(struct IORequest *, pio, A1),
190 struct PrinterUnit *, pd, 6, PrinterUnit)
192 AROS_LIBFUNC_INIT
193 return IOERR_NOCMD;
194 AROS_LIBFUNC_EXIT
197 /* These wrappers make sure that we don't
198 * make WaitIO() hang or corrupt memory
199 * if called on an already completed IO
201 static inline LONG WaitIOStd(struct IOStdReq *io)
203 WaitIO((struct IORequest *)io);
204 io->io_Message.mn_Node.ln_Type = 0;
205 return io->io_Error;
208 static inline LONG DoIOStd(struct IOStdReq *io)
210 DoIO((struct IORequest *)io);
211 io->io_Message.mn_Node.ln_Type = 0;
212 return io->io_Error;
215 static LONG pd_PWrite(APTR data, LONG len)
217 struct IOStdReq *io;
218 TASK_PRINTERDATA(pd);
220 if (pd->pd_Flags & PDF_NOIO)
221 return IOERR_OPENFAIL;
223 io = (pd->pd_Flags & PDF_IOREQ) ?
224 (struct IOStdReq *)&pd->pd_ior1 :
225 (struct IOStdReq *)&pd->pd_ior0;
226 WaitIOStd(io);
227 /* TODO: Call error hook if there is an error */
228 io->io_Command = CMD_WRITE;
229 io->io_Flags = 0;
230 io->io_Actual = 0;
231 io->io_Length = len;
232 io->io_Data = data;
233 io->io_Offset = 0;
234 io->io_Message.mn_Length = sizeof(*io);
235 SendIO((struct IORequest *)io);
237 pd->pd_Flags ^= PDF_IOREQ;
239 return 0;
242 static LONG pd_PBothReady(VOID)
244 TASK_PRINTERDATA(pd);
246 D(bug("%s:\n", __func__));
247 if (pd->pd_Flags & PDF_NOIO)
248 return IOERR_OPENFAIL;
250 WaitIOStd((struct IOStdReq *)&pd->pd_ior0);
251 WaitIOStd((struct IOStdReq *)&pd->pd_ior1);
253 return 0;
256 static LONG pd_PRead(char * buffer, LONG *length, struct timeval *tv)
258 ULONG sigs;
259 struct IOStdReq *io;
260 LONG err;
261 TASK_PRINTERDATA(pd);
263 if (pd->pd_Flags & PDF_NOIO)
264 return IOERR_OPENFAIL;
266 D(bug("%s:\n", __func__));
267 io = (pd->pd_Flags & PDF_IOREQ) ?
268 (struct IOStdReq *)&pd->pd_ior1 :
269 (struct IOStdReq *)&pd->pd_ior0;
270 WaitIOStd(io);
271 /* TODO: Call error hook if there is an error */
272 pd->pd_TIOR.tr_node.io_Command = TR_ADDREQUEST;
273 pd->pd_TIOR.tr_node.io_Flags = 0;
274 pd->pd_TIOR.tr_node.io_Message.mn_Length = sizeof(pd->pd_TIOR);
275 pd->pd_TIOR.tr_time = *tv;
276 SendIO((struct IORequest *)&pd->pd_TIOR);
278 io->io_Command = CMD_READ;
279 io->io_Flags = 0;
280 io->io_Actual = 0;
281 io->io_Length = *length;
282 io->io_Data = buffer;
283 io->io_Offset = 0;
284 io->io_Message.mn_Length = sizeof(*io);
285 SendIO((struct IORequest *)io);
286 sigs = Wait((1 << io->io_Message.mn_ReplyPort->mp_SigBit) |
287 (1 << pd->pd_IORPort.mp_SigBit));
288 if (sigs & (1 << pd->pd_IORPort.mp_SigBit)) {
289 WaitIO((struct IORequest *)&pd->pd_TIOR);
290 if (!CheckIO((struct IORequest *)io))
291 AbortIO((struct IORequest *)io);
293 WaitIOStd(io);
294 err = io->io_Error;
295 if (err == 0)
296 *length = io->io_Actual;
298 /* No need to swap units, as this one has been completed */
300 return err;
303 static LONG pd_CallErrHook(struct Hook *hook, union printerIO *ior, struct PrtErrMsg *pem)
305 /* TODO */
306 return 0;
309 /* Only designed to work on the serial port. */
310 static LONG pd_PQuery(LONG *numofchars)
312 LONG err;
313 struct IOStdReq *io;
315 TASK_PRINTERDATA(pd);
317 if (pd->pd_Flags & PDF_NOIO)
318 return IOERR_OPENFAIL;
320 D(bug("%s:\n", __func__));
321 io = (pd->pd_Flags & PDF_IOREQ) ?
322 (struct IOStdReq *)&pd->pd_ior1 :
323 (struct IOStdReq *)&pd->pd_ior0;
324 WaitIOStd(io);
325 /* TODO: Call error hook if there is an error */
326 io->io_Command = SDCMD_QUERY;
327 io->io_Flags = 0;
328 io->io_Actual = 0;
329 io->io_Length = 0;
330 io->io_Data = NULL;
331 io->io_Offset = 0;
332 io->io_Message.mn_Length = sizeof(*io);
333 err = DoIOStd(io);
334 if (err == 0)
335 *numofchars = io->io_Actual;
336 else
337 *numofchars = 0;
339 /* No need to swap units, as this one has been completed */
341 return err;
344 /* Only designed to work on the serial and parallel port. */
345 static LONG pd_Query(struct IOStdReq *sio)
347 LONG err;
348 struct IOStdReq *io;
350 TASK_PRINTERDATA(pd);
352 D(bug("%s:\n", __func__));
353 if (pd->pd_PUnit->pu_Prefs.pp_Unit.pu_DeviceName[0] != 0 ||
354 (pd->pd_Flags & PDF_NOIO)) {
355 sio->io_Actual = 0;
356 return IOERR_OPENFAIL;
359 io = (pd->pd_Flags & PDF_IOREQ) ?
360 (struct IOStdReq *)&pd->pd_ior1 :
361 (struct IOStdReq *)&pd->pd_ior0;
362 WaitIOStd(io);
363 /* TODO: Call error hook if there is an error */
364 io->io_Command = SDCMD_QUERY;
365 io->io_Flags = 0;
366 io->io_Actual = 0;
367 io->io_Length = 0;
368 io->io_Data = NULL;
369 io->io_Offset = 0;
370 io->io_Message.mn_Length = sizeof(*io);
371 err = DoIOStd(io);
372 if (err == 0) {
373 UBYTE *data = sio->io_Data;
374 if (data) {
375 UWORD status;
377 switch (pd->pd_PUnit->pu_Prefs.pp_Txt.pt_Port) {
378 case PP_SERIAL:
379 status = ((struct IOExtSer *)io)->io_Status;
380 break;
381 case PP_PARALLEL:
382 status = ((struct IOExtPar *)io)->io_Status;
383 break;
384 default:
385 status = 0;
386 break;
388 data[0] = (status >> 0) & 0xff;
389 data[1] = (status >> 8) & 0xff;
391 sio->io_Actual = pd->pd_PUnit->pu_Prefs.pp_Txt.pt_Port + 1;
394 /* No need to swap units, as this one has been completed */
396 return err;
399 static LONG pd_Init(struct PrinterData *pd)
401 struct PrinterExtendedData *ped = &pd->pd_SegmentData->ps_PED;
402 TEXT devname[sizeof(pd->pd_Preferences.PrtDevName) + 7 + 1];
404 /* Initialize the unit */
405 strcpy(devname, pd->pd_Preferences.PrtDevName);
406 strcat(devname, ".device");
408 D(bug("%s: create msgport %p\n", __func__, &pd->pd_Unit));
409 if (initMsgPort(&pd->pd_Unit)) {
410 D(bug("%s: Call ped_Init => %p\n", __func__, pd->pd_SegmentData->ps_PED.ped_Init));
411 if (0 == pd->pd_SegmentData->ps_PED.ped_Init(pd)) {
412 if (pd->pd_Flags & PDF_NOIO)
413 return 0;
415 if ((pd->pd_ior0.pd_p0.IOPar.io_Message.mn_ReplyPort=CreateMsgPort())) {
416 if (0 == OpenDevice(devname,
417 pd->pd_Preferences.DefaultPrtUnit,
418 (struct IORequest *)&pd->pd_ior0, 0)) {
419 D(bug("%s: open %s %d for io 0\n", __func__, devname, pd->pd_Preferences.DefaultPrtUnit));
420 pd->pd_ior0.pd_p0.IOPar.io_Message.mn_Node.ln_Type = 0;
421 if ((pd->pd_ior1.pd_p1.IOPar.io_Message.mn_ReplyPort=CreateMsgPort())) {
422 if (0 == OpenDevice(devname,
423 pd->pd_Preferences.DefaultPrtUnit,
424 (struct IORequest *)&pd->pd_ior1, 0)) {
425 pd->pd_ior1.pd_p1.IOPar.io_Message.mn_Node.ln_Type = 0;
426 D(bug("%s: open %s %d for io 1\n", __func__, devname, pd->pd_Preferences.DefaultPrtUnit));
427 if (initMsgPort(&pd->pd_IORPort)) {
428 pd->pd_TIOR.tr_node.io_Message.mn_ReplyPort=&pd->pd_IORPort;
429 pd->pd_TIOR.tr_node.io_Message.mn_Length = sizeof(pd->pd_TIOR);
430 if (0 == OpenDevice("timer.device", UNIT_VBLANK,
431 (struct IORequest *)&pd->pd_TIOR, 0)) {
432 D(bug("%s: open timer.device %d\n", __func__, UNIT_VBLANK));
433 if (ped->ped_Render) {
434 LONG err = ped->ped_Render(0, 0, 0, PRS_PREINIT);
435 if (err == 0)
436 return 0;
437 } else {
438 return 0;
441 FreeSignal(pd->pd_IORPort.mp_SigBit);
443 CloseDevice((struct IORequest *)&pd->pd_ior1);
445 DeleteMsgPort(pd->pd_ior1.pd_p1.IOPar.io_Message.mn_ReplyPort);
447 CloseDevice((struct IORequest *)&pd->pd_ior0);
449 DeleteMsgPort(pd->pd_ior0.pd_p0.IOPar.io_Message.mn_ReplyPort);
451 pd->pd_SegmentData->ps_PED.ped_Expunge();
453 FreeSignal(pd->pd_Unit.mp_SigBit);
456 return -1;
459 static VOID pd_Close(struct PrinterData *pd, union printerIO *pio)
461 struct PrinterBase *PrinterBase = pd->pd_PUnit->pu_PrinterBase;
462 struct PrinterExtendedData *ped = &pd->pd_SegmentData->ps_PED;
463 LONG unitnum = pd->pd_PUnit->pu_Prefs.pp_DeviceUnit.pd_UnitNum;
465 ped->ped_Close(pio);
467 if (!(pd->pd_Flags & PDF_NOIO)) {
468 CloseDevice((struct IORequest *)&pd->pd_TIOR);
469 FreeSignal(pd->pd_IORPort.mp_SigBit);
470 CloseDevice((struct IORequest *)&pd->pd_ior1);
471 DeleteMsgPort(pd->pd_ior1.pd_p1.IOPar.io_Message.mn_ReplyPort);
472 CloseDevice((struct IORequest *)&pd->pd_ior0);
473 DeleteMsgPort(pd->pd_ior0.pd_p0.IOPar.io_Message.mn_ReplyPort);
475 FreeSignal(pd->pd_Unit.mp_SigBit);
477 ped->ped_Expunge();
479 /* Remove from the parent printer.device */
480 ObtainSemaphore(&PrinterBase->pb_UnitLock[unitnum]);
481 PrinterBase->pb_Unit[unitnum] = NULL;
482 Forbid();
483 PrinterBase->pb_Device.dd_Library.lib_OpenCnt--;
484 Permit();
485 ReleaseSemaphore(&PrinterBase->pb_UnitLock[unitnum]);
488 static LONG pd_DoPreferences(const union printerIO *pio, LONG command)
490 LONG err;
492 TASK_PRINTERDATA(pd);
494 if (pd->pd_SegmentData->ps_Version >= 44 &&
495 (pd->pd_SegmentData->ps_PED.ped_PrinterClass & PPCF_EXTENDED) &&
496 pd->pd_SegmentData->ps_PED.ped_DoPreferences != NULL) {
497 err = pd->pd_SegmentData->ps_PED.ped_DoPreferences((union printerIO *)pio, command);
498 } else {
499 switch (command) {
500 case PRD_RESETPREFS:
501 case PRD_LOADPREFS:
502 case PRD_USEPREFS:
503 case PRD_SAVEPREFS:
504 case PRD_READPREFS:
505 case PRD_WRITEPREFS:
506 case PRD_EDITPREFS:
507 default:
508 err = IOERR_NOCMD;
509 break;
513 return err;
516 /* A driver task is created on an OpenDevice() call,
517 * and is killed by a CloseDevice() call.
519 static LONG pd_DriverTask(VOID)
521 TASK_PRINTERDATA(pd);
523 struct Process *me = (struct Process *)FindTask(NULL);
524 struct PrinterExtendedData *ped = &pd->pd_SegmentData->ps_PED;
525 struct PrinterMessage *msg = NULL;
526 union printerIO *pio;
527 UWORD cmd;
528 BOOL stopped = FALSE;
529 LONG ret;
531 /* Wait for startup message -
532 * we use the DOS port because the
533 * pd_Unit has not been created yet
535 D(bug("%s: Waiting for startup. pd=%p\n", __func__, pd));
536 WaitPort(&me->pr_MsgPort);
537 msg = (struct PrinterMessage *)GetMsg(&me->pr_MsgPort);
539 D(bug("%s: Initializing driver, Unit Port %p\n", __func__, &pd->pd_Unit));
540 ret = pd_Init(pd);
542 /* We want to look like a TURBOPRINT driver
543 * TPMATCHWORD is in the 3rd ULONG in pd_OldStk
544 * TURBOPRINT was documented as using:
546 * (BOOL)TP_Installed = ( ((ULONG *)(PD->pd_OldStk))[2] == TPMATCHWORD)
548 * So the assumption is that this ULONG is in native endian format.
550 ((ULONG *)(pd->pd_OldStk))[2] = TPMATCHWORD;
553 D(bug("%s: Replying with %d\n", __func__, ret));
554 msg->mm_Version = ret;
555 ReplyMsg(&msg->mm_Message);
557 if (0 != ret)
558 return ret;
560 /* Wait for unit messages on the pd_Unit */
561 do {
562 LONG err = 0;
564 D(bug("%s: Waiting for command on port %p\n", __func__, &pd->pd_Unit));
565 WaitPort(&pd->pd_Unit);
566 pio = (union printerIO *)GetMsg(&pd->pd_Unit);
567 cmd = pio->ios.io_Command;
569 D(bug("%s: Command = %d\n", __func__, cmd));
570 switch (cmd) {
571 case CMD_OPENDEVICE:
572 err = ped->ped_Open(pio);
573 if (err == 0)
574 Printer_Text_Write(pd, "\033#1", 3); /* aRIN */
575 break;
576 case CMD_CLOSEDEVICE:
577 pd_Close(pd, pio);
578 break;
579 case CMD_FLUSH:
580 AbortIO((struct IORequest *)&pd->pd_ior0);
581 WaitIOStd((struct IOStdReq *)&pd->pd_ior0);
582 AbortIO((struct IORequest *)&pd->pd_ior1);
583 WaitIOStd((struct IOStdReq *)&pd->pd_ior1);
584 break;
585 case CMD_RESET:
586 if (stopped)
587 err = PDERR_CANCEL;
588 else {
589 err = Printer_Text_Command(pd, aRIN, 0, 0, 0, 0);
591 break;
592 case CMD_STOP:
593 stopped = TRUE;
594 break;
595 case CMD_START:
596 stopped = FALSE;
597 break;
598 case CMD_WRITE:
599 if (stopped)
600 err = PDERR_CANCEL;
601 else {
602 err = Printer_Text_Write(pd, pio->ios.io_Data, pio->ios.io_Length);
603 if (err == 0)
604 pio->ios.io_Actual = pio->ios.io_Length;
606 break;
607 case PRD_RAWWRITE:
608 if (stopped)
609 err = PDERR_CANCEL;
610 else {
611 err = pd_PWrite(pio->ios.io_Data, pio->ios.io_Length);
612 if (err == 0)
613 pio->ios.io_Actual = pio->ios.io_Length;
615 break;
616 case PRD_RESETPREFS:
617 case PRD_LOADPREFS:
618 case PRD_USEPREFS:
619 case PRD_SAVEPREFS:
620 case PRD_READPREFS:
621 case PRD_EDITPREFS:
622 err = pd_DoPreferences(pio, pio->ios.io_Command);
623 break;
624 case PRD_SETERRHOOK:
625 pd->pd_PUnit->pu_ErrHook = ((struct IOPrtErrReq *)pio)->io_Hook;
626 break;
627 case PRD_DUMPRPORTTAGS:
628 if (stopped)
629 err = PDERR_CANCEL;
630 else
631 err = Printer_Gfx_DumpRPort((struct IODRPReq *)pio, ((struct IODRPTagsReq *)pio)->io_TagList);
632 break;
633 case PRD_DUMPRPORT:
634 case PRD_TPEXTDUMPRPORT:
635 if (stopped)
636 err = PDERR_CANCEL;
637 else
638 err = Printer_Gfx_DumpRPort((struct IODRPReq *)pio, NULL);
639 break;
640 case PRD_QUERY:
641 err = pd_Query(&pio->ios);
642 break;
643 default:
644 err = IOERR_NOCMD;
645 break;
647 pio->ios.io_Error = err;
648 D(bug("%s: Command = %d, Result = %d\n", __func__, cmd, err));
650 ReplyMsg((struct Message *)pio);
651 } while (cmd != CMD_CLOSEDEVICE);
653 D(bug("%s: Shutting down\n", __func__));
655 return 0;
658 /* Synchronize old-style prefs with new style prefs
660 static void pd_SyncPrefs(struct PrinterData *pd)
662 struct Preferences *dprefs = &pd->pd_Preferences;
663 struct PrinterPrefs *uprefs = &pd->pd_PUnit->pu_Prefs;
665 dprefs->PrinterType = pd->pd_PrinterType;
667 strncpy(dprefs->PrinterFilename, uprefs->pp_Txt.pt_Driver,
668 sizeof(dprefs->PrinterFilename));
669 dprefs->PrinterFilename[sizeof(dprefs->PrinterFilename)-1] = 0;
671 dprefs->PrintPitch = uprefs->pp_Txt.pt_Pitch;
672 dprefs->PrintQuality = uprefs->pp_Txt.pt_Quality;
673 dprefs->PrintSpacing = uprefs->pp_Txt.pt_Spacing;
674 dprefs->PrintLeftMargin = uprefs->pp_Txt.pt_LeftMargin;
675 dprefs->PrintRightMargin = uprefs->pp_Txt.pt_RightMargin;
676 dprefs->PrintImage = uprefs->pp_Gfx.pg_Image;
677 dprefs->PrintAspect = uprefs->pp_Gfx.pg_Aspect;
678 dprefs->PrintShade = uprefs->pp_Gfx.pg_Shade;
679 dprefs->PrintThreshold = uprefs->pp_Gfx.pg_Threshold;
680 dprefs->PaperSize = uprefs->pp_Txt.pt_PaperSize;
681 dprefs->PaperType = uprefs->pp_Txt.pt_PaperType;
682 dprefs->PaperLength = uprefs->pp_Txt.pt_PaperLength;
684 if (uprefs->pp_Unit.pu_DeviceName[0] == 0) {
685 if (uprefs->pp_Txt.pt_Port == PP_PARALLEL) {
686 strcpy(dprefs->PrtDevName, "parallel");
687 } else if (uprefs->pp_Txt.pt_Port == PP_SERIAL) {
688 strcpy(dprefs->PrtDevName, "serial");
689 } else {
690 strcpy(dprefs->PrtDevName, "printtofile");
692 } else {
693 strncpy(dprefs->PrtDevName, uprefs->pp_Unit.pu_DeviceName, sizeof(dprefs->PrtDevName));
694 dprefs->PrtDevName[sizeof(dprefs->PrtDevName)-1]=0;
697 if (strcmp(dprefs->PrtDevName, "parallel") == 0 ||
698 strcmp(dprefs->PrtDevName, "usbparallel") == 0) {
699 pd->pd_ior0.pd_p0.IOPar.io_Message.mn_Length = sizeof(pd->pd_ior0.pd_p0);
700 pd->pd_ior0.pd_p0.io_ParFlags = PARF_SHARED;
701 pd->pd_ior1.pd_p1.IOPar.io_Message.mn_Length = sizeof(pd->pd_ior1.pd_p1);
702 pd->pd_ior1.pd_p1.io_ParFlags = PARF_SHARED;
703 } else if (strcmp(dprefs->PrtDevName, "serial") == 0) {
704 pd->pd_ior0.pd_s0.IOSer.io_Message.mn_Length = sizeof(pd->pd_ior0.pd_s0);
705 pd->pd_ior0.pd_s0.io_SerFlags = SERF_SHARED;
706 pd->pd_ior1.pd_s1.IOSer.io_Message.mn_Length = sizeof(pd->pd_ior1.pd_s1);
707 pd->pd_ior1.pd_s1.io_SerFlags = SERF_SHARED;
708 } else {
709 pd->pd_ior0.pd_i0.io_Message.mn_Length = sizeof(pd->pd_ior0.pd_i0);
710 pd->pd_ior1.pd_i1.io_Message.mn_Length = sizeof(pd->pd_ior1.pd_i1);
713 dprefs->DefaultPrtUnit = uprefs->pp_Unit.pu_UnitNum;
714 dprefs->PrintFlags = uprefs->pp_Gfx.pg_GraphicFlags;
715 dprefs->PrintMaxWidth = uprefs->pp_Gfx.pg_PrintMaxWidth;
716 dprefs->PrintMaxHeight = uprefs->pp_Gfx.pg_PrintMaxHeight;
717 dprefs->PrintDensity = uprefs->pp_Gfx.pg_PrintDensity;
718 dprefs->PrintXOffset = uprefs->pp_Gfx.pg_PrintXOffset;
721 /* Create a PrinterData plugin
723 struct PrinterUnit *Printer_Unit(struct PrinterBase *PrinterBase, LONG unitnum)
725 struct PrinterUnit *pu;
726 struct PrinterPrefs prefs;
727 BPTR olddir, dir, driverseg;
729 if (!Printer_LoadPrefs(PrinterBase, unitnum, &prefs) || prefs.pp_Txt.pt_Driver[0] == 0) {
730 D(bug("%s: No valid prefs for printer.device %d\n", __func__, unitnum));
731 return NULL;
734 if ((dir = Lock("DEVS:Printers", SHARED_LOCK)) != BNULL) {
735 olddir = CurrentDir(dir);
736 driverseg = LoadSeg(prefs.pp_Txt.pt_Driver);
737 CurrentDir(olddir);
738 UnLock(dir);
740 D(bug("%s: %s => %p\n", __func__, prefs.pp_Txt.pt_Driver, BADDR(driverseg)));
742 if (driverseg) {
743 struct PrinterSegment *prtseg = BADDR(driverseg);
745 D(bug("%s: magic 0x%08x, expect 0x%08x\n", __func__, prtseg->ps_runAlert, AROS_PRINTER_MAGIC));
746 if (prtseg->ps_runAlert == AROS_PRINTER_MAGIC) {
747 APTR funcs[] = {
748 AROS_SLIB_ENTRY(OpenDevice,PrinterUnit,1),
749 AROS_SLIB_ENTRY(CloseDevice,PrinterUnit,2),
750 AROS_SLIB_ENTRY(Expunge,PrinterUnit,3),
751 NULL,
752 AROS_SLIB_ENTRY(BeginIO,PrinterUnit,5),
753 AROS_SLIB_ENTRY(AbortIO,PrinterUnit,6),
754 (APTR)-1,
757 if ((pu = (struct PrinterUnit *)MakeLibrary(funcs, NULL, NULL, sizeof(*pu), driverseg))) {
758 struct Process *proc;
759 struct PrinterData *pd = &pu->pu_PrinterData;
760 struct Device *dev = (struct Device *)pu;
762 /* Loop back to self */
763 pu->pu_PrinterBase = PrinterBase;
764 pd->pd_PUnit = pu;
766 /* Duplicate the prefs */
767 CopyMem(&prefs, &pu->pu_Prefs, sizeof(prefs));
769 /* Update pd->pd_Preferences from pu->pu_Prefs */
770 pd_SyncPrefs(pd);
772 dev->dd_Library.lib_Node.ln_Name = pu->pu_Prefs.pp_DeviceUnit.pd_UnitName;
773 dev->dd_Library.lib_Version = prtseg->ps_Version;
774 dev->dd_Library.lib_Revision = prtseg->ps_Revision;
775 /* Magic token for TASK_PRINTERDATA() macro */
776 dev->dd_Library.lib_IdString = (APTR)driverID;
778 pd->pd_Device.dd_Segment = BADDR(driverseg);
779 pd->pd_Device.dd_ExecBase = SysBase;
780 pd->pd_Device.dd_CmdVectors = prtseg->ps_PED.ped_Commands;
781 pd->pd_Device.dd_CmdBytes = NULL;
782 pd->pd_Device.dd_NumCommands = aRAW + 1;
783 pd->pd_PrinterSegment = driverseg;
784 pd->pd_PrinterType = 0;
785 pd->pd_SegmentData = prtseg;
786 pd->pd_PWrite = pd_PWrite;
787 pd->pd_PBothReady = pd_PBothReady;
788 pd->pd_PRead = pd_PRead;
789 pd->pd_CallErrHook = (APTR)pd_CallErrHook;
790 pd->pd_PQuery = pd_PQuery;
791 pd->pd_UnitNumber = unitnum;
792 pd->pd_DriverName = &pd->pd_Preferences.PrinterFilename[0];
794 /* Make RemDevice() and friends happy */
795 AddDevice(dev);
797 proc = CreateNewProcTags(NP_Entry, pd_DriverTask,
798 NP_Name, prefs.pp_DeviceUnit.pd_UnitName,
799 NP_Priority, 0,
800 NP_Arguments, NULL,
801 NP_UserData, pd);
803 D(bug("%s: Driver process %p\n", __func__, proc));
804 if (proc != NULL) {
805 struct MsgPort *port;
807 /* Store the process here... */
808 pu->pu_Process = proc;
811 if ((port = CreateMsgPort())) {
812 struct PrinterMessage startup, *reply;
814 D(bug("%s: Driver unit port %p\n", __func__, port));
815 startup.mm_Message.mn_ReplyPort=port;
816 startup.mm_Message.mn_Length = sizeof(startup);
817 startup.mm_Magic = AROS_MAKE_ID('p','r','u','n');
818 startup.mm_Version = 0;
819 PutMsg(&proc->pr_MsgPort, (struct Message *)&startup);
820 WaitPort(port);
821 D(bug("%s: Driver replied\n", __func__));
822 reply = (struct PrinterMessage *)GetMsg(port);
823 D(bug("%s: Driver reply = %p\n", __func__, reply));
824 DeleteMsgPort(port);
825 D(bug("%s: Driver port %p gone\n", __func__, port));
826 if (reply == &startup &&
827 reply->mm_Message.mn_Length == sizeof(*reply) &&
828 reply->mm_Magic == AROS_MAKE_ID('p','r','u','n') &&
829 reply->mm_Version == 0) {
830 /* Success! */
831 D(bug("%s: Driver started\n", __func__));
832 return pu;
834 D(bug("%s: Driver startup failed\n", __func__));
836 /* pd_DriverTask will kill itself on failure */
838 /* pd_Expunge() calls UnLoadSeg() automatically */
839 RemDevice((struct Device *)pd);
840 driverseg = BNULL;
843 if (driverseg)
844 UnLoadSeg(driverseg);
848 return NULL;