Skip to contentSkip to conversation

filling in ACPI files in sysfs

RFC Paul Ionescu 3 participants 10 messages Apr 7, 2004 – Apr 10, 2004 10 messages not in the archive ACPI

lore
Share & tools
lore
#0 lore raw

Hi Alex,

I patch-ed a 2.6.5 kernel, and boot-ed an IBM T30 Thinkpad Laptop. It looks nice at first sight, and now I want _Qxx methods in /EC to play with :)

What I found strange is the following behaviour:
If I boot with my second battery inserted, I have the corresponding entries for BAT1 in /proc/acpi/battery and /sys/.../EC/BAT1 If I boot without my second battery inserted, and I insert it later on, I don't have the corresponding BAT1 directory for it in /proc/acpi and /sys/.../EC/.
And this is true for other acpi devices too.
I think that the problem is that it does not (yet) update the list of active devices in real time, but uses the list with devices detected at boot time.

Anyway, this is a good start, and I am waiting for more patches to test.

Thanks,
Paul

Quoted 6 lines

Seems like it's about time the ACPI sysfs namespace started >doing
more than looking pretty. Here's a stab at adding in some basic functionality. I'd like to get some feedback before I start filling in the more complicated features. This has been lightly tested on a sampling of HP ia64 boxes. Does this seem like a reasonable start? Comments and reports from other platforms welcome. Thanks,

-------------------------------------------------------
This SF.Net email is sponsored by: IBM Linux Tutorials Free Linux tutorial presented by Daniel Robbins, President and CEO of GenToo technologies. Learn everything from fundamentals to system administration.http://ads.osdn.com/?ad_id=1470&alloc_id=3638&op=click

A message that is not in the archive (sent off-list or not yet received): [email protected]

#2 lore raw
Quoted 6 lines · Paul Ionescu

Hi Alex,

I patch-ed a 2.6.5 kernel, and boot-ed an IBM T30 Thinkpad Laptop. It looks nice at first sight, and now I want _Qxx methods in /EC to play with :)

Quoted 10 lines

What I found strange is the following behaviour:
If I boot with my second battery inserted, I have the corresponding entries for BAT1 in /proc/acpi/battery and /sys/.../EC/BAT1 If I boot without my second battery inserted, and I insert it later on, I don't have the corresponding BAT1 directory for it in /proc/acpi and /sys/.../EC/.
And this is true for other acpi devices too.
I think that the problem is that it does not (yet) update the list of active devices in real time, but uses the list with devices detected at boot time.

Yeah, we were only filling in devices that the _STA method claimed
were present at boot. I've fixed that now.

Quoted 1 line

Anyway, this is a good start, and I am waiting for more patches to test.

Here you go, a second iteration. I haven't looked at the _Qxx
methods yet, but we're up to over 30 methods exported now. I've added several writable methods so you can do more than query status. I've been able to undock my omnibook 500 laptop (electromechanical eject) and switch between a CRT and LCD using only the sysfs interface. I thought about parsing some of the more complicated data structures, but that turned into way too much code too quickly. So you'll find there are several entries that return a binary dump of the data structures. these include _CRS, _PRS, _PRT, and _MAT. Some of the methods look like they should work, but I don't have a box w/ firmware that exports them, so let me know if the output is broken. Thanks,

Alex

Signature · 407 lines
Alex Williamson                             HP Linux & Open Source Lab

===== drivers/acpi/scan.c 1.22 vs edited =====
--- 1.22/drivers/acpi/scan.c	Tue Feb  3 22:29:19 2004
+++ edited/drivers/acpi/scan.c	Wed Apr  7 15:55:17 2004
@@ -7,6 +7,7 @@
 
 #include <acpi/acpi_drivers.h>
 #include <acpi/acinterp.h>	/* for acpi_ex_eisa_id_to_string() */
+#include <acpi/actypes.h>
 
 
 #define _COMPONENT		ACPI_BUS_COMPONENT
@@ -22,9 +23,326 @@
 #define ACPI_BUS_DRIVER_NAME		"ACPI Bus Driver"
 #define ACPI_BUS_DEVICE_NAME		"System Bus"
 
+#define METHOD_NAME__BCL		"_BCL"
+#define METHOD_NAME__BCM		"_BCM"
+#define METHOD_NAME__DCK		"_DCK"
+#define METHOD_NAME__DCS		"_DCS"
+#define METHOD_NAME__DGS		"_DGS"
+#define METHOD_NAME__DDN		"_DDN"
+#define METHOD_NAME__DSS		"_DSS"
+#define METHOD_NAME__DOS		"_DOS"
+#define METHOD_NAME__DOD		"_DOD"
+#define METHOD_NAME__EDL		"_EDL"
+#define METHOD_NAME__EJ0		"_EJ0"
+#define METHOD_NAME__EJD		"_EJD"
+#define METHOD_NAME__FIX		"_FIX"
+#define METHOD_NAME__HPP		"_HPP"
+#define METHOD_NAME__LCK		"_LCK"
+#define METHOD_NAME__LID		"_LID"
+#define METHOD_NAME__MAT		"_MAT"
+#define METHOD_NAME__PXM		"_PXM"
+#define METHOD_NAME__RMV		"_RMV"
+#define METHOD_NAME__STR		"_STR"
+#define METHOD_NAME__SUN		"_SUN"
+
 static LIST_HEAD(acpi_device_list);
 static spinlock_t acpi_device_lock = SPIN_LOCK_UNLOCKED;
 
