52 #define DPRINTK(fmt, args...) printk(KERN_DEBUG fmt, ## args)
54 #define DPRINTK(fmt, args...)
57 #include <linux/module.h>
59 #include <linux/kernel.h>
60 #include <linux/string.h>
61 #include <linux/capability.h>
62 #include <linux/ctype.h>
65 #include <linux/device.h>
66 #include <linux/errno.h>
71 #include <asm/uaccess.h>
74 #define PDCS_VERSION "0.30"
75 #define PDCS_PREFIX "PDC Stable Storage"
77 #define PDCS_ADDR_PPRI 0x00
78 #define PDCS_ADDR_OSID 0x40
79 #define PDCS_ADDR_OSD1 0x48
80 #define PDCS_ADDR_DIAG 0x58
81 #define PDCS_ADDR_FSIZ 0x5C
82 #define PDCS_ADDR_PCON 0x60
83 #define PDCS_ADDR_PALT 0x80
84 #define PDCS_ADDR_PKBD 0xA0
85 #define PDCS_ADDR_OSD2 0xE0
115 #define PDCSPATH_ENTRY(_addr, _name) \
116 struct pdcspath_entry pdcspath_entry_##_name = { \
119 .name = __stringify(_name), \
122 #define PDCS_ATTR(_name, _mode, _show, _store) \
123 struct kobj_attribute pdcs_attr_##_name = { \
124 .attr = {.name = __stringify(_name), .mode = _mode}, \
129 #define PATHS_ATTR(_name, _mode, _show, _store) \
130 struct pdcspath_attribute paths_attr_##_name = { \
131 .attr = {.name = __stringify(_name), .mode = _mode}, \
136 #define to_pdcspath_attribute(_attr) container_of(_attr, struct pdcspath_attribute, attr)
137 #define to_pdcspath_entry(obj) container_of(obj, struct pdcspath_entry, kobj)
161 DPRINTK(
"%s: fetch: 0x%p, 0x%p, addr: 0x%lx\n", __func__,
162 entry, devpath, entry->
addr);
175 DPRINTK(
"%s: device: 0x%p\n", __func__, entry->
dev);
211 DPRINTK(
"%s: store: 0x%p, 0x%p, addr: 0x%lx\n", __func__,
212 entry, devpath, entry->
addr);
217 "It is likely that the Stable Storage data has been corrupted.\n"
218 "Please check it carefully upon next reboot.\n", __func__);
225 DPRINTK(
"%s: device: 0x%p\n", __func__, entry->
dev);
253 for (i = 0; i < 6; i++) {
254 if (devpath->
bc[i] >= 128)
256 out +=
sprintf(out,
"%u/", (
unsigned char)devpath->
bc[i]);
258 out +=
sprintf(out,
"%u\n", (
unsigned char)devpath->
mod);
287 if (!entry || !buf || !count)
295 memset(&hwpath, 0xff,
sizeof(hwpath));
298 if (!(temp =
strrchr(in,
'/')))
303 DPRINTK(
"%s: mod: %d\n", __func__, hwpath.mod);
310 for (i=5; ((temp =
strrchr(in,
'/'))) && (temp-in > 0) && (
likely(i)); i--) {
313 DPRINTK(
"%s: bc[%d]: %d\n", __func__, i, hwpath.bc[i]);
318 DPRINTK(
"%s: bc[%d]: %d\n", __func__, i, hwpath.bc[i]);
323 "hardware path: %s\n", __func__, entry->
name, buf);
333 pdcspath_store(entry);
373 for (i = 0; i < 6 && devpath->
layers[
i]; i++)
394 pdcspath_layer_write(
struct pdcspath_entry *entry,
const char *buf,
size_t count)
398 char in[count+1], *
temp;
400 if (!entry || !buf || !count)
408 memset(&layers, 0,
sizeof(layers));
414 DPRINTK(
"%s: layer[0]: %d\n", __func__, layers[0]);
417 for (i=1; ((temp =
strchr(temp,
'.'))) && (
likely(i<6)); i++) {
421 DPRINTK(
"%s: layer[%d]: %d\n", __func__, i, layers[i]);
432 pdcspath_store(entry);
455 ret = pdcs_attr->
show(entry, buf);
469 const char *buf,
size_t count)
478 if (pdcs_attr->
store)
479 ret = pdcs_attr->
store(entry, buf, count);
484 static const struct sysfs_ops pdcspath_attr_ops = {
485 .show = pdcspath_attr_show,
486 .store = pdcspath_attr_store,
490 static PATHS_ATTR(hwpath, 0644, pdcspath_hwpath_read, pdcspath_hwpath_write);
491 static PATHS_ATTR(layer, 0644, pdcspath_layer_read, pdcspath_layer_write);
493 static struct attribute *paths_subsys_attrs[] = {
494 &paths_attr_hwpath.attr,
495 &paths_attr_layer.attr,
500 static struct kobj_type ktype_pdcspath = {
501 .sysfs_ops = &pdcspath_attr_ops,
502 .default_attrs = paths_subsys_attrs,
513 &pdcspath_entry_primary,
514 &pdcspath_entry_alternative,
515 &pdcspath_entry_console,
516 &pdcspath_entry_keyboard,
538 out +=
sprintf(out,
"%ld\n", pdcs_size);
559 pathentry = &pdcspath_entry_primary;
576 return pdcs_auto_read(kobj, attr, buf,
PF_AUTOBOOT);
605 pathentry = &pdcspath_entry_primary;
628 out +=
sprintf(out,
"%s dependent data (0x%.4x)\n",
629 os_id_to_string(pdcs_osid), pdcs_osid);
652 out +=
sprintf(out,
"0x%.8x\n", result[0]);
653 out +=
sprintf(out,
"0x%.8x\n", result[1]);
654 out +=
sprintf(out,
"0x%.8x\n", result[2]);
655 out +=
sprintf(out,
"0x%.8x\n", result[3]);
679 out +=
sprintf(out,
"0x%.4x\n", (result >> 16));
703 if ((result & 0x0F) < 0x0E)
704 out +=
sprintf(out,
"%d kB", (1<<(result & 0x0F))*256);
729 size = pdcs_size - 224;
734 for (i=0; i<
size; i+=4) {
736 sizeof(result)) !=
PDC_OK))
738 out +=
sprintf(out,
"0x%.8x\n", result);
756 size_t count,
int knob)
760 char in[count+1], *
temp;
774 pathentry = &pdcspath_entry_primary;
778 flags = pathentry->
devpath.flags;
781 DPRINTK(
"%s: flags before: 0x%X\n", __func__, flags);
786 if ((c != 0) && (c != 1))
793 DPRINTK(
"%s: flags after: 0x%X\n", __func__, flags);
802 pdcspath_store(pathentry);
807 (flags & knob) ?
"On" :
"Off");
827 const char *buf,
size_t count)
829 return pdcs_auto_write(kobj, attr, buf, count,
PF_AUTOBOOT);
843 const char *buf,
size_t count)
845 return pdcs_auto_write(kobj, attr, buf, count,
PF_AUTOSEARCH);
859 const char *buf,
size_t count)
896 const char *buf,
size_t count)
914 size = pdcs_size - 224;
921 for (i=0; i<
count; i+=4) {
923 memcpy(in, buf+i, (count-i < 4) ? count-i : 4);
934 static PDCS_ATTR(autoboot, 0644, pdcs_autoboot_read, pdcs_autoboot_write);
935 static PDCS_ATTR(autosearch, 0644, pdcs_autosearch_read, pdcs_autosearch_write);
938 static PDCS_ATTR(osdep1, 0600, pdcs_osdep1_read, pdcs_osdep1_write);
939 static PDCS_ATTR(diagnostic, 0400, pdcs_diagnostic_read,
NULL);
941 static PDCS_ATTR(osdep2, 0600, pdcs_osdep2_read, pdcs_osdep2_write);
943 static struct attribute *pdcs_subsys_attrs[] = {
944 &pdcs_attr_size.attr,
945 &pdcs_attr_autoboot.attr,
946 &pdcs_attr_autosearch.attr,
947 &pdcs_attr_timer.attr,
948 &pdcs_attr_osid.attr,
949 &pdcs_attr_osdep1.attr,
950 &pdcs_attr_diagnostic.attr,
951 &pdcs_attr_fastsize.attr,
952 &pdcs_attr_osdep2.attr,
957 .attrs = pdcs_subsys_attrs,
960 static struct kobject *stable_kobj;
961 static struct kset *paths_kset;
973 pdcs_register_pathentries(
void)
980 for (i = 0; (entry = pdcspath_entries[
i]); i++)
983 for (i = 0; (entry = pdcspath_entries[
i]); i++) {
985 err = pdcspath_fetch(entry);
991 entry->
kobj.kset = paths_kset;
1018 pdcs_unregister_pathentries(
void)
1023 for (i = 0; (entry = pdcspath_entries[
i]); i++) {
1025 if (entry->
ready >= 2)
1036 pdc_stable_init(
void)
1056 pdcs_osid = (
u16)(result >> 16);
1076 if ((rc = pdcs_register_pathentries()))
1082 pdcs_unregister_pathentries();
1094 pdc_stable_exit(
void)
1096 pdcs_unregister_pathentries();