LCOV - code coverage report
Current view: top level - drivers/char - nvram.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 11 176 6.2 %
Date: 2022-04-01 14:58:12 Functions: 2 18 11.1 %
Branches: 3 71 4.2 %

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

Generated by: LCOV version 1.14