[kernel] bug#25: [PATCH] Some ideas
None
X-PA-RISC Linux-PR-Message: report 25
X-PA-RISC Linux-PR-Package: kernel
X-Loop: daniel_frazier@hp.com
Received: via spool by 25-bugs@bugs.parisc-linux.org id=B25.98364333531141
(code B ref 25); Sat, 03 Mar 2001 18:18:01 GMT
Date: Sat, 3 Mar 2001 11:14:05 -0700
Message-ID: <20010303111405.V27829@tausq.org>
From: "Randolph Chung" <randolph@tausq.org>
To: 25@bugs.parisc-linux.org
Mime-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
User-Agent: Mutt/1.2.5i
X-PGP: for PGP key, see http://www.tausq.org/pgp.txt
X-GPG: for GPG key, see http://www.tausq.org/gpg.txt
Been experimenting a bit with various methods...
the first is a /proc/pdc interface:
frodo:~# ls -l /proc/pdc/
total 0
-r-------- 1 root root 0 Jan 31 11:10 model_info
-r-------- 1 root root 0 Jan 31 11:10 model_name
-rw------- 1 root root 0 Jan 31 11:10 timeofday
frodo:~# cat /proc/pdc/model_info
hversion: 0x6010
sversion: 0x481
hw_id: 0x0
boot_id: 0x0
sw_id: 0x77F17B38
sw_cap: 0x0
arch_rev: 0x4
pot_key: 0x72
curr_key: 0x72
this is fairly straightforward, but probably only works well for very
simple PDC interfaces.
The second is a /dev based interface. For example:
frodo:~# ls -l /dev/stable /dev/nvram
crw-r--r-- 1 root root 10, 160 Mar 3 2001 /dev/nvram
crw-r--r-- 1 root root 10, 162 Mar 1 2001 /dev/stable
On startup, I get:
Initializing /dev/stable and /dev/nvram support
/dev/nvram not available
/dev/stable: 256 bytes available
and i can do, f.i., cat /dev/stable > /tmp/foo
the devices support read/write/lseek and ioctls for init/verify/getsize
sample code for each is attached. still working on the /dev interface.
i get data back, but it doesn't look quite right... comments,
suggestions and critiques are most welcome.
randolph
--
@..@ http://www.TauSq.org/
(----)
( >__< )
^^ ~~ ^^
============ arch/parisc/kernel/proc_pdc.c ==============
/*
* $Id$
* /proc/pdc interface
*
* Copyright 2001 Randolph Chung <tausq@debian.org>
* GPLv2
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/proc_fs.h>
#include <asm/pdc.h>
#include <asm/page.h>
#include <asm/uaccess.h>
#define PROCPDCDEBUG
#ifdef PROCPDCDEBUG
#define dbg(fmt...) printk(fmt)
#else
#define dbg(fmt...) /* nothing */
#endif
/*
* Root /proc/pdc entry
*/
#define PDCROOT "pdc"
static struct proc_dir_entry *proc_pdc_root = NULL;
static long my_atol(const char *s)
{
long out = 0;
const char *p = s;
for (; *p != 0; p++)
{
if (*p < '0' || *p > '9') break;
out = out * 10 + (*p - '0');
}
return out;
}
/*
* static int procpdc_write(struct file *file, const char *buf,
* unsigned long size, void *data)
*
* static int procpdc_read(char *page, char **start, off_t off, int size,
* int *eof, void *data)
*/
static int ppdc_modelinfo(char *page, char **start, off_t off, int size,
int *eof, void *data)
{
struct pdc_model model;
*eof = 1;
if (pdc_model_info(&model) == 0)
return sprintf(page,
"hversion: 0x%lX\n"
"sversion: 0x%lX\n"
"hw_id: 0x%lX\n"
"boot_id: 0x%lX\n"
"sw_id: 0x%lX\n"
"sw_cap: 0x%lX\n"
"arch_rev: 0x%lX\n"
"pot_key: 0x%lX\n"
"curr_key: 0x%lX\n",
model.hversion, model.sversion, model.hw_id,
model.boot_id, model.sw_id, model.sw_cap,
model.arch_rev, model.pot_key, model.curr_key);
else
return -EINVAL;
}
static int ppdc_modelname(char *page, char **start, off_t off, int size,
int *eof, void *data)
{
char modelname[81]; /* PDC spec says name is <= 80 characters */
*eof = 1;
if (pdc_model_sysmodel(modelname) == 0)
return sprintf(page, "%s\n", modelname);
else
return -EINVAL;
}
static int ppdc_tod_set(struct file *file, const char *buf, unsigned long size,
void *data)
{
unsigned long sec = 0, usec = 0;
char todbuf[128] = {0};
char *p;
if (size >= sizeof(todbuf)) return -EINVAL;
copy_from_user(todbuf, buf, size);
p = todbuf;
while (*p != 0 && *p != ' ' && *p != '\t') p++;
if (*p != 0)
{
*p++ = 0;
while (*p != 0 && (*p == ' ' || *p == '\t')) p++;
}
sec = my_atol(todbuf);
usec = my_atol(p);
if (sec != 0)
{
pdc_tod_set(sec, usec);
return size;
}
else
{
return -EINVAL;
}
}
static int ppdc_tod_get(char *page, char **start, off_t off, int size,
int *eof, void *data)
{
struct pdc_tod tod;
*eof = 1;
if (pdc_tod_read(&tod) == 0)
return sprintf(page, "%ld %ld\n", tod.tod_sec, tod.tod_usec);
else
return -EINVAL;
}
/* *********************************************************************** */
static struct pdc_proc_handler_list_t {
char *name; /* proc entry to create */
/* read handler */
int (*reader)(char *, char **, off_t, int, int *, void *);
/* write handler */
int (*writer)(struct file *, const char *, unsigned long, void *);
void *data;
} pdc_proc_handlers[] = {
{ "model_info", ppdc_modelinfo, 0, 0 },
{ "model_name", ppdc_modelname, 0, 0 },
{ "timeofday", ppdc_tod_get, ppdc_tod_set, 0 }
};
int __init procpdc_init(void)
{
long i;
struct proc_dir_entry *ent;
dbg("Initializing /proc/pdc support: ");
proc_pdc_root = proc_mkdir(PDCROOT, 0);
for (i = 0; i < sizeof(pdc_proc_handlers)/sizeof(pdc_proc_handlers[0]); i++)
{
dbg("%s ", pdc_proc_handlers[i].name);
ent = create_proc_entry(pdc_proc_handlers[i].name,
(pdc_proc_handlers[i].writer ? S_IFREG|S_IRUSR|S_IWUSR :
S_IFREG|S_IRUSR), proc_pdc_root);
if (ent == NULL)
{
dbg("create_proc_entry() returned NULL\n");
return -1;
}
ent->nlink = 1;
ent->data = (void *)&pdc_proc_handlers[i];
ent->read_proc = pdc_proc_handlers[i].reader;
ent->write_proc = pdc_proc_handlers[i].writer;
}
printk("\n");
return 0;
}
void __exit procpdc_exit(void)
{
int i;
for (i = 0; i < sizeof(pdc_proc_handlers)/sizeof(pdc_proc_handlers[0]); i++)
{
remove_proc_entry(pdc_proc_handlers[i].name, 0);
}
remove_proc_entry(PDCROOT, 0);
return 0;
}
module_init(procpdc_init);
module_exit(procpdc_exit);
================= arch/parisc/kernel/stable-nvram.c =======================
/*
* $Id$
* /dev/nvram - access to nonvolatile memory via PDC_NVOLATILE
* /dev/stable - access to stable storage via PDC_STABLE
*
* (c) 2001 Randolph Chung <tausq@debian.org>
* GPLv2
*/
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/malloc.h>
#include <linux/fcntl.h>
#include <linux/init.h>
#include <asm/uaccess.h>
#include <asm/pdc.h>
#define DEBUG 1
#ifdef DEBUG
#define dbg(fmt...) printk(fmt)
#else
#define dbg(fmt...)
#endif
static struct file_operations dev_sn_fops;
static struct device_t {
const char *name;
int opened;
unsigned long size;
int (*init)(void);
int (*verify)(void);
int (*getsize)(unsigned long *size);
int (*read)(void *, void *, unsigned long count);
int (*write)(void *, void *, unsigned long count);
struct miscdevice miscdev;
} devices[] = {
{ "nvram", 0, 0, pdc_nvram_init, pdc_nvram_verify,
pdc_nvram_size, pdc_nvram_read, pdc_nvram_write,
{ PARISC_NVRAM_MINOR, "nvram", &dev_sn_fops } },
{ "stable", 0, 0, pdc_stable_init, pdc_stable_verify,
pdc_stable_size, pdc_stable_read, pdc_stable_write,
{ PARISC_STABLE_MINOR, "stable", &dev_sn_fops } },
};
#define NVRAM_DEVICE 0
#define STABLE_DEVICE 1
static inline int getdevicenum(int minor)
{
switch (minor)
{
case PARISC_NVRAM_MINOR: return NVRAM_DEVICE;
case PARISC_STABLE_MINOR: return STABLE_DEVICE;
default:
printk(KERN_CRIT "%s: requesting unknown device!\n", __FILE__);
return -1;
}
}
static int dev_sn_open(struct inode *inode, struct file *file)
{
int n = getdevicenum(MINOR(inode->i_rdev));
dbg("Opening /dev/%s\n", devices[n].name);
if (devices[n].opened) return -EBUSY;
devices[n].opened = 1;
return 0;
}
static int dev_sn_release(struct inode *inode, struct file *file)
{
int n = getdevicenum(MINOR(inode->i_rdev));
dbg("Opening /dev/%s\n", devices[n].name);
devices[n].opened = 0;
return 0;
}
static ssize_t dev_sn_read(struct file *file, char *buf, size_t count,
loff_t *ppos)
{
char *kbuf;
unsigned long pos = (long)*ppos;
int n = getdevicenum(MINOR(file->f_dentry->d_inode->i_rdev));
dbg("dev_sn_read: pos = %ld, count = %u\n", pos, (unsigned int)count);
if (pos + count > devices[n].size)
count = devices[n].size - pos;
if (pos > devices[n].size || count == 0)
return 0;
if ((kbuf = kmalloc(count, GFP_KERNEL)) == 0)
return -EFAULT;
dbg("allocated %u byte buffer\n", (unsigned int)count);
if (devices[n].read((void *)pos, kbuf, count) < 0 ||
copy_to_user(buf, kbuf, count))
return -EFAULT;
kfree(kbuf);
*ppos += count;
return count;
}
static ssize_t dev_sn_write(struct file *file, const char *buf,
size_t count, loff_t *ppos)
{
char *kbuf;
unsigned long pos = (long)*ppos;
int n = getdevicenum(MINOR(file->f_dentry->d_inode->i_rdev));
dbg("dev_sn_write: pos = %ld, count = %u\n", pos, (unsigned int)count);
if (pos + count > devices[n].size)
count = devices[n].size - pos;
if (pos > devices[n].size || count == 0)
return 0;
if ((kbuf = kmalloc(count, GFP_KERNEL)) == 0)
return -EFAULT;
dbg("allocated %u byte buffer\n", (unsigned int)count);
if (copy_from_user(kbuf, buf, count) ||
devices[n].write((void *)pos, kbuf, count) < 0)
return -EFAULT;
kfree(kbuf);
*ppos += count;
return count;
}
static int dev_sn_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
int n = getdevicenum(MINOR(inode->i_rdev));
int r = 1;
dbg("dev_sn_ioctl: cmd = %d\n", cmd);
if (cmd == NVRAM_INIT || cmd == STABLE_INIT)
r = devices[n].init();
else if (cmd == NVRAM_VERIFY || cmd == STABLE_VERIFY)
r = devices[n].verify();
else if (cmd == NVRAM_SIZE || cmd == STABLE_SIZE)
r = devices[n].getsize((unsigned long *)arg);
return (r == 0) ? 0 : -EINVAL;
}
static long long dev_sn_llseek(struct file *file, loff_t offset, int origin)
{
int n = getdevicenum(MINOR(file->f_dentry->d_inode->i_rdev));
dbg("dev_sn_llseek\n");
switch (origin)
{
case 1:
offset += file->f_pos;
break;
case 2:
offset += devices[n].size;
break;
}
if (offset < 0 || offset >= devices[n].size) return -EINVAL;
file->f_pos = offset;
return file->f_pos;
}
static struct file_operations dev_sn_fops = {
open: dev_sn_open,
release: dev_sn_release,
read: dev_sn_read,
write: dev_sn_write,
ioctl: dev_sn_ioctl,
llseek: dev_sn_llseek,
};
int __init dev_sn_init(void)
{
int i;
printk("Initializing /dev/stable and /dev/nvram support\n");
for (i = 0; i < sizeof(devices)/sizeof(devices[0]); i++)
{
if (devices[i].getsize(&devices[i].size) < 0 ||
devices[i].size == 0)
{
printk("/dev/%s not available\n",
devices[i].name);
}
else
{
printk("/dev/%s: %lu bytes available\n",
devices[i].name, devices[i].size);
misc_register(&devices[i].miscdev);
}
}
return 0;
}
void __exit dev_sn_exit(void)
{
int i;
for (i = 0; i < sizeof(devices)/sizeof(devices[0]); i++)
misc_register(&devices[i].miscdev);
}
module_init(dev_sn_init);
module_exit(dev_sn_exit);