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
;
30 /* Per-open settable arguments */
43 enum { PRT_COOKED
, PRT_RAW
, PRT_TRANSPARENT
} pr_Type
;
47 /* Only used in the per-open instances */
48 struct MsgPort
*pa_IOMsg
;
58 /* Decode the following flags:
65 * 9600 (and other baud rates)
68 static SIPTR
decodeArgs(struct portBase
*pb
, struct portArgs
*pa
, BSTR args
)
70 int loc
, len
= AROS_BSTR_strlen(args
);
71 CONST_STRPTR cp
= AROS_BSTR_ADDR(args
);
73 /* Skip any VOL: prefix */
74 for (loc
= 0; loc
< len
; loc
++) {
84 int slen
; /* length of section */
86 /* Advance to next section */
90 /* Find next section */
91 for (loc
= 0; loc
< len
; loc
++) {
100 /* Check for matches.. */
101 if (slen
>= 5 && (0 == Strnicmp(cp
, "UNIT=", 5))) {
102 CONST_STRPTR unit
= cp
+ 5;
107 for (i
= 0; i
< ulen
; i
++) {
108 if (unit
[i
] < '0' || unit
[i
] > '9')
111 uval
+= unit
[i
] - '0';
115 pa
->pa_DeviceUnit
= uval
;
117 } else if (pb
->pb_Mode
== PORT_PARALLEL
) {
118 /* No parallel.device options to process */
119 } else if (pb
->pb_Mode
== PORT_PRINTER
) {
120 if (slen
== 3 && Strnicmp(cp
, "RAW", 3) == 0) {
121 pa
->pa_Printer
.pr_Type
= PRT_RAW
;
122 } else if (slen
== 11 && Strnicmp(cp
, "TRANSPARENT", 11) == 0) {
123 pa
->pa_Printer
.pr_Type
= PRT_TRANSPARENT
;
125 } else if (pb
->pb_Mode
== PORT_SERIAL
) {
129 /* Check for all-numeric */
130 for (i
= 0; i
< slen
; i
++) {
131 if (cp
[i
] < '0' || cp
[i
] > '9')
137 pa
->pa_Serial
.ps_Baud
= baud
;
138 } else if (slen
== 3) {
139 TEXT bits
, mode
, stop
;
141 mode
= ToUpper(cp
[1]);
144 if ((bits
== '7' || bits
== '8') &&
145 (mode
== 'N' || mode
== 'O' || mode
== 'E' ||
146 mode
== 'M' || mode
== 'S') &&
147 (stop
== '1' || stop
== '2')) {
148 pa
->pa_Serial
.ps_StopBits
= stop
- '0';
149 pa
->pa_Serial
.ps_LenBits
= bits
- '0';
151 case 'N': pa
->pa_Serial
.ps_SerFlags
= 0;
152 pa
->pa_Serial
.ps_ExtFlags
= 0;
154 case 'O': pa
->pa_Serial
.ps_SerFlags
= SERF_PARTY_ON
| SERF_PARTY_ODD
;
155 pa
->pa_Serial
.ps_ExtFlags
= 0;
157 case 'E': pa
->pa_Serial
.ps_SerFlags
= SERF_PARTY_ON
;
158 pa
->pa_Serial
.ps_ExtFlags
= 0;
160 case 'M': pa
->pa_Serial
.ps_SerFlags
= SERF_PARTY_ON
;
161 pa
->pa_Serial
.ps_ExtFlags
= SEXTF_MSPON
| SEXTF_MARK
;
163 case 'S': pa
->pa_Serial
.ps_SerFlags
= SERF_PARTY_ON
;
164 pa
->pa_Serial
.ps_ExtFlags
= SEXTF_MSPON
;
176 static void portSerialDefaults(struct portArgs
*pa
)
179 pa
->pa_Serial
.ps_StopBits
= 1;
180 pa
->pa_Serial
.ps_Baud
= 9600;
181 pa
->pa_Serial
.ps_SerFlags
= 0;
182 pa
->pa_Serial
.ps_ExtFlags
= 0;
185 /* Decode the startup message
187 static SIPTR
decodeStartup(struct portBase
*pb
, BPTR startup
)
190 struct FileSysStartupMsg
*fssm
;
191 struct DosEnvec
*env
;
192 struct portArgs
*pa
= &pb
->pb_Defaults
;
193 SIPTR ret
= RETURN_OK
;
195 switch ((SIPTR
)startup
) {
197 pb
->pb_Mode
= PORT_SERIAL
;
198 strcpy(pb
->pb_DeviceName
, "serial.device");
199 pa
->pa_DeviceUnit
= 0;
200 pb
->pb_DeviceFlags
= 0;
201 portSerialDefaults(pa
);
204 pb
->pb_Mode
= PORT_PARALLEL
;
205 strcpy(pb
->pb_DeviceName
, "parallel.device");
206 pa
->pa_DeviceUnit
= 0;
207 pb
->pb_DeviceFlags
= 0;
210 pb
->pb_Mode
= PORT_PRINTER
;
211 pa
->pa_Printer
.pr_Type
= PRT_COOKED
;
212 strcpy(pb
->pb_DeviceName
, "printer.device");
213 pa
->pa_DeviceUnit
= 0;
214 pb
->pb_DeviceFlags
= 0;
217 fssm
= BADDR(startup
);
218 if (fssm
->fssm_Device
== BNULL
) {
223 len
= AROS_BSTR_strlen(fssm
->fssm_Device
);
224 if (len
> sizeof(pb
->pb_DeviceName
)-1) {
229 CopyMem(AROS_BSTR_ADDR(fssm
->fssm_Device
), pb
->pb_DeviceName
, len
);
230 pb
->pb_DeviceName
[len
] = 0;
232 if (0 == Stricmp(pb
->pb_DeviceName
, "serial.device")) {
233 pb
->pb_Mode
= PORT_SERIAL
;
234 portSerialDefaults(pa
);
235 } else if (0 == Stricmp(pb
->pb_DeviceName
, "parallel.device")) {
236 pb
->pb_Mode
= PORT_PARALLEL
;
237 } else if (0 == Stricmp(pb
->pb_DeviceName
, "printer.device")) {
238 pb
->pb_Mode
= PORT_PRINTER
;
240 pb
->pb_Mode
= PORT_STREAM
;
242 pa
->pa_DeviceUnit
= fssm
->fssm_Unit
;
243 pb
->pb_DeviceFlags
= fssm
->fssm_Flags
;
244 if ((env
= BADDR(fssm
->fssm_Environ
)) &&
245 (env
->de_TableSize
> DE_CONTROL
) &&
246 ((BSTR
)env
->de_Control
!= BNULL
)) {
247 ret
= decodeArgs(pb
, pa
, (BSTR
)env
->de_Control
);
255 /* Open the device for IO
257 static struct portArgs
*portOpen(struct portBase
*pb
, struct portArgs
*pa
, BPTR name
, SIPTR
*err
)
259 int len
= AROS_BSTR_strlen(name
);
261 if ((pa
= AllocVec(sizeof(*pa
) + len
+ 1, MEMF_ANY
))) {
262 CopyMem(&pb
->pb_Defaults
, pa
, sizeof(*pa
));
264 pa
->pa_Node
.ln_Type
= NT_PORTARGS
;
265 pa
->pa_Node
.ln_Name
= (APTR
)(&pa
[1]);
266 CopyMem(AROS_BSTR_ADDR(name
), pa
->pa_Node
.ln_Name
, len
);
267 pa
->pa_Node
.ln_Name
[len
] = 0;
269 decodeArgs(pb
, pa
, name
);
271 if ((pa
->pa_IOMsg
= CreateMsgPort())) {
272 if ((pa
->pa_IO
= (APTR
)CreateIORequest(pa
->pa_IOMsg
, sizeof(*pa
->pa_IO
)))) {
273 if (0 == OpenDevice(pb
->pb_DeviceName
, pa
->pa_DeviceUnit
, (struct IORequest
*)pa
->pa_IO
, pb
->pb_DeviceFlags
)) {
275 if (pb
->pb_Mode
!= PORT_SERIAL
) {
276 AddTail(&pb
->pb_Files
, &pa
->pa_Node
);
280 pa
->pa_IO
->ser
.IOSer
.io_Command
= SDCMD_SETPARAMS
;
281 /* xON xOFF ENQ ACK */
282 pa
->pa_IO
->ser
.io_CtlChar
= SER_DEFAULT_CTLCHAR
;
283 pa
->pa_IO
->ser
.io_RBufLen
= 64;
284 pa
->pa_IO
->ser
.io_SerFlags
= pa
->pa_Serial
.ps_SerFlags
;
285 pa
->pa_IO
->ser
.io_ExtFlags
= pa
->pa_Serial
.ps_ExtFlags
;
286 pa
->pa_IO
->ser
.io_Baud
= pa
->pa_Serial
.ps_Baud
;
287 pa
->pa_IO
->ser
.io_BrkTime
= 250000;
288 pa
->pa_IO
->ser
.io_TermArray
.TermArray0
= 0;
289 pa
->pa_IO
->ser
.io_TermArray
.TermArray1
= 1;
290 pa
->pa_IO
->ser
.io_ReadLen
= pa
->pa_Serial
.ps_LenBits
;
291 pa
->pa_IO
->ser
.io_WriteLen
= pa
->pa_Serial
.ps_LenBits
;
292 pa
->pa_IO
->ser
.io_StopBits
= pa
->pa_Serial
.ps_StopBits
;
294 if (0 == DoIO((struct IORequest
*)pa
->pa_IO
)) {
295 AddTail(&pb
->pb_Files
, &pa
->pa_Node
);
298 CloseDevice((struct IORequest
*)pa
->pa_IO
);
300 DeleteIORequest((struct IORequest
*)pa
->pa_IO
);
302 DeleteMsgPort(pa
->pa_IOMsg
);
307 *err
= ERROR_NO_DISK
;
311 static void portClose(struct portArgs
*pa
)
313 Remove(&pa
->pa_Node
);
314 CloseDevice((struct IORequest
*)pa
->pa_IO
);
315 DeleteIORequest((struct IORequest
*)pa
->pa_IO
);
316 DeleteMsgPort(pa
->pa_IOMsg
);
320 __startup
void _main(void)
322 struct DosPacket
*dp
;
326 struct FileHandle
*fh
;
327 struct portBase pb
= {};
330 NEWLIST(&pb
.pb_Files
);
332 mp
= &((struct Process
*)FindTask(NULL
))->pr_MsgPort
;
336 dp
= (struct DosPacket
*)(GetMsg(mp
)->mn_Node
.ln_Name
);
339 if ((pb
.pb_UtilityBase
= OpenLibrary("utility.library", 0))) {
340 res
= decodeStartup(&pb
, (BPTR
)dp
->dp_Arg2
);
344 dp
->dp_Res1
= (dp
->dp_Res2
== 0) ? DOSTRUE
: DOSFALSE
;
347 PutMsg (dp
->dp_Port
, dp
->dp_Link
);
349 dp
= (struct DosPacket
*)(GetMsg(mp
)->mn_Node
.ln_Name
);
351 switch (dp
->dp_Type
) {
352 case ACTION_FINDINPUT
:
353 case ACTION_FINDOUTPUT
:
354 case ACTION_FINDUPDATE
:
355 pa
= portOpen(&pb
, pa
, (BSTR
)dp
->dp_Arg3
, &dp
->dp_Res2
);
356 if (dp
->dp_Res2
== RETURN_OK
) {
357 fh
= BADDR(dp
->dp_Arg1
);
358 fh
->fh_Arg1
= (SIPTR
)pa
;
361 dp
->dp_Res1
= (dp
->dp_Res2
== 0) ? DOSTRUE
: DOSFALSE
;
364 if ((pa
= (struct portArgs
*)dp
->dp_Arg1
)) {
365 pa
->pa_IO
->std
.io_Command
= CMD_READ
;
366 pa
->pa_IO
->std
.io_Data
= (APTR
)dp
->dp_Arg2
;
367 pa
->pa_IO
->std
.io_Length
= dp
->dp_Arg3
;
368 pa
->pa_IO
->std
.io_Actual
= 0;
369 pa
->pa_IO
->std
.io_Offset
= 0;
370 pa
->pa_IO
->std
.io_Message
.mn_Length
= sizeof(pa
->pa_IO
->std
);
371 res
= DoIO((struct IORequest
*)pa
->pa_IO
);
373 dp
->dp_Res1
= pa
->pa_IO
->std
.io_Actual
;
376 dp
->dp_Res1
= DOSFALSE
;
377 dp
->dp_Res2
= ERROR_READ_PROTECTED
;
380 dp
->dp_Res1
= DOSFALSE
;
381 dp
->dp_Res2
= ERROR_OBJECT_WRONG_TYPE
;
385 if ((pa
= (struct portArgs
*)dp
->dp_Arg1
)) {
386 if (pb
.pb_Mode
== PORT_PRINTER
&&
387 pa
->pa_Printer
.pr_Type
== PRT_RAW
)
388 pa
->pa_IO
->std
.io_Command
= PRD_RAWWRITE
;
390 pa
->pa_IO
->std
.io_Command
= CMD_WRITE
;
391 pa
->pa_IO
->std
.io_Data
= (APTR
)dp
->dp_Arg2
;
392 pa
->pa_IO
->std
.io_Length
= dp
->dp_Arg3
;
393 pa
->pa_IO
->std
.io_Actual
= 0;
394 pa
->pa_IO
->std
.io_Offset
= 0;
395 pa
->pa_IO
->std
.io_Message
.mn_Length
= sizeof(pa
->pa_IO
->std
);
396 res
= DoIO((struct IORequest
*)pa
->pa_IO
);
398 dp
->dp_Res1
= pa
->pa_IO
->std
.io_Actual
;
401 dp
->dp_Res1
= DOSFALSE
;
402 dp
->dp_Res2
= ERROR_READ_PROTECTED
;
405 dp
->dp_Res1
= DOSFALSE
;
406 dp
->dp_Res2
= ERROR_OBJECT_WRONG_TYPE
;
410 if ((pa
= (struct portArgs
*)dp
->dp_Arg1
)) {
412 dp
->dp_Res1
= DOSTRUE
;
415 dp
->dp_Res1
= DOSFALSE
;
416 dp
->dp_Res2
= ERROR_OBJECT_WRONG_TYPE
;
420 if (IsListEmpty(&pb
.pb_Files
)) {
421 dp
->dp_Res1
= DOSTRUE
;
425 dp
->dp_Res1
= DOSFALSE
;
426 dp
->dp_Res2
= ERROR_OBJECT_IN_USE
;
430 dp
->dp_Res1
= DOSFALSE
;
431 dp
->dp_Res2
= ERROR_ACTION_NOT_KNOWN
;
436 /* ACTION_DIE ends up here... */
437 PutMsg (dp
->dp_Port
, dp
->dp_Link
);
439 CloseLibrary(pb
.pb_UtilityBase
);