Merge branch 'upstream-linus' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik...
[linux-2.6] / arch / i386 / kernel / bootflag.c
1 /*
2  *      Implement 'Simple Boot Flag Specification 2.0'
3  */
4
5
6 #include <linux/types.h>
7 #include <linux/kernel.h>
8 #include <linux/init.h>
9 #include <linux/string.h>
10 #include <linux/slab.h>
11 #include <linux/spinlock.h>
12 #include <linux/acpi.h>
13 #include <asm/io.h>
14
15 #include <linux/mc146818rtc.h>
16
17
18 #define SBF_RESERVED (0x78)
19 #define SBF_PNPOS    (1<<0)
20 #define SBF_BOOTING  (1<<1)
21 #define SBF_DIAG     (1<<2)
22 #define SBF_PARITY   (1<<7)
23
24
25 int sbf_port __initdata = -1;   /* set via acpi_boot_init() */
26
27
28 static int __init parity(u8 v)
29 {
30         int x = 0;
31         int i;
32         
33         for(i=0;i<8;i++)
34         {
35                 x^=(v&1);
36                 v>>=1;
37         }
38         return x;
39 }
40
41 static void __init sbf_write(u8 v)
42 {
43         unsigned long flags;
44         if(sbf_port != -1)
45         {
46                 v &= ~SBF_PARITY;
47                 if(!parity(v))
48                         v|=SBF_PARITY;
49
50                 printk(KERN_INFO "Simple Boot Flag at 0x%x set to 0x%x\n", sbf_port, v);
51
52                 spin_lock_irqsave(&rtc_lock, flags);
53                 CMOS_WRITE(v, sbf_port);
54                 spin_unlock_irqrestore(&rtc_lock, flags);
55         }
56 }
57
58 static u8 __init sbf_read(void)
59 {
60         u8 v;
61         unsigned long flags;
62         if(sbf_port == -1)
63                 return 0;
64         spin_lock_irqsave(&rtc_lock, flags);
65         v = CMOS_READ(sbf_port);
66         spin_unlock_irqrestore(&rtc_lock, flags);
67         return v;
68 }
69
70 static int __init sbf_value_valid(u8 v)
71 {
72         if(v&SBF_RESERVED)              /* Reserved bits */
73                 return 0;
74         if(!parity(v))
75                 return 0;
76         return 1;
77 }
78
79 static int __init sbf_init(void)
80 {
81         u8 v;
82         if(sbf_port == -1)
83                 return 0;
84         v = sbf_read();
85         if(!sbf_value_valid(v))
86                 printk(KERN_WARNING "Simple Boot Flag value 0x%x read from CMOS RAM was invalid\n",v);
87
88         v &= ~SBF_RESERVED;
89         v &= ~SBF_BOOTING;
90         v &= ~SBF_DIAG;
91 #if defined(CONFIG_ISAPNP)
92         v |= SBF_PNPOS;
93 #endif
94         sbf_write(v);
95         return 0;
96 }
97
98 module_init(sbf_init);