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"
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
),
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
;
59 #define TASK_PRINTERDATA(pd) \
60 struct PrinterData *pd =(struct PrinterData *)FindTask(NULL)->tc_UserData; \
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, \
68 EasyRequestArgs(NULL, (struct EasyStruct *)&driverMisuse, \
69 0, (RAWARG)&args[0]); \
70 CloseLibrary(IntuitionBase); \
76 static BOOL
initMsgPort(struct MsgPort
*port
)
78 BYTE sb
= AllocSignal(-1);
83 memset( port
, 0, sizeof( *port
) );
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
);
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
)
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
;
117 STATIC
AROS_LH1(BPTR
, CloseDevice
,
118 AROS_LCA(struct IORequest
*,io
, A1
),
119 struct PrinterUnit
*, pu
, 2, PrinterUnit
)
126 if ((mp
= CreateMsgPort())) {
127 struct IORequest ior
= *io
;
128 ior
.io_Message
.mn_ReplyPort
= mp
;
129 ior
.io_Command
= CMD_CLOSEDEVICE
;
131 ret
= AROS_LC1(BPTR
, Expunge
,
132 AROS_LCA(struct PrinterUnit
*, pu
, D0
),
133 struct PrinterUnit
*, pu
, 3, PrinterUnit
);
142 STATIC
AROS_LH1(BPTR
, Expunge
,
143 AROS_LHA(struct Library
*, extralib
, D0
),
144 struct PrinterUnit
*, pu
, 3, PrinterUnit
)
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
+
158 D(bug("%s: Return segment %p\n", __func__
, BADDR(seg
)));
162 lib
->lib_Flags
|= LIBF_DELEXP
;
170 STATIC
AROS_LH1(void, BeginIO
,
171 AROS_LHA(union printerIO
*, pio
, A1
),
172 struct PrinterUnit
*, pu
, 5, PrinterUnit
)
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
);
189 STATIC
AROS_LH1(LONG
, AbortIO
,
190 AROS_LHA(struct IORequest
*, pio
, A1
),
191 struct PrinterUnit
*, pd
, 6, PrinterUnit
)
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;
209 static inline LONG
DoIOStd(struct IOStdReq
*io
)
211 DoIO((struct IORequest
*)io
);
212 io
->io_Message
.mn_Node
.ln_Type
= 0;
216 static LONG
pd_PWrite(APTR data
, LONG len
)
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
;
228 /* TODO: Call error hook if there is an error */
229 io
->io_Command
= CMD_WRITE
;
235 io
->io_Message
.mn_Length
= sizeof(*io
);
236 SendIO((struct IORequest
*)io
);
238 pd
->pd_Flags
^= PDF_IOREQ
;
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
);
257 static LONG
pd_PRead(char * buffer
, LONG
*length
, struct timeval
*tv
)
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
;
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
;
282 io
->io_Length
= *length
;
283 io
->io_Data
= buffer
;
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
);
297 *length
= io
->io_Actual
;
299 /* No need to swap units, as this one has been completed */
304 static LONG
pd_CallErrHook(struct Hook
*hook
, union printerIO
*ior
, struct PrtErrMsg
*pem
)
310 /* Only designed to work on the serial port. */
311 static LONG
pd_PQuery(LONG
*numofchars
)
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
;
326 /* TODO: Call error hook if there is an error */
327 io
->io_Command
= SDCMD_QUERY
;
333 io
->io_Message
.mn_Length
= sizeof(*io
);
336 *numofchars
= io
->io_Actual
;
340 /* No need to swap units, as this one has been completed */
345 /* Only designed to work on the serial and parallel port. */
346 static LONG
pd_Query(struct IOStdReq
*sio
)
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
)) {
357 return IOERR_OPENFAIL
;
360 io
= (pd
->pd_Flags
& PDF_IOREQ
) ?
361 (struct IOStdReq
*)&pd
->pd_ior1
:
362 (struct IOStdReq
*)&pd
->pd_ior0
;
364 /* TODO: Call error hook if there is an error */
365 io
->io_Command
= SDCMD_QUERY
;
371 io
->io_Message
.mn_Length
= sizeof(*io
);
374 UBYTE
*data
= sio
->io_Data
;
378 switch (pd
->pd_PUnit
->pu_Prefs
.pp_Txt
.pt_Port
) {
380 status
= ((struct IOExtSer
*)io
)->io_Status
;
383 status
= ((struct IOExtPar
*)io
)->io_Status
;
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 */
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
)
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
);
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
);
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
;
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
);
483 /* Remove from the parent printer.device */
484 ObtainSemaphore(&PrinterBase
->pb_UnitLock
[unitnum
]);
485 PrinterBase
->pb_Unit
[unitnum
] = NULL
;
487 PrinterBase
->pb_Device
.dd_Library
.lib_OpenCnt
--;
489 ReleaseSemaphore(&PrinterBase
->pb_UnitLock
[unitnum
]);
492 static LONG
pd_DoPreferences(const union printerIO
*pio
, LONG command
)
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
);
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
;
532 BOOL stopped
= FALSE
;
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
));
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
)));
561 D(bug("%s: Replying with %d\n", __func__
, ret
));
562 msg
->mm_Version
= ret
;
563 ReplyMsg(&msg
->mm_Message
);
568 /* Wait for unit messages on the pd_Unit */
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
));
580 err
= ped
->ped_Open(pio
);
582 Printer_Text_Write(pd
, "\033#1", 3); /* aRIN */
584 case CMD_CLOSEDEVICE
:
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
);
597 err
= Printer_Text_Command(pd
, aRIN
, 0, 0, 0, 0);
610 err
= Printer_Text_Write(pd
, pio
->ios
.io_Data
, pio
->ios
.io_Length
);
612 pio
->ios
.io_Actual
= pio
->ios
.io_Length
;
619 err
= pd_PWrite(pio
->ios
.io_Data
, pio
->ios
.io_Length
);
621 pio
->ios
.io_Actual
= pio
->ios
.io_Length
;
630 err
= pd_DoPreferences(pio
, pio
->ios
.io_Command
);
633 pd
->pd_PUnit
->pu_ErrHook
= ((struct IOPrtErrReq
*)pio
)->io_Hook
;
635 case PRD_DUMPRPORTTAGS
:
639 err
= Printer_Gfx_DumpRPort((struct IODRPReq
*)pio
, ((struct IODRPTagsReq
*)pio
)->io_TagList
);
642 case PRD_TPEXTDUMPRPORT
:
646 err
= Printer_Gfx_DumpRPort((struct IODRPReq
*)pio
, NULL
);
649 err
= pd_Query(&pio
->ios
);
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__
));
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");
698 strcpy(dprefs
->PrtDevName
, "printtofile");
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
;
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
));
742 if ((dir
= Lock("DEVS:Printers", SHARED_LOCK
)) != BNULL
) {
743 olddir
= CurrentDir(dir
);
744 driverseg
= LoadSeg(prefs
.pp_Txt
.pt_Driver
);
748 D(bug("%s: %s => %p\n", __func__
, prefs
.pp_Txt
.pt_Driver
, BADDR(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
) {
756 AROS_SLIB_ENTRY(OpenDevice
,PrinterUnit
,1),
757 AROS_SLIB_ENTRY(CloseDevice
,PrinterUnit
,2),
758 AROS_SLIB_ENTRY(Expunge
,PrinterUnit
,3),
760 AROS_SLIB_ENTRY(BeginIO
,PrinterUnit
,5),
761 AROS_SLIB_ENTRY(AbortIO
,PrinterUnit
,6),
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
;
774 /* Duplicate the prefs */
775 CopyMem(&prefs
, &pu
->pu_Prefs
, sizeof(prefs
));
777 /* Update pd->pd_Preferences from pu->pu_Prefs */
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 */
805 proc
= CreateNewProcTags(NP_Entry
, pd_DriverTask
,
806 NP_Name
, prefs
.pp_DeviceUnit
.pd_UnitName
,
811 D(bug("%s: Driver process %p\n", __func__
, proc
));
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
);
829 D(bug("%s: Driver replied\n", __func__
));
830 reply
= (struct PrinterMessage
*)GetMsg(port
);
831 D(bug("%s: Driver reply = %p\n", __func__
, reply
));
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) {
839 D(bug("%s: Driver started\n", __func__
));
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
);
852 UnLoadSeg(driverseg
);