1// SPDX-License-Identifier: GPL-2.0
2#include "wakeup.h"
3#include "boot.h"
4
5static void udelay(int loops)
6{
7	while (loops--)
8		io_delay();	/* Approximately 1 us */
9}
10
11static void beep(unsigned int hz)
12{
13	u8 enable;
14
15	if (!hz) {
16		enable = 0x00;		/* Turn off speaker */
17	} else {
18		u16 div = 1193181/hz;
19
20		outb(0xb6, 0x43);	/* Ctr 2, squarewave, load, binary */
21		io_delay();
22		outb(div, 0x42);	/* LSB of counter */
23		io_delay();
24		outb(div >> 8, 0x42);	/* MSB of counter */
25		io_delay();
26
27		enable = 0x03;		/* Turn on speaker */
28	}
29	inb(0x61);		/* Dummy read of System Control Port B */
30	io_delay();
31	outb(enable, 0x61);	/* Enable timer 2 output to speaker */
32	io_delay();
33}
34
35#define DOT_HZ		880
36#define DASH_HZ		587
37#define US_PER_DOT	125000
38
39/* Okay, this is totally silly, but it's kind of fun. */
40static void send_morse(const char *pattern)
41{
42	char s;
43
44	while ((s = *pattern++)) {
45		switch (s) {
46		case '.':
47			beep(DOT_HZ);
48			udelay(US_PER_DOT);
49			beep(0);
50			udelay(US_PER_DOT);
51			break;
52		case '-':
53			beep(DASH_HZ);
54			udelay(US_PER_DOT * 3);
55			beep(0);
56			udelay(US_PER_DOT);
57			break;
58		default:	/* Assume it's a space */
59			udelay(US_PER_DOT * 3);
60			break;
61		}
62	}
63}
64
65struct port_io_ops pio_ops;
66
67void main(void)
68{
69	init_default_io_ops();
70
71	/* Kill machine if structures are wrong */
72	if (wakeup_header.real_magic != 0x12345678)
73		while (1)
74			;
75
76	if (wakeup_header.realmode_flags & 4)
77		send_morse("...-");
78
79	if (wakeup_header.realmode_flags & 1)
80		asm volatile("lcallw   $0xc000,$3");
81
82	if (wakeup_header.realmode_flags & 2) {
83		/* Need to call BIOS */
84		probe_cards(0);
85		set_mode(wakeup_header.video_mode);
86	}
87}
88