[PATCH 21/25] sony-laptop: add optical device power control

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Vaio S and Z Series allow to turn off the optical device to save battery power, this patch exposes a control file to power on and off the device.


On Windows OS this feature is well integrated with the power management system, how to do the same on Linux? Moreover no media presence control and bus disconnection is performed (the DSDT provides the SATA controller the drive is connected to), should we do this in the driver or inside a userspace daemon?


Signed-off-by: Marco Chiappero <marco@xxxxxxxxxx>
---

--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -2627,6 +2627,118 @@ static int sony_nc_fan_cleanup(struct pl
 	return 0;
 }

+struct odd {
+	unsigned int vendor_id;
+	unsigned int model_id;
+	struct device_attribute status_attr;
+};
+static struct odd *odd_handle;
+
+static ssize_t sony_nc_odd_status_store(struct device *dev,
+		struct device_attribute *attr,
+		const char *buffer, size_t count)
+{
+	unsigned int result;
+	unsigned long value;
+
+	if (count > 31)
+		return -EINVAL;
+	if (strict_strtoul(buffer, 10, &value) || value > 1)
+		return -EINVAL;
+
+	/* 0x200 turn on (sysfs: 1), 0x300 turn off (sysfs: 0) */
+	value = (!value << 0x08) + 0x200;
+
+	/* the MSB have to be high */
+	if (sony_call_snc_handle(0x126, (1 << 0x10) | value, &result))
+		return -EIO;
+
+	return count;
+}
+
+static ssize_t sony_nc_odd_status_show(struct device *dev,
+		struct device_attribute *attr, char *buffer)
+{
+	ssize_t count = 0;
+	unsigned int result;
+
+	if (sony_call_snc_handle(0x126, 0x100, &result))
+		return -EINVAL;
+
+	count = snprintf(buffer, PAGE_SIZE, "%d\n", result & 0x01);
+	return count;
+}
+
+static int sony_nc_odd_setup(struct platform_device *pd)
+{
+#define ODD_TAB_SIZE 32
+	u8 list[ODD_TAB_SIZE] = { 0 };
+	int ret = 0;
+	int found = 0;
+	int i = 0;
+	unsigned int vendor = 0;
+	unsigned int model = 0;
+	u16 word = 0;
+
+	ret = sony_call_snc_handle_buffer(0x126, 0x0000, list, ODD_TAB_SIZE);
+	if (ret < 0) {
+		pr_info("unable to retrieve the odd table\n");
+		return -EIO;
+	}
+
+	/* parse the table looking for optical devices */
+	do {
+		word = (list[i+1] << 8) | list[i];
+
+		if (word == 1) { /* 1 DWord device data following */
+			vendor = (list[i+3] << 8) | list[i+2];
+			model = (list[i+5] << 8) | list[i+4];
+			found++;
+			i += 6;
+		} else {
+			i += 2;
+		}
+	} while (word != 0xff00);
+
+	if (found)
+		dprintk("one optical device found, connected to: %x:%x\n",
+				vendor, model);
+	else
+		return 0;
+
+	odd_handle = kzalloc(sizeof(*odd_handle), GFP_KERNEL);
+	if (!odd_handle)
+		return -ENOMEM;
+
+	odd_handle->vendor_id = vendor;
+	odd_handle->model_id = model;
+
+	sysfs_attr_init(&odd_handle->status_attr.attr);
+	odd_handle->status_attr.attr.name = "odd_power";
+	odd_handle->status_attr.attr.mode = S_IRUGO | S_IWUSR;
+	odd_handle->status_attr.show = sony_nc_odd_status_show;
+	odd_handle->status_attr.store = sony_nc_odd_status_store;
+
+	if (device_create_file(&pd->dev, &odd_handle->status_attr)) {
+		kfree(odd_handle);
+		odd_handle = NULL;
+		return -1;
+	}
+
+	return 0;
+}
+
+static int sony_nc_odd_cleanup(struct platform_device *pd)
+{
+	if (odd_handle) {
+		device_remove_file(&pd->dev, &odd_handle->status_attr);
+		kfree(odd_handle);
+		odd_handle = NULL;
+	}
+
+	return 0;
+}
+

 static void sony_nc_backlight_ng_read_limits(int handle,
 		struct sony_backlight_props *props)
@@ -2780,6 +2892,9 @@ static void sony_nc_snc_setup_handles(st
 		case 0x0122:
 			ret = sony_nc_thermal_setup(pd);
 			break;
+		case 0x0126:
+			ret = sony_nc_odd_setup(pd);
+			break;
 		case 0x0137:
 		case 0x0143:
 			sony_kbd_handle = handle;
@@ -2843,6 +2958,9 @@ static void sony_nc_snc_cleanup_handles(
 		case 0x0122:
 			sony_nc_thermal_cleanup(pd);
 			break;
+		case 0x0126:
+			sony_nc_odd_cleanup(pd);
+			break;
 		case 0x0137:
 		case 0x0143:
 			sony_nc_kbd_backlight_cleanup(pd);
--
To unsubscribe from this list: send the line "unsubscribe platform-driver-x86" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Kernel Development]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux