Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 31143
b: refs/heads/master
c: 3f9edb5
h: refs/heads/master
i:
  31141: 660a2a3
  31139: c5dd329
  31135: 26d7fb0
v: v3
  • Loading branch information
Thibaut Varene authored and Kyle McMartin committed Jun 27, 2006
1 parent 902a612 commit ed09fe2
Show file tree
Hide file tree
Showing 3 changed files with 211 additions and 15 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 9b0703fed7ca1af95d4454f45e2f25733f0afa76
refs/heads/master: 3f9edb53f74b4e18f92783da7b6f5ad1d36e05b2
5 changes: 5 additions & 0 deletions trunk/arch/parisc/kernel/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,8 @@ extern void eisa_init(void);

static int __init parisc_init(void)
{
u32 osid = (0x0006 << 16);

parisc_proc_mkdir();
parisc_init_resources();
do_device_inventory(); /* probe for hardware */
Expand All @@ -311,6 +313,9 @@ static int __init parisc_init(void)

/* set up a new led state on systems shipped LED State panel */
pdc_chassis_send_status(PDC_CHASSIS_DIRECT_BSTART);

/* tell PDC we're Linux. Nevermind failure. */
pdc_stable_write(0x40, &osid, sizeof(osid));

processor_init();
printk(KERN_INFO "CPU(s): %d x %s at %d.%06d MHz\n",
Expand Down
219 changes: 205 additions & 14 deletions trunk/drivers/parisc/pdc_stable.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,15 @@
* following code can deal with just 96 bytes of Stable Storage, and all
* sizes between 96 and 192 bytes (provided they are multiple of struct
* device_path size, eg: 128, 160 and 192) to provide full information.
* The code makes no use of data above 192 bytes. One last word: there's one
* path we can always count on: the primary path.
* One last word: there's one path we can always count on: the primary path.
* Anything above 224 bytes is used for 'osdep2' OS-dependent storage area.
*
* The first OS-dependent area should always be available. Obviously, this is
* not true for the other one. Also bear in mind that reading/writing from/to
* osdep2 is much more expensive than from/to osdep1.
* NOTE: We do not handle the 2 bytes OS-dep area at 0x5D, nor the first
* 2 bytes of storage available right after OSID. That's a total of 4 bytes
* sacrificed: -ETOOLAZY :P
*
* The current policy wrt file permissions is:
* - write: root only
Expand Down Expand Up @@ -64,15 +71,18 @@
#include <asm/uaccess.h>
#include <asm/hardware.h>

#define PDCS_VERSION "0.22"
#define PDCS_VERSION "0.30"
#define PDCS_PREFIX "PDC Stable Storage"

#define PDCS_ADDR_PPRI 0x00
#define PDCS_ADDR_OSID 0x40
#define PDCS_ADDR_OSD1 0x48
#define PDCS_ADDR_DIAG 0x58
#define PDCS_ADDR_FSIZ 0x5C
#define PDCS_ADDR_PCON 0x60
#define PDCS_ADDR_PALT 0x80
#define PDCS_ADDR_PKBD 0xA0
#define PDCS_ADDR_OSD2 0xE0

MODULE_AUTHOR("Thibaut VARENE <varenet@parisc-linux.org>");
MODULE_DESCRIPTION("sysfs interface to HP PDC Stable Storage data");
Expand All @@ -82,6 +92,9 @@ MODULE_VERSION(PDCS_VERSION);
/* holds Stable Storage size. Initialized once and for all, no lock needed */
static unsigned long pdcs_size __read_mostly;

/* holds OS ID. Initialized once and for all, hopefully to 0x0006 */
static u16 pdcs_osid __read_mostly;

/* This struct defines what we need to deal with a parisc pdc path entry */
struct pdcspath_entry {
rwlock_t rw_lock; /* to protect path entry access */
Expand Down Expand Up @@ -609,27 +622,74 @@ static ssize_t
pdcs_osid_read(struct subsystem *entry, char *buf)
{
char *out = buf;
__u32 result;
char *tmpstr = NULL;

if (!entry || !buf)
return -EINVAL;

/* get OSID */
if (pdc_stable_read(PDCS_ADDR_OSID, &result, sizeof(result)) != PDC_OK)
return -EIO;

/* the actual result is 16 bits away */
switch (result >> 16) {
switch (pdcs_osid) {
case 0x0000: tmpstr = "No OS-dependent data"; break;
case 0x0001: tmpstr = "HP-UX dependent data"; break;
case 0x0002: tmpstr = "MPE-iX dependent data"; break;
case 0x0003: tmpstr = "OSF dependent data"; break;
case 0x0004: tmpstr = "HP-RT dependent data"; break;
case 0x0005: tmpstr = "Novell Netware dependent data"; break;
case 0x0006: tmpstr = "Linux dependent data"; break;
default: tmpstr = "Unknown"; break;
}
out += sprintf(out, "%s (0x%.4x)\n", tmpstr, (result >> 16));
out += sprintf(out, "%s (0x%.4x)\n", tmpstr, pdcs_osid);

return out - buf;
}

/**
* pdcs_osdep1_read - Stable Storage OS-Dependent data area 1 output.
* @entry: An allocated and populated subsytem struct. We don't use it tho.
* @buf: The output buffer to write to.
*
* This can hold 16 bytes of OS-Dependent data.
*/
static ssize_t
pdcs_osdep1_read(struct subsystem *entry, char *buf)
{
char *out = buf;
u32 result[4];

if (!entry || !buf)
return -EINVAL;

if (pdc_stable_read(PDCS_ADDR_OSD1, &result, sizeof(result)) != PDC_OK)
return -EIO;

out += sprintf(out, "0x%.8x\n", result[0]);
out += sprintf(out, "0x%.8x\n", result[1]);
out += sprintf(out, "0x%.8x\n", result[2]);
out += sprintf(out, "0x%.8x\n", result[3]);

return out - buf;
}

/**
* pdcs_diagnostic_read - Stable Storage Diagnostic register output.
* @entry: An allocated and populated subsytem struct. We don't use it tho.
* @buf: The output buffer to write to.
*
* I have NFC how to interpret the content of that register ;-).
*/
static ssize_t
pdcs_diagnostic_read(struct subsystem *entry, char *buf)
{
char *out = buf;
u32 result;

if (!entry || !buf)
return -EINVAL;

/* get diagnostic */
if (pdc_stable_read(PDCS_ADDR_DIAG, &result, sizeof(result)) != PDC_OK)
return -EIO;

out += sprintf(out, "0x%.4x\n", (result >> 16));

return out - buf;
}
Expand All @@ -645,7 +705,7 @@ static ssize_t
pdcs_fastsize_read(struct subsystem *entry, char *buf)
{
char *out = buf;
__u32 result;
u32 result;

if (!entry || !buf)
return -EINVAL;
Expand All @@ -663,6 +723,39 @@ pdcs_fastsize_read(struct subsystem *entry, char *buf)
return out - buf;
}

/**
* pdcs_osdep2_read - Stable Storage OS-Dependent data area 2 output.
* @entry: An allocated and populated subsytem struct. We don't use it tho.
* @buf: The output buffer to write to.
*
* This can hold pdcs_size - 224 bytes of OS-Dependent data, when available.
*/
static ssize_t
pdcs_osdep2_read(struct subsystem *entry, char *buf)
{
char *out = buf;
unsigned long size;
unsigned short i;
u32 result;

if (unlikely(pdcs_size <= 224))
return -ENODATA;

size = pdcs_size - 224;

if (!entry || !buf)
return -EINVAL;

for (i=0; i<size; i+=4) {
if (unlikely(pdc_stable_read(PDCS_ADDR_OSD2 + i, &result,
sizeof(result)) != PDC_OK))
return -EIO;
out += sprintf(out, "0x%.8x\n", result);
}

return out - buf;
}

/**
* pdcs_auto_write - This function handles autoboot/search flag modifying.
* @entry: An allocated and populated subsytem struct. We don't use it tho.
Expand Down Expand Up @@ -770,21 +863,111 @@ pdcs_autosearch_write(struct subsystem *entry, const char *buf, size_t count)
return pdcs_auto_write(entry, buf, count, PF_AUTOSEARCH);
}

/**
* pdcs_osdep1_write - Stable Storage OS-Dependent data area 1 input.
* @entry: An allocated and populated subsytem struct. We don't use it tho.
* @buf: The input buffer to read from.
* @count: The number of bytes to be read.
*
* This can store 16 bytes of OS-Dependent data. We use a byte-by-byte
* write approach. It's up to userspace to deal with it when constructing
* its input buffer.
*/
static ssize_t
pdcs_osdep1_write(struct subsystem *entry, const char *buf, size_t count)
{
u8 in[16];

if (!capable(CAP_SYS_ADMIN))
return -EACCES;

if (!entry || !buf || !count)
return -EINVAL;

if (unlikely(pdcs_osid != 0x0006))
return -EPERM;

if (count > 16)
return -EMSGSIZE;

/* We'll use a local copy of buf */
memset(in, 0, 16);
memcpy(in, buf, count);

if (pdc_stable_write(PDCS_ADDR_OSD1, &in, sizeof(in)) != PDC_OK)
return -EIO;

return count;
}

/**
* pdcs_osdep2_write - Stable Storage OS-Dependent data area 2 input.
* @entry: An allocated and populated subsytem struct. We don't use it tho.
* @buf: The input buffer to read from.
* @count: The number of bytes to be read.
*
* This can store pdcs_size - 224 bytes of OS-Dependent data. We use a
* byte-by-byte write approach. It's up to userspace to deal with it when
* constructing its input buffer.
*/
static ssize_t
pdcs_osdep2_write(struct subsystem *entry, const char *buf, size_t count)
{
unsigned long size;
unsigned short i;
u8 in[4];

if (!capable(CAP_SYS_ADMIN))
return -EACCES;

if (!entry || !buf || !count)
return -EINVAL;

if (unlikely(pdcs_size <= 224))
return -ENOSYS;

if (unlikely(pdcs_osid != 0x0006))
return -EPERM;

size = pdcs_size - 224;

if (count > size)
return -EMSGSIZE;

/* We'll use a local copy of buf */

for (i=0; i<count; i+=4) {
memset(in, 0, 4);
memcpy(in, buf+i, (count-i < 4) ? count-i : 4);
if (unlikely(pdc_stable_write(PDCS_ADDR_OSD2 + i, &in,
sizeof(in)) != PDC_OK))
return -EIO;
}

return count;
}

/* The remaining attributes. */
static PDCS_ATTR(size, 0444, pdcs_size_read, NULL);
static PDCS_ATTR(autoboot, 0644, pdcs_autoboot_read, pdcs_autoboot_write);
static PDCS_ATTR(autosearch, 0644, pdcs_autosearch_read, pdcs_autosearch_write);
static PDCS_ATTR(timer, 0444, pdcs_timer_read, NULL);
static PDCS_ATTR(osid, 0400, pdcs_osid_read, NULL);
static PDCS_ATTR(osid, 0444, pdcs_osid_read, NULL);
static PDCS_ATTR(osdep1, 0600, pdcs_osdep1_read, pdcs_osdep1_write);
static PDCS_ATTR(diagnostic, 0400, pdcs_diagnostic_read, NULL);
static PDCS_ATTR(fastsize, 0400, pdcs_fastsize_read, NULL);
static PDCS_ATTR(osdep2, 0600, pdcs_osdep2_read, pdcs_osdep2_write);

static struct subsys_attribute *pdcs_subsys_attrs[] = {
&pdcs_attr_size,
&pdcs_attr_autoboot,
&pdcs_attr_autosearch,
&pdcs_attr_timer,
&pdcs_attr_osid,
&pdcs_attr_osdep1,
&pdcs_attr_diagnostic,
&pdcs_attr_fastsize,
&pdcs_attr_osdep2,
NULL,
};

Expand Down Expand Up @@ -865,6 +1048,7 @@ pdc_stable_init(void)
{
struct subsys_attribute *attr;
int i, rc = 0, error = 0;
u32 result;

/* find the size of the stable storage */
if (pdc_stable_get_size(&pdcs_size) != PDC_OK)
Expand All @@ -876,6 +1060,13 @@ pdc_stable_init(void)

printk(KERN_INFO PDCS_PREFIX " facility v%s\n", PDCS_VERSION);

/* get OSID */
if (pdc_stable_read(PDCS_ADDR_OSID, &result, sizeof(result)) != PDC_OK)
return -EIO;

/* the actual result is 16 bits away */
pdcs_osid = (u16)(result >> 16);

/* For now we'll register the stable subsys within this driver */
if ((rc = firmware_register(&stable_subsys)))
goto fail_firmreg;
Expand All @@ -887,7 +1078,7 @@ pdc_stable_init(void)

/* register the paths subsys as a subsystem of stable subsys */
kset_set_kset_s(&paths_subsys, stable_subsys);
if ((rc= subsystem_register(&paths_subsys)))
if ((rc = subsystem_register(&paths_subsys)))
goto fail_subsysreg;

/* now we create all "files" for the paths subsys */
Expand Down

0 comments on commit ed09fe2

Please sign in to comment.