public inbox for linux-acpi@vger.kernel.org
 help / color / mirror / Atom feed
From: Martin Lucina <mato@kotelna.sk>
To: Harald Welte <laforge@gnumonks.org>
Cc: linux-acpi@vger.kernel.org
Subject: [PATCH] panasonic-laptop.c: add support for optical drive power control
Date: Wed, 14 Jan 2009 19:42:28 +0100	[thread overview]
Message-ID: <20090114184227.GC3654@dezo.moloch.sk> (raw)
In-Reply-To: <20090114060834.GN4791@prithivi.gnumonks.org>

Add support for power control of the built in optical drive on models
with the required ACPI methods present.  Tested on Panasonic CF-W4.

Creates an interface in /sys/devices/platform/panasonic/cdpower, to
which you can write "1" to switch the drive on, "0" to switch it off
or read from to query the current state.

Signed-off-by: Martin Lucina <mato@kotelna.sk>

---

Harald, this should address all the comments in this thread.  I've
removed the DMI table and enable the code if _SB.{STAT,FBAY,CDDI} are
all present.

I've not figured out how to return an actual error from the sysfs
show/store functions so I've at least added ACPI_DEBUG_PRINT to print an
error if the relevant methods fail.

-mato

--- linux-2.6.28/drivers/misc/panasonic-laptop.c.orig	2009-01-14 19:10:33.626598152 +0100
+++ linux-2.6.28/drivers/misc/panasonic-laptop.c	2009-01-14 19:22:06.500598198 +0100
@@ -24,6 +24,9 @@
  *---------------------------------------------------------------------------
  *
  * ChangeLog:
+ *	Jan.14, 2009    Martin Lucina <mato@kotelna.sk>
+ *		-v0.96  add support for optical drive power control
+ *			via /sys/devices/platform/panasonic/cdpower
  *	Sep.23, 2008	Harald Welte <laforge@gnumonks.org>
  *		-v0.95	rename driver from drivers/acpi/pcc_acpi.c to
  *			drivers/misc/panasonic-laptop.c
@@ -127,6 +130,7 @@
 #include <acpi/acpi_bus.h>
 #include <acpi/acpi_drivers.h>
 #include <linux/input.h>
+#include <linux/platform_device.h>
 
 
 #ifndef ACPI_HOTKEY_COMPONENT
@@ -219,6 +223,7 @@ struct pcc_acpi {
 	struct acpi_device	*device;
 	struct input_dev	*input_dev;
 	struct backlight_device	*backlight;
+	struct platform_device  *platform;
 	int			keymap[KEYMAP_SIZE];
 };
 
@@ -360,6 +365,96 @@ static struct backlight_ops pcc_backligh
 	.update_status	= bl_set_status,
 };
 
+/* returns ACPI_SUCCESS if methods to control optical drive are present */
+
+static acpi_status check_optd_present(void)
+{
+	acpi_status status = AE_OK;
+	acpi_handle handle;
+
+	status = acpi_get_handle(NULL, "\\_SB.STAT", &handle);
+	if (ACPI_FAILURE(status))
+		goto out;
+	status = acpi_get_handle(NULL, "\\_SB.FBAY", &handle);
+	if (ACPI_FAILURE(status))
+		goto out;
+	status = acpi_get_handle(NULL, "\\_SB.CDDI", &handle);
+	if (ACPI_FAILURE(status))
+		goto out;
+
+out:
+	return status;
+}
+
+/* get optical driver power state */
+
+static int get_optd_power_state(void)
+{
+	acpi_status status;
+	unsigned long long state;
+	int result;
+
+	status = acpi_evaluate_integer(NULL, "\\_SB.STAT", NULL, &state);
+	if (ACPI_FAILURE(status)) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+				  "evaluation error _SB.STAT\n"));
+		result = -EIO;
+		goto out;
+	}
+	switch (state) {
+	case 0: /* power off */
+		result = 0;
+		break;
+	case 0x0f: /* power on */
+		result = 1;
+		break;
+	default:
+		result = -EIO;
+		break;
+	}
+
+out:
+	return result;
+}
+
+/* set optical drive power state */
+
+static int set_optd_power_state(int new_state)
+{
+	int result;
+	acpi_status status;
+
+	result = get_optd_power_state();
+	if (result < 0)
+		goto out;
+	if (new_state == result)
+		goto out;
+
+	switch (new_state) {
+	case 0: /* power off */
+		status = acpi_evaluate_object(NULL, "\\_SB.CDDI", NULL, NULL);
+		if (ACPI_FAILURE(status)) {
+			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+					  "evaluation error _SB.CDDI\n"));
+			result = -EIO;
+		}
+		break;
+	case 1: /* power on */
+		status = acpi_evaluate_object(NULL, "\\_SB.FBAY", NULL, NULL);
+		if (ACPI_FAILURE(status)) {
+			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+					  "evaluation error _SB.FBAY\n"));
+			result = -EIO;
+		}
+		break;
+	default:
+		result = -EINVAL;
+		break;
+	}
+
+out:
+	return result;
+}
 
 /* sysfs user interface functions */
 
@@ -427,10 +522,29 @@ static ssize_t set_sticky(struct device 
 	return count;
 }
 
+static ssize_t show_cdpower(struct device *dev, struct device_attribute *attr,
+			    char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%d\n", get_optd_power_state());
+}
+
+static ssize_t set_cdpower(struct device *dev, struct device_attribute *attr,
+			   const char *buf, size_t count)
+{
+	int value;
+
+	if (count) {
+		value = simple_strtoul(buf, NULL, 10);
+		set_optd_power_state(value);
+	}
+	return count;
+}
+
 static DEVICE_ATTR(numbatt, S_IRUGO, show_numbatt, NULL);
 static DEVICE_ATTR(lcdtype, S_IRUGO, show_lcdtype, NULL);
 static DEVICE_ATTR(mute, S_IRUGO, show_mute, NULL);
 static DEVICE_ATTR(sticky_key, S_IRUGO | S_IWUSR, show_sticky, set_sticky);
+static DEVICE_ATTR(cdpower, S_IRUGO | S_IWUSR, show_cdpower, set_cdpower);
 
 static struct attribute *pcc_sysfs_entries[] = {
 	&dev_attr_numbatt.attr,
@@ -691,8 +805,26 @@ static int acpi_pcc_hotkey_add(struct ac
 	if (result)
 		goto out_backlight;
 
+	/* optical drive initialization */
+	if (ACPI_SUCCESS(check_optd_present())) {
+		pcc->platform = platform_device_register_simple("panasonic",
+			-1, NULL, 0);
+		if (IS_ERR(pcc->platform)) {
+			result = PTR_ERR(pcc->platform);
+			goto out_backlight;
+		}
+		result = device_create_file(&pcc->platform->dev,
+			&dev_attr_cdpower);
+		if (result)
+			goto out_platform;
+	} else {
+		pcc->platform = NULL;
+	}
+
 	return 0;
 
+out_platform:
+	platform_device_unregister(pcc->platform);
 out_backlight:
 	backlight_device_unregister(pcc->backlight);
 out_notify:
@@ -738,6 +870,11 @@ static int acpi_pcc_hotkey_remove(struct
 	if (!device || !pcc)
 		return -EINVAL;
 
+	if (pcc->platform) {
+		device_remove_file(&pcc->platform->dev, &dev_attr_cdpower);
+		platform_device_unregister(pcc->platform);
+	}
+
 	sysfs_remove_group(&device->dev.kobj, &pcc_attr_group);
 
 	backlight_device_unregister(pcc->backlight);

  reply	other threads:[~2009-01-14 18:42 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-01-13 16:32 [RFC] [PATCH] panasonic-laptop.c: add support for CD power management Martin Lucina
2009-01-13 17:16 ` Karthik Gopalakrishnan
2009-01-13 19:14   ` Martin Lucina
2009-01-14  6:08 ` Harald Welte
2009-01-14 18:42   ` Martin Lucina [this message]
2009-04-05  4:53     ` [PATCH] panasonic-laptop.c: add support for optical drive power control Len Brown
2009-04-06 16:22       ` Martin Lucina
2009-04-07  5:59         ` Len Brown
2009-04-07 23:07       ` Harald Welte

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20090114184227.GC3654@dezo.moloch.sk \
    --to=mato@kotelna.sk \
    --cc=laforge@gnumonks.org \
    --cc=linux-acpi@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox