2005-04-17 02:20:36 +04:00
/*
* Generic / dev / nvram driver for architectures providing some
* " generic " hooks , that is :
*
2009-08-13 12:03:02 +04:00
* nvram_read_byte , nvram_write_byte , nvram_sync , nvram_get_size
2005-04-17 02:20:36 +04:00
*
* 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>
2010-06-02 16:28:52 +04:00
# include <linux/mutex.h>
2005-04-17 02:20:36 +04:00
# include <asm/uaccess.h>
# include <asm/nvram.h>
2006-03-28 16:15:54 +04:00
# ifdef CONFIG_PPC_PMAC
# include <asm/machdep.h>
# endif
2005-04-17 02:20:36 +04:00
# define NVRAM_SIZE 8192
2010-06-02 16:28:52 +04:00
static DEFINE_MUTEX ( nvram_mutex ) ;
2009-08-13 12:03:02 +04:00
static ssize_t nvram_len ;
2005-04-17 02:20:36 +04:00
static loff_t nvram_llseek ( struct file * file , loff_t offset , int origin )
{
switch ( origin ) {
2011-07-18 21:21:39 +04:00
case 0 :
break ;
2005-04-17 02:20:36 +04:00
case 1 :
offset + = file - > f_pos ;
break ;
case 2 :
2009-08-13 12:03:02 +04:00
offset + = nvram_len ;
2005-04-17 02:20:36 +04:00
break ;
2011-07-18 21:21:39 +04:00
default :
offset = - 1 ;
2005-04-17 02:20:36 +04:00
}
2009-10-09 23:20:30 +04:00
if ( offset < 0 )
2005-04-17 02:20:36 +04:00
return - EINVAL ;
2009-10-09 23:20:30 +04:00
2005-04-17 02:20:36 +04:00
file - > f_pos = offset ;
2009-10-09 23:20:30 +04:00
2005-04-17 02:20:36 +04:00
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 ;
2009-08-13 12:03:02 +04:00
if ( * ppos > = nvram_len )
2005-04-17 02:20:36 +04:00
return 0 ;
2009-08-13 12:03:02 +04:00
for ( i = * ppos ; count > 0 & & i < nvram_len ; + + i , + + p , - - count )
2005-04-17 02:20:36 +04:00
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 ;
2009-08-13 12:03:02 +04:00
if ( * ppos > = nvram_len )
2005-04-17 02:20:36 +04:00
return 0 ;
2009-08-13 12:03:02 +04:00
for ( i = * ppos ; count > 0 & & i < nvram_len ; + + i , + + p , - - count ) {
2005-04-17 02:20:36 +04:00
if ( __get_user ( c , p ) )
return - EFAULT ;
nvram_write_byte ( c , i ) ;
}
* ppos = i ;
return p - buf ;
}
2010-04-27 02:24:05 +04:00
static int nvram_ioctl ( struct file * file , unsigned int cmd , unsigned long arg )
2005-04-17 02:20:36 +04:00
{
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 ;
2006-03-28 16:15:54 +04:00
if ( ! machine_is ( powermac ) )
2005-04-17 02:20:36 +04:00
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 ;
}
2010-04-27 02:24:05 +04:00
static long nvram_unlocked_ioctl ( struct file * file , unsigned int cmd , unsigned long arg )
{
int ret ;
2010-06-02 16:28:52 +04:00
mutex_lock ( & nvram_mutex ) ;
2010-04-27 02:24:05 +04:00
ret = nvram_ioctl ( file , cmd , arg ) ;
2010-06-02 16:28:52 +04:00
mutex_unlock ( & nvram_mutex ) ;
2010-04-27 02:24:05 +04:00
return ret ;
}
2007-02-12 11:55:32 +03:00
const struct file_operations nvram_fops = {
2005-04-17 02:20:36 +04:00
. owner = THIS_MODULE ,
. llseek = nvram_llseek ,
. read = read_nvram ,
. write = write_nvram ,
2010-04-27 02:24:05 +04:00
. unlocked_ioctl = nvram_unlocked_ioctl ,
2005-04-17 02:20:36 +04:00
} ;
static struct miscdevice nvram_dev = {
NVRAM_MINOR ,
" nvram " ,
& nvram_fops
} ;
int __init nvram_init ( void )
{
2009-08-13 12:03:02 +04:00
int ret = 0 ;
2008-06-13 02:21:46 +04:00
printk ( KERN_INFO " Generic non-volatile memory driver v%s \n " ,
2005-04-17 02:20:36 +04:00
NVRAM_VERSION ) ;
2009-08-13 12:03:02 +04:00
ret = misc_register ( & nvram_dev ) ;
if ( ret ! = 0 )
goto out ;
nvram_len = nvram_get_size ( ) ;
if ( nvram_len < 0 )
nvram_len = NVRAM_SIZE ;
out :
return ret ;
2005-04-17 02:20:36 +04:00
}
void __exit nvram_cleanup ( void )
{
misc_deregister ( & nvram_dev ) ;
}
module_init ( nvram_init ) ;
module_exit ( nvram_cleanup ) ;
MODULE_LICENSE ( " GPL " ) ;