2 * Copyright (C) 2011, 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
10 #include <aros/debug.h>
12 #include <intuition/preferences.h> /* DEVNAME_SIZE */
13 #include <devices/serial.h>
14 #include <devices/printer.h>
16 #include <proto/exec.h>
17 #include <proto/dos.h>
18 #include <proto/utility.h>
20 #define NT_PORTARGS (NT_USER - 1)
22 #define UtilityBase (pb->pb_UtilityBase)
25 TEXT pb_DeviceName
[DEVNAME_SIZE
];
27 enum { PORT_SERIAL
, PORT_PARALLEL
, PORT_PRINTER
, PORT_STREAM
} pb_Mode
;
28 struct Library
*pb_UtilityBase
;
29 struct ExecBase
*pb_SysBase
;
31 /* Per-open settable arguments */
44 enum { PRT_COOKED
, PRT_RAW
, PRT_TRANSPARENT
} pr_Type
;
48 /* Only used in the per-open instances */
49 struct MsgPort
*pa_IOMsg
;
59 /* Decode the following flags:
66 * 9600 (and other baud rates)
69 static SIPTR
decodeArgs(struct portBase
*pb
, struct portArgs
*pa
, BSTR args
)
71 int loc
, len
= AROS_BSTR_strlen(args
);
72 CONST_STRPTR cp
= AROS_BSTR_ADDR(args
);
74 /* Skip any VOL: prefix */
75 for (loc
= 0; loc
< len
; loc
++) {
85 int slen
; /* length of section */
87 /* Advance to next section */
91 /* Find next section */
92 for (loc
= 0; loc
< len
; loc
++) {
101 /* Check for matches.. */
102 if (slen
>= 5 && (0 == Strnicmp(cp
, "UNIT=", 5))) {
103 CONST_STRPTR unit
= cp
+ 5;
108 for (i
= 0; i
< ulen
; i
++) {
109 if (unit
[i
] < '0' || unit
[i
] > '9')
112 uval
+= unit
[i
] - '0';
116 pa
->pa_DeviceUnit
= uval
;
118 } else if (pb
->pb_Mode
== PORT_PARALLEL
) {
119 /* No parallel.device options to process */
120 } else if (pb
->pb_Mode
== PORT_PRINTER
) {
121 if (slen
== 3 && Strnicmp(cp
, "RAW", 3) == 0) {
122 pa
->pa_Printer
.pr_Type
= PRT_RAW
;
123 } else if (slen
== 11 && Strnicmp(cp
, "TRANSPARENT", 11) == 0) {
124 pa
->pa_Printer
.pr_Type
= PRT_TRANSPARENT
;
126 } else if (pb
->pb_Mode
== PORT_SERIAL
) {
130 /* Check for all-numeric */
131 for (i
= 0; i
< slen
; i
++) {
132 if (cp
[i
] < '0' || cp
[i
] > '9')
138 pa
->pa_Serial
.ps_Baud
= baud
;
139 } else if (slen
== 3) {
140 TEXT bits
, mode
, stop
;
142 mode
= ToUpper(cp
[1]);
145 if ((bits
== '7' || bits
== '8') &&
146 (mode
== 'N' || mode
== 'O' || mode
== 'E' ||
147 mode
== 'M' || mode
== 'S') &&
148 (stop
== '1' || stop
== '2')) {
149 pa
->pa_Serial
.ps_StopBits
= stop
- '0';
150 pa
->pa_Serial
.ps_LenBits
= bits
- '0';
152 case 'N': pa
->pa_Serial
.ps_SerFlags
= 0;
153 pa
->pa_Serial
.ps_ExtFlags
= 0;
155 case 'O': pa
->pa_Serial
.ps_SerFlags
= SERF_PARTY_ON
| SERF_PARTY_ODD
;
156 pa
->pa_Serial
.ps_ExtFlags
= 0;
158 case 'E': pa
->pa_Serial
.ps_SerFlags
= SERF_PARTY_ON
;
159 pa
->pa_Serial
.ps_ExtFlags
= 0;
161 case 'M': pa
->pa_Serial
.ps_SerFlags
= SERF_PARTY_ON
;
162 pa
->pa_Serial
.ps_ExtFlags
= SEXTF_MSPON
| SEXTF_MARK
;
164 case 'S': pa
->pa_Serial
.ps_SerFlags
= SERF_PARTY_ON
;
165 pa
->pa_Serial
.ps_ExtFlags
= SEXTF_MSPON
;
177 static void portSerialDefaults(struct portArgs
*pa
)
181 pa
->pa_Serial
.ps_Baud
= 9600;
184 pa
->pa_Serial
.ps_Baud
= 115200;
187 pa
->pa_Serial
.ps_StopBits
= 1;
188 pa
->pa_Serial
.ps_SerFlags
= 0;
189 pa
->pa_Serial
.ps_ExtFlags
= 0;
192 /* Decode the startup message
194 static SIPTR
decodeStartup(struct portBase
*pb
, BPTR startup
)
196 struct ExecBase
*SysBase
= pb
->pb_SysBase
;
198 struct FileSysStartupMsg
*fssm
;
199 struct DosEnvec
*env
;
200 struct portArgs
*pa
= &pb
->pb_Defaults
;
201 SIPTR ret
= RETURN_OK
;
203 D(bug("\tStartup = %d\n", (SIPTR
)startup
));
205 switch ((SIPTR
)startup
) {
207 pb
->pb_Mode
= PORT_SERIAL
;
208 strcpy(pb
->pb_DeviceName
, "serial.device");
209 pa
->pa_DeviceUnit
= 0;
210 pb
->pb_DeviceFlags
= 0;
211 portSerialDefaults(pa
);
214 pb
->pb_Mode
= PORT_PARALLEL
;
215 strcpy(pb
->pb_DeviceName
, "parallel.device");
216 pa
->pa_DeviceUnit
= 0;
217 pb
->pb_DeviceFlags
= 0;
220 pb
->pb_Mode
= PORT_PRINTER
;
221 pa
->pa_Printer
.pr_Type
= PRT_COOKED
;
222 strcpy(pb
->pb_DeviceName
, "printer.device");
223 pa
->pa_DeviceUnit
= 0;
224 pb
->pb_DeviceFlags
= 0;
227 fssm
= BADDR(startup
);
228 if (fssm
->fssm_Device
== BNULL
) {
233 len
= AROS_BSTR_strlen(fssm
->fssm_Device
);
234 if (len
> sizeof(pb
->pb_DeviceName
)-1) {
239 CopyMem(AROS_BSTR_ADDR(fssm
->fssm_Device
), pb
->pb_DeviceName
, len
);
240 pb
->pb_DeviceName
[len
] = 0;
242 if (0 == Stricmp(pb
->pb_DeviceName
, "serial.device")) {
243 pb
->pb_Mode
= PORT_SERIAL
;
244 portSerialDefaults(pa
);
245 } else if (0 == Stricmp(pb
->pb_DeviceName
, "parallel.device")) {
246 pb
->pb_Mode
= PORT_PARALLEL
;
247 } else if (0 == Stricmp(pb
->pb_DeviceName
, "printer.device")) {
248 pb
->pb_Mode
= PORT_PRINTER
;
250 pb
->pb_Mode
= PORT_STREAM
;
252 pa
->pa_DeviceUnit
= fssm
->fssm_Unit
;
253 pb
->pb_DeviceFlags
= fssm
->fssm_Flags
;
254 if ((env
= BADDR(fssm
->fssm_Environ
)) &&
255 (env
->de_TableSize
> DE_CONTROL
) &&
256 ((BSTR
)env
->de_Control
!= BNULL
)) {
257 ret
= decodeArgs(pb
, pa
, (BSTR
)env
->de_Control
);
265 /* Open the device for IO
267 static struct portArgs
*portOpen(struct portBase
*pb
, struct portArgs
*pa
, BPTR name
, SIPTR
*err
)
269 int len
= AROS_BSTR_strlen(name
);
270 struct ExecBase
*SysBase
= pb
->pb_SysBase
;
272 if ((pa
= AllocVec(sizeof(*pa
) + len
+ 1, MEMF_ANY
))) {
273 CopyMem(&pb
->pb_Defaults
, pa
, sizeof(*pa
));
275 pa
->pa_Node
.ln_Type
= NT_PORTARGS
;
276 pa
->pa_Node
.ln_Name
= (APTR
)(&pa
[1]);
277 CopyMem(AROS_BSTR_ADDR(name
), pa
->pa_Node
.ln_Name
, len
);
278 pa
->pa_Node
.ln_Name
[len
] = 0;
280 decodeArgs(pb
, pa
, name
);
282 D(bug("%s: %s device=%s, unit=%d (%d), mode=%d\n",
283 __func__
, name
, pb
->pb_DeviceName
,
284 pa
->pa_DeviceUnit
, pb
->pb_DeviceFlags
,
287 if ((pa
->pa_IOMsg
= CreateMsgPort())) {
288 if ((pa
->pa_IO
= (APTR
)CreateIORequest(pa
->pa_IOMsg
, sizeof(*pa
->pa_IO
)))) {
289 if (0 == OpenDevice(pb
->pb_DeviceName
, pa
->pa_DeviceUnit
, (struct IORequest
*)pa
->pa_IO
, pb
->pb_DeviceFlags
)) {
290 D(bug("%s: Device is open\n", __func__
));
292 if (pb
->pb_Mode
!= PORT_SERIAL
) {
293 AddTail(&pb
->pb_Files
, &pa
->pa_Node
);
297 pa
->pa_IO
->ser
.IOSer
.io_Command
= SDCMD_SETPARAMS
;
298 /* xON xOFF ENQ ACK */
299 pa
->pa_IO
->ser
.io_CtlChar
= SER_DEFAULT_CTLCHAR
;
300 pa
->pa_IO
->ser
.io_RBufLen
= 64;
301 pa
->pa_IO
->ser
.io_SerFlags
= pa
->pa_Serial
.ps_SerFlags
;
302 pa
->pa_IO
->ser
.io_ExtFlags
= pa
->pa_Serial
.ps_ExtFlags
;
303 pa
->pa_IO
->ser
.io_Baud
= pa
->pa_Serial
.ps_Baud
;
304 pa
->pa_IO
->ser
.io_BrkTime
= 250000;
305 pa
->pa_IO
->ser
.io_TermArray
.TermArray0
= 0;
306 pa
->pa_IO
->ser
.io_TermArray
.TermArray1
= 1;
307 pa
->pa_IO
->ser
.io_ReadLen
= pa
->pa_Serial
.ps_LenBits
;
308 pa
->pa_IO
->ser
.io_WriteLen
= pa
->pa_Serial
.ps_LenBits
;
309 pa
->pa_IO
->ser
.io_StopBits
= pa
->pa_Serial
.ps_StopBits
;
311 if (0 == DoIO((struct IORequest
*)pa
->pa_IO
)) {
312 AddTail(&pb
->pb_Files
, &pa
->pa_Node
);
315 CloseDevice((struct IORequest
*)pa
->pa_IO
);
317 DeleteIORequest((struct IORequest
*)pa
->pa_IO
);
319 DeleteMsgPort(pa
->pa_IOMsg
);
324 D(bug("%s: Didn't open device\n", __func__
));
325 *err
= ERROR_NO_DISK
;
329 static void portClose(struct portArgs
*pa
, struct ExecBase
*SysBase
)
331 D(bug("%s: Close %s\n", pa
->pa_Node
.ln_Name
));
332 Remove(&pa
->pa_Node
);
333 CloseDevice((struct IORequest
*)pa
->pa_IO
);
334 DeleteIORequest((struct IORequest
*)pa
->pa_IO
);
335 DeleteMsgPort(pa
->pa_IOMsg
);
339 void replyPkt(struct DosPacket
*dp
, struct ExecBase
*SysBase
)
344 D(bug("%s: type=%d res1=%d, res2=0x%p\n", __func__
, dp
->dp_Type
, dp
->dp_Res1
, dp
->dp_Res2
));
347 mn
->mn_Node
.ln_Name
= (char*)dp
;
348 dp
->dp_Port
= &((struct Process
*)FindTask(NULL
))->pr_MsgPort
;
352 LONG
port_handler(struct ExecBase
*SysBase
)
354 struct DosPacket
*dp
;
358 struct FileHandle
*fh
;
359 struct portBase pb
= {};
362 pb
.pb_SysBase
= SysBase
;
364 NEWLIST(&pb
.pb_Files
);
366 mp
= &((struct Process
*)FindTask(NULL
))->pr_MsgPort
;
370 dp
= (struct DosPacket
*)(GetMsg(mp
)->mn_Node
.ln_Name
);
373 if ((pb
.pb_UtilityBase
= OpenLibrary("utility.library", 0))) {
374 res
= decodeStartup(&pb
, (BPTR
)dp
->dp_Arg2
);
378 ((struct DeviceNode
*)BADDR(dp
->dp_Arg3
))->dn_Task
= mp
;
381 dp
->dp_Res1
= (dp
->dp_Res2
== 0) ? DOSTRUE
: DOSFALSE
;
384 replyPkt(dp
, SysBase
);
386 dp
= (struct DosPacket
*)(GetMsg(mp
)->mn_Node
.ln_Name
);
387 D(bug("%s: type=%d\n", __func__
, dp
->dp_Type
));
389 switch (dp
->dp_Type
) {
390 case ACTION_FINDINPUT
:
391 case ACTION_FINDOUTPUT
:
392 case ACTION_FINDUPDATE
:
393 pa
= portOpen(&pb
, pa
, (BSTR
)dp
->dp_Arg3
, &dp
->dp_Res2
);
394 if (dp
->dp_Res2
== RETURN_OK
) {
395 fh
= BADDR(dp
->dp_Arg1
);
396 fh
->fh_Arg1
= (SIPTR
)pa
;
399 dp
->dp_Res1
= (dp
->dp_Res2
== 0) ? DOSTRUE
: DOSFALSE
;
402 if ((pa
= (struct portArgs
*)dp
->dp_Arg1
)) {
403 pa
->pa_IO
->std
.io_Command
= CMD_READ
;
404 pa
->pa_IO
->std
.io_Data
= (APTR
)dp
->dp_Arg2
;
405 pa
->pa_IO
->std
.io_Length
= dp
->dp_Arg3
;
406 pa
->pa_IO
->std
.io_Actual
= 0;
407 pa
->pa_IO
->std
.io_Offset
= 0;
408 pa
->pa_IO
->std
.io_Message
.mn_Length
= sizeof(pa
->pa_IO
->std
);
409 res
= DoIO((struct IORequest
*)pa
->pa_IO
);
411 dp
->dp_Res1
= pa
->pa_IO
->std
.io_Actual
;
414 dp
->dp_Res1
= DOSFALSE
;
415 dp
->dp_Res2
= ERROR_READ_PROTECTED
;
418 dp
->dp_Res1
= DOSFALSE
;
419 dp
->dp_Res2
= ERROR_OBJECT_WRONG_TYPE
;
423 if ((pa
= (struct portArgs
*)dp
->dp_Arg1
)) {
424 if (pb
.pb_Mode
== PORT_PRINTER
&&
425 pa
->pa_Printer
.pr_Type
== PRT_RAW
)
426 pa
->pa_IO
->std
.io_Command
= PRD_RAWWRITE
;
428 pa
->pa_IO
->std
.io_Command
= CMD_WRITE
;
429 pa
->pa_IO
->std
.io_Data
= (APTR
)dp
->dp_Arg2
;
430 pa
->pa_IO
->std
.io_Length
= dp
->dp_Arg3
;
431 pa
->pa_IO
->std
.io_Actual
= 0;
432 pa
->pa_IO
->std
.io_Offset
= 0;
433 pa
->pa_IO
->std
.io_Message
.mn_Length
= sizeof(pa
->pa_IO
->std
);
434 res
= DoIO((struct IORequest
*)pa
->pa_IO
);
436 dp
->dp_Res1
= pa
->pa_IO
->std
.io_Actual
;
439 dp
->dp_Res1
= DOSFALSE
;
440 dp
->dp_Res2
= ERROR_READ_PROTECTED
;
443 dp
->dp_Res1
= DOSFALSE
;
444 dp
->dp_Res2
= ERROR_OBJECT_WRONG_TYPE
;
448 if ((pa
= (struct portArgs
*)dp
->dp_Arg1
)) {
449 portClose(pa
, SysBase
);
450 dp
->dp_Res1
= DOSTRUE
;
453 dp
->dp_Res1
= DOSFALSE
;
454 dp
->dp_Res2
= ERROR_OBJECT_WRONG_TYPE
;
458 if (IsListEmpty(&pb
.pb_Files
)) {
459 dp
->dp_Res1
= DOSTRUE
;
463 dp
->dp_Res1
= DOSFALSE
;
464 dp
->dp_Res2
= ERROR_OBJECT_IN_USE
;
468 dp
->dp_Res1
= DOSFALSE
;
469 dp
->dp_Res2
= ERROR_ACTION_NOT_KNOWN
;
474 /* ACTION_DIE ends up here... */
475 D(bug("%s: Exiting\n"));
477 replyPkt(dp
, SysBase
);
479 CloseLibrary(pb
.pb_UtilityBase
);