xref: /haiku/src/system/boot/platform/amiga_m68k/console.cpp (revision 837b16251d4b2b6249ebcaa19bb319cbe82c6126)
1 /*
2  * Copyright 2007, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT license.
4  *
5  * Author:
6  *		François Revol, revol@free.fr.
7  */
8 
9 #include <SupportDefs.h>
10 #include <string.h>
11 #include "rom_calls.h"
12 #include <util/kernel_cpp.h>
13 
14 #include "Handle.h"
15 #include "console.h"
16 #include "keyboard.h"
17 
18 class ConsoleHandle : public CharHandle {
19 	public:
20 		ConsoleHandle();
21 
22 		virtual ssize_t ReadAt(void *cookie, off_t pos, void *buffer,
23 			size_t bufferSize);
24 		virtual ssize_t WriteAt(void *cookie, off_t pos, const void *buffer,
25 			size_t bufferSize);
26 
27 		void	Clear();
28 		void	MoveTo(int16 x, int16 y);
29 		void	SetColor(int32 foreground, int32 background);
30 		int		Columns();
31 		int		Rows();
32 
33 	private:
34 		static int16	fX;
35 		static int16	fY;
36 		uint16	fPen;
37 };
38 
39 class ConsoleDevice : public ExecDevice {
40 	public:
41 		ConsoleDevice(const char *title);
42 		virtual ~ConsoleDevice();
43 
44 		status_t	Open();
45 
46 		virtual ssize_t ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize);
47 		virtual ssize_t WriteAt(void *cookie, off_t pos, const void *buffer, size_t bufferSize);
48 
49 		void	Clear();
50 		void	MoveTo(int16 x, int16 y);
51 		void	SetColor(int32 foreground, int32 background);
52 
53 		int		Columns();
54 		int		Rows();
55 
56 		int	WaitForKey();
57 
58 	protected:
59 		const char	*fTitle;
60 		struct Window	*fWindow;
61 		int	fRows, fCols;
62 };
63 
64 class KeyboardDevice : public ExecDevice {
65 	public:
66 		KeyboardDevice();
67 		virtual ~KeyboardDevice();
68 
69 		status_t	Open();
70 
71 		virtual ssize_t ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize);
72 		virtual ssize_t WriteAt(void *cookie, off_t pos, const void *buffer, size_t bufferSize);
73 
74 		int	WaitForKey();
75 		status_t	ReadEvent(struct InputEvent *event);
76 
77 	protected:
78 };
79 
80 class LLKeyboardDevice : public CharHandle {
81 	public:
82 		LLKeyboardDevice();
83 		virtual ~LLKeyboardDevice();
84 
85 		status_t	Open();
86 
87 		virtual ssize_t ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize);
88 		virtual ssize_t WriteAt(void *cookie, off_t pos, const void *buffer, size_t bufferSize);
89 
90 		int	WaitForKey();
91 
92 	protected:
93 };
94 
95 
96 static const uint16 kPalette[] = {
97 	0x000,
98 	0x00a,
99 	0x0a0,
100 	0x0aa,
101 	0xa00,
102 	0xa0a,
103 	0xa50,
104 	0xaaa,
105 	0x555,
106 	0x55f,
107 	0x5f5,
108 	0x5ff,
109 	0xf55,
110 	0xf5f,
111 	0xff5,
112 	0xfff
113 };
114 
115 struct Screen *gScreen;
116 static int16 sFontWidth, sFontHeight;
117 static int sScreenTopOffset = 16;
118 int16 ConsoleHandle::fX = 0;
119 int16 ConsoleHandle::fY = 0;
120 
121 FILE *stdin, *stdout, *stderr, *dbgerr;
122 
123 
124 //	#pragma mark -
125 
126 ConsoleHandle::ConsoleHandle()
127 	: CharHandle()
128 {
129 }
130 
131 
132 ssize_t
133 ConsoleHandle::ReadAt(void */*cookie*/, off_t /*pos*/, void *buffer,
134 	size_t bufferSize)
135 {
136 	// don't seek in character devices
137 	// not implemented (and not yet? needed)
138 	return B_ERROR;
139 }
140 
141 
142 ssize_t
143 ConsoleHandle::WriteAt(void */*cookie*/, off_t /*pos*/, const void *buffer,
144 	size_t bufferSize)
145 {
146 	const char *string = (const char *)buffer;
147 	size_t i, len;
148 
149 	// be nice to our audience and replace single "\n" with "\r\n"
150 
151 	for (i = 0, len = 0; i < bufferSize; i++, len++) {
152 		if (string[i] == '\0')
153 			break;
154 		if (string[i] == '\n') {
155 			//Text(&gScreen->RastPort, &string[i - len], len);
156 			fX = 0;
157 			fY++;
158 			if (fY >= console_height())
159 				fY = 0;
160 			len = 0;
161 			console_set_cursor(fX, fY);
162 			continue;
163 		}
164 		Text(&gScreen->RastPort, &string[i], 1);
165 	}
166 
167 	// not exactly, but we don't care...
168 	return bufferSize;
169 }
170 
171 
172 void
173 ConsoleHandle::Clear()
174 {
175 	Move(&gScreen->RastPort, 0, sScreenTopOffset);
176 	ClearScreen(&gScreen->RastPort);
177 }
178 
179 
180 void
181 ConsoleHandle::MoveTo(int16 x, int16 y)
182 {
183 	fX = x;
184 	fY = y;
185 	Move(&gScreen->RastPort, sFontWidth * x,
186 		sFontHeight * y + sScreenTopOffset);
187 	// why do I have to add this to keep the title ?
188 
189 }
190 
191 
192 void
193 ConsoleHandle::SetColor(int32 foreground, int32 background)
194 {
195 	SetAPen(&gScreen->RastPort, foreground);
196 	SetBPen(&gScreen->RastPort, background);
197 }
198 
199 
200 int
201 ConsoleHandle::Columns()
202 {
203 	int columnCount = gScreen->Width / sFontWidth;
204 	return columnCount;
205 }
206 
207 
208 int
209 ConsoleHandle::Rows()
210 {
211 	int lineCount = (gScreen->Height - sScreenTopOffset) / sFontHeight;
212 	return lineCount;
213 }
214 
215 
216 // #pragma mark -
217 
218 
219 ConsoleDevice::ConsoleDevice(const char *title)
220 	: ExecDevice(),
221 	fTitle(title),
222 	fWindow(NULL)
223 {
224 }
225 
226 
227 ConsoleDevice::~ConsoleDevice()
228 {
229 }
230 
231 
232 status_t
233 ConsoleDevice::Open()
234 {
235 	status_t err;
236 
237 	if (fWindow)
238 		return B_ERROR;
239 
240 	err = AllocRequest(sizeof(struct IOStdReq));
241 	if (err < B_OK)
242 		panic("AllocRequest");;
243 	if (err < B_OK)
244 		return err;
245 
246 	int16 topEdge = gScreen->Height - 60;
247 	int height = 60;
248 
249 	if (fTitle == NULL) {
250 		topEdge = 10;
251 		height = gScreen->Height - 40;
252 		fTitle = "Console";
253 	}
254 
255 	struct NewWindow newWindow = {
256 		0, topEdge,
257 		gScreen->Width, height,
258 		BLACK, WHITE,
259 		IDCMP_CLOSEWINDOW,
260 		WFLG_SIZEGADGET | WFLG_DRAGBAR | WFLG_DEPTHGADGET | WFLG_SIMPLE_REFRESH
261 			| WFLG_ACTIVATE,
262 		NULL,
263 		NULL,
264 		fTitle,
265 		gScreen,
266 		NULL,
267 		100, 45,
268 		gScreen->Width, gScreen->Height,
269 		CUSTOMSCREEN
270 	};
271 
272 	fWindow = OpenWindow(&newWindow);
273 	if (fWindow == NULL)
274 		panic("OpenWindow");;
275 	if (fWindow == NULL)
276 		return B_ERROR;
277 	fIOStdReq->io_Data = fWindow;
278 	fIOStdReq->io_Length = sizeof(struct Window);
279 	err = ExecDevice::Open(CONSOLENAME, CONU_STANDARD, 0);
280 	if (err < B_OK)
281 		return err;
282 
283 	MoveTo(0, 0);
284 	SetColor(WHITE, BLACK);
285 	Clear();
286 }
287 
288 
289 ssize_t
290 ConsoleDevice::ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize)
291 {
292 	return ExecDevice::ReadAt(cookie, pos, buffer, bufferSize);
293 }
294 
295 
296 int
297 ConsoleDevice::WaitForKey()
298 {
299 	char ascii;
300 
301 	if (Read(&ascii, 1) < 1)
302 		return TEXT_CONSOLE_NO_KEY;
303 	//dprintf("ascii %d %c\n", ascii, ascii);
304 
305 	if (ascii == (char)0x9b) {
306 		if (Read(&ascii, 1) < 1)
307 			return TEXT_CONSOLE_NO_KEY;
308 		//dprintf(">ascii %d %c\n", ascii, ascii);
309 		switch (ascii) {
310 			case 'A':
311 				return TEXT_CONSOLE_KEY_UP;
312 			case 'B':
313 				return TEXT_CONSOLE_KEY_DOWN;
314 			case 'D':
315 				return TEXT_CONSOLE_KEY_LEFT;
316 			case 'C':
317 				return TEXT_CONSOLE_KEY_RIGHT;
318 			case '4':
319 			{
320 				if (Read(&ascii, 1) < 1)
321 					return TEXT_CONSOLE_NO_KEY;
322 				if (ascii == '~')
323 					return TEXT_CONSOLE_NO_KEY;
324 				switch (ascii) {
325 					case '1':
326 						Read(&ascii, 1); // ~
327 						return TEXT_CONSOLE_KEY_PAGE_UP;
328 					case '2':
329 						Read(&ascii, 1); // ~
330 						return TEXT_CONSOLE_KEY_PAGE_UP;
331 					default:
332 						return TEXT_CONSOLE_NO_KEY;
333 				}
334 				return TEXT_CONSOLE_NO_KEY;
335 			}
336 			default:
337 				break;
338 		}
339 	}
340 	return ascii;
341 }
342 
343 
344 ssize_t
345 ConsoleDevice::WriteAt(void *cookie, off_t pos, const void *buffer, size_t bufferSize)
346 {
347 	return ExecDevice::WriteAt(cookie, pos, buffer, bufferSize);
348 }
349 
350 
351 void
352 ConsoleDevice::Clear()
353 {
354 	char buff[] = "\x0c";
355 	WriteAt(NULL, 0LL, buff, sizeof(buff) - 1);
356 }
357 
358 
359 void
360 ConsoleDevice::MoveTo(int16 x, int16 y)
361 {
362 	char buff[32];
363 	x = MIN(79,MAX(0,x));
364 	y = MIN(24,MAX(0,y));
365 	sprintf(buff, "\x9b%02d;%02d\x48", y + 1, x + 1);
366 	//buff[4] += (char)x;
367 	//buff[2] += (char)y;
368 	WriteAt(NULL, 0LL, buff, strlen(buff));
369 }
370 
371 
372 void
373 ConsoleDevice::SetColor(int32 foreground, int32 background)
374 {
375 	//char buff[] = "\x9b37;40m";
376 	char buff[] = "\2330;30;40m";
377 
378 
379 	if (foreground >= 8) {
380 		foreground -= 8;
381 		//buff[1] = '1'; // bold
382 	}
383 
384 	// else
385 	//	buff[1] = '2';
386 	//if (background >= 8)
387 	//	background -= 8;
388 
389 	if (foreground == background) {
390 		foreground = 7 - background;
391 	}
392 
393 	if (foreground < 8)
394 		buff[4] += foreground;
395 
396 	if (background < 8)
397 		buff[7] += background;
398 
399 	WriteAt(NULL, 0LL, buff, sizeof(buff) - 1);
400 }
401 
402 
403 int
404 ConsoleDevice::Columns()
405 {
406 	struct ConUnit *unit = (struct ConUnit *)fIOStdReq->io_Unit;
407 	return unit->cu_XMax;
408 }
409 
410 
411 int
412 ConsoleDevice::Rows()
413 {
414 	struct ConUnit *unit = (struct ConUnit *)fIOStdReq->io_Unit;
415 	return unit->cu_YMax - 1;
416 }
417 
418 
419 // #pragma mark -
420 
421 
422 KeyboardDevice::KeyboardDevice()
423 	: ExecDevice()
424 {
425 }
426 
427 
428 KeyboardDevice::~KeyboardDevice()
429 {
430 }
431 
432 
433 status_t
434 KeyboardDevice::Open()
435 {
436 	return ExecDevice::Open("keyboard.device");
437 }
438 
439 
440 status_t
441 KeyboardDevice::ReadEvent(struct InputEvent *event)
442 {
443 	fIOStdReq->io_Command = KBD_READEVENT;
444 	fIOStdReq->io_Flags = IOF_QUICK;
445 	fIOStdReq->io_Length = sizeof(struct InputEvent);
446 	fIOStdReq->io_Data = event;
447 	status_t err = Do();
448 	if (err < B_OK)
449 		return err;
450 	/*
451 	dprintf("key: class %d sclass %d code %d 0x%02x qual 0x%04x\n",
452 		event->ie_Class, event->ie_SubClass,
453 		event->ie_Code, event->ie_Code, event->ie_Qualifier);
454 	*/
455 	return B_OK;
456 }
457 
458 
459 ssize_t
460 KeyboardDevice::ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize)
461 {
462 	struct InputEvent event;
463 	ssize_t actual;
464 	status_t err;
465 
466 	do {
467 		err = ReadEvent(&event);
468 		if (err < B_OK)
469 			return err;
470 	} while (event.ie_Code > IECODE_UP_PREFIX);
471 
472 	actual = MapRawKey(&event, (char *)buffer, bufferSize, NULL);
473 	//dprintf("%s actual %d\n", __FUNCTION__, actual);
474 	if (actual > 0) {
475 		return actual;
476 	}
477 	return B_ERROR;
478 }
479 
480 
481 int
482 KeyboardDevice::WaitForKey()
483 {
484 	struct InputEvent event;
485 	char ascii;
486 	ssize_t actual;
487 	status_t err;
488 
489 	do {
490 		err = ReadEvent(&event);
491 		if (err < B_OK)
492 			return err;
493 	} while (event.ie_Code < IECODE_UP_PREFIX);
494 
495 	event.ie_Code &= ~IECODE_UP_PREFIX;
496 
497 	switch (event.ie_Code) {
498 		case IECODE_KEY_UP:
499 			return TEXT_CONSOLE_KEY_UP;
500 		case IECODE_KEY_DOWN:
501 			return TEXT_CONSOLE_KEY_DOWN;
502 		case IECODE_KEY_LEFT:
503 			return TEXT_CONSOLE_KEY_LEFT;
504 		case IECODE_KEY_RIGHT:
505 			return TEXT_CONSOLE_KEY_RIGHT;
506 		case IECODE_KEY_PAGE_UP:
507 			return TEXT_CONSOLE_KEY_PAGE_UP;
508 		case IECODE_KEY_PAGE_DOWN:
509 			return TEXT_CONSOLE_KEY_PAGE_DOWN;
510 		default:
511 			break;
512 	}
513 
514 	actual = MapRawKey(&event, &ascii, 1, NULL);
515 	//dprintf("%s actual %d\n", __FUNCTION__, actual);
516 	if (actual > 0)
517 		return ascii;
518 	return TEXT_CONSOLE_NO_KEY;
519 }
520 
521 
522 ssize_t
523 KeyboardDevice::WriteAt(void *cookie, off_t pos, const void *buffer, size_t bufferSize)
524 {
525 	return B_ERROR;
526 }
527 
528 
529 // #pragma mark -
530 
531 
532 LLKeyboardDevice::LLKeyboardDevice()
533 	: CharHandle()
534 {
535 }
536 
537 
538 LLKeyboardDevice::~LLKeyboardDevice()
539 {
540 }
541 
542 
543 status_t
544 LLKeyboardDevice::Open()
545 {
546 	if (LowLevelBase == NULL)
547 		LowLevelBase = (Library *)OldOpenLibrary(LOWLEVELNAME);
548 	return (LowLevelBase == NULL) ? B_ERROR : B_OK;
549 }
550 
551 
552 ssize_t
553 LLKeyboardDevice::ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize)
554 {
555 	struct InputEvent event;
556 	ssize_t actual;
557 	status_t err;
558 	uint32 key;
559 
560 
561 	key = GetKey();
562 	if (key & 0x0000ffff == 0x0ff)
563 		return B_ERROR;
564 	event.ie_Class = IECLASS_RAWKEY;
565 	event.ie_SubClass = IESUBCLASS_RAWKEY;
566 	event.ie_Code = (uint16)(key & 0x0000ffff);
567 	event.ie_Qualifier = (key & 0xffff0000) >> 16;
568 
569 	actual = MapRawKey(&event, (char *)buffer, bufferSize, NULL);
570 	//dprintf("%s actual %d\n", __FUNCTION__, actual);
571 	if (actual > 0) {
572 		return actual;
573 	}
574 	return B_ERROR;
575 }
576 
577 
578 int
579 LLKeyboardDevice::WaitForKey()
580 {
581 	struct InputEvent event;
582 	uint32 key;
583 	char ascii;
584 	ssize_t actual;
585 	status_t err;
586 
587 	do {
588 		key = GetKey();
589 	} while (key & 0x0000ffff == 0x0ff);
590 
591 	event.ie_Class = IECLASS_RAWKEY;
592 	event.ie_SubClass = IESUBCLASS_RAWKEY;
593 	event.ie_Code = (uint16)(key & 0x0000ffff);
594 	event.ie_Qualifier = (key & 0xffff0000) >> 16;
595 
596 	switch (event.ie_Code) {
597 		case IECODE_KEY_UP:
598 			return TEXT_CONSOLE_KEY_UP;
599 		case IECODE_KEY_DOWN:
600 			return TEXT_CONSOLE_KEY_DOWN;
601 		case IECODE_KEY_LEFT:
602 			return TEXT_CONSOLE_KEY_LEFT;
603 		case IECODE_KEY_RIGHT:
604 			return TEXT_CONSOLE_KEY_RIGHT;
605 		case IECODE_KEY_PAGE_UP:
606 			return TEXT_CONSOLE_KEY_PAGE_UP;
607 		case IECODE_KEY_PAGE_DOWN:
608 			return TEXT_CONSOLE_KEY_PAGE_DOWN;
609 		default:
610 			break;
611 	}
612 
613 	actual = MapRawKey(&event, &ascii, 1, NULL);
614 	//dprintf("%s actual %d\n", __FUNCTION__, actual);
615 	if (actual > 0)
616 		return ascii;
617 	return TEXT_CONSOLE_NO_KEY;
618 }
619 
620 
621 ssize_t
622 LLKeyboardDevice::WriteAt(void *cookie, off_t pos, const void *buffer, size_t bufferSize)
623 {
624 	return B_ERROR;
625 }
626 
627 
628 //	#pragma mark -
629 
630 
631 static ConsoleDevice sOutput(NULL);
632 //static ConsoleHandle sOutput;
633 //static ConsoleHandle sErrorOutput;
634 //static ConsoleHandle sDebugOutput;
635 static ConsoleDevice sDebugOutput("Debug");
636 
637 //static KeyboardDevice sInput;
638 static ConsoleDevice &sInput = sOutput;
639 
640 
641 status_t
642 console_init(void)
643 {
644 	status_t err;
645 
646 	GRAPHICS_BASE_NAME = (GfxBase *)OldOpenLibrary(GRAPHICSNAME);
647 	if (GRAPHICS_BASE_NAME == NULL)
648 		panic("Cannot open %s", GRAPHICSNAME);
649 
650 	static NewScreen newScreen = {
651 		0, 0,
652 		640, -1,
653 		4,
654 		BLACK, WHITE,
655 		0x8000,
656 		0x11,
657 		NULL,
658 		"Haiku Loader",
659 		NULL,
660 		NULL
661 	};
662 
663 	gScreen = OpenScreen(&newScreen);
664 	if (gScreen == NULL)
665 		panic("OpenScreen()\n");
666 
667 	LoadRGB4(&gScreen->ViewPort, kPalette, 16);
668 
669 	SetDrMd(&gScreen->RastPort, JAM2);
670 
671 	// seems not necessary, there is a default font already set.
672 	/*
673 	TextAttr attrs = { "Topaz", 8, 0, 0};
674 	TextFont *font = OpenFont(&attrs);
675 	*/
676 	TextFont *font = OpenFont(gScreen->Font);
677 	if (font == NULL)
678 		panic("OpenFont()\n");
679 	sFontHeight = gScreen->Font->ta_YSize;
680 	sFontWidth = font->tf_XSize;
681 
682 	sScreenTopOffset = gScreen->BarHeight * 2; // ???
683 
684 
685 	//ClearScreen(&gScreen->RastPort);
686 
687 
688 	err = sDebugOutput.Open();
689 	if (err < B_OK)
690 		panic("sDebugOutput.Open() 0x%08lx\n", err);
691 	dbgerr = stderr = (FILE *)&sDebugOutput;
692 
693 
694 	err = sOutput.Open();
695 	if (err < B_OK)
696 		panic("sOutput.Open() 0x%08lx\n", err);
697 
698 	stdout = (FILE *)&sOutput;
699 
700 	console_set_cursor(0, 0);
701 
702 	/*
703 	dprintf("LeftEdge %d\n", gScreen->LeftEdge);
704 	dprintf("TopEdge %d\n", gScreen->TopEdge);
705 	dprintf("Width %d\n", gScreen->Width);
706 	dprintf("Height %d\n", gScreen->Height);
707 	dprintf("MouseX %d\n", gScreen->MouseX);
708 	dprintf("MouseY %d\n", gScreen->MouseY);
709 	dprintf("Flags 0x%08x\n", gScreen->Flags);
710 	dprintf("BarHeight %d\n", gScreen->BarHeight);
711 	dprintf("BarVBorder %d\n", gScreen->BarVBorder);
712 	dprintf("BarHBorder %d\n", gScreen->BarHBorder);
713 	dprintf("MenuVBorder %d\n", gScreen->MenuVBorder);
714 	dprintf("MenuHBorder %d\n", gScreen->MenuHBorder);
715 	dprintf("WBorTop %d\n", gScreen->WBorTop);
716 	dprintf("WBorLeft %d\n", gScreen->WBorLeft);
717 	dprintf("WBorRight %d\n", gScreen->WBorRight);
718 	dprintf("WBorBottom %d\n", gScreen->WBorBottom);
719 	*/
720 
721 	KEYMAP_BASE_NAME = (Library *)OldOpenLibrary(KEYMAPNAME);
722 	if (KEYMAP_BASE_NAME == NULL)
723 		panic("Cannot open %s", KEYMAPNAME);
724 
725 
726 	/*
727 	err = sInput.Open();
728 	if (err < B_OK)
729 		panic("sInput.Open() 0x%08lx\n", err);
730 	*/
731 	stdin = (FILE *)&sInput;
732 
733 	return B_OK;
734 }
735 
736 
737 // #pragma mark -
738 
739 
740 void
741 console_clear_screen(void)
742 {
743 	sOutput.Clear();
744 }
745 
746 
747 int32
748 console_width(void)
749 {
750 	return sOutput.Columns();
751 }
752 
753 
754 int32
755 console_height(void)
756 {
757 	return sOutput.Rows();
758 }
759 
760 
761 void
762 console_set_cursor(int32 x, int32 y)
763 {
764 	sOutput.MoveTo(x, y);
765 }
766 
767 
768 void
769 console_set_color(int32 foreground, int32 background)
770 {
771 	sOutput.SetColor(foreground, background);
772 }
773 
774 
775 void
776 console_show_cursor(void)
777 {
778 }
779 
780 
781 void
782 console_hide_cursor(void)
783 {
784 }
785 
786 
787 int
788 console_wait_for_key(void)
789 {
790 	int key = sInput.WaitForKey();
791 	//dprintf("k: %08x '%c'\n", key, key);
792 	return key;
793 }
794 
795