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