Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^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");