1 /* 2 * CMOS/NV-RAM driver for Linux 3 * 4 * Copyright (C) 1997 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> 5 * idea by and with help from Richard Jelinek <rj@suse.de> 6 * Portions copyright (c) 2001,2002 Sun Microsystems (thockin@sun.com) 7 * 8 * This driver allows you to access the contents of the non-volatile memory in 9 * the mc146818rtc.h real-time clock. This chip is built into all PCs and into 10 * many Atari machines. In the former it's called "CMOS-RAM", in the latter 11 * "NVRAM" (NV stands for non-volatile). 12 * 13 * The data are supplied as a (seekable) character device, /dev/nvram. The 14 * size of this file is dependent on the controller. The usual size is 114, 15 * the number of freely available bytes in the memory (i.e., not used by the 16 * RTC itself). 17 * 18 * Checksums over the NVRAM contents are managed by this driver. In case of a 19 * bad checksum, reads and writes return -EIO. The checksum can be initialized 20 * to a sane state either by ioctl(NVRAM_INIT) (clear whole NVRAM) or 21 * ioctl(NVRAM_SETCKS) (doesn't change contents, just makes checksum valid 22 * again; use with care!) 23 * 24 * 1.1 Cesar Barros: SMP locking fixes 25 * added changelog 26 * 1.2 Erik Gilling: Cobalt Networks support 27 * Tim Hockin: general cleanup, Cobalt support 28 * 1.3 Wim Van Sebroeck: convert PRINT_PROC to seq_file 29 */ 30 31 #define NVRAM_VERSION "1.3" 32 33 #include <linux/module.h> 34 #include <linux/nvram.h> 35 #include <linux/types.h> 36 #include <linux/errno.h> 37 #include <linux/miscdevice.h> 38 #include <linux/ioport.h> 39 #include <linux/fcntl.h> 40 #include <linux/mc146818rtc.h> 41 #include <linux/init.h> 42 #include <linux/proc_fs.h> 43 #include <linux/seq_file.h> 44 #include <linux/spinlock.h> 45 #include <linux/io.h> 46 #include <linux/uaccess.h> 47 #include <linux/mutex.h> 48 #include <linux/pagemap.h> 49 50 51 static DEFINE_MUTEX(nvram_mutex); 52 static DEFINE_SPINLOCK(nvram_state_lock); 53 static int nvram_open_cnt; /* #times opened */ 54 static int nvram_open_mode; /* special open modes */ 55 #define NVRAM_WRITE 1 /* opened for writing (exclusive) */ 56 #define NVRAM_EXCL 2 /* opened with O_EXCL */ 57 58 #ifdef CONFIG_PROC_FS 59 static void pc_nvram_proc_read(unsigned char *contents, struct seq_file *seq, 60 void *offset); 61 #endif 62 63 /* 64 * These functions are provided to be called internally or by other parts of 65 * the kernel. It's up to the caller to ensure correct checksum before reading 66 * or after writing (needs to be done only once). 67 * 68 * It is worth noting that these functions all access bytes of general 69 * purpose memory in the NVRAM - that is to say, they all add the 70 * NVRAM_FIRST_BYTE offset. Pass them offsets into NVRAM as if you did not 71 * know about the RTC cruft. 72 */ 73 74 #define NVRAM_BYTES (128 - NVRAM_FIRST_BYTE) 75 76 /* Note that *all* calls to CMOS_READ and CMOS_WRITE must be done with 77 * rtc_lock held. Due to the index-port/data-port design of the RTC, we 78 * don't want two different things trying to get to it at once. (e.g. the 79 * periodic 11 min sync from kernel/time/ntp.c vs. this driver.) 80 */ 81 82 unsigned char __nvram_read_byte(int i) 83 { 84 return CMOS_READ(NVRAM_FIRST_BYTE + i); 85 } 86 EXPORT_SYMBOL(__nvram_read_byte); 87 88 unsigned char nvram_read_byte(int i) 89 { 90 unsigned long flags; 91 unsigned char c; 92 93 spin_lock_irqsave(&rtc_lock, flags); 94 c = __nvram_read_byte(i); 95 spin_unlock_irqrestore(&rtc_lock, flags); 96 return c; 97 } 98 EXPORT_SYMBOL(nvram_read_byte); 99 100 /* This races nicely with trying to read with checksum checking (nvram_read) */ 101 void __nvram_write_byte(unsigned char c, int i) 102 { 103 CMOS_WRITE(c, NVRAM_FIRST_BYTE + i); 104 } 105 EXPORT_SYMBOL(__nvram_write_byte); 106 107 void nvram_write_byte(unsigned char c, int i) 108 { 109 unsigned long flags; 110 111 spin_lock_irqsave(&rtc_lock, flags); 112 __nvram_write_byte(c, i); 113 spin_unlock_irqrestore(&rtc_lock, flags); 114 } 115 EXPORT_SYMBOL(nvram_write_byte); 116 117 /* On PCs, the checksum is built only over bytes 2..31 */ 118 #define PC_CKS_RANGE_START 2 119 #define PC_CKS_RANGE_END 31 120 #define PC_CKS_LOC 32 121 122 int __nvram_check_checksum(void) 123 { 124 int i; 125 unsigned short sum = 0; 126 unsigned short expect; 127 128 for (i = PC_CKS_RANGE_START; i <= PC_CKS_RANGE_END; ++i) 129 sum += __nvram_read_byte(i); 130 expect = __nvram_read_byte(PC_CKS_LOC)<<8 | 131 __nvram_read_byte(PC_CKS_LOC+1); 132 return (sum & 0xffff) == expect; 133 } 134 EXPORT_SYMBOL(__nvram_check_checksum); 135 136 int nvram_check_checksum(void) 137 { 138 unsigned long flags; 139 int rv; 140 141 spin_lock_irqsave(&rtc_lock, flags); 142 rv = __nvram_check_checksum(); 143 spin_unlock_irqrestore(&rtc_lock, flags); 144 return rv; 145 } 146 EXPORT_SYMBOL(nvram_check_checksum); 147 148 static void __nvram_set_checksum(void) 149 { 150 int i; 151 unsigned short sum = 0; 152 153 for (i = PC_CKS_RANGE_START; i <= PC_CKS_RANGE_END; ++i) 154 sum += __nvram_read_byte(i); 155 __nvram_write_byte(sum >> 8, PC_CKS_LOC); 156 __nvram_write_byte(sum & 0xff, PC_CKS_LOC + 1); 157 } 158 159 #if 0 160 void nvram_set_checksum(void) 161 { 162 unsigned long flags; 163 164 spin_lock_irqsave(&rtc_lock, flags); 165 __nvram_set_checksum(); 166 spin_unlock_irqrestore(&rtc_lock, flags); 167 } 168 #endif /* 0 */ 169 170 /* 171 * The are the file operation function for user access to /dev/nvram 172 */ 173 174 static loff_t nvram_llseek(struct file *file, loff_t offset, int origin) 175 { 176 return generic_file_llseek_size(file, offset, origin, MAX_LFS_FILESIZE, 177 NVRAM_BYTES); 178 } 179 180 static ssize_t nvram_read(struct file *file, char __user *buf, 181 size_t count, loff_t *ppos) 182 { 183 unsigned char contents[NVRAM_BYTES]; 184 unsigned i = *ppos; 185 unsigned char *tmp; 186 187 spin_lock_irq(&rtc_lock); 188 189 if (!__nvram_check_checksum()) 190 goto checksum_err; 191 192 for (tmp = contents; count-- > 0 && i < NVRAM_BYTES; ++i, ++tmp) 193 *tmp = __nvram_read_byte(i); 194 195 spin_unlock_irq(&rtc_lock); 196 197 if (copy_to_user(buf, contents, tmp - contents)) 198 return -EFAULT; 199 200 *ppos = i; 201 202 return tmp - contents; 203 204 checksum_err: 205 spin_unlock_irq(&rtc_lock); 206 return -EIO; 207 } 208 209 static ssize_t nvram_write(struct file *file, const char __user *buf, 210 size_t count, loff_t *ppos) 211 { 212 unsigned char contents[NVRAM_BYTES]; 213 unsigned i = *ppos; 214 unsigned char *tmp; 215 216 if (i >= NVRAM_BYTES) 217 return 0; /* Past EOF */ 218 219 if (count > NVRAM_BYTES - i) 220 count = NVRAM_BYTES - i; 221 if (count > NVRAM_BYTES) 222 return -EFAULT; /* Can't happen, but prove it to gcc */ 223 224 if (copy_from_user(contents, buf, count)) 225 return -EFAULT; 226 227 spin_lock_irq(&rtc_lock); 228 229 if (!__nvram_check_checksum()) 230 goto checksum_err; 231 232 for (tmp = contents; count--; ++i, ++tmp) 233 __nvram_write_byte(*tmp, i); 234 235 __nvram_set_checksum(); 236 237 spin_unlock_irq(&rtc_lock); 238 239 *ppos = i; 240 241 return tmp - contents; 242 243 checksum_err: 244 spin_unlock_irq(&rtc_lock); 245 return -EIO; 246 } 247 248 static long nvram_ioctl(struct file *file, unsigned int cmd, 249 unsigned long arg) 250 { 251 int i; 252 253 switch (cmd) { 254 255 case NVRAM_INIT: 256 /* initialize NVRAM contents and checksum */ 257 if (!capable(CAP_SYS_ADMIN)) 258 return -EACCES; 259 260 mutex_lock(&nvram_mutex); 261 spin_lock_irq(&rtc_lock); 262 263 for (i = 0; i < NVRAM_BYTES; ++i) 264 __nvram_write_byte(0, i); 265 __nvram_set_checksum(); 266 267 spin_unlock_irq(&rtc_lock); 268 mutex_unlock(&nvram_mutex); 269 return 0; 270 271 case NVRAM_SETCKS: 272 /* just set checksum, contents unchanged (maybe useful after 273 * checksum garbaged somehow...) */ 274 if (!capable(CAP_SYS_ADMIN)) 275 return -EACCES; 276 277 mutex_lock(&nvram_mutex); 278 spin_lock_irq(&rtc_lock); 279 __nvram_set_checksum(); 280 spin_unlock_irq(&rtc_lock); 281 mutex_unlock(&nvram_mutex); 282 return 0; 283 284 default: 285 return -ENOTTY; 286 } 287 } 288 289 static int nvram_open(struct inode *inode, struct file *file) 290 { 291 spin_lock(&nvram_state_lock); 292 293 if ((nvram_open_cnt && (file->f_flags & O_EXCL)) || 294 (nvram_open_mode & NVRAM_EXCL) || 295 ((file->f_mode & FMODE_WRITE) && (nvram_open_mode & NVRAM_WRITE))) { 296 spin_unlock(&nvram_state_lock); 297 return -EBUSY; 298 } 299 300 if (file->f_flags & O_EXCL) 301 nvram_open_mode |= NVRAM_EXCL; 302 if (file->f_mode & FMODE_WRITE) 303 nvram_open_mode |= NVRAM_WRITE; 304 nvram_open_cnt++; 305 306 spin_unlock(&nvram_state_lock); 307 308 return 0; 309 } 310 311 static int nvram_release(struct inode *inode, struct file *file) 312 { 313 spin_lock(&nvram_state_lock); 314 315 nvram_open_cnt--; 316 317 /* if only one instance is open, clear the EXCL bit */ 318 if (nvram_open_mode & NVRAM_EXCL) 319 nvram_open_mode &= ~NVRAM_EXCL; 320 if (file->f_mode & FMODE_WRITE) 321 nvram_open_mode &= ~NVRAM_WRITE; 322 323 spin_unlock(&nvram_state_lock); 324 325 return 0; 326 } 327 328 #ifndef CONFIG_PROC_FS 329 static int nvram_add_proc_fs(void) 330 { 331 return 0; 332 } 333 334 #else 335 336 static int nvram_proc_read(struct seq_file *seq, void *offset) 337 { 338 unsigned char contents[NVRAM_BYTES]; 339 int i = 0; 340 341 spin_lock_irq(&rtc_lock); 342 for (i = 0; i < NVRAM_BYTES; ++i) 343 contents[i] = __nvram_read_byte(i); 344 spin_unlock_irq(&rtc_lock); 345 346 pc_nvram_proc_read(contents, seq, offset); 347 348 return 0; 349 } 350 351 static int nvram_add_proc_fs(void) 352 { 353 if (!proc_create_single("driver/nvram", 0, NULL, nvram_proc_read)) 354 return -ENOMEM; 355 return 0; 356 } 357 358 #endif /* CONFIG_PROC_FS */ 359 360 static const struct file_operations nvram_fops = { 361 .owner = THIS_MODULE, 362 .llseek = nvram_llseek, 363 .read = nvram_read, 364 .write = nvram_write, 365 .unlocked_ioctl = nvram_ioctl, 366 .open = nvram_open, 367 .release = nvram_release, 368 }; 369 370 static struct miscdevice nvram_dev = { 371 NVRAM_MINOR, 372 "nvram", 373 &nvram_fops 374 }; 375 376 static int __init nvram_init(void) 377 { 378 int ret; 379 380 ret = misc_register(&nvram_dev); 381 if (ret) { 382 printk(KERN_ERR "nvram: can't misc_register on minor=%d\n", 383 NVRAM_MINOR); 384 goto out; 385 } 386 ret = nvram_add_proc_fs(); 387 if (ret) { 388 printk(KERN_ERR "nvram: can't create /proc/driver/nvram\n"); 389 goto outmisc; 390 } 391 ret = 0; 392 printk(KERN_INFO "Non-volatile memory driver v" NVRAM_VERSION "\n"); 393 out: 394 return ret; 395 outmisc: 396 misc_deregister(&nvram_dev); 397 goto out; 398 } 399 400 static void __exit nvram_cleanup_module(void) 401 { 402 remove_proc_entry("driver/nvram", NULL); 403 misc_deregister(&nvram_dev); 404 } 405 406 module_init(nvram_init); 407 module_exit(nvram_cleanup_module); 408 409 #ifdef CONFIG_PROC_FS 410 411 static const char * const floppy_types[] = { 412 "none", "5.25'' 360k", "5.25'' 1.2M", "3.5'' 720k", "3.5'' 1.44M", 413 "3.5'' 2.88M", "3.5'' 2.88M" 414 }; 415 416 static const char * const gfx_types[] = { 417 "EGA, VGA, ... (with BIOS)", 418 "CGA (40 cols)", 419 "CGA (80 cols)", 420 "monochrome", 421 }; 422 423 static void pc_nvram_proc_read(unsigned char *nvram, struct seq_file *seq, 424 void *offset) 425 { 426 int checksum; 427 int type; 428 429 spin_lock_irq(&rtc_lock); 430 checksum = __nvram_check_checksum(); 431 spin_unlock_irq(&rtc_lock); 432 433 seq_printf(seq, "Checksum status: %svalid\n", checksum ? "" : "not "); 434 435 seq_printf(seq, "# floppies : %d\n", 436 (nvram[6] & 1) ? (nvram[6] >> 6) + 1 : 0); 437 seq_printf(seq, "Floppy 0 type : "); 438 type = nvram[2] >> 4; 439 if (type < ARRAY_SIZE(floppy_types)) 440 seq_printf(seq, "%s\n", floppy_types[type]); 441 else 442 seq_printf(seq, "%d (unknown)\n", type); 443 seq_printf(seq, "Floppy 1 type : "); 444 type = nvram[2] & 0x0f; 445 if (type < ARRAY_SIZE(floppy_types)) 446 seq_printf(seq, "%s\n", floppy_types[type]); 447 else 448 seq_printf(seq, "%d (unknown)\n", type); 449 450 seq_printf(seq, "HD 0 type : "); 451 type = nvram[4] >> 4; 452 if (type) 453 seq_printf(seq, "%02x\n", type == 0x0f ? nvram[11] : type); 454 else 455 seq_printf(seq, "none\n"); 456 457 seq_printf(seq, "HD 1 type : "); 458 type = nvram[4] & 0x0f; 459 if (type) 460 seq_printf(seq, "%02x\n", type == 0x0f ? nvram[12] : type); 461 else 462 seq_printf(seq, "none\n"); 463 464 seq_printf(seq, "HD type 48 data: %d/%d/%d C/H/S, precomp %d, lz %d\n", 465 nvram[18] | (nvram[19] << 8), 466 nvram[20], nvram[25], 467 nvram[21] | (nvram[22] << 8), nvram[23] | (nvram[24] << 8)); 468 seq_printf(seq, "HD type 49 data: %d/%d/%d C/H/S, precomp %d, lz %d\n", 469 nvram[39] | (nvram[40] << 8), 470 nvram[41], nvram[46], 471 nvram[42] | (nvram[43] << 8), nvram[44] | (nvram[45] << 8)); 472 473 seq_printf(seq, "DOS base memory: %d kB\n", nvram[7] | (nvram[8] << 8)); 474 seq_printf(seq, "Extended memory: %d kB (configured), %d kB (tested)\n", 475 nvram[9] | (nvram[10] << 8), nvram[34] | (nvram[35] << 8)); 476 477 seq_printf(seq, "Gfx adapter : %s\n", 478 gfx_types[(nvram[6] >> 4) & 3]); 479 480 seq_printf(seq, "FPU : %sinstalled\n", 481 (nvram[6] & 2) ? "" : "not "); 482 483 return; 484 } 485 486 #endif /* CONFIG_PROC_FS */ 487 488 MODULE_LICENSE("GPL"); 489 MODULE_ALIAS_MISCDEV(NVRAM_MINOR); 490