+struct acpi_handle_attribute {
+	struct attribute attr;
+	ssize_t (*show)(struct acpi_device *, char *, char *);
+	ssize_t (*store)(struct acpi_device *, char *, const char *, size_t);
+};
+
+#define EISA_ID_TYPE (1<<0)
+#define UNICODE_TYPE (1<<1)
+
+static ssize_t
+parse_integer(char *buf, u32 value, unsigned int flags) {
+	if (flags & EISA_ID_TYPE) {
+		acpi_ex_eisa_id_to_string(value, buf);
+		buf[8] = '\n';
+		return 9;
+	}
+	return sprintf(buf, "%08x\n", value);
+}
+
+static ssize_t
+parse_string(char *buf, u32 length, char *pointer, unsigned int flags) {
+	snprintf(buf, length, "%s", pointer);
+	buf[length++] = '\n';
+	return length;
+}
+
+static ssize_t
+parse_buffer(char *buf, u32 length, u8 *pointer, unsigned int flags) {
+	ssize_t offset = 0;
+
+	if (flags & UNICODE_TYPE) {
+		for (; length > 0 ; length -= 2) {
+			buf[offset++] = *pointer;
+			pointer += 2;
+		}
+	} else {
+		for (; length > 0 ; length--) {
+			sprintf(buf + offset, "%02x", *pointer);
+			offset += 2;
+			pointer++;
+		}
+	}
+	buf[offset++] = '\n';
+	return offset;
+}
+
+static ssize_t parse_package(char *, union acpi_object *, unsigned int);
+
+static ssize_t
+parse_element(
+	char			*buf,
+	union acpi_object	*element,
+	unsigned int		flags)
+{
+
+	switch (element->type) {
+		case ACPI_TYPE_INTEGER:
+			return parse_integer(buf, element->integer.value, flags);
+		case ACPI_TYPE_STRING:
+			return parse_string(buf, element->string.length,
+			                    element->string.pointer, flags);
+		case ACPI_TYPE_BUFFER:
+			return parse_buffer(buf, element->buffer.length,
+			                   element->buffer.pointer, flags);
+		case ACPI_TYPE_PACKAGE:
+			return parse_package(buf, element, flags);
+		default:
+			return sprintf(buf, "Unknown Type: %d\n", element->type);
+	}
+}
+
+static ssize_t
+parse_package(char *buf, union acpi_object *element, unsigned int flags) {
+	int count = element->package.count;
+	ssize_t tmp, retval = 0;
+
+	element = element->package.elements;
+
+	for (; count > 0 ; count--, element++) {
+		tmp = parse_element(buf, element, flags);
+		buf += tmp;
+		retval += tmp;
+	}
+	return retval;
+}
+
+static ssize_t
+acpi_device_read_file (
+	struct acpi_device	*device,
+	char			*method,
+	char			*buf)
+{
+	acpi_status status;
+	union acpi_object *element;
+	struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+	ssize_t retval = 0;
+	unsigned int flags = 0;
+
+	if (!strcmp(method, METHOD_NAME__CRS)) {
+		status = acpi_get_current_resources(device->handle, &buffer);
+		if (ACPI_FAILURE(status))
+			return -ENODEV;
+
+		memcpy(buf, buffer.pointer, buffer.length);
+		retval = buffer.length;
+		acpi_os_free(buffer.pointer);
+	} else if (!strcmp(method, METHOD_NAME__PRS)) {
+		status = acpi_get_possible_resources(device->handle, &buffer);
+		if (ACPI_FAILURE(status))
+			return -ENODEV;
+
+		memcpy(buf, buffer.pointer, buffer.length);
+		retval = buffer.length;
+		acpi_os_free(buffer.pointer);
+	} else if (!strcmp(method, METHOD_NAME__PRT)) {
+		status = acpi_get_irq_routing_table(device->handle, &buffer);
+		if (ACPI_FAILURE(status))
+			return -ENODEV;
+
+		memcpy(buf, buffer.pointer, buffer.length);
+		retval = buffer.length;
+		acpi_os_free(buffer.pointer);
+	} else if (!strcmp(method, METHOD_NAME__MAT)) {
+		status = acpi_evaluate_object(device->handle, method,
+		                              NULL, &buffer);
+		if (ACPI_FAILURE(status))
+			return -ENODEV;
+
+		memcpy(buf, buffer.pointer, buffer.length);
+		retval = buffer.length;
+		acpi_os_free(buffer.pointer);
+	} else {
+		status = acpi_evaluate_object(device->handle, method,
+		                              NULL, &buffer);
+		if (ACPI_FAILURE(status))
+			return -ENODEV;
+	
+		if (!strcmp(method, METHOD_NAME__HID)
+		    || !strcmp(method, METHOD_NAME__CID)
+		    || !strcmp(method, METHOD_NAME__FIX))
+			flags |= EISA_ID_TYPE;
+
+		if (!strcmp(method, METHOD_NAME__STR))
+			flags |= UNICODE_TYPE;
+
+		element = (union acpi_object *) buffer.pointer;
+		retval = parse_element(buf, element, flags);
+		acpi_os_free(buffer.pointer);
+	}
+	return retval;
+}
+
+static ssize_t
+acpi_device_write_integer (
+	struct acpi_device	*device,
+	char			*method,
+	const char		*buf,
+	size_t			length)
+{
+	struct acpi_object_list arg_list;
+	union acpi_object arg;
+	int value;
+
+
+	value = simple_strtol(buf, NULL, 0);
+
+	arg_list.count = 1;
+	arg_list.pointer = &arg;
+	arg.type = ACPI_TYPE_INTEGER;
+	arg.integer.value = value;
+
+	if (ACPI_FAILURE(acpi_evaluate_object(device->handle, method, &arg_list, NULL)))
+		return -ENODEV;
+	
+	return length;
+}
+
+#define acpi_handle_attr(method, show_func, store_func) \
+static struct acpi_handle_attribute acpi_handle_attr##method = { \
+	.attr = {.name = METHOD_NAME_##method, .mode = S_IFREG | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP}, \
+	.show = show_func, \
+	.store = store_func, \
+};
+
+acpi_handle_attr(_ADR, acpi_device_read_file, NULL)
+acpi_handle_attr(_BBN, acpi_device_read_file, NULL)
+acpi_handle_attr(_BCL, acpi_device_read_file, NULL)
+acpi_handle_attr(_BCM, NULL, acpi_device_write_integer)
+acpi_handle_attr(_CID, acpi_device_read_file, NULL)
+acpi_handle_attr(_CRS, acpi_device_read_file, NULL)
+acpi_handle_attr(_DCK, NULL, acpi_device_write_integer)
+acpi_handle_attr(_DCS, acpi_device_read_file, NULL)
+acpi_handle_attr(_DGS, acpi_device_read_file, NULL)
+acpi_handle_attr(_DDN, acpi_device_read_file, NULL)
+acpi_handle_attr(_DSS, NULL, acpi_device_write_integer)
+acpi_handle_attr(_DOS, NULL, acpi_device_write_integer)
+acpi_handle_attr(_DOD, acpi_device_read_file, NULL)
+acpi_handle_attr(_EDL, acpi_device_read_file, NULL)
+acpi_handle_attr(_EJ0, NULL, acpi_device_write_integer)
+acpi_handle_attr(_EJD, acpi_device_read_file, NULL)
+acpi_handle_attr(_FIX, acpi_device_read_file, NULL)
+acpi_handle_attr(_HID, acpi_device_read_file, NULL)
+acpi_handle_attr(_HPP, acpi_device_read_file, NULL)
+acpi_handle_attr(_LCK, NULL, acpi_device_write_integer)
+acpi_handle_attr(_LID, acpi_device_read_file, NULL)
+acpi_handle_attr(_MAT, acpi_device_read_file, NULL)
+acpi_handle_attr(_PRS, acpi_device_read_file, NULL)
+acpi_handle_attr(_PRT, acpi_device_read_file, NULL)
+acpi_handle_attr(_PXM, acpi_device_read_file, NULL)
+acpi_handle_attr(_RMV, acpi_device_read_file, NULL)
+acpi_handle_attr(_SEG, acpi_device_read_file, NULL)
+acpi_handle_attr(_STA, acpi_device_read_file, NULL)
+acpi_handle_attr(_STR, acpi_device_read_file, NULL)
+acpi_handle_attr(_SUN, acpi_device_read_file, NULL)
+acpi_handle_attr(_UID, acpi_device_read_file, NULL)
+
+typedef void acpi_device_sysfs_files(struct kobject *,
+                                     const struct attribute *);
+
+static void
+setup_sys_fs_files (
+	struct acpi_device *dev,
+	acpi_device_sysfs_files *func)
+{
+	acpi_handle tmp = NULL;
+
+	if (ACPI_SUCCESS(acpi_get_handle(dev->handle, METHOD_NAME__ADR, &tmp)))
+		(*(func))(&dev->kobj, &acpi_handle_attr_ADR.attr);
+	if (ACPI_SUCCESS(acpi_get_handle(dev->handle, METHOD_NAME__BBN, &tmp)))
+		(*(func))(&dev->kobj, &acpi_handle_attr_BBN.attr);
+	if (ACPI_SUCCESS(acpi_get_handle(dev->handle, METHOD_NAME__BCL, &tmp)))
+		(*(func))(&dev->kobj, &acpi_handle_attr_BCL.attr);
+	if (ACPI_SUCCESS(acpi_get_handle(dev->handle, METHOD_NAME__BCM, &tmp)))
+		(*(func))(&dev->kobj, &acpi_handle_attr_BCM.attr);
+	if (ACPI_SUCCESS(acpi_get_handle(dev->handle, METHOD_NAME__CID, &tmp)))
+		(*(func))(&dev->kobj, &acpi_handle_attr_CID.attr);
+	if (ACPI_SUCCESS(acpi_get_handle(dev->handle, METHOD_NAME__CRS, &tmp)))
+		(*(func))(&dev->kobj, &acpi_handle_attr_CRS.attr);
+	if (ACPI_SUCCESS(acpi_get_handle(dev->handle, METHOD_NAME__DCK, &tmp)))
+		(*(func))(&dev->kobj, &acpi_handle_attr_DCK.attr);
+	if (ACPI_SUCCESS(acpi_get_handle(dev->handle, METHOD_NAME__DCS, &tmp)))
+		(*(func))(&dev->kobj, &acpi_handle_attr_DCS.attr);
+	if (ACPI_SUCCESS(acpi_get_handle(dev->handle, METHOD_NAME__DGS, &tmp)))
+		(*(func))(&dev->kobj, &acpi_handle_attr_DGS.attr);
+	if (ACPI_SUCCESS(acpi_get_handle(dev->handle, METHOD_NAME__DDN, &tmp)))
+		(*(func))(&dev->kobj, &acpi_handle_attr_DDN.attr);
+	if (ACPI_SUCCESS(acpi_get_handle(dev->handle, METHOD_NAME__DSS, &tmp)))
+		(*(func))(&dev->kobj, &acpi_handle_attr_DSS.attr);
+	if (ACPI_SUCCESS(acpi_get_handle(dev->handle, METHOD_NAME__DOS, &tmp)))
+		(*(func))(&dev->kobj, &acpi_handle_attr_DOS.attr);
+	if (ACPI_SUCCESS(acpi_get_handle(dev->handle, METHOD_NAME__DOD, &tmp)))
+		(*(func))(&dev->kobj, &acpi_handle_attr_DOD.attr);
+	if (ACPI_SUCCESS(acpi_get_handle(dev->handle, METHOD_NAME__EDL, &tmp)))
+		(*(func))(&dev->kobj, &acpi_handle_attr_EDL.attr);
+	if (ACPI_SUCCESS(acpi_get_handle(dev->handle, METHOD_NAME__EJ0, &tmp)))
+		(*(func))(&dev->kobj, &acpi_handle_attr_EJ0.attr);
+	if (ACPI_SUCCESS(acpi_get_handle(dev->handle, METHOD_NAME__EJD, &tmp)))
+		(*(func))(&dev->kobj, &acpi_handle_attr_EJD.attr);
+	if (ACPI_SUCCESS(acpi_get_handle(dev->handle, METHOD_NAME__FIX, &tmp)))
+		(*(func))(&dev->kobj, &acpi_handle_attr_FIX.attr);
+	if (ACPI_SUCCESS(acpi_get_handle(dev->handle, METHOD_NAME__HID, &tmp)))
+		(*(func))(&dev->kobj, &acpi_handle_attr_HID.attr);
+	if (ACPI_SUCCESS(acpi_get_handle(dev->handle, METHOD_NAME__HPP, &tmp)))
+		(*(func))(&dev->kobj, &acpi_handle_attr_HPP.attr);
+	if (ACPI_SUCCESS(acpi_get_handle(dev->handle, METHOD_NAME__LCK, &tmp)))
+		(*(func))(&dev->kobj, &acpi_handle_attr_LCK.attr);
+	if (ACPI_SUCCESS(acpi_get_handle(dev->handle, METHOD_NAME__LID, &tmp)))
+		(*(func))(&dev->kobj, &acpi_handle_attr_LID.attr);
+	if (ACPI_SUCCESS(acpi_get_handle(dev->handle, METHOD_NAME__MAT, &tmp)))
+		(*(func))(&dev->kobj, &acpi_handle_attr_MAT.attr);
+	if (ACPI_SUCCESS(acpi_get_handle(dev->handle, METHOD_NAME__PRS, &tmp)))
+		(*(func))(&dev->kobj, &acpi_handle_attr_PRS.attr);
+	if (ACPI_SUCCESS(acpi_get_handle(dev->handle, METHOD_NAME__PRT, &tmp)))
+		(*(func))(&dev->kobj, &acpi_handle_attr_PRT.attr);
+	if (ACPI_SUCCESS(acpi_get_handle(dev->handle, METHOD_NAME__PXM, &tmp)))
+		(*(func))(&dev->kobj, &acpi_handle_attr_PXM.attr);
+	if (ACPI_SUCCESS(acpi_get_handle(dev->handle, METHOD_NAME__RMV, &tmp)))
+		(*(func))(&dev->kobj, &acpi_handle_attr_RMV.attr);
+	if (ACPI_SUCCESS(acpi_get_handle(dev->handle, METHOD_NAME__SEG, &tmp)))
+		(*(func))(&dev->kobj, &acpi_handle_attr_SEG.attr);
+	if (ACPI_SUCCESS(acpi_get_handle(dev->handle, METHOD_NAME__STA, &tmp)))
+		(*(func))(&dev->kobj, &acpi_handle_attr_STA.attr);
+	if (ACPI_SUCCESS(acpi_get_handle(dev->handle, METHOD_NAME__STR, &tmp)))
+		(*(func))(&dev->kobj, &acpi_handle_attr_STR.attr);
+	if (ACPI_SUCCESS(acpi_get_handle(dev->handle, METHOD_NAME__SUN, &tmp)))
+		(*(func))(&dev->kobj, &acpi_handle_attr_SUN.attr);
+	if (ACPI_SUCCESS(acpi_get_handle(dev->handle, METHOD_NAME__UID, &tmp)))
+		(*(func))(&dev->kobj, &acpi_handle_attr_UID.attr);
+}
+
+#define create_sysfs_files(dev) \
+	setup_sys_fs_files(dev, (acpi_device_sysfs_files *)&sysfs_create_file)
+#define remove_sysfs_files(dev) \
+	setup_sys_fs_files(dev, &sysfs_remove_file)
+
 static void acpi_device_release(struct kobject * kobj)
 {
 	struct acpi_device * dev = container_of(kobj,struct acpi_device,kobj);
@@ -33,7 +351,32 @@
 	kfree(dev);
 }
 
+#define to_acpi_device(n) container_of(n, struct acpi_device, kobj)
+#define to_handle_attr(n) container_of(n, struct acpi_handle_attribute, attr);
+
+static ssize_t acpi_device_attr_show(struct kobject *kobj,
+                struct attribute *attr, char *buf)
+{
+	struct acpi_device *device = to_acpi_device(kobj);
+	struct acpi_handle_attribute *attribute = to_handle_attr(attr);
+	return attribute->show ? attribute->show(device, attribute->attr.name, buf) : 0;
+}
+
+static ssize_t acpi_device_attr_store(struct kobject *kobj,
+                struct attribute *attr, const char *buf, size_t len)
+{
+	struct acpi_device *device = to_acpi_device(kobj);
+	struct acpi_handle_attribute *attribute = to_handle_attr(attr);
+	return attribute->store ? attribute->store(device, attribute->attr.name, buf, len) : len;
+}
+
+static struct sysfs_ops acpi_device_sysfs_ops = {
+	.show = acpi_device_attr_show,
+	.store = acpi_device_attr_store,
+};
+
 static struct kobj_type ktype_acpi_ns = {
+	.sysfs_ops	= &acpi_device_sysfs_ops,
 	.release	= acpi_device_release,
 };
 
@@ -72,6 +415,7 @@
 	device->kobj.ktype = &ktype_acpi_ns;
 	device->kobj.kset = &acpi_namespace_kset;
 	kobject_add(&device->kobj);
+	create_sysfs_files(device);
 }
 
 static int
@@ -79,6 +423,7 @@
 	struct acpi_device	*device, 
 	int			type)
 {
+	remove_sysfs_files(device);
 	kobject_unregister(&device->kobj);
 	return 0;
 }
@@ -706,7 +1051,7 @@
 	switch (type) {
 	case ACPI_BUS_TYPE_DEVICE:
 		result = acpi_bus_get_status(device);
-		if (ACPI_FAILURE(result) || !device->status.present) {
+		if (ACPI_FAILURE(result)) {
 			result = -ENOENT;
 			goto end;
 		}




-------------------------------------------------------
This SF.Net email is sponsored by: IBM Linux Tutorials
Free Linux tutorial presented by Daniel Robbins, President and CEO of
GenToo technologies. Learn everything from fundamentals to system
administration.http://ads.osdn.com/?ad_id=1470&alloc_id=3638&op=click

A message that is not in the archive (sent off-list or not yet received): [email protected]

#4 lore raw

Hi Alex,

Boy, you are fast.
I compiled the second patch in kernel 2.6.5 and booted the laptop. The first thing I've noticed is that now we have all devices in /sys/firmware/acpi/... even if they are initialized or not (present or not) which IMHO is good. So, your fix works.
I still don't have /proc/acpi/battery/BAT1 if I hot plug the second battery after loading the kernel. I don't really know if is because of your patch or this is how new kernel behave (I have to test it with vanilla 2.6.5 later)

I will get back with more details after more testing/playing.

Thanks,
Paul

Quoted 35 lines · Alex Williamson
Quoted 6 lines · Paul Ionescu

Hi Alex,

I patch-ed a 2.6.5 kernel, and boot-ed an IBM T30 Thinkpad Laptop. It looks nice at first sight, and now I want _Qxx methods in /EC to play with :)

Quoted 10 lines

What I found strange is the following behaviour:
If I boot with my second battery inserted, I have the corresponding entries for BAT1 in /proc/acpi/battery and /sys/.../EC/BAT1 If I boot without my second battery inserted, and I insert it later on, I don't have the corresponding BAT1 directory for it in /proc/acpi and /sys/.../EC/.
And this is true for other acpi devices too.
I think that the problem is that it does not (yet) update the list of active devices in real time, but uses the list with devices detected at boot time.

Yeah, we were only filling in devices that the _STA method claimed
were present at boot. I've fixed that now.

Quoted 1 line

Anyway, this is a good start, and I am waiting for more patches to test.

Here you go, a second iteration. I haven't looked at the _Qxx
methods yet, but we're up to over 30 methods exported now. I've added several writable methods so you can do more than query status. I've been able to undock my omnibook 500 laptop (electromechanical eject) and switch between a CRT and LCD using only the sysfs interface. I thought about parsing some of the more complicated data structures, but that turned into way too much code too quickly. So you'll find there are several entries that return a binary dump of the data structures. these include _CRS, _PRS, _PRT, and _MAT. Some of the methods look like they should work, but I don't have a box w/ firmware that exports them, so let me know if the output is broken. Thanks,

Quoted 1 line

Alex

-------------------------------------------------------
This SF.Net email is sponsored by: IBM Linux Tutorials Free Linux tutorial presented by Daniel Robbins, President and CEO of GenToo technologies. Learn everything from fundamentals to system administration.http://ads.osdn.com/?ad_id=1470&alloc_id=3638&op=click

#5 lore raw
In reply to a message not in the archive

Hi Alex,

I think I found a little bug:

cat _SB/PCI0/LCP/UART/_EJD
gives me: _SB.PCI0.PCI1.DOC
and it should give _SB.PCI0.PCI1.DOCK (I searched in the DSDT)

So I think that _EJD function is eating the last byte.

I tried some more _EJDs and the same result; missing last byte.

Thanks,
Paul

-------------------------------------------------------
This SF.Net email is sponsored by: IBM Linux Tutorials Free Linux tutorial presented by Daniel Robbins, President and CEO of GenToo technologies. Learn everything from fundamentals to system administration.http://ads.osdn.com/?ad_id=1470&alloc_id=3638&op=click

A message that is not in the archive (sent off-list or not yet received): [email protected]

#7 lore raw
Quoted 9 lines · Paul Ionescu

Hi Alex,

I think I found a little bug:

cat _SB/PCI0/LCP/UART/_EJD
gives me: _SB.PCI0.PCI1.DOC
and it should give _SB.PCI0.PCI1.DOCK (I searched in the DSDT)

So I think that _EJD function is eating the last byte.

Yep, I wasn't accounting for the '\0' snprintf wants to put at the
end. If you make drivers/acpi/scan.c:parse_string() look like this it should work:

static ssize_t

parse_string(char *buf, u32 length, char *pointer, unsigned int flags) {
	length += 2;
	return snprintf(buf, length, "%s\n", pointer);
}

I could probably just use an sprintf, but I was being paranoid that firmware might not terminate the string. I'll fix it in the next version. Thanks,

Alex

Signature · 9 lines
Alex Williamson                             HP Linux & Open Source Lab



-------------------------------------------------------
This SF.Net email is sponsored by: IBM Linux Tutorials
Free Linux tutorial presented by Daniel Robbins, President and CEO of
GenToo technologies. Learn everything from fundamentals to system
administration.http://ads.osdn.com/?ad_id=1470&alloc_id=3638&op=click
#8 lore raw
In reply to a message not in the archive

Hi Alex,

I was browsing my DSDT when I found out that I really have in it description for DOCK.IDE1.MSTR, DOCK.CBS2 and DOCK.CBS3, but they don't appear in my /sys/firmware/... unless I booted in docking station. Is this normal ? I thought that it should be like the battery thing, if is in DSDT, then we should have it, even if it is not present at the boot time.

Thanks,
Paul

-------------------------------------------------------
This SF.Net email is sponsored by: IBM Linux Tutorials Free Linux tutorial presented by Daniel Robbins, President and CEO of GenToo technologies. Learn everything from fundamentals to system administration.http://ads.osdn.com/?ad_id=1470&alloc_id=3638&op=click

#9 lore raw
In reply to a message not in the archive
Quoted 11 lines · Alex Williamson

Here you go, a second iteration. I haven't looked at the _Qxx
methods yet, but we're up to over 30 methods exported now. I've added several writable methods so you can do more than query status. I've been able to undock my omnibook 500 laptop (electromechanical eject) and switch between a CRT and LCD using only the sysfs interface. I thought about parsing some of the more complicated data structures, but that turned into way too much code too quickly. So you'll find there are several entries that return a binary dump of the data structures. these include _CRS, _PRS, _PRT, and _MAT. Some of the methods look like they should work, but I don't have a box w/ firmware that exports them, so let me know if the output is broken. Thanks,

Ii'm not a big fan of overloading acpi_device_read_file ... how about splitting it up like this?

drivers/acpi/scan.c +80 -55
diff -u edited/drivers/acpi/scan.c b/drivers/acpi/scan.c
@@ -146,61 +146,86 @@
 	ssize_t retval = 0;
 	unsigned int flags = 0;
 
-	if (!strcmp(method, METHOD_NAME__CRS)) {
-		status = acpi_get_current_resources(device->handle, &buffer);
-		if (ACPI_FAILURE(status))
-			return -ENODEV;
-
-		memcpy(buf, buffer.pointer, buffer.length);
-		retval = buffer.length;
-		acpi_os_free(buffer.pointer);
-	} else if (!strcmp(method, METHOD_NAME__PRS)) {
-		status = acpi_get_possible_resources(device->handle, &buffer);
-		if (ACPI_FAILURE(status))
-			return -ENODEV;
-
-		memcpy(buf, buffer.pointer, buffer.length);
-		retval = buffer.length;
-		acpi_os_free(buffer.pointer);
-	} else if (!strcmp(method, METHOD_NAME__PRT)) {
-		status = acpi_get_irq_routing_table(device->handle, &buffer);
-		if (ACPI_FAILURE(status))
-			return -ENODEV;
-
-		memcpy(buf, buffer.pointer, buffer.length);
-		retval = buffer.length;
-		acpi_os_free(buffer.pointer);
-	} else if (!strcmp(method, METHOD_NAME__MAT)) {
-		status = acpi_evaluate_object(device->handle, method,
-		                              NULL, &buffer);
-		if (ACPI_FAILURE(status))
-			return -ENODEV;
-
-		memcpy(buf, buffer.pointer, buffer.length);
-		retval = buffer.length;
-		acpi_os_free(buffer.pointer);
-	} else {
-		status = acpi_evaluate_object(device->handle, method,
-		                              NULL, &buffer);
-		if (ACPI_FAILURE(status))
-			return -ENODEV;
-	
-		if (!strcmp(method, METHOD_NAME__HID)
-		    || !strcmp(method, METHOD_NAME__CID)
-		    || !strcmp(method, METHOD_NAME__FIX))
-			flags |= EISA_ID_TYPE;
-
-		if (!strcmp(method, METHOD_NAME__STR))
-			flags |= UNICODE_TYPE;
-
-		element = (union acpi_object *) buffer.pointer;
-		retval = parse_element(buf, element, flags);
-		acpi_os_free(buffer.pointer);
-	}
+	status = acpi_evaluate_object(device->handle, method, NULL, &buffer);
+	if (ACPI_FAILURE(status))
+		return -ENODEV;
+
+	if (!strcmp(method, METHOD_NAME__HID)
+	    || !strcmp(method, METHOD_NAME__CID)
+	    || !strcmp(method, METHOD_NAME__FIX))
+		flags = EISA_ID_TYPE;
+
+	if (!strcmp(method, METHOD_NAME__STR))
+		flags = UNICODE_TYPE;
+
+	element = (union acpi_object *) buffer.pointer;
+	retval = parse_element(buf, element, flags);
+	acpi_os_free(buffer.pointer);
+
 	return retval;
 }
 
 static ssize_t
+acpi_device_read_raw(struct acpi_device *device, char *method, char *buf)
+{
+	acpi_status status;
+	struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+
+	status = acpi_evaluate_object(device->handle, method, NULL, &buffer);
+	if (ACPI_FAILURE(status))
+		return -ENODEV;
+
+	memcpy(buf, buffer.pointer, buffer.length);
+	acpi_os_free(buffer.pointer);
+	return buffer.length;
+}
+
+static ssize_t
+acpi_device_read_crs(struct acpi_device *device, char *method, char *buf)
+{
+	acpi_status status;
+	struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+
+	status = acpi_get_current_resources(device->handle, &buffer);
+	if (ACPI_FAILURE(status))
+		return -ENODEV;
+
+	memcpy(buf, buffer.pointer, buffer.length);
+	acpi_os_free(buffer.pointer);
+	return buffer.length;
+}
+
+static ssize_t
+acpi_device_read_prs(struct acpi_device *device, char *method, char *buf)
+{
+	acpi_status status;
+	struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+
+	status = acpi_get_possible_resources(device->handle, &buffer);
+	if (ACPI_FAILURE(status))
+		return -ENODEV;
+
+	memcpy(buf, buffer.pointer, buffer.length);
+	acpi_os_free(buffer.pointer);
+	return buffer.length;
+}
+
+static ssize_t
+acpi_device_read_prt(struct acpi_device *device, char *method, char *buf)
+{
+	acpi_status status;
+	struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+
+	status = acpi_get_irq_routing_table(device->handle, &buffer);
+	if (ACPI_FAILURE(status))
+		return -ENODEV;
+
+	memcpy(buf, buffer.pointer, buffer.length);
+	acpi_os_free(buffer.pointer);
+	return buffer.length;
+}
+
+static ssize_t
 acpi_device_write_integer (
 	struct acpi_device	*device,
 	char			*method,
@@ -237,7 +262,7 @@
 acpi_handle_attr(_BCL, acpi_device_read_file, NULL)
 acpi_handle_attr(_BCM, NULL, acpi_device_write_integer)
 acpi_handle_attr(_CID, acpi_device_read_file, NULL)
-acpi_handle_attr(_CRS, acpi_device_read_file, NULL)
+acpi_handle_attr(_CRS, acpi_device_read_crs, NULL)
 acpi_handle_attr(_DCK, NULL, acpi_device_write_integer)
 acpi_handle_attr(_DCS, acpi_device_read_file, NULL)
 acpi_handle_attr(_DGS, acpi_device_read_file, NULL)
@@ -253,9 +278,9 @@
 acpi_handle_attr(_HPP, acpi_device_read_file, NULL)
 acpi_handle_attr(_LCK, NULL, acpi_device_write_integer)
 acpi_handle_attr(_LID, acpi_device_read_file, NULL)
-acpi_handle_attr(_MAT, acpi_device_read_file, NULL)
-acpi_handle_attr(_PRS, acpi_device_read_file, NULL)
-acpi_handle_attr(_PRT, acpi_device_read_file, NULL)
+acpi_handle_attr(_MAT, acpi_device_read_raw, NULL)
+acpi_handle_attr(_PRS, acpi_device_read_prs, NULL)
+acpi_handle_attr(_PRT, acpi_device_read_prt, NULL)
 acpi_handle_attr(_PXM, acpi_device_read_file, NULL)
 acpi_handle_attr(_RMV, acpi_device_read_file, NULL)
 acpi_handle_attr(_SEG, acpi_device_read_file, NULL)
Signature · 13 lines
"Next the statesmen will invent cheap lies, putting the blame upon 
the nation that is attacked, and every man will be glad of those
conscience-soothing falsities, and will diligently study them, and refuse
to examine any refutations of them; and thus he will by and by convince 
himself that the war is just, and will thank God for the better sleep 
he enjoys after this process of grotesque self-deception." -- Mark Twain


-------------------------------------------------------
This SF.Net email is sponsored by: IBM Linux Tutorials
Free Linux tutorial presented by Daniel Robbins, President and CEO of
GenToo technologies. Learn everything from fundamentals to system
administration.http://ads.osdn.com/?ad_id=1470&alloc_id=3638&op=click

A message that is not in the archive (sent off-list or not yet received): 20040408172548.GH18329-+pPCBgu9SkPzIGdyhVEDUDl5KyyQGfY2kSSpQ9I8OhVaa/[email protected]

#11 lore raw
Quoted 4 lines · Matthew Wilcox

Ii'm not a big fan of overloading acpi_device_read_file ... how about splitting it up like this?

Looks good to me, I'll incorporate the changes. Thanks,

Alex

Signature · 9 lines
Alex Williamson                             HP Linux & Open Source Lab



-------------------------------------------------------
This SF.Net email is sponsored by: IBM Linux Tutorials
Free Linux tutorial presented by Daniel Robbins, President and CEO of
GenToo technologies. Learn everything from fundamentals to system
administration.http://ads.osdn.com/?ad_id=1470&alloc_id=3638&op=click

A message that is not in the archive (sent off-list or not yet received): 1081536801.26073.120.camel@t40

A message that is not in the archive (sent off-list or not yet received): [email protected]

A message that is not in the archive (sent off-list or not yet received): [email protected]

#15 lore raw

Hi Alex,

You are right, I have:
/sys/bus/pci/slots/4294967295 # find .
.
./test
./cur_bus_speed
./max_bus_speed
./address
./adapter
./latch
./attention
./power

When I boot in dock, the value of power and adapter is 1, when I boot normaly, I have 0 in those files.
Now, I booted in DOCK, and I did an echo 0 > power, and surprise, it did an electromechanicaly eject of dock !!!.
Anyway, echo-ing 1 again, does nothing for me. I expected to power the pci slot again and find the coresponding device in there. So, thanks for the tips, now I get back to playing with apci.

Paul

Quoted 9 lines · Alex Williamson
Quoted 6 lines · Paul Ionescu

I also have an ACPI hotplug PCI slot in the laptop, because when I insert acpiphp.ko module, it sais that it found and registered a slot. Now, where do I find some info about that slot, or how can I play with it ? I suppose it is the PCI slot from my dock.
I could not find any info about it in /proc or /sys.
Is there a standard name I should look for ?

Quoted 5 lines

PCI hotplug slots registered via the ACPI hotplug driver show up
under /sys/bus/pci/slots. There are a few things you can do w/ it via that interface.

Alex

-------------------------------------------------------
This SF.Net email is sponsored by: IBM Linux Tutorials Free Linux tutorial presented by Daniel Robbins, President and CEO of GenToo technologies. Learn everything from fundamentals to system administration.http://ads.osdn.com/?ad_id=1470&alloc_id=3638&op=click

A message that is not in the archive (sent off-list or not yet received): 1081536489.23178.113.camel@t40

A message that is not in the archive (sent off-list or not yet received): [email protected]

A message that is not in the archive (sent off-list or not yet received): [email protected]

#19 lore raw

Hi Alex,

I found this in scan.c:
/*
* If the device is present, enabled, and functioning then
* parse its scope (depth-first). Note that we need to
* represent absent devices to facilitate PnP notifications
* -- but only the subtree head (not all of its children,
* which will be enumerated when the parent is inserted). *
* TBD: Need notifications and other detection mechanisms
* in place before we can fully implement this.
*/

This can be the reason I don't see the subdevices in DOCK but only the DOCK, when the dock is not active. So till someone does the TBD, this is the normal behaviour, ie subdevices don't show up unless the parent is active at scan time.

What do you think ?

Quoted 22 lines · Alex Williamson
Quoted 5 lines · Paul Ionescu

Hi Alex,

Do you have any ideea why I don't have IDE1, CBS2 and CBS3 in the tree even if they are present in the DSDT ?
They appear only when I boot in the dock.

No, I don't. You can try adding chunks of code like this in the scan
file:

{
        char pathname[ACPI_PATHNAME_MAX] = {0};
        struct acpi_buffer buffer = {0, NULL};
        buffer.length = sizeof(pathname);
        buffer.pointer = pathname;
        acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
        printk("%s() - [%s]\n", __FUNCTION__, pathname);
}

*Fix the handle pointer to be appropriate, everything else should be self contained

Quoted 6 lines

I'd start with adding it inside the while loop at the top of drivers/acpi/scan.c:acpi_bus_scan(). It's possible it's in the DSDT, but not activated for some reason. I'll be interested to hear why it's not showing up. Thanks,

Alex

-------------------------------------------------------
This SF.Net email is sponsored by: IBM Linux Tutorials Free Linux tutorial presented by Daniel Robbins, President and CEO of GenToo technologies. Learn everything from fundamentals to system administration.http://ads.osdn.com/?ad_id=1470&alloc_id=3638&op=click