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 20int sbf_port __initdata = -1; /* set via acpi_boot_init() */ 21 22static 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 35static 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 53static 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 68static 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 78static 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} 101module_init(sbf_init); 102