revert between 56095 -> 55830 in arch
[AROS.git] / workbench / devs / printer / driver.c
blobc48c1a6a68c69027f8d300c1fe73d744a3be821e
1 /*
2 * Copyright (C) 2012-2017, 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 CONST_STRPTR args[] = { FindTask(NULL)->tc_Node.ln_Name, \
67 __func__ }; \
68 EasyRequestArgs(NULL, (struct EasyStruct *)&driverMisuse, \
69 0, (RAWARG)&args[0]); \
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 memset( port, 0, sizeof( *port ) );
84 port->mp_SigBit = sb;
85 port->mp_SigTask = FindTask(NULL);
86 port->mp_Flags = PA_SIGNAL;
87 port->mp_Node.ln_Type = NT_MSGPORT;
88 NEWLIST(&port->mp_MsgList);
90 return TRUE;
93 STATIC AROS_LH3(LONG, OpenDevice,
94 AROS_LHA(struct IORequest *, io, A1),
95 AROS_LHA(IPTR, unitNumber, D0),
96 AROS_LHA(ULONG, flags, D1),
97 struct PrinterUnit *, pu, 1, PrinterUnit)
99 AROS_LIBFUNC_INIT
101 struct MsgPort *mp;
102 LONG ret = IOERR_OPENFAIL;
104 if ((mp = CreateMsgPort())) {
105 struct IORequest ior = *io;
106 ior.io_Message.mn_ReplyPort = mp;
107 ior.io_Command = CMD_OPENDEVICE;
108 ret = DoIO(&ior);
109 DeleteMsgPort(mp);
112 return ret;
114 AROS_LIBFUNC_EXIT
117 STATIC AROS_LH1(BPTR, CloseDevice,
118 AROS_LCA(struct IORequest *,io, A1),
119 struct PrinterUnit *, pu, 2, PrinterUnit)
121 AROS_LIBFUNC_INIT
123 BPTR ret = BNULL;
124 struct MsgPort *mp;
126 if ((mp = CreateMsgPort())) {
127 struct IORequest ior = *io;
128 ior.io_Message.mn_ReplyPort = mp;
129 ior.io_Command = CMD_CLOSEDEVICE;
130 DoIO(&ior);
131 ret = AROS_LC1(BPTR, Expunge,
132 AROS_LCA(struct PrinterUnit *, pu, D0),
133 struct PrinterUnit *, pu, 3, PrinterUnit);
134 DeleteMsgPort(mp);
137 return ret;
139 AROS_LIBFUNC_EXIT
142 STATIC AROS_LH1(BPTR, Expunge,
143 AROS_LHA(struct Library *, extralib, D0),
144 struct PrinterUnit *, pu, 3, PrinterUnit)
146 AROS_LIBFUNC_INIT
148 struct Library *lib = (struct Library *)pu;
150 if (lib->lib_OpenCnt == 0) {
151 BPTR seg = pu->pu_PrinterData.pd_PrinterSegment;
153 Remove((struct Node *)lib);
154 FreeMem((UBYTE *)lib - lib->lib_NegSize,
155 (ULONG) (lib->lib_NegSize +
156 lib->lib_PosSize));
158 D(bug("%s: Return segment %p\n", __func__, BADDR(seg)));
159 return seg;
162 lib->lib_Flags |= LIBF_DELEXP;
164 return BNULL;
166 AROS_LIBFUNC_EXIT
170 STATIC AROS_LH1(void, BeginIO,
171 AROS_LHA(union printerIO *, pio, A1),
172 struct PrinterUnit *, pu, 5, PrinterUnit)
174 AROS_LIBFUNC_INIT
176 struct IOStdReq *io = &pio->ios;
177 struct PrinterData *pd = &pu->pu_PrinterData;
179 D(bug("BeginIO: io_Command = %d, Unit Port %p\n", io->io_Command, &pd->pd_Unit));
181 io->io_Flags &= ~IOF_QUICK;
182 PutMsg(&pd->pd_Unit, &io->io_Message);
184 return;
186 AROS_LIBFUNC_EXIT
189 STATIC AROS_LH1(LONG, AbortIO,
190 AROS_LHA(struct IORequest *, pio, A1),
191 struct PrinterUnit *, pd, 6, PrinterUnit)
193 AROS_LIBFUNC_INIT
194 return IOERR_NOCMD;
195 AROS_LIBFUNC_EXIT
198 /* These wrappers make sure that we don't
199 * make WaitIO() hang or corrupt memory
200 * if called on an already completed IO
202 static inline LONG WaitIOStd(struct IOStdReq *io)
204 WaitIO((struct IORequest *)io);
205 io->io_Message.mn_Node.ln_Type = 0;
206 return io->io_Error;
209 static inline LONG DoIOStd(struct IOStdReq *io)
211 DoIO((struct IORequest *)io);
212 io->io_Message.mn_Node.ln_Type = 0;
213 return io->io_Error;
216 static LONG pd_PWrite(APTR data, LONG len)
218 struct IOStdReq *io;
219 TASK_PRINTERDATA(pd);
221 if (pd->pd_Flags & PDF_NOIO)
222 return IOERR_OPENFAIL;
224 io = (pd->pd_Flags & PDF_IOREQ) ?
225 (struct IOStdReq *)&pd->pd_ior1 :
226 (struct IOStdReq *)&pd->pd_ior0;
227 WaitIOStd(io);
228 /* TODO: Call error hook if there is an error */
229 io->io_Command = CMD_WRITE;
230 io->io_Flags = 0;
231 io->io_Actual = 0;
232 io->io_Length = len;
233 io->io_Data = data;
234 io->io_Offset = 0;
235 io->io_Message.mn_Length = sizeof(*io);
236 SendIO((struct IORequest *)io);
238 pd->pd_Flags ^= PDF_IOREQ;
240 return 0;
243 static LONG pd_PBothReady(VOID)
245 TASK_PRINTERDATA(pd);
247 D(bug("%s:\n", __func__));
248 if (pd->pd_Flags & PDF_NOIO)
249 return IOERR_OPENFAIL;
251 WaitIOStd((struct IOStdReq *)&pd->pd_ior0);
252 WaitIOStd((struct IOStdReq *)&pd->pd_ior1);
254 return 0;
257 static LONG pd_PRead(char * buffer, LONG *length, struct timeval *tv)
259 ULONG sigs;
260 struct IOStdReq *io;
261 LONG err;
262 TASK_PRINTERDATA(pd);
264 if (pd->pd_Flags & PDF_NOIO)
265 return IOERR_OPENFAIL;
267 D(bug("%s:\n", __func__));
268 io = (pd->pd_Flags & PDF_IOREQ) ?
269 (struct IOStdReq *)&pd->pd_ior1 :
270 (struct IOStdReq *)&pd->pd_ior0;
271 WaitIOStd(io);
272 /* TODO: Call error hook if there is an error */
273 pd->pd_TIOR.tr_node.io_Command = TR_ADDREQUEST;
274 pd->pd_TIOR.tr_node.io_Flags = 0;
275 pd->pd_TIOR.tr_node.io_Message.mn_Length = sizeof(pd->pd_TIOR);
276 pd->pd_TIOR.tr_time = *tv;
277 SendIO((struct IORequest *)&pd->pd_TIOR);
279 io->io_Command = CMD_READ;
280 io->io_Flags = 0;
281 io->io_Actual = 0;
282 io->io_Length = *length;
283 io->io_Data = buffer;
284 io->io_Offset = 0;
285 io->io_Message.mn_Length = sizeof(*io);
286 SendIO((struct IORequest *)io);
287 sigs = Wait((1 << io->io_Message.mn_ReplyPort->mp_SigBit) |
288 (1 << pd->pd_IORPort.mp_SigBit));
289 if (sigs & (1 << pd->pd_IORPort.mp_SigBit)) {
290 WaitIO((struct IORequest *)&pd->pd_TIOR);
291 if (!CheckIO((struct IORequest *)io))
292 AbortIO((struct IORequest *)io);
294 WaitIOStd(io);
295 err = io->io_Error;
296 if (err == 0)
297 *length = io->io_Actual;
299 /* No need to swap units, as this one has been completed */
301 return err;
304 static LONG pd_CallErrHook(struct Hook *hook, union printerIO *ior, struct PrtErrMsg *pem)
306 /* TODO */
307 return 0;
310 /* Only designed to work on the serial port. */
311 static LONG pd_PQuery(LONG *numofchars)
313 LONG err;
314 struct IOStdReq *io;
316 TASK_PRINTERDATA(pd);
318 if (pd->pd_Flags & PDF_NOIO)
319 return IOERR_OPENFAIL;
321 D(bug("%s:\n", __func__));
322 io = (pd->pd_Flags & PDF_IOREQ) ?
323 (struct IOStdReq *)&pd->pd_ior1 :
324 (struct IOStdReq *)&pd->pd_ior0;
325 WaitIOStd(io);
326 /* TODO: Call error hook if there is an error */
327 io->io_Command = SDCMD_QUERY;
328 io->io_Flags = 0;
329 io->io_Actual = 0;
330 io->io_Length = 0;
331 io->io_Data = NULL;
332 io->io_Offset = 0;
333 io->io_Message.mn_Length = sizeof(*io);
334 err = DoIOStd(io);
335 if (err == 0)
336 *numofchars = io->io_Actual;
337 else
338 *numofchars = 0;
340 /* No need to swap units, as this one has been completed */
342 return err;
345 /* Only designed to work on the serial and parallel port. */
346 static LONG pd_Query(struct IOStdReq *sio)
348 LONG err;
349 struct IOStdReq *io;
351 TASK_PRINTERDATA(pd);
353 D(bug("%s:\n", __func__));
354 if (pd->pd_PUnit->pu_Prefs.pp_Unit.pu_DeviceName[0] != 0 ||
355 (pd->pd_Flags & PDF_NOIO)) {
356 sio->io_Actual = 0;
357 return IOERR_OPENFAIL;
360 io = (pd->pd_Flags & PDF_IOREQ) ?
361 (struct IOStdReq *)&pd->pd_ior1 :
362 (struct IOStdReq *)&pd->pd_ior0;
363 WaitIOStd(io);
364 /* TODO: Call error hook if there is an error */
365 io->io_Command = SDCMD_QUERY;
366 io->io_Flags = 0;
367 io->io_Actual = 0;
368 io->io_Length = 0;
369 io->io_Data = NULL;
370 io->io_Offset = 0;
371 io->io_Message.mn_Length = sizeof(*io);
372 err = DoIOStd(io);
373 if (err == 0) {
374 UBYTE *data = sio->io_Data;
375 if (data) {
376 UWORD status;
378 switch (pd->pd_PUnit->pu_Prefs.pp_Txt.pt_Port) {
379 case PP_SERIAL:
380 status = ((struct IOExtSer *)io)->io_Status;
381 break;
382 case PP_PARALLEL:
383 status = ((struct IOExtPar *)io)->io_Status;
384 break;
385 default:
386 status = 0;
387 break;
389 data[0] = (status >> 0) & 0xff;
390 data[1] = (status >> 8) & 0xff;
392 sio->io_Actual = pd->pd_PUnit->pu_Prefs.pp_Txt.pt_Port + 1;
395 /* No need to swap units, as this one has been completed */
397 return err;
400 static LONG pd_Init(struct PrinterData *pd)
402 struct PrinterExtendedData *ped = &pd->pd_SegmentData->ps_PED;
403 TEXT devname[sizeof(pd->pd_Preferences.PrtDevName) + 7 + 1];
405 /* Initialize the unit */
406 strcpy(devname, pd->pd_Preferences.PrtDevName);
407 strcat(devname, ".device");
409 D(bug("%s: create msgport %p\n", __func__, &pd->pd_Unit));
410 if (initMsgPort(&pd->pd_Unit)) {
411 D(bug("%s: Call ped_Init => %p\n", __func__, pd->pd_SegmentData->ps_PED.ped_Init));
412 if (0 == pd->pd_SegmentData->ps_PED.ped_Init(pd)) {
413 if (pd->pd_Flags & PDF_NOIO)
414 return 0;
416 pd->pd_ior0.pd_p0.io_ParFlags = PARF_SHARED;
417 if ((pd->pd_ior0.pd_p0.IOPar.io_Message.mn_ReplyPort=CreateMsgPort())) {
418 if (0 == OpenDevice(devname,
419 pd->pd_Preferences.DefaultPrtUnit,
420 (struct IORequest *)&pd->pd_ior0, 0)) {
421 D(bug("%s: open %s %d for io 0\n", __func__, devname, pd->pd_Preferences.DefaultPrtUnit));
422 pd->pd_ior0.pd_p0.IOPar.io_Message.mn_Node.ln_Type = 0;
424 pd->pd_ior1.pd_p1.io_ParFlags = PARF_SHARED;
425 if ((pd->pd_ior1.pd_p1.IOPar.io_Message.mn_ReplyPort=CreateMsgPort())) {
426 if (0 == OpenDevice(devname,
427 pd->pd_Preferences.DefaultPrtUnit,
428 (struct IORequest *)&pd->pd_ior1, 0)) {
429 pd->pd_ior1.pd_p1.IOPar.io_Message.mn_Node.ln_Type = 0;
430 D(bug("%s: open %s %d for io 1\n", __func__, devname, pd->pd_Preferences.DefaultPrtUnit));
431 if (initMsgPort(&pd->pd_IORPort)) {
432 pd->pd_TIOR.tr_node.io_Message.mn_ReplyPort=&pd->pd_IORPort;
433 pd->pd_TIOR.tr_node.io_Message.mn_Length = sizeof(pd->pd_TIOR);
434 if (0 == OpenDevice("timer.device", UNIT_VBLANK,
435 (struct IORequest *)&pd->pd_TIOR, 0)) {
436 D(bug("%s: open timer.device %d\n", __func__, UNIT_VBLANK));
437 if (ped->ped_Render) {
438 LONG err = ped->ped_Render(0, 0, 0, PRS_PREINIT);
439 if (err == 0)
440 return 0;
441 } else {
442 return 0;
445 FreeSignal(pd->pd_IORPort.mp_SigBit);
447 CloseDevice((struct IORequest *)&pd->pd_ior1);
449 DeleteMsgPort(pd->pd_ior1.pd_p1.IOPar.io_Message.mn_ReplyPort);
451 CloseDevice((struct IORequest *)&pd->pd_ior0);
453 DeleteMsgPort(pd->pd_ior0.pd_p0.IOPar.io_Message.mn_ReplyPort);
455 pd->pd_SegmentData->ps_PED.ped_Expunge();
457 FreeSignal(pd->pd_Unit.mp_SigBit);
460 return -1;
463 static VOID pd_Close(struct PrinterData *pd, union printerIO *pio)
465 struct PrinterBase *PrinterBase = pd->pd_PUnit->pu_PrinterBase;
466 struct PrinterExtendedData *ped = &pd->pd_SegmentData->ps_PED;
467 LONG unitnum = pd->pd_PUnit->pu_Prefs.pp_DeviceUnit.pd_UnitNum;
469 ped->ped_Close(pio);
471 if (!(pd->pd_Flags & PDF_NOIO)) {
472 CloseDevice((struct IORequest *)&pd->pd_TIOR);
473 FreeSignal(pd->pd_IORPort.mp_SigBit);
474 CloseDevice((struct IORequest *)&pd->pd_ior1);
475 DeleteMsgPort(pd->pd_ior1.pd_p1.IOPar.io_Message.mn_ReplyPort);
476 CloseDevice((struct IORequest *)&pd->pd_ior0);
477 DeleteMsgPort(pd->pd_ior0.pd_p0.IOPar.io_Message.mn_ReplyPort);
479 FreeSignal(pd->pd_Unit.mp_SigBit);
481 ped->ped_Expunge();
483 /* Remove from the parent printer.device */
484 ObtainSemaphore(&PrinterBase->pb_UnitLock[unitnum]);
485 PrinterBase->pb_Unit[unitnum] = NULL;
486 Forbid();
487 PrinterBase->pb_Device.dd_Library.lib_OpenCnt--;
488 Permit();
489 ReleaseSemaphore(&PrinterBase->pb_UnitLock[unitnum]);
492 static LONG pd_DoPreferences(const union printerIO *pio, LONG command)
494 LONG err;
496 TASK_PRINTERDATA(pd);
498 if (pd->pd_SegmentData->ps_Version >= 44 &&
499 (pd->pd_SegmentData->ps_PED.ped_PrinterClass & PPCF_EXTENDED) &&
500 pd->pd_SegmentData->ps_PED.ped_DoPreferences != NULL) {
501 err = pd->pd_SegmentData->ps_PED.ped_DoPreferences((union printerIO *)pio, command);
502 } else {
503 switch (command) {
504 case PRD_RESETPREFS:
505 case PRD_LOADPREFS:
506 case PRD_USEPREFS:
507 case PRD_SAVEPREFS:
508 case PRD_READPREFS:
509 case PRD_WRITEPREFS:
510 case PRD_EDITPREFS:
511 default:
512 err = IOERR_NOCMD;
513 break;
517 return err;
520 /* A driver task is created on an OpenDevice() call,
521 * and is killed by a CloseDevice() call.
523 static LONG pd_DriverTask(VOID)
525 TASK_PRINTERDATA(pd);
527 struct Process *me = (struct Process *)FindTask(NULL);
528 struct PrinterExtendedData *ped = &pd->pd_SegmentData->ps_PED;
529 struct PrinterMessage *msg = NULL;
530 union printerIO *pio;
531 UWORD cmd;
532 BOOL stopped = FALSE;
533 LONG ret;
535 /* Wait for startup message -
536 * we use the DOS port because the
537 * pd_Unit has not been created yet
539 D(bug("%s: Waiting for startup. pd=%p\n", __func__, pd));
540 WaitPort(&me->pr_MsgPort);
541 msg = (struct PrinterMessage *)GetMsg(&me->pr_MsgPort);
543 D(bug("%s: Initializing driver, Unit Port %p\n", __func__, &pd->pd_Unit));
544 ret = pd_Init(pd);
546 /* We want to look like a TURBOPRINT driver
547 * TPMATCHWORD is in the 3rd ULONG in pd_OldStk
548 * TURBOPRINT was documented as using:
550 * (BOOL)TP_Installed = ( ((ULONG *)(PD->pd_OldStk))[2] == TPMATCHWORD)
552 * So the assumption is that this ULONG is in native endian format.
555 typedef union { UBYTE b[4]; ULONG l; } BL;
556 BL *p = (BL*)(pd->pd_OldStk + (2 * sizeof(ULONG)));
557 p->l = TPMATCHWORD;
561 D(bug("%s: Replying with %d\n", __func__, ret));
562 msg->mm_Version = ret;
563 ReplyMsg(&msg->mm_Message);
565 if (0 != ret)
566 return ret;
568 /* Wait for unit messages on the pd_Unit */
569 do {
570 LONG err = 0;
572 D(bug("%s: Waiting for command on port %p\n", __func__, &pd->pd_Unit));
573 WaitPort(&pd->pd_Unit);
574 pio = (union printerIO *)GetMsg(&pd->pd_Unit);
575 cmd = pio->ios.io_Command;
577 D(bug("%s: Command = %d\n", __func__, cmd));
578 switch (cmd) {
579 case CMD_OPENDEVICE:
580 err = ped->ped_Open(pio);
581 if (err == 0)
582 Printer_Text_Write(pd, "\033#1", 3); /* aRIN */
583 break;
584 case CMD_CLOSEDEVICE:
585 pd_Close(pd, pio);
586 break;
587 case CMD_FLUSH:
588 AbortIO((struct IORequest *)&pd->pd_ior0);
589 WaitIOStd((struct IOStdReq *)&pd->pd_ior0);
590 AbortIO((struct IORequest *)&pd->pd_ior1);
591 WaitIOStd((struct IOStdReq *)&pd->pd_ior1);
592 break;
593 case CMD_RESET:
594 if (stopped)
595 err = PDERR_CANCEL;
596 else {
597 err = Printer_Text_Command(pd, aRIN, 0, 0, 0, 0);
599 break;
600 case CMD_STOP:
601 stopped = TRUE;
602 break;
603 case CMD_START:
604 stopped = FALSE;
605 break;
606 case CMD_WRITE:
607 if (stopped)
608 err = PDERR_CANCEL;
609 else {
610 err = Printer_Text_Write(pd, pio->ios.io_Data, pio->ios.io_Length);
611 if (err == 0)
612 pio->ios.io_Actual = pio->ios.io_Length;
614 break;
615 case PRD_RAWWRITE:
616 if (stopped)
617 err = PDERR_CANCEL;
618 else {
619 err = pd_PWrite(pio->ios.io_Data, pio->ios.io_Length);
620 if (err == 0)
621 pio->ios.io_Actual = pio->ios.io_Length;
623 break;
624 case PRD_RESETPREFS:
625 case PRD_LOADPREFS:
626 case PRD_USEPREFS:
627 case PRD_SAVEPREFS:
628 case PRD_READPREFS:
629 case PRD_EDITPREFS:
630 err = pd_DoPreferences(pio, pio->ios.io_Command);
631 break;
632 case PRD_SETERRHOOK:
633 pd->pd_PUnit->pu_ErrHook = ((struct IOPrtErrReq *)pio)->io_Hook;
634 break;
635 case PRD_DUMPRPORTTAGS:
636 if (stopped)
637 err = PDERR_CANCEL;
638 else
639 err = Printer_Gfx_DumpRPort((struct IODRPReq *)pio, ((struct IODRPTagsReq *)pio)->io_TagList);
640 break;
641 case PRD_DUMPRPORT:
642 case PRD_TPEXTDUMPRPORT:
643 if (stopped)
644 err = PDERR_CANCEL;
645 else
646 err = Printer_Gfx_DumpRPort((struct IODRPReq *)pio, NULL);
647 break;
648 case PRD_QUERY:
649 err = pd_Query(&pio->ios);
650 break;
651 default:
652 err = IOERR_NOCMD;
653 break;
655 pio->ios.io_Error = err;
656 D(bug("%s: Command = %d, Result = %d\n", __func__, cmd, err));
658 ReplyMsg((struct Message *)pio);
659 } while (cmd != CMD_CLOSEDEVICE);
661 D(bug("%s: Shutting down\n", __func__));
663 return 0;
666 /* Synchronize old-style prefs with new style prefs
668 static void pd_SyncPrefs(struct PrinterData *pd)
670 struct Preferences *dprefs = &pd->pd_Preferences;
671 struct PrinterPrefs *uprefs = &pd->pd_PUnit->pu_Prefs;
673 dprefs->PrinterType = pd->pd_PrinterType;
675 strncpy(dprefs->PrinterFilename, uprefs->pp_Txt.pt_Driver,
676 sizeof(dprefs->PrinterFilename));
677 dprefs->PrinterFilename[sizeof(dprefs->PrinterFilename)-1] = 0;
679 dprefs->PrintPitch = uprefs->pp_Txt.pt_Pitch;
680 dprefs->PrintQuality = uprefs->pp_Txt.pt_Quality;
681 dprefs->PrintSpacing = uprefs->pp_Txt.pt_Spacing;
682 dprefs->PrintLeftMargin = uprefs->pp_Txt.pt_LeftMargin;
683 dprefs->PrintRightMargin = uprefs->pp_Txt.pt_RightMargin;
684 dprefs->PrintImage = uprefs->pp_Gfx.pg_Image;
685 dprefs->PrintAspect = uprefs->pp_Gfx.pg_Aspect;
686 dprefs->PrintShade = uprefs->pp_Gfx.pg_Shade;
687 dprefs->PrintThreshold = uprefs->pp_Gfx.pg_Threshold;
688 dprefs->PaperSize = uprefs->pp_Txt.pt_PaperSize;
689 dprefs->PaperType = uprefs->pp_Txt.pt_PaperType;
690 dprefs->PaperLength = uprefs->pp_Txt.pt_PaperLength;
692 if (uprefs->pp_Unit.pu_DeviceName[0] == 0) {
693 if (uprefs->pp_Txt.pt_Port == PP_PARALLEL) {
694 strcpy(dprefs->PrtDevName, "parallel");
695 } else if (uprefs->pp_Txt.pt_Port == PP_SERIAL) {
696 strcpy(dprefs->PrtDevName, "serial");
697 } else {
698 strcpy(dprefs->PrtDevName, "printtofile");
700 } else {
701 strncpy(dprefs->PrtDevName, uprefs->pp_Unit.pu_DeviceName, sizeof(dprefs->PrtDevName));
702 dprefs->PrtDevName[sizeof(dprefs->PrtDevName)-1]=0;
705 if (strcmp(dprefs->PrtDevName, "parallel") == 0 ||
706 strcmp(dprefs->PrtDevName, "usbparallel") == 0) {
707 pd->pd_ior0.pd_p0.IOPar.io_Message.mn_Length = sizeof(pd->pd_ior0.pd_p0);
708 pd->pd_ior0.pd_p0.io_ParFlags = PARF_SHARED;
709 pd->pd_ior1.pd_p1.IOPar.io_Message.mn_Length = sizeof(pd->pd_ior1.pd_p1);
710 pd->pd_ior1.pd_p1.io_ParFlags = PARF_SHARED;
711 } else if (strcmp(dprefs->PrtDevName, "serial") == 0) {
712 pd->pd_ior0.pd_s0.IOSer.io_Message.mn_Length = sizeof(pd->pd_ior0.pd_s0);
713 pd->pd_ior0.pd_s0.io_SerFlags = SERF_SHARED;
714 pd->pd_ior1.pd_s1.IOSer.io_Message.mn_Length = sizeof(pd->pd_ior1.pd_s1);
715 pd->pd_ior1.pd_s1.io_SerFlags = SERF_SHARED;
716 } else {
717 pd->pd_ior0.pd_i0.io_Message.mn_Length = sizeof(pd->pd_ior0.pd_i0);
718 pd->pd_ior1.pd_i1.io_Message.mn_Length = sizeof(pd->pd_ior1.pd_i1);
721 dprefs->DefaultPrtUnit = uprefs->pp_Unit.pu_UnitNum;
722 dprefs->PrintFlags = uprefs->pp_Gfx.pg_GraphicFlags;
723 dprefs->PrintMaxWidth = uprefs->pp_Gfx.pg_PrintMaxWidth;
724 dprefs->PrintMaxHeight = uprefs->pp_Gfx.pg_PrintMaxHeight;
725 dprefs->PrintDensity = uprefs->pp_Gfx.pg_PrintDensity;
726 dprefs->PrintXOffset = uprefs->pp_Gfx.pg_PrintXOffset;
729 /* Create a PrinterData plugin
731 struct PrinterUnit *Printer_Unit(struct PrinterBase *PrinterBase, LONG unitnum)
733 struct PrinterUnit *pu;
734 struct PrinterPrefs prefs;
735 BPTR olddir, dir, driverseg;
737 if (!Printer_LoadPrefs(PrinterBase, unitnum, &prefs) || prefs.pp_Txt.pt_Driver[0] == 0) {
738 D(bug("%s: No valid prefs for printer.device %d\n", __func__, unitnum));
739 return NULL;
742 if ((dir = Lock("DEVS:Printers", SHARED_LOCK)) != BNULL) {
743 olddir = CurrentDir(dir);
744 driverseg = LoadSeg(prefs.pp_Txt.pt_Driver);
745 CurrentDir(olddir);
746 UnLock(dir);
748 D(bug("%s: %s => %p\n", __func__, prefs.pp_Txt.pt_Driver, BADDR(driverseg)));
750 if (driverseg) {
751 struct PrinterSegment *prtseg = BADDR(driverseg);
753 D(bug("%s: magic 0x%08x, expect 0x%08x\n", __func__, prtseg->ps_runAlert, AROS_PRINTER_MAGIC));
754 if (prtseg->ps_runAlert == AROS_PRINTER_MAGIC) {
755 APTR funcs[] = {
756 AROS_SLIB_ENTRY(OpenDevice,PrinterUnit,1),
757 AROS_SLIB_ENTRY(CloseDevice,PrinterUnit,2),
758 AROS_SLIB_ENTRY(Expunge,PrinterUnit,3),
759 NULL,
760 AROS_SLIB_ENTRY(BeginIO,PrinterUnit,5),
761 AROS_SLIB_ENTRY(AbortIO,PrinterUnit,6),
762 (APTR)-1,
765 if ((pu = (struct PrinterUnit *)MakeLibrary(funcs, NULL, NULL, sizeof(*pu), driverseg))) {
766 struct Process *proc;
767 struct PrinterData *pd = &pu->pu_PrinterData;
768 struct Device *dev = (struct Device *)pu;
770 /* Loop back to self */
771 pu->pu_PrinterBase = PrinterBase;
772 pd->pd_PUnit = pu;
774 /* Duplicate the prefs */
775 CopyMem(&prefs, &pu->pu_Prefs, sizeof(prefs));
777 /* Update pd->pd_Preferences from pu->pu_Prefs */
778 pd_SyncPrefs(pd);
780 dev->dd_Library.lib_Node.ln_Name = pu->pu_Prefs.pp_DeviceUnit.pd_UnitName;
781 dev->dd_Library.lib_Version = prtseg->ps_Version;
782 dev->dd_Library.lib_Revision = prtseg->ps_Revision;
783 /* Magic token for TASK_PRINTERDATA() macro */
784 dev->dd_Library.lib_IdString = (APTR)driverID;
786 pd->pd_Device.dd_Segment = BADDR(driverseg);
787 pd->pd_Device.dd_ExecBase = SysBase;
788 pd->pd_Device.dd_CmdVectors = prtseg->ps_PED.ped_Commands;
789 pd->pd_Device.dd_CmdBytes = NULL;
790 pd->pd_Device.dd_NumCommands = aRAW + 1;
791 pd->pd_PrinterSegment = driverseg;
792 pd->pd_PrinterType = 0;
793 pd->pd_SegmentData = prtseg;
794 pd->pd_PWrite = pd_PWrite;
795 pd->pd_PBothReady = pd_PBothReady;
796 pd->pd_PRead = pd_PRead;
797 pd->pd_CallErrHook = (APTR)pd_CallErrHook;
798 pd->pd_PQuery = pd_PQuery;
799 pd->pd_UnitNumber = unitnum;
800 pd->pd_DriverName = &pd->pd_Preferences.PrinterFilename[0];
802 /* Make RemDevice() and friends happy */
803 AddDevice(dev);
805 proc = CreateNewProcTags(NP_Entry, pd_DriverTask,
806 NP_Name, prefs.pp_DeviceUnit.pd_UnitName,
807 NP_Priority, 0,
808 NP_Arguments, NULL,
809 NP_UserData, pd);
811 D(bug("%s: Driver process %p\n", __func__, proc));
812 if (proc != NULL) {
813 struct MsgPort *port;
815 /* Store the process here... */
816 pu->pu_Process = proc;
819 if ((port = CreateMsgPort())) {
820 struct PrinterMessage startup, *reply;
822 D(bug("%s: Driver unit port %p\n", __func__, port));
823 startup.mm_Message.mn_ReplyPort=port;
824 startup.mm_Message.mn_Length = sizeof(startup);
825 startup.mm_Magic = AROS_MAKE_ID('p','r','u','n');
826 startup.mm_Version = 0;
827 PutMsg(&proc->pr_MsgPort, (struct Message *)&startup);
828 WaitPort(port);
829 D(bug("%s: Driver replied\n", __func__));
830 reply = (struct PrinterMessage *)GetMsg(port);
831 D(bug("%s: Driver reply = %p\n", __func__, reply));
832 DeleteMsgPort(port);
833 D(bug("%s: Driver port %p gone\n", __func__, port));
834 if (reply == &startup &&
835 reply->mm_Message.mn_Length == sizeof(*reply) &&
836 reply->mm_Magic == AROS_MAKE_ID('p','r','u','n') &&
837 reply->mm_Version == 0) {
838 /* Success! */
839 D(bug("%s: Driver started\n", __func__));
840 return pu;
842 D(bug("%s: Driver startup failed\n", __func__));
844 /* pd_DriverTask will kill itself on failure */
846 /* pd_Expunge() calls UnLoadSeg() automatically */
847 RemDevice((struct Device *)pd);
848 driverseg = BNULL;
851 if (driverseg)
852 UnLoadSeg(driverseg);
856 return NULL;