sony-laptop: add Type4 model
authorMattia Dongili <malattia@linux.it>
Mon, 14 Jan 2008 09:05:45 +0000 (18:05 +0900)
committerLen Brown <len.brown@intel.com>
Thu, 24 Jan 2008 05:47:27 +0000 (00:47 -0500)
Recent Vaio models (UX, SZ and presumably TZ and others) add more
events and a slightly different handling of Fn key events for
additional hotkeys (s1, s2, zoom-in/out, etc.).

Signed-off-by: Mattia Dongili <malattia@linux.it>
Signed-off-by: Len Brown <len.brown@intel.com>
drivers/misc/sony-laptop.c
include/linux/sonypi.h

index 9869286..70d5cc5 100644 (file)
@@ -146,68 +146,70 @@ struct sony_laptop_keypress {
  * and input layer indexes in the keymap
  */
 static int sony_laptop_input_index[] = {
-       -1,     /* no event */
-       -1,     /* SONYPI_EVENT_JOGDIAL_DOWN */
-       -1,     /* SONYPI_EVENT_JOGDIAL_UP */
-       -1,     /* SONYPI_EVENT_JOGDIAL_DOWN_PRESSED */
-       -1,     /* SONYPI_EVENT_JOGDIAL_UP_PRESSED */
-       -1,     /* SONYPI_EVENT_JOGDIAL_PRESSED */
-       -1,     /* SONYPI_EVENT_JOGDIAL_RELEASED */
-        0,     /* SONYPI_EVENT_CAPTURE_PRESSED */
-        1,     /* SONYPI_EVENT_CAPTURE_RELEASED */
-        2,     /* SONYPI_EVENT_CAPTURE_PARTIALPRESSED */
-        3,     /* SONYPI_EVENT_CAPTURE_PARTIALRELEASED */
-        4,     /* SONYPI_EVENT_FNKEY_ESC */
-        5,     /* SONYPI_EVENT_FNKEY_F1 */
-        6,     /* SONYPI_EVENT_FNKEY_F2 */
-        7,     /* SONYPI_EVENT_FNKEY_F3 */
-        8,     /* SONYPI_EVENT_FNKEY_F4 */
-        9,     /* SONYPI_EVENT_FNKEY_F5 */
-       10,     /* SONYPI_EVENT_FNKEY_F6 */
-       11,     /* SONYPI_EVENT_FNKEY_F7 */
-       12,     /* SONYPI_EVENT_FNKEY_F8 */
-       13,     /* SONYPI_EVENT_FNKEY_F9 */
-       14,     /* SONYPI_EVENT_FNKEY_F10 */
-       15,     /* SONYPI_EVENT_FNKEY_F11 */
-       16,     /* SONYPI_EVENT_FNKEY_F12 */
-       17,     /* SONYPI_EVENT_FNKEY_1 */
-       18,     /* SONYPI_EVENT_FNKEY_2 */
-       19,     /* SONYPI_EVENT_FNKEY_D */
-       20,     /* SONYPI_EVENT_FNKEY_E */
-       21,     /* SONYPI_EVENT_FNKEY_F */
-       22,     /* SONYPI_EVENT_FNKEY_S */
-       23,     /* SONYPI_EVENT_FNKEY_B */
-       24,     /* SONYPI_EVENT_BLUETOOTH_PRESSED */
-       25,     /* SONYPI_EVENT_PKEY_P1 */
-       26,     /* SONYPI_EVENT_PKEY_P2 */
-       27,     /* SONYPI_EVENT_PKEY_P3 */
-       28,     /* SONYPI_EVENT_BACK_PRESSED */
-       -1,     /* SONYPI_EVENT_LID_CLOSED */
-       -1,     /* SONYPI_EVENT_LID_OPENED */
-       29,     /* SONYPI_EVENT_BLUETOOTH_ON */
-       30,     /* SONYPI_EVENT_BLUETOOTH_OFF */
-       31,     /* SONYPI_EVENT_HELP_PRESSED */
-       32,     /* SONYPI_EVENT_FNKEY_ONLY */
-       33,     /* SONYPI_EVENT_JOGDIAL_FAST_DOWN */
-       34,     /* SONYPI_EVENT_JOGDIAL_FAST_UP */
-       35,     /* SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED */
-       36,     /* SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED */
-       37,     /* SONYPI_EVENT_JOGDIAL_VFAST_DOWN */
-       38,     /* SONYPI_EVENT_JOGDIAL_VFAST_UP */
-       39,     /* SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED */
-       40,     /* SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED */
-       41,     /* SONYPI_EVENT_ZOOM_PRESSED */
-       42,     /* SONYPI_EVENT_THUMBPHRASE_PRESSED */
-       43,     /* SONYPI_EVENT_MEYE_FACE */
-       44,     /* SONYPI_EVENT_MEYE_OPPOSITE */
-       45,     /* SONYPI_EVENT_MEMORYSTICK_INSERT */
-       46,     /* SONYPI_EVENT_MEMORYSTICK_EJECT */
-       -1,     /* SONYPI_EVENT_ANYBUTTON_RELEASED */
-       -1,     /* SONYPI_EVENT_BATTERY_INSERT */
-       -1,     /* SONYPI_EVENT_BATTERY_REMOVE */
-       -1,     /* SONYPI_EVENT_FNKEY_RELEASED */
-       47,     /* SONYPI_EVENT_WIRELESS_ON */
-       48,     /* SONYPI_EVENT_WIRELESS_OFF */
+       -1,     /*  0 no event */
+       -1,     /*  1 SONYPI_EVENT_JOGDIAL_DOWN */
+       -1,     /*  2 SONYPI_EVENT_JOGDIAL_UP */
+       -1,     /*  3 SONYPI_EVENT_JOGDIAL_DOWN_PRESSED */
+       -1,     /*  4 SONYPI_EVENT_JOGDIAL_UP_PRESSED */
+       -1,     /*  5 SONYPI_EVENT_JOGDIAL_PRESSED */
+       -1,     /*  6 SONYPI_EVENT_JOGDIAL_RELEASED */
+        0,     /*  7 SONYPI_EVENT_CAPTURE_PRESSED */
+        1,     /*  8 SONYPI_EVENT_CAPTURE_RELEASED */
+        2,     /*  9 SONYPI_EVENT_CAPTURE_PARTIALPRESSED */
+        3,     /* 10 SONYPI_EVENT_CAPTURE_PARTIALRELEASED */
+        4,     /* 11 SONYPI_EVENT_FNKEY_ESC */
+        5,     /* 12 SONYPI_EVENT_FNKEY_F1 */
+        6,     /* 13 SONYPI_EVENT_FNKEY_F2 */
+        7,     /* 14 SONYPI_EVENT_FNKEY_F3 */
+        8,     /* 15 SONYPI_EVENT_FNKEY_F4 */
+        9,     /* 16 SONYPI_EVENT_FNKEY_F5 */
+       10,     /* 17 SONYPI_EVENT_FNKEY_F6 */
+       11,     /* 18 SONYPI_EVENT_FNKEY_F7 */
+       12,     /* 19 SONYPI_EVENT_FNKEY_F8 */
+       13,     /* 20 SONYPI_EVENT_FNKEY_F9 */
+       14,     /* 21 SONYPI_EVENT_FNKEY_F10 */
+       15,     /* 22 SONYPI_EVENT_FNKEY_F11 */
+       16,     /* 23 SONYPI_EVENT_FNKEY_F12 */
+       17,     /* 24 SONYPI_EVENT_FNKEY_1 */
+       18,     /* 25 SONYPI_EVENT_FNKEY_2 */
+       19,     /* 26 SONYPI_EVENT_FNKEY_D */
+       20,     /* 27 SONYPI_EVENT_FNKEY_E */
+       21,     /* 28 SONYPI_EVENT_FNKEY_F */
+       22,     /* 29 SONYPI_EVENT_FNKEY_S */
+       23,     /* 30 SONYPI_EVENT_FNKEY_B */
+       24,     /* 31 SONYPI_EVENT_BLUETOOTH_PRESSED */
+       25,     /* 32 SONYPI_EVENT_PKEY_P1 */
+       26,     /* 33 SONYPI_EVENT_PKEY_P2 */
+       27,     /* 34 SONYPI_EVENT_PKEY_P3 */
+       28,     /* 35 SONYPI_EVENT_BACK_PRESSED */
+       -1,     /* 36 SONYPI_EVENT_LID_CLOSED */
+       -1,     /* 37 SONYPI_EVENT_LID_OPENED */
+       29,     /* 38 SONYPI_EVENT_BLUETOOTH_ON */
+       30,     /* 39 SONYPI_EVENT_BLUETOOTH_OFF */
+       31,     /* 40 SONYPI_EVENT_HELP_PRESSED */
+       32,     /* 41 SONYPI_EVENT_FNKEY_ONLY */
+       33,     /* 42 SONYPI_EVENT_JOGDIAL_FAST_DOWN */
+       34,     /* 43 SONYPI_EVENT_JOGDIAL_FAST_UP */
+       35,     /* 44 SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED */
+       36,     /* 45 SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED */
+       37,     /* 46 SONYPI_EVENT_JOGDIAL_VFAST_DOWN */
+       38,     /* 47 SONYPI_EVENT_JOGDIAL_VFAST_UP */
+       39,     /* 48 SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED */
+       40,     /* 49 SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED */
+       41,     /* 50 SONYPI_EVENT_ZOOM_PRESSED */
+       42,     /* 51 SONYPI_EVENT_THUMBPHRASE_PRESSED */
+       43,     /* 52 SONYPI_EVENT_MEYE_FACE */
+       44,     /* 53 SONYPI_EVENT_MEYE_OPPOSITE */
+       45,     /* 54 SONYPI_EVENT_MEMORYSTICK_INSERT */
+       46,     /* 55 SONYPI_EVENT_MEMORYSTICK_EJECT */
+       -1,     /* 56 SONYPI_EVENT_ANYBUTTON_RELEASED */
+       -1,     /* 57 SONYPI_EVENT_BATTERY_INSERT */
+       -1,     /* 58 SONYPI_EVENT_BATTERY_REMOVE */
+       -1,     /* 59 SONYPI_EVENT_FNKEY_RELEASED */
+       47,     /* 60 SONYPI_EVENT_WIRELESS_ON */
+       48,     /* 61 SONYPI_EVENT_WIRELESS_OFF */
+       49,     /* 62 SONYPI_EVENT_ZOOM_IN_PRESSED */
+       50,     /* 63 SONYPI_EVENT_ZOOM_OUT_PRESSED */
 };
 
 static int sony_laptop_input_keycode_map[] = {
@@ -260,6 +262,8 @@ static int sony_laptop_input_keycode_map[] = {
        KEY_RESERVED,   /* 46 SONYPI_EVENT_MEMORYSTICK_EJECT */
        KEY_WLAN,       /* 47 SONYPI_EVENT_WIRELESS_ON */
        KEY_WLAN,       /* 48 SONYPI_EVENT_WIRELESS_OFF */
+       KEY_ZOOMIN,     /* 49 SONYPI_EVENT_ZOOM_IN_PRESSED */
+       KEY_ZOOMOUT     /* 50 SONYPI_EVENT_ZOOM_OUT_PRESSED */
 };
 
 /* release buttons after a short delay if pressed */
@@ -1178,10 +1182,12 @@ static struct acpi_driver sony_nc_driver = {
 #define SONYPI_DEVICE_TYPE1    0x00000001
 #define SONYPI_DEVICE_TYPE2    0x00000002
 #define SONYPI_DEVICE_TYPE3    0x00000004
+#define SONYPI_DEVICE_TYPE4    0x00000008
 
 #define SONYPI_TYPE1_OFFSET    0x04
 #define SONYPI_TYPE2_OFFSET    0x12
 #define SONYPI_TYPE3_OFFSET    0x12
+#define SONYPI_TYPE4_OFFSET    0x12
 
 struct sony_pic_ioport {
        struct acpi_resource_io io1;
@@ -1202,7 +1208,7 @@ struct sonypi_eventtypes {
 
 struct device_ctrl {
        int                             model;
-       int                             (*handle_irq)(void);
+       int                             (*handle_irq)(const u8, const u8);
        u16                             evport_offset;
        u8                              has_camera;
        u8                              has_bluetooth;
@@ -1277,6 +1283,7 @@ static struct sonypi_event sonypi_joggerev[] = {
 static struct sonypi_event sonypi_captureev[] = {
        { 0x05, SONYPI_EVENT_CAPTURE_PARTIALPRESSED },
        { 0x07, SONYPI_EVENT_CAPTURE_PRESSED },
+       { 0x40, SONYPI_EVENT_CAPTURE_PRESSED },
        { 0x01, SONYPI_EVENT_CAPTURE_PARTIALRELEASED },
        { 0, 0 }
 };
@@ -1313,7 +1320,6 @@ static struct sonypi_event sonypi_pkeyev[] = {
        { 0x01, SONYPI_EVENT_PKEY_P1 },
        { 0x02, SONYPI_EVENT_PKEY_P2 },
        { 0x04, SONYPI_EVENT_PKEY_P3 },
-       { 0x5c, SONYPI_EVENT_PKEY_P1 },
        { 0, 0 }
 };
 
@@ -1355,6 +1361,8 @@ static struct sonypi_event sonypi_lidev[] = {
 /* The set of possible zoom events */
 static struct sonypi_event sonypi_zoomev[] = {
        { 0x39, SONYPI_EVENT_ZOOM_PRESSED },
+       { 0x10, SONYPI_EVENT_ZOOM_IN_PRESSED },
+       { 0x20, SONYPI_EVENT_ZOOM_OUT_PRESSED },
        { 0, 0 }
 };
 
@@ -1424,55 +1432,19 @@ static struct sonypi_eventtypes type3_events[] = {
        { 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev },
        { 0 },
 };
-
-static struct device_ctrl spic_types[] = {
-       {
-               .model = SONYPI_DEVICE_TYPE1,
-               .handle_irq = NULL,
-               .evport_offset = SONYPI_TYPE1_OFFSET,
-               .event_types = type1_events,
-       },
-       {
-               .model = SONYPI_DEVICE_TYPE2,
-               .handle_irq = NULL,
-               .evport_offset = SONYPI_TYPE2_OFFSET,
-               .event_types = type2_events,
-       },
-       {
-               .model = SONYPI_DEVICE_TYPE3,
-               .handle_irq = NULL,
-               .evport_offset = SONYPI_TYPE3_OFFSET,
-               .event_types = type3_events,
-       },
+static struct sonypi_eventtypes type4_events[] = {
+       { 0, 0xffffffff, sonypi_releaseev },
+       { 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
+       { 0x31, SONYPI_WIRELESS_MASK, sonypi_wlessev },
+       { 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
+       { 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev },
+       { 0x05, SONYPI_PKEY_MASK, sonypi_pkeyev },
+       { 0x05, SONYPI_ZOOM_MASK, sonypi_zoomev },
+       { 0x05, SONYPI_CAPTURE_MASK, sonypi_captureev },
+       { 0 },
 };
 
-static void sony_pic_detect_device_type(struct sony_pic_dev *dev)
-{
-       struct pci_dev *pcidev;
-
-       if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
-                                    PCI_DEVICE_ID_INTEL_82371AB_3, NULL)))
-               dev->control = &spic_types[0];
-
-       else if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
-                                         PCI_DEVICE_ID_INTEL_ICH6_1, NULL)))
-               dev->control = &spic_types[2];
-
-       else if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
-                                         PCI_DEVICE_ID_INTEL_ICH7_1, NULL)))
-               dev->control = &spic_types[2];
-
-       else
-               dev->control = &spic_types[1];
-
-       if (pcidev)
-               pci_dev_put(pcidev);
-
-       printk(KERN_INFO DRV_PFX "detected Type%d model\n",
-                       dev->control->model == SONYPI_DEVICE_TYPE1 ? 1 :
-                       dev->control->model == SONYPI_DEVICE_TYPE2 ? 2 : 3);
-}
-
+/* low level spic calls */
 #define ITERATIONS_LONG                10000
 #define ITERATIONS_SHORT       10
 #define wait_on_command(command, iterations) {                         \
@@ -1528,6 +1500,100 @@ static u8 sony_pic_call3(u8 dev, u8 fn, u8 v)
        return v1;
 }
 
+/*
+ * minidrivers for SPIC models
+ */
+static int type4_handle_irq(const u8 data_mask, const u8 ev)
+{
+       /*
+        * 0x31 could mean we have to take some extra action and wait for
+        * the next irq for some Type4 models, it will generate a new
+        * irq and we can read new data from the device:
+        *  - 0x5c and 0x5f requires 0xA0
+        *  - 0x61 requires 0xB3
+        */
+       if (data_mask == 0x31) {
+               if (ev == 0x5c || ev == 0x5f)
+                       sony_pic_call1(0xA0);
+               else if (ev == 0x61)
+                       sony_pic_call1(0xB3);
+               return 0;
+       }
+       return 1;
+}
+
+static struct device_ctrl spic_types[] = {
+       {
+               .model = SONYPI_DEVICE_TYPE1,
+               .handle_irq = NULL,
+               .evport_offset = SONYPI_TYPE1_OFFSET,
+               .event_types = type1_events,
+       },
+       {
+               .model = SONYPI_DEVICE_TYPE2,
+               .handle_irq = NULL,
+               .evport_offset = SONYPI_TYPE2_OFFSET,
+               .event_types = type2_events,
+       },
+       {
+               .model = SONYPI_DEVICE_TYPE3,
+               .handle_irq = NULL,
+               .evport_offset = SONYPI_TYPE3_OFFSET,
+               .event_types = type3_events,
+       },
+       {
+               .model = SONYPI_DEVICE_TYPE4,
+               .handle_irq = type4_handle_irq,
+               .evport_offset = SONYPI_TYPE4_OFFSET,
+               .event_types = type4_events,
+       },
+};
+
+static void sony_pic_detect_device_type(struct sony_pic_dev *dev)
+{
+       struct pci_dev *pcidev;
+
+       pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
+                       PCI_DEVICE_ID_INTEL_82371AB_3, NULL);
+       if (pcidev) {
+               dev->control = &spic_types[0];
+               goto out;
+       }
+
+       pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
+                       PCI_DEVICE_ID_INTEL_ICH6_1, NULL);
+       if (pcidev) {
+               dev->control = &spic_types[2];
+               goto out;
+       }
+
+       pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
+                       PCI_DEVICE_ID_INTEL_ICH7_1, NULL);
+       if (pcidev) {
+               dev->control = &spic_types[3];
+               goto out;
+       }
+
+       pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
+                       PCI_DEVICE_ID_INTEL_ICH8_4, NULL);
+       if (pcidev) {
+               dev->control = &spic_types[3];
+               goto out;
+       }
+
+       /* default */
+       dev->control = &spic_types[1];
+
+out:
+       if (pcidev)
+               pci_dev_put(pcidev);
+
+       printk(KERN_INFO DRV_PFX "detected Type%d model\n",
+                       dev->control->model == SONYPI_DEVICE_TYPE1 ? 1 :
+                       dev->control->model == SONYPI_DEVICE_TYPE2 ? 2 :
+                       dev->control->model == SONYPI_DEVICE_TYPE3 ? 3 : 4);
+}
+
 /* camera tests and poweron/poweroff */
 #define SONYPI_CAMERA_PICTURE          5
 #define SONYPI_CAMERA_CONTROL          0x10
@@ -2406,6 +2472,13 @@ static irqreturn_t sony_pic_irq(int irq, void *dev_id)
                        }
                }
        }
+       /* Still not able to decode the event try to pass
+        * it over to the minidriver
+        */
+       if (dev->control->handle_irq &&
+                       dev->control->handle_irq(data_mask, ev) == 0)
+               return IRQ_HANDLED;
+
        dprintk("unknown event ([%.2x] [%.2x]) at port 0x%.4x(+0x%.2x)\n",
                        ev, data_mask, dev->cur_ioport->io1.minimum,
                        dev->control->evport_offset);
index 40c7b5d..f41ffd7 100644 (file)
 #define SONYPI_EVENT_FNKEY_RELEASED            59
 #define SONYPI_EVENT_WIRELESS_ON               60
 #define SONYPI_EVENT_WIRELESS_OFF              61
+#define SONYPI_EVENT_ZOOM_IN_PRESSED           62
+#define SONYPI_EVENT_ZOOM_OUT_PRESSED          63
 
 /* get/set brightness */
 #define SONYPI_IOCGBRT         _IOR('v', 0, __u8)