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