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