1*1da177e4SLinus Torvalds /* 2*1da177e4SLinus Torvalds * CMOS/NV-RAM driver for Linux 3*1da177e4SLinus Torvalds * 4*1da177e4SLinus Torvalds * Copyright (C) 1997 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> 5*1da177e4SLinus Torvalds * idea by and with help from Richard Jelinek <rj@suse.de> 6*1da177e4SLinus Torvalds * Portions copyright (c) 2001,2002 Sun Microsystems (thockin@sun.com) 7*1da177e4SLinus Torvalds * 8*1da177e4SLinus Torvalds * This driver allows you to access the contents of the non-volatile memory in 9*1da177e4SLinus Torvalds * the mc146818rtc.h real-time clock. This chip is built into all PCs and into 10*1da177e4SLinus Torvalds * many Atari machines. In the former it's called "CMOS-RAM", in the latter 11*1da177e4SLinus Torvalds * "NVRAM" (NV stands for non-volatile). 12*1da177e4SLinus Torvalds * 13*1da177e4SLinus Torvalds * The data are supplied as a (seekable) character device, /dev/nvram. The 14*1da177e4SLinus Torvalds * size of this file is dependent on the controller. The usual size is 114, 15*1da177e4SLinus Torvalds * the number of freely available bytes in the memory (i.e., not used by the 16*1da177e4SLinus Torvalds * RTC itself). 17*1da177e4SLinus Torvalds * 18*1da177e4SLinus Torvalds * Checksums over the NVRAM contents are managed by this driver. In case of a 19*1da177e4SLinus Torvalds * bad checksum, reads and writes return -EIO. The checksum can be initialized 20*1da177e4SLinus Torvalds * to a sane state either by ioctl(NVRAM_INIT) (clear whole NVRAM) or 21*1da177e4SLinus Torvalds * ioctl(NVRAM_SETCKS) (doesn't change contents, just makes checksum valid 22*1da177e4SLinus Torvalds * again; use with care!) 23*1da177e4SLinus Torvalds * 24*1da177e4SLinus Torvalds * This file also provides some functions for other parts of the kernel that 25*1da177e4SLinus Torvalds * want to access the NVRAM: nvram_{read,write,check_checksum,set_checksum}. 26*1da177e4SLinus Torvalds * Obviously this can be used only if this driver is always configured into 27*1da177e4SLinus Torvalds * the kernel and is not a module. Since the functions are used by some Atari 28*1da177e4SLinus Torvalds * drivers, this is the case on the Atari. 29*1da177e4SLinus Torvalds * 30*1da177e4SLinus Torvalds * 31*1da177e4SLinus Torvalds * 1.1 Cesar Barros: SMP locking fixes 32*1da177e4SLinus Torvalds * added changelog 33*1da177e4SLinus Torvalds * 1.2 Erik Gilling: Cobalt Networks support 34*1da177e4SLinus Torvalds * Tim Hockin: general cleanup, Cobalt support 35*1da177e4SLinus Torvalds */ 36*1da177e4SLinus Torvalds 37*1da177e4SLinus Torvalds #define NVRAM_VERSION "1.2" 38*1da177e4SLinus Torvalds 39*1da177e4SLinus Torvalds #include <linux/module.h> 40*1da177e4SLinus Torvalds #include <linux/config.h> 41*1da177e4SLinus Torvalds #include <linux/sched.h> 42*1da177e4SLinus Torvalds #include <linux/smp_lock.h> 43*1da177e4SLinus Torvalds #include <linux/nvram.h> 44*1da177e4SLinus Torvalds 45*1da177e4SLinus Torvalds #define PC 1 46*1da177e4SLinus Torvalds #define ATARI 2 47*1da177e4SLinus Torvalds #define COBALT 3 48*1da177e4SLinus Torvalds 49*1da177e4SLinus Torvalds /* select machine configuration */ 50*1da177e4SLinus Torvalds #if defined(CONFIG_ATARI) 51*1da177e4SLinus Torvalds # define MACH ATARI 52*1da177e4SLinus Torvalds #elif defined(__i386__) || defined(__x86_64__) || defined(__arm__) /* and others?? */ 53*1da177e4SLinus Torvalds #define MACH PC 54*1da177e4SLinus Torvalds # if defined(CONFIG_COBALT) 55*1da177e4SLinus Torvalds # include <linux/cobalt-nvram.h> 56*1da177e4SLinus Torvalds # define MACH COBALT 57*1da177e4SLinus Torvalds # else 58*1da177e4SLinus Torvalds # define MACH PC 59*1da177e4SLinus Torvalds # endif 60*1da177e4SLinus Torvalds #else 61*1da177e4SLinus Torvalds # error Cannot build nvram driver for this machine configuration. 62*1da177e4SLinus Torvalds #endif 63*1da177e4SLinus Torvalds 64*1da177e4SLinus Torvalds #if MACH == PC 65*1da177e4SLinus Torvalds 66*1da177e4SLinus Torvalds /* RTC in a PC */ 67*1da177e4SLinus Torvalds #define CHECK_DRIVER_INIT() 1 68*1da177e4SLinus Torvalds 69*1da177e4SLinus Torvalds /* On PCs, the checksum is built only over bytes 2..31 */ 70*1da177e4SLinus Torvalds #define PC_CKS_RANGE_START 2 71*1da177e4SLinus Torvalds #define PC_CKS_RANGE_END 31 72*1da177e4SLinus Torvalds #define PC_CKS_LOC 32 73*1da177e4SLinus Torvalds #define NVRAM_BYTES (128-NVRAM_FIRST_BYTE) 74*1da177e4SLinus Torvalds 75*1da177e4SLinus Torvalds #define mach_check_checksum pc_check_checksum 76*1da177e4SLinus Torvalds #define mach_set_checksum pc_set_checksum 77*1da177e4SLinus Torvalds #define mach_proc_infos pc_proc_infos 78*1da177e4SLinus Torvalds 79*1da177e4SLinus Torvalds #endif 80*1da177e4SLinus Torvalds 81*1da177e4SLinus Torvalds #if MACH == COBALT 82*1da177e4SLinus Torvalds 83*1da177e4SLinus Torvalds #define CHECK_DRIVER_INIT() 1 84*1da177e4SLinus Torvalds 85*1da177e4SLinus Torvalds #define NVRAM_BYTES (128-NVRAM_FIRST_BYTE) 86*1da177e4SLinus Torvalds 87*1da177e4SLinus Torvalds #define mach_check_checksum cobalt_check_checksum 88*1da177e4SLinus Torvalds #define mach_set_checksum cobalt_set_checksum 89*1da177e4SLinus Torvalds #define mach_proc_infos cobalt_proc_infos 90*1da177e4SLinus Torvalds 91*1da177e4SLinus Torvalds #endif 92*1da177e4SLinus Torvalds 93*1da177e4SLinus Torvalds #if MACH == ATARI 94*1da177e4SLinus Torvalds 95*1da177e4SLinus Torvalds /* Special parameters for RTC in Atari machines */ 96*1da177e4SLinus Torvalds #include <asm/atarihw.h> 97*1da177e4SLinus Torvalds #include <asm/atariints.h> 98*1da177e4SLinus Torvalds #define RTC_PORT(x) (TT_RTC_BAS + 2*(x)) 99*1da177e4SLinus Torvalds #define CHECK_DRIVER_INIT() (MACH_IS_ATARI && ATARIHW_PRESENT(TT_CLK)) 100*1da177e4SLinus Torvalds 101*1da177e4SLinus Torvalds #define NVRAM_BYTES 50 102*1da177e4SLinus Torvalds 103*1da177e4SLinus Torvalds /* On Ataris, the checksum is over all bytes except the checksum bytes 104*1da177e4SLinus Torvalds * themselves; these are at the very end */ 105*1da177e4SLinus Torvalds #define ATARI_CKS_RANGE_START 0 106*1da177e4SLinus Torvalds #define ATARI_CKS_RANGE_END 47 107*1da177e4SLinus Torvalds #define ATARI_CKS_LOC 48 108*1da177e4SLinus Torvalds 109*1da177e4SLinus Torvalds #define mach_check_checksum atari_check_checksum 110*1da177e4SLinus Torvalds #define mach_set_checksum atari_set_checksum 111*1da177e4SLinus Torvalds #define mach_proc_infos atari_proc_infos 112*1da177e4SLinus Torvalds 113*1da177e4SLinus Torvalds #endif 114*1da177e4SLinus Torvalds 115*1da177e4SLinus Torvalds /* Note that *all* calls to CMOS_READ and CMOS_WRITE must be done with 116*1da177e4SLinus Torvalds * rtc_lock held. Due to the index-port/data-port design of the RTC, we 117*1da177e4SLinus Torvalds * don't want two different things trying to get to it at once. (e.g. the 118*1da177e4SLinus Torvalds * periodic 11 min sync from time.c vs. this driver.) 119*1da177e4SLinus Torvalds */ 120*1da177e4SLinus Torvalds 121*1da177e4SLinus Torvalds #include <linux/types.h> 122*1da177e4SLinus Torvalds #include <linux/errno.h> 123*1da177e4SLinus Torvalds #include <linux/miscdevice.h> 124*1da177e4SLinus Torvalds #include <linux/slab.h> 125*1da177e4SLinus Torvalds #include <linux/ioport.h> 126*1da177e4SLinus Torvalds #include <linux/fcntl.h> 127*1da177e4SLinus Torvalds #include <linux/mc146818rtc.h> 128*1da177e4SLinus Torvalds #include <linux/init.h> 129*1da177e4SLinus Torvalds #include <linux/proc_fs.h> 130*1da177e4SLinus Torvalds #include <linux/spinlock.h> 131*1da177e4SLinus Torvalds 132*1da177e4SLinus Torvalds #include <asm/io.h> 133*1da177e4SLinus Torvalds #include <asm/uaccess.h> 134*1da177e4SLinus Torvalds #include <asm/system.h> 135*1da177e4SLinus Torvalds 136*1da177e4SLinus Torvalds static DEFINE_SPINLOCK(nvram_state_lock); 137*1da177e4SLinus Torvalds static int nvram_open_cnt; /* #times opened */ 138*1da177e4SLinus Torvalds static int nvram_open_mode; /* special open modes */ 139*1da177e4SLinus Torvalds #define NVRAM_WRITE 1 /* opened for writing (exclusive) */ 140*1da177e4SLinus Torvalds #define NVRAM_EXCL 2 /* opened with O_EXCL */ 141*1da177e4SLinus Torvalds 142*1da177e4SLinus Torvalds static int mach_check_checksum(void); 143*1da177e4SLinus Torvalds static void mach_set_checksum(void); 144*1da177e4SLinus Torvalds 145*1da177e4SLinus Torvalds #ifdef CONFIG_PROC_FS 146*1da177e4SLinus Torvalds static int mach_proc_infos(unsigned char *contents, char *buffer, int *len, 147*1da177e4SLinus Torvalds off_t *begin, off_t offset, int size); 148*1da177e4SLinus Torvalds #endif 149*1da177e4SLinus Torvalds 150*1da177e4SLinus Torvalds /* 151*1da177e4SLinus Torvalds * These functions are provided to be called internally or by other parts of 152*1da177e4SLinus Torvalds * the kernel. It's up to the caller to ensure correct checksum before reading 153*1da177e4SLinus Torvalds * or after writing (needs to be done only once). 154*1da177e4SLinus Torvalds * 155*1da177e4SLinus Torvalds * It is worth noting that these functions all access bytes of general 156*1da177e4SLinus Torvalds * purpose memory in the NVRAM - that is to say, they all add the 157*1da177e4SLinus Torvalds * NVRAM_FIRST_BYTE offset. Pass them offsets into NVRAM as if you did not 158*1da177e4SLinus Torvalds * know about the RTC cruft. 159*1da177e4SLinus Torvalds */ 160*1da177e4SLinus Torvalds 161*1da177e4SLinus Torvalds unsigned char 162*1da177e4SLinus Torvalds __nvram_read_byte(int i) 163*1da177e4SLinus Torvalds { 164*1da177e4SLinus Torvalds return CMOS_READ(NVRAM_FIRST_BYTE + i); 165*1da177e4SLinus Torvalds } 166*1da177e4SLinus Torvalds 167*1da177e4SLinus Torvalds unsigned char 168*1da177e4SLinus Torvalds nvram_read_byte(int i) 169*1da177e4SLinus Torvalds { 170*1da177e4SLinus Torvalds unsigned long flags; 171*1da177e4SLinus Torvalds unsigned char c; 172*1da177e4SLinus Torvalds 173*1da177e4SLinus Torvalds spin_lock_irqsave(&rtc_lock, flags); 174*1da177e4SLinus Torvalds c = __nvram_read_byte(i); 175*1da177e4SLinus Torvalds spin_unlock_irqrestore(&rtc_lock, flags); 176*1da177e4SLinus Torvalds return c; 177*1da177e4SLinus Torvalds } 178*1da177e4SLinus Torvalds 179*1da177e4SLinus Torvalds /* This races nicely with trying to read with checksum checking (nvram_read) */ 180*1da177e4SLinus Torvalds void 181*1da177e4SLinus Torvalds __nvram_write_byte(unsigned char c, int i) 182*1da177e4SLinus Torvalds { 183*1da177e4SLinus Torvalds CMOS_WRITE(c, NVRAM_FIRST_BYTE + i); 184*1da177e4SLinus Torvalds } 185*1da177e4SLinus Torvalds 186*1da177e4SLinus Torvalds void 187*1da177e4SLinus Torvalds nvram_write_byte(unsigned char c, int i) 188*1da177e4SLinus Torvalds { 189*1da177e4SLinus Torvalds unsigned long flags; 190*1da177e4SLinus Torvalds 191*1da177e4SLinus Torvalds spin_lock_irqsave(&rtc_lock, flags); 192*1da177e4SLinus Torvalds __nvram_write_byte(c, i); 193*1da177e4SLinus Torvalds spin_unlock_irqrestore(&rtc_lock, flags); 194*1da177e4SLinus Torvalds } 195*1da177e4SLinus Torvalds 196*1da177e4SLinus Torvalds int 197*1da177e4SLinus Torvalds __nvram_check_checksum(void) 198*1da177e4SLinus Torvalds { 199*1da177e4SLinus Torvalds return mach_check_checksum(); 200*1da177e4SLinus Torvalds } 201*1da177e4SLinus Torvalds 202*1da177e4SLinus Torvalds int 203*1da177e4SLinus Torvalds nvram_check_checksum(void) 204*1da177e4SLinus Torvalds { 205*1da177e4SLinus Torvalds unsigned long flags; 206*1da177e4SLinus Torvalds int rv; 207*1da177e4SLinus Torvalds 208*1da177e4SLinus Torvalds spin_lock_irqsave(&rtc_lock, flags); 209*1da177e4SLinus Torvalds rv = __nvram_check_checksum(); 210*1da177e4SLinus Torvalds spin_unlock_irqrestore(&rtc_lock, flags); 211*1da177e4SLinus Torvalds return rv; 212*1da177e4SLinus Torvalds } 213*1da177e4SLinus Torvalds 214*1da177e4SLinus Torvalds void 215*1da177e4SLinus Torvalds __nvram_set_checksum(void) 216*1da177e4SLinus Torvalds { 217*1da177e4SLinus Torvalds mach_set_checksum(); 218*1da177e4SLinus Torvalds } 219*1da177e4SLinus Torvalds 220*1da177e4SLinus Torvalds void 221*1da177e4SLinus Torvalds nvram_set_checksum(void) 222*1da177e4SLinus Torvalds { 223*1da177e4SLinus Torvalds unsigned long flags; 224*1da177e4SLinus Torvalds 225*1da177e4SLinus Torvalds spin_lock_irqsave(&rtc_lock, flags); 226*1da177e4SLinus Torvalds __nvram_set_checksum(); 227*1da177e4SLinus Torvalds spin_unlock_irqrestore(&rtc_lock, flags); 228*1da177e4SLinus Torvalds } 229*1da177e4SLinus Torvalds 230*1da177e4SLinus Torvalds /* 231*1da177e4SLinus Torvalds * The are the file operation function for user access to /dev/nvram 232*1da177e4SLinus Torvalds */ 233*1da177e4SLinus Torvalds 234*1da177e4SLinus Torvalds static loff_t nvram_llseek(struct file *file,loff_t offset, int origin ) 235*1da177e4SLinus Torvalds { 236*1da177e4SLinus Torvalds lock_kernel(); 237*1da177e4SLinus Torvalds switch (origin) { 238*1da177e4SLinus Torvalds case 0: 239*1da177e4SLinus Torvalds /* nothing to do */ 240*1da177e4SLinus Torvalds break; 241*1da177e4SLinus Torvalds case 1: 242*1da177e4SLinus Torvalds offset += file->f_pos; 243*1da177e4SLinus Torvalds break; 244*1da177e4SLinus Torvalds case 2: 245*1da177e4SLinus Torvalds offset += NVRAM_BYTES; 246*1da177e4SLinus Torvalds break; 247*1da177e4SLinus Torvalds } 248*1da177e4SLinus Torvalds unlock_kernel(); 249*1da177e4SLinus Torvalds return (offset >= 0) ? (file->f_pos = offset) : -EINVAL; 250*1da177e4SLinus Torvalds } 251*1da177e4SLinus Torvalds 252*1da177e4SLinus Torvalds static ssize_t 253*1da177e4SLinus Torvalds nvram_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) 254*1da177e4SLinus Torvalds { 255*1da177e4SLinus Torvalds unsigned char contents[NVRAM_BYTES]; 256*1da177e4SLinus Torvalds unsigned i = *ppos; 257*1da177e4SLinus Torvalds unsigned char *tmp; 258*1da177e4SLinus Torvalds 259*1da177e4SLinus Torvalds spin_lock_irq(&rtc_lock); 260*1da177e4SLinus Torvalds 261*1da177e4SLinus Torvalds if (!__nvram_check_checksum()) 262*1da177e4SLinus Torvalds goto checksum_err; 263*1da177e4SLinus Torvalds 264*1da177e4SLinus Torvalds for (tmp = contents; count-- > 0 && i < NVRAM_BYTES; ++i, ++tmp) 265*1da177e4SLinus Torvalds *tmp = __nvram_read_byte(i); 266*1da177e4SLinus Torvalds 267*1da177e4SLinus Torvalds spin_unlock_irq(&rtc_lock); 268*1da177e4SLinus Torvalds 269*1da177e4SLinus Torvalds if (copy_to_user(buf, contents, tmp - contents)) 270*1da177e4SLinus Torvalds return -EFAULT; 271*1da177e4SLinus Torvalds 272*1da177e4SLinus Torvalds *ppos = i; 273*1da177e4SLinus Torvalds 274*1da177e4SLinus Torvalds return tmp - contents; 275*1da177e4SLinus Torvalds 276*1da177e4SLinus Torvalds checksum_err: 277*1da177e4SLinus Torvalds spin_unlock_irq(&rtc_lock); 278*1da177e4SLinus Torvalds return -EIO; 279*1da177e4SLinus Torvalds } 280*1da177e4SLinus Torvalds 281*1da177e4SLinus Torvalds static ssize_t 282*1da177e4SLinus Torvalds nvram_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) 283*1da177e4SLinus Torvalds { 284*1da177e4SLinus Torvalds unsigned char contents[NVRAM_BYTES]; 285*1da177e4SLinus Torvalds unsigned i = *ppos; 286*1da177e4SLinus Torvalds unsigned char *tmp; 287*1da177e4SLinus Torvalds int len; 288*1da177e4SLinus Torvalds 289*1da177e4SLinus Torvalds len = (NVRAM_BYTES - i) < count ? (NVRAM_BYTES - i) : count; 290*1da177e4SLinus Torvalds if (copy_from_user(contents, buf, len)) 291*1da177e4SLinus Torvalds return -EFAULT; 292*1da177e4SLinus Torvalds 293*1da177e4SLinus Torvalds spin_lock_irq(&rtc_lock); 294*1da177e4SLinus Torvalds 295*1da177e4SLinus Torvalds if (!__nvram_check_checksum()) 296*1da177e4SLinus Torvalds goto checksum_err; 297*1da177e4SLinus Torvalds 298*1da177e4SLinus Torvalds for (tmp = contents; count-- > 0 && i < NVRAM_BYTES; ++i, ++tmp) 299*1da177e4SLinus Torvalds __nvram_write_byte(*tmp, i); 300*1da177e4SLinus Torvalds 301*1da177e4SLinus Torvalds __nvram_set_checksum(); 302*1da177e4SLinus Torvalds 303*1da177e4SLinus Torvalds spin_unlock_irq(&rtc_lock); 304*1da177e4SLinus Torvalds 305*1da177e4SLinus Torvalds *ppos = i; 306*1da177e4SLinus Torvalds 307*1da177e4SLinus Torvalds return tmp - contents; 308*1da177e4SLinus Torvalds 309*1da177e4SLinus Torvalds checksum_err: 310*1da177e4SLinus Torvalds spin_unlock_irq(&rtc_lock); 311*1da177e4SLinus Torvalds return -EIO; 312*1da177e4SLinus Torvalds } 313*1da177e4SLinus Torvalds 314*1da177e4SLinus Torvalds static int 315*1da177e4SLinus Torvalds nvram_ioctl(struct inode *inode, struct file *file, 316*1da177e4SLinus Torvalds unsigned int cmd, unsigned long arg) 317*1da177e4SLinus Torvalds { 318*1da177e4SLinus Torvalds int i; 319*1da177e4SLinus Torvalds 320*1da177e4SLinus Torvalds switch (cmd) { 321*1da177e4SLinus Torvalds 322*1da177e4SLinus Torvalds case NVRAM_INIT: 323*1da177e4SLinus Torvalds /* initialize NVRAM contents and checksum */ 324*1da177e4SLinus Torvalds if (!capable(CAP_SYS_ADMIN)) 325*1da177e4SLinus Torvalds return -EACCES; 326*1da177e4SLinus Torvalds 327*1da177e4SLinus Torvalds spin_lock_irq(&rtc_lock); 328*1da177e4SLinus Torvalds 329*1da177e4SLinus Torvalds for (i = 0; i < NVRAM_BYTES; ++i) 330*1da177e4SLinus Torvalds __nvram_write_byte(0, i); 331*1da177e4SLinus Torvalds __nvram_set_checksum(); 332*1da177e4SLinus Torvalds 333*1da177e4SLinus Torvalds spin_unlock_irq(&rtc_lock); 334*1da177e4SLinus Torvalds return 0; 335*1da177e4SLinus Torvalds 336*1da177e4SLinus Torvalds case NVRAM_SETCKS: 337*1da177e4SLinus Torvalds /* just set checksum, contents unchanged (maybe useful after 338*1da177e4SLinus Torvalds * checksum garbaged somehow...) */ 339*1da177e4SLinus Torvalds if (!capable(CAP_SYS_ADMIN)) 340*1da177e4SLinus Torvalds return -EACCES; 341*1da177e4SLinus Torvalds 342*1da177e4SLinus Torvalds spin_lock_irq(&rtc_lock); 343*1da177e4SLinus Torvalds __nvram_set_checksum(); 344*1da177e4SLinus Torvalds spin_unlock_irq(&rtc_lock); 345*1da177e4SLinus Torvalds return 0; 346*1da177e4SLinus Torvalds 347*1da177e4SLinus Torvalds default: 348*1da177e4SLinus Torvalds return -ENOTTY; 349*1da177e4SLinus Torvalds } 350*1da177e4SLinus Torvalds } 351*1da177e4SLinus Torvalds 352*1da177e4SLinus Torvalds static int 353*1da177e4SLinus Torvalds nvram_open(struct inode *inode, struct file *file) 354*1da177e4SLinus Torvalds { 355*1da177e4SLinus Torvalds spin_lock(&nvram_state_lock); 356*1da177e4SLinus Torvalds 357*1da177e4SLinus Torvalds if ((nvram_open_cnt && (file->f_flags & O_EXCL)) || 358*1da177e4SLinus Torvalds (nvram_open_mode & NVRAM_EXCL) || 359*1da177e4SLinus Torvalds ((file->f_mode & 2) && (nvram_open_mode & NVRAM_WRITE))) { 360*1da177e4SLinus Torvalds spin_unlock(&nvram_state_lock); 361*1da177e4SLinus Torvalds return -EBUSY; 362*1da177e4SLinus Torvalds } 363*1da177e4SLinus Torvalds 364*1da177e4SLinus Torvalds if (file->f_flags & O_EXCL) 365*1da177e4SLinus Torvalds nvram_open_mode |= NVRAM_EXCL; 366*1da177e4SLinus Torvalds if (file->f_mode & 2) 367*1da177e4SLinus Torvalds nvram_open_mode |= NVRAM_WRITE; 368*1da177e4SLinus Torvalds nvram_open_cnt++; 369*1da177e4SLinus Torvalds 370*1da177e4SLinus Torvalds spin_unlock(&nvram_state_lock); 371*1da177e4SLinus Torvalds 372*1da177e4SLinus Torvalds return 0; 373*1da177e4SLinus Torvalds } 374*1da177e4SLinus Torvalds 375*1da177e4SLinus Torvalds static int 376*1da177e4SLinus Torvalds nvram_release(struct inode *inode, struct file *file) 377*1da177e4SLinus Torvalds { 378*1da177e4SLinus Torvalds spin_lock(&nvram_state_lock); 379*1da177e4SLinus Torvalds 380*1da177e4SLinus Torvalds nvram_open_cnt--; 381*1da177e4SLinus Torvalds 382*1da177e4SLinus Torvalds /* if only one instance is open, clear the EXCL bit */ 383*1da177e4SLinus Torvalds if (nvram_open_mode & NVRAM_EXCL) 384*1da177e4SLinus Torvalds nvram_open_mode &= ~NVRAM_EXCL; 385*1da177e4SLinus Torvalds if (file->f_mode & 2) 386*1da177e4SLinus Torvalds nvram_open_mode &= ~NVRAM_WRITE; 387*1da177e4SLinus Torvalds 388*1da177e4SLinus Torvalds spin_unlock(&nvram_state_lock); 389*1da177e4SLinus Torvalds 390*1da177e4SLinus Torvalds return 0; 391*1da177e4SLinus Torvalds } 392*1da177e4SLinus Torvalds 393*1da177e4SLinus Torvalds #ifndef CONFIG_PROC_FS 394*1da177e4SLinus Torvalds static int 395*1da177e4SLinus Torvalds nvram_read_proc(char *buffer, char **start, off_t offset, 396*1da177e4SLinus Torvalds int size, int *eof, void *data) 397*1da177e4SLinus Torvalds { 398*1da177e4SLinus Torvalds return 0; 399*1da177e4SLinus Torvalds } 400*1da177e4SLinus Torvalds #else 401*1da177e4SLinus Torvalds 402*1da177e4SLinus Torvalds static int 403*1da177e4SLinus Torvalds nvram_read_proc(char *buffer, char **start, off_t offset, 404*1da177e4SLinus Torvalds int size, int *eof, void *data) 405*1da177e4SLinus Torvalds { 406*1da177e4SLinus Torvalds unsigned char contents[NVRAM_BYTES]; 407*1da177e4SLinus Torvalds int i, len = 0; 408*1da177e4SLinus Torvalds off_t begin = 0; 409*1da177e4SLinus Torvalds 410*1da177e4SLinus Torvalds spin_lock_irq(&rtc_lock); 411*1da177e4SLinus Torvalds for (i = 0; i < NVRAM_BYTES; ++i) 412*1da177e4SLinus Torvalds contents[i] = __nvram_read_byte(i); 413*1da177e4SLinus Torvalds spin_unlock_irq(&rtc_lock); 414*1da177e4SLinus Torvalds 415*1da177e4SLinus Torvalds *eof = mach_proc_infos(contents, buffer, &len, &begin, offset, size); 416*1da177e4SLinus Torvalds 417*1da177e4SLinus Torvalds if (offset >= begin + len) 418*1da177e4SLinus Torvalds return 0; 419*1da177e4SLinus Torvalds *start = buffer + (offset - begin); 420*1da177e4SLinus Torvalds return (size < begin + len - offset) ? size : begin + len - offset; 421*1da177e4SLinus Torvalds 422*1da177e4SLinus Torvalds } 423*1da177e4SLinus Torvalds 424*1da177e4SLinus Torvalds /* This macro frees the machine specific function from bounds checking and 425*1da177e4SLinus Torvalds * this like that... */ 426*1da177e4SLinus Torvalds #define PRINT_PROC(fmt,args...) \ 427*1da177e4SLinus Torvalds do { \ 428*1da177e4SLinus Torvalds *len += sprintf(buffer+*len, fmt, ##args); \ 429*1da177e4SLinus Torvalds if (*begin + *len > offset + size) \ 430*1da177e4SLinus Torvalds return 0; \ 431*1da177e4SLinus Torvalds if (*begin + *len < offset) { \ 432*1da177e4SLinus Torvalds *begin += *len; \ 433*1da177e4SLinus Torvalds *len = 0; \ 434*1da177e4SLinus Torvalds } \ 435*1da177e4SLinus Torvalds } while(0) 436*1da177e4SLinus Torvalds 437*1da177e4SLinus Torvalds #endif /* CONFIG_PROC_FS */ 438*1da177e4SLinus Torvalds 439*1da177e4SLinus Torvalds static struct file_operations nvram_fops = { 440*1da177e4SLinus Torvalds .owner = THIS_MODULE, 441*1da177e4SLinus Torvalds .llseek = nvram_llseek, 442*1da177e4SLinus Torvalds .read = nvram_read, 443*1da177e4SLinus Torvalds .write = nvram_write, 444*1da177e4SLinus Torvalds .ioctl = nvram_ioctl, 445*1da177e4SLinus Torvalds .open = nvram_open, 446*1da177e4SLinus Torvalds .release = nvram_release, 447*1da177e4SLinus Torvalds }; 448*1da177e4SLinus Torvalds 449*1da177e4SLinus Torvalds static struct miscdevice nvram_dev = { 450*1da177e4SLinus Torvalds NVRAM_MINOR, 451*1da177e4SLinus Torvalds "nvram", 452*1da177e4SLinus Torvalds &nvram_fops 453*1da177e4SLinus Torvalds }; 454*1da177e4SLinus Torvalds 455*1da177e4SLinus Torvalds static int __init 456*1da177e4SLinus Torvalds nvram_init(void) 457*1da177e4SLinus Torvalds { 458*1da177e4SLinus Torvalds int ret; 459*1da177e4SLinus Torvalds 460*1da177e4SLinus Torvalds /* First test whether the driver should init at all */ 461*1da177e4SLinus Torvalds if (!CHECK_DRIVER_INIT()) 462*1da177e4SLinus Torvalds return -ENXIO; 463*1da177e4SLinus Torvalds 464*1da177e4SLinus Torvalds ret = misc_register(&nvram_dev); 465*1da177e4SLinus Torvalds if (ret) { 466*1da177e4SLinus Torvalds printk(KERN_ERR "nvram: can't misc_register on minor=%d\n", 467*1da177e4SLinus Torvalds NVRAM_MINOR); 468*1da177e4SLinus Torvalds goto out; 469*1da177e4SLinus Torvalds } 470*1da177e4SLinus Torvalds if (!create_proc_read_entry("driver/nvram", 0, NULL, nvram_read_proc, 471*1da177e4SLinus Torvalds NULL)) { 472*1da177e4SLinus Torvalds printk(KERN_ERR "nvram: can't create /proc/driver/nvram\n"); 473*1da177e4SLinus Torvalds ret = -ENOMEM; 474*1da177e4SLinus Torvalds goto outmisc; 475*1da177e4SLinus Torvalds } 476*1da177e4SLinus Torvalds ret = 0; 477*1da177e4SLinus Torvalds printk(KERN_INFO "Non-volatile memory driver v" NVRAM_VERSION "\n"); 478*1da177e4SLinus Torvalds out: 479*1da177e4SLinus Torvalds return ret; 480*1da177e4SLinus Torvalds outmisc: 481*1da177e4SLinus Torvalds misc_deregister(&nvram_dev); 482*1da177e4SLinus Torvalds goto out; 483*1da177e4SLinus Torvalds } 484*1da177e4SLinus Torvalds 485*1da177e4SLinus Torvalds static void __exit 486*1da177e4SLinus Torvalds nvram_cleanup_module(void) 487*1da177e4SLinus Torvalds { 488*1da177e4SLinus Torvalds remove_proc_entry("driver/nvram", NULL); 489*1da177e4SLinus Torvalds misc_deregister(&nvram_dev); 490*1da177e4SLinus Torvalds } 491*1da177e4SLinus Torvalds 492*1da177e4SLinus Torvalds module_init(nvram_init); 493*1da177e4SLinus Torvalds module_exit(nvram_cleanup_module); 494*1da177e4SLinus Torvalds 495*1da177e4SLinus Torvalds /* 496*1da177e4SLinus Torvalds * Machine specific functions 497*1da177e4SLinus Torvalds */ 498*1da177e4SLinus Torvalds 499*1da177e4SLinus Torvalds #if MACH == PC 500*1da177e4SLinus Torvalds 501*1da177e4SLinus Torvalds static int 502*1da177e4SLinus Torvalds pc_check_checksum(void) 503*1da177e4SLinus Torvalds { 504*1da177e4SLinus Torvalds int i; 505*1da177e4SLinus Torvalds unsigned short sum = 0; 506*1da177e4SLinus Torvalds unsigned short expect; 507*1da177e4SLinus Torvalds 508*1da177e4SLinus Torvalds for (i = PC_CKS_RANGE_START; i <= PC_CKS_RANGE_END; ++i) 509*1da177e4SLinus Torvalds sum += __nvram_read_byte(i); 510*1da177e4SLinus Torvalds expect = __nvram_read_byte(PC_CKS_LOC)<<8 | 511*1da177e4SLinus Torvalds __nvram_read_byte(PC_CKS_LOC+1); 512*1da177e4SLinus Torvalds return ((sum & 0xffff) == expect); 513*1da177e4SLinus Torvalds } 514*1da177e4SLinus Torvalds 515*1da177e4SLinus Torvalds static void 516*1da177e4SLinus Torvalds pc_set_checksum(void) 517*1da177e4SLinus Torvalds { 518*1da177e4SLinus Torvalds int i; 519*1da177e4SLinus Torvalds unsigned short sum = 0; 520*1da177e4SLinus Torvalds 521*1da177e4SLinus Torvalds for (i = PC_CKS_RANGE_START; i <= PC_CKS_RANGE_END; ++i) 522*1da177e4SLinus Torvalds sum += __nvram_read_byte(i); 523*1da177e4SLinus Torvalds __nvram_write_byte(sum >> 8, PC_CKS_LOC); 524*1da177e4SLinus Torvalds __nvram_write_byte(sum & 0xff, PC_CKS_LOC + 1); 525*1da177e4SLinus Torvalds } 526*1da177e4SLinus Torvalds 527*1da177e4SLinus Torvalds #ifdef CONFIG_PROC_FS 528*1da177e4SLinus Torvalds 529*1da177e4SLinus Torvalds static char *floppy_types[] = { 530*1da177e4SLinus Torvalds "none", "5.25'' 360k", "5.25'' 1.2M", "3.5'' 720k", "3.5'' 1.44M", 531*1da177e4SLinus Torvalds "3.5'' 2.88M", "3.5'' 2.88M" 532*1da177e4SLinus Torvalds }; 533*1da177e4SLinus Torvalds 534*1da177e4SLinus Torvalds static char *gfx_types[] = { 535*1da177e4SLinus Torvalds "EGA, VGA, ... (with BIOS)", 536*1da177e4SLinus Torvalds "CGA (40 cols)", 537*1da177e4SLinus Torvalds "CGA (80 cols)", 538*1da177e4SLinus Torvalds "monochrome", 539*1da177e4SLinus Torvalds }; 540*1da177e4SLinus Torvalds 541*1da177e4SLinus Torvalds static int 542*1da177e4SLinus Torvalds pc_proc_infos(unsigned char *nvram, char *buffer, int *len, 543*1da177e4SLinus Torvalds off_t *begin, off_t offset, int size) 544*1da177e4SLinus Torvalds { 545*1da177e4SLinus Torvalds int checksum; 546*1da177e4SLinus Torvalds int type; 547*1da177e4SLinus Torvalds 548*1da177e4SLinus Torvalds spin_lock_irq(&rtc_lock); 549*1da177e4SLinus Torvalds checksum = __nvram_check_checksum(); 550*1da177e4SLinus Torvalds spin_unlock_irq(&rtc_lock); 551*1da177e4SLinus Torvalds 552*1da177e4SLinus Torvalds PRINT_PROC("Checksum status: %svalid\n", checksum ? "" : "not "); 553*1da177e4SLinus Torvalds 554*1da177e4SLinus Torvalds PRINT_PROC("# floppies : %d\n", 555*1da177e4SLinus Torvalds (nvram[6] & 1) ? (nvram[6] >> 6) + 1 : 0); 556*1da177e4SLinus Torvalds PRINT_PROC("Floppy 0 type : "); 557*1da177e4SLinus Torvalds type = nvram[2] >> 4; 558*1da177e4SLinus Torvalds if (type < sizeof (floppy_types) / sizeof (*floppy_types)) 559*1da177e4SLinus Torvalds PRINT_PROC("%s\n", floppy_types[type]); 560*1da177e4SLinus Torvalds else 561*1da177e4SLinus Torvalds PRINT_PROC("%d (unknown)\n", type); 562*1da177e4SLinus Torvalds PRINT_PROC("Floppy 1 type : "); 563*1da177e4SLinus Torvalds type = nvram[2] & 0x0f; 564*1da177e4SLinus Torvalds if (type < sizeof (floppy_types) / sizeof (*floppy_types)) 565*1da177e4SLinus Torvalds PRINT_PROC("%s\n", floppy_types[type]); 566*1da177e4SLinus Torvalds else 567*1da177e4SLinus Torvalds PRINT_PROC("%d (unknown)\n", type); 568*1da177e4SLinus Torvalds 569*1da177e4SLinus Torvalds PRINT_PROC("HD 0 type : "); 570*1da177e4SLinus Torvalds type = nvram[4] >> 4; 571*1da177e4SLinus Torvalds if (type) 572*1da177e4SLinus Torvalds PRINT_PROC("%02x\n", type == 0x0f ? nvram[11] : type); 573*1da177e4SLinus Torvalds else 574*1da177e4SLinus Torvalds PRINT_PROC("none\n"); 575*1da177e4SLinus Torvalds 576*1da177e4SLinus Torvalds PRINT_PROC("HD 1 type : "); 577*1da177e4SLinus Torvalds type = nvram[4] & 0x0f; 578*1da177e4SLinus Torvalds if (type) 579*1da177e4SLinus Torvalds PRINT_PROC("%02x\n", type == 0x0f ? nvram[12] : type); 580*1da177e4SLinus Torvalds else 581*1da177e4SLinus Torvalds PRINT_PROC("none\n"); 582*1da177e4SLinus Torvalds 583*1da177e4SLinus Torvalds PRINT_PROC("HD type 48 data: %d/%d/%d C/H/S, precomp %d, lz %d\n", 584*1da177e4SLinus Torvalds nvram[18] | (nvram[19] << 8), 585*1da177e4SLinus Torvalds nvram[20], nvram[25], 586*1da177e4SLinus Torvalds nvram[21] | (nvram[22] << 8), nvram[23] | (nvram[24] << 8)); 587*1da177e4SLinus Torvalds PRINT_PROC("HD type 49 data: %d/%d/%d C/H/S, precomp %d, lz %d\n", 588*1da177e4SLinus Torvalds nvram[39] | (nvram[40] << 8), 589*1da177e4SLinus Torvalds nvram[41], nvram[46], 590*1da177e4SLinus Torvalds nvram[42] | (nvram[43] << 8), nvram[44] | (nvram[45] << 8)); 591*1da177e4SLinus Torvalds 592*1da177e4SLinus Torvalds PRINT_PROC("DOS base memory: %d kB\n", nvram[7] | (nvram[8] << 8)); 593*1da177e4SLinus Torvalds PRINT_PROC("Extended memory: %d kB (configured), %d kB (tested)\n", 594*1da177e4SLinus Torvalds nvram[9] | (nvram[10] << 8), nvram[34] | (nvram[35] << 8)); 595*1da177e4SLinus Torvalds 596*1da177e4SLinus Torvalds PRINT_PROC("Gfx adapter : %s\n", gfx_types[(nvram[6] >> 4) & 3]); 597*1da177e4SLinus Torvalds 598*1da177e4SLinus Torvalds PRINT_PROC("FPU : %sinstalled\n", 599*1da177e4SLinus Torvalds (nvram[6] & 2) ? "" : "not "); 600*1da177e4SLinus Torvalds 601*1da177e4SLinus Torvalds return 1; 602*1da177e4SLinus Torvalds } 603*1da177e4SLinus Torvalds #endif 604*1da177e4SLinus Torvalds 605*1da177e4SLinus Torvalds #endif /* MACH == PC */ 606*1da177e4SLinus Torvalds 607*1da177e4SLinus Torvalds #if MACH == COBALT 608*1da177e4SLinus Torvalds 609*1da177e4SLinus Torvalds /* the cobalt CMOS has a wider range of its checksum */ 610*1da177e4SLinus Torvalds static int cobalt_check_checksum(void) 611*1da177e4SLinus Torvalds { 612*1da177e4SLinus Torvalds int i; 613*1da177e4SLinus Torvalds unsigned short sum = 0; 614*1da177e4SLinus Torvalds unsigned short expect; 615*1da177e4SLinus Torvalds 616*1da177e4SLinus Torvalds for (i = COBT_CMOS_CKS_START; i <= COBT_CMOS_CKS_END; ++i) { 617*1da177e4SLinus Torvalds if ((i == COBT_CMOS_CHECKSUM) || (i == (COBT_CMOS_CHECKSUM+1))) 618*1da177e4SLinus Torvalds continue; 619*1da177e4SLinus Torvalds 620*1da177e4SLinus Torvalds sum += __nvram_read_byte(i); 621*1da177e4SLinus Torvalds } 622*1da177e4SLinus Torvalds expect = __nvram_read_byte(COBT_CMOS_CHECKSUM) << 8 | 623*1da177e4SLinus Torvalds __nvram_read_byte(COBT_CMOS_CHECKSUM+1); 624*1da177e4SLinus Torvalds return ((sum & 0xffff) == expect); 625*1da177e4SLinus Torvalds } 626*1da177e4SLinus Torvalds 627*1da177e4SLinus Torvalds static void cobalt_set_checksum(void) 628*1da177e4SLinus Torvalds { 629*1da177e4SLinus Torvalds int i; 630*1da177e4SLinus Torvalds unsigned short sum = 0; 631*1da177e4SLinus Torvalds 632*1da177e4SLinus Torvalds for (i = COBT_CMOS_CKS_START; i <= COBT_CMOS_CKS_END; ++i) { 633*1da177e4SLinus Torvalds if ((i == COBT_CMOS_CHECKSUM) || (i == (COBT_CMOS_CHECKSUM+1))) 634*1da177e4SLinus Torvalds continue; 635*1da177e4SLinus Torvalds 636*1da177e4SLinus Torvalds sum += __nvram_read_byte(i); 637*1da177e4SLinus Torvalds } 638*1da177e4SLinus Torvalds 639*1da177e4SLinus Torvalds __nvram_write_byte(sum >> 8, COBT_CMOS_CHECKSUM); 640*1da177e4SLinus Torvalds __nvram_write_byte(sum & 0xff, COBT_CMOS_CHECKSUM+1); 641*1da177e4SLinus Torvalds } 642*1da177e4SLinus Torvalds 643*1da177e4SLinus Torvalds #ifdef CONFIG_PROC_FS 644*1da177e4SLinus Torvalds 645*1da177e4SLinus Torvalds static int cobalt_proc_infos(unsigned char *nvram, char *buffer, int *len, 646*1da177e4SLinus Torvalds off_t *begin, off_t offset, int size) 647*1da177e4SLinus Torvalds { 648*1da177e4SLinus Torvalds int i; 649*1da177e4SLinus Torvalds unsigned int checksum; 650*1da177e4SLinus Torvalds unsigned int flags; 651*1da177e4SLinus Torvalds char sernum[14]; 652*1da177e4SLinus Torvalds char *key = "cNoEbTaWlOtR!"; 653*1da177e4SLinus Torvalds unsigned char bto_csum; 654*1da177e4SLinus Torvalds 655*1da177e4SLinus Torvalds spin_lock_irq(&rtc_lock); 656*1da177e4SLinus Torvalds checksum = __nvram_check_checksum(); 657*1da177e4SLinus Torvalds spin_unlock_irq(&rtc_lock); 658*1da177e4SLinus Torvalds 659*1da177e4SLinus Torvalds PRINT_PROC("Checksum status: %svalid\n", checksum ? "" : "not "); 660*1da177e4SLinus Torvalds 661*1da177e4SLinus Torvalds flags = nvram[COBT_CMOS_FLAG_BYTE_0] << 8 662*1da177e4SLinus Torvalds | nvram[COBT_CMOS_FLAG_BYTE_1]; 663*1da177e4SLinus Torvalds 664*1da177e4SLinus Torvalds PRINT_PROC("Console: %s\n", 665*1da177e4SLinus Torvalds flags & COBT_CMOS_CONSOLE_FLAG ? "on": "off"); 666*1da177e4SLinus Torvalds 667*1da177e4SLinus Torvalds PRINT_PROC("Firmware Debug Messages: %s\n", 668*1da177e4SLinus Torvalds flags & COBT_CMOS_DEBUG_FLAG ? "on": "off"); 669*1da177e4SLinus Torvalds 670*1da177e4SLinus Torvalds PRINT_PROC("Auto Prompt: %s\n", 671*1da177e4SLinus Torvalds flags & COBT_CMOS_AUTO_PROMPT_FLAG ? "on": "off"); 672*1da177e4SLinus Torvalds 673*1da177e4SLinus Torvalds PRINT_PROC("Shutdown Status: %s\n", 674*1da177e4SLinus Torvalds flags & COBT_CMOS_CLEAN_BOOT_FLAG ? "clean": "dirty"); 675*1da177e4SLinus Torvalds 676*1da177e4SLinus Torvalds PRINT_PROC("Hardware Probe: %s\n", 677*1da177e4SLinus Torvalds flags & COBT_CMOS_HW_NOPROBE_FLAG ? "partial": "full"); 678*1da177e4SLinus Torvalds 679*1da177e4SLinus Torvalds PRINT_PROC("System Fault: %sdetected\n", 680*1da177e4SLinus Torvalds flags & COBT_CMOS_SYSFAULT_FLAG ? "": "not "); 681*1da177e4SLinus Torvalds 682*1da177e4SLinus Torvalds PRINT_PROC("Panic on OOPS: %s\n", 683*1da177e4SLinus Torvalds flags & COBT_CMOS_OOPSPANIC_FLAG ? "yes": "no"); 684*1da177e4SLinus Torvalds 685*1da177e4SLinus Torvalds PRINT_PROC("Delayed Cache Initialization: %s\n", 686*1da177e4SLinus Torvalds flags & COBT_CMOS_DELAY_CACHE_FLAG ? "yes": "no"); 687*1da177e4SLinus Torvalds 688*1da177e4SLinus Torvalds PRINT_PROC("Show Logo at Boot: %s\n", 689*1da177e4SLinus Torvalds flags & COBT_CMOS_NOLOGO_FLAG ? "no": "yes"); 690*1da177e4SLinus Torvalds 691*1da177e4SLinus Torvalds PRINT_PROC("Boot Method: "); 692*1da177e4SLinus Torvalds switch (nvram[COBT_CMOS_BOOT_METHOD]) { 693*1da177e4SLinus Torvalds case COBT_CMOS_BOOT_METHOD_DISK: 694*1da177e4SLinus Torvalds PRINT_PROC("disk\n"); 695*1da177e4SLinus Torvalds break; 696*1da177e4SLinus Torvalds 697*1da177e4SLinus Torvalds case COBT_CMOS_BOOT_METHOD_ROM: 698*1da177e4SLinus Torvalds PRINT_PROC("rom\n"); 699*1da177e4SLinus Torvalds break; 700*1da177e4SLinus Torvalds 701*1da177e4SLinus Torvalds case COBT_CMOS_BOOT_METHOD_NET: 702*1da177e4SLinus Torvalds PRINT_PROC("net\n"); 703*1da177e4SLinus Torvalds break; 704*1da177e4SLinus Torvalds 705*1da177e4SLinus Torvalds default: 706*1da177e4SLinus Torvalds PRINT_PROC("unknown\n"); 707*1da177e4SLinus Torvalds break; 708*1da177e4SLinus Torvalds } 709*1da177e4SLinus Torvalds 710*1da177e4SLinus Torvalds PRINT_PROC("Primary Boot Device: %d:%d\n", 711*1da177e4SLinus Torvalds nvram[COBT_CMOS_BOOT_DEV0_MAJ], 712*1da177e4SLinus Torvalds nvram[COBT_CMOS_BOOT_DEV0_MIN] ); 713*1da177e4SLinus Torvalds PRINT_PROC("Secondary Boot Device: %d:%d\n", 714*1da177e4SLinus Torvalds nvram[COBT_CMOS_BOOT_DEV1_MAJ], 715*1da177e4SLinus Torvalds nvram[COBT_CMOS_BOOT_DEV1_MIN] ); 716*1da177e4SLinus Torvalds PRINT_PROC("Tertiary Boot Device: %d:%d\n", 717*1da177e4SLinus Torvalds nvram[COBT_CMOS_BOOT_DEV2_MAJ], 718*1da177e4SLinus Torvalds nvram[COBT_CMOS_BOOT_DEV2_MIN] ); 719*1da177e4SLinus Torvalds 720*1da177e4SLinus Torvalds PRINT_PROC("Uptime: %d\n", 721*1da177e4SLinus Torvalds nvram[COBT_CMOS_UPTIME_0] << 24 | 722*1da177e4SLinus Torvalds nvram[COBT_CMOS_UPTIME_1] << 16 | 723*1da177e4SLinus Torvalds nvram[COBT_CMOS_UPTIME_2] << 8 | 724*1da177e4SLinus Torvalds nvram[COBT_CMOS_UPTIME_3]); 725*1da177e4SLinus Torvalds 726*1da177e4SLinus Torvalds PRINT_PROC("Boot Count: %d\n", 727*1da177e4SLinus Torvalds nvram[COBT_CMOS_BOOTCOUNT_0] << 24 | 728*1da177e4SLinus Torvalds nvram[COBT_CMOS_BOOTCOUNT_1] << 16 | 729*1da177e4SLinus Torvalds nvram[COBT_CMOS_BOOTCOUNT_2] << 8 | 730*1da177e4SLinus Torvalds nvram[COBT_CMOS_BOOTCOUNT_3]); 731*1da177e4SLinus Torvalds 732*1da177e4SLinus Torvalds /* 13 bytes of serial num */ 733*1da177e4SLinus Torvalds for (i=0 ; i<13 ; i++) { 734*1da177e4SLinus Torvalds sernum[i] = nvram[COBT_CMOS_SYS_SERNUM_0 + i]; 735*1da177e4SLinus Torvalds } 736*1da177e4SLinus Torvalds sernum[13] = '\0'; 737*1da177e4SLinus Torvalds 738*1da177e4SLinus Torvalds checksum = 0; 739*1da177e4SLinus Torvalds for (i=0 ; i<13 ; i++) { 740*1da177e4SLinus Torvalds checksum += sernum[i] ^ key[i]; 741*1da177e4SLinus Torvalds } 742*1da177e4SLinus Torvalds checksum = ((checksum & 0x7f) ^ (0xd6)) & 0xff; 743*1da177e4SLinus Torvalds 744*1da177e4SLinus Torvalds PRINT_PROC("Serial Number: %s", sernum); 745*1da177e4SLinus Torvalds if (checksum != nvram[COBT_CMOS_SYS_SERNUM_CSUM]) { 746*1da177e4SLinus Torvalds PRINT_PROC(" (invalid checksum)"); 747*1da177e4SLinus Torvalds } 748*1da177e4SLinus Torvalds PRINT_PROC("\n"); 749*1da177e4SLinus Torvalds 750*1da177e4SLinus Torvalds PRINT_PROC("Rom Revison: %d.%d.%d\n", nvram[COBT_CMOS_ROM_REV_MAJ], 751*1da177e4SLinus Torvalds nvram[COBT_CMOS_ROM_REV_MIN], nvram[COBT_CMOS_ROM_REV_REV]); 752*1da177e4SLinus Torvalds 753*1da177e4SLinus Torvalds PRINT_PROC("BTO Server: %d.%d.%d.%d", nvram[COBT_CMOS_BTO_IP_0], 754*1da177e4SLinus Torvalds nvram[COBT_CMOS_BTO_IP_1], nvram[COBT_CMOS_BTO_IP_2], 755*1da177e4SLinus Torvalds nvram[COBT_CMOS_BTO_IP_3]); 756*1da177e4SLinus Torvalds bto_csum = nvram[COBT_CMOS_BTO_IP_0] + nvram[COBT_CMOS_BTO_IP_1] 757*1da177e4SLinus Torvalds + nvram[COBT_CMOS_BTO_IP_2] + nvram[COBT_CMOS_BTO_IP_3]; 758*1da177e4SLinus Torvalds if (bto_csum != nvram[COBT_CMOS_BTO_IP_CSUM]) { 759*1da177e4SLinus Torvalds PRINT_PROC(" (invalid checksum)"); 760*1da177e4SLinus Torvalds } 761*1da177e4SLinus Torvalds PRINT_PROC("\n"); 762*1da177e4SLinus Torvalds 763*1da177e4SLinus Torvalds if (flags & COBT_CMOS_VERSION_FLAG 764*1da177e4SLinus Torvalds && nvram[COBT_CMOS_VERSION] >= COBT_CMOS_VER_BTOCODE) { 765*1da177e4SLinus Torvalds PRINT_PROC("BTO Code: 0x%x\n", 766*1da177e4SLinus Torvalds nvram[COBT_CMOS_BTO_CODE_0] << 24 | 767*1da177e4SLinus Torvalds nvram[COBT_CMOS_BTO_CODE_1] << 16 | 768*1da177e4SLinus Torvalds nvram[COBT_CMOS_BTO_CODE_2] << 8 | 769*1da177e4SLinus Torvalds nvram[COBT_CMOS_BTO_CODE_3]); 770*1da177e4SLinus Torvalds } 771*1da177e4SLinus Torvalds 772*1da177e4SLinus Torvalds return 1; 773*1da177e4SLinus Torvalds } 774*1da177e4SLinus Torvalds #endif /* CONFIG_PROC_FS */ 775*1da177e4SLinus Torvalds 776*1da177e4SLinus Torvalds #endif /* MACH == COBALT */ 777*1da177e4SLinus Torvalds 778*1da177e4SLinus Torvalds #if MACH == ATARI 779*1da177e4SLinus Torvalds 780*1da177e4SLinus Torvalds static int 781*1da177e4SLinus Torvalds atari_check_checksum(void) 782*1da177e4SLinus Torvalds { 783*1da177e4SLinus Torvalds int i; 784*1da177e4SLinus Torvalds unsigned char sum = 0; 785*1da177e4SLinus Torvalds 786*1da177e4SLinus Torvalds for (i = ATARI_CKS_RANGE_START; i <= ATARI_CKS_RANGE_END; ++i) 787*1da177e4SLinus Torvalds sum += __nvram_read_byte(i); 788*1da177e4SLinus Torvalds return (__nvram_read_byte(ATARI_CKS_LOC) == (~sum & 0xff) && 789*1da177e4SLinus Torvalds __nvram_read_byte(ATARI_CKS_LOC + 1) == (sum & 0xff)); 790*1da177e4SLinus Torvalds } 791*1da177e4SLinus Torvalds 792*1da177e4SLinus Torvalds static void 793*1da177e4SLinus Torvalds atari_set_checksum(void) 794*1da177e4SLinus Torvalds { 795*1da177e4SLinus Torvalds int i; 796*1da177e4SLinus Torvalds unsigned char sum = 0; 797*1da177e4SLinus Torvalds 798*1da177e4SLinus Torvalds for (i = ATARI_CKS_RANGE_START; i <= ATARI_CKS_RANGE_END; ++i) 799*1da177e4SLinus Torvalds sum += __nvram_read_byte(i); 800*1da177e4SLinus Torvalds __nvram_write_byte(~sum, ATARI_CKS_LOC); 801*1da177e4SLinus Torvalds __nvram_write_byte(sum, ATARI_CKS_LOC + 1); 802*1da177e4SLinus Torvalds } 803*1da177e4SLinus Torvalds 804*1da177e4SLinus Torvalds #ifdef CONFIG_PROC_FS 805*1da177e4SLinus Torvalds 806*1da177e4SLinus Torvalds static struct { 807*1da177e4SLinus Torvalds unsigned char val; 808*1da177e4SLinus Torvalds char *name; 809*1da177e4SLinus Torvalds } boot_prefs[] = { 810*1da177e4SLinus Torvalds { 0x80, "TOS" }, 811*1da177e4SLinus Torvalds { 0x40, "ASV" }, 812*1da177e4SLinus Torvalds { 0x20, "NetBSD (?)" }, 813*1da177e4SLinus Torvalds { 0x10, "Linux" }, 814*1da177e4SLinus Torvalds { 0x00, "unspecified" } 815*1da177e4SLinus Torvalds }; 816*1da177e4SLinus Torvalds 817*1da177e4SLinus Torvalds static char *languages[] = { 818*1da177e4SLinus Torvalds "English (US)", 819*1da177e4SLinus Torvalds "German", 820*1da177e4SLinus Torvalds "French", 821*1da177e4SLinus Torvalds "English (UK)", 822*1da177e4SLinus Torvalds "Spanish", 823*1da177e4SLinus Torvalds "Italian", 824*1da177e4SLinus Torvalds "6 (undefined)", 825*1da177e4SLinus Torvalds "Swiss (French)", 826*1da177e4SLinus Torvalds "Swiss (German)" 827*1da177e4SLinus Torvalds }; 828*1da177e4SLinus Torvalds 829*1da177e4SLinus Torvalds static char *dateformat[] = { 830*1da177e4SLinus Torvalds "MM%cDD%cYY", 831*1da177e4SLinus Torvalds "DD%cMM%cYY", 832*1da177e4SLinus Torvalds "YY%cMM%cDD", 833*1da177e4SLinus Torvalds "YY%cDD%cMM", 834*1da177e4SLinus Torvalds "4 (undefined)", 835*1da177e4SLinus Torvalds "5 (undefined)", 836*1da177e4SLinus Torvalds "6 (undefined)", 837*1da177e4SLinus Torvalds "7 (undefined)" 838*1da177e4SLinus Torvalds }; 839*1da177e4SLinus Torvalds 840*1da177e4SLinus Torvalds static char *colors[] = { 841*1da177e4SLinus Torvalds "2", "4", "16", "256", "65536", "??", "??", "??" 842*1da177e4SLinus Torvalds }; 843*1da177e4SLinus Torvalds 844*1da177e4SLinus Torvalds #define fieldsize(a) (sizeof(a)/sizeof(*a)) 845*1da177e4SLinus Torvalds 846*1da177e4SLinus Torvalds static int 847*1da177e4SLinus Torvalds atari_proc_infos(unsigned char *nvram, char *buffer, int *len, 848*1da177e4SLinus Torvalds off_t *begin, off_t offset, int size) 849*1da177e4SLinus Torvalds { 850*1da177e4SLinus Torvalds int checksum = nvram_check_checksum(); 851*1da177e4SLinus Torvalds int i; 852*1da177e4SLinus Torvalds unsigned vmode; 853*1da177e4SLinus Torvalds 854*1da177e4SLinus Torvalds PRINT_PROC("Checksum status : %svalid\n", checksum ? "" : "not "); 855*1da177e4SLinus Torvalds 856*1da177e4SLinus Torvalds PRINT_PROC("Boot preference : "); 857*1da177e4SLinus Torvalds for (i = fieldsize(boot_prefs) - 1; i >= 0; --i) { 858*1da177e4SLinus Torvalds if (nvram[1] == boot_prefs[i].val) { 859*1da177e4SLinus Torvalds PRINT_PROC("%s\n", boot_prefs[i].name); 860*1da177e4SLinus Torvalds break; 861*1da177e4SLinus Torvalds } 862*1da177e4SLinus Torvalds } 863*1da177e4SLinus Torvalds if (i < 0) 864*1da177e4SLinus Torvalds PRINT_PROC("0x%02x (undefined)\n", nvram[1]); 865*1da177e4SLinus Torvalds 866*1da177e4SLinus Torvalds PRINT_PROC("SCSI arbitration : %s\n", 867*1da177e4SLinus Torvalds (nvram[16] & 0x80) ? "on" : "off"); 868*1da177e4SLinus Torvalds PRINT_PROC("SCSI host ID : "); 869*1da177e4SLinus Torvalds if (nvram[16] & 0x80) 870*1da177e4SLinus Torvalds PRINT_PROC("%d\n", nvram[16] & 7); 871*1da177e4SLinus Torvalds else 872*1da177e4SLinus Torvalds PRINT_PROC("n/a\n"); 873*1da177e4SLinus Torvalds 874*1da177e4SLinus Torvalds /* the following entries are defined only for the Falcon */ 875*1da177e4SLinus Torvalds if ((atari_mch_cookie >> 16) != ATARI_MCH_FALCON) 876*1da177e4SLinus Torvalds return 1; 877*1da177e4SLinus Torvalds 878*1da177e4SLinus Torvalds PRINT_PROC("OS language : "); 879*1da177e4SLinus Torvalds if (nvram[6] < fieldsize(languages)) 880*1da177e4SLinus Torvalds PRINT_PROC("%s\n", languages[nvram[6]]); 881*1da177e4SLinus Torvalds else 882*1da177e4SLinus Torvalds PRINT_PROC("%u (undefined)\n", nvram[6]); 883*1da177e4SLinus Torvalds PRINT_PROC("Keyboard language: "); 884*1da177e4SLinus Torvalds if (nvram[7] < fieldsize(languages)) 885*1da177e4SLinus Torvalds PRINT_PROC("%s\n", languages[nvram[7]]); 886*1da177e4SLinus Torvalds else 887*1da177e4SLinus Torvalds PRINT_PROC("%u (undefined)\n", nvram[7]); 888*1da177e4SLinus Torvalds PRINT_PROC("Date format : "); 889*1da177e4SLinus Torvalds PRINT_PROC(dateformat[nvram[8] & 7], 890*1da177e4SLinus Torvalds nvram[9] ? nvram[9] : '/', nvram[9] ? nvram[9] : '/'); 891*1da177e4SLinus Torvalds PRINT_PROC(", %dh clock\n", nvram[8] & 16 ? 24 : 12); 892*1da177e4SLinus Torvalds PRINT_PROC("Boot delay : "); 893*1da177e4SLinus Torvalds if (nvram[10] == 0) 894*1da177e4SLinus Torvalds PRINT_PROC("default"); 895*1da177e4SLinus Torvalds else 896*1da177e4SLinus Torvalds PRINT_PROC("%ds%s\n", nvram[10], 897*1da177e4SLinus Torvalds nvram[10] < 8 ? ", no memory test" : ""); 898*1da177e4SLinus Torvalds 899*1da177e4SLinus Torvalds vmode = (nvram[14] << 8) || nvram[15]; 900*1da177e4SLinus Torvalds PRINT_PROC("Video mode : %s colors, %d columns, %s %s monitor\n", 901*1da177e4SLinus Torvalds colors[vmode & 7], 902*1da177e4SLinus Torvalds vmode & 8 ? 80 : 40, 903*1da177e4SLinus Torvalds vmode & 16 ? "VGA" : "TV", vmode & 32 ? "PAL" : "NTSC"); 904*1da177e4SLinus Torvalds PRINT_PROC(" %soverscan, compat. mode %s%s\n", 905*1da177e4SLinus Torvalds vmode & 64 ? "" : "no ", 906*1da177e4SLinus Torvalds vmode & 128 ? "on" : "off", 907*1da177e4SLinus Torvalds vmode & 256 ? 908*1da177e4SLinus Torvalds (vmode & 16 ? ", line doubling" : ", half screen") : ""); 909*1da177e4SLinus Torvalds 910*1da177e4SLinus Torvalds return 1; 911*1da177e4SLinus Torvalds } 912*1da177e4SLinus Torvalds #endif 913*1da177e4SLinus Torvalds 914*1da177e4SLinus Torvalds #endif /* MACH == ATARI */ 915*1da177e4SLinus Torvalds 916*1da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 917*1da177e4SLinus Torvalds 918*1da177e4SLinus Torvalds EXPORT_SYMBOL(__nvram_read_byte); 919*1da177e4SLinus Torvalds EXPORT_SYMBOL(nvram_read_byte); 920*1da177e4SLinus Torvalds EXPORT_SYMBOL(__nvram_write_byte); 921*1da177e4SLinus Torvalds EXPORT_SYMBOL(nvram_write_byte); 922*1da177e4SLinus Torvalds EXPORT_SYMBOL(__nvram_check_checksum); 923*1da177e4SLinus Torvalds EXPORT_SYMBOL(nvram_check_checksum); 924*1da177e4SLinus Torvalds EXPORT_SYMBOL(__nvram_set_checksum); 925*1da177e4SLinus Torvalds EXPORT_SYMBOL(nvram_set_checksum); 926*1da177e4SLinus Torvalds MODULE_ALIAS_MISCDEV(NVRAM_MINOR); 927