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 IPTR args[] = { (IPTR)FindTask(NULL)->tc_Node.ln_Name, \
68 EasyRequestArgs(NULL, (struct EasyStruct *)&driverMisuse, \
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 if ((pd
->pd_ior0
.pd_p0
.IOPar
.io_Message
.mn_ReplyPort
=CreateMsgPort())) {
416 if (0 == OpenDevice(devname
,
417 pd
->pd_Preferences
.DefaultPrtUnit
,
418 (struct IORequest
*)&pd
->pd_ior0
, 0)) {
419 D(bug("%s: open %s %d for io 0\n", __func__
, devname
, pd
->pd_Preferences
.DefaultPrtUnit
));
420 pd
->pd_ior0
.pd_p0
.IOPar
.io_Message
.mn_Node
.ln_Type
= 0;
421 if ((pd
->pd_ior1
.pd_p1
.IOPar
.io_Message
.mn_ReplyPort
=CreateMsgPort())) {
422 if (0 == OpenDevice(devname
,
423 pd
->pd_Preferences
.DefaultPrtUnit
,
424 (struct IORequest
*)&pd
->pd_ior1
, 0)) {
425 pd
->pd_ior1
.pd_p1
.IOPar
.io_Message
.mn_Node
.ln_Type
= 0;
426 D(bug("%s: open %s %d for io 1\n", __func__
, devname
, pd
->pd_Preferences
.DefaultPrtUnit
));
427 if (initMsgPort(&pd
->pd_IORPort
)) {
428 pd
->pd_TIOR
.tr_node
.io_Message
.mn_ReplyPort
=&pd
->pd_IORPort
;
429 pd
->pd_TIOR
.tr_node
.io_Message
.mn_Length
= sizeof(pd
->pd_TIOR
);
430 if (0 == OpenDevice("timer.device", UNIT_VBLANK
,
431 (struct IORequest
*)&pd
->pd_TIOR
, 0)) {
432 D(bug("%s: open timer.device %d\n", __func__
, UNIT_VBLANK
));
433 if (ped
->ped_Render
) {
434 LONG err
= ped
->ped_Render(0, 0, 0, PRS_PREINIT
);
441 FreeSignal(pd
->pd_IORPort
.mp_SigBit
);
443 CloseDevice((struct IORequest
*)&pd
->pd_ior1
);
445 DeleteMsgPort(pd
->pd_ior1
.pd_p1
.IOPar
.io_Message
.mn_ReplyPort
);
447 CloseDevice((struct IORequest
*)&pd
->pd_ior0
);
449 DeleteMsgPort(pd
->pd_ior0
.pd_p0
.IOPar
.io_Message
.mn_ReplyPort
);
451 pd
->pd_SegmentData
->ps_PED
.ped_Expunge();
453 FreeSignal(pd
->pd_Unit
.mp_SigBit
);
459 static VOID
pd_Close(struct PrinterData
*pd
, union printerIO
*pio
)
461 struct PrinterBase
*PrinterBase
= pd
->pd_PUnit
->pu_PrinterBase
;
462 struct PrinterExtendedData
*ped
= &pd
->pd_SegmentData
->ps_PED
;
463 LONG unitnum
= pd
->pd_PUnit
->pu_Prefs
.pp_DeviceUnit
.pd_UnitNum
;
467 if (!(pd
->pd_Flags
& PDF_NOIO
)) {
468 CloseDevice((struct IORequest
*)&pd
->pd_TIOR
);
469 FreeSignal(pd
->pd_IORPort
.mp_SigBit
);
470 CloseDevice((struct IORequest
*)&pd
->pd_ior1
);
471 DeleteMsgPort(pd
->pd_ior1
.pd_p1
.IOPar
.io_Message
.mn_ReplyPort
);
472 CloseDevice((struct IORequest
*)&pd
->pd_ior0
);
473 DeleteMsgPort(pd
->pd_ior0
.pd_p0
.IOPar
.io_Message
.mn_ReplyPort
);
475 FreeSignal(pd
->pd_Unit
.mp_SigBit
);
479 /* Remove from the parent printer.device */
480 ObtainSemaphore(&PrinterBase
->pb_UnitLock
[unitnum
]);
481 PrinterBase
->pb_Unit
[unitnum
] = NULL
;
483 PrinterBase
->pb_Device
.dd_Library
.lib_OpenCnt
--;
485 ReleaseSemaphore(&PrinterBase
->pb_UnitLock
[unitnum
]);
488 static LONG
pd_DoPreferences(const union printerIO
*pio
, LONG command
)
492 TASK_PRINTERDATA(pd
);
494 if (pd
->pd_SegmentData
->ps_Version
>= 44 &&
495 (pd
->pd_SegmentData
->ps_PED
.ped_PrinterClass
& PPCF_EXTENDED
) &&
496 pd
->pd_SegmentData
->ps_PED
.ped_DoPreferences
!= NULL
) {
497 err
= pd
->pd_SegmentData
->ps_PED
.ped_DoPreferences((union printerIO
*)pio
, command
);
516 /* A driver task is created on an OpenDevice() call,
517 * and is killed by a CloseDevice() call.
519 static LONG
pd_DriverTask(VOID
)
521 TASK_PRINTERDATA(pd
);
523 struct Process
*me
= (struct Process
*)FindTask(NULL
);
524 struct PrinterExtendedData
*ped
= &pd
->pd_SegmentData
->ps_PED
;
525 struct PrinterMessage
*msg
= NULL
;
526 union printerIO
*pio
;
528 BOOL stopped
= FALSE
;
531 /* Wait for startup message -
532 * we use the DOS port because the
533 * pd_Unit has not been created yet
535 D(bug("%s: Waiting for startup. pd=%p\n", __func__
, pd
));
536 WaitPort(&me
->pr_MsgPort
);
537 msg
= (struct PrinterMessage
*)GetMsg(&me
->pr_MsgPort
);
539 D(bug("%s: Initializing driver, Unit Port %p\n", __func__
, &pd
->pd_Unit
));
542 /* We want to look like a TURBOPRINT driver
543 * TPMATCHWORD is in the 3rd ULONG in pd_OldStk
544 * TURBOPRINT was documented as using:
546 * (BOOL)TP_Installed = ( ((ULONG *)(PD->pd_OldStk))[2] == TPMATCHWORD)
548 * So the assumption is that this ULONG is in native endian format.
550 ((ULONG
*)(pd
->pd_OldStk
))[2] = TPMATCHWORD
;
553 D(bug("%s: Replying with %d\n", __func__
, ret
));
554 msg
->mm_Version
= ret
;
555 ReplyMsg(&msg
->mm_Message
);
560 /* Wait for unit messages on the pd_Unit */
564 D(bug("%s: Waiting for command on port %p\n", __func__
, &pd
->pd_Unit
));
565 WaitPort(&pd
->pd_Unit
);
566 pio
= (union printerIO
*)GetMsg(&pd
->pd_Unit
);
567 cmd
= pio
->ios
.io_Command
;
569 D(bug("%s: Command = %d\n", __func__
, cmd
));
572 err
= ped
->ped_Open(pio
);
574 Printer_Text_Write(pd
, "\033#1", 3); /* aRIN */
576 case CMD_CLOSEDEVICE
:
580 AbortIO((struct IORequest
*)&pd
->pd_ior0
);
581 WaitIOStd((struct IOStdReq
*)&pd
->pd_ior0
);
582 AbortIO((struct IORequest
*)&pd
->pd_ior1
);
583 WaitIOStd((struct IOStdReq
*)&pd
->pd_ior1
);
589 err
= Printer_Text_Command(pd
, aRIN
, 0, 0, 0, 0);
602 err
= Printer_Text_Write(pd
, pio
->ios
.io_Data
, pio
->ios
.io_Length
);
604 pio
->ios
.io_Actual
= pio
->ios
.io_Length
;
611 err
= pd_PWrite(pio
->ios
.io_Data
, pio
->ios
.io_Length
);
613 pio
->ios
.io_Actual
= pio
->ios
.io_Length
;
622 err
= pd_DoPreferences(pio
, pio
->ios
.io_Command
);
625 pd
->pd_PUnit
->pu_ErrHook
= ((struct IOPrtErrReq
*)pio
)->io_Hook
;
627 case PRD_DUMPRPORTTAGS
:
631 err
= Printer_Gfx_DumpRPort((struct IODRPReq
*)pio
, ((struct IODRPTagsReq
*)pio
)->io_TagList
);
634 case PRD_TPEXTDUMPRPORT
:
638 err
= Printer_Gfx_DumpRPort((struct IODRPReq
*)pio
, NULL
);
641 err
= pd_Query(&pio
->ios
);
647 pio
->ios
.io_Error
= err
;
648 D(bug("%s: Command = %d, Result = %d\n", __func__
, cmd
, err
));
650 ReplyMsg((struct Message
*)pio
);
651 } while (cmd
!= CMD_CLOSEDEVICE
);
653 D(bug("%s: Shutting down\n", __func__
));
658 /* Synchronize old-style prefs with new style prefs
660 static void pd_SyncPrefs(struct PrinterData
*pd
)
662 struct Preferences
*dprefs
= &pd
->pd_Preferences
;
663 struct PrinterPrefs
*uprefs
= &pd
->pd_PUnit
->pu_Prefs
;
665 dprefs
->PrinterType
= pd
->pd_PrinterType
;
667 strncpy(dprefs
->PrinterFilename
, uprefs
->pp_Txt
.pt_Driver
,
668 sizeof(dprefs
->PrinterFilename
));
669 dprefs
->PrinterFilename
[sizeof(dprefs
->PrinterFilename
)-1] = 0;
671 dprefs
->PrintPitch
= uprefs
->pp_Txt
.pt_Pitch
;
672 dprefs
->PrintQuality
= uprefs
->pp_Txt
.pt_Quality
;
673 dprefs
->PrintSpacing
= uprefs
->pp_Txt
.pt_Spacing
;
674 dprefs
->PrintLeftMargin
= uprefs
->pp_Txt
.pt_LeftMargin
;
675 dprefs
->PrintRightMargin
= uprefs
->pp_Txt
.pt_RightMargin
;
676 dprefs
->PrintImage
= uprefs
->pp_Gfx
.pg_Image
;
677 dprefs
->PrintAspect
= uprefs
->pp_Gfx
.pg_Aspect
;
678 dprefs
->PrintShade
= uprefs
->pp_Gfx
.pg_Shade
;
679 dprefs
->PrintThreshold
= uprefs
->pp_Gfx
.pg_Threshold
;
680 dprefs
->PaperSize
= uprefs
->pp_Txt
.pt_PaperSize
;
681 dprefs
->PaperType
= uprefs
->pp_Txt
.pt_PaperType
;
682 dprefs
->PaperLength
= uprefs
->pp_Txt
.pt_PaperLength
;
684 if (uprefs
->pp_Unit
.pu_DeviceName
[0] == 0) {
685 if (uprefs
->pp_Txt
.pt_Port
== PP_PARALLEL
) {
686 strcpy(dprefs
->PrtDevName
, "parallel");
687 } else if (uprefs
->pp_Txt
.pt_Port
== PP_SERIAL
) {
688 strcpy(dprefs
->PrtDevName
, "serial");
690 strcpy(dprefs
->PrtDevName
, "printtofile");
693 strncpy(dprefs
->PrtDevName
, uprefs
->pp_Unit
.pu_DeviceName
, sizeof(dprefs
->PrtDevName
));
694 dprefs
->PrtDevName
[sizeof(dprefs
->PrtDevName
)-1]=0;
697 if (strcmp(dprefs
->PrtDevName
, "parallel") == 0 ||
698 strcmp(dprefs
->PrtDevName
, "usbparallel") == 0) {
699 pd
->pd_ior0
.pd_p0
.IOPar
.io_Message
.mn_Length
= sizeof(pd
->pd_ior0
.pd_p0
);
700 pd
->pd_ior0
.pd_p0
.io_ParFlags
= PARF_SHARED
;
701 pd
->pd_ior1
.pd_p1
.IOPar
.io_Message
.mn_Length
= sizeof(pd
->pd_ior1
.pd_p1
);
702 pd
->pd_ior1
.pd_p1
.io_ParFlags
= PARF_SHARED
;
703 } else if (strcmp(dprefs
->PrtDevName
, "serial") == 0) {
704 pd
->pd_ior0
.pd_s0
.IOSer
.io_Message
.mn_Length
= sizeof(pd
->pd_ior0
.pd_s0
);
705 pd
->pd_ior0
.pd_s0
.io_SerFlags
= SERF_SHARED
;
706 pd
->pd_ior1
.pd_s1
.IOSer
.io_Message
.mn_Length
= sizeof(pd
->pd_ior1
.pd_s1
);
707 pd
->pd_ior1
.pd_s1
.io_SerFlags
= SERF_SHARED
;
709 pd
->pd_ior0
.pd_i0
.io_Message
.mn_Length
= sizeof(pd
->pd_ior0
.pd_i0
);
710 pd
->pd_ior1
.pd_i1
.io_Message
.mn_Length
= sizeof(pd
->pd_ior1
.pd_i1
);
713 dprefs
->DefaultPrtUnit
= uprefs
->pp_Unit
.pu_UnitNum
;
714 dprefs
->PrintFlags
= uprefs
->pp_Gfx
.pg_GraphicFlags
;
715 dprefs
->PrintMaxWidth
= uprefs
->pp_Gfx
.pg_PrintMaxWidth
;
716 dprefs
->PrintMaxHeight
= uprefs
->pp_Gfx
.pg_PrintMaxHeight
;
717 dprefs
->PrintDensity
= uprefs
->pp_Gfx
.pg_PrintDensity
;
718 dprefs
->PrintXOffset
= uprefs
->pp_Gfx
.pg_PrintXOffset
;
721 /* Create a PrinterData plugin
723 struct PrinterUnit
*Printer_Unit(struct PrinterBase
*PrinterBase
, LONG unitnum
)
725 struct PrinterUnit
*pu
;
726 struct PrinterPrefs prefs
;
727 BPTR olddir
, dir
, driverseg
;
729 if (!Printer_LoadPrefs(PrinterBase
, unitnum
, &prefs
) || prefs
.pp_Txt
.pt_Driver
[0] == 0) {
730 D(bug("%s: No valid prefs for printer.device %d\n", __func__
, unitnum
));
734 if ((dir
= Lock("DEVS:Printers", SHARED_LOCK
)) != BNULL
) {
735 olddir
= CurrentDir(dir
);
736 driverseg
= LoadSeg(prefs
.pp_Txt
.pt_Driver
);
740 D(bug("%s: %s => %p\n", __func__
, prefs
.pp_Txt
.pt_Driver
, BADDR(driverseg
)));
743 struct PrinterSegment
*prtseg
= BADDR(driverseg
);
745 D(bug("%s: magic 0x%08x, expect 0x%08x\n", __func__
, prtseg
->ps_runAlert
, AROS_PRINTER_MAGIC
));
746 if (prtseg
->ps_runAlert
== AROS_PRINTER_MAGIC
) {
748 AROS_SLIB_ENTRY(OpenDevice
,PrinterUnit
,1),
749 AROS_SLIB_ENTRY(CloseDevice
,PrinterUnit
,2),
750 AROS_SLIB_ENTRY(Expunge
,PrinterUnit
,3),
752 AROS_SLIB_ENTRY(BeginIO
,PrinterUnit
,5),
753 AROS_SLIB_ENTRY(AbortIO
,PrinterUnit
,6),
757 if ((pu
= (struct PrinterUnit
*)MakeLibrary(funcs
, NULL
, NULL
, sizeof(*pu
), driverseg
))) {
758 struct Process
*proc
;
759 struct PrinterData
*pd
= &pu
->pu_PrinterData
;
760 struct Device
*dev
= (struct Device
*)pu
;
762 /* Loop back to self */
763 pu
->pu_PrinterBase
= PrinterBase
;
766 /* Duplicate the prefs */
767 CopyMem(&prefs
, &pu
->pu_Prefs
, sizeof(prefs
));
769 /* Update pd->pd_Preferences from pu->pu_Prefs */
772 dev
->dd_Library
.lib_Node
.ln_Name
= pu
->pu_Prefs
.pp_DeviceUnit
.pd_UnitName
;
773 dev
->dd_Library
.lib_Version
= prtseg
->ps_Version
;
774 dev
->dd_Library
.lib_Revision
= prtseg
->ps_Revision
;
775 /* Magic token for TASK_PRINTERDATA() macro */
776 dev
->dd_Library
.lib_IdString
= (APTR
)driverID
;
778 pd
->pd_Device
.dd_Segment
= BADDR(driverseg
);
779 pd
->pd_Device
.dd_ExecBase
= SysBase
;
780 pd
->pd_Device
.dd_CmdVectors
= prtseg
->ps_PED
.ped_Commands
;
781 pd
->pd_Device
.dd_CmdBytes
= NULL
;
782 pd
->pd_Device
.dd_NumCommands
= aRAW
+ 1;
783 pd
->pd_PrinterSegment
= driverseg
;
784 pd
->pd_PrinterType
= 0;
785 pd
->pd_SegmentData
= prtseg
;
786 pd
->pd_PWrite
= pd_PWrite
;
787 pd
->pd_PBothReady
= pd_PBothReady
;
788 pd
->pd_PRead
= pd_PRead
;
789 pd
->pd_CallErrHook
= (APTR
)pd_CallErrHook
;
790 pd
->pd_PQuery
= pd_PQuery
;
791 pd
->pd_UnitNumber
= unitnum
;
792 pd
->pd_DriverName
= &pd
->pd_Preferences
.PrinterFilename
[0];
794 /* Make RemDevice() and friends happy */
797 proc
= CreateNewProcTags(NP_Entry
, pd_DriverTask
,
798 NP_Name
, prefs
.pp_DeviceUnit
.pd_UnitName
,
803 D(bug("%s: Driver process %p\n", __func__
, proc
));
805 struct MsgPort
*port
;
807 /* Store the process here... */
808 pu
->pu_Process
= proc
;
811 if ((port
= CreateMsgPort())) {
812 struct PrinterMessage startup
, *reply
;
814 D(bug("%s: Driver unit port %p\n", __func__
, port
));
815 startup
.mm_Message
.mn_ReplyPort
=port
;
816 startup
.mm_Message
.mn_Length
= sizeof(startup
);
817 startup
.mm_Magic
= AROS_MAKE_ID('p','r','u','n');
818 startup
.mm_Version
= 0;
819 PutMsg(&proc
->pr_MsgPort
, (struct Message
*)&startup
);
821 D(bug("%s: Driver replied\n", __func__
));
822 reply
= (struct PrinterMessage
*)GetMsg(port
);
823 D(bug("%s: Driver reply = %p\n", __func__
, reply
));
825 D(bug("%s: Driver port %p gone\n", __func__
, port
));
826 if (reply
== &startup
&&
827 reply
->mm_Message
.mn_Length
== sizeof(*reply
) &&
828 reply
->mm_Magic
== AROS_MAKE_ID('p','r','u','n') &&
829 reply
->mm_Version
== 0) {
831 D(bug("%s: Driver started\n", __func__
));
834 D(bug("%s: Driver startup failed\n", __func__
));
836 /* pd_DriverTask will kill itself on failure */
838 /* pd_Expunge() calls UnLoadSeg() automatically */
839 RemDevice((struct Device
*)pd
);
844 UnLoadSeg(driverseg
);