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 D(bug("%s: %s device=%s, unit=%d (%d), mode=%d\n",
272 __func__
, name
, pb
->pb_DeviceName
,
273 pa
->pa_DeviceUnit
, pb
->pb_DeviceFlags
,
276 if ((pa
->pa_IOMsg
= CreateMsgPort())) {
277 if ((pa
->pa_IO
= (APTR
)CreateIORequest(pa
->pa_IOMsg
, sizeof(*pa
->pa_IO
)))) {
278 if (0 == OpenDevice(pb
->pb_DeviceName
, pa
->pa_DeviceUnit
, (struct IORequest
*)pa
->pa_IO
, pb
->pb_DeviceFlags
)) {
279 D(bug("%s: Device is open\n"));
281 if (pb
->pb_Mode
!= PORT_SERIAL
) {
282 AddTail(&pb
->pb_Files
, &pa
->pa_Node
);
286 pa
->pa_IO
->ser
.IOSer
.io_Command
= SDCMD_SETPARAMS
;
287 /* xON xOFF ENQ ACK */
288 pa
->pa_IO
->ser
.io_CtlChar
= SER_DEFAULT_CTLCHAR
;
289 pa
->pa_IO
->ser
.io_RBufLen
= 64;
290 pa
->pa_IO
->ser
.io_SerFlags
= pa
->pa_Serial
.ps_SerFlags
;
291 pa
->pa_IO
->ser
.io_ExtFlags
= pa
->pa_Serial
.ps_ExtFlags
;
292 pa
->pa_IO
->ser
.io_Baud
= pa
->pa_Serial
.ps_Baud
;
293 pa
->pa_IO
->ser
.io_BrkTime
= 250000;
294 pa
->pa_IO
->ser
.io_TermArray
.TermArray0
= 0;
295 pa
->pa_IO
->ser
.io_TermArray
.TermArray1
= 1;
296 pa
->pa_IO
->ser
.io_ReadLen
= pa
->pa_Serial
.ps_LenBits
;
297 pa
->pa_IO
->ser
.io_WriteLen
= pa
->pa_Serial
.ps_LenBits
;
298 pa
->pa_IO
->ser
.io_StopBits
= pa
->pa_Serial
.ps_StopBits
;
300 if (0 == DoIO((struct IORequest
*)pa
->pa_IO
)) {
301 AddTail(&pb
->pb_Files
, &pa
->pa_Node
);
304 CloseDevice((struct IORequest
*)pa
->pa_IO
);
306 DeleteIORequest((struct IORequest
*)pa
->pa_IO
);
308 DeleteMsgPort(pa
->pa_IOMsg
);
313 D(bug("%s: Didn't open device\n", __func__
));
314 *err
= ERROR_NO_DISK
;
318 static void portClose(struct portArgs
*pa
)
320 D(bug("%s: Close %s\n", pa
->pa_Node
.ln_Name
));
321 Remove(&pa
->pa_Node
);
322 CloseDevice((struct IORequest
*)pa
->pa_IO
);
323 DeleteIORequest((struct IORequest
*)pa
->pa_IO
);
324 DeleteMsgPort(pa
->pa_IOMsg
);
328 void replyPkt(struct DosPacket
*dp
)
333 D(bug("%s: type=%d res1=%d, res2=0x%p\n", __func__
, dp
->dp_Type
, dp
->dp_Res1
, dp
->dp_Res2
));
336 mn
->mn_Node
.ln_Name
= (char*)dp
;
337 dp
->dp_Port
= &((struct Process
*)FindTask(NULL
))->pr_MsgPort
;
341 __startup
void port_handler(void)
343 struct DosPacket
*dp
;
347 struct FileHandle
*fh
;
348 struct portBase pb
= {};
351 NEWLIST(&pb
.pb_Files
);
353 mp
= &((struct Process
*)FindTask(NULL
))->pr_MsgPort
;
357 dp
= (struct DosPacket
*)(GetMsg(mp
)->mn_Node
.ln_Name
);
360 if ((pb
.pb_UtilityBase
= OpenLibrary("utility.library", 0))) {
361 res
= decodeStartup(&pb
, (BPTR
)dp
->dp_Arg2
);
365 ((struct DeviceNode
*)BADDR(dp
->dp_Arg3
))->dn_Task
= mp
;
368 dp
->dp_Res1
= (dp
->dp_Res2
== 0) ? DOSTRUE
: DOSFALSE
;
373 dp
= (struct DosPacket
*)(GetMsg(mp
)->mn_Node
.ln_Name
);
374 D(bug("%s: type=%d\n", __func__
, dp
->dp_Type
));
376 switch (dp
->dp_Type
) {
377 case ACTION_FINDINPUT
:
378 case ACTION_FINDOUTPUT
:
379 case ACTION_FINDUPDATE
:
380 pa
= portOpen(&pb
, pa
, (BSTR
)dp
->dp_Arg3
, &dp
->dp_Res2
);
381 if (dp
->dp_Res2
== RETURN_OK
) {
382 fh
= BADDR(dp
->dp_Arg1
);
383 fh
->fh_Arg1
= (SIPTR
)pa
;
386 dp
->dp_Res1
= (dp
->dp_Res2
== 0) ? DOSTRUE
: DOSFALSE
;
389 if ((pa
= (struct portArgs
*)dp
->dp_Arg1
)) {
390 pa
->pa_IO
->std
.io_Command
= CMD_READ
;
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
)) {
411 if (pb
.pb_Mode
== PORT_PRINTER
&&
412 pa
->pa_Printer
.pr_Type
== PRT_RAW
)
413 pa
->pa_IO
->std
.io_Command
= PRD_RAWWRITE
;
415 pa
->pa_IO
->std
.io_Command
= CMD_WRITE
;
416 pa
->pa_IO
->std
.io_Data
= (APTR
)dp
->dp_Arg2
;
417 pa
->pa_IO
->std
.io_Length
= dp
->dp_Arg3
;
418 pa
->pa_IO
->std
.io_Actual
= 0;
419 pa
->pa_IO
->std
.io_Offset
= 0;
420 pa
->pa_IO
->std
.io_Message
.mn_Length
= sizeof(pa
->pa_IO
->std
);
421 res
= DoIO((struct IORequest
*)pa
->pa_IO
);
423 dp
->dp_Res1
= pa
->pa_IO
->std
.io_Actual
;
426 dp
->dp_Res1
= DOSFALSE
;
427 dp
->dp_Res2
= ERROR_READ_PROTECTED
;
430 dp
->dp_Res1
= DOSFALSE
;
431 dp
->dp_Res2
= ERROR_OBJECT_WRONG_TYPE
;
435 if ((pa
= (struct portArgs
*)dp
->dp_Arg1
)) {
437 dp
->dp_Res1
= DOSTRUE
;
440 dp
->dp_Res1
= DOSFALSE
;
441 dp
->dp_Res2
= ERROR_OBJECT_WRONG_TYPE
;
445 if (IsListEmpty(&pb
.pb_Files
)) {
446 dp
->dp_Res1
= DOSTRUE
;
450 dp
->dp_Res1
= DOSFALSE
;
451 dp
->dp_Res2
= ERROR_OBJECT_IN_USE
;
455 dp
->dp_Res1
= DOSFALSE
;
456 dp
->dp_Res2
= ERROR_ACTION_NOT_KNOWN
;
461 /* ACTION_DIE ends up here... */
462 D(bug("%s: Exiting\n"));
466 CloseLibrary(pb
.pb_UtilityBase
);