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"
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);
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
);
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
)
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
;
116 STATIC
AROS_LH1(BPTR
, CloseDevice
,
117 AROS_LCA(struct IORequest
*,io
, A1
),
118 struct PrinterUnit
*, pu
, 2, PrinterUnit
)
125 if ((mp
= CreateMsgPort())) {
126 struct IORequest ior
= *io
;
127 ior
.io_Message
.mn_ReplyPort
= mp
;
128 ior
.io_Command
= CMD_CLOSEDEVICE
;
130 ret
= AROS_LC1(BPTR
, Expunge
,
131 AROS_LCA(struct PrinterUnit
*, pu
, D0
),
132 struct PrinterUnit
*, pu
, 3, PrinterUnit
);
141 STATIC
AROS_LH1(BPTR
, Expunge
,
142 AROS_LHA(struct Library
*, extralib
, D0
),
143 struct PrinterUnit
*, pu
, 3, PrinterUnit
)
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
+
157 D(bug("%s: Return segment %p\n", __func__
, BADDR(seg
)));
161 lib
->lib_Flags
|= LIBF_DELEXP
;
169 STATIC
AROS_LH1(void, BeginIO
,
170 AROS_LHA(union printerIO
*, pio
, A1
),
171 struct PrinterUnit
*, pu
, 5, PrinterUnit
)
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
);
188 STATIC
AROS_LH1(LONG
, AbortIO
,
189 AROS_LHA(struct IORequest
*, pio
, A1
),
190 struct PrinterUnit
*, pd
, 6, PrinterUnit
)
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;
208 static inline LONG
DoIOStd(struct IOStdReq
*io
)
210 DoIO((struct IORequest
*)io
);
211 io
->io_Message
.mn_Node
.ln_Type
= 0;
215 static LONG
pd_PWrite(APTR data
, LONG len
)
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
;
227 /* TODO: Call error hook if there is an error */
228 io
->io_Command
= CMD_WRITE
;
234 io
->io_Message
.mn_Length
= sizeof(*io
);
235 SendIO((struct IORequest
*)io
);
237 pd
->pd_Flags
^= PDF_IOREQ
;
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
);
256 static LONG
pd_PRead(char * buffer
, LONG
*length
, struct timeval
*tv
)
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
;
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
;
281 io
->io_Length
= *length
;
282 io
->io_Data
= buffer
;
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
);
296 *length
= io
->io_Actual
;
298 /* No need to swap units, as this one has been completed */
303 static LONG
pd_CallErrHook(struct Hook
*hook
, union printerIO
*ior
, struct PrtErrMsg
*pem
)
309 /* Only designed to work on the serial port. */
310 static LONG
pd_PQuery(LONG
*numofchars
)
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
;
325 /* TODO: Call error hook if there is an error */
326 io
->io_Command
= SDCMD_QUERY
;
332 io
->io_Message
.mn_Length
= sizeof(*io
);
335 *numofchars
= io
->io_Actual
;
339 /* No need to swap units, as this one has been completed */
344 /* Only designed to work on the serial and parallel port. */
345 static LONG
pd_Query(struct IOStdReq
*sio
)
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
)) {
356 return IOERR_OPENFAIL
;
359 io
= (pd
->pd_Flags
& PDF_IOREQ
) ?
360 (struct IOStdReq
*)&pd
->pd_ior1
:
361 (struct IOStdReq
*)&pd
->pd_ior0
;
363 /* TODO: Call error hook if there is an error */
364 io
->io_Command
= SDCMD_QUERY
;
370 io
->io_Message
.mn_Length
= sizeof(*io
);
373 UBYTE
*data
= sio
->io_Data
;
377 switch (pd
->pd_PUnit
->pu_Prefs
.pp_Txt
.pt_Port
) {
379 status
= ((struct IOExtSer
*)io
)->io_Status
;
382 status
= ((struct IOExtPar
*)io
)->io_Status
;
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 */
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
)
415 pd
->pd_ior0
.pd_p0
.io_ParFlags
= PARF_SHARED
;
416 if ((pd
->pd_ior0
.pd_p0
.IOPar
.io_Message
.mn_ReplyPort
=CreateMsgPort())) {
417 if (0 == OpenDevice(devname
,
418 pd
->pd_Preferences
.DefaultPrtUnit
,
419 (struct IORequest
*)&pd
->pd_ior0
, 0)) {
420 D(bug("%s: open %s %d for io 0\n", __func__
, devname
, pd
->pd_Preferences
.DefaultPrtUnit
));
421 pd
->pd_ior0
.pd_p0
.IOPar
.io_Message
.mn_Node
.ln_Type
= 0;
423 pd
->pd_ior1
.pd_p1
.io_ParFlags
= PARF_SHARED
;
424 if ((pd
->pd_ior1
.pd_p1
.IOPar
.io_Message
.mn_ReplyPort
=CreateMsgPort())) {
425 if (0 == OpenDevice(devname
,
426 pd
->pd_Preferences
.DefaultPrtUnit
,
427 (struct IORequest
*)&pd
->pd_ior1
, 0)) {
428 pd
->pd_ior1
.pd_p1
.IOPar
.io_Message
.mn_Node
.ln_Type
= 0;
429 D(bug("%s: open %s %d for io 1\n", __func__
, devname
, pd
->pd_Preferences
.DefaultPrtUnit
));
430 if (initMsgPort(&pd
->pd_IORPort
)) {
431 pd
->pd_TIOR
.tr_node
.io_Message
.mn_ReplyPort
=&pd
->pd_IORPort
;
432 pd
->pd_TIOR
.tr_node
.io_Message
.mn_Length
= sizeof(pd
->pd_TIOR
);
433 if (0 == OpenDevice("timer.device", UNIT_VBLANK
,
434 (struct IORequest
*)&pd
->pd_TIOR
, 0)) {
435 D(bug("%s: open timer.device %d\n", __func__
, UNIT_VBLANK
));
436 if (ped
->ped_Render
) {
437 LONG err
= ped
->ped_Render(0, 0, 0, PRS_PREINIT
);
444 FreeSignal(pd
->pd_IORPort
.mp_SigBit
);
446 CloseDevice((struct IORequest
*)&pd
->pd_ior1
);
448 DeleteMsgPort(pd
->pd_ior1
.pd_p1
.IOPar
.io_Message
.mn_ReplyPort
);
450 CloseDevice((struct IORequest
*)&pd
->pd_ior0
);
452 DeleteMsgPort(pd
->pd_ior0
.pd_p0
.IOPar
.io_Message
.mn_ReplyPort
);
454 pd
->pd_SegmentData
->ps_PED
.ped_Expunge();
456 FreeSignal(pd
->pd_Unit
.mp_SigBit
);
462 static VOID
pd_Close(struct PrinterData
*pd
, union printerIO
*pio
)
464 struct PrinterBase
*PrinterBase
= pd
->pd_PUnit
->pu_PrinterBase
;
465 struct PrinterExtendedData
*ped
= &pd
->pd_SegmentData
->ps_PED
;
466 LONG unitnum
= pd
->pd_PUnit
->pu_Prefs
.pp_DeviceUnit
.pd_UnitNum
;
470 if (!(pd
->pd_Flags
& PDF_NOIO
)) {
471 CloseDevice((struct IORequest
*)&pd
->pd_TIOR
);
472 FreeSignal(pd
->pd_IORPort
.mp_SigBit
);
473 CloseDevice((struct IORequest
*)&pd
->pd_ior1
);
474 DeleteMsgPort(pd
->pd_ior1
.pd_p1
.IOPar
.io_Message
.mn_ReplyPort
);
475 CloseDevice((struct IORequest
*)&pd
->pd_ior0
);
476 DeleteMsgPort(pd
->pd_ior0
.pd_p0
.IOPar
.io_Message
.mn_ReplyPort
);
478 FreeSignal(pd
->pd_Unit
.mp_SigBit
);
482 /* Remove from the parent printer.device */
483 ObtainSemaphore(&PrinterBase
->pb_UnitLock
[unitnum
]);
484 PrinterBase
->pb_Unit
[unitnum
] = NULL
;
486 PrinterBase
->pb_Device
.dd_Library
.lib_OpenCnt
--;
488 ReleaseSemaphore(&PrinterBase
->pb_UnitLock
[unitnum
]);
491 static LONG
pd_DoPreferences(const union printerIO
*pio
, LONG command
)
495 TASK_PRINTERDATA(pd
);
497 if (pd
->pd_SegmentData
->ps_Version
>= 44 &&
498 (pd
->pd_SegmentData
->ps_PED
.ped_PrinterClass
& PPCF_EXTENDED
) &&
499 pd
->pd_SegmentData
->ps_PED
.ped_DoPreferences
!= NULL
) {
500 err
= pd
->pd_SegmentData
->ps_PED
.ped_DoPreferences((union printerIO
*)pio
, command
);
519 /* A driver task is created on an OpenDevice() call,
520 * and is killed by a CloseDevice() call.
522 static LONG
pd_DriverTask(VOID
)
524 TASK_PRINTERDATA(pd
);
526 struct Process
*me
= (struct Process
*)FindTask(NULL
);
527 struct PrinterExtendedData
*ped
= &pd
->pd_SegmentData
->ps_PED
;
528 struct PrinterMessage
*msg
= NULL
;
529 union printerIO
*pio
;
531 BOOL stopped
= FALSE
;
534 /* Wait for startup message -
535 * we use the DOS port because the
536 * pd_Unit has not been created yet
538 D(bug("%s: Waiting for startup. pd=%p\n", __func__
, pd
));
539 WaitPort(&me
->pr_MsgPort
);
540 msg
= (struct PrinterMessage
*)GetMsg(&me
->pr_MsgPort
);
542 D(bug("%s: Initializing driver, Unit Port %p\n", __func__
, &pd
->pd_Unit
));
545 /* We want to look like a TURBOPRINT driver
546 * TPMATCHWORD is in the 3rd ULONG in pd_OldStk
547 * TURBOPRINT was documented as using:
549 * (BOOL)TP_Installed = ( ((ULONG *)(PD->pd_OldStk))[2] == TPMATCHWORD)
551 * So the assumption is that this ULONG is in native endian format.
553 ((ULONG
*)(pd
->pd_OldStk
))[2] = TPMATCHWORD
;
556 D(bug("%s: Replying with %d\n", __func__
, ret
));
557 msg
->mm_Version
= ret
;
558 ReplyMsg(&msg
->mm_Message
);
563 /* Wait for unit messages on the pd_Unit */
567 D(bug("%s: Waiting for command on port %p\n", __func__
, &pd
->pd_Unit
));
568 WaitPort(&pd
->pd_Unit
);
569 pio
= (union printerIO
*)GetMsg(&pd
->pd_Unit
);
570 cmd
= pio
->ios
.io_Command
;
572 D(bug("%s: Command = %d\n", __func__
, cmd
));
575 err
= ped
->ped_Open(pio
);
577 Printer_Text_Write(pd
, "\033#1", 3); /* aRIN */
579 case CMD_CLOSEDEVICE
:
583 AbortIO((struct IORequest
*)&pd
->pd_ior0
);
584 WaitIOStd((struct IOStdReq
*)&pd
->pd_ior0
);
585 AbortIO((struct IORequest
*)&pd
->pd_ior1
);
586 WaitIOStd((struct IOStdReq
*)&pd
->pd_ior1
);
592 err
= Printer_Text_Command(pd
, aRIN
, 0, 0, 0, 0);
605 err
= Printer_Text_Write(pd
, pio
->ios
.io_Data
, pio
->ios
.io_Length
);
607 pio
->ios
.io_Actual
= pio
->ios
.io_Length
;
614 err
= pd_PWrite(pio
->ios
.io_Data
, pio
->ios
.io_Length
);
616 pio
->ios
.io_Actual
= pio
->ios
.io_Length
;
625 err
= pd_DoPreferences(pio
, pio
->ios
.io_Command
);
628 pd
->pd_PUnit
->pu_ErrHook
= ((struct IOPrtErrReq
*)pio
)->io_Hook
;
630 case PRD_DUMPRPORTTAGS
:
634 err
= Printer_Gfx_DumpRPort((struct IODRPReq
*)pio
, ((struct IODRPTagsReq
*)pio
)->io_TagList
);
637 case PRD_TPEXTDUMPRPORT
:
641 err
= Printer_Gfx_DumpRPort((struct IODRPReq
*)pio
, NULL
);
644 err
= pd_Query(&pio
->ios
);
650 pio
->ios
.io_Error
= err
;
651 D(bug("%s: Command = %d, Result = %d\n", __func__
, cmd
, err
));
653 ReplyMsg((struct Message
*)pio
);
654 } while (cmd
!= CMD_CLOSEDEVICE
);
656 D(bug("%s: Shutting down\n", __func__
));
661 /* Synchronize old-style prefs with new style prefs
663 static void pd_SyncPrefs(struct PrinterData
*pd
)
665 struct Preferences
*dprefs
= &pd
->pd_Preferences
;
666 struct PrinterPrefs
*uprefs
= &pd
->pd_PUnit
->pu_Prefs
;
668 dprefs
->PrinterType
= pd
->pd_PrinterType
;
670 strncpy(dprefs
->PrinterFilename
, uprefs
->pp_Txt
.pt_Driver
,
671 sizeof(dprefs
->PrinterFilename
));
672 dprefs
->PrinterFilename
[sizeof(dprefs
->PrinterFilename
)-1] = 0;
674 dprefs
->PrintPitch
= uprefs
->pp_Txt
.pt_Pitch
;
675 dprefs
->PrintQuality
= uprefs
->pp_Txt
.pt_Quality
;
676 dprefs
->PrintSpacing
= uprefs
->pp_Txt
.pt_Spacing
;
677 dprefs
->PrintLeftMargin
= uprefs
->pp_Txt
.pt_LeftMargin
;
678 dprefs
->PrintRightMargin
= uprefs
->pp_Txt
.pt_RightMargin
;
679 dprefs
->PrintImage
= uprefs
->pp_Gfx
.pg_Image
;
680 dprefs
->PrintAspect
= uprefs
->pp_Gfx
.pg_Aspect
;
681 dprefs
->PrintShade
= uprefs
->pp_Gfx
.pg_Shade
;
682 dprefs
->PrintThreshold
= uprefs
->pp_Gfx
.pg_Threshold
;
683 dprefs
->PaperSize
= uprefs
->pp_Txt
.pt_PaperSize
;
684 dprefs
->PaperType
= uprefs
->pp_Txt
.pt_PaperType
;
685 dprefs
->PaperLength
= uprefs
->pp_Txt
.pt_PaperLength
;
687 if (uprefs
->pp_Unit
.pu_DeviceName
[0] == 0) {
688 if (uprefs
->pp_Txt
.pt_Port
== PP_PARALLEL
) {
689 strcpy(dprefs
->PrtDevName
, "parallel");
690 } else if (uprefs
->pp_Txt
.pt_Port
== PP_SERIAL
) {
691 strcpy(dprefs
->PrtDevName
, "serial");
693 strcpy(dprefs
->PrtDevName
, "printtofile");
696 strncpy(dprefs
->PrtDevName
, uprefs
->pp_Unit
.pu_DeviceName
, sizeof(dprefs
->PrtDevName
));
697 dprefs
->PrtDevName
[sizeof(dprefs
->PrtDevName
)-1]=0;
700 if (strcmp(dprefs
->PrtDevName
, "parallel") == 0 ||
701 strcmp(dprefs
->PrtDevName
, "usbparallel") == 0) {
702 pd
->pd_ior0
.pd_p0
.IOPar
.io_Message
.mn_Length
= sizeof(pd
->pd_ior0
.pd_p0
);
703 pd
->pd_ior0
.pd_p0
.io_ParFlags
= PARF_SHARED
;
704 pd
->pd_ior1
.pd_p1
.IOPar
.io_Message
.mn_Length
= sizeof(pd
->pd_ior1
.pd_p1
);
705 pd
->pd_ior1
.pd_p1
.io_ParFlags
= PARF_SHARED
;
706 } else if (strcmp(dprefs
->PrtDevName
, "serial") == 0) {
707 pd
->pd_ior0
.pd_s0
.IOSer
.io_Message
.mn_Length
= sizeof(pd
->pd_ior0
.pd_s0
);
708 pd
->pd_ior0
.pd_s0
.io_SerFlags
= SERF_SHARED
;
709 pd
->pd_ior1
.pd_s1
.IOSer
.io_Message
.mn_Length
= sizeof(pd
->pd_ior1
.pd_s1
);
710 pd
->pd_ior1
.pd_s1
.io_SerFlags
= SERF_SHARED
;
712 pd
->pd_ior0
.pd_i0
.io_Message
.mn_Length
= sizeof(pd
->pd_ior0
.pd_i0
);
713 pd
->pd_ior1
.pd_i1
.io_Message
.mn_Length
= sizeof(pd
->pd_ior1
.pd_i1
);
716 dprefs
->DefaultPrtUnit
= uprefs
->pp_Unit
.pu_UnitNum
;
717 dprefs
->PrintFlags
= uprefs
->pp_Gfx
.pg_GraphicFlags
;
718 dprefs
->PrintMaxWidth
= uprefs
->pp_Gfx
.pg_PrintMaxWidth
;
719 dprefs
->PrintMaxHeight
= uprefs
->pp_Gfx
.pg_PrintMaxHeight
;
720 dprefs
->PrintDensity
= uprefs
->pp_Gfx
.pg_PrintDensity
;
721 dprefs
->PrintXOffset
= uprefs
->pp_Gfx
.pg_PrintXOffset
;
724 /* Create a PrinterData plugin
726 struct PrinterUnit
*Printer_Unit(struct PrinterBase
*PrinterBase
, LONG unitnum
)
728 struct PrinterUnit
*pu
;
729 struct PrinterPrefs prefs
;
730 BPTR olddir
, dir
, driverseg
;
732 if (!Printer_LoadPrefs(PrinterBase
, unitnum
, &prefs
) || prefs
.pp_Txt
.pt_Driver
[0] == 0) {
733 D(bug("%s: No valid prefs for printer.device %d\n", __func__
, unitnum
));
737 if ((dir
= Lock("DEVS:Printers", SHARED_LOCK
)) != BNULL
) {
738 olddir
= CurrentDir(dir
);
739 driverseg
= LoadSeg(prefs
.pp_Txt
.pt_Driver
);
743 D(bug("%s: %s => %p\n", __func__
, prefs
.pp_Txt
.pt_Driver
, BADDR(driverseg
)));
746 struct PrinterSegment
*prtseg
= BADDR(driverseg
);
748 D(bug("%s: magic 0x%08x, expect 0x%08x\n", __func__
, prtseg
->ps_runAlert
, AROS_PRINTER_MAGIC
));
749 if (prtseg
->ps_runAlert
== AROS_PRINTER_MAGIC
) {
751 AROS_SLIB_ENTRY(OpenDevice
,PrinterUnit
,1),
752 AROS_SLIB_ENTRY(CloseDevice
,PrinterUnit
,2),
753 AROS_SLIB_ENTRY(Expunge
,PrinterUnit
,3),
755 AROS_SLIB_ENTRY(BeginIO
,PrinterUnit
,5),
756 AROS_SLIB_ENTRY(AbortIO
,PrinterUnit
,6),
760 if ((pu
= (struct PrinterUnit
*)MakeLibrary(funcs
, NULL
, NULL
, sizeof(*pu
), driverseg
))) {
761 struct Process
*proc
;
762 struct PrinterData
*pd
= &pu
->pu_PrinterData
;
763 struct Device
*dev
= (struct Device
*)pu
;
765 /* Loop back to self */
766 pu
->pu_PrinterBase
= PrinterBase
;
769 /* Duplicate the prefs */
770 CopyMem(&prefs
, &pu
->pu_Prefs
, sizeof(prefs
));
772 /* Update pd->pd_Preferences from pu->pu_Prefs */
775 dev
->dd_Library
.lib_Node
.ln_Name
= pu
->pu_Prefs
.pp_DeviceUnit
.pd_UnitName
;
776 dev
->dd_Library
.lib_Version
= prtseg
->ps_Version
;
777 dev
->dd_Library
.lib_Revision
= prtseg
->ps_Revision
;
778 /* Magic token for TASK_PRINTERDATA() macro */
779 dev
->dd_Library
.lib_IdString
= (APTR
)driverID
;
781 pd
->pd_Device
.dd_Segment
= BADDR(driverseg
);
782 pd
->pd_Device
.dd_ExecBase
= SysBase
;
783 pd
->pd_Device
.dd_CmdVectors
= prtseg
->ps_PED
.ped_Commands
;
784 pd
->pd_Device
.dd_CmdBytes
= NULL
;
785 pd
->pd_Device
.dd_NumCommands
= aRAW
+ 1;
786 pd
->pd_PrinterSegment
= driverseg
;
787 pd
->pd_PrinterType
= 0;
788 pd
->pd_SegmentData
= prtseg
;
789 pd
->pd_PWrite
= pd_PWrite
;
790 pd
->pd_PBothReady
= pd_PBothReady
;
791 pd
->pd_PRead
= pd_PRead
;
792 pd
->pd_CallErrHook
= (APTR
)pd_CallErrHook
;
793 pd
->pd_PQuery
= pd_PQuery
;
794 pd
->pd_UnitNumber
= unitnum
;
795 pd
->pd_DriverName
= &pd
->pd_Preferences
.PrinterFilename
[0];
797 /* Make RemDevice() and friends happy */
800 proc
= CreateNewProcTags(NP_Entry
, pd_DriverTask
,
801 NP_Name
, prefs
.pp_DeviceUnit
.pd_UnitName
,
806 D(bug("%s: Driver process %p\n", __func__
, proc
));
808 struct MsgPort
*port
;
810 /* Store the process here... */
811 pu
->pu_Process
= proc
;
814 if ((port
= CreateMsgPort())) {
815 struct PrinterMessage startup
, *reply
;
817 D(bug("%s: Driver unit port %p\n", __func__
, port
));
818 startup
.mm_Message
.mn_ReplyPort
=port
;
819 startup
.mm_Message
.mn_Length
= sizeof(startup
);
820 startup
.mm_Magic
= AROS_MAKE_ID('p','r','u','n');
821 startup
.mm_Version
= 0;
822 PutMsg(&proc
->pr_MsgPort
, (struct Message
*)&startup
);
824 D(bug("%s: Driver replied\n", __func__
));
825 reply
= (struct PrinterMessage
*)GetMsg(port
);
826 D(bug("%s: Driver reply = %p\n", __func__
, reply
));
828 D(bug("%s: Driver port %p gone\n", __func__
, port
));
829 if (reply
== &startup
&&
830 reply
->mm_Message
.mn_Length
== sizeof(*reply
) &&
831 reply
->mm_Magic
== AROS_MAKE_ID('p','r','u','n') &&
832 reply
->mm_Version
== 0) {
834 D(bug("%s: Driver started\n", __func__
));
837 D(bug("%s: Driver startup failed\n", __func__
));
839 /* pd_DriverTask will kill itself on failure */
841 /* pd_Expunge() calls UnLoadSeg() automatically */
842 RemDevice((struct Device
*)pd
);
847 UnLoadSeg(driverseg
);