dtpic.mui: added MUI4 attributes. (Only attribute
[AROS.git] / workbench / fs / port / port-handler.c
blob77568d993007ce861abdcbf70e11630e369f9667
1 /*
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
6 */
8 #include <string.h>
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)
24 struct portBase {
25 TEXT pb_DeviceName[DEVNAME_SIZE];
26 LONG pb_DeviceFlags;
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 */
32 struct portArgs {
33 struct Node pa_Node;
34 IPTR pa_DeviceUnit;
35 union {
36 struct {
37 ULONG ps_Baud;
38 UBYTE ps_LenBits;
39 UBYTE ps_StopBits;
40 UBYTE ps_SerFlags;
41 UBYTE ps_ExtFlags;
42 } pa_Serial;
43 struct {
44 enum { PRT_COOKED, PRT_RAW, PRT_TRANSPARENT } pr_Type;
45 } pa_Printer;
48 /* Only used in the per-open instances */
49 struct MsgPort *pa_IOMsg;
50 union {
51 struct IOStdReq std;
52 struct IOExtSer ser;
53 } *pa_IO;
54 } pb_Defaults;
56 struct List pb_Files;
59 /* Decode the following flags:
60 * Any type:
61 * UNIT=n
62 * PORT_PRINTER:
63 * TRANSPARENT
64 * RAW
65 * PORT_SERIAL:
66 * 9600 (and other baud rates)
67 * [78][NOEMS][12]
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++) {
76 if (cp[loc] == ':')
77 break;
79 if (loc < len)
80 loc++;
81 else
82 loc=0;
84 while (loc < len) {
85 int slen; /* length of section */
87 /* Advance to next section */
88 cp = &cp[loc];
89 len -= loc;
91 /* Find next section */
92 for (loc = 0; loc < len; loc++) {
93 if (cp[loc] == '/')
94 break;
96 slen = loc;
98 if (loc < len)
99 loc++;
101 /* Check for matches.. */
102 if (slen >= 5 && (0 == Strnicmp(cp, "UNIT=", 5))) {
103 CONST_STRPTR unit = cp + 5;
104 int ulen = slen - 5;
105 int i;
106 SIPTR uval = 0;
108 for (i = 0; i < ulen; i++) {
109 if (unit[i] < '0' || unit[i] > '9')
110 break;
111 uval *= 10;
112 uval += unit[i] - '0';
115 if (i == ulen)
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) {
127 int i;
128 ULONG baud = 0;
130 /* Check for all-numeric */
131 for (i = 0; i < slen; i++) {
132 if (cp[i] < '0' || cp[i] > '9')
133 break;
134 baud *= 10;
135 baud += cp[i] - '0';
137 if (i == slen) {
138 pa->pa_Serial.ps_Baud = baud;
139 } else if (slen == 3) {
140 TEXT bits, mode, stop;
141 bits = cp[0];
142 mode = ToUpper(cp[1]);
143 stop = cp[2];
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';
151 switch (mode) {
152 case 'N': pa->pa_Serial.ps_SerFlags = 0;
153 pa->pa_Serial.ps_ExtFlags = 0;
154 break;
155 case 'O': pa->pa_Serial.ps_SerFlags = SERF_PARTY_ON | SERF_PARTY_ODD;
156 pa->pa_Serial.ps_ExtFlags = 0;
157 break;
158 case 'E': pa->pa_Serial.ps_SerFlags = SERF_PARTY_ON;
159 pa->pa_Serial.ps_ExtFlags = 0;
160 break;
161 case 'M': pa->pa_Serial.ps_SerFlags = SERF_PARTY_ON;
162 pa->pa_Serial.ps_ExtFlags = SEXTF_MSPON | SEXTF_MARK;
163 break;
164 case 'S': pa->pa_Serial.ps_SerFlags = SERF_PARTY_ON;
165 pa->pa_Serial.ps_ExtFlags = SEXTF_MSPON;
166 break;
174 return RETURN_OK;
177 static void portSerialDefaults(struct portArgs *pa)
179 #ifdef __mc68000
180 /* 9600 */
181 pa->pa_Serial.ps_Baud = 9600;
182 #else
183 /* 115200 */
184 pa->pa_Serial.ps_Baud = 115200;
185 #endif
186 /* 8N1 */
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;
197 int len;
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) {
206 case 0:
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);
212 break;
213 case 1:
214 pb->pb_Mode = PORT_PARALLEL;
215 strcpy(pb->pb_DeviceName, "parallel.device");
216 pa->pa_DeviceUnit = 0;
217 pb->pb_DeviceFlags = 0;
218 break;
219 case 2:
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;
225 break;
226 default:
227 fssm = BADDR(startup);
228 if (fssm->fssm_Device == BNULL) {
229 ret = ERROR_NO_DISK;
230 break;
233 len = AROS_BSTR_strlen(fssm->fssm_Device);
234 if (len > sizeof(pb->pb_DeviceName)-1) {
235 ret = ERROR_NO_DISK;
236 break;
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;
249 } else {
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);
259 break;
262 return ret;
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,
285 pb->pb_Mode));
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__));
291 *err = 0;
292 if (pb->pb_Mode != PORT_SERIAL) {
293 AddTail(&pb->pb_Files, &pa->pa_Node);
294 return pa;
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);
313 return pa;
315 CloseDevice((struct IORequest *)pa->pa_IO);
317 DeleteIORequest((struct IORequest *)pa->pa_IO);
319 DeleteMsgPort(pa->pa_IOMsg);
321 FreeVec(pa);
324 D(bug("%s: Didn't open device\n", __func__));
325 *err = ERROR_NO_DISK;
326 return NULL;
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);
336 FreeVec(pa);
339 void replyPkt(struct DosPacket *dp, struct ExecBase *SysBase)
341 struct MsgPort *mp;
342 struct Message *mn;
344 D(bug("%s: type=%d res1=%d, res2=0x%p\n", __func__, dp->dp_Type, dp->dp_Res1, dp->dp_Res2));
345 mp = dp->dp_Port;
346 mn = dp->dp_Link;
347 mn->mn_Node.ln_Name = (char*)dp;
348 dp->dp_Port = &((struct Process*)FindTask(NULL))->pr_MsgPort;
349 PutMsg(mp, mn);
352 LONG port_handler(struct ExecBase *SysBase)
354 struct DosPacket *dp;
355 struct MsgPort *mp;
356 BOOL dead = FALSE;
357 SIPTR res;
358 struct FileHandle *fh;
359 struct portBase pb = {};
360 struct portArgs *pa;
362 pb.pb_SysBase = SysBase;
364 NEWLIST(&pb.pb_Files);
366 mp = &((struct Process *)FindTask(NULL))->pr_MsgPort;
368 WaitPort(mp);
370 dp = (struct DosPacket *)(GetMsg(mp)->mn_Node.ln_Name);
372 res = RETURN_FAIL;
373 if ((pb.pb_UtilityBase = OpenLibrary("utility.library", 0))) {
374 res = decodeStartup(&pb, (BPTR)dp->dp_Arg2);
377 if (res == 0)
378 ((struct DeviceNode *)BADDR(dp->dp_Arg3))->dn_Task = mp;
380 dp->dp_Res2 = res;
381 dp->dp_Res1 = (dp->dp_Res2 == 0) ? DOSTRUE : DOSFALSE;
383 do {
384 replyPkt(dp, SysBase);
385 WaitPort(mp);
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;
397 fh->fh_Type = mp;
399 dp->dp_Res1 = (dp->dp_Res2 == 0) ? DOSTRUE : DOSFALSE;
400 break;
401 case ACTION_READ:
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);
410 if (res == 0) {
411 dp->dp_Res1 = pa->pa_IO->std.io_Actual;
412 dp->dp_Res2 = 0;
413 } else {
414 dp->dp_Res1 = DOSFALSE;
415 dp->dp_Res2 = ERROR_READ_PROTECTED;
417 } else {
418 dp->dp_Res1 = DOSFALSE;
419 dp->dp_Res2 = ERROR_OBJECT_WRONG_TYPE;
421 break;
422 case ACTION_WRITE:
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;
427 else
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);
435 if (res == 0) {
436 dp->dp_Res1 = pa->pa_IO->std.io_Actual;
437 dp->dp_Res2 = 0;
438 } else {
439 dp->dp_Res1 = DOSFALSE;
440 dp->dp_Res2 = ERROR_READ_PROTECTED;
442 } else {
443 dp->dp_Res1 = DOSFALSE;
444 dp->dp_Res2 = ERROR_OBJECT_WRONG_TYPE;
446 break;
447 case ACTION_END:
448 if ((pa = (struct portArgs *)dp->dp_Arg1)) {
449 portClose(pa, SysBase);
450 dp->dp_Res1 = DOSTRUE;
451 dp->dp_Res2 = 0;
452 } else {
453 dp->dp_Res1 = DOSFALSE;
454 dp->dp_Res2 = ERROR_OBJECT_WRONG_TYPE;
456 break;
457 case ACTION_DIE:
458 if (IsListEmpty(&pb.pb_Files)) {
459 dp->dp_Res1 = DOSTRUE;
460 dp->dp_Res2 = 0;
461 dead = TRUE;
462 } else {
463 dp->dp_Res1 = DOSFALSE;
464 dp->dp_Res2 = ERROR_OBJECT_IN_USE;
466 break;
467 default:
468 dp->dp_Res1 = DOSFALSE;
469 dp->dp_Res2 = ERROR_ACTION_NOT_KNOWN;
470 break;
472 } while (!dead);
474 /* ACTION_DIE ends up here... */
475 D(bug("%s: Exiting\n"));
477 replyPkt(dp, SysBase);
479 CloseLibrary(pb.pb_UtilityBase);
481 return RETURN_OK;