arch/ppc-native/processor: Don't build for non-native PPC targets
[AROS.git] / workbench / devs / printer / driver.c
blobc61157db29cde2e24247cb3abc44c1e5577e6ed4
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 *mp;
91 LONG ret = IOERR_OPENFAIL;
93 if ((mp = CreateMsgPort())) {
94 struct IORequest ior = *io;
95 ior.io_Message.mn_ReplyPort = mp;
96 ior.io_Command = CMD_OPENDEVICE;
97 ret = DoIO(&ior);
98 DeleteMsgPort(mp);
101 return ret;
103 AROS_LIBFUNC_EXIT
106 STATIC AROS_LH1(BPTR, CloseDevice,
107 AROS_LCA(struct IORequest *,io, A1),
108 struct PrinterUnit *, pu, 2, PrinterUnit)
110 AROS_LIBFUNC_INIT
112 BPTR ret = BNULL;
113 struct MsgPort *mp;
115 if ((mp = CreateMsgPort())) {
116 struct IORequest ior = *io;
117 ior.io_Message.mn_ReplyPort = mp;
118 ior.io_Command = CMD_CLOSEDEVICE;
119 DoIO(&ior);
120 ret = AROS_LC1(BPTR, Expunge,
121 AROS_LCA(struct PrinterUnit *, pu, D0),
122 struct PrinterUnit *, pu, 3, PrinterUnit);
123 DeleteMsgPort(mp);
126 return ret;
128 AROS_LIBFUNC_EXIT
131 STATIC AROS_LH1(BPTR, Expunge,
132 AROS_LHA(struct Library *, extralib, D0),
133 struct PrinterUnit *, pu, 3, PrinterUnit)
135 AROS_LIBFUNC_INIT
137 struct Library *lib = (struct Library *)pu;
139 if (lib->lib_OpenCnt == 0) {
140 BPTR seg = pu->pu_PrinterData.pd_PrinterSegment;
142 Remove((struct Node *)lib);
143 FreeMem((UBYTE *)lib - lib->lib_NegSize,
144 (ULONG) (lib->lib_NegSize +
145 lib->lib_PosSize));
147 D(bug("%s: Return segment %p\n", __func__, BADDR(seg)));
148 return seg;
151 lib->lib_Flags |= LIBF_DELEXP;
153 return BNULL;
155 AROS_LIBFUNC_EXIT
159 STATIC AROS_LH1(void, BeginIO,
160 AROS_LHA(union printerIO *, pio, A1),
161 struct PrinterUnit *, pu, 5, PrinterUnit)
163 AROS_LIBFUNC_INIT
165 struct IOStdReq *io = &pio->ios;
166 struct PrinterData *pd = &pu->pu_PrinterData;
168 D(bug("BeginIO: io_Command = %d, Unit Port %p\n", io->io_Command, &pd->pd_Unit));
170 io->io_Flags &= ~IOF_QUICK;
171 PutMsg(&pd->pd_Unit, &io->io_Message);
173 return;
175 AROS_LIBFUNC_EXIT
178 STATIC AROS_LH1(LONG, AbortIO,
179 AROS_LHA(struct IORequest *, pio, A1),
180 struct PrinterUnit *, pd, 6, PrinterUnit)
182 AROS_LIBFUNC_INIT
183 return IOERR_NOCMD;
184 AROS_LIBFUNC_EXIT
187 /* These wrappers make sure that we don't
188 * make WaitIO() hang or corrupt memory
189 * if called on an already completed IO
191 static inline LONG WaitIOStd(struct IOStdReq *io)
193 WaitIO((struct IORequest *)io);
194 io->io_Message.mn_Node.ln_Type = 0;
195 return io->io_Error;
198 static inline LONG DoIOStd(struct IOStdReq *io)
200 DoIO((struct IORequest *)io);
201 io->io_Message.mn_Node.ln_Type = 0;
202 return io->io_Error;
205 static LONG pd_PWrite(APTR data, LONG len)
207 struct IOStdReq *io;
208 TASK_PRINTERDATA(pd);
210 if (pd->pd_Flags & PDF_NOIO)
211 return IOERR_OPENFAIL;
213 io = (pd->pd_Flags & PDF_IOREQ) ?
214 (struct IOStdReq *)&pd->pd_ior1 :
215 (struct IOStdReq *)&pd->pd_ior0;
216 WaitIOStd(io);
217 /* TODO: Call error hook if there is an error */
218 io->io_Command = CMD_WRITE;
219 io->io_Flags = 0;
220 io->io_Actual = 0;
221 io->io_Length = len;
222 io->io_Data = data;
223 io->io_Offset = 0;
224 io->io_Message.mn_Length = sizeof(*io);
225 SendIO((struct IORequest *)io);
227 pd->pd_Flags ^= PDF_IOREQ;
229 return 0;
232 static LONG pd_PBothReady(VOID)
234 TASK_PRINTERDATA(pd);
236 D(bug("%s:\n", __func__));
237 if (pd->pd_Flags & PDF_NOIO)
238 return IOERR_OPENFAIL;
240 WaitIOStd((struct IOStdReq *)&pd->pd_ior0);
241 WaitIOStd((struct IOStdReq *)&pd->pd_ior1);
243 return 0;
246 static LONG pd_PRead(char * buffer, LONG *length, struct timeval *tv)
248 ULONG sigs;
249 struct IOStdReq *io;
250 LONG err;
251 TASK_PRINTERDATA(pd);
253 if (pd->pd_Flags & PDF_NOIO)
254 return IOERR_OPENFAIL;
256 D(bug("%s:\n", __func__));
257 io = (pd->pd_Flags & PDF_IOREQ) ?
258 (struct IOStdReq *)&pd->pd_ior1 :
259 (struct IOStdReq *)&pd->pd_ior0;
260 WaitIOStd(io);
261 /* TODO: Call error hook if there is an error */
262 pd->pd_TIOR.tr_node.io_Command = TR_ADDREQUEST;
263 pd->pd_TIOR.tr_node.io_Flags = 0;
264 pd->pd_TIOR.tr_node.io_Message.mn_Length = sizeof(pd->pd_TIOR);
265 pd->pd_TIOR.tr_time = *tv;
266 SendIO((struct IORequest *)&pd->pd_TIOR);
268 io->io_Command = CMD_READ;
269 io->io_Flags = 0;
270 io->io_Actual = 0;
271 io->io_Length = *length;
272 io->io_Data = buffer;
273 io->io_Offset = 0;
274 io->io_Message.mn_Length = sizeof(*io);
275 SendIO((struct IORequest *)io);
276 sigs = Wait((1 << io->io_Message.mn_ReplyPort->mp_SigBit) |
277 (1 << pd->pd_IORPort.mp_SigBit));
278 if (sigs & (1 << pd->pd_IORPort.mp_SigBit)) {
279 WaitIO((struct IORequest *)&pd->pd_TIOR);
280 if (!CheckIO((struct IORequest *)io))
281 AbortIO((struct IORequest *)io);
283 WaitIOStd(io);
284 err = io->io_Error;
285 if (err == 0)
286 *length = io->io_Actual;
288 /* No need to swap units, as this one has been completed */
290 return err;
293 static LONG pd_CallErrHook(struct Hook *hook, union printerIO *ior, struct PrtErrMsg *pem)
295 /* TODO */
296 return 0;
299 /* Only designed to work on the serial port. */
300 static LONG pd_PQuery(LONG *numofchars)
302 LONG err;
303 struct IOStdReq *io;
305 TASK_PRINTERDATA(pd);
307 if (pd->pd_Flags & PDF_NOIO)
308 return IOERR_OPENFAIL;
310 D(bug("%s:\n", __func__));
311 io = (pd->pd_Flags & PDF_IOREQ) ?
312 (struct IOStdReq *)&pd->pd_ior1 :
313 (struct IOStdReq *)&pd->pd_ior0;
314 WaitIOStd(io);
315 /* TODO: Call error hook if there is an error */
316 io->io_Command = SDCMD_QUERY;
317 io->io_Flags = 0;
318 io->io_Actual = 0;
319 io->io_Length = 0;
320 io->io_Data = NULL;
321 io->io_Offset = 0;
322 io->io_Message.mn_Length = sizeof(*io);
323 err = DoIOStd(io);
324 if (err == 0)
325 *numofchars = io->io_Actual;
326 else
327 *numofchars = 0;
329 /* No need to swap units, as this one has been completed */
331 return err;
334 /* Only designed to work on the serial and parallel port. */
335 static LONG pd_Query(struct IOStdReq *sio)
337 LONG err;
338 struct IOStdReq *io;
340 TASK_PRINTERDATA(pd);
342 D(bug("%s:\n", __func__));
343 if (pd->pd_PUnit->pu_Prefs.pp_Unit.pu_DeviceName[0] != 0 ||
344 (pd->pd_Flags & PDF_NOIO)) {
345 sio->io_Actual = 0;
346 return IOERR_OPENFAIL;
349 io = (pd->pd_Flags & PDF_IOREQ) ?
350 (struct IOStdReq *)&pd->pd_ior1 :
351 (struct IOStdReq *)&pd->pd_ior0;
352 WaitIOStd(io);
353 /* TODO: Call error hook if there is an error */
354 io->io_Command = SDCMD_QUERY;
355 io->io_Flags = 0;
356 io->io_Actual = 0;
357 io->io_Length = 0;
358 io->io_Data = NULL;
359 io->io_Offset = 0;
360 io->io_Message.mn_Length = sizeof(*io);
361 err = DoIOStd(io);
362 if (err == 0) {
363 UBYTE *data = sio->io_Data;
364 if (data) {
365 UWORD status;
367 switch (pd->pd_PUnit->pu_Prefs.pp_Txt.pt_Port) {
368 case PP_SERIAL:
369 status = ((struct IOExtSer *)io)->io_Status;
370 break;
371 case PP_PARALLEL:
372 status = ((struct IOExtPar *)io)->io_Status;
373 break;
374 default:
375 status = 0;
376 break;
378 data[0] = (status >> 0) & 0xff;
379 data[1] = (status >> 8) & 0xff;
381 sio->io_Actual = pd->pd_PUnit->pu_Prefs.pp_Txt.pt_Port + 1;
384 /* No need to swap units, as this one has been completed */
386 return err;
389 static LONG pd_Init(struct PrinterData *pd)
391 struct PrinterExtendedData *ped = &pd->pd_SegmentData->ps_PED;
392 TEXT devname[sizeof(pd->pd_Preferences.PrtDevName) + 7 + 1];
394 /* Initialize the unit */
395 strcpy(devname, pd->pd_Preferences.PrtDevName);
396 strcat(devname, ".device");
398 D(bug("%s: create msgport %p\n", __func__, &pd->pd_Unit));
399 if (initMsgPort(&pd->pd_Unit)) {
400 D(bug("%s: Call ped_Init => %p\n", __func__, pd->pd_SegmentData->ps_PED.ped_Init));
401 if (0 == pd->pd_SegmentData->ps_PED.ped_Init(pd)) {
402 if (pd->pd_Flags & PDF_NOIO)
403 return 0;
405 if ((pd->pd_ior0.pd_p0.IOPar.io_Message.mn_ReplyPort=CreateMsgPort())) {
406 if (0 == OpenDevice(devname,
407 pd->pd_Preferences.DefaultPrtUnit,
408 (struct IORequest *)&pd->pd_ior0, 0)) {
409 D(bug("%s: open %s %d for io 0\n", __func__, devname, pd->pd_Preferences.DefaultPrtUnit));
410 pd->pd_ior0.pd_p0.IOPar.io_Message.mn_Node.ln_Type = 0;
411 if ((pd->pd_ior1.pd_p1.IOPar.io_Message.mn_ReplyPort=CreateMsgPort())) {
412 if (0 == OpenDevice(devname,
413 pd->pd_Preferences.DefaultPrtUnit,
414 (struct IORequest *)&pd->pd_ior1, 0)) {
415 pd->pd_ior1.pd_p1.IOPar.io_Message.mn_Node.ln_Type = 0;
416 D(bug("%s: open %s %d for io 1\n", __func__, devname, pd->pd_Preferences.DefaultPrtUnit));
417 if (initMsgPort(&pd->pd_IORPort)) {
418 pd->pd_TIOR.tr_node.io_Message.mn_ReplyPort=&pd->pd_IORPort;
419 pd->pd_TIOR.tr_node.io_Message.mn_Length = sizeof(pd->pd_TIOR);
420 if (0 == OpenDevice("timer.device", UNIT_VBLANK,
421 (struct IORequest *)&pd->pd_TIOR, 0)) {
422 D(bug("%s: open timer.device %d\n", __func__, UNIT_VBLANK));
423 if (ped->ped_Render) {
424 LONG err = ped->ped_Render(0, 0, 0, PRS_PREINIT);
425 if (err == 0)
426 return 0;
427 } else {
428 return 0;
431 FreeSignal(pd->pd_IORPort.mp_SigBit);
433 CloseDevice((struct IORequest *)&pd->pd_ior1);
435 DeleteMsgPort(pd->pd_ior1.pd_p1.IOPar.io_Message.mn_ReplyPort);
437 CloseDevice((struct IORequest *)&pd->pd_ior0);
439 DeleteMsgPort(pd->pd_ior0.pd_p0.IOPar.io_Message.mn_ReplyPort);
441 pd->pd_SegmentData->ps_PED.ped_Expunge();
443 FreeSignal(pd->pd_Unit.mp_SigBit);
446 return -1;
449 static VOID pd_Close(struct PrinterData *pd, union printerIO *pio)
451 struct PrinterBase *PrinterBase = pd->pd_PUnit->pu_PrinterBase;
452 struct PrinterExtendedData *ped = &pd->pd_SegmentData->ps_PED;
453 LONG unitnum = pd->pd_PUnit->pu_Prefs.pp_DeviceUnit.pd_UnitNum;
455 ped->ped_Close(pio);
457 if (!(pd->pd_Flags & PDF_NOIO)) {
458 CloseDevice((struct IORequest *)&pd->pd_TIOR);
459 FreeSignal(pd->pd_IORPort.mp_SigBit);
460 CloseDevice((struct IORequest *)&pd->pd_ior1);
461 DeleteMsgPort(pd->pd_ior1.pd_p1.IOPar.io_Message.mn_ReplyPort);
462 CloseDevice((struct IORequest *)&pd->pd_ior0);
463 DeleteMsgPort(pd->pd_ior0.pd_p0.IOPar.io_Message.mn_ReplyPort);
465 FreeSignal(pd->pd_Unit.mp_SigBit);
467 ped->ped_Expunge();
469 /* Remove from the parent printer.device */
470 ObtainSemaphore(&PrinterBase->pb_UnitLock[unitnum]);
471 PrinterBase->pb_Unit[unitnum] = NULL;
472 Forbid();
473 PrinterBase->pb_Device.dd_Library.lib_OpenCnt--;
474 Permit();
475 ReleaseSemaphore(&PrinterBase->pb_UnitLock[unitnum]);
478 static LONG pd_DoPreferences(const union printerIO *pio, LONG command)
480 LONG err;
482 TASK_PRINTERDATA(pd);
484 if (pd->pd_SegmentData->ps_Version >= 44 &&
485 (pd->pd_SegmentData->ps_PED.ped_PrinterClass & PPCF_EXTENDED) &&
486 pd->pd_SegmentData->ps_PED.ped_DoPreferences != NULL) {
487 err = pd->pd_SegmentData->ps_PED.ped_DoPreferences((union printerIO *)pio, command);
488 } else {
489 switch (command) {
490 case PRD_RESETPREFS:
491 case PRD_LOADPREFS:
492 case PRD_USEPREFS:
493 case PRD_SAVEPREFS:
494 case PRD_READPREFS:
495 case PRD_WRITEPREFS:
496 case PRD_EDITPREFS:
497 default:
498 err = IOERR_NOCMD;
499 break;
503 return err;
506 /* A driver task is created on an OpenDevice() call,
507 * and is killed by a CloseDevice() call.
509 static LONG pd_DriverTask(VOID)
511 TASK_PRINTERDATA(pd);
513 struct Process *me = (struct Process *)FindTask(NULL);
514 struct PrinterExtendedData *ped = &pd->pd_SegmentData->ps_PED;
515 struct MagicMessage *msg = NULL;
516 union printerIO *pio;
517 UWORD cmd;
518 BOOL stopped = FALSE;
519 LONG ret;
521 /* Wait for startup message -
522 * we use the DOS port because the
523 * pd_Unit has not been created yet
525 D(bug("%s: Waiting for startup. pd=%p\n", __func__, pd));
526 WaitPort(&me->pr_MsgPort);
527 msg = (struct MagicMessage *)GetMsg(&me->pr_MsgPort);
529 D(bug("%s: Initializing driver, Unit Port %p\n", __func__, &pd->pd_Unit));
530 ret = pd_Init(pd);
532 D(bug("%s: Replying with %d\n", __func__, ret));
533 msg->mn_Version = ret;
534 ReplyMsg((struct Message *)msg);
536 if (0 != ret)
537 return ret;
539 /* Wait for unit messages on the pd_Unit */
540 do {
541 LONG err = 0;
543 D(bug("%s: Waiting for command on port %p\n", __func__, &pd->pd_Unit));
544 WaitPort(&pd->pd_Unit);
545 pio = (union printerIO *)GetMsg(&pd->pd_Unit);
546 cmd = pio->ios.io_Command;
548 D(bug("%s: Command = %d\n", __func__, cmd));
549 switch (cmd) {
550 case CMD_OPENDEVICE:
551 err = ped->ped_Open(pio);
552 if (err == 0)
553 Printer_Text_Write(pd, "\033#1", 3); /* aRIN */
554 break;
555 case CMD_CLOSEDEVICE:
556 pd_Close(pd, pio);
557 break;
558 case CMD_FLUSH:
559 AbortIO((struct IORequest *)&pd->pd_ior0);
560 WaitIOStd((struct IOStdReq *)&pd->pd_ior0);
561 AbortIO((struct IORequest *)&pd->pd_ior1);
562 WaitIOStd((struct IOStdReq *)&pd->pd_ior1);
563 break;
564 case CMD_RESET:
565 if (stopped)
566 err = PDERR_CANCEL;
567 else {
568 err = Printer_Text_Command(pd, aRIN, 0, 0, 0, 0);
570 break;
571 case CMD_STOP:
572 stopped = TRUE;
573 break;
574 case CMD_START:
575 stopped = FALSE;
576 break;
577 case CMD_WRITE:
578 if (stopped)
579 err = PDERR_CANCEL;
580 else {
581 err = Printer_Text_Write(pd, pio->ios.io_Data, pio->ios.io_Length);
582 if (err == 0)
583 pio->ios.io_Actual = pio->ios.io_Length;
585 break;
586 case PRD_RAWWRITE:
587 if (stopped)
588 err = PDERR_CANCEL;
589 else {
590 err = pd_PWrite(pio->ios.io_Data, pio->ios.io_Length);
591 if (err == 0)
592 pio->ios.io_Actual = pio->ios.io_Length;
594 break;
595 case PRD_RESETPREFS:
596 case PRD_LOADPREFS:
597 case PRD_USEPREFS:
598 case PRD_SAVEPREFS:
599 case PRD_READPREFS:
600 case PRD_EDITPREFS:
601 err = pd_DoPreferences(pio, pio->ios.io_Command);
602 break;
603 case PRD_SETERRHOOK:
604 pd->pd_PUnit->pu_ErrHook = ((struct IOPrtErrReq *)pio)->io_Hook;
605 break;
606 case PRD_DUMPRPORTTAGS:
607 if (stopped)
608 err = PDERR_CANCEL;
609 else
610 err = Printer_Gfx_DumpRPort((struct IODRPReq *)pio, ((struct IODRPTagsReq *)pio)->io_TagList);
611 break;
612 case PRD_DUMPRPORT:
613 if (stopped)
614 err = PDERR_CANCEL;
615 else
616 err = Printer_Gfx_DumpRPort((struct IODRPReq *)pio, NULL);
617 break;
618 case PRD_QUERY:
619 err = pd_Query(&pio->ios);
620 break;
621 default:
622 err = IOERR_NOCMD;
623 break;
625 pio->ios.io_Error = err;
626 D(bug("%s: Command = %d, Result = %d\n", __func__, cmd, err));
628 ReplyMsg((struct Message *)pio);
629 } while (cmd != CMD_CLOSEDEVICE);
631 D(bug("%s: Shutting down\n", __func__));
633 return 0;
636 /* Synchronize old-style prefs with new style prefs
638 static void pd_SyncPrefs(struct PrinterData *pd)
640 struct Preferences *dprefs = &pd->pd_Preferences;
641 struct PrinterPrefs *uprefs = &pd->pd_PUnit->pu_Prefs;
643 dprefs->PrinterType = pd->pd_PrinterType;
645 strncpy(dprefs->PrinterFilename, uprefs->pp_Txt.pt_Driver,
646 sizeof(dprefs->PrinterFilename));
647 dprefs->PrinterFilename[sizeof(dprefs->PrinterFilename)-1] = 0;
649 dprefs->PrintPitch = uprefs->pp_Txt.pt_Pitch;
650 dprefs->PrintQuality = uprefs->pp_Txt.pt_Quality;
651 dprefs->PrintSpacing = uprefs->pp_Txt.pt_Spacing;
652 dprefs->PrintLeftMargin = uprefs->pp_Txt.pt_LeftMargin;
653 dprefs->PrintRightMargin = uprefs->pp_Txt.pt_RightMargin;
654 dprefs->PrintImage = uprefs->pp_Gfx.pg_Image;
655 dprefs->PrintAspect = uprefs->pp_Gfx.pg_Aspect;
656 dprefs->PrintShade = uprefs->pp_Gfx.pg_Shade;
657 dprefs->PrintThreshold = uprefs->pp_Gfx.pg_Threshold;
658 dprefs->PaperSize = uprefs->pp_Txt.pt_PaperSize;
659 dprefs->PaperType = uprefs->pp_Txt.pt_PaperType;
660 dprefs->PaperLength = uprefs->pp_Txt.pt_PaperLength;
662 if (uprefs->pp_Unit.pu_DeviceName[0] == 0) {
663 if (uprefs->pp_Txt.pt_Port == PP_PARALLEL) {
664 strcpy(dprefs->PrtDevName, "parallel");
665 } else if (uprefs->pp_Txt.pt_Port == PP_SERIAL) {
666 strcpy(dprefs->PrtDevName, "serial");
667 } else {
668 strcpy(dprefs->PrtDevName, "printtofile");
670 } else {
671 strncpy(dprefs->PrtDevName, uprefs->pp_Unit.pu_DeviceName, sizeof(dprefs->PrtDevName));
672 dprefs->PrtDevName[sizeof(dprefs->PrtDevName)-1]=0;
675 if (strcmp(dprefs->PrtDevName, "parallel") == 0 ||
676 strcmp(dprefs->PrtDevName, "usbparallel") == 0) {
677 pd->pd_ior0.pd_p0.IOPar.io_Message.mn_Length = sizeof(pd->pd_ior0.pd_p0);
678 pd->pd_ior0.pd_p0.io_ParFlags = PARF_SHARED;
679 pd->pd_ior1.pd_p1.IOPar.io_Message.mn_Length = sizeof(pd->pd_ior1.pd_p1);
680 pd->pd_ior1.pd_p1.io_ParFlags = PARF_SHARED;
681 } else if (strcmp(dprefs->PrtDevName, "serial") == 0) {
682 pd->pd_ior0.pd_s0.IOSer.io_Message.mn_Length = sizeof(pd->pd_ior0.pd_s0);
683 pd->pd_ior0.pd_s0.io_SerFlags = SERF_SHARED;
684 pd->pd_ior1.pd_s1.IOSer.io_Message.mn_Length = sizeof(pd->pd_ior1.pd_s1);
685 pd->pd_ior1.pd_s1.io_SerFlags = SERF_SHARED;
686 } else {
687 pd->pd_ior0.pd_i0.io_Message.mn_Length = sizeof(pd->pd_ior0.pd_i0);
688 pd->pd_ior1.pd_i1.io_Message.mn_Length = sizeof(pd->pd_ior1.pd_i1);
691 dprefs->DefaultPrtUnit = uprefs->pp_Unit.pu_UnitNum;
692 dprefs->PrintFlags = uprefs->pp_Gfx.pg_GraphicFlags;
693 dprefs->PrintMaxWidth = uprefs->pp_Gfx.pg_PrintMaxWidth;
694 dprefs->PrintMaxHeight = uprefs->pp_Gfx.pg_PrintMaxHeight;
695 dprefs->PrintDensity = uprefs->pp_Gfx.pg_PrintDensity;
696 dprefs->PrintXOffset = uprefs->pp_Gfx.pg_PrintXOffset;
699 /* Create a PrinterData plugin
701 struct PrinterUnit *Printer_Unit(struct PrinterBase *PrinterBase, LONG unitnum)
703 struct PrinterUnit *pu;
704 struct PrinterPrefs prefs;
705 BPTR olddir, dir, driverseg;
707 if (!Printer_LoadPrefs(PrinterBase, unitnum, &prefs) || prefs.pp_Txt.pt_Driver[0] == 0) {
708 D(bug("%s: No valid prefs for printer.device %d\n", __func__, unitnum));
709 return NULL;
712 if ((dir = Lock("DEVS:Printers", SHARED_LOCK)) != BNULL) {
713 olddir = CurrentDir(dir);
714 driverseg = LoadSeg(prefs.pp_Txt.pt_Driver);
715 CurrentDir(olddir);
716 UnLock(dir);
718 D(bug("%s: %s => %p\n", __func__, prefs.pp_Txt.pt_Driver, BADDR(driverseg)));
720 if (driverseg) {
721 struct PrinterSegment *prtseg = BADDR(driverseg);
723 D(bug("%s: magic 0x%08x, expect 0x%08x\n", __func__, prtseg->ps_runAlert, AROS_PRINTER_MAGIC));
724 if (prtseg->ps_runAlert == AROS_PRINTER_MAGIC) {
725 APTR funcs[] = {
726 AROS_SLIB_ENTRY(OpenDevice,PrinterUnit,1),
727 AROS_SLIB_ENTRY(CloseDevice,PrinterUnit,2),
728 AROS_SLIB_ENTRY(Expunge,PrinterUnit,3),
729 NULL,
730 AROS_SLIB_ENTRY(BeginIO,PrinterUnit,5),
731 AROS_SLIB_ENTRY(AbortIO,PrinterUnit,6),
732 (APTR)-1,
735 if ((pu = (struct PrinterUnit *)MakeLibrary(funcs, NULL, NULL, sizeof(*pu), driverseg))) {
736 struct Process *proc;
737 struct PrinterData *pd = &pu->pu_PrinterData;
738 struct Device *dev = (struct Device *)pu;
740 /* Loop back to self */
741 pu->pu_PrinterBase = PrinterBase;
742 pd->pd_PUnit = pu;
744 /* Duplicate the prefs */
745 CopyMem(&prefs, &pu->pu_Prefs, sizeof(prefs));
747 /* Update pd->pd_Preferences from pu->pu_Prefs */
748 pd_SyncPrefs(pd);
750 dev->dd_Library.lib_Node.ln_Name = pu->pu_Prefs.pp_DeviceUnit.pd_UnitName;
751 dev->dd_Library.lib_Version = prtseg->ps_Version;
752 dev->dd_Library.lib_Revision = prtseg->ps_Revision;
753 /* Magic token for TASK_PRINTERDATA() macro */
754 dev->dd_Library.lib_IdString = (APTR)driverID;
756 pd->pd_Device.dd_Segment = BADDR(driverseg);
757 pd->pd_Device.dd_ExecBase = SysBase;
758 pd->pd_Device.dd_CmdVectors = prtseg->ps_PED.ped_Commands;
759 pd->pd_Device.dd_CmdBytes = NULL;
760 pd->pd_Device.dd_NumCommands = aRAW + 1;
761 pd->pd_PrinterSegment = driverseg;
762 pd->pd_PrinterType = 0;
763 pd->pd_SegmentData = prtseg;
764 pd->pd_PWrite = pd_PWrite;
765 pd->pd_PBothReady = pd_PBothReady;
766 pd->pd_PRead = pd_PRead;
767 pd->pd_CallErrHook = (APTR)pd_CallErrHook;
768 pd->pd_PQuery = pd_PQuery;
769 pd->pd_UnitNumber = unitnum;
770 pd->pd_DriverName = &pd->pd_Preferences.PrinterFilename[0];
772 /* Make RemDevice() and friends happy */
773 AddDevice(dev);
775 proc = CreateNewProcTags(NP_Entry, pd_DriverTask,
776 NP_Name, prefs.pp_DeviceUnit.pd_UnitName,
777 NP_Priority, 0,
778 NP_Arguments, NULL,
779 NP_UserData, pd);
781 D(bug("%s: Driver process %p\n", __func__, proc));
782 if (proc != NULL) {
783 struct MsgPort *port;
785 /* Store the process here... */
786 pu->pu_Process = proc;
789 if ((port = CreateMsgPort())) {
790 struct MagicMessage startup, *reply;
792 D(bug("%s: Driver unit port %p\n", __func__, port));
793 startup.mn_ReplyPort=port;
794 startup.mn_Length = sizeof(startup);
795 startup.mn_Magic = AROS_MAKE_ID('p','r','u','n');
796 startup.mn_Version = 0;
797 PutMsg(&proc->pr_MsgPort, (struct Message *)&startup);
798 WaitPort(port);
799 D(bug("%s: Driver replied\n", __func__));
800 reply = (struct MagicMessage *)GetMsg(port);
801 D(bug("%s: Driver reply = %p\n", __func__, reply));
802 DeleteMsgPort(port);
803 D(bug("%s: Driver port %p gone\n", __func__, port));
804 if (reply == &startup &&
805 reply->mn_Length == sizeof(*reply) &&
806 reply->mn_Magic == AROS_MAKE_ID('p','r','u','n') &&
807 reply->mn_Version == 0) {
808 /* Success! */
809 D(bug("%s: Driver started\n", __func__));
810 return pu;
812 D(bug("%s: Driver startup failed\n", __func__));
814 /* pd_DriverTask will kill itself on failure */
816 /* pd_Expunge() calls UnLoadSeg() automatically */
817 RemDevice((struct Device *)pd);
818 driverseg = BNULL;
821 if (driverseg)
822 UnLoadSeg(driverseg);
826 return NULL;