162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci#include "wakeup.h"
362306a36Sopenharmony_ci#include "boot.h"
462306a36Sopenharmony_ci
562306a36Sopenharmony_cistatic void udelay(int loops)
662306a36Sopenharmony_ci{
762306a36Sopenharmony_ci	while (loops--)
862306a36Sopenharmony_ci		io_delay();	/* Approximately 1 us */
962306a36Sopenharmony_ci}
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_cistatic void beep(unsigned int hz)
1262306a36Sopenharmony_ci{
1362306a36Sopenharmony_ci	u8 enable;
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci	if (!hz) {
1662306a36Sopenharmony_ci		enable = 0x00;		/* Turn off speaker */
1762306a36Sopenharmony_ci	} else {
1862306a36Sopenharmony_ci		u16 div = 1193181/hz;
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci		outb(0xb6, 0x43);	/* Ctr 2, squarewave, load, binary */
2162306a36Sopenharmony_ci		io_delay();
2262306a36Sopenharmony_ci		outb(div, 0x42);	/* LSB of counter */
2362306a36Sopenharmony_ci		io_delay();
2462306a36Sopenharmony_ci		outb(div >> 8, 0x42);	/* MSB of counter */
2562306a36Sopenharmony_ci		io_delay();
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci		enable = 0x03;		/* Turn on speaker */
2862306a36Sopenharmony_ci	}
2962306a36Sopenharmony_ci	inb(0x61);		/* Dummy read of System Control Port B */
3062306a36Sopenharmony_ci	io_delay();
3162306a36Sopenharmony_ci	outb(enable, 0x61);	/* Enable timer 2 output to speaker */
3262306a36Sopenharmony_ci	io_delay();
3362306a36Sopenharmony_ci}
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci#define DOT_HZ		880
3662306a36Sopenharmony_ci#define DASH_HZ		587
3762306a36Sopenharmony_ci#define US_PER_DOT	125000
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci/* Okay, this is totally silly, but it's kind of fun. */
4062306a36Sopenharmony_cistatic void send_morse(const char *pattern)
4162306a36Sopenharmony_ci{
4262306a36Sopenharmony_ci	char s;
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	while ((s = *pattern++)) {
4562306a36Sopenharmony_ci		switch (s) {
4662306a36Sopenharmony_ci		case '.':
4762306a36Sopenharmony_ci			beep(DOT_HZ);
4862306a36Sopenharmony_ci			udelay(US_PER_DOT);
4962306a36Sopenharmony_ci			beep(0);
5062306a36Sopenharmony_ci			udelay(US_PER_DOT);
5162306a36Sopenharmony_ci			break;
5262306a36Sopenharmony_ci		case '-':
5362306a36Sopenharmony_ci			beep(DASH_HZ);
5462306a36Sopenharmony_ci			udelay(US_PER_DOT * 3);
5562306a36Sopenharmony_ci			beep(0);
5662306a36Sopenharmony_ci			udelay(US_PER_DOT);
5762306a36Sopenharmony_ci			break;
5862306a36Sopenharmony_ci		default:	/* Assume it's a space */
5962306a36Sopenharmony_ci			udelay(US_PER_DOT * 3);
6062306a36Sopenharmony_ci			break;
6162306a36Sopenharmony_ci		}
6262306a36Sopenharmony_ci	}
6362306a36Sopenharmony_ci}
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_cistruct port_io_ops pio_ops;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_civoid main(void)
6862306a36Sopenharmony_ci{
6962306a36Sopenharmony_ci	init_default_io_ops();
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	/* Kill machine if structures are wrong */
7262306a36Sopenharmony_ci	if (wakeup_header.real_magic != 0x12345678)
7362306a36Sopenharmony_ci		while (1)
7462306a36Sopenharmony_ci			;
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	if (wakeup_header.realmode_flags & 4)
7762306a36Sopenharmony_ci		send_morse("...-");
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	if (wakeup_header.realmode_flags & 1)
8062306a36Sopenharmony_ci		asm volatile("lcallw   $0xc000,$3");
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	if (wakeup_header.realmode_flags & 2) {
8362306a36Sopenharmony_ci		/* Need to call BIOS */
8462306a36Sopenharmony_ci		probe_cards(0);
8562306a36Sopenharmony_ci		set_mode(wakeup_header.video_mode);
8662306a36Sopenharmony_ci	}
8762306a36Sopenharmony_ci}
88