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

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
Loading
Loading
Loading
Loading
+40 −30
Original line number Diff line number Diff line
@@ -136,16 +136,25 @@ static void __nvram_set_checksum(void)
	__nvram_write_byte(sum & 0xff, PC_CKS_LOC + 1);
}

#if 0
void nvram_set_checksum(void)
static long pc_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();
	spin_unlock_irqrestore(&rtc_lock, flags);
	spin_unlock_irq(&rtc_lock);
	return 0;
}
#endif  /*  0  */

static ssize_t pc_nvram_get_size(void)
{
@@ -156,6 +165,8 @@ const struct nvram_ops arch_nvram_ops = {
	.read_byte      = pc_nvram_read_byte,
	.write_byte     = pc_nvram_write_byte,
	.get_size       = pc_nvram_get_size,
	.set_checksum   = pc_nvram_set_checksum,
	.initialize     = pc_nvram_initialize,
};
EXPORT_SYMBOL(arch_nvram_ops);
#endif /* CONFIG_X86 */
@@ -241,51 +252,50 @@ checksum_err:
static long nvram_misc_ioctl(struct file *file, unsigned int cmd,
			     unsigned long arg)
{
	int i;
	long ret = -ENOTTY;

	switch (cmd) {

	case NVRAM_INIT:
		/* initialize NVRAM contents and checksum */
		if (!capable(CAP_SYS_ADMIN))
			return -EACCES;

		if (arch_nvram_ops.initialize != NULL) {
			mutex_lock(&nvram_mutex);
		spin_lock_irq(&rtc_lock);

		for (i = 0; i < NVRAM_BYTES; ++i)
			__nvram_write_byte(0, i);
		__nvram_set_checksum();

		spin_unlock_irq(&rtc_lock);
			ret = arch_nvram_ops.initialize();
			mutex_unlock(&nvram_mutex);
		return 0;

		}
		break;
	case NVRAM_SETCKS:
		/* just set checksum, contents unchanged (maybe useful after
		 * checksum garbaged somehow...) */
		if (!capable(CAP_SYS_ADMIN))
			return -EACCES;

		if (arch_nvram_ops.set_checksum != NULL) {
			mutex_lock(&nvram_mutex);
		spin_lock_irq(&rtc_lock);
		__nvram_set_checksum();
		spin_unlock_irq(&rtc_lock);
			ret = arch_nvram_ops.set_checksum();
			mutex_unlock(&nvram_mutex);
		return 0;

	default:
		return -ENOTTY;
		}
		break;
	}
	return ret;
}

static int nvram_misc_open(struct inode *inode, struct file *file)
{
	spin_lock(&nvram_state_lock);

	/* Prevent multiple readers/writers if desired. */
	if ((nvram_open_cnt && (file->f_flags & O_EXCL)) ||
	    (nvram_open_mode & NVRAM_EXCL) ||
	    ((file->f_mode & FMODE_WRITE) && (nvram_open_mode & NVRAM_WRITE))) {
	    (nvram_open_mode & NVRAM_EXCL)) {
		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);
		return -EBUSY;
	}
+2 −0
Original line number Diff line number Diff line
@@ -31,6 +31,8 @@ struct nvram_ops {
	void            (*write_byte)(unsigned char, int);
	ssize_t         (*read)(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;