@@ -3,6 +3,7 @@
*
* Copyright (C) 2004-2005 Stelian Pop <stelian@popies.net>
* Copyright (C) 2007 Mattia Dongili <malattia@linux.it>
+ * Copyright (C) 2009 Matthias Welwarsky <matze@welwarsky.de>
*
* Parts of this driver inspired from asus_acpi.c and ibm_acpi.c
* which are copyrighted by their respective authors.
@@ -84,6 +85,8 @@
#define SONY_PIC_HID "SNY6001"
#define SONY_PIC_DRIVER_NAME "Sony Programmable IO Control Driver"
+#define SONY_WMMX_GUID "F6CB5C3C-9CAE-4EBD-B577-931EA32A2CC0"
+
MODULE_AUTHOR("Stelian Pop, Mattia Dongili");
MODULE_DESCRIPTION("Sony laptop extras driver (SPIC and SNC ACPI device)");
MODULE_LICENSE("GPL");
@@ -115,6 +118,11 @@ MODULE_PARM_DESC(camera,
"set this to 1 to enable Motion Eye camera controls "
"(only use it if you have a C1VE or C1VN model)");
+static int speed_stamina;
+module_param(speed_stamina, int, 0444);
+MODULE_PARM_DESC(speed_stamina,
+ "Set this to 1 to enable SPEED mode on module load (EXPERIMENTAL)");
+
#ifdef CONFIG_SONYPI_COMPAT
static int minor = -1;
module_param(minor, int, 0);
@@ -475,9 +483,158 @@ static void sony_laptop_remove_input(voi
}
/*********** Platform Device ***********/
+static int sony_ovga_dsm(int func, int arg)
+{
+ static const char *path = "\\_SB.PCI0.OVGA._DSM";
+ static const char muid[] = {
+ /*00*/ 0xA0, 0xA0, 0x95, 0x9D, 0x60, 0x00, 0x48, 0x4D, /* MUID */
+ /*08*/ 0xB3, 0x4D, 0x7E, 0x5F, 0xEA, 0x12, 0x9F, 0xD4,
+ };
+
+ struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+ struct acpi_object_list input;
+ union acpi_object params[4];
+ union acpi_object *obj;
+ int result;
+
+ input.count = 4;
+ input.pointer = params;
+ params[0].type = ACPI_TYPE_BUFFER;
+ params[0].buffer.length = sizeof(muid);
+ params[0].buffer.pointer = muid;
+ params[1].type = ACPI_TYPE_INTEGER;
+ params[1].integer.value = 0x00000102;
+ params[2].type = ACPI_TYPE_INTEGER;
+ params[2].integer.value = func;
+ params[3].type = ACPI_TYPE_INTEGER;
+ params[3].integer.value = arg;
+
+ result = acpi_evaluate_object(NULL, path, &input, &output);
+ if (result) {
+ printk("%s failed: %d\n", path, result);
+ return -1;
+ }
+
+ obj = (union acpi_object*)output.pointer;
+ printk("result type %d\n", obj->type);
+ if (obj->type == ACPI_TYPE_PACKAGE) {
+ int i;
+ printk("returned package sized %d\n", obj->package.count);
+ for (i = 0; i < obj->package.count; i++)
+ printk("%d %08x\n", i, obj->package.elements[i].integer.value);
+ } else
+ if (obj->type == ACPI_TYPE_INTEGER) {
+ printk("returned integer %08X\n", obj->integer.value);
+ } else
+ if (obj->type == ACPI_TYPE_BUFFER) {
+ int i;
+ printk("returned buffer sized %d\n", obj->buffer.length);
+ for (i = 0; i < obj->buffer.length; i++)
+ printk("%d %02x\n", i, obj->buffer.pointer[i]);
+ }
+ kfree(output.pointer);
+
+ return 0;
+}
+
+static int sony_led_stamina(void)
+{
+ return sony_ovga_dsm(2, 0x11);
+}
+
+static int sony_led_speed(void)
+{
+ return sony_ovga_dsm(2, 0x12);
+}
+
+static int sony_led_off(void)
+{
+ return sony_ovga_dsm(2, 0x13);
+}
+
+static int sony_dgpu_sta(void)
+{
+ return sony_ovga_dsm(3, 0x00);
+}
+
+static int sony_dgpu_off(void)
+{
+ return sony_ovga_dsm(3, 0x02);
+}
+
+static int sony_dgpu_on(void)
+{
+ return sony_ovga_dsm(3, 0x01);
+}
+
+static ssize_t sony_pf_store_speed_stamina(struct device *dev,
+ struct device_attribute *attr,
+ const char *buffer, size_t count)
+{
+ if (!strncmp(buffer, "speed", strlen("speed"))) {
+ sony_dgpu_on();
+ sony_led_speed();
+ speed_stamina = 1;
+ } else
+ if (!strncmp(buffer, "stamina", strlen("stamina"))) {
+ sony_dgpu_off();
+ sony_led_stamina();
+ speed_stamina = 0;
+ } else
+ return -EINVAL;
+
+ return count;
+}
+
+static ssize_t sony_pf_show_speed_stamina(struct device *dev,
+ struct device_attribute *attr, char *buffer)
+{
+ return snprintf(buffer, PAGE_SIZE, "%s\n", speed_stamina ? "speed":"stamina");
+}
+
+static struct device_attribute sony_pf_speed_stamina_attr =
+ __ATTR(speed_stamina, S_IWUSR|S_IRUGO,
+ sony_pf_show_speed_stamina, sony_pf_store_speed_stamina);
+
+static int sony_pf_probe(struct platform_device *pdev)
+{
+ int result;
+
+ result = device_create_file(&pdev->dev, &sony_pf_speed_stamina_attr);
+ if (result)
+ printk(KERN_DEBUG "sony_pf_probe: failed to add speed/stamina switch\n");
+
+ /* initialize default, look at module param speed_stamina */
+ if (speed_stamina == 1) {
+ sony_dgpu_on();
+ sony_led_speed();
+ } else {
+ sony_dgpu_off();
+ sony_led_stamina();
+ }
+
+ return 0;
+}
+
+static int sony_pf_resume(struct platform_device *pdev)
+{
+ /* on resume, restore previous state */
+ if (speed_stamina == 1) {
+ sony_dgpu_on();
+ sony_led_speed();
+ } else {
+ sony_dgpu_off();
+ sony_led_stamina();
+ }
+ return 0;
+}
static atomic_t sony_pf_users = ATOMIC_INIT(0);
static struct platform_driver sony_pf_driver = {
+ .probe = sony_pf_probe,
+#ifdef CONFIG_PM
+ .resume_early = sony_pf_resume,
+#endif
.driver = {
.name = "sony-laptop",
.owner = THIS_MODULE,
@@ -775,6 +932,36 @@ static ssize_t sony_nc_sysfs_store(struc
return count;
}
+/* WWAN power */
+static ssize_t sony_wwanpower_show(struct device *dev, struct device_attribute *attr,
+ char *buffer)
+{
+ return 0;
+}
+
+static ssize_t sony_wwanpower_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buffer, size_t count)
+{
+ int value;
+
+ value = strtoul(buffer, NULL, 10);
+ if ( (value < 0) || (value > 1) )
+ return -EINVAL;
+
+ if (value) {
+ if (acpi_callsetfunc(sony_nc_acpi_handle, "SN07", 0x9f070803, NULL) < 0)
+ return -EIO;
+ } else {
+ if (acpi_callsetfunc(sony_nc_acpi_handle, "SN07", 0x00000803, NULL) < 0)
+ return -EIO;
+ }
+
+ return count;
+}
+
+static struct device_attribute wwanpower_attr =
+ __ATTR(snc_wwanpower, S_IRUGO|S_IWUSR, sony_wwanpower_show, sony_wwanpower_store);
/*
* Backlight device
@@ -889,6 +1076,15 @@ static const struct dmi_system_id sony_n
DMI_MATCH(DMI_PRODUCT_NAME, "VGN-N"),
},
},
+ {
+ .ident = "Sony Vaio Z Series",
+ .callback = sony_nc_C_enable,
+ .driver_data = sony_C_events,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "VGN-Z"),
+ },
+ },
{ }
};
@@ -935,17 +1131,14 @@ static void sony_acpi_notify(acpi_handle
static acpi_status sony_walk_callback(acpi_handle handle, u32 level,
void *context, void **return_value)
{
- struct acpi_device_info *info;
- struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+ struct acpi_namespace_node *node;
+ union acpi_operand_object *operand;
- if (ACPI_SUCCESS(acpi_get_object_info(handle, &buffer))) {
- info = buffer.pointer;
+ node = (struct acpi_namespace_node *)handle;
+ operand = (union acpi_operand_object *)node->object;
- printk(KERN_WARNING DRV_PFX "method: name: %4.4s, args %X\n",
- (char *)&info->name, info->param_count);
-
- kfree(buffer.pointer);
- }
+ printk(KERN_WARNING DRV_PFX "method: name: %4.4s, args %X\n", node->name.ascii,
+ (u32) operand->method.param_count);
return AE_OK;
}
@@ -973,7 +1166,7 @@ static int sony_nc_resume(struct acpi_de
/* set the last requested brightness level */
if (sony_backlight_device &&
!sony_backlight_update_status(sony_backlight_device))
- printk(KERN_WARNING DRV_PFX "unable to restore brightness level\n");
+ printk(KERN_WARNING DRV_PFX "unable to restore brightness level");
/* re-initialize models with specific requirements */
dmi_check_system(sony_nc_ids);
@@ -1023,6 +1216,11 @@ static int sony_nc_add(struct acpi_devic
NULL, NULL)))
dprintk("_INI Method failed\n");
}
+#if 0
+ /* try to _INI the ECON variable */
+ if (acpi_callsetfunc(sony_nc_acpi_handle, "ECON", 1, &result))
+ dprintk("ECON Method failed\n");
+#endif
/* setup input devices and helper fifo */
result = sony_laptop_setup_input(device);
@@ -1042,7 +1240,7 @@ static int sony_nc_add(struct acpi_devic
}
if (acpi_video_backlight_support()) {
- printk(KERN_INFO DRV_PFX "brightness ignored, must be "
+ printk(KERN_INFO DRV_PFX "Sony: Brightness ignored, must be "
"controlled by ACPI video driver\n");
} else if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT",
&handle))) {
@@ -1109,6 +1307,10 @@ static int sony_nc_add(struct acpi_devic
}
}
+ result = device_create_file(&sony_pf_device->dev, &wwanpower_attr);
+ if (result)
+ goto out_sysfs;
+
return 0;
out_sysfs:
@@ -1927,6 +2129,7 @@ static int sonypi_misc_fasync(int fd, st
static int sonypi_misc_release(struct inode *inode, struct file *file)
{
+ sonypi_misc_fasync(-1, file, 0);
atomic_dec(&sonypi_compat.open_count);
return 0;
}