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(hz: 0);
50 udelay(US_PER_DOT);
51 break;
52 case '-':
53 beep(DASH_HZ);
54 udelay(US_PER_DOT * 3);
55 beep(hz: 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(pattern: "...-");
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(unsafe: 0);
85 set_mode(wakeup_header.video_mode);
86 }
87}
88

source code of linux/arch/x86/realmode/rm/wakemain.c