Commit 2d58636e authored by Finn Thain's avatar Finn Thain Committed by Greg Kroah-Hartman

char/nvram: Allow the set_checksum and initialize ioctls to be omitted

The drivers/char/nvram.c module has previously supported only RTC "CMOS"
NVRAM, for which it provides appropriate checksum ioctls. Make these
ioctls optional so the module can be re-used with other kinds of NVRAM.

The ops struct methods that implement the ioctls now return error
codes so that a multi-platform kernel binary can do the right thing when
running on hardware without a suitable NVRAM.
Signed-off-by: default avatarFinn Thain <fthain@telegraphics.com.au>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent d5bbb502
...@@ -136,16 +136,25 @@ static void __nvram_set_checksum(void) ...@@ -136,16 +136,25 @@ static void __nvram_set_checksum(void)
__nvram_write_byte(sum & 0xff, PC_CKS_LOC + 1); __nvram_write_byte(sum & 0xff, PC_CKS_LOC + 1);
} }
#if 0 static long pc_nvram_set_checksum(void)
void nvram_set_checksum(void)
{ {
unsigned long flags; spin_lock_irq(&rtc_lock);
__nvram_set_checksum();
spin_unlock_irq(&rtc_lock);
return 0;
}
spin_lock_irqsave(&rtc_lock, flags); static long pc_nvram_initialize(void)
{
ssize_t i;
spin_lock_irq(&rtc_lock);
for (i = 0; i < NVRAM_BYTES; ++i)
__nvram_write_byte(0, i);
__nvram_set_checksum(); __nvram_set_checksum();
spin_unlock_irqrestore(&rtc_lock, flags); spin_unlock_irq(&rtc_lock);
return 0;
} }
#endif /* 0 */
static ssize_t pc_nvram_get_size(void) static ssize_t pc_nvram_get_size(void)
{ {
...@@ -156,6 +165,8 @@ const struct nvram_ops arch_nvram_ops = { ...@@ -156,6 +165,8 @@ const struct nvram_ops arch_nvram_ops = {
.read_byte = pc_nvram_read_byte, .read_byte = pc_nvram_read_byte,
.write_byte = pc_nvram_write_byte, .write_byte = pc_nvram_write_byte,
.get_size = pc_nvram_get_size, .get_size = pc_nvram_get_size,
.set_checksum = pc_nvram_set_checksum,
.initialize = pc_nvram_initialize,
}; };
EXPORT_SYMBOL(arch_nvram_ops); EXPORT_SYMBOL(arch_nvram_ops);
#endif /* CONFIG_X86 */ #endif /* CONFIG_X86 */
...@@ -241,51 +252,50 @@ static ssize_t nvram_misc_write(struct file *file, const char __user *buf, ...@@ -241,51 +252,50 @@ static ssize_t nvram_misc_write(struct file *file, const char __user *buf,
static long nvram_misc_ioctl(struct file *file, unsigned int cmd, static long nvram_misc_ioctl(struct file *file, unsigned int cmd,
unsigned long arg) unsigned long arg)
{ {
int i; long ret = -ENOTTY;
switch (cmd) { switch (cmd) {
case NVRAM_INIT: case NVRAM_INIT:
/* initialize NVRAM contents and checksum */ /* initialize NVRAM contents and checksum */
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return -EACCES; return -EACCES;
mutex_lock(&nvram_mutex); if (arch_nvram_ops.initialize != NULL) {
spin_lock_irq(&rtc_lock); mutex_lock(&nvram_mutex);
ret = arch_nvram_ops.initialize();
for (i = 0; i < NVRAM_BYTES; ++i) mutex_unlock(&nvram_mutex);
__nvram_write_byte(0, i); }
__nvram_set_checksum(); break;
spin_unlock_irq(&rtc_lock);
mutex_unlock(&nvram_mutex);
return 0;
case NVRAM_SETCKS: case NVRAM_SETCKS:
/* just set checksum, contents unchanged (maybe useful after /* just set checksum, contents unchanged (maybe useful after
* checksum garbaged somehow...) */ * checksum garbaged somehow...) */
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return -EACCES; return -EACCES;
mutex_lock(&nvram_mutex); if (arch_nvram_ops.set_checksum != NULL) {
spin_lock_irq(&rtc_lock); mutex_lock(&nvram_mutex);
__nvram_set_checksum(); ret = arch_nvram_ops.set_checksum();
spin_unlock_irq(&rtc_lock); mutex_unlock(&nvram_mutex);
mutex_unlock(&nvram_mutex); }
return 0; break;
default:
return -ENOTTY;
} }
return ret;
} }
static int nvram_misc_open(struct inode *inode, struct file *file) static int nvram_misc_open(struct inode *inode, struct file *file)
{ {
spin_lock(&nvram_state_lock); spin_lock(&nvram_state_lock);
/* Prevent multiple readers/writers if desired. */
if ((nvram_open_cnt && (file->f_flags & O_EXCL)) || if ((nvram_open_cnt && (file->f_flags & O_EXCL)) ||
(nvram_open_mode & NVRAM_EXCL) || (nvram_open_mode & NVRAM_EXCL)) {
((file->f_mode & FMODE_WRITE) && (nvram_open_mode & NVRAM_WRITE))) { spin_unlock(&nvram_state_lock);
return -EBUSY;
}
/* Prevent multiple writers if the set_checksum ioctl is implemented. */
if ((arch_nvram_ops.set_checksum != NULL) &&
(file->f_mode & FMODE_WRITE) && (nvram_open_mode & NVRAM_WRITE)) {
spin_unlock(&nvram_state_lock); spin_unlock(&nvram_state_lock);
return -EBUSY; return -EBUSY;
} }
......
...@@ -31,6 +31,8 @@ struct nvram_ops { ...@@ -31,6 +31,8 @@ struct nvram_ops {
void (*write_byte)(unsigned char, int); void (*write_byte)(unsigned char, int);
ssize_t (*read)(char *, size_t, loff_t *); ssize_t (*read)(char *, size_t, loff_t *);
ssize_t (*write)(char *, size_t, loff_t *); ssize_t (*write)(char *, size_t, loff_t *);
long (*initialize)(void);
long (*set_checksum)(void);
}; };
extern const struct nvram_ops arch_nvram_ops; extern const struct nvram_ops arch_nvram_ops;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment