alsa.audio: move handling of XRUN when writting to the slave task
[AROS.git] / rom / filesys / console_handler / con_handler.c
blob5402d60ee8f95f6ce6ede77d65478af6e7044063
1 /*
2 Copyright © 1995-2014, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 #include <proto/exec.h>
7 #include <exec/libraries.h>
8 #include <exec/resident.h>
9 #include <exec/memory.h>
10 #include <exec/io.h>
11 #include <exec/errors.h>
12 #include <exec/alerts.h>
13 #include <utility/tagitem.h>
14 #include <dos/exall.h>
15 #include <dos/dosasl.h>
16 #include <intuition/intuition.h>
17 #include <proto/dos.h>
18 #include <proto/intuition.h>
19 #include <proto/workbench.h>
20 #include <workbench/startup.h>
21 #include <devices/conunit.h>
23 #include <stddef.h>
24 #include <string.h>
26 #include "con_handler_intern.h"
27 #include "support.h"
29 #undef SDEBUG
30 #undef DEBUG
31 #define SDEBUG 0
32 #define DEBUG 0
33 #include <aros/debug.h>
35 static char *BSTR2C(BSTR srcs)
37 UBYTE *src = BADDR(srcs);
38 char *dst;
40 dst = AllocVec(src[0] + 1, MEMF_ANY);
41 if (!dst)
42 return NULL;
43 memcpy(dst, src + 1, src[0]);
44 dst[src[0]] = 0;
45 return dst;
47 static WORD isdosdevicec(CONST_STRPTR s)
49 UBYTE b = 0;
50 while (s[b])
52 if (s[b] == ':')
53 return b;
54 b++;
56 return -1;
59 #define ioReq(x) ((struct IORequest *)x)
61 static const struct NewWindow default_nw =
63 0, /* LeftEdge */
64 0, /* TopEdge */
65 -1, /* Width */
66 -1, /* Height */
67 1, /* DetailPen */
68 0, /* BlockPen */
69 0, /* IDCMP */
70 WFLG_DEPTHGADGET |
71 WFLG_SIZEGADGET |
72 WFLG_DRAGBAR |
73 WFLG_SIZEBRIGHT |
74 WFLG_SMART_REFRESH |
75 WFLG_ACTIVATE,
76 0, /* FirstGadget */
77 0, /* CheckMark */
78 "CON:", /* Title */
79 0, /* Screen */
80 0, /* Bitmap */
81 100, /* MinWidth */
82 70, /* MinHeight */
83 32767, /* MaxWidth */
84 32767, /* MaxHeight */
85 WBENCHSCREEN /* type */
89 static LONG MakeConWindow(struct filehandle *fh)
91 LONG err = 0;
93 if (fh->otherwindow == NULL)
95 struct TagItem win_tags[] =
97 { WA_PubScreen, 0 },
98 { WA_AutoAdjust, TRUE },
99 { WA_PubScreenName, 0 },
100 { WA_PubScreenFallBack, TRUE },
101 { TAG_DONE }
104 win_tags[2].ti_Data = (IPTR) fh->screenname;
105 D(bug("[contask] Opening window on screen %s, IntuitionBase = 0x%p\n", fh->screenname, IntuitionBase));
107 /* Autoadjust doesn't enforce the window's width and height to be larger than
108 minwidth and minheight, so we set it here to avoid crashes in devs/console
109 if a user does e.g. dir >con:0/0/0/0
111 fh->nw.Width = fh->nw.Width > fh->nw.MinWidth ? fh->nw.Width : -1;
112 fh->nw.Height = (fh->flags & FHFLG_BOOTCON && fh->nw.Height == -1) ||
113 fh->nw.Height > fh->nw.MinHeight ? fh->nw.Height : fh->nw.MinHeight;
115 fh->window = OpenWindowTagList(&fh->nw, (struct TagItem *) win_tags);
117 else
119 D(bug("[contask] Using window %p\n", fh->otherwindow));
120 fh->window = fh->otherwindow;
123 if (fh->window)
125 D(bug("contask: window opened\n"));
126 fh->conreadio->io_Data = (APTR) fh->window;
127 fh->conreadio->io_Length = sizeof(struct Window);
129 if (0 == OpenDevice("console.device", CONU_SNIPMAP, ioReq(fh->conreadio), 0))
131 const UBYTE lf_on[] =
132 { 0x9B, 0x32, 0x30, 0x68 }; /* Set linefeed mode */
134 D(bug("contask: device opened\n"));
136 fh->flags |= FHFLG_CONSOLEDEVICEOPEN;
138 fh->conwriteio = *fh->conreadio;
139 fh->conwriteio.io_Message.mn_ReplyPort = fh->conwritemp;
141 /* Turn the console into LF+CR mode so that both
142 linefeed and carriage return is done on
144 fh->conwriteio.io_Command = CMD_WRITE;
145 fh->conwriteio.io_Data = (APTR) lf_on;
146 fh->conwriteio.io_Length = 4;
148 DoIO(ioReq(&fh->conwriteio));
150 if (fh->workbenchbase && (fh->appmsgport = CreateMsgPort()))
152 if ((fh->appwindow = AddAppWindow(0, 0, fh->window, fh->appmsgport, NULL)))
153 D(bug("[CON] Console promoted to be an AppWindow\n"));
156 } /* if (0 == OpenDevice("console.device", CONU_STANDARD, ioReq(fh->conreadio), 0)) */
157 else
159 err = ERROR_INVALID_RESIDENT_LIBRARY;
161 if (err)
162 CloseWindow(fh->window);
164 } /* if (fh->window) */
165 else
167 D(bug("[contask] Failed to open a window\n"));
168 err = ERROR_NO_FREE_STORE;
171 return err;
174 static BOOL MakeSureWinIsOpen(struct filehandle *fh)
176 if (fh->window)
177 return TRUE;
178 return MakeConWindow(fh) == 0;
181 static void close_con(struct filehandle *fh)
183 /* Clean up */
185 D(bug("[CON] Deleting timer request 0x%p\n", fh->timerreq));
186 if (fh->timerreq)
188 CloseDevice((struct IORequest *) fh->timerreq);
189 DeleteIORequest((struct IORequest *) fh->timerreq);
192 D(bug("[CON] Deleting timer port 0x%p\n", fh->timermp));
193 DeleteMsgPort(fh->timermp);
195 if (fh->flags & FHFLG_CONSOLEDEVICEOPEN)
197 D(bug("[CON] Closing console.device...\n"));
198 CloseDevice((struct IORequest *) fh->conreadio);
201 if (fh->appwindow)
203 D(bug("[CON] Unpromote console window from being an AppWindow\n"));
204 RemoveAppWindow(fh->appwindow);
206 if (fh->appmsgport)
208 struct AppMessage *appmsg;
209 while ((appmsg = (struct AppMessage *) GetMsg(fh->appmsgport)))
210 ReplyMsg ((struct Message *) appmsg);
211 D(bug("[CON] Delete MsgPort for AppWindow\n"));
212 DeleteMsgPort(fh->appmsgport);
215 D(bug("[CON] Closing window 0x%p\n", fh->window));
216 if (fh->window)
217 CloseWindow(fh->window);
219 D(bug("[CON] Delete console.device IORequest 0x%p\n", fh->conreadio));
220 DeleteIORequest(ioReq(fh->conreadio));
222 D(bug("[CON] Delete console.device MsgPort 0x%p\n", fh->conreadmp));
223 FreeVec(fh->conreadmp);
225 if (fh->screenname)
226 FreeVec(fh->screenname);
227 if (fh->wintitle)
228 FreeVec(fh->wintitle);
229 if (fh->pastebuffer)
230 FreeMem(fh->pastebuffer, PASTEBUFSIZE);
232 CloseLibrary((struct Library*) fh->intuibase);
233 CloseLibrary((struct Library*) fh->dosbase);
234 CloseLibrary((struct Library*) fh->workbenchbase);
236 /* These libraries are opened only if completion was used */
237 if (fh->gfxbase)
238 CloseLibrary((struct Library*) fh->gfxbase);
239 if (fh->gtbase)
240 CloseLibrary(fh->gtbase);
242 FreeVec(fh);
245 static struct filehandle *open_con(struct DosPacket *dp, LONG *perr)
247 char *filename, *fn;
248 struct filehandle *fh;
249 struct DeviceNode *dn;
250 LONG err, ok;
251 LONG i;
253 dn = BADDR(dp->dp_Arg3);
254 *perr = ERROR_NO_FREE_STORE;
255 fh = AllocVec(sizeof(struct filehandle), MEMF_PUBLIC | MEMF_CLEAR);
256 if (!fh)
257 return NULL;
259 fh->intuibase = (APTR) OpenLibrary("intuition.library", 0);
260 fh->dosbase = (APTR) OpenLibrary("dos.library", 0);
261 fh->utilbase = (APTR) OpenLibrary("utility.library", 0);
262 fh->workbenchbase = (APTR) OpenLibrary("workbench.library", 0);
263 Forbid();
264 fh->inputbase = (struct Device *) FindName(&SysBase->DeviceList, "input.device");
265 Permit();
267 if (!fh->intuibase || !fh->dosbase || !fh->utilbase || !fh->inputbase)
269 CloseLibrary((APTR) fh->utilbase);
270 CloseLibrary((APTR) fh->dosbase);
271 CloseLibrary((APTR) fh->intuibase);
272 CloseLibrary((APTR) fh->workbenchbase);
273 FreeVec(fh);
274 return NULL;
277 fh->timermp = CreateMsgPort();
278 fh->timerreq = (struct timerequest*) CreateIORequest(fh->timermp, sizeof(struct timerequest));
279 OpenDevice(TIMERNAME, UNIT_MICROHZ, (struct IORequest *) fh->timerreq, 0);
281 err = 0;
282 filename = BSTR2C((BSTR) dp->dp_Arg1);
283 fn = filename;
284 i = isdosdevicec(fn);
285 if (i >= 0)
286 fn += i + 1;
288 fh->contask = FindTask(0);
290 NEWLIST(&fh->pendingReads);
292 /* Create msgport for console.device communication */
293 fh->conreadmp = AllocVec(sizeof(struct MsgPort) * 2, MEMF_PUBLIC | MEMF_CLEAR);
294 if (fh->conreadmp)
297 fh->conreadmp->mp_Node.ln_Type = NT_MSGPORT;
298 fh->conreadmp->mp_Flags = PA_SIGNAL;
299 fh->conreadmp->mp_SigBit = AllocSignal(-1);
300 fh->conreadmp->mp_SigTask = fh->contask;
301 NEWLIST(&fh->conreadmp->mp_MsgList);
303 fh->conwritemp = fh->conreadmp + 1;
305 fh->conwritemp->mp_Node.ln_Type = NT_MSGPORT;
306 fh->conwritemp->mp_Flags = PA_SIGNAL;
307 fh->conwritemp->mp_SigBit = AllocSignal(-1);
308 fh->conwritemp->mp_SigTask = fh->contask;
309 NEWLIST(&fh->conwritemp->mp_MsgList);
311 fh->conreadio = (struct IOStdReq *) CreateIORequest(fh->conreadmp, sizeof(struct IOStdReq));
312 if (fh->conreadio)
314 D(bug("contask: conreadio created, parms '%s'\n", fn));
316 fh->nw = default_nw;
318 if (parse_filename(fh, fn, &fh->nw))
320 if (!(fh->flags & FHFLG_AUTO))
322 err = MakeConWindow(fh);
323 if (!err)
324 ok = TRUE;
326 else
328 ok = TRUE;
331 else
332 err = ERROR_BAD_STREAM_NAME;
334 if (!ok)
336 DeleteIORequest(ioReq(fh->conreadio));
339 } /* if (fh->conreadio) */
340 else
342 err = ERROR_NO_FREE_STORE;
345 } /* if (fh->conreadmp) */
346 else
348 err = ERROR_NO_FREE_STORE;
351 if (dn->dn_Startup)
352 fh->flags |= FHFLG_RAW;
354 if (!ok)
355 close_con(fh);
357 *perr = err;
358 FreeVec(filename);
359 return fh;
362 static void startread(struct filehandle *fh)
364 if (fh->flags & FHFLG_ASYNCCONSOLEREAD)
365 return;
366 fh->conreadio->io_Command = CMD_READ;
367 fh->conreadio->io_Data = fh->consolebuffer;
368 fh->conreadio->io_Length = CONSOLEBUFFER_SIZE;
369 SendIO((struct IORequest*) fh->conreadio);
370 fh->flags |= FHFLG_ASYNCCONSOLEREAD;
373 static void stopwait(struct filehandle *fh, struct DosPacket *waitingdp, ULONG result)
375 if (waitingdp)
377 AbortIO((struct IORequest *) fh->timerreq);
378 WaitIO((struct IORequest *) fh->timerreq);
379 replypkt(waitingdp, result);
383 static void stopread(struct filehandle *fh, struct DosPacket *waitingdp)
385 struct Message *msg, *next_msg;
387 stopwait(fh, waitingdp, DOSFALSE);
389 ForeachNodeSafe(&fh->pendingReads, msg, next_msg)
391 struct DosPacket *dpr;
393 Remove((struct Node *) msg);
394 dpr = (struct DosPacket*) msg->mn_Node.ln_Name;
395 replypkt(dpr, DOSFALSE);
399 LONG CONMain(struct ExecBase *SysBase)
401 struct MsgPort *mp;
402 struct DosPacket *dp;
403 struct Message *mn;
404 struct FileHandle *dosfh;
405 LONG error;
406 struct filehandle *fh;
407 struct FileLock *fl;
408 struct DosPacket *waitingdp = NULL;
410 D(bug("[CON] started\n"));
411 mp = &((struct Process*) FindTask(NULL))->pr_MsgPort;
412 WaitPort(mp);
413 dp = (struct DosPacket*) GetMsg(mp)->mn_Node.ln_Name;
414 D(bug("[CON] startup message received. port=0x%p path='%b'\n", mp, dp->dp_Arg1));
416 fh = open_con(dp, &error);
417 if (!fh)
419 D(bug("[CON] init failed\n"));
420 goto end;
422 D(bug("[CON] 0x%p open\n", fh));
423 replypkt(dp, DOSTRUE);
425 for (;;)
427 ULONG conreadmask = 1L << fh->conreadmp->mp_SigBit;
428 ULONG timermask = 1L << fh->timermp->mp_SigBit;
429 ULONG packetmask = 1L << mp->mp_SigBit;
430 ULONG appwindowmask = fh->appmsgport ? 1L << fh->appmsgport->mp_SigBit : 0L;
431 ULONG i = 0, insertedlen = 0;
432 ULONG sigs;
433 UBYTE iconpath[INPUTBUFFER_SIZE];
434 WORD currentpos, currentrest;
436 sigs = Wait(packetmask | conreadmask | timermask | appwindowmask);
438 if (sigs & appwindowmask)
440 while ((fh->appmsg = (struct AppMessage *)GetMsg(fh->appmsgport)))
442 if (fh->appmsg->am_Type == AMTYPE_APPWINDOW)
444 if (fh->appmsg->am_NumArgs >= 1)
448 if (fh->appmsg->am_ArgList[i].wa_Lock)
450 NameFromLock(fh->appmsg->am_ArgList[i].wa_Lock,
451 iconpath, INPUTBUFFER_SIZE - 1);
452 AddPart(iconpath, fh->appmsg->am_ArgList[i].wa_Name,
453 INPUTBUFFER_SIZE - 1);
454 D(bug("[CON]: D&D iconpath: %s\n", iconpath));
456 if ((insertedlen = strlen(iconpath)))
459 * Get rid of trailing slashes of drawers?
460 if ((iconpath[insertedlen - 1] == '/'))
461 insertedlen--;
463 if ( strchr(iconpath, ' ')
464 && insertedlen <= (INPUTBUFFER_SIZE - 2))
466 memmove(iconpath + 1, iconpath, ++insertedlen);
467 iconpath[0] = iconpath[insertedlen++] = '"';
469 if (insertedlen <= (INPUTBUFFER_SIZE - 1))
470 iconpath[insertedlen++] = ' ';
472 currentpos = fh->inputpos;
473 currentrest = fh->inputsize - fh->inputpos;
474 memmove(&fh->inputbuffer[currentpos + insertedlen],
475 &fh->inputbuffer[currentpos],
476 currentrest);
477 CopyMem(iconpath, &fh->inputbuffer[currentpos],
478 insertedlen);
479 fh->inputsize += insertedlen;
480 fh->inputpos += insertedlen;
482 do_write(fh, &fh->inputbuffer[currentpos],
483 insertedlen + currentrest);
484 do_movecursor(fh, CUR_LEFT, currentrest);
487 } while (++i < fh->appmsg->am_NumArgs);
490 ReplyMsg((struct Message *)fh->appmsg);
492 ActivateWindow(fh->window);
495 if (sigs & timermask)
497 if (waitingdp)
499 replypkt(waitingdp, DOSFALSE);
500 waitingdp = NULL;
504 if (sigs & conreadmask)
506 GetMsg(fh->conreadmp);
507 fh->flags &= ~FHFLG_ASYNCCONSOLEREAD;
508 if (waitingdp)
510 stopwait(fh, waitingdp, DOSTRUE);
511 waitingdp = NULL;
513 D(bug("IO_READ %d\n", fh->conreadio->io_Actual));
514 fh->conbuffersize = fh->conreadio->io_Actual;
515 fh->conbufferpos = 0;
516 /* terminate with 0 char */
517 fh->consolebuffer[fh->conbuffersize] = '\0';
518 if (fh->flags & FHFLG_RAW)
520 LONG inp;
521 /* raw mode */
522 for (inp = 0; (inp < fh->conbuffersize) && (fh->inputpos < INPUTBUFFER_SIZE);)
524 fh->inputbuffer[fh->inputpos++] = fh->consolebuffer[inp++];
526 fh->inputsize = fh->inputstart = fh->inputpos;
527 HandlePendingReads(fh);
528 } /* if (fh->flags & FHFLG_RAW) */
529 else
531 /* Cooked mode */
532 if (process_input(fh))
535 * process_input() returns TRUE when EOF was received after the WAIT console
536 * has been closed by the owner.
538 dp = NULL;
539 goto end;
541 } /* if (fh->flags & FHFLG_RAW) else ... */
543 if (fh->flags & FHFLG_CONSOLEDEVICEOPEN) /* device could have been closed */
544 startread(fh);
547 while ((mn = GetMsg(mp)))
549 dp = (struct DosPacket*) mn->mn_Node.ln_Name;
550 dp->dp_Res2 = 0;
552 bug("[CON 0x%p] packet 0x%p:%d 0x%p,0x%p,0x%p\n", fh, dp, dp->dp_Type, dp->dp_Arg1, dp->dp_Arg2,
553 dp->dp_Arg3));
554 error = 0;
555 switch (dp->dp_Type)
557 case ACTION_FH_FROM_LOCK:
558 fl = BADDR(dp->dp_Arg2);
559 if (fl->fl_Task != mp || fl->fl_Key != (IPTR) fh)
561 replypkt2(dp, DOSFALSE, ERROR_OBJECT_NOT_FOUND);
562 break;
564 fh->usecount--;
565 FreeMem(fl, sizeof(*fl));
566 /* Fallthrough */
567 case ACTION_FINDINPUT:
568 case ACTION_FINDOUTPUT:
569 case ACTION_FINDUPDATE:
570 dosfh = BADDR(dp->dp_Arg1);
571 dosfh->fh_Interactive = DOSTRUE;
572 dosfh->fh_Arg1 = (SIPTR) fh;
573 fh->usecount++;
574 fh->breaktask = dp->dp_Port->mp_SigTask;
575 D(bug("[CON] Find fh=%x. Usecount=%d\n", dosfh, fh->usecount));
576 replypkt(dp, DOSTRUE);
577 break;
578 case ACTION_COPY_DIR_FH:
579 fl = AllocMem(sizeof(*fl), MEMF_CLEAR | MEMF_PUBLIC);
580 if (fl == BNULL)
582 replypkt2(dp, (SIPTR) BNULL, ERROR_NO_FREE_STORE);
584 else
586 fh->usecount++;
587 fl->fl_Task = mp;
588 fl->fl_Access = ACCESS_READ;
589 fl->fl_Key = (IPTR) fh;
590 replypkt(dp, (SIPTR) MKBADDR(fl));
592 break;
593 case ACTION_FREE_LOCK:
594 fl = BADDR(dp->dp_Arg1);
595 fh = (struct filehandle *)fl->fl_Key;
597 FreeMem(fl, sizeof(*fl));
598 fh->usecount--;
600 replypkt(dp, DOSTRUE);
601 break;
602 case ACTION_END:
603 fh->usecount--;
604 D(bug("[CON] usecount=%d\n", fh->usecount));
605 if (fh->usecount <= 0)
607 if (fh->flags & FHFLG_WAIT)
609 D(bug("[CON] Delayed close, waiting...\n"));
612 * Bounce all pending read and waits (the same as we do when exiting).
613 * However the process is still around, waiting for EOF input.
614 * Our user has just closed his struct FileHandle and dropped us.
616 stopread(fh, waitingdp);
617 waitingdp = NULL;
618 fh->flags = (fh->flags & ~FHFLG_READPENDING) | FHFLG_WAITFORCLOSE;
620 else
621 goto end;
623 replypkt(dp, DOSTRUE);
624 break;
625 case ACTION_READ:
626 if (!MakeSureWinIsOpen(fh))
628 replypkt2(dp, DOSFALSE, ERROR_NO_FREE_STORE);
629 break;
631 fh->breaktask = dp->dp_Port->mp_SigTask;
632 startread(fh);
633 con_read(fh, dp);
634 break;
635 case ACTION_WRITE:
636 if (!MakeSureWinIsOpen(fh))
638 replypkt2(dp, DOSFALSE, ERROR_NO_FREE_STORE);
639 break;
641 fh->breaktask = dp->dp_Port->mp_SigTask;
642 startread(fh);
643 answer_write_request(fh, dp);
644 break;
645 case ACTION_SCREEN_MODE:
647 D(bug("ACTION_SCREEN_MODE %s\n", dp->dp_Arg1 ? "RAW" : "CON"));
648 if (dp->dp_Arg1 && !(fh->flags & FHFLG_RAW))
650 /* Switching from CON: mode to RAW: mode */
651 fh->flags |= FHFLG_RAW;
652 fh->inputstart = fh->inputsize;
653 fh->inputpos = fh->inputsize;
654 HandlePendingReads(fh);
656 else
658 /* otherwise just copy the flags */
659 if (dp->dp_Arg1)
660 fh->flags |= FHFLG_RAW;
661 else
662 fh->flags &= ~FHFLG_RAW;
664 replypkt(dp, DOSTRUE);
666 break;
667 case ACTION_CHANGE_SIGNAL:
669 struct Task *old = fh->breaktask;
670 if (dp->dp_Arg2)
671 fh->breaktask = (struct Task*) dp->dp_Arg2;
672 replypkt2(dp, DOSTRUE, (SIPTR) old);
674 break;
675 case ACTION_WAIT_CHAR:
677 if (!MakeSureWinIsOpen(fh))
679 replypkt2(dp, DOSFALSE, ERROR_NO_FREE_STORE);
680 break;
682 if (fh->inputsize > 0)
684 replypkt(dp, DOSTRUE);
686 else if (dp->dp_Arg1 == 0)
688 replypkt(dp, DOSFALSE);
690 else
692 LONG timeout = dp->dp_Arg1;
693 LONG sec = timeout / 1000000;
694 LONG usec = timeout % 1000000;
696 fh->timerreq->tr_node.io_Command = TR_ADDREQUEST;
697 fh->timerreq->tr_time.tv_secs = sec;
698 fh->timerreq->tr_time.tv_micro = usec;
699 SendIO((struct IORequest *) fh->timerreq);
700 waitingdp = dp;
702 startread(fh);
704 break;
705 case ACTION_IS_FILESYSTEM:
706 replypkt(dp, DOSFALSE);
707 break;
708 case ACTION_DISK_INFO:
710 /* strange console handler features */
711 struct InfoData *id = BADDR(dp->dp_Arg1);
712 memset(id, 0, sizeof(struct InfoData));
713 id->id_DiskType =
714 (fh->flags & FHFLG_RAW) ? AROS_MAKE_ID('R', 'A', 'W', 0) : AROS_MAKE_ID('C', 'O', 'N', 0);
715 id->id_VolumeNode = (BPTR) fh->window;
716 id->id_InUse = (IPTR) fh->conreadio;
717 replypkt(dp, DOSTRUE);
719 break;
720 case ACTION_SEEK:
721 /* Yes, DOSTRUE. Check Guru Book for details. */
722 replypkt2(dp, DOSTRUE, ERROR_ACTION_NOT_KNOWN);
723 break;
724 default:
725 bug("[CON] unknown action %d\n", dp->dp_Type);
726 replypkt2(dp, DOSFALSE, ERROR_ACTION_NOT_KNOWN);
727 break;
731 end:
732 D(bug("[CON] 0x%p closing\n", fh));
733 if (fh)
735 D(bug("[CON] Cancelling read requests...\n"));
736 stopread(fh, waitingdp);
738 if (fh->flags & FHFLG_ASYNCCONSOLEREAD)
740 D(bug("[CON] Aborting console ioReq 0x%p\n", fh->conreadio));
742 AbortIO(ioReq(fh->conreadio));
743 WaitIO(ioReq(fh->conreadio));
746 D(bug("[CON] Closing handle...\n"));
747 close_con(fh);
750 if (dp)
752 D(bug("[CON] Replying packet 0x%p\n", dp));
753 replypkt(dp, DOSFALSE);
756 D(bug("[CON] 0x%p closed\n", fh));
757 return 0;