printer.device: Fix hang due to race condition exposed by port-handler
[AROS.git] / workbench / devs / printer / driver.c
blob9f906b955b0a7daf77b32d9dbc7ddc86b4853fbe
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 CMD_OPENDEVICE (0x100)
25 #define CMD_CLOSEDEVICE (0x101)
27 #include LC_LIBDEFS_FILE
29 #include "printer_intern.h"
31 /* pd_Flags values */
32 #define PDF_IOREQ (1 << 0) /* IORequest 0 or 1 */
33 #define PDF_NOIO (1 << 1) /* PRTA_NoIO was true */
34 #define PDF_CONVERT (1 << 2) /* PRTA_ConvertSource was true */
35 #define PDF_8BITGUNS (1 << 3) /* PRTA_8BitGuns was true */
37 const TEXT driverID[] = "printer.driver";
39 const struct EasyStruct driverMisuse = { \
40 .es_StructSize = sizeof(struct EasyStruct),
41 .es_Flags = 0,
42 .es_Title = "Improper use of printer.device",
43 .es_TextFormat = "\"%s\" attempted to use the private\n"
44 "printer.driver method %s.\n"
45 "Only CMD_RAWWRITE is supported.\n",
46 .es_GadgetFormat = "Ok",
49 #define TASK_PRINTERDATA(pd) \
50 struct PrinterData *pd =(struct PrinterData *)FindTask(NULL)->tc_UserData; \
51 if (pd == NULL || \
52 pd->pd_Device.dd_Device.lib_Node.ln_Type != NT_DEVICE || \
53 pd->pd_Device.dd_Device.lib_IdString != driverID) { \
54 struct Library *IntuitionBase; \
55 if ((IntuitionBase = TaggedOpenLibrary(TAGGEDOPEN_INTUITION))) { \
56 IPTR args[] = { (IPTR)FindTask(NULL)->tc_Node.ln_Name, \
57 (IPTR)__func__ }; \
58 EasyRequestArgs(NULL, (struct EasyStruct *)&driverMisuse, \
59 0, args); \
60 CloseLibrary(IntuitionBase); \
61 } \
62 return IOERR_NOCMD; \
66 static BOOL initMsgPort(struct MsgPort *port)
68 BYTE sb = AllocSignal(-1);
70 if (sb < 0)
71 return FALSE;
73 port->mp_SigBit = sb;
74 port->mp_SigTask = FindTask(NULL);
75 port->mp_Flags = PA_SIGNAL;
76 port->mp_Node.ln_Type = NT_MSGPORT;
77 NEWLIST(&port->mp_MsgList);
79 return TRUE;
82 STATIC AROS_LH3(LONG, OpenDevice,
83 AROS_LHA(struct IORequest *, io, A1),
84 AROS_LHA(IPTR, unitNumber, D0),
85 AROS_LHA(ULONG, flags, D1),
86 struct PrinterUnit *, pu, 1, PrinterUnit)
88 AROS_LIBFUNC_INIT
90 struct MsgPort *reply;
92 if ((reply = CreateMsgPort())) {
93 struct IORequest ior = *io;
94 ior.io_Message.mn_ReplyPort = reply;
95 ior.io_Command = CMD_OPENDEVICE;
96 return DoIO(&ior);
99 return IOERR_OPENFAIL;
101 AROS_LIBFUNC_EXIT
104 STATIC AROS_LH1(BPTR, CloseDevice,
105 AROS_LCA(struct IORequest *,io, A1),
106 struct PrinterUnit *, pu, 2, PrinterUnit)
108 AROS_LIBFUNC_INIT
110 struct MsgPort *reply;
112 if ((reply = CreateMsgPort())) {
113 struct IORequest ior = *io;
114 ior.io_Message.mn_ReplyPort = reply;
115 ior.io_Command = CMD_CLOSEDEVICE;
116 DoIO(&ior);
117 return AROS_LC1(BPTR, Expunge,
118 AROS_LCA(struct PrinterUnit *, pu, D0),
119 struct PrinterUnit *, pu, 3, PrinterUnit);
122 return BNULL;
124 AROS_LIBFUNC_EXIT
127 STATIC AROS_LH1(BPTR, Expunge,
128 AROS_LHA(struct Library *, extralib, D0),
129 struct PrinterUnit *, pu, 3, PrinterUnit)
131 AROS_LIBFUNC_INIT
133 struct Library *lib = (struct Library *)pu;
135 if (lib->lib_OpenCnt == 0) {
136 BPTR seg = pu->pu_PrinterData.pd_PrinterSegment;
138 Remove((struct Node *)lib);
139 FreeMem((UBYTE *)lib - lib->lib_NegSize,
140 (ULONG) (lib->lib_NegSize +
141 lib->lib_PosSize));
143 D(bug("%s: Return segment %p\n", __func__, BADDR(seg)));
144 return seg;
147 lib->lib_Flags |= LIBF_DELEXP;
149 return BNULL;
151 AROS_LIBFUNC_EXIT
155 STATIC AROS_LH1(void, BeginIO,
156 AROS_LHA(union printerIO *, pio, A1),
157 struct PrinterUnit *, pu, 5, PrinterUnit)
159 AROS_LIBFUNC_INIT
161 struct IOStdReq *io = &pio->ios;
162 struct PrinterData *pd = &pu->pu_PrinterData;
164 D(bug("BeginIO: io_Command = %d, Unit Port %p\n", io->io_Command, &pd->pd_Unit));
166 io->io_Flags &= ~IOF_QUICK;
167 PutMsg(&pd->pd_Unit, &io->io_Message);
169 return;
171 AROS_LIBFUNC_EXIT
174 STATIC AROS_LH1(LONG, AbortIO,
175 AROS_LHA(struct IORequest *, pio, A1),
176 struct PrinterUnit *, pd, 6, PrinterUnit)
178 AROS_LIBFUNC_INIT
179 return IOERR_NOCMD;
180 AROS_LIBFUNC_EXIT
183 /* These wrappers make sure that we don't
184 * make WaitIO() hang or corrupt memory
185 * if called on an already completed IO
187 static inline LONG WaitIOStd(struct IOStdReq *io)
189 WaitIO((struct IORequest *)io);
190 io->io_Message.mn_Node.ln_Type = 0;
191 return io->io_Error;
194 static inline LONG DoIOStd(struct IOStdReq *io)
196 DoIO((struct IORequest *)io);
197 io->io_Message.mn_Node.ln_Type = 0;
198 return io->io_Error;
201 static LONG pd_PWrite(APTR data, LONG len)
203 struct IOStdReq *io;
204 TASK_PRINTERDATA(pd);
206 if (pd->pd_Flags & PDF_NOIO)
207 return IOERR_OPENFAIL;
209 io = (pd->pd_Flags & PDF_IOREQ) ?
210 (struct IOStdReq *)&pd->pd_ior1 :
211 (struct IOStdReq *)&pd->pd_ior0;
212 bug("%s: '%s'@%p (%d), io %d\n", __func__, data, data, len, pd->pd_Flags & PDF_IOREQ);
213 WaitIOStd(io);
214 /* TODO: Call error hook if there is an error */
215 io->io_Command = CMD_WRITE;
216 io->io_Flags = 0;
217 io->io_Actual = 0;
218 io->io_Length = len;
219 io->io_Data = data;
220 io->io_Offset = 0;
221 io->io_Message.mn_Length = sizeof(*io);
222 SendIO((struct IORequest *)io);
224 pd->pd_Flags ^= PDF_IOREQ;
226 return 0;
229 static LONG pd_PBothReady(VOID)
231 TASK_PRINTERDATA(pd);
233 D(bug("%s:\n", __func__));
234 if (pd->pd_Flags & PDF_NOIO)
235 return IOERR_OPENFAIL;
237 WaitIOStd((struct IOStdReq *)&pd->pd_ior0);
238 WaitIOStd((struct IOStdReq *)&pd->pd_ior1);
240 return 0;
243 static LONG pd_PRead(char * buffer, LONG *length, struct timeval *tv)
245 ULONG sigs;
246 struct IOStdReq *io;
247 LONG err;
248 TASK_PRINTERDATA(pd);
250 if (pd->pd_Flags & PDF_NOIO)
251 return IOERR_OPENFAIL;
253 D(bug("%s:\n", __func__));
254 io = (pd->pd_Flags & PDF_IOREQ) ?
255 (struct IOStdReq *)&pd->pd_ior1 :
256 (struct IOStdReq *)&pd->pd_ior0;
257 WaitIOStd(io);
258 /* TODO: Call error hook if there is an error */
259 pd->pd_TIOR.tr_node.io_Command = TR_ADDREQUEST;
260 pd->pd_TIOR.tr_node.io_Flags = 0;
261 pd->pd_TIOR.tr_node.io_Message.mn_Length = sizeof(pd->pd_TIOR);
262 pd->pd_TIOR.tr_time = *tv;
263 SendIO((struct IORequest *)&pd->pd_TIOR);
265 io->io_Command = CMD_READ;
266 io->io_Flags = 0;
267 io->io_Actual = 0;
268 io->io_Length = *length;
269 io->io_Data = buffer;
270 io->io_Offset = 0;
271 io->io_Message.mn_Length = sizeof(*io);
272 SendIO((struct IORequest *)io);
273 sigs = Wait((1 << io->io_Message.mn_ReplyPort->mp_SigBit) |
274 (1 << pd->pd_IORPort.mp_SigBit));
275 if (sigs & (1 << pd->pd_IORPort.mp_SigBit)) {
276 WaitIO((struct IORequest *)&pd->pd_TIOR);
277 if (!CheckIO((struct IORequest *)io))
278 AbortIO((struct IORequest *)io);
280 WaitIOStd(io);
281 err = io->io_Error;
282 if (err == 0)
283 *length = io->io_Actual;
285 /* No need to swap units, as this one has been completed */
287 return err;
290 static LONG pd_CallErrHook(struct Hook *hook, union printerIO *ior, struct PrtErrMsg *pem)
292 /* TODO */
293 return 0;
296 /* Only designed to work on the serial port. */
297 static LONG pd_PQuery(LONG *numofchars)
299 LONG err;
300 struct IOStdReq *io;
302 TASK_PRINTERDATA(pd);
304 if (pd->pd_Flags & PDF_NOIO)
305 return IOERR_OPENFAIL;
307 D(bug("%s:\n", __func__));
308 io = (pd->pd_Flags & PDF_IOREQ) ?
309 (struct IOStdReq *)&pd->pd_ior1 :
310 (struct IOStdReq *)&pd->pd_ior0;
311 WaitIOStd(io);
312 /* TODO: Call error hook if there is an error */
313 io->io_Command = SDCMD_QUERY;
314 io->io_Flags = 0;
315 io->io_Actual = 0;
316 io->io_Length = 0;
317 io->io_Data = NULL;
318 io->io_Offset = 0;
319 io->io_Message.mn_Length = sizeof(*io);
320 err = DoIOStd(io);
321 if (err == 0)
322 *numofchars = io->io_Actual;
323 else
324 *numofchars = 0;
326 /* No need to swap units, as this one has been completed */
328 return err;
331 /* Only designed to work on the serial and parallel port. */
332 static LONG pd_Query(struct IOStdReq *sio)
334 LONG err;
335 struct IOStdReq *io;
337 TASK_PRINTERDATA(pd);
339 D(bug("%s:\n", __func__));
340 if (pd->pd_PUnit->pu_Prefs.pp_Unit.pu_DeviceName[0] != 0 ||
341 (pd->pd_Flags & PDF_NOIO)) {
342 sio->io_Actual = 0;
343 return IOERR_OPENFAIL;
346 io = (pd->pd_Flags & PDF_IOREQ) ?
347 (struct IOStdReq *)&pd->pd_ior1 :
348 (struct IOStdReq *)&pd->pd_ior0;
349 WaitIOStd(io);
350 /* TODO: Call error hook if there is an error */
351 io->io_Command = SDCMD_QUERY;
352 io->io_Flags = 0;
353 io->io_Actual = 0;
354 io->io_Length = 0;
355 io->io_Data = NULL;
356 io->io_Offset = 0;
357 io->io_Message.mn_Length = sizeof(*io);
358 err = DoIOStd(io);
359 if (err == 0) {
360 UBYTE *data = sio->io_Data;
361 if (data) {
362 UWORD status;
364 switch (pd->pd_PUnit->pu_Prefs.pp_Txt.pt_Port) {
365 case PP_SERIAL:
366 status = ((struct IOExtSer *)io)->io_Status;
367 break;
368 case PP_PARALLEL:
369 status = ((struct IOExtPar *)io)->io_Status;
370 break;
371 default:
372 status = 0;
373 break;
375 data[0] = (status >> 0) & 0xff;
376 data[1] = (status >> 8) & 0xff;
378 sio->io_Actual = pd->pd_PUnit->pu_Prefs.pp_Txt.pt_Port + 1;
381 /* No need to swap units, as this one has been completed */
383 return err;
386 static LONG pd_Init(struct PrinterData *pd)
388 struct PrinterExtendedData *ped = &pd->pd_SegmentData->ps_PED;
389 TEXT devname[sizeof(pd->pd_Preferences.PrtDevName) + 7 + 1];
391 /* Initialize the unit */
392 strcpy(devname, pd->pd_Preferences.PrtDevName);
393 strcat(devname, ".device");
395 D(bug("%s: create msgport %p\n", __func__, &pd->pd_Unit));
396 if (initMsgPort(&pd->pd_Unit)) {
397 D(bug("%s: Call ped_Init => %p\n", __func__, pd->pd_SegmentData->ps_PED.ped_Init));
398 if (0 == pd->pd_SegmentData->ps_PED.ped_Init(pd)) {
399 if (pd->pd_Flags & PDF_NOIO)
400 return 0;
402 if ((pd->pd_ior0.pd_p0.IOPar.io_Message.mn_ReplyPort=CreateMsgPort())) {
403 pd->pd_ior0.pd_p0.IOPar.io_Message.mn_Length = sizeof(pd->pd_ior0);
404 if (0 == OpenDevice(devname,
405 pd->pd_Preferences.DefaultPrtUnit,
406 (struct IORequest *)&pd->pd_ior0, 0)) {
407 D(bug("%s: open %s %d for io 0\n", __func__, devname, pd->pd_Preferences.DefaultPrtUnit));
408 pd->pd_ior0.pd_p0.IOPar.io_Message.mn_Node.ln_Type = 0;
409 if ((pd->pd_ior1.pd_p1.IOPar.io_Message.mn_ReplyPort=CreateMsgPort())) {
410 pd->pd_ior1.pd_p1.IOPar.io_Message.mn_Length = sizeof(pd->pd_ior1);
411 if (0 == OpenDevice(devname,
412 pd->pd_Preferences.DefaultPrtUnit,
413 (struct IORequest *)&pd->pd_ior1, 0)) {
414 pd->pd_ior1.pd_p1.IOPar.io_Message.mn_Node.ln_Type = 0;
415 D(bug("%s: open %s %d for io 1\n", __func__, devname, pd->pd_Preferences.DefaultPrtUnit));
416 if (initMsgPort(&pd->pd_IORPort)) {
417 pd->pd_TIOR.tr_node.io_Message.mn_ReplyPort=&pd->pd_IORPort;
418 pd->pd_TIOR.tr_node.io_Message.mn_Length = sizeof(pd->pd_TIOR);
419 if (0 == OpenDevice("timer.device", UNIT_VBLANK,
420 (struct IORequest *)&pd->pd_TIOR, 0)) {
421 D(bug("%s: open timer.device %d\n", __func__, UNIT_VBLANK));
422 if (ped->ped_Render) {
423 LONG err = ped->ped_Render(0, 0, 0, PRS_PREINIT);
424 if (err == 0)
425 return 0;
426 } else {
427 return 0;
430 FreeSignal(pd->pd_IORPort.mp_SigBit);
432 CloseDevice((struct IORequest *)&pd->pd_ior1);
434 DeleteMsgPort(pd->pd_ior1.pd_p1.IOPar.io_Message.mn_ReplyPort);
436 CloseDevice((struct IORequest *)&pd->pd_ior0);
438 DeleteMsgPort(pd->pd_ior0.pd_p0.IOPar.io_Message.mn_ReplyPort);
440 pd->pd_SegmentData->ps_PED.ped_Expunge();
442 FreeSignal(pd->pd_Unit.mp_SigBit);
445 return -1;
448 static VOID pd_Close(struct PrinterData *pd, union printerIO *pio)
450 struct PrinterBase *PrinterBase = pd->pd_PUnit->pu_PrinterBase;
451 struct PrinterExtendedData *ped = &pd->pd_SegmentData->ps_PED;
452 LONG unitnum = pd->pd_PUnit->pu_Prefs.pp_DeviceUnit.pd_UnitNum;
454 ped->ped_Close(pio);
456 if (!(pd->pd_Flags & PDF_NOIO)) {
457 CloseDevice((struct IORequest *)&pd->pd_TIOR);
458 FreeSignal(pd->pd_IORPort.mp_SigBit);
459 CloseDevice((struct IORequest *)&pd->pd_ior1);
460 DeleteMsgPort(pd->pd_ior1.pd_p1.IOPar.io_Message.mn_ReplyPort);
461 CloseDevice((struct IORequest *)&pd->pd_ior0);
462 DeleteMsgPort(pd->pd_ior0.pd_p0.IOPar.io_Message.mn_ReplyPort);
464 FreeSignal(pd->pd_Unit.mp_SigBit);
466 ped->ped_Expunge();
468 /* Remove from the parent printer.device */
469 ObtainSemaphore(&PrinterBase->pb_UnitLock[unitnum]);
470 PrinterBase->pb_Unit[unitnum] = NULL;
471 Forbid();
472 PrinterBase->pb_Device.dd_Library.lib_OpenCnt--;
473 Permit();
474 ReleaseSemaphore(&PrinterBase->pb_UnitLock[unitnum]);
477 static LONG pd_DoPreferences(const union printerIO *pio, LONG command)
479 LONG err;
481 TASK_PRINTERDATA(pd);
483 if (pd->pd_SegmentData->ps_Version >= 44 &&
484 (pd->pd_SegmentData->ps_PED.ped_PrinterClass & PPCF_EXTENDED) &&
485 pd->pd_SegmentData->ps_PED.ped_DoPreferences != NULL) {
486 err = pd->pd_SegmentData->ps_PED.ped_DoPreferences((union printerIO *)pio, command);
487 } else {
488 switch (command) {
489 case PRD_RESETPREFS:
490 case PRD_LOADPREFS:
491 case PRD_USEPREFS:
492 case PRD_SAVEPREFS:
493 case PRD_READPREFS:
494 case PRD_WRITEPREFS:
495 case PRD_EDITPREFS:
496 default:
497 err = IOERR_NOCMD;
498 break;
502 return err;
505 /* A driver task is created on an OpenDevice() call,
506 * and is killed by a CloseDevice() call.
508 static LONG pd_DriverTask(VOID)
510 TASK_PRINTERDATA(pd);
512 struct Process *me = (struct Process *)FindTask(NULL);
513 struct PrinterExtendedData *ped = &pd->pd_SegmentData->ps_PED;
514 struct MagicMessage *msg = NULL;
515 union printerIO *pio;
516 UWORD cmd;
517 BOOL stopped = FALSE;
518 LONG ret;
520 /* Wait for startup message -
521 * we use the DOS port because the
522 * pd_Unit has not been created yet
524 D(bug("%s: Waiting for startup. pd=%p\n", __func__, pd));
525 WaitPort(&me->pr_MsgPort);
526 msg = (struct MagicMessage *)GetMsg(&me->pr_MsgPort);
528 D(bug("%s: Initializing driver, Unit Port %p\n", __func__, &pd->pd_Unit));
529 ret = pd_Init(pd);
531 D(bug("%s: Replying with %d\n", __func__, ret));
532 msg->mn_Version = ret;
533 ReplyMsg((struct Message *)msg);
535 if (0 != ret)
536 return ret;
538 /* Wait for unit messages on the pd_Unit */
539 do {
540 LONG err = 0;
542 D(bug("%s: Waiting for command on port %p\n", __func__, &pd->pd_Unit));
543 WaitPort(&pd->pd_Unit);
544 pio = (union printerIO *)GetMsg(&pd->pd_Unit);
545 cmd = pio->ios.io_Command;
547 D(bug("%s: Command = %d\n", __func__, cmd));
548 switch (cmd) {
549 case CMD_OPENDEVICE:
550 err = ped->ped_Open(pio);
551 if (err == 0)
552 Printer_Text_Write(pd, "\033#1", 3); /* aRIN */
553 break;
554 case CMD_CLOSEDEVICE:
555 pd_Close(pd, pio);
556 break;
557 case CMD_FLUSH:
558 AbortIO((struct IORequest *)&pd->pd_ior0);
559 WaitIOStd((struct IOStdReq *)&pd->pd_ior0);
560 AbortIO((struct IORequest *)&pd->pd_ior1);
561 WaitIOStd((struct IOStdReq *)&pd->pd_ior1);
562 break;
563 case CMD_RESET:
564 if (stopped)
565 err = PDERR_CANCEL;
566 else {
567 err = Printer_Text_Command(pd, aRIN, 0, 0, 0, 0);
569 break;
570 case CMD_STOP:
571 stopped = TRUE;
572 break;
573 case CMD_START:
574 stopped = FALSE;
575 break;
576 case CMD_WRITE:
577 if (stopped)
578 err = PDERR_CANCEL;
579 else {
580 err = Printer_Text_Write(pd, pio->ios.io_Data, pio->ios.io_Length);
581 if (err == 0)
582 pio->ios.io_Actual = pio->ios.io_Length;
584 break;
585 case PRD_RAWWRITE:
586 if (stopped)
587 err = PDERR_CANCEL;
588 else {
589 err = pd_PWrite(pio->ios.io_Data, pio->ios.io_Length);
590 if (err == 0)
591 pio->ios.io_Actual = pio->ios.io_Length;
593 break;
594 case PRD_RESETPREFS:
595 case PRD_LOADPREFS:
596 case PRD_USEPREFS:
597 case PRD_SAVEPREFS:
598 case PRD_READPREFS:
599 case PRD_EDITPREFS:
600 err = pd_DoPreferences(pio, pio->ios.io_Command);
601 break;
602 case PRD_SETERRHOOK:
603 pd->pd_PUnit->pu_ErrHook = ((struct IOPrtErrReq *)pio)->io_Hook;
604 break;
605 case PRD_DUMPRPORTTAGS:
606 if (stopped)
607 err = PDERR_CANCEL;
608 else
609 err = Printer_Gfx_DumpRPort((struct IODRPReq *)pio, ((struct IODRPTagsReq *)pio)->io_TagList);
610 break;
611 case PRD_DUMPRPORT:
612 if (stopped)
613 err = PDERR_CANCEL;
614 else
615 err = Printer_Gfx_DumpRPort((struct IODRPReq *)pio, NULL);
616 break;
617 case PRD_QUERY:
618 err = pd_Query(&pio->ios);
619 break;
620 default:
621 err = IOERR_NOCMD;
622 break;
624 pio->ios.io_Error = err;
625 D(bug("%s: Command = %d, Result = %d\n", __func__, cmd, err));
627 ReplyMsg((struct Message *)pio);
628 } while (cmd != CMD_CLOSEDEVICE);
630 D(bug("%s: Shutting down\n", __func__));
632 return 0;
635 /* Synchronize old-style prefs with new style prefs
637 static void pd_SyncPrefs(struct PrinterData *pd)
639 struct Preferences *dprefs = &pd->pd_Preferences;
640 struct PrinterPrefs *uprefs = &pd->pd_PUnit->pu_Prefs;
642 dprefs->PrinterType = pd->pd_PrinterType;
644 strncpy(dprefs->PrinterFilename, uprefs->pp_Txt.pt_Driver,
645 sizeof(dprefs->PrinterFilename));
646 dprefs->PrinterFilename[sizeof(dprefs->PrinterFilename)-1] = 0;
648 dprefs->PrintPitch = uprefs->pp_Txt.pt_Pitch;
649 dprefs->PrintQuality = uprefs->pp_Txt.pt_Quality;
650 dprefs->PrintSpacing = uprefs->pp_Txt.pt_Spacing;
651 dprefs->PrintLeftMargin = uprefs->pp_Txt.pt_LeftMargin;
652 dprefs->PrintRightMargin = uprefs->pp_Txt.pt_RightMargin;
653 dprefs->PrintImage = uprefs->pp_Gfx.pg_Image;
654 dprefs->PrintAspect = uprefs->pp_Gfx.pg_Aspect;
655 dprefs->PrintShade = uprefs->pp_Gfx.pg_Shade;
656 dprefs->PrintThreshold = uprefs->pp_Gfx.pg_Threshold;
657 dprefs->PaperSize = uprefs->pp_Txt.pt_PaperSize;
658 dprefs->PaperType = uprefs->pp_Txt.pt_PaperType;
659 dprefs->PaperLength = uprefs->pp_Txt.pt_PaperLength;
661 if (uprefs->pp_Unit.pu_DeviceName[0] == 0) {
662 if (uprefs->pp_Txt.pt_Port == PP_PARALLEL) {
663 strcpy(dprefs->PrtDevName, "parallel");
664 } else if (uprefs->pp_Txt.pt_Port == PP_SERIAL) {
665 strcpy(dprefs->PrtDevName, "serial");
666 } else {
667 strcpy(dprefs->PrtDevName, "printtofile");
669 } else {
670 strncpy(dprefs->PrtDevName, uprefs->pp_Unit.pu_DeviceName, sizeof(dprefs->PrtDevName));
671 dprefs->PrtDevName[sizeof(dprefs->PrtDevName)-1]=0;
674 dprefs->DefaultPrtUnit = uprefs->pp_Unit.pu_UnitNum;
675 dprefs->PrintFlags = uprefs->pp_Gfx.pg_GraphicFlags;
676 dprefs->PrintMaxWidth = uprefs->pp_Gfx.pg_PrintMaxWidth;
677 dprefs->PrintMaxHeight = uprefs->pp_Gfx.pg_PrintMaxHeight;
678 dprefs->PrintDensity = uprefs->pp_Gfx.pg_PrintDensity;
679 dprefs->PrintXOffset = uprefs->pp_Gfx.pg_PrintXOffset;
682 /* Create a PrinterData plugin
684 struct PrinterUnit *Printer_Unit(struct PrinterBase *PrinterBase, LONG unitnum)
686 struct PrinterUnit *pu;
687 struct PrinterPrefs prefs;
688 BPTR olddir, dir, driverseg;
690 if (!Printer_LoadPrefs(PrinterBase, unitnum, &prefs) || prefs.pp_Txt.pt_Driver[0] == 0) {
691 D(bug("%s: No valid prefs for printer.device %d\n", __func__, unitnum));
692 return NULL;
695 if ((dir = Lock("DEVS:Printers", SHARED_LOCK)) != BNULL) {
696 olddir = CurrentDir(dir);
697 driverseg = LoadSeg(prefs.pp_Txt.pt_Driver);
698 CurrentDir(olddir);
699 UnLock(dir);
701 D(bug("%s: %s => %p\n", __func__, prefs.pp_Txt.pt_Driver, BADDR(driverseg)));
703 if (driverseg) {
704 struct PrinterSegment *prtseg = BADDR(driverseg);
706 D(bug("%s: magic 0x%08x, expect 0x%08x\n", __func__, prtseg->ps_runAlert, AROS_PRINTER_MAGIC));
707 if (prtseg->ps_runAlert == AROS_PRINTER_MAGIC) {
708 APTR funcs[] = {
709 AROS_SLIB_ENTRY(OpenDevice,PrinterUnit,1),
710 AROS_SLIB_ENTRY(CloseDevice,PrinterUnit,2),
711 AROS_SLIB_ENTRY(Expunge,PrinterUnit,3),
712 NULL,
713 AROS_SLIB_ENTRY(BeginIO,PrinterUnit,5),
714 AROS_SLIB_ENTRY(AbortIO,PrinterUnit,6),
715 (APTR)-1,
718 if ((pu = (struct PrinterUnit *)MakeLibrary(funcs, NULL, NULL, sizeof(*pu), driverseg))) {
719 struct Process *proc;
720 struct PrinterData *pd = &pu->pu_PrinterData;
721 struct Device *dev = (struct Device *)pu;
723 /* Loop back to self */
724 pu->pu_PrinterBase = PrinterBase;
725 pd->pd_PUnit = pu;
727 /* Duplicate the prefs */
728 CopyMem(&prefs, &pu->pu_Prefs, sizeof(prefs));
730 /* Update pd->pd_Preferences from pu->pu_Prefs */
731 pd_SyncPrefs(pd);
733 dev->dd_Library.lib_Node.ln_Name = pu->pu_Prefs.pp_DeviceUnit.pd_UnitName;
734 dev->dd_Library.lib_Version = prtseg->ps_Version;
735 dev->dd_Library.lib_Revision = prtseg->ps_Revision;
736 /* Magic token for TASK_PRINTERDATA() macro */
737 dev->dd_Library.lib_IdString = (APTR)driverID;
739 pd->pd_Device.dd_Segment = BADDR(driverseg);
740 pd->pd_Device.dd_ExecBase = SysBase;
741 pd->pd_Device.dd_CmdVectors = prtseg->ps_PED.ped_Commands;
742 pd->pd_Device.dd_CmdBytes = NULL;
743 pd->pd_Device.dd_NumCommands = aRAW + 1;
744 pd->pd_PrinterSegment = driverseg;
745 pd->pd_PrinterType = 0;
746 pd->pd_SegmentData = prtseg;
747 pd->pd_PWrite = pd_PWrite;
748 pd->pd_PBothReady = pd_PBothReady;
749 pd->pd_PRead = pd_PRead;
750 pd->pd_CallErrHook = (APTR)pd_CallErrHook;
751 pd->pd_PQuery = pd_PQuery;
752 pd->pd_UnitNumber = unitnum;
753 pd->pd_DriverName = &pd->pd_Preferences.PrinterFilename[0];
755 /* Make RemDevice() and friends happy */
756 AddDevice(dev);
758 proc = CreateNewProcTags(NP_Entry, pd_DriverTask,
759 NP_Name, prefs.pp_DeviceUnit.pd_UnitName,
760 NP_Priority, 0,
761 NP_Arguments, NULL,
762 NP_UserData, pd);
764 D(bug("%s: Driver process %p\n", __func__, proc));
765 if (proc != NULL) {
766 struct MsgPort *port;
768 /* Store the process here... */
769 pu->pu_Process = proc;
772 if ((port = CreateMsgPort())) {
773 struct MagicMessage startup, *reply;
775 D(bug("%s: Driver unit port %p\n", __func__, port));
776 startup.mn_ReplyPort=port;
777 startup.mn_Length = sizeof(startup);
778 startup.mn_Magic = AROS_MAKE_ID('p','r','u','n');
779 startup.mn_Version = 0;
780 PutMsg(&proc->pr_MsgPort, (struct Message *)&startup);
781 WaitPort(port);
782 D(bug("%s: Driver replied\n", __func__));
783 reply = (struct MagicMessage *)GetMsg(port);
784 D(bug("%s: Driver reply = %p\n", __func__, reply));
785 DeleteMsgPort(port);
786 D(bug("%s: Driver port %p gone\n", __func__, port));
787 if (reply == &startup &&
788 reply->mn_Length == sizeof(*reply) &&
789 reply->mn_Magic == AROS_MAKE_ID('p','r','u','n') &&
790 reply->mn_Version == 0) {
791 /* Success! */
792 D(bug("%s: Driver started\n", __func__));
793 return pu;
795 D(bug("%s: Driver startup failed\n", __func__));
797 /* pd_DriverTask will kill itself on failure */
799 /* pd_Expunge() calls UnLoadSeg() automatically */
800 RemDevice((struct Device *)pd);
801 driverseg = BNULL;
804 if (driverseg)
805 UnLoadSeg(driverseg);
809 return NULL;