GNU Linux-libre 4.14.266-gnu1
[releases.git] / arch / x86 / realmode / rm / wakemain.c
1 // SPDX-License-Identifier: GPL-2.0
2 #include "wakeup.h"
3 #include "boot.h"
4
5 static void udelay(int loops)
6 {
7         while (loops--)
8                 io_delay();     /* Approximately 1 us */
9 }
10
11 static 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. */
40 static 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
65 void main(void)
66 {
67         /* Kill machine if structures are wrong */
68         if (wakeup_header.real_magic != 0x12345678)
69                 while (1)
70                         ;
71
72         if (wakeup_header.realmode_flags & 4)
73                 send_morse("...-");
74
75         if (wakeup_header.realmode_flags & 1)
76                 asm volatile("lcallw   $0xc000,$3");
77
78         if (wakeup_header.realmode_flags & 2) {
79                 /* Need to call BIOS */
80                 probe_cards(0);
81                 set_mode(wakeup_header.video_mode);
82         }
83 }