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
25int sbf_port __initdata = -1;	/* set via acpi_boot_init() */
26
27
28static 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
41static 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
58static 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
70static 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
79static 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
98module_init(sbf_init);
99