revert between 56095 -> 55830 in arch
[AROS.git] / rom / devs / console / consoletask.c
blob3ee2be7feb4769f4fc3f01997d446af5dd203286
1 /*
2 Copyright © 1995-2014, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Code executed by the console.device task.
6 Lang: english
7 */
9 #include <exec/lists.h>
10 #include <proto/exec.h>
11 #include <proto/intuition.h>
12 #include <proto/console.h>
13 #include <exec/io.h>
14 #include <exec/alerts.h>
15 #include <dos/dos.h>
16 #include <devices/input.h>
17 #include <devices/rawkeycodes.h>
19 #include "console_gcc.h"
20 #include "consoleif.h"
22 #define DEBUG 0
23 #include <aros/debug.h>
25 VOID con_inject(struct ConsoleBase *ConsoleDevice, struct ConUnit *cu,
26 const UBYTE *data, LONG size)
28 struct intConUnit *icu = ICU(cu);
29 ObtainSemaphore(&ConsoleDevice->consoleTaskLock);
30 if (data && size)
32 struct intPasteData *p =
33 AllocMem(sizeof(struct intPasteData), MEMF_ANY);
34 if (p)
36 if (size < 0)
37 size = strlen(data);
38 p->pasteBuffer = AllocMem(size, MEMF_ANY);
39 if (p->pasteBuffer)
41 CopyMem((APTR) data, p->pasteBuffer, size);
42 p->pasteBufferSize = size;
43 p->unit = icu;
44 AddTail((struct List *)&icu->pasteData, (struct Node *)p);
45 D(bug("con_inject(%x %x %x %d)\n", icu, p, p->pasteBuffer,
46 p->pasteBufferSize));
48 else
50 FreeMem(p, sizeof(struct intPasteData));
54 ReleaseSemaphore(&ConsoleDevice->consoleTaskLock);
55 /* Wake up possible waiting CMD_READs */
56 Signal(ConsoleDevice->consoleTask, SIGBREAKF_CTRL_D);
59 /* Protos */
60 static BOOL checkconunit(Object *unit, struct ConsoleBase *ConsoleDevice);
61 static void answer_read_request(struct IOStdReq *req,
62 struct ConsoleBase *ConsoleDevice);
64 static VOID answer_requests(APTR unit, struct ConsoleBase *ConsoleDevice)
66 struct IOStdReq *req, *nextreq;
67 /* See if there are any queued io read requests that wants to be replied */
68 ForeachNodeSafe(&ConsoleDevice->readRequests, req, nextreq)
70 if ((APTR) req->io_Unit == (APTR) unit)
72 /* Paranoia */
73 if (0 != ICU(req->io_Unit)->numStoredChars)
75 Remove((struct Node *)req);
76 answer_read_request(req, ConsoleDevice);
82 static ULONG pasteData(struct intConUnit *icu,
83 struct ConsoleBase *ConsoleDevice)
85 /* Check if we have data to paste to the input buffer */
86 struct intPasteData *pd =
87 (struct intPasteData *)GetHead(&icu->pasteData);
88 if (pd)
90 ULONG tocopy =
91 MIN(pd->pasteBufferSize - icu->pasteBufferPos,
92 CON_INPUTBUF_SIZE - icu->numStoredChars);
94 D(bug("Pasting %ld bytes\n", tocopy));
95 CopyMem(pd->pasteBuffer + icu->pasteBufferPos,
96 icu->inputBuf + icu->numStoredChars, tocopy);
97 icu->numStoredChars += tocopy;
98 icu->pasteBufferPos += tocopy;
100 if (icu->pasteBufferPos >= pd->pasteBufferSize)
102 FreeMem(pd->pasteBuffer, pd->pasteBufferSize);
103 Remove((struct Node *)pd);
104 FreeMem(pd, sizeof(struct intPasteData));
105 icu->pasteBufferPos = 0;
108 answer_requests((APTR) icu, ConsoleDevice);
109 return tocopy;
111 return 0;
114 VOID consoleTaskEntry(struct ConsoleBase *ConsoleDevice)
116 BOOL success = FALSE;
117 LONG waitsigs = 0L, wakeupsig, commandsig, inputsig;
120 /* CD input handler puts data into this port */
121 struct MsgPort *inputport;
124 /* Used for input.device */
125 struct MsgPort *inputmp;
127 /* Add the CDInputHandler to input.device's list of input handlers */
128 inputmp = CreateMsgPort();
129 if (inputmp)
131 struct IOStdReq *inputio;
132 inputio =
133 (struct IOStdReq *)CreateIORequest(inputmp,
134 sizeof(struct IOStdReq));
135 if (inputio)
137 /* Open the input.device */
138 if (!OpenDevice("input.device", -1, (struct IORequest *)inputio,
139 0UL))
141 /* Initialize the inputhandler itself */
142 ConsoleDevice->inputHandler = initCDIH(ConsoleDevice);
143 if (ConsoleDevice->inputHandler)
145 inputio->io_Data = ConsoleDevice->inputHandler;
146 inputio->io_Command = IND_ADDHANDLER;
148 DoIO((struct IORequest *)inputio);
149 success = TRUE;
151 CloseDevice((struct IORequest *)inputio);
155 DeleteIORequest((struct IORequest *)inputio);
158 DeleteMsgPort(inputmp);
161 NEWLIST(&ConsoleDevice->readRequests);
163 /* if not successful, throw an alert */
164 if (!success)
166 Alert(AT_DeadEnd | AN_ConsoleDev | AG_OpenDev | AO_Unknown);
169 D(bug("Console task initialized\n"));
172 /* Get console.device input handler's port */
173 inputport =
174 ((struct cdihData *)ConsoleDevice->inputHandler->is_Data)->
175 inputPort;
177 inputsig = 1 << inputport->mp_SigBit;
178 commandsig = 1 << ConsoleDevice->commandPort->mp_SigBit;
180 waitsigs = inputsig | commandsig | SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D;
182 for (;;)
184 wakeupsig = Wait(waitsigs);
186 /* Anyone wanting to kill us ? */
187 if (wakeupsig & SIGBREAKF_CTRL_C)
189 break;
192 ObtainSemaphore(&ConsoleDevice->consoleTaskLock);
194 if (wakeupsig & SIGBREAKF_CTRL_D)
196 struct IOStdReq *req;
197 BOOL active = TRUE;
198 D(bug("SIGBREAKF_CTRL_D\n"));
199 /* console.device pasted data? */
200 while (active)
202 active = FALSE;
203 ForeachNode(&ConsoleDevice->readRequests, req)
205 if (pasteData(ICU(req->io_Unit), ConsoleDevice))
207 answer_requests(NULL, ConsoleDevice);
208 active = TRUE;
209 break;
215 if (wakeupsig & inputsig)
217 /* A message from the console device input handler */
218 struct cdihMessage *cdihmsg;
220 while ((cdihmsg = (struct cdihMessage *)GetMsg(inputport)))
222 /* Check that the ConUnit has not been disposed,
223 while the message was passed
225 if (checkconunit(cdihmsg->unit, ConsoleDevice))
227 switch (cdihmsg->ie.ie_Class)
229 case IECLASS_CLOSEWINDOW:
230 /* this is a hack. It would actually be up to the
231 * console.device user (CON: handler for example) to
232 * activate CLOSEWINDOW raw events (SET RAW EVENTS cmd)
233 * and then look out for this in the input stream
234 * (CMD_READ) */
235 /* fall through */
237 case IECLASS_RAWKEY:
239 #define MAPRAWKEY_BUFSIZE 80
241 UBYTE inputBuf[MAPRAWKEY_BUFSIZE + 1];
242 LONG actual;
243 ULONG tocopy;
244 struct InputEvent e;
246 /* Mouse wheel support */
247 if (cdihmsg->ie.ie_Code == RAWKEY_NM_WHEEL_UP ||
248 cdihmsg->ie.ie_Code == RAWKEY_NM_WHEEL_DOWN)
250 e.ie_EventAddress =
251 (cdihmsg->ie.ie_Code ==
252 RAWKEY_NM_WHEEL_UP) ? (APTR) 1 : (APTR)
254 e.ie_Class = IECLASS_GADGETDOWN;
255 Console_HandleGadgets(cdihmsg->unit, &e);
256 e.ie_Class = IECLASS_GADGETUP;
257 Console_HandleGadgets(cdihmsg->unit, &e);
259 else
261 /* Convert it to ANSI chars */
263 if (cdihmsg->ie.ie_Class ==
264 IECLASS_CLOSEWINDOW)
266 /* HACK */
267 inputBuf[0] = 28; /* CTRL-\ */
268 actual = 1;
269 /* HACK */
271 else
273 actual =
274 RawKeyConvert(&cdihmsg->ie,
275 inputBuf, MAPRAWKEY_BUFSIZE, NULL);
277 if (cdihmsg->ie.ie_Qualifier ==
278 IEQUALIFIER_RCOMMAND && actual == 1)
280 switch (inputBuf[0])
282 case 'c':
283 D(bug("Console_Copy\n"));
284 Console_Copy(cdihmsg->unit);
285 actual = 0;
286 break;
287 case 'v':
288 D(bug("Console_Paste\n"));
289 Console_Paste(cdihmsg->unit);
290 /* We have likely put something
291 * into the input buffer */
292 if (ICU(cdihmsg->unit)->
293 numStoredChars)
294 answer_requests(cdihmsg->
295 unit, ConsoleDevice);
296 actual = 0;
297 break;
302 D(bug("RawKeyConvert returned %ld\n",
303 actual));
306 if (actual > 0)
308 /* Copy received characters to the console
309 * unit input buffer. If the buffer is
310 * full, then console input will be lost
312 tocopy =
313 MIN(actual,
314 CON_INPUTBUF_SIZE -
315 ICU(cdihmsg->unit)->numStoredChars);
317 /* Copy the input over to the unit's
318 * buffer */
319 CopyMem(inputBuf,
320 ICU(cdihmsg->unit)->inputBuf +
321 ICU(cdihmsg->unit)->numStoredChars,
322 tocopy);
324 ICU(cdihmsg->unit)->numStoredChars +=
325 tocopy;
327 answer_requests(cdihmsg->unit,
328 ConsoleDevice);
329 } /* if (actual > 0) */
332 break;
334 case IECLASS_GADGETDOWN:
335 case IECLASS_GADGETUP:
336 case IECLASS_TIMER:
337 case IECLASS_RAWMOUSE:
338 Console_HandleGadgets(cdihmsg->unit,
339 &(cdihmsg->ie));
340 //.ie_Class, (APTR)cdihmsg->ie.ie_EventAddress);
341 break;
343 case IECLASS_REFRESHWINDOW:
344 case IECLASS_SIZEWINDOW:
346 /* Intentionally empty (Begin|End)Refresh() pair,
347 * as we are required to call them to keep
348 * Intuition informed, but we don't want to be
349 * restricted to rendering just in the damaged
350 * area (WFLG_NOCAREREFRESH is another possibility,
351 * but it's not our window). */
352 BeginRefresh(WINDOW(cdihmsg->unit));
353 EndRefresh(WINDOW(cdihmsg->unit), TRUE);
355 /* Refresh window contents */
356 Console_NewWindowSize(cdihmsg->unit);
358 break;
359 default:
360 D(bug("cdihmsg->ie.ie_Class = %d\n",
361 cdihmsg->ie.ie_Class));
362 } /* switch(cdihmsg->ie.ie_Class) */
363 } /* if (checkconunit(cdihmsg->unit, ConsoleDevice)) */
365 /* Tell the input handler we're done */
366 ReplyMsg((struct Message *)cdihmsg);
367 } /* while ((cdihmsg = (struct cdihMessage *)GetMsg(inputport))) */
368 } /* if (wakeupsig & inputsig) */
370 if (wakeupsig & commandsig)
372 /* We got a command from the outside. Investigate it */
373 struct IOStdReq *req;
375 while ((req =
376 (struct IOStdReq *)GetMsg(ConsoleDevice->commandPort)))
378 pasteData(ICU(req->io_Unit), ConsoleDevice);
380 switch (req->io_Command)
382 case CMD_READ:
383 if (0 != ICU(req->io_Unit)->numStoredChars)
385 answer_read_request(req, ConsoleDevice);
387 else
389 /* Not enough bytes in the buffer to fill the request,
390 * put it on hold. ioReq already removed from the
391 * queue with GetMsg() */
392 AddTail((struct List *)&ConsoleDevice->readRequests,
393 (struct Node *)req);
395 break;
397 default:
398 kprintf
399 ("!!! UNKNOWN COMMAND RECEIVED BY CONSOLE TASK !!!\n");
400 kprintf("!!! THIS SHOULD NEVER HAPPEN !!!\n");
401 break;
404 } /* while ((req = (struct IOStdReq *)GetMsg(ConsoleDevice->commandPort))) */
406 } /* if (wakeupsig & commandsig) */
408 ReleaseSemaphore(&ConsoleDevice->consoleTaskLock);
409 } /* forever */
411 /* FIXME: Do cleanup here */
414 /********** checkconunit() *******************************/
416 /* Checks that the supplied unit has not been disposed */
417 static BOOL checkconunit(Object *unit, struct ConsoleBase *ConsoleDevice)
419 Object *o, *ostate;
420 BOOL found = FALSE;
422 ObtainSemaphoreShared(&ConsoleDevice->unitListLock);
424 ostate = (Object *) ConsoleDevice->unitList.mlh_Head;
425 while ((o = NextObject(&ostate)) && (!found))
427 if (o == unit)
429 found = TRUE;
433 ReleaseSemaphore(&ConsoleDevice->unitListLock);
434 return found;
437 /******** answer_read_request() ***************************/
439 static void answer_read_request(struct IOStdReq *req,
440 struct ConsoleBase *ConsoleDevice)
442 Object *unit;
444 D(bug("answer_read_request\n"));
445 /* This function assumes that there are at least one character
446 available in the unitsinput buffer
449 unit = (Object *) req->io_Unit;
451 req->io_Actual = MIN(ICU(unit)->numStoredChars, req->io_Length);
453 /* Copy characters from the buffer into the request */
454 CopyMem((APTR) ICU(unit)->inputBuf, req->io_Data, req->io_Actual);
456 if (ICU(unit)->numStoredChars > req->io_Length)
458 ULONG i;
460 ICU(unit)->numStoredChars -= req->io_Actual;
462 /* We have to move the rest of the bytes to the start
463 of the buffer.
465 NOTE: we could alternatively use a circular buffer
468 for (i = 0; i < ICU(unit)->numStoredChars; i++)
470 ICU(unit)->inputBuf[i] =
471 ICU(unit)->inputBuf[i + req->io_Actual];
474 else
476 /* No more unread characters in the buffer */
477 ICU(unit)->numStoredChars = 0;
481 req->io_Error = 0;
482 /* All done. Just reply the request */
484 /* stegerg: caller of answer_read_request is responsible for the Remove,
485 because the Remove must be used only if the req was in
486 the readrequests list
487 Remove((struct Node *)req);
491 /* kprintf("receiving task=%s, sigbit=%d\n, mode=%d"
492 , ((struct Task *)req->io_Message.mn_ReplyPort->mp_SigTask)->tc_Node.ln_Name
493 , req->io_Message.mn_ReplyPort->mp_SigBit
494 , req->io_Message.mn_ReplyPort->mp_Flags
497 ReplyMsg((struct Message *)req);
499 return;