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