18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci#include "wakeup.h"
38c2ecf20Sopenharmony_ci#include "boot.h"
48c2ecf20Sopenharmony_ci
58c2ecf20Sopenharmony_cistatic void udelay(int loops)
68c2ecf20Sopenharmony_ci{
78c2ecf20Sopenharmony_ci	while (loops--)
88c2ecf20Sopenharmony_ci		io_delay();	/* Approximately 1 us */
98c2ecf20Sopenharmony_ci}
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_cistatic void beep(unsigned int hz)
128c2ecf20Sopenharmony_ci{
138c2ecf20Sopenharmony_ci	u8 enable;
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci	if (!hz) {
168c2ecf20Sopenharmony_ci		enable = 0x00;		/* Turn off speaker */
178c2ecf20Sopenharmony_ci	} else {
188c2ecf20Sopenharmony_ci		u16 div = 1193181/hz;
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci		outb(0xb6, 0x43);	/* Ctr 2, squarewave, load, binary */
218c2ecf20Sopenharmony_ci		io_delay();
228c2ecf20Sopenharmony_ci		outb(div, 0x42);	/* LSB of counter */
238c2ecf20Sopenharmony_ci		io_delay();
248c2ecf20Sopenharmony_ci		outb(div >> 8, 0x42);	/* MSB of counter */
258c2ecf20Sopenharmony_ci		io_delay();
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci		enable = 0x03;		/* Turn on speaker */
288c2ecf20Sopenharmony_ci	}
298c2ecf20Sopenharmony_ci	inb(0x61);		/* Dummy read of System Control Port B */
308c2ecf20Sopenharmony_ci	io_delay();
318c2ecf20Sopenharmony_ci	outb(enable, 0x61);	/* Enable timer 2 output to speaker */
328c2ecf20Sopenharmony_ci	io_delay();
338c2ecf20Sopenharmony_ci}
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci#define DOT_HZ		880
368c2ecf20Sopenharmony_ci#define DASH_HZ		587
378c2ecf20Sopenharmony_ci#define US_PER_DOT	125000
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci/* Okay, this is totally silly, but it's kind of fun. */
408c2ecf20Sopenharmony_cistatic void send_morse(const char *pattern)
418c2ecf20Sopenharmony_ci{
428c2ecf20Sopenharmony_ci	char s;
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	while ((s = *pattern++)) {
458c2ecf20Sopenharmony_ci		switch (s) {
468c2ecf20Sopenharmony_ci		case '.':
478c2ecf20Sopenharmony_ci			beep(DOT_HZ);
488c2ecf20Sopenharmony_ci			udelay(US_PER_DOT);
498c2ecf20Sopenharmony_ci			beep(0);
508c2ecf20Sopenharmony_ci			udelay(US_PER_DOT);
518c2ecf20Sopenharmony_ci			break;
528c2ecf20Sopenharmony_ci		case '-':
538c2ecf20Sopenharmony_ci			beep(DASH_HZ);
548c2ecf20Sopenharmony_ci			udelay(US_PER_DOT * 3);
558c2ecf20Sopenharmony_ci			beep(0);
568c2ecf20Sopenharmony_ci			udelay(US_PER_DOT);
578c2ecf20Sopenharmony_ci			break;
588c2ecf20Sopenharmony_ci		default:	/* Assume it's a space */
598c2ecf20Sopenharmony_ci			udelay(US_PER_DOT * 3);
608c2ecf20Sopenharmony_ci			break;
618c2ecf20Sopenharmony_ci		}
628c2ecf20Sopenharmony_ci	}
638c2ecf20Sopenharmony_ci}
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_civoid main(void)
668c2ecf20Sopenharmony_ci{
678c2ecf20Sopenharmony_ci	/* Kill machine if structures are wrong */
688c2ecf20Sopenharmony_ci	if (wakeup_header.real_magic != 0x12345678)
698c2ecf20Sopenharmony_ci		while (1)
708c2ecf20Sopenharmony_ci			;
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	if (wakeup_header.realmode_flags & 4)
738c2ecf20Sopenharmony_ci		send_morse("...-");
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	if (wakeup_header.realmode_flags & 1)
768c2ecf20Sopenharmony_ci		asm volatile("lcallw   $0xc000,$3");
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	if (wakeup_header.realmode_flags & 2) {
798c2ecf20Sopenharmony_ci		/* Need to call BIOS */
808c2ecf20Sopenharmony_ci		probe_cards(0);
818c2ecf20Sopenharmony_ci		set_mode(wakeup_header.video_mode);
828c2ecf20Sopenharmony_ci	}
838c2ecf20Sopenharmony_ci}
84