From: Erik Waling Newer Sony VAIO models (VGN-S480, VGN-S460, VGN-S3XP etc) use a new method to initialize the SPIC device. The new way to initialize (and disable) the device comes directly from the AML code in the _CRS, _SRS and _DIS methods from the DSDT table. This patch adds support for the new models. Signed-off-by: Erik Waling Signed-off-by: Stelian Pop Signed-off-by: Andrew Morton --- Documentation/sonypi.txt | 10 ++++ drivers/char/sonypi.c | 117 ++++++++++++++++++++++++++++++++++++++--------- include/linux/sonypi.h | 2 3 files changed, 109 insertions(+), 20 deletions(-) diff -puN Documentation/sonypi.txt~sonypi-spic-initialisation-fix Documentation/sonypi.txt --- devel/Documentation/sonypi.txt~sonypi-spic-initialisation-fix 2005-08-01 17:39:24.000000000 -0700 +++ devel-akpm/Documentation/sonypi.txt 2005-08-01 17:39:24.000000000 -0700 @@ -99,6 +99,7 @@ statically linked into the kernel). Thos SONYPI_MEYE_MASK 0x0400 SONYPI_MEMORYSTICK_MASK 0x0800 SONYPI_BATTERY_MASK 0x1000 + SONYPI_WIRELESS_MASK 0x2000 useinput: if set (which is the default) two input devices are created, one which interprets the jogdial events as @@ -137,6 +138,15 @@ Bugs: speed handling etc). Use ACPI instead of APM if it works on your laptop. + - sonypi lacks the ability to distinguish between certain key + events on some models. + + - some models with the nvidia card (geforce go 6200 tc) uses a + different way to adjust the backlighting of the screen. There + is a userspace utility to adjust the brightness on those models, + which can be downloaded from + http://www.acc.umu.se/~erikw/program/smartdimmer-0.1.tar.bz2 + - since all development was done by reverse engineering, there is _absolutely no guarantee_ that this driver will not crash your laptop. Permanently. diff -puN drivers/char/sonypi.c~sonypi-spic-initialisation-fix drivers/char/sonypi.c --- devel/drivers/char/sonypi.c~sonypi-spic-initialisation-fix 2005-08-01 17:39:24.000000000 -0700 +++ devel-akpm/drivers/char/sonypi.c 2005-08-01 17:39:24.000000000 -0700 @@ -98,12 +98,13 @@ MODULE_PARM_DESC(useinput, #define SONYPI_DEVICE_MODEL_TYPE1 1 #define SONYPI_DEVICE_MODEL_TYPE2 2 +#define SONYPI_DEVICE_MODEL_TYPE3 3 /* type1 models use those */ #define SONYPI_IRQ_PORT 0x8034 #define SONYPI_IRQ_SHIFT 22 -#define SONYPI_BASE 0x50 -#define SONYPI_G10A (SONYPI_BASE+0x14) +#define SONYPI_TYPE1_BASE 0x50 +#define SONYPI_G10A (SONYPI_TYPE1_BASE+0x14) #define SONYPI_TYPE1_REGION_SIZE 0x08 #define SONYPI_TYPE1_EVTYPE_OFFSET 0x04 @@ -114,6 +115,13 @@ MODULE_PARM_DESC(useinput, #define SONYPI_TYPE2_REGION_SIZE 0x20 #define SONYPI_TYPE2_EVTYPE_OFFSET 0x12 +/* type3 series specifics */ +#define SONYPI_TYPE3_BASE 0x40 +#define SONYPI_TYPE3_GID2 (SONYPI_TYPE3_BASE+0x48) /* 16 bits */ +#define SONYPI_TYPE3_MISC (SONYPI_TYPE3_BASE+0x6d) /* 8 bits */ +#define SONYPI_TYPE3_REGION_SIZE 0x20 +#define SONYPI_TYPE3_EVTYPE_OFFSET 0x12 + /* battery / brightness addresses */ #define SONYPI_BAT_FLAGS 0x81 #define SONYPI_LCD_LIGHT 0x96 @@ -159,6 +167,10 @@ static struct sonypi_ioport_list sonypi_ { 0x0, 0x0 } }; +/* same as in type 2 models */ +static struct sonypi_ioport_list *sonypi_type3_ioport_list = + sonypi_type2_ioport_list; + /* The set of possible interrupts */ struct sonypi_irq_list { u16 irq; @@ -180,6 +192,9 @@ static struct sonypi_irq_list sonypi_typ { 0, 0x00 } /* no IRQ, 0x00 in SIRQ in AML */ }; +/* same as in type2 models */ +static struct sonypi_irq_list *sonypi_type3_irq_list = sonypi_type2_irq_list; + #define SONYPI_CAMERA_BRIGHTNESS 0 #define SONYPI_CAMERA_CONTRAST 1 #define SONYPI_CAMERA_HUE 2 @@ -223,6 +238,7 @@ static struct sonypi_irq_list sonypi_typ #define SONYPI_MEYE_MASK 0x00000400 #define SONYPI_MEMORYSTICK_MASK 0x00000800 #define SONYPI_BATTERY_MASK 0x00001000 +#define SONYPI_WIRELESS_MASK 0x00002000 struct sonypi_event { u8 data; @@ -305,6 +321,13 @@ static struct sonypi_event sonypi_blueev { 0, 0 } }; +/* The set of possible wireless events */ +static struct sonypi_event sonypi_wlessev[] = { + { 0x59, SONYPI_EVENT_WIRELESS_ON }, + { 0x5a, SONYPI_EVENT_WIRELESS_OFF }, + { 0, 0 } +}; + /* The set of possible back button events */ static struct sonypi_event sonypi_backev[] = { { 0x20, SONYPI_EVENT_BACK_PRESSED }, @@ -391,6 +414,12 @@ static struct sonypi_eventtypes { { SONYPI_DEVICE_MODEL_TYPE2, 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev }, { SONYPI_DEVICE_MODEL_TYPE2, 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev }, + { SONYPI_DEVICE_MODEL_TYPE3, 0, 0xffffffff, sonypi_releaseev }, + { SONYPI_DEVICE_MODEL_TYPE3, 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev }, + { SONYPI_DEVICE_MODEL_TYPE3, 0x31, SONYPI_WIRELESS_MASK, sonypi_wlessev }, + { SONYPI_DEVICE_MODEL_TYPE3, 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev }, + { SONYPI_DEVICE_MODEL_TYPE3, 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev }, + { SONYPI_DEVICE_MODEL_TYPE3, 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev }, { 0 } }; @@ -563,6 +592,23 @@ static void sonypi_type2_srs(void) udelay(10); } +static void sonypi_type3_srs(void) +{ + u16 v16; + u8 v8; + + /* This model type uses the same initialiazation of + * the embedded controller as the type2 models. */ + sonypi_type2_srs(); + + /* Initialization of PCI config space of the LPC interface bridge. */ + v16 = (sonypi_device.ioport1 & 0xFFF0) | 0x01; + pci_write_config_word(sonypi_device.dev, SONYPI_TYPE3_GID2, v16); + pci_read_config_byte(sonypi_device.dev, SONYPI_TYPE3_MISC, &v8); + v8 = (v8 & 0xCF) | 0x10; + pci_write_config_byte(sonypi_device.dev, SONYPI_TYPE3_MISC, v8); +} + /* Disables the device - this comes from the AML code in the ACPI bios */ static void sonypi_type1_dis(void) { @@ -587,6 +633,13 @@ static void sonypi_type2_dis(void) printk(KERN_WARNING "ec_write failed\n"); } +static void sonypi_type3_dis(void) +{ + sonypi_type2_dis(); + udelay(10); + pci_write_config_word(sonypi_device.dev, SONYPI_TYPE3_GID2, 0); +} + static u8 sonypi_call1(u8 dev) { u8 v1, v2; @@ -1067,10 +1120,17 @@ static struct miscdevice sonypi_misc_dev static void sonypi_enable(unsigned int camera_on) { - if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2) - sonypi_type2_srs(); - else + switch (sonypi_device.model) { + case SONYPI_DEVICE_MODEL_TYPE1: sonypi_type1_srs(); + break; + case SONYPI_DEVICE_MODEL_TYPE2: + sonypi_type2_srs(); + break; + case SONYPI_DEVICE_MODEL_TYPE3: + sonypi_type3_srs(); + break; + } sonypi_call1(0x82); sonypi_call2(0x81, 0xff); @@ -1094,10 +1154,18 @@ static int sonypi_disable(void) if (!SONYPI_ACPI_ACTIVE && fnkeyinit) outb(0xf1, 0xb2); - if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2) - sonypi_type2_dis(); - else + switch (sonypi_device.model) { + case SONYPI_DEVICE_MODEL_TYPE1: sonypi_type1_dis(); + break; + case SONYPI_DEVICE_MODEL_TYPE2: + sonypi_type2_dis(); + break; + case SONYPI_DEVICE_MODEL_TYPE3: + sonypi_type3_dis(); + break; + } + return 0; } @@ -1143,12 +1211,16 @@ static int __devinit sonypi_probe(void) struct sonypi_irq_list *irq_list; struct pci_dev *pcidev; - pcidev = pci_get_device(PCI_VENDOR_ID_INTEL, - PCI_DEVICE_ID_INTEL_82371AB_3, NULL); + if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_82371AB_3, NULL))) + sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE1; + else if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_ICH6_1, NULL))) + sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE3; + else + sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE2; sonypi_device.dev = pcidev; - sonypi_device.model = pcidev ? - SONYPI_DEVICE_MODEL_TYPE1 : SONYPI_DEVICE_MODEL_TYPE2; spin_lock_init(&sonypi_device.fifo_lock); sonypi_device.fifo = kfifo_alloc(SONYPI_BUF_SIZE, GFP_KERNEL, @@ -1176,16 +1248,22 @@ static int __devinit sonypi_probe(void) goto out_miscreg; } - if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2) { + + if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE1) { + ioport_list = sonypi_type1_ioport_list; + sonypi_device.region_size = SONYPI_TYPE1_REGION_SIZE; + sonypi_device.evtype_offset = SONYPI_TYPE1_EVTYPE_OFFSET; + irq_list = sonypi_type1_irq_list; + } else if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2) { ioport_list = sonypi_type2_ioport_list; sonypi_device.region_size = SONYPI_TYPE2_REGION_SIZE; sonypi_device.evtype_offset = SONYPI_TYPE2_EVTYPE_OFFSET; irq_list = sonypi_type2_irq_list; } else { - ioport_list = sonypi_type1_ioport_list; - sonypi_device.region_size = SONYPI_TYPE1_REGION_SIZE; - sonypi_device.evtype_offset = SONYPI_TYPE1_EVTYPE_OFFSET; - irq_list = sonypi_type1_irq_list; + ioport_list = sonypi_type3_ioport_list; + sonypi_device.region_size = SONYPI_TYPE3_REGION_SIZE; + sonypi_device.evtype_offset = SONYPI_TYPE3_EVTYPE_OFFSET; + irq_list = sonypi_type3_irq_list; } for (i = 0; ioport_list[i].port1; i++) { @@ -1274,11 +1352,10 @@ static int __devinit sonypi_probe(void) printk(KERN_INFO "sonypi: Sony Programmable I/O Controller Driver" "v%s.\n", SONYPI_DRIVER_VERSION); - printk(KERN_INFO "sonypi: detected %s model, " + printk(KERN_INFO "sonypi: detected type%d model, " "verbose = %d, fnkeyinit = %s, camera = %s, " "compat = %s, mask = 0x%08lx, useinput = %s, acpi = %s\n", - (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE1) ? - "type1" : "type2", + sonypi_device.model, verbose, fnkeyinit ? "on" : "off", camera ? "on" : "off", diff -puN include/linux/sonypi.h~sonypi-spic-initialisation-fix include/linux/sonypi.h --- devel/include/linux/sonypi.h~sonypi-spic-initialisation-fix 2005-08-01 17:39:24.000000000 -0700 +++ devel-akpm/include/linux/sonypi.h 2005-08-01 17:39:24.000000000 -0700 @@ -99,6 +99,8 @@ #define SONYPI_EVENT_BATTERY_INSERT 57 #define SONYPI_EVENT_BATTERY_REMOVE 58 #define SONYPI_EVENT_FNKEY_RELEASED 59 +#define SONYPI_EVENT_WIRELESS_ON 60 +#define SONYPI_EVENT_WIRELESS_OFF 61 /* get/set brightness */ #define SONYPI_IOCGBRT _IOR('v', 0, __u8) _