2b8693c061
Many struct file_operations in the kernel can be "const". Marking them const moves these to the .rodata section, which avoids false sharing with potential dirty data. In addition it'll catch accidental writes at compile time to these shared resources. Signed-off-by: Arjan van de Ven <arjan@linux.intel.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
148 lines
3 KiB
C
148 lines
3 KiB
C
/*
|
|
* Generic /dev/nvram driver for architectures providing some
|
|
* "generic" hooks, that is :
|
|
*
|
|
* nvram_read_byte, nvram_write_byte, nvram_sync
|
|
*
|
|
* Note that an additional hook is supported for PowerMac only
|
|
* for getting the nvram "partition" informations
|
|
*
|
|
*/
|
|
|
|
#define NVRAM_VERSION "1.1"
|
|
|
|
#include <linux/module.h>
|
|
|
|
#include <linux/types.h>
|
|
#include <linux/errno.h>
|
|
#include <linux/fs.h>
|
|
#include <linux/miscdevice.h>
|
|
#include <linux/fcntl.h>
|
|
#include <linux/init.h>
|
|
#include <linux/smp_lock.h>
|
|
#include <asm/uaccess.h>
|
|
#include <asm/nvram.h>
|
|
#ifdef CONFIG_PPC_PMAC
|
|
#include <asm/machdep.h>
|
|
#endif
|
|
|
|
#define NVRAM_SIZE 8192
|
|
|
|
static loff_t nvram_llseek(struct file *file, loff_t offset, int origin)
|
|
{
|
|
lock_kernel();
|
|
switch (origin) {
|
|
case 1:
|
|
offset += file->f_pos;
|
|
break;
|
|
case 2:
|
|
offset += NVRAM_SIZE;
|
|
break;
|
|
}
|
|
if (offset < 0) {
|
|
unlock_kernel();
|
|
return -EINVAL;
|
|
}
|
|
file->f_pos = offset;
|
|
unlock_kernel();
|
|
return file->f_pos;
|
|
}
|
|
|
|
static ssize_t read_nvram(struct file *file, char __user *buf,
|
|
size_t count, loff_t *ppos)
|
|
{
|
|
unsigned int i;
|
|
char __user *p = buf;
|
|
|
|
if (!access_ok(VERIFY_WRITE, buf, count))
|
|
return -EFAULT;
|
|
if (*ppos >= NVRAM_SIZE)
|
|
return 0;
|
|
for (i = *ppos; count > 0 && i < NVRAM_SIZE; ++i, ++p, --count)
|
|
if (__put_user(nvram_read_byte(i), p))
|
|
return -EFAULT;
|
|
*ppos = i;
|
|
return p - buf;
|
|
}
|
|
|
|
static ssize_t write_nvram(struct file *file, const char __user *buf,
|
|
size_t count, loff_t *ppos)
|
|
{
|
|
unsigned int i;
|
|
const char __user *p = buf;
|
|
char c;
|
|
|
|
if (!access_ok(VERIFY_READ, buf, count))
|
|
return -EFAULT;
|
|
if (*ppos >= NVRAM_SIZE)
|
|
return 0;
|
|
for (i = *ppos; count > 0 && i < NVRAM_SIZE; ++i, ++p, --count) {
|
|
if (__get_user(c, p))
|
|
return -EFAULT;
|
|
nvram_write_byte(c, i);
|
|
}
|
|
*ppos = i;
|
|
return p - buf;
|
|
}
|
|
|
|
static int nvram_ioctl(struct inode *inode, struct file *file,
|
|
unsigned int cmd, unsigned long arg)
|
|
{
|
|
switch(cmd) {
|
|
#ifdef CONFIG_PPC_PMAC
|
|
case OBSOLETE_PMAC_NVRAM_GET_OFFSET:
|
|
printk(KERN_WARNING "nvram: Using obsolete PMAC_NVRAM_GET_OFFSET ioctl\n");
|
|
case IOC_NVRAM_GET_OFFSET: {
|
|
int part, offset;
|
|
|
|
if (!machine_is(powermac))
|
|
return -EINVAL;
|
|
if (copy_from_user(&part, (void __user*)arg, sizeof(part)) != 0)
|
|
return -EFAULT;
|
|
if (part < pmac_nvram_OF || part > pmac_nvram_NR)
|
|
return -EINVAL;
|
|
offset = pmac_get_partition(part);
|
|
if (copy_to_user((void __user*)arg, &offset, sizeof(offset)) != 0)
|
|
return -EFAULT;
|
|
break;
|
|
}
|
|
#endif /* CONFIG_PPC_PMAC */
|
|
case IOC_NVRAM_SYNC:
|
|
nvram_sync();
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
const struct file_operations nvram_fops = {
|
|
.owner = THIS_MODULE,
|
|
.llseek = nvram_llseek,
|
|
.read = read_nvram,
|
|
.write = write_nvram,
|
|
.ioctl = nvram_ioctl,
|
|
};
|
|
|
|
static struct miscdevice nvram_dev = {
|
|
NVRAM_MINOR,
|
|
"nvram",
|
|
&nvram_fops
|
|
};
|
|
|
|
int __init nvram_init(void)
|
|
{
|
|
printk(KERN_INFO "Macintosh non-volatile memory driver v%s\n",
|
|
NVRAM_VERSION);
|
|
return misc_register(&nvram_dev);
|
|
}
|
|
|
|
void __exit nvram_cleanup(void)
|
|
{
|
|
misc_deregister( &nvram_dev );
|
|
}
|
|
|
|
module_init(nvram_init);
|
|
module_exit(nvram_cleanup);
|
|
MODULE_LICENSE("GPL");
|