From 75a1f9ce8f422fd32774a0674ed4386d07628d5e Mon Sep 17 00:00:00 2001 From: Mattia Dongili Date: Mon, 14 Jan 2008 18:05:41 +0900 Subject: sony-laptop: printk more info in sony_pic_call[123] Signed-off-by: Mattia Dongili Signed-off-by: Len Brown --- drivers/misc/sony-laptop.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/sony-laptop.c b/drivers/misc/sony-laptop.c index b0f68031b49..0435b3d6416 100644 --- a/drivers/misc/sony-laptop.c +++ b/drivers/misc/sony-laptop.c @@ -1451,7 +1451,7 @@ static u8 sony_pic_call1(u8 dev) outb(dev, spic_dev.cur_ioport->io1.minimum + 4); v1 = inb_p(spic_dev.cur_ioport->io1.minimum + 4); v2 = inb_p(spic_dev.cur_ioport->io1.minimum); - dprintk("sony_pic_call1: 0x%.4x\n", (v2 << 8) | v1); + dprintk("sony_pic_call1(0x%.2x): 0x%.4x\n", dev, (v2 << 8) | v1); return v2; } @@ -1466,7 +1466,7 @@ static u8 sony_pic_call2(u8 dev, u8 fn) ITERATIONS_LONG); outb(fn, spic_dev.cur_ioport->io1.minimum); v1 = inb_p(spic_dev.cur_ioport->io1.minimum); - dprintk("sony_pic_call2: 0x%.4x\n", v1); + dprintk("sony_pic_call2(0x%.2x - 0x%.2x): 0x%.4x\n", dev, fn, v1); return v1; } @@ -1481,7 +1481,8 @@ static u8 sony_pic_call3(u8 dev, u8 fn, u8 v) wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG); outb(v, spic_dev.cur_ioport->io1.minimum); v1 = inb_p(spic_dev.cur_ioport->io1.minimum); - dprintk("sony_pic_call3: 0x%.4x\n", v1); + dprintk("sony_pic_call3(0x%.2x - 0x%.2x - 0x%.2x): 0x%.4x\n", + dev, fn, v, v1); return v1; } -- cgit v1.2.3 From 88877c2a2ebd0e554496efb23e7dc8ade661d289 Mon Sep 17 00:00:00 2001 From: Mattia Dongili Date: Mon, 14 Jan 2008 18:05:42 +0900 Subject: sony-laptop: Add Vaio N series to the special init sequence to enable Fn keys Also the recent Vaio N series need some more calls into the DSDT to enable reporting of FN key events to be delivered to the SNC device. Signed-off-by: Mattia Dongili Signed-off-by: Len Brown --- drivers/misc/sony-laptop.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/misc') diff --git a/drivers/misc/sony-laptop.c b/drivers/misc/sony-laptop.c index 0435b3d6416..7a32b355869 100644 --- a/drivers/misc/sony-laptop.c +++ b/drivers/misc/sony-laptop.c @@ -875,6 +875,15 @@ static const struct dmi_system_id sony_nc_ids[] = { DMI_MATCH(DMI_PRODUCT_NAME, "VGN-C"), }, }, + { + .ident = "Sony Vaio N 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-N"), + }, + }, { } }; -- cgit v1.2.3 From de9204300112dea10ca3d3cc76858cee61043e47 Mon Sep 17 00:00:00 2001 From: Mattia Dongili Date: Mon, 14 Jan 2008 18:05:43 +0900 Subject: sony-laptop: refactor model types Create mini drivers and allow callbacks for each model to be specified. Following patches will make use of this feature to handle specific cases instead of just executing code and hope not to break other models. Signed-off-by: Mattia Dongili Signed-off-by: Len Brown --- drivers/misc/sony-laptop.c | 186 +++++++++++++++++++++++++-------------------- 1 file changed, 104 insertions(+), 82 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/sony-laptop.c b/drivers/misc/sony-laptop.c index 7a32b355869..a650f25d76c 100644 --- a/drivers/misc/sony-laptop.c +++ b/drivers/misc/sony-laptop.c @@ -1194,18 +1194,33 @@ struct sony_pic_irq { struct list_head list; }; +struct sonypi_eventtypes { + u8 data; + unsigned long mask; + struct sonypi_event *events; +}; + +struct device_ctrl { + int model; + int (*handle_irq)(void); + u16 evport_offset; + u8 has_camera; + u8 has_bluetooth; + u8 has_wwan; + struct sonypi_eventtypes *event_types; +}; + struct sony_pic_dev { - int model; - u16 evport_offset; - u8 camera_power; - u8 bluetooth_power; - u8 wwan_power; + struct device_ctrl *control; struct acpi_device *acpi_dev; struct sony_pic_irq *cur_irq; struct sony_pic_ioport *cur_ioport; struct list_head interrupts; struct list_head ioports; struct mutex lock; + u8 camera_power; + u8 bluetooth_power; + u8 wwan_power; }; static struct sony_pic_dev spic_dev = { @@ -1370,74 +1385,92 @@ static struct sonypi_event sonypi_batteryev[] = { { 0, 0 } }; -static struct sonypi_eventtypes { - int model; - u8 data; - unsigned long mask; - struct sonypi_event * events; -} sony_pic_eventtypes[] = { - { SONYPI_DEVICE_TYPE1, 0, 0xffffffff, sonypi_releaseev }, - { SONYPI_DEVICE_TYPE1, 0x70, SONYPI_MEYE_MASK, sonypi_meyeev }, - { SONYPI_DEVICE_TYPE1, 0x30, SONYPI_LID_MASK, sonypi_lidev }, - { SONYPI_DEVICE_TYPE1, 0x60, SONYPI_CAPTURE_MASK, sonypi_captureev }, - { SONYPI_DEVICE_TYPE1, 0x10, SONYPI_JOGGER_MASK, sonypi_joggerev }, - { SONYPI_DEVICE_TYPE1, 0x20, SONYPI_FNKEY_MASK, sonypi_fnkeyev }, - { SONYPI_DEVICE_TYPE1, 0x30, SONYPI_BLUETOOTH_MASK, sonypi_blueev }, - { SONYPI_DEVICE_TYPE1, 0x40, SONYPI_PKEY_MASK, sonypi_pkeyev }, - { SONYPI_DEVICE_TYPE1, 0x30, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev }, - { SONYPI_DEVICE_TYPE1, 0x40, SONYPI_BATTERY_MASK, sonypi_batteryev }, - - { SONYPI_DEVICE_TYPE2, 0, 0xffffffff, sonypi_releaseev }, - { SONYPI_DEVICE_TYPE2, 0x38, SONYPI_LID_MASK, sonypi_lidev }, - { SONYPI_DEVICE_TYPE2, 0x11, SONYPI_JOGGER_MASK, sonypi_joggerev }, - { SONYPI_DEVICE_TYPE2, 0x61, SONYPI_CAPTURE_MASK, sonypi_captureev }, - { SONYPI_DEVICE_TYPE2, 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev }, - { SONYPI_DEVICE_TYPE2, 0x31, SONYPI_BLUETOOTH_MASK, sonypi_blueev }, - { SONYPI_DEVICE_TYPE2, 0x08, SONYPI_PKEY_MASK, sonypi_pkeyev }, - { SONYPI_DEVICE_TYPE2, 0x11, SONYPI_BACK_MASK, sonypi_backev }, - { SONYPI_DEVICE_TYPE2, 0x21, SONYPI_HELP_MASK, sonypi_helpev }, - { SONYPI_DEVICE_TYPE2, 0x21, SONYPI_ZOOM_MASK, sonypi_zoomev }, - { SONYPI_DEVICE_TYPE2, 0x20, SONYPI_THUMBPHRASE_MASK, sonypi_thumbphraseev }, - { SONYPI_DEVICE_TYPE2, 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev }, - { SONYPI_DEVICE_TYPE2, 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev }, - { SONYPI_DEVICE_TYPE2, 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev }, - - { SONYPI_DEVICE_TYPE3, 0, 0xffffffff, sonypi_releaseev }, - { SONYPI_DEVICE_TYPE3, 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev }, - { SONYPI_DEVICE_TYPE3, 0x31, SONYPI_WIRELESS_MASK, sonypi_wlessev }, - { SONYPI_DEVICE_TYPE3, 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev }, - { SONYPI_DEVICE_TYPE3, 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev }, - { SONYPI_DEVICE_TYPE3, 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev }, - { 0 } +static struct sonypi_eventtypes type1_events[] = { + { 0, 0xffffffff, sonypi_releaseev }, + { 0x70, SONYPI_MEYE_MASK, sonypi_meyeev }, + { 0x30, SONYPI_LID_MASK, sonypi_lidev }, + { 0x60, SONYPI_CAPTURE_MASK, sonypi_captureev }, + { 0x10, SONYPI_JOGGER_MASK, sonypi_joggerev }, + { 0x20, SONYPI_FNKEY_MASK, sonypi_fnkeyev }, + { 0x30, SONYPI_BLUETOOTH_MASK, sonypi_blueev }, + { 0x40, SONYPI_PKEY_MASK, sonypi_pkeyev }, + { 0x30, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev }, + { 0x40, SONYPI_BATTERY_MASK, sonypi_batteryev }, + { 0 }, +}; +static struct sonypi_eventtypes type2_events[] = { + { 0, 0xffffffff, sonypi_releaseev }, + { 0x38, SONYPI_LID_MASK, sonypi_lidev }, + { 0x11, SONYPI_JOGGER_MASK, sonypi_joggerev }, + { 0x61, SONYPI_CAPTURE_MASK, sonypi_captureev }, + { 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev }, + { 0x31, SONYPI_BLUETOOTH_MASK, sonypi_blueev }, + { 0x08, SONYPI_PKEY_MASK, sonypi_pkeyev }, + { 0x11, SONYPI_BACK_MASK, sonypi_backev }, + { 0x21, SONYPI_HELP_MASK, sonypi_helpev }, + { 0x21, SONYPI_ZOOM_MASK, sonypi_zoomev }, + { 0x20, SONYPI_THUMBPHRASE_MASK, sonypi_thumbphraseev }, + { 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev }, + { 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev }, + { 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev }, + { 0 }, +}; +static struct sonypi_eventtypes type3_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 }, + { 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev }, + { 0 }, }; -static int sony_pic_detect_device_type(void) +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 void sony_pic_detect_device_type(struct sony_pic_dev *dev) { struct pci_dev *pcidev; - int model = 0; if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, NULL))) - model = SONYPI_DEVICE_TYPE1; + dev->control = &spic_types[0]; else if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1, NULL))) - model = SONYPI_DEVICE_TYPE3; + dev->control = &spic_types[2]; else if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1, NULL))) - model = SONYPI_DEVICE_TYPE3; + dev->control = &spic_types[2]; else - model = SONYPI_DEVICE_TYPE2; + dev->control = &spic_types[1]; if (pcidev) pci_dev_put(pcidev); printk(KERN_INFO DRV_PFX "detected Type%d model\n", - model == SONYPI_DEVICE_TYPE1 ? 1 : - model == SONYPI_DEVICE_TYPE2 ? 2 : 3); - return model; + dev->control->model == SONYPI_DEVICE_TYPE1 ? 1 : + dev->control->model == SONYPI_DEVICE_TYPE2 ? 2 : 3); } #define ITERATIONS_LONG 10000 @@ -2263,7 +2296,7 @@ static int sony_pic_enable(struct acpi_device *device, buffer.pointer = resource; /* setup Type 1 resources */ - if (spic_dev.model == SONYPI_DEVICE_TYPE1) { + if (spic_dev.control->model == SONYPI_DEVICE_TYPE1) { /* setup io resources */ resource->res1.type = ACPI_RESOURCE_TYPE_IO; @@ -2345,39 +2378,42 @@ static irqreturn_t sony_pic_irq(int irq, void *dev_id) if (dev->cur_ioport->io2.minimum) data_mask = inb_p(dev->cur_ioport->io2.minimum); else - data_mask = inb_p(dev->cur_ioport->io1.minimum + dev->evport_offset); + data_mask = inb_p(dev->cur_ioport->io1.minimum + + dev->control->evport_offset); dprintk("event ([%.2x] [%.2x]) at port 0x%.4x(+0x%.2x)\n", - ev, data_mask, dev->cur_ioport->io1.minimum, dev->evport_offset); + ev, data_mask, dev->cur_ioport->io1.minimum, + dev->control->evport_offset); if (ev == 0x00 || ev == 0xff) return IRQ_HANDLED; - for (i = 0; sony_pic_eventtypes[i].model; i++) { + for (i = 0; dev->control->event_types[i].mask; i++) { - if (spic_dev.model != sony_pic_eventtypes[i].model) + if ((data_mask & dev->control->event_types[i].data) != + dev->control->event_types[i].data) continue; - if ((data_mask & sony_pic_eventtypes[i].data) != - sony_pic_eventtypes[i].data) + if (!(mask & dev->control->event_types[i].mask)) continue; - if (!(mask & sony_pic_eventtypes[i].mask)) - continue; - - for (j = 0; sony_pic_eventtypes[i].events[j].event; j++) { - if (ev == sony_pic_eventtypes[i].events[j].data) { + for (j = 0; dev->control->event_types[i].events[j].event; j++) { + if (ev == dev->control->event_types[i].events[j].data) { device_event = - sony_pic_eventtypes[i].events[j].event; + dev->control-> + event_types[i].events[j].event; goto found; } } } + dprintk("unknown event ([%.2x] [%.2x]) at port 0x%.4x(+0x%.2x)\n", + ev, data_mask, dev->cur_ioport->io1.minimum, + dev->control->evport_offset); return IRQ_HANDLED; found: sony_laptop_report_input_event(device_event); - acpi_bus_generate_proc_event(spic_dev.acpi_dev, 1, device_event); + acpi_bus_generate_proc_event(dev->acpi_dev, 1, device_event); sonypi_compat_report_event(device_event); return IRQ_HANDLED; @@ -2439,23 +2475,9 @@ static int sony_pic_add(struct acpi_device *device) spic_dev.acpi_dev = device; strcpy(acpi_device_class(device), "sony/hotkey"); - spic_dev.model = sony_pic_detect_device_type(); + sony_pic_detect_device_type(&spic_dev); mutex_init(&spic_dev.lock); - /* model specific characteristics */ - switch(spic_dev.model) { - case SONYPI_DEVICE_TYPE1: - spic_dev.evport_offset = SONYPI_TYPE1_OFFSET; - break; - case SONYPI_DEVICE_TYPE3: - spic_dev.evport_offset = SONYPI_TYPE3_OFFSET; - break; - case SONYPI_DEVICE_TYPE2: - default: - spic_dev.evport_offset = SONYPI_TYPE2_OFFSET; - break; - } - /* read _PRS resources */ result = sony_pic_possible_resources(device); if (result) { -- cgit v1.2.3 From 425ef5d75de25c53b6dc79008fe3678d2fe7e8ed Mon Sep 17 00:00:00 2001 From: Mattia Dongili Date: Mon, 14 Jan 2008 18:05:44 +0900 Subject: sony-laptop: bump version to 0.6 Signed-off-by: Mattia Dongili Signed-off-by: Len Brown --- drivers/misc/sony-laptop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/misc') diff --git a/drivers/misc/sony-laptop.c b/drivers/misc/sony-laptop.c index a650f25d76c..98692862fbc 100644 --- a/drivers/misc/sony-laptop.c +++ b/drivers/misc/sony-laptop.c @@ -73,7 +73,7 @@ if (debug) printk(KERN_WARNING DRV_PFX msg); \ } while (0) -#define SONY_LAPTOP_DRIVER_VERSION "0.5" +#define SONY_LAPTOP_DRIVER_VERSION "0.6" #define SONY_NC_CLASS "sony-nc" #define SONY_NC_HID "SNY5001" -- cgit v1.2.3 From 3eb8749a37990b505ab94466038c067444bbd7eb Mon Sep 17 00:00:00 2001 From: Mattia Dongili Date: Mon, 14 Jan 2008 18:05:45 +0900 Subject: sony-laptop: add Type4 model 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 Signed-off-by: Len Brown --- drivers/misc/sony-laptop.c | 295 ++++++++++++++++++++++++++++----------------- 1 file changed, 184 insertions(+), 111 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/sony-laptop.c b/drivers/misc/sony-laptop.c index 98692862fbc..70d5cc5969a 100644 --- a/drivers/misc/sony-laptop.c +++ b/drivers/misc/sony-laptop.c @@ -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); -- cgit v1.2.3 From fccd5d00ba68455425a35f905fd92538429c310d Mon Sep 17 00:00:00 2001 From: Mattia Dongili Date: Mon, 14 Jan 2008 18:05:46 +0900 Subject: sony-laptop: fix scancode decode compare against the sony_laptop specific event list index to decode the input scancode to send. Signed-off-by: Mattia Dongili Signed-off-by: Len Brown --- drivers/misc/sony-laptop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/misc') diff --git a/drivers/misc/sony-laptop.c b/drivers/misc/sony-laptop.c index 70d5cc5969a..899e3f75f28 100644 --- a/drivers/misc/sony-laptop.c +++ b/drivers/misc/sony-laptop.c @@ -315,7 +315,7 @@ static void sony_laptop_report_input_event(u8 event) break; default: - if (event > ARRAY_SIZE (sony_laptop_input_keycode_map)) { + if (event > ARRAY_SIZE(sony_laptop_input_index)) { dprintk("sony_laptop_report_input_event, event not known: %d\n", event); break; } -- cgit v1.2.3 From 0f089147e620e083f58a0e641f701bd4244b455b Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Tue, 8 Jan 2008 13:02:38 -0200 Subject: ACPI: thinkpad-acpi: document keymap gotcha's (v2) Publish the requirements for keymap changes. This is a documentation change, only. Currently, people look at the thinkpad-acpi default keymaps, and think: "modifying this is a trivial thing, it can't break systems, and there are keys defined for foo and bar, but the driver has them as KEY_RESERVED. Must have been an oversight, let me change it." And since they never get to see the bug reports, because they are not really a part of the Linux ThinkPad users community (linux-thinkpad mailinglist, thinkwiki wiki, thinkpad forums) and laptop users are slow to complain to distros about any breakages... Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 68 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 63 insertions(+), 5 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index cf56647a6ca..7b1080f5843 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -954,26 +954,67 @@ static struct attribute *hotkey_mask_attributes[] __initdata = { static int __init hotkey_init(struct ibm_init_struct *iibm) { - + /* Requirements for changing the default keymaps: + * + * 1. Many of the keys are mapped to KEY_RESERVED for very + * good reasons. Do not change them unless you have deep + * knowledge on the IBM and Lenovo ThinkPad firmware for + * the various ThinkPad models. The driver behaves + * differently for KEY_RESERVED: such keys have their + * hot key mask *unset* in mask_recommended, and also + * in the initial hot key mask programmed into the + * firmware at driver load time, which means the firm- + * ware may react very differently if you change them to + * something else; + * + * 2. You must be subscribed to the linux-thinkpad and + * ibm-acpi-devel mailing lists, and you should read the + * list archives since 2007 if you want to change the + * keymaps. This requirement exists so that you will + * know the past history of problems with the thinkpad- + * acpi driver keymaps, and also that you will be + * listening to any bug reports; + * + * 3. Do not send thinkpad-acpi specific patches directly to + * for merging, *ever*. Send them to the linux-acpi + * mailinglist for comments. Merging is to be done only + * through acpi-test and the ACPI maintainer. + * + * If the above is too much to ask, don't change the keymap. + * Ask the thinkpad-acpi maintainer to do it, instead. + */ static u16 ibm_keycode_map[] __initdata = { /* Scan Codes 0x00 to 0x0B: ACPI HKEY FN+F1..F12 */ KEY_FN_F1, KEY_FN_F2, KEY_COFFEE, KEY_SLEEP, KEY_WLAN, KEY_FN_F6, KEY_SWITCHVIDEOMODE, KEY_FN_F8, KEY_FN_F9, KEY_FN_F10, KEY_FN_F11, KEY_SUSPEND, - /* Scan codes 0x0C to 0x0F: Other ACPI HKEY hot keys */ + + /* Scan codes 0x0C to 0x1F: Other ACPI HKEY hot keys */ KEY_UNKNOWN, /* 0x0C: FN+BACKSPACE */ KEY_UNKNOWN, /* 0x0D: FN+INSERT */ KEY_UNKNOWN, /* 0x0E: FN+DELETE */ + + /* brightness: firmware always reacts to them, unless + * X.org did some tricks in the radeon BIOS scratch + * registers of *some* models */ KEY_RESERVED, /* 0x0F: FN+HOME (brightness up) */ - /* Scan codes 0x10 to 0x1F: Extended ACPI HKEY hot keys */ KEY_RESERVED, /* 0x10: FN+END (brightness down) */ + + /* Thinklight: firmware always react to it */ KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */ + KEY_UNKNOWN, /* 0x12: FN+PGDOWN */ KEY_ZOOM, /* 0x13: FN+SPACE (zoom) */ + + /* Volume: firmware always react to it and reprograms + * the built-in *extra* mixer. Never map it to control + * another mixer by default. */ KEY_RESERVED, /* 0x14: VOLUME UP */ KEY_RESERVED, /* 0x15: VOLUME DOWN */ KEY_RESERVED, /* 0x16: MUTE */ + KEY_VENDOR, /* 0x17: Thinkpad/AccessIBM/Lenovo */ + /* (assignments unknown, please report if found) */ KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, @@ -983,20 +1024,37 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) KEY_FN_F1, KEY_COFFEE, KEY_BATTERY, KEY_SLEEP, KEY_WLAN, KEY_FN_F6, KEY_SWITCHVIDEOMODE, KEY_FN_F8, KEY_FN_F9, KEY_FN_F10, KEY_FN_F11, KEY_SUSPEND, - /* Scan codes 0x0C to 0x0F: Other ACPI HKEY hot keys */ + + /* Scan codes 0x0C to 0x1F: Other ACPI HKEY hot keys */ KEY_UNKNOWN, /* 0x0C: FN+BACKSPACE */ KEY_UNKNOWN, /* 0x0D: FN+INSERT */ KEY_UNKNOWN, /* 0x0E: FN+DELETE */ + KEY_RESERVED, /* 0x0F: FN+HOME (brightness up) */ - /* Scan codes 0x10 to 0x1F: Extended ACPI HKEY hot keys */ KEY_RESERVED, /* 0x10: FN+END (brightness down) */ + KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */ + KEY_UNKNOWN, /* 0x12: FN+PGDOWN */ KEY_ZOOM, /* 0x13: FN+SPACE (zoom) */ + + /* Volume: z60/z61, T60 (BIOS version?): firmware always + * react to it and reprograms the built-in *extra* mixer. + * Never map it to control another mixer by default. + * + * T60?, T61, R60?, R61: firmware and EC tries to send + * these over the regular keyboard, so these are no-ops, + * but there are still weird bugs re. MUTE, so do not + * change unless you get test reports from all Lenovo + * models. May cause the BIOS to interfere with the + * HDA mixer. + */ KEY_RESERVED, /* 0x14: VOLUME UP */ KEY_RESERVED, /* 0x15: VOLUME DOWN */ KEY_RESERVED, /* 0x16: MUTE */ + KEY_VENDOR, /* 0x17: Thinkpad/AccessIBM/Lenovo */ + /* (assignments unknown, please report if found) */ KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, -- cgit v1.2.3 From b2c985e7eba858a1765db6d56bdd4df775f53633 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Tue, 8 Jan 2008 13:02:39 -0200 Subject: ACPI: thinkpad-acpi: refactor hotkey_get and hotkey_set (v2) Refactor and organize the code a bit for the NVRAM polling support: 1. Split hotkey_get/set into hotkey_status_get/set and hotkey_mask_get/set; 2. Cache the status of hot key mask for later driver use; 3. Make sure the cache of hot key mask is refreshed when needed; 4. log a printk notice when the firmware doesn't set the hot key mask to exactly what we asked it to; 5. Add proper locking to the data structures. Only (4) should be user-noticeable, but there is a chance (5) fixes some unknown/unreported race conditions. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 184 +++++++++++++++++++++++++------------------ drivers/misc/thinkpad_acpi.h | 2 - 2 files changed, 109 insertions(+), 77 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 7b1080f5843..49d4f4af759 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -777,6 +777,7 @@ static int hotkey_orig_status; static u32 hotkey_orig_mask; static u32 hotkey_all_mask; static u32 hotkey_reserved_mask; +static u32 hotkey_mask; static u16 *hotkey_keycode_map; @@ -789,15 +790,76 @@ static int hotkey_get_wlsw(int *status) return 0; } +/* + * Call with hotkey_mutex held + */ +static int hotkey_mask_get(void) +{ + if (tp_features.hotkey_mask) { + if (!acpi_evalf(hkey_handle, &hotkey_mask, "DHKN", "d")) + return -EIO; + } + + return 0; +} + +/* + * Call with hotkey_mutex held + */ +static int hotkey_mask_set(u32 mask) +{ + int i; + int rc = 0; + + if (tp_features.hotkey_mask) { + for (i = 0; i < 32; i++) { + u32 m = 1 << i; + if (!acpi_evalf(hkey_handle, + NULL, "MHKM", "vdd", i + 1, + !!(mask & m))) { + rc = -EIO; + break; + } else { + hotkey_mask = (hotkey_mask & ~m) | (mask & m); + } + } + + /* hotkey_mask_get must be called unconditionally below */ + if (!hotkey_mask_get() && !rc && hotkey_mask != mask) { + printk(IBM_NOTICE + "requested hot key mask 0x%08x, but " + "firmware forced it to 0x%08x\n", + mask, hotkey_mask); + } + } + + return rc; +} + +static int hotkey_status_get(int *status) +{ + if (!acpi_evalf(hkey_handle, status, "DHKC", "d")) + return -EIO; + + return 0; +} + +static int hotkey_status_set(int status) +{ + if (!acpi_evalf(hkey_handle, NULL, "MHKC", "vd", status)) + return -EIO; + + return 0; +} + /* sysfs hotkey enable ------------------------------------------------- */ static ssize_t hotkey_enable_show(struct device *dev, struct device_attribute *attr, char *buf) { int res, status; - u32 mask; - res = hotkey_get(&status, &mask); + res = hotkey_status_get(&status); if (res) return res; @@ -809,15 +871,12 @@ static ssize_t hotkey_enable_store(struct device *dev, const char *buf, size_t count) { unsigned long t; - int res, status; - u32 mask; + int res; if (parse_strtoul(buf, 1, &t)) return -EINVAL; - res = hotkey_get(&status, &mask); - if (!res) - res = hotkey_set(t, mask); + res = hotkey_status_set(t); return (res) ? res : count; } @@ -831,14 +890,15 @@ static ssize_t hotkey_mask_show(struct device *dev, struct device_attribute *attr, char *buf) { - int res, status; - u32 mask; + int res; - res = hotkey_get(&status, &mask); - if (res) - return res; + if (mutex_lock_interruptible(&hotkey_mutex)) + return -ERESTARTSYS; + res = hotkey_mask_get(); + mutex_unlock(&hotkey_mutex); - return snprintf(buf, PAGE_SIZE, "0x%08x\n", mask); + return (res)? + res : snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_mask); } static ssize_t hotkey_mask_store(struct device *dev, @@ -846,15 +906,16 @@ static ssize_t hotkey_mask_store(struct device *dev, const char *buf, size_t count) { unsigned long t; - int res, status; - u32 mask; + int res; if (parse_strtoul(buf, 0xffffffffUL, &t)) return -EINVAL; - res = hotkey_get(&status, &mask); - if (!res) - hotkey_set(status, t); + if (mutex_lock_interruptible(&hotkey_mutex)) + return -ERESTARTSYS; + + res = hotkey_mask_set(t); + mutex_unlock(&hotkey_mutex); return (res) ? res : count; } @@ -1123,11 +1184,16 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) } } - res = hotkey_get(&hotkey_orig_status, &hotkey_orig_mask); + res = hotkey_status_get(&hotkey_orig_status); if (!res && tp_features.hotkey_mask) { - res = add_many_to_attr_set(hotkey_dev_attributes, - hotkey_mask_attributes, - ARRAY_SIZE(hotkey_mask_attributes)); + res = hotkey_mask_get(); + hotkey_orig_mask = hotkey_mask; + if (!res) { + res = add_many_to_attr_set( + hotkey_dev_attributes, + hotkey_mask_attributes, + ARRAY_SIZE(hotkey_mask_attributes)); + } } /* Not all thinkpads have a hardware radio switch */ @@ -1191,7 +1257,10 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) dbg_printk(TPACPI_DBG_INIT, "enabling hot key handling\n"); - res = hotkey_set(1, (hotkey_all_mask & ~hotkey_reserved_mask) + res = hotkey_status_set(1); + if (res) + return res; + res = hotkey_mask_set((hotkey_all_mask & ~hotkey_reserved_mask) | hotkey_orig_mask); if (res) return res; @@ -1207,13 +1276,12 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) static void hotkey_exit(void) { - int res; - if (tp_features.hotkey) { - dbg_printk(TPACPI_DBG_EXIT, "restoring original hotkey mask\n"); - res = hotkey_set(hotkey_orig_status, hotkey_orig_mask); - if (res) - printk(IBM_ERR "failed to restore hotkey to BIOS defaults\n"); + dbg_printk(TPACPI_DBG_EXIT, "restoring original hot key mask\n"); + /* no short-circuit boolean operator below! */ + if ((hotkey_mask_set(hotkey_orig_mask) | + hotkey_status_set(hotkey_orig_status)) != 0) + printk(IBM_ERR "failed to restore hot key mask to BIOS defaults\n"); } if (hotkey_dev_attributes) { @@ -1349,50 +1417,15 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) static void hotkey_resume(void) { + if (hotkey_mask_get()) + printk(IBM_ERR "error while trying to read hot key mask from firmware\n"); tpacpi_input_send_radiosw(); } -/* - * Call with hotkey_mutex held - */ -static int hotkey_get(int *status, u32 *mask) -{ - if (!acpi_evalf(hkey_handle, status, "DHKC", "d")) - return -EIO; - - if (tp_features.hotkey_mask) - if (!acpi_evalf(hkey_handle, mask, "DHKN", "d")) - return -EIO; - - return 0; -} - -/* - * Call with hotkey_mutex held - */ -static int hotkey_set(int status, u32 mask) -{ - int i; - - if (!acpi_evalf(hkey_handle, NULL, "MHKC", "vd", status)) - return -EIO; - - if (tp_features.hotkey_mask) - for (i = 0; i < 32; i++) { - int bit = ((1 << i) & mask) != 0; - if (!acpi_evalf(hkey_handle, - NULL, "MHKM", "vdd", i + 1, bit)) - return -EIO; - } - - return 0; -} - /* procfs -------------------------------------------------------------- */ static int hotkey_read(char *p) { int res, status; - u32 mask; int len = 0; if (!tp_features.hotkey) { @@ -1402,14 +1435,16 @@ static int hotkey_read(char *p) if (mutex_lock_interruptible(&hotkey_mutex)) return -ERESTARTSYS; - res = hotkey_get(&status, &mask); + res = hotkey_status_get(&status); + if (!res) + res = hotkey_mask_get(); mutex_unlock(&hotkey_mutex); if (res) return res; len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 0)); if (tp_features.hotkey_mask) { - len += sprintf(p + len, "mask:\t\t0x%08x\n", mask); + len += sprintf(p + len, "mask:\t\t0x%08x\n", hotkey_mask); len += sprintf(p + len, "commands:\tenable, disable, reset, \n"); } else { @@ -1425,7 +1460,6 @@ static int hotkey_write(char *buf) int res, status; u32 mask; char *cmd; - int do_cmd = 0; if (!tp_features.hotkey) return -ENODEV; @@ -1433,9 +1467,8 @@ static int hotkey_write(char *buf) if (mutex_lock_interruptible(&hotkey_mutex)) return -ERESTARTSYS; - res = hotkey_get(&status, &mask); - if (res) - goto errexit; + status = -1; + mask = hotkey_mask; res = 0; while ((cmd = next_cmd(&buf))) { @@ -1454,11 +1487,12 @@ static int hotkey_write(char *buf) res = -EINVAL; goto errexit; } - do_cmd = 1; } + if (status != -1) + res = hotkey_status_set(status); - if (do_cmd) - res = hotkey_set(status, mask); + if (!res && mask != hotkey_mask) + res = hotkey_mask_set(mask); errexit: mutex_unlock(&hotkey_mutex); diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h index 8fba2bbe345..3b031344313 100644 --- a/drivers/misc/thinkpad_acpi.h +++ b/drivers/misc/thinkpad_acpi.h @@ -461,8 +461,6 @@ static struct mutex hotkey_mutex; static int hotkey_init(struct ibm_init_struct *iibm); static void hotkey_exit(void); -static int hotkey_get(int *status, u32 *mask); -static int hotkey_set(int status, u32 mask); static void hotkey_notify(struct ibm_struct *ibm, u32 event); static int hotkey_read(char *p); static int hotkey_write(char *buf); -- cgit v1.2.3 From b7c8c200bfbf523ea0a72fd8a5e39089c74da371 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Tue, 8 Jan 2008 13:02:40 -0200 Subject: ACPI: thinkpad-acpi: prepare for NVRAM polling support Make some small internal thinkpad-acpi changes to the hotkey subdriver code that will make it easier to add NVRAM polling support. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 82 +++++++++++++++++++++++--------------------- 1 file changed, 42 insertions(+), 40 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 49d4f4af759..e7ac1c8a554 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -852,6 +852,46 @@ static int hotkey_status_set(int status) return 0; } +static void tpacpi_input_send_radiosw(void) +{ + int wlsw; + + mutex_lock(&tpacpi_inputdev_send_mutex); + + if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw)) { + input_report_switch(tpacpi_inputdev, + SW_RADIO, !!wlsw); + input_sync(tpacpi_inputdev); + } + + mutex_unlock(&tpacpi_inputdev_send_mutex); +} + +static void tpacpi_input_send_key(unsigned int scancode) +{ + unsigned int keycode; + + keycode = hotkey_keycode_map[scancode]; + + if (keycode != KEY_RESERVED) { + mutex_lock(&tpacpi_inputdev_send_mutex); + + input_report_key(tpacpi_inputdev, keycode, 1); + if (keycode == KEY_UNKNOWN) + input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN, + scancode); + input_sync(tpacpi_inputdev); + + input_report_key(tpacpi_inputdev, keycode, 0); + if (keycode == KEY_UNKNOWN) + input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN, + scancode); + input_sync(tpacpi_inputdev); + + mutex_unlock(&tpacpi_inputdev_send_mutex); + } +} + /* sysfs hotkey enable ------------------------------------------------- */ static ssize_t hotkey_enable_show(struct device *dev, struct device_attribute *attr, @@ -1290,47 +1330,10 @@ static void hotkey_exit(void) } } -static void tpacpi_input_send_key(unsigned int scancode, - unsigned int keycode) -{ - if (keycode != KEY_RESERVED) { - mutex_lock(&tpacpi_inputdev_send_mutex); - - input_report_key(tpacpi_inputdev, keycode, 1); - if (keycode == KEY_UNKNOWN) - input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN, - scancode); - input_sync(tpacpi_inputdev); - - input_report_key(tpacpi_inputdev, keycode, 0); - if (keycode == KEY_UNKNOWN) - input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN, - scancode); - input_sync(tpacpi_inputdev); - - mutex_unlock(&tpacpi_inputdev_send_mutex); - } -} - -static void tpacpi_input_send_radiosw(void) -{ - int wlsw; - - mutex_lock(&tpacpi_inputdev_send_mutex); - - if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw)) { - input_report_switch(tpacpi_inputdev, - SW_RADIO, !!wlsw); - input_sync(tpacpi_inputdev); - } - - mutex_unlock(&tpacpi_inputdev_send_mutex); -} - static void hotkey_notify(struct ibm_struct *ibm, u32 event) { u32 hkey; - unsigned int keycode, scancode; + unsigned int scancode; int send_acpi_ev; int ignore_acpi_ev; @@ -1363,8 +1366,7 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) scancode = hkey & 0xfff; if (scancode > 0 && scancode < 0x21) { scancode--; - keycode = hotkey_keycode_map[scancode]; - tpacpi_input_send_key(scancode, keycode); + tpacpi_input_send_key(scancode); } else { printk(IBM_ERR "hotkey 0x%04x out of range for keyboard map\n", -- cgit v1.2.3 From 01e88f25985d8ea5866c9a73d56b3a9a9145066f Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Tue, 8 Jan 2008 13:02:41 -0200 Subject: ACPI: thinkpad-acpi: add CMOS NVRAM polling for hot keys (v9) Older ThinkPad models do not export some of the hot keys over the event-based ACPI hot key interface. For these models, one has to poll the CMOS NVRAM to check the key state at a rate faster than the expected rate at which the user might repeatedly press the same hot key. This patch implements this functionality for many of the hotkeys in a transparent way: hot keys will now Just Work, and the driver knows the best approach (events or NVRAM polling) to employ, based on the HKEY.MHKA ACPI method. Also, the driver can turn off the polling when there are no users for the hot keys that need such polling. The NVRAM-based hot keys of the A3x series that have never been implemented by later models are not supported, to avoid changes in the keymap of the input devices that could cause headaches in the future. There is a Kconfig option to avoid compiling the NVRAM polling code, as it is not very small, and unlikely to be useful on any ThinkPad newer than a T40, X31 or R52. This feature is based on a previous effort by Richard Hughes. Signed-off-by: Henrique de Moraes Holschuh Cc: Richard Hughes Signed-off-by: Len Brown --- drivers/misc/Kconfig | 19 ++ drivers/misc/thinkpad_acpi.c | 505 +++++++++++++++++++++++++++++++++++++++++-- drivers/misc/thinkpad_acpi.h | 60 ++++- 3 files changed, 567 insertions(+), 17 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index b5e67c0ff43..b1f9a405c82 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -219,6 +219,25 @@ config THINKPAD_ACPI_BAY If you are not sure, say Y here. +config THINKPAD_ACPI_HOTKEY_POLL + bool "Suport NVRAM polling for hot keys" + depends on THINKPAD_ACPI + default y + ---help--- + Some thinkpad models benefit from NVRAM polling to detect a few of + the hot key press events. If you know your ThinkPad model does not + need to do NVRAM polling to support any of the hot keys you use, + unselecting this option will save about 1kB of memory. + + ThinkPads T40 and newer, R52 and newer, and X31 and newer are + unlikely to need NVRAM polling in their latest BIOS versions. + + NVRAM polling can detect at most the following keys: ThinkPad/Access + IBM, Zoom, Switch Display (fn+F7), ThinkLight, Volume up/down/mute, + Brightness up/down, Display Expand (fn+F8), Hibernate (fn+F12). + + If you are not sure, say Y here. The driver enables polling only if + it is strictly necessary to do so. config ATMEL_SSC tristate "Device driver for Atmel SSC peripheral" diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index e7ac1c8a554..9ff9142ce06 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -22,7 +22,7 @@ */ #define IBM_VERSION "0.17" -#define TPACPI_SYSFS_VERSION 0x020000 +#define TPACPI_SYSFS_VERSION 0x020101 /* * Changelog: @@ -773,6 +773,67 @@ static struct ibm_struct thinkpad_acpi_driver_data = { * Hotkey subdriver */ +enum { /* Keys available through NVRAM polling */ + TPACPI_HKEY_NVRAM_KNOWN_MASK = 0x00fb88c0U, + TPACPI_HKEY_NVRAM_GOOD_MASK = 0x00fb8000U, +}; + +enum { /* Positions of some of the keys in hotkey masks */ + TP_ACPI_HKEY_DISPSWTCH_MASK = 1 << TP_ACPI_HOTKEYSCAN_FNF7, + TP_ACPI_HKEY_DISPXPAND_MASK = 1 << TP_ACPI_HOTKEYSCAN_FNF8, + TP_ACPI_HKEY_HIBERNATE_MASK = 1 << TP_ACPI_HOTKEYSCAN_FNF12, + TP_ACPI_HKEY_BRGHTUP_MASK = 1 << TP_ACPI_HOTKEYSCAN_FNHOME, + TP_ACPI_HKEY_BRGHTDWN_MASK = 1 << TP_ACPI_HOTKEYSCAN_FNEND, + TP_ACPI_HKEY_THNKLGHT_MASK = 1 << TP_ACPI_HOTKEYSCAN_FNPAGEUP, + TP_ACPI_HKEY_ZOOM_MASK = 1 << TP_ACPI_HOTKEYSCAN_FNSPACE, + TP_ACPI_HKEY_VOLUP_MASK = 1 << TP_ACPI_HOTKEYSCAN_VOLUMEUP, + TP_ACPI_HKEY_VOLDWN_MASK = 1 << TP_ACPI_HOTKEYSCAN_VOLUMEDOWN, + TP_ACPI_HKEY_MUTE_MASK = 1 << TP_ACPI_HOTKEYSCAN_MUTE, + TP_ACPI_HKEY_THINKPAD_MASK = 1 << TP_ACPI_HOTKEYSCAN_THINKPAD, +}; + +enum { /* NVRAM to ACPI HKEY group map */ + TP_NVRAM_HKEY_GROUP_HK2 = TP_ACPI_HKEY_THINKPAD_MASK | + TP_ACPI_HKEY_ZOOM_MASK | + TP_ACPI_HKEY_DISPSWTCH_MASK | + TP_ACPI_HKEY_HIBERNATE_MASK, + TP_NVRAM_HKEY_GROUP_BRIGHTNESS = TP_ACPI_HKEY_BRGHTUP_MASK | + TP_ACPI_HKEY_BRGHTDWN_MASK, + TP_NVRAM_HKEY_GROUP_VOLUME = TP_ACPI_HKEY_VOLUP_MASK | + TP_ACPI_HKEY_VOLDWN_MASK | + TP_ACPI_HKEY_MUTE_MASK, +}; + +#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL +struct tp_nvram_state { + u16 thinkpad_toggle:1; + u16 zoom_toggle:1; + u16 display_toggle:1; + u16 thinklight_toggle:1; + u16 hibernate_toggle:1; + u16 displayexp_toggle:1; + u16 display_state:1; + u16 brightness_toggle:1; + u16 volume_toggle:1; + u16 mute:1; + + u8 brightness_level; + u8 volume_level; +}; + +static struct task_struct *tpacpi_hotkey_task; +static u32 hotkey_source_mask; /* bit mask 0=ACPI,1=NVRAM */ +static int hotkey_poll_freq = 10; /* Hz */ +static struct mutex hotkey_thread_mutex; +static struct mutex hotkey_thread_data_mutex; +static unsigned int hotkey_config_change; + +#else /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ + +#define hotkey_source_mask 0U + +#endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ + static int hotkey_orig_status; static u32 hotkey_orig_mask; static u32 hotkey_all_mask; @@ -783,6 +844,17 @@ static u16 *hotkey_keycode_map; static struct attribute_set *hotkey_dev_attributes; +#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL +#define HOTKEY_CONFIG_CRITICAL_START \ + mutex_lock(&hotkey_thread_data_mutex); \ + hotkey_config_change++; +#define HOTKEY_CONFIG_CRITICAL_END \ + mutex_unlock(&hotkey_thread_data_mutex); +#else +#define HOTKEY_CONFIG_CRITICAL_START +#define HOTKEY_CONFIG_CRITICAL_END +#endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ + static int hotkey_get_wlsw(int *status) { if (!acpi_evalf(hkey_handle, status, "WLSW", "d")) @@ -795,10 +867,13 @@ static int hotkey_get_wlsw(int *status) */ static int hotkey_mask_get(void) { + u32 m = 0; + if (tp_features.hotkey_mask) { - if (!acpi_evalf(hkey_handle, &hotkey_mask, "DHKN", "d")) + if (!acpi_evalf(hkey_handle, &m, "DHKN", "d")) return -EIO; } + hotkey_mask = m | (hotkey_source_mask & hotkey_mask); return 0; } @@ -812,25 +887,50 @@ static int hotkey_mask_set(u32 mask) int rc = 0; if (tp_features.hotkey_mask) { + HOTKEY_CONFIG_CRITICAL_START for (i = 0; i < 32; i++) { u32 m = 1 << i; + /* enable in firmware mask only keys not in NVRAM + * mode, but enable the key in the cached hotkey_mask + * regardless of mode, or the key will end up + * disabled by hotkey_mask_get() */ if (!acpi_evalf(hkey_handle, NULL, "MHKM", "vdd", i + 1, - !!(mask & m))) { + !!((mask & ~hotkey_source_mask) & m))) { rc = -EIO; break; } else { hotkey_mask = (hotkey_mask & ~m) | (mask & m); } } + HOTKEY_CONFIG_CRITICAL_END /* hotkey_mask_get must be called unconditionally below */ - if (!hotkey_mask_get() && !rc && hotkey_mask != mask) { + if (!hotkey_mask_get() && !rc && + (hotkey_mask & ~hotkey_source_mask) != + (mask & ~hotkey_source_mask)) { printk(IBM_NOTICE "requested hot key mask 0x%08x, but " "firmware forced it to 0x%08x\n", mask, hotkey_mask); } + } else { +#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL + HOTKEY_CONFIG_CRITICAL_START + hotkey_mask = mask & hotkey_source_mask; + HOTKEY_CONFIG_CRITICAL_END + hotkey_mask_get(); + if (hotkey_mask != mask) { + printk(IBM_NOTICE + "requested hot key mask 0x%08x, " + "forced to 0x%08x (NVRAM poll mask is " + "0x%08x): no firmware mask support\n", + mask, hotkey_mask, hotkey_source_mask); + } +#else + hotkey_mask_get(); + rc = -ENXIO; +#endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ } return rc; @@ -892,6 +992,256 @@ static void tpacpi_input_send_key(unsigned int scancode) } } +#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL +static struct tp_acpi_drv_struct ibm_hotkey_acpidriver; + +static void tpacpi_hotkey_send_key(unsigned int scancode) +{ + tpacpi_input_send_key(scancode); + if (hotkey_report_mode < 2) { + acpi_bus_generate_proc_event(ibm_hotkey_acpidriver.device, + 0x80, 0x1001 + scancode); + } +} + +static void hotkey_read_nvram(struct tp_nvram_state *n, u32 m) +{ + u8 d; + + if (m & TP_NVRAM_HKEY_GROUP_HK2) { + d = nvram_read_byte(TP_NVRAM_ADDR_HK2); + n->thinkpad_toggle = !!(d & TP_NVRAM_MASK_HKT_THINKPAD); + n->zoom_toggle = !!(d & TP_NVRAM_MASK_HKT_ZOOM); + n->display_toggle = !!(d & TP_NVRAM_MASK_HKT_DISPLAY); + n->hibernate_toggle = !!(d & TP_NVRAM_MASK_HKT_HIBERNATE); + } + if (m & TP_ACPI_HKEY_THNKLGHT_MASK) { + d = nvram_read_byte(TP_NVRAM_ADDR_THINKLIGHT); + n->thinklight_toggle = !!(d & TP_NVRAM_MASK_THINKLIGHT); + } + if (m & TP_ACPI_HKEY_DISPXPAND_MASK) { + d = nvram_read_byte(TP_NVRAM_ADDR_VIDEO); + n->displayexp_toggle = + !!(d & TP_NVRAM_MASK_HKT_DISPEXPND); + } + if (m & TP_NVRAM_HKEY_GROUP_BRIGHTNESS) { + d = nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS); + n->brightness_level = (d & TP_NVRAM_MASK_LEVEL_BRIGHTNESS) + >> TP_NVRAM_POS_LEVEL_BRIGHTNESS; + n->brightness_toggle = + !!(d & TP_NVRAM_MASK_HKT_BRIGHTNESS); + } + if (m & TP_NVRAM_HKEY_GROUP_VOLUME) { + d = nvram_read_byte(TP_NVRAM_ADDR_MIXER); + n->volume_level = (d & TP_NVRAM_MASK_LEVEL_VOLUME) + >> TP_NVRAM_POS_LEVEL_VOLUME; + n->mute = !!(d & TP_NVRAM_MASK_MUTE); + n->volume_toggle = !!(d & TP_NVRAM_MASK_HKT_VOLUME); + } +} + +#define TPACPI_COMPARE_KEY(__scancode, __member) \ + do { if ((mask & (1 << __scancode)) && oldn->__member != newn->__member) \ + tpacpi_hotkey_send_key(__scancode); } while (0) + +#define TPACPI_MAY_SEND_KEY(__scancode) \ + do { if (mask & (1 << __scancode)) \ + tpacpi_hotkey_send_key(__scancode); } while (0) + +static void hotkey_compare_and_issue_event(struct tp_nvram_state *oldn, + struct tp_nvram_state *newn, + u32 mask) +{ + TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_THINKPAD, thinkpad_toggle); + TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNSPACE, zoom_toggle); + TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNF7, display_toggle); + TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNF12, hibernate_toggle); + + TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNPAGEUP, thinklight_toggle); + + TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNF8, displayexp_toggle); + + /* handle volume */ + if (oldn->volume_toggle != newn->volume_toggle) { + if (oldn->mute != newn->mute) { + TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_MUTE); + } + if (oldn->volume_level > newn->volume_level) { + TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEDOWN); + } else if (oldn->volume_level < newn->volume_level) { + TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEUP); + } else if (oldn->mute == newn->mute) { + /* repeated key presses that didn't change state */ + if (newn->mute) { + TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_MUTE); + } else if (newn->volume_level != 0) { + TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEUP); + } else { + TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEDOWN); + } + } + } + + /* handle brightness */ + if (oldn->brightness_toggle != newn->brightness_toggle) { + if (oldn->brightness_level < newn->brightness_level) { + TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_FNHOME); + } else if (oldn->brightness_level > newn->brightness_level) { + TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_FNEND); + } else { + /* repeated key presses that didn't change state */ + if (newn->brightness_level != 0) { + TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_FNHOME); + } else { + TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_FNEND); + } + } + } +} + +#undef TPACPI_COMPARE_KEY +#undef TPACPI_MAY_SEND_KEY + +static int hotkey_kthread(void *data) +{ + struct tp_nvram_state s[2]; + u32 mask; + unsigned int si, so; + unsigned long t; + unsigned int change_detector, must_reset; + + mutex_lock(&hotkey_thread_mutex); + + if (tpacpi_lifecycle == TPACPI_LIFE_EXITING) + goto exit; + + set_freezable(); + + so = 0; + si = 1; + t = 0; + + /* Initial state for compares */ + mutex_lock(&hotkey_thread_data_mutex); + change_detector = hotkey_config_change; + mask = hotkey_source_mask & hotkey_mask; + mutex_unlock(&hotkey_thread_data_mutex); + hotkey_read_nvram(&s[so], mask); + + while (!kthread_should_stop() && hotkey_poll_freq) { + if (t == 0) + t = 1000/hotkey_poll_freq; + t = msleep_interruptible(t); + if (unlikely(kthread_should_stop())) + break; + must_reset = try_to_freeze(); + if (t > 0 && !must_reset) + continue; + + mutex_lock(&hotkey_thread_data_mutex); + if (must_reset || hotkey_config_change != change_detector) { + /* forget old state on thaw or config change */ + si = so; + t = 0; + change_detector = hotkey_config_change; + } + mask = hotkey_source_mask & hotkey_mask; + mutex_unlock(&hotkey_thread_data_mutex); + + if (likely(mask)) { + hotkey_read_nvram(&s[si], mask); + if (likely(si != so)) { + hotkey_compare_and_issue_event(&s[so], &s[si], + mask); + } + } + + so = si; + si ^= 1; + } + +exit: + mutex_unlock(&hotkey_thread_mutex); + return 0; +} + +static void hotkey_poll_stop_sync(void) +{ + if (tpacpi_hotkey_task) { + if (frozen(tpacpi_hotkey_task) || + freezing(tpacpi_hotkey_task)) + thaw_process(tpacpi_hotkey_task); + + kthread_stop(tpacpi_hotkey_task); + tpacpi_hotkey_task = NULL; + mutex_lock(&hotkey_thread_mutex); + /* at this point, the thread did exit */ + mutex_unlock(&hotkey_thread_mutex); + } +} + +/* call with hotkey_mutex held */ +static void hotkey_poll_setup(int may_warn) +{ + if ((hotkey_source_mask & hotkey_mask) != 0 && + hotkey_poll_freq > 0 && + (tpacpi_inputdev->users > 0 || hotkey_report_mode < 2)) { + if (!tpacpi_hotkey_task) { + tpacpi_hotkey_task = kthread_run(hotkey_kthread, + NULL, IBM_FILE "d"); + if (IS_ERR(tpacpi_hotkey_task)) { + tpacpi_hotkey_task = NULL; + printk(IBM_ERR "could not create kernel thread " + "for hotkey polling\n"); + } + } + } else { + hotkey_poll_stop_sync(); + if (may_warn && + hotkey_source_mask != 0 && hotkey_poll_freq == 0) { + printk(IBM_NOTICE "hot keys 0x%08x require polling, " + "which is currently disabled\n", + hotkey_source_mask); + } + } +} + +static void hotkey_poll_setup_safe(int may_warn) +{ + mutex_lock(&hotkey_mutex); + hotkey_poll_setup(may_warn); + mutex_unlock(&hotkey_mutex); +} + +static int hotkey_inputdev_open(struct input_dev *dev) +{ + switch (tpacpi_lifecycle) { + case TPACPI_LIFE_INIT: + /* + * hotkey_init will call hotkey_poll_setup_safe + * at the appropriate moment + */ + return 0; + case TPACPI_LIFE_EXITING: + return -EBUSY; + case TPACPI_LIFE_RUNNING: + hotkey_poll_setup_safe(0); + return 0; + } + + /* Should only happen if tpacpi_lifecycle is corrupt */ + BUG(); + return -EBUSY; +} + +static void hotkey_inputdev_close(struct input_dev *dev) +{ + /* disable hotkey polling when possible */ + if (tpacpi_lifecycle == TPACPI_LIFE_RUNNING) + hotkey_poll_setup_safe(0); +} +#endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ + /* sysfs hotkey enable ------------------------------------------------- */ static ssize_t hotkey_enable_show(struct device *dev, struct device_attribute *attr, @@ -955,6 +1305,11 @@ static ssize_t hotkey_mask_store(struct device *dev, return -ERESTARTSYS; res = hotkey_mask_set(t); + +#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL + hotkey_poll_setup(1); +#endif + mutex_unlock(&hotkey_mutex); return (res) ? res : count; @@ -991,7 +1346,8 @@ static ssize_t hotkey_all_mask_show(struct device *dev, struct device_attribute *attr, char *buf) { - return snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_all_mask); + return snprintf(buf, PAGE_SIZE, "0x%08x\n", + hotkey_all_mask | hotkey_source_mask); } static struct device_attribute dev_attr_hotkey_all_mask = @@ -1003,13 +1359,86 @@ static ssize_t hotkey_recommended_mask_show(struct device *dev, char *buf) { return snprintf(buf, PAGE_SIZE, "0x%08x\n", - hotkey_all_mask & ~hotkey_reserved_mask); + (hotkey_all_mask | hotkey_source_mask) + & ~hotkey_reserved_mask); } static struct device_attribute dev_attr_hotkey_recommended_mask = __ATTR(hotkey_recommended_mask, S_IRUGO, hotkey_recommended_mask_show, NULL); +#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL + +/* sysfs hotkey hotkey_source_mask ------------------------------------- */ +static ssize_t hotkey_source_mask_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_source_mask); +} + +static ssize_t hotkey_source_mask_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long t; + + if (parse_strtoul(buf, 0xffffffffUL, &t) || + ((t & ~TPACPI_HKEY_NVRAM_KNOWN_MASK) != 0)) + return -EINVAL; + + if (mutex_lock_interruptible(&hotkey_mutex)) + return -ERESTARTSYS; + + HOTKEY_CONFIG_CRITICAL_START + hotkey_source_mask = t; + HOTKEY_CONFIG_CRITICAL_END + + hotkey_poll_setup(1); + + mutex_unlock(&hotkey_mutex); + + return count; +} + +static struct device_attribute dev_attr_hotkey_source_mask = + __ATTR(hotkey_source_mask, S_IWUSR | S_IRUGO, + hotkey_source_mask_show, hotkey_source_mask_store); + +/* sysfs hotkey hotkey_poll_freq --------------------------------------- */ +static ssize_t hotkey_poll_freq_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", hotkey_poll_freq); +} + +static ssize_t hotkey_poll_freq_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long t; + + if (parse_strtoul(buf, 25, &t)) + return -EINVAL; + + if (mutex_lock_interruptible(&hotkey_mutex)) + return -ERESTARTSYS; + + hotkey_poll_freq = t; + + hotkey_poll_setup(1); + mutex_unlock(&hotkey_mutex); + + return count; +} + +static struct device_attribute dev_attr_hotkey_poll_freq = + __ATTR(hotkey_poll_freq, S_IWUSR | S_IRUGO, + hotkey_poll_freq_show, hotkey_poll_freq_store); + +#endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ + /* sysfs hotkey radio_sw ----------------------------------------------- */ static ssize_t hotkey_radio_sw_show(struct device *dev, struct device_attribute *attr, @@ -1042,15 +1471,24 @@ static struct device_attribute dev_attr_hotkey_report_mode = static struct attribute *hotkey_attributes[] __initdata = { &dev_attr_hotkey_enable.attr, + &dev_attr_hotkey_bios_enabled.attr, &dev_attr_hotkey_report_mode.attr, +#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL + &dev_attr_hotkey_mask.attr, + &dev_attr_hotkey_all_mask.attr, + &dev_attr_hotkey_recommended_mask.attr, + &dev_attr_hotkey_source_mask.attr, + &dev_attr_hotkey_poll_freq.attr, +#endif }; static struct attribute *hotkey_mask_attributes[] __initdata = { - &dev_attr_hotkey_mask.attr, - &dev_attr_hotkey_bios_enabled.attr, &dev_attr_hotkey_bios_mask.attr, +#ifndef CONFIG_THINKPAD_ACPI_HOTKEY_POLL + &dev_attr_hotkey_mask.attr, &dev_attr_hotkey_all_mask.attr, &dev_attr_hotkey_recommended_mask.attr, +#endif }; static int __init hotkey_init(struct ibm_init_struct *iibm) @@ -1172,10 +1610,17 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) vdbg_printk(TPACPI_DBG_INIT, "initializing hotkey subdriver\n"); BUG_ON(!tpacpi_inputdev); + BUG_ON(tpacpi_inputdev->open != NULL || + tpacpi_inputdev->close != NULL); IBM_ACPIHANDLE_INIT(hkey); mutex_init(&hotkey_mutex); +#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL + mutex_init(&hotkey_thread_mutex); + mutex_init(&hotkey_thread_data_mutex); +#endif + /* hotkey not supported on 570 */ tp_features.hotkey = hkey_handle != NULL; @@ -1183,7 +1628,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) str_supported(tp_features.hotkey)); if (tp_features.hotkey) { - hotkey_dev_attributes = create_attr_set(8, NULL); + hotkey_dev_attributes = create_attr_set(10, NULL); if (!hotkey_dev_attributes) return -ENOMEM; res = add_many_to_attr_set(hotkey_dev_attributes, @@ -1205,7 +1650,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) /* * MHKV 0x100 in A31, R40, R40e, * T4x, X31, and later - * */ + */ tp_features.hotkey_mask = 1; } } @@ -1224,6 +1669,8 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) } } + /* hotkey_source_mask *must* be zero for + * the first hotkey_mask_get */ res = hotkey_status_get(&hotkey_orig_status); if (!res && tp_features.hotkey_mask) { res = hotkey_mask_get(); @@ -1236,6 +1683,19 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) } } +#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL + if (tp_features.hotkey_mask) { + hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK + & ~hotkey_all_mask; + } else { + hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK; + } + + vdbg_printk(TPACPI_DBG_INIT, + "hotkey source mask 0x%08x, polling freq %d\n", + hotkey_source_mask, hotkey_poll_freq); +#endif + /* Not all thinkpads have a hardware radio switch */ if (!res && acpi_evalf(hkey_handle, &status, "WLSW", "qd")) { tp_features.hotkey_wlsw = 1; @@ -1300,15 +1760,23 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) res = hotkey_status_set(1); if (res) return res; - res = hotkey_mask_set((hotkey_all_mask & ~hotkey_reserved_mask) + res = hotkey_mask_set(((hotkey_all_mask | hotkey_source_mask) + & ~hotkey_reserved_mask) | hotkey_orig_mask); - if (res) + if (res < 0 && res != -ENXIO) return res; dbg_printk(TPACPI_DBG_INIT, "legacy hot key reporting over procfs %s\n", (hotkey_report_mode < 2) ? "enabled" : "disabled"); + +#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL + tpacpi_inputdev->open = &hotkey_inputdev_open; + tpacpi_inputdev->close = &hotkey_inputdev_close; + + hotkey_poll_setup_safe(1); +#endif } return (tp_features.hotkey)? 0 : 1; @@ -1316,6 +1784,10 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) static void hotkey_exit(void) { +#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL + hotkey_poll_stop_sync(); +#endif + if (tp_features.hotkey) { dbg_printk(TPACPI_DBG_EXIT, "restoring original hot key mask\n"); /* no short-circuit boolean operator below! */ @@ -1366,7 +1838,11 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) scancode = hkey & 0xfff; if (scancode > 0 && scancode < 0x21) { scancode--; - tpacpi_input_send_key(scancode); + if (!(hotkey_source_mask & (1 << scancode))) { + tpacpi_input_send_key(scancode); + } else { + ignore_acpi_ev = 1; + } } else { printk(IBM_ERR "hotkey 0x%04x out of range for keyboard map\n", @@ -1422,6 +1898,9 @@ static void hotkey_resume(void) if (hotkey_mask_get()) printk(IBM_ERR "error while trying to read hot key mask from firmware\n"); tpacpi_input_send_radiosw(); +#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL + hotkey_poll_setup_safe(0); +#endif } /* procfs -------------------------------------------------------------- */ diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h index 3b031344313..582184dc454 100644 --- a/drivers/misc/thinkpad_acpi.h +++ b/drivers/misc/thinkpad_acpi.h @@ -31,6 +31,9 @@ #include #include #include +#include +#include +#include #include #include @@ -82,10 +85,31 @@ #define TP_CMOS_BRIGHTNESS_UP 4 #define TP_CMOS_BRIGHTNESS_DOWN 5 -/* ThinkPad CMOS NVRAM constants */ -#define TP_NVRAM_ADDR_BRIGHTNESS 0x5e -#define TP_NVRAM_MASK_LEVEL_BRIGHTNESS 0x0f -#define TP_NVRAM_POS_LEVEL_BRIGHTNESS 0 +/* NVRAM Addresses */ +enum tp_nvram_addr { + TP_NVRAM_ADDR_HK2 = 0x57, + TP_NVRAM_ADDR_THINKLIGHT = 0x58, + TP_NVRAM_ADDR_VIDEO = 0x59, + TP_NVRAM_ADDR_BRIGHTNESS = 0x5e, + TP_NVRAM_ADDR_MIXER = 0x60, +}; + +/* NVRAM bit masks */ +enum { + TP_NVRAM_MASK_HKT_THINKPAD = 0x08, + TP_NVRAM_MASK_HKT_ZOOM = 0x20, + TP_NVRAM_MASK_HKT_DISPLAY = 0x40, + TP_NVRAM_MASK_HKT_HIBERNATE = 0x80, + TP_NVRAM_MASK_THINKLIGHT = 0x10, + TP_NVRAM_MASK_HKT_DISPEXPND = 0x30, + TP_NVRAM_MASK_HKT_BRIGHTNESS = 0x20, + TP_NVRAM_MASK_LEVEL_BRIGHTNESS = 0x0f, + TP_NVRAM_POS_LEVEL_BRIGHTNESS = 0, + TP_NVRAM_MASK_MUTE = 0x40, + TP_NVRAM_MASK_HKT_VOLUME = 0x80, + TP_NVRAM_MASK_LEVEL_VOLUME = 0x0f, + TP_NVRAM_POS_LEVEL_VOLUME = 0, +}; #define onoff(status,bit) ((status) & (1 << (bit)) ? "on" : "off") #define enabled(status,bit) ((status) & (1 << (bit)) ? "enabled" : "disabled") @@ -255,6 +279,7 @@ static struct { u32 sensors_pdrv_registered:1; u32 sensors_pdrv_attrs_registered:1; u32 sensors_pdev_attrs_registered:1; + u32 hotkey_poll_active:1; } tp_features; struct thinkpad_id_data { @@ -454,6 +479,33 @@ static int fan_write_cmd_watchdog(const char *cmd, int *rc); * Hotkey subdriver */ +enum { /* hot key scan codes (derived from ACPI DSDT) */ + TP_ACPI_HOTKEYSCAN_FNF1 = 0, + TP_ACPI_HOTKEYSCAN_FNF2, + TP_ACPI_HOTKEYSCAN_FNF3, + TP_ACPI_HOTKEYSCAN_FNF4, + TP_ACPI_HOTKEYSCAN_FNF5, + TP_ACPI_HOTKEYSCAN_FNF6, + TP_ACPI_HOTKEYSCAN_FNF7, + TP_ACPI_HOTKEYSCAN_FNF8, + TP_ACPI_HOTKEYSCAN_FNF9, + TP_ACPI_HOTKEYSCAN_FNF10, + TP_ACPI_HOTKEYSCAN_FNF11, + TP_ACPI_HOTKEYSCAN_FNF12, + TP_ACPI_HOTKEYSCAN_FNBACKSPACE, + TP_ACPI_HOTKEYSCAN_FNINSERT, + TP_ACPI_HOTKEYSCAN_FNDELETE, + TP_ACPI_HOTKEYSCAN_FNHOME, + TP_ACPI_HOTKEYSCAN_FNEND, + TP_ACPI_HOTKEYSCAN_FNPAGEUP, + TP_ACPI_HOTKEYSCAN_FNPAGEDOWN, + TP_ACPI_HOTKEYSCAN_FNSPACE, + TP_ACPI_HOTKEYSCAN_VOLUMEUP, + TP_ACPI_HOTKEYSCAN_VOLUMEDOWN, + TP_ACPI_HOTKEYSCAN_MUTE, + TP_ACPI_HOTKEYSCAN_THINKPAD, +}; + static int hotkey_orig_status; static u32 hotkey_orig_mask; -- cgit v1.2.3 From 50efd8310f4f532231b15c6bcb9007c99ac05466 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Tue, 8 Jan 2008 13:02:42 -0200 Subject: ACPI: thinkpad-acpi: bump up version to 0.18 The NVRAM polling support for hot keys is reason enough to bump up the version string. Do it. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/misc') diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 9ff9142ce06..11ee444261b 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -21,7 +21,7 @@ * 02110-1301, USA. */ -#define IBM_VERSION "0.17" +#define IBM_VERSION "0.18" #define TPACPI_SYSFS_VERSION 0x020101 /* -- cgit v1.2.3 From 0c78039fcdb0806fafcc40400ace7fb7e81c65a5 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Tue, 8 Jan 2008 13:02:43 -0200 Subject: ACPI: thinkpad-acpi: spring cleanup part 1 Remove the header file. Private header files used by a single .c file are in bad taste, and I know better now. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 632 ++++++++++++++++++++++++++++++++++++++++- drivers/misc/thinkpad_acpi.h | 656 ------------------------------------------- 2 files changed, 631 insertions(+), 657 deletions(-) delete mode 100644 drivers/misc/thinkpad_acpi.h (limited to 'drivers/misc') diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 11ee444261b..59b127cff1e 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -82,7 +82,637 @@ * 2004-08-09 0.1 initial release, support for X series */ -#include "thinkpad_acpi.h" +/* ==================================================== BEGIN HEADER */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +/**************************************************************************** + * Main driver + */ + +#define IBM_NAME "thinkpad" +#define IBM_DESC "ThinkPad ACPI Extras" +#define IBM_FILE IBM_NAME "_acpi" +#define IBM_URL "http://ibm-acpi.sf.net/" +#define IBM_MAIL "ibm-acpi-devel@lists.sourceforge.net" + +#define IBM_PROC_DIR "ibm" +#define IBM_ACPI_EVENT_PREFIX "ibm" +#define IBM_DRVR_NAME IBM_FILE +#define IBM_HWMON_DRVR_NAME IBM_NAME "_hwmon" + +#define IBM_LOG IBM_FILE ": " +#define IBM_ERR KERN_ERR IBM_LOG +#define IBM_NOTICE KERN_NOTICE IBM_LOG +#define IBM_INFO KERN_INFO IBM_LOG +#define IBM_DEBUG KERN_DEBUG IBM_LOG + +#define IBM_MAX_ACPI_ARGS 3 + +/* ThinkPad CMOS commands */ +#define TP_CMOS_VOLUME_DOWN 0 +#define TP_CMOS_VOLUME_UP 1 +#define TP_CMOS_VOLUME_MUTE 2 +#define TP_CMOS_BRIGHTNESS_UP 4 +#define TP_CMOS_BRIGHTNESS_DOWN 5 + +/* NVRAM Addresses */ +enum tp_nvram_addr { + TP_NVRAM_ADDR_HK2 = 0x57, + TP_NVRAM_ADDR_THINKLIGHT = 0x58, + TP_NVRAM_ADDR_VIDEO = 0x59, + TP_NVRAM_ADDR_BRIGHTNESS = 0x5e, + TP_NVRAM_ADDR_MIXER = 0x60, +}; + +/* NVRAM bit masks */ +enum { + TP_NVRAM_MASK_HKT_THINKPAD = 0x08, + TP_NVRAM_MASK_HKT_ZOOM = 0x20, + TP_NVRAM_MASK_HKT_DISPLAY = 0x40, + TP_NVRAM_MASK_HKT_HIBERNATE = 0x80, + TP_NVRAM_MASK_THINKLIGHT = 0x10, + TP_NVRAM_MASK_HKT_DISPEXPND = 0x30, + TP_NVRAM_MASK_HKT_BRIGHTNESS = 0x20, + TP_NVRAM_MASK_LEVEL_BRIGHTNESS = 0x0f, + TP_NVRAM_POS_LEVEL_BRIGHTNESS = 0, + TP_NVRAM_MASK_MUTE = 0x40, + TP_NVRAM_MASK_HKT_VOLUME = 0x80, + TP_NVRAM_MASK_LEVEL_VOLUME = 0x0f, + TP_NVRAM_POS_LEVEL_VOLUME = 0, +}; + +#define onoff(status,bit) ((status) & (1 << (bit)) ? "on" : "off") +#define enabled(status,bit) ((status) & (1 << (bit)) ? "enabled" : "disabled") +#define strlencmp(a,b) (strncmp((a), (b), strlen(b))) + +/* Debugging */ +#define TPACPI_DBG_ALL 0xffff +#define TPACPI_DBG_ALL 0xffff +#define TPACPI_DBG_INIT 0x0001 +#define TPACPI_DBG_EXIT 0x0002 +#define dbg_printk(a_dbg_level, format, arg...) \ + do { if (dbg_level & a_dbg_level) \ + printk(IBM_DEBUG "%s: " format, __func__ , ## arg); } while (0) +#ifdef CONFIG_THINKPAD_ACPI_DEBUG +#define vdbg_printk(a_dbg_level, format, arg...) \ + dbg_printk(a_dbg_level, format, ## arg) +static const char *str_supported(int is_supported); +#else +#define vdbg_printk(a_dbg_level, format, arg...) +#endif + +/* Input IDs */ +#define TPACPI_HKEY_INPUT_VENDOR PCI_VENDOR_ID_IBM +#define TPACPI_HKEY_INPUT_PRODUCT 0x5054 /* "TP" */ +#define TPACPI_HKEY_INPUT_VERSION 0x4101 + +/* ACPI HIDs */ +#define IBM_HKEY_HID "IBM0068" + +/* ACPI helpers */ +static int __must_check acpi_evalf(acpi_handle handle, + void *res, char *method, char *fmt, ...); +static int __must_check acpi_ec_read(int i, u8 * p); +static int __must_check acpi_ec_write(int i, u8 v); +static int __must_check _sta(acpi_handle handle); + +/* ACPI handles */ +static acpi_handle root_handle; /* root namespace */ +static acpi_handle ec_handle; /* EC */ +static acpi_handle ecrd_handle, ecwr_handle; /* 570 EC access */ +static acpi_handle cmos_handle, hkey_handle; /* basic thinkpad handles */ + +static void drv_acpi_handle_init(char *name, + acpi_handle *handle, acpi_handle parent, + char **paths, int num_paths, char **path); +#define IBM_ACPIHANDLE_INIT(object) \ + drv_acpi_handle_init(#object, &object##_handle, *object##_parent, \ + object##_paths, ARRAY_SIZE(object##_paths), &object##_path) + +/* ThinkPad ACPI helpers */ +static int issue_thinkpad_cmos_command(int cmos_cmd); + +/* procfs support */ +static struct proc_dir_entry *proc_dir; + +/* procfs helpers */ +static int dispatch_procfs_read(char *page, char **start, off_t off, + int count, int *eof, void *data); +static int dispatch_procfs_write(struct file *file, + const char __user * userbuf, + unsigned long count, void *data); +static char *next_cmd(char **cmds); + +/* sysfs support */ +struct attribute_set { + unsigned int members, max_members; + struct attribute_group group; +}; + +static struct attribute_set *create_attr_set(unsigned int max_members, + const char* name); +#define destroy_attr_set(_set) \ + kfree(_set); +static int add_to_attr_set(struct attribute_set* s, struct attribute *attr); +static int add_many_to_attr_set(struct attribute_set* s, + struct attribute **attr, + unsigned int count); +#define register_attr_set_with_sysfs(_attr_set, _kobj) \ + sysfs_create_group(_kobj, &_attr_set->group) +static void delete_attr_set(struct attribute_set* s, struct kobject *kobj); + +static int parse_strtoul(const char *buf, unsigned long max, + unsigned long *value); + +/* Device model */ +static struct platform_device *tpacpi_pdev; +static struct platform_device *tpacpi_sensors_pdev; +static struct device *tpacpi_hwmon; +static struct platform_driver tpacpi_pdriver; +static struct input_dev *tpacpi_inputdev; +static int tpacpi_create_driver_attributes(struct device_driver *drv); +static void tpacpi_remove_driver_attributes(struct device_driver *drv); + +/* Module */ +static int experimental; +static u32 dbg_level; +static int force_load; +static unsigned int hotkey_report_mode; + +static int thinkpad_acpi_module_init(void); +static void thinkpad_acpi_module_exit(void); + + +/**************************************************************************** + * Subdrivers + */ + +struct ibm_struct; + +struct tp_acpi_drv_struct { + const struct acpi_device_id *hid; + struct acpi_driver *driver; + + void (*notify) (struct ibm_struct *, u32); + acpi_handle *handle; + u32 type; + struct acpi_device *device; +}; + +struct ibm_struct { + char *name; + + int (*read) (char *); + int (*write) (char *); + void (*exit) (void); + void (*resume) (void); + + struct list_head all_drivers; + + struct tp_acpi_drv_struct *acpi; + + struct { + u8 acpi_driver_registered:1; + u8 acpi_notify_installed:1; + u8 proc_created:1; + u8 init_called:1; + u8 experimental:1; + } flags; +}; + +struct ibm_init_struct { + char param[32]; + + int (*init) (struct ibm_init_struct *); + struct ibm_struct *data; +}; + +static struct { +#ifdef CONFIG_THINKPAD_ACPI_BAY + u32 bay_status:1; + u32 bay_eject:1; + u32 bay_status2:1; + u32 bay_eject2:1; +#endif + u32 bluetooth:1; + u32 hotkey:1; + u32 hotkey_mask:1; + u32 hotkey_wlsw:1; + u32 light:1; + u32 light_status:1; + u32 bright_16levels:1; + u32 wan:1; + u32 fan_ctrl_status_undef:1; + u32 input_device_registered:1; + u32 platform_drv_registered:1; + u32 platform_drv_attrs_registered:1; + u32 sensors_pdrv_registered:1; + u32 sensors_pdrv_attrs_registered:1; + u32 sensors_pdev_attrs_registered:1; + u32 hotkey_poll_active:1; +} tp_features; + +struct thinkpad_id_data { + unsigned int vendor; /* ThinkPad vendor: + * PCI_VENDOR_ID_IBM/PCI_VENDOR_ID_LENOVO */ + + char *bios_version_str; /* Something like 1ZET51WW (1.03z) */ + char *ec_version_str; /* Something like 1ZHT51WW-1.04a */ + + u16 bios_model; /* Big Endian, TP-1Y = 0x5931, 0 = unknown */ + u16 ec_model; + + char *model_str; +}; + +static struct thinkpad_id_data thinkpad_id; + +static struct list_head tpacpi_all_drivers; + +static struct ibm_init_struct ibms_init[]; +static int set_ibm_param(const char *val, struct kernel_param *kp); +static int ibm_init(struct ibm_init_struct *iibm); +static void ibm_exit(struct ibm_struct *ibm); + + +/* + * procfs master subdriver + */ +static int thinkpad_acpi_driver_init(struct ibm_init_struct *iibm); +static int thinkpad_acpi_driver_read(char *p); + + +/* + * Bay subdriver + */ + +#ifdef CONFIG_THINKPAD_ACPI_BAY +static acpi_handle bay_handle, bay_ej_handle; +static acpi_handle bay2_handle, bay2_ej_handle; + +static int bay_init(struct ibm_init_struct *iibm); +static void bay_notify(struct ibm_struct *ibm, u32 event); +static int bay_read(char *p); +static int bay_write(char *buf); +#endif /* CONFIG_THINKPAD_ACPI_BAY */ + + +/* + * Beep subdriver + */ + +static acpi_handle beep_handle; + +static int beep_read(char *p); +static int beep_write(char *buf); + + +/* + * Bluetooth subdriver + */ + +enum { + /* ACPI GBDC/SBDC bits */ + TP_ACPI_BLUETOOTH_HWPRESENT = 0x01, /* Bluetooth hw available */ + TP_ACPI_BLUETOOTH_RADIOSSW = 0x02, /* Bluetooth radio enabled */ + TP_ACPI_BLUETOOTH_UNK = 0x04, /* unknown function */ +}; + +static int bluetooth_init(struct ibm_init_struct *iibm); +static int bluetooth_get_radiosw(void); +static int bluetooth_set_radiosw(int radio_on); +static int bluetooth_read(char *p); +static int bluetooth_write(char *buf); + + +/* + * Brightness (backlight) subdriver + */ + +#define TPACPI_BACKLIGHT_DEV_NAME "thinkpad_screen" + +static struct backlight_device *ibm_backlight_device; +static int brightness_offset = 0x31; +static int brightness_mode; +static unsigned int brightness_enable; /* 0 = no, 1 = yes, 2 = auto */ + +static int brightness_init(struct ibm_init_struct *iibm); +static void brightness_exit(void); +static int brightness_get(struct backlight_device *bd); +static int brightness_set(int value); +static int brightness_update_status(struct backlight_device *bd); +static int brightness_read(char *p); +static int brightness_write(char *buf); + + +/* + * CMOS subdriver + */ + +static int cmos_read(char *p); +static int cmos_write(char *buf); + + +/* + * Dock subdriver + */ + +#ifdef CONFIG_THINKPAD_ACPI_DOCK +static acpi_handle pci_handle; +static acpi_handle dock_handle; + +static void dock_notify(struct ibm_struct *ibm, u32 event); +static int dock_read(char *p); +static int dock_write(char *buf); +#endif /* CONFIG_THINKPAD_ACPI_DOCK */ + + +/* + * EC dump subdriver + */ + +static int ecdump_read(char *p) ; +static int ecdump_write(char *buf); + + +/* + * Fan subdriver + */ + +enum { /* Fan control constants */ + fan_status_offset = 0x2f, /* EC register 0x2f */ + fan_rpm_offset = 0x84, /* EC register 0x84: LSB, 0x85 MSB (RPM) + * 0x84 must be read before 0x85 */ + + TP_EC_FAN_FULLSPEED = 0x40, /* EC fan mode: full speed */ + TP_EC_FAN_AUTO = 0x80, /* EC fan mode: auto fan control */ + + TPACPI_FAN_LAST_LEVEL = 0x100, /* Use cached last-seen fan level */ +}; + +enum fan_status_access_mode { + TPACPI_FAN_NONE = 0, /* No fan status or control */ + TPACPI_FAN_RD_ACPI_GFAN, /* Use ACPI GFAN */ + TPACPI_FAN_RD_TPEC, /* Use ACPI EC regs 0x2f, 0x84-0x85 */ +}; + +enum fan_control_access_mode { + TPACPI_FAN_WR_NONE = 0, /* No fan control */ + TPACPI_FAN_WR_ACPI_SFAN, /* Use ACPI SFAN */ + TPACPI_FAN_WR_TPEC, /* Use ACPI EC reg 0x2f */ + TPACPI_FAN_WR_ACPI_FANS, /* Use ACPI FANS and EC reg 0x2f */ +}; + +enum fan_control_commands { + TPACPI_FAN_CMD_SPEED = 0x0001, /* speed command */ + TPACPI_FAN_CMD_LEVEL = 0x0002, /* level command */ + TPACPI_FAN_CMD_ENABLE = 0x0004, /* enable/disable cmd, + * and also watchdog cmd */ +}; + +static int fan_control_allowed; + +static enum fan_status_access_mode fan_status_access_mode; +static enum fan_control_access_mode fan_control_access_mode; +static enum fan_control_commands fan_control_commands; +static u8 fan_control_initial_status; +static u8 fan_control_desired_level; +static int fan_watchdog_maxinterval; + +static struct mutex fan_mutex; + +static acpi_handle fans_handle, gfan_handle, sfan_handle; + +static int fan_init(struct ibm_init_struct *iibm); +static void fan_exit(void); +static int fan_get_status(u8 *status); +static int fan_get_status_safe(u8 *status); +static int fan_get_speed(unsigned int *speed); +static void fan_update_desired_level(u8 status); +static void fan_watchdog_fire(struct work_struct *ignored); +static void fan_watchdog_reset(void); +static int fan_set_level(int level); +static int fan_set_level_safe(int level); +static int fan_set_enable(void); +static int fan_set_disable(void); +static int fan_set_speed(int speed); +static int fan_read(char *p); +static int fan_write(char *buf); +static int fan_write_cmd_level(const char *cmd, int *rc); +static int fan_write_cmd_enable(const char *cmd, int *rc); +static int fan_write_cmd_disable(const char *cmd, int *rc); +static int fan_write_cmd_speed(const char *cmd, int *rc); +static int fan_write_cmd_watchdog(const char *cmd, int *rc); + + +/* + * Hotkey subdriver + */ + +enum { /* hot key scan codes (derived from ACPI DSDT) */ + TP_ACPI_HOTKEYSCAN_FNF1 = 0, + TP_ACPI_HOTKEYSCAN_FNF2, + TP_ACPI_HOTKEYSCAN_FNF3, + TP_ACPI_HOTKEYSCAN_FNF4, + TP_ACPI_HOTKEYSCAN_FNF5, + TP_ACPI_HOTKEYSCAN_FNF6, + TP_ACPI_HOTKEYSCAN_FNF7, + TP_ACPI_HOTKEYSCAN_FNF8, + TP_ACPI_HOTKEYSCAN_FNF9, + TP_ACPI_HOTKEYSCAN_FNF10, + TP_ACPI_HOTKEYSCAN_FNF11, + TP_ACPI_HOTKEYSCAN_FNF12, + TP_ACPI_HOTKEYSCAN_FNBACKSPACE, + TP_ACPI_HOTKEYSCAN_FNINSERT, + TP_ACPI_HOTKEYSCAN_FNDELETE, + TP_ACPI_HOTKEYSCAN_FNHOME, + TP_ACPI_HOTKEYSCAN_FNEND, + TP_ACPI_HOTKEYSCAN_FNPAGEUP, + TP_ACPI_HOTKEYSCAN_FNPAGEDOWN, + TP_ACPI_HOTKEYSCAN_FNSPACE, + TP_ACPI_HOTKEYSCAN_VOLUMEUP, + TP_ACPI_HOTKEYSCAN_VOLUMEDOWN, + TP_ACPI_HOTKEYSCAN_MUTE, + TP_ACPI_HOTKEYSCAN_THINKPAD, +}; + +static int hotkey_orig_status; +static u32 hotkey_orig_mask; + +static struct mutex hotkey_mutex; + +static int hotkey_init(struct ibm_init_struct *iibm); +static void hotkey_exit(void); +static void hotkey_notify(struct ibm_struct *ibm, u32 event); +static int hotkey_read(char *p); +static int hotkey_write(char *buf); + + +/* + * LED subdriver + */ + +enum led_access_mode { + TPACPI_LED_NONE = 0, + TPACPI_LED_570, /* 570 */ + TPACPI_LED_OLD, /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */ + TPACPI_LED_NEW, /* all others */ +}; + +enum { /* For TPACPI_LED_OLD */ + TPACPI_LED_EC_HLCL = 0x0c, /* EC reg to get led to power on */ + TPACPI_LED_EC_HLBL = 0x0d, /* EC reg to blink a lit led */ + TPACPI_LED_EC_HLMS = 0x0e, /* EC reg to select led to command */ +}; + +static enum led_access_mode led_supported; +static acpi_handle led_handle; + +static int led_init(struct ibm_init_struct *iibm); +static int led_read(char *p); +static int led_write(char *buf); + +/* + * Light (thinklight) subdriver + */ + +static acpi_handle lght_handle, ledb_handle; + +static int light_init(struct ibm_init_struct *iibm); +static int light_read(char *p); +static int light_write(char *buf); + + +/* + * Thermal subdriver + */ + +enum thermal_access_mode { + TPACPI_THERMAL_NONE = 0, /* No thermal support */ + TPACPI_THERMAL_ACPI_TMP07, /* Use ACPI TMP0-7 */ + TPACPI_THERMAL_ACPI_UPDT, /* Use ACPI TMP0-7 with UPDT */ + TPACPI_THERMAL_TPEC_8, /* Use ACPI EC regs, 8 sensors */ + TPACPI_THERMAL_TPEC_16, /* Use ACPI EC regs, 16 sensors */ +}; + +enum { /* TPACPI_THERMAL_TPEC_* */ + TP_EC_THERMAL_TMP0 = 0x78, /* ACPI EC regs TMP 0..7 */ + TP_EC_THERMAL_TMP8 = 0xC0, /* ACPI EC regs TMP 8..15 */ + TP_EC_THERMAL_TMP_NA = -128, /* ACPI EC sensor not available */ +}; + +#define TPACPI_MAX_THERMAL_SENSORS 16 /* Max thermal sensors supported */ +struct ibm_thermal_sensors_struct { + s32 temp[TPACPI_MAX_THERMAL_SENSORS]; +}; + +static enum thermal_access_mode thermal_read_mode; + +static int thermal_init(struct ibm_init_struct *iibm); +static int thermal_get_sensor(int idx, s32 *value); +static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s); +static int thermal_read(char *p); + + +/* + * Video subdriver + */ + +enum video_access_mode { + TPACPI_VIDEO_NONE = 0, + TPACPI_VIDEO_570, /* 570 */ + TPACPI_VIDEO_770, /* 600e/x, 770e, 770x */ + TPACPI_VIDEO_NEW, /* all others */ +}; + +enum { /* video status flags, based on VIDEO_570 */ + TP_ACPI_VIDEO_S_LCD = 0x01, /* LCD output enabled */ + TP_ACPI_VIDEO_S_CRT = 0x02, /* CRT output enabled */ + TP_ACPI_VIDEO_S_DVI = 0x08, /* DVI output enabled */ +}; + +enum { /* TPACPI_VIDEO_570 constants */ + TP_ACPI_VIDEO_570_PHSCMD = 0x87, /* unknown magic constant :( */ + TP_ACPI_VIDEO_570_PHSMASK = 0x03, /* PHS bits that map to + * video_status_flags */ + TP_ACPI_VIDEO_570_PHS2CMD = 0x8b, /* unknown magic constant :( */ + TP_ACPI_VIDEO_570_PHS2SET = 0x80, /* unknown magic constant :( */ +}; + +static enum video_access_mode video_supported; +static int video_orig_autosw; +static acpi_handle vid_handle, vid2_handle; + +static int video_init(struct ibm_init_struct *iibm); +static void video_exit(void); +static int video_outputsw_get(void); +static int video_outputsw_set(int status); +static int video_autosw_get(void); +static int video_autosw_set(int enable); +static int video_outputsw_cycle(void); +static int video_expand_toggle(void); +static int video_read(char *p); +static int video_write(char *buf); + + +/* + * Volume subdriver + */ + +static int volume_offset = 0x30; + +static int volume_read(char *p); +static int volume_write(char *buf); + + +/* + * Wan subdriver + */ + +enum { + /* ACPI GWAN/SWAN bits */ + TP_ACPI_WANCARD_HWPRESENT = 0x01, /* Wan hw available */ + TP_ACPI_WANCARD_RADIOSSW = 0x02, /* Wan radio enabled */ + TP_ACPI_WANCARD_UNK = 0x04, /* unknown function */ +}; + +static int wan_init(struct ibm_init_struct *iibm); +static int wan_get_radiosw(void); +static int wan_set_radiosw(int radio_on); +static int wan_read(char *p); +static int wan_write(char *buf); + +/* ==================================================== END HEADER */ MODULE_AUTHOR("Borislav Deianov, Henrique de Moraes Holschuh"); MODULE_DESCRIPTION(IBM_DESC); diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h deleted file mode 100644 index 582184dc454..00000000000 --- a/drivers/misc/thinkpad_acpi.h +++ /dev/null @@ -1,656 +0,0 @@ -/* - * thinkpad_acpi.h - ThinkPad ACPI Extras - * - * - * Copyright (C) 2004-2005 Borislav Deianov - * Copyright (C) 2006-2007 Henrique de Moraes Holschuh - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -#ifndef __THINKPAD_ACPI_H__ -#define __THINKPAD_ACPI_H__ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -#include - -/**************************************************************************** - * Main driver - */ - -#define IBM_NAME "thinkpad" -#define IBM_DESC "ThinkPad ACPI Extras" -#define IBM_FILE IBM_NAME "_acpi" -#define IBM_URL "http://ibm-acpi.sf.net/" -#define IBM_MAIL "ibm-acpi-devel@lists.sourceforge.net" - -#define IBM_PROC_DIR "ibm" -#define IBM_ACPI_EVENT_PREFIX "ibm" -#define IBM_DRVR_NAME IBM_FILE -#define IBM_HWMON_DRVR_NAME IBM_NAME "_hwmon" - -#define IBM_LOG IBM_FILE ": " -#define IBM_ERR KERN_ERR IBM_LOG -#define IBM_NOTICE KERN_NOTICE IBM_LOG -#define IBM_INFO KERN_INFO IBM_LOG -#define IBM_DEBUG KERN_DEBUG IBM_LOG - -#define IBM_MAX_ACPI_ARGS 3 - -/* ThinkPad CMOS commands */ -#define TP_CMOS_VOLUME_DOWN 0 -#define TP_CMOS_VOLUME_UP 1 -#define TP_CMOS_VOLUME_MUTE 2 -#define TP_CMOS_BRIGHTNESS_UP 4 -#define TP_CMOS_BRIGHTNESS_DOWN 5 - -/* NVRAM Addresses */ -enum tp_nvram_addr { - TP_NVRAM_ADDR_HK2 = 0x57, - TP_NVRAM_ADDR_THINKLIGHT = 0x58, - TP_NVRAM_ADDR_VIDEO = 0x59, - TP_NVRAM_ADDR_BRIGHTNESS = 0x5e, - TP_NVRAM_ADDR_MIXER = 0x60, -}; - -/* NVRAM bit masks */ -enum { - TP_NVRAM_MASK_HKT_THINKPAD = 0x08, - TP_NVRAM_MASK_HKT_ZOOM = 0x20, - TP_NVRAM_MASK_HKT_DISPLAY = 0x40, - TP_NVRAM_MASK_HKT_HIBERNATE = 0x80, - TP_NVRAM_MASK_THINKLIGHT = 0x10, - TP_NVRAM_MASK_HKT_DISPEXPND = 0x30, - TP_NVRAM_MASK_HKT_BRIGHTNESS = 0x20, - TP_NVRAM_MASK_LEVEL_BRIGHTNESS = 0x0f, - TP_NVRAM_POS_LEVEL_BRIGHTNESS = 0, - TP_NVRAM_MASK_MUTE = 0x40, - TP_NVRAM_MASK_HKT_VOLUME = 0x80, - TP_NVRAM_MASK_LEVEL_VOLUME = 0x0f, - TP_NVRAM_POS_LEVEL_VOLUME = 0, -}; - -#define onoff(status,bit) ((status) & (1 << (bit)) ? "on" : "off") -#define enabled(status,bit) ((status) & (1 << (bit)) ? "enabled" : "disabled") -#define strlencmp(a,b) (strncmp((a), (b), strlen(b))) - -/* Debugging */ -#define TPACPI_DBG_ALL 0xffff -#define TPACPI_DBG_ALL 0xffff -#define TPACPI_DBG_INIT 0x0001 -#define TPACPI_DBG_EXIT 0x0002 -#define dbg_printk(a_dbg_level, format, arg...) \ - do { if (dbg_level & a_dbg_level) \ - printk(IBM_DEBUG "%s: " format, __func__ , ## arg); } while (0) -#ifdef CONFIG_THINKPAD_ACPI_DEBUG -#define vdbg_printk(a_dbg_level, format, arg...) \ - dbg_printk(a_dbg_level, format, ## arg) -static const char *str_supported(int is_supported); -#else -#define vdbg_printk(a_dbg_level, format, arg...) -#endif - -/* Input IDs */ -#define TPACPI_HKEY_INPUT_VENDOR PCI_VENDOR_ID_IBM -#define TPACPI_HKEY_INPUT_PRODUCT 0x5054 /* "TP" */ -#define TPACPI_HKEY_INPUT_VERSION 0x4101 - -/* ACPI HIDs */ -#define IBM_HKEY_HID "IBM0068" - -/* ACPI helpers */ -static int __must_check acpi_evalf(acpi_handle handle, - void *res, char *method, char *fmt, ...); -static int __must_check acpi_ec_read(int i, u8 * p); -static int __must_check acpi_ec_write(int i, u8 v); -static int __must_check _sta(acpi_handle handle); - -/* ACPI handles */ -static acpi_handle root_handle; /* root namespace */ -static acpi_handle ec_handle; /* EC */ -static acpi_handle ecrd_handle, ecwr_handle; /* 570 EC access */ -static acpi_handle cmos_handle, hkey_handle; /* basic thinkpad handles */ - -static void drv_acpi_handle_init(char *name, - acpi_handle *handle, acpi_handle parent, - char **paths, int num_paths, char **path); -#define IBM_ACPIHANDLE_INIT(object) \ - drv_acpi_handle_init(#object, &object##_handle, *object##_parent, \ - object##_paths, ARRAY_SIZE(object##_paths), &object##_path) - -/* ThinkPad ACPI helpers */ -static int issue_thinkpad_cmos_command(int cmos_cmd); - -/* procfs support */ -static struct proc_dir_entry *proc_dir; - -/* procfs helpers */ -static int dispatch_procfs_read(char *page, char **start, off_t off, - int count, int *eof, void *data); -static int dispatch_procfs_write(struct file *file, - const char __user * userbuf, - unsigned long count, void *data); -static char *next_cmd(char **cmds); - -/* sysfs support */ -struct attribute_set { - unsigned int members, max_members; - struct attribute_group group; -}; - -static struct attribute_set *create_attr_set(unsigned int max_members, - const char* name); -#define destroy_attr_set(_set) \ - kfree(_set); -static int add_to_attr_set(struct attribute_set* s, struct attribute *attr); -static int add_many_to_attr_set(struct attribute_set* s, - struct attribute **attr, - unsigned int count); -#define register_attr_set_with_sysfs(_attr_set, _kobj) \ - sysfs_create_group(_kobj, &_attr_set->group) -static void delete_attr_set(struct attribute_set* s, struct kobject *kobj); - -static int parse_strtoul(const char *buf, unsigned long max, - unsigned long *value); - -/* Device model */ -static struct platform_device *tpacpi_pdev; -static struct platform_device *tpacpi_sensors_pdev; -static struct device *tpacpi_hwmon; -static struct platform_driver tpacpi_pdriver; -static struct input_dev *tpacpi_inputdev; -static int tpacpi_create_driver_attributes(struct device_driver *drv); -static void tpacpi_remove_driver_attributes(struct device_driver *drv); - -/* Module */ -static int experimental; -static u32 dbg_level; -static int force_load; -static unsigned int hotkey_report_mode; - -static int thinkpad_acpi_module_init(void); -static void thinkpad_acpi_module_exit(void); - - -/**************************************************************************** - * Subdrivers - */ - -struct ibm_struct; - -struct tp_acpi_drv_struct { - const struct acpi_device_id *hid; - struct acpi_driver *driver; - - void (*notify) (struct ibm_struct *, u32); - acpi_handle *handle; - u32 type; - struct acpi_device *device; -}; - -struct ibm_struct { - char *name; - - int (*read) (char *); - int (*write) (char *); - void (*exit) (void); - void (*resume) (void); - - struct list_head all_drivers; - - struct tp_acpi_drv_struct *acpi; - - struct { - u8 acpi_driver_registered:1; - u8 acpi_notify_installed:1; - u8 proc_created:1; - u8 init_called:1; - u8 experimental:1; - } flags; -}; - -struct ibm_init_struct { - char param[32]; - - int (*init) (struct ibm_init_struct *); - struct ibm_struct *data; -}; - -static struct { -#ifdef CONFIG_THINKPAD_ACPI_BAY - u32 bay_status:1; - u32 bay_eject:1; - u32 bay_status2:1; - u32 bay_eject2:1; -#endif - u32 bluetooth:1; - u32 hotkey:1; - u32 hotkey_mask:1; - u32 hotkey_wlsw:1; - u32 light:1; - u32 light_status:1; - u32 bright_16levels:1; - u32 wan:1; - u32 fan_ctrl_status_undef:1; - u32 input_device_registered:1; - u32 platform_drv_registered:1; - u32 platform_drv_attrs_registered:1; - u32 sensors_pdrv_registered:1; - u32 sensors_pdrv_attrs_registered:1; - u32 sensors_pdev_attrs_registered:1; - u32 hotkey_poll_active:1; -} tp_features; - -struct thinkpad_id_data { - unsigned int vendor; /* ThinkPad vendor: - * PCI_VENDOR_ID_IBM/PCI_VENDOR_ID_LENOVO */ - - char *bios_version_str; /* Something like 1ZET51WW (1.03z) */ - char *ec_version_str; /* Something like 1ZHT51WW-1.04a */ - - u16 bios_model; /* Big Endian, TP-1Y = 0x5931, 0 = unknown */ - u16 ec_model; - - char *model_str; -}; - -static struct thinkpad_id_data thinkpad_id; - -static struct list_head tpacpi_all_drivers; - -static struct ibm_init_struct ibms_init[]; -static int set_ibm_param(const char *val, struct kernel_param *kp); -static int ibm_init(struct ibm_init_struct *iibm); -static void ibm_exit(struct ibm_struct *ibm); - - -/* - * procfs master subdriver - */ -static int thinkpad_acpi_driver_init(struct ibm_init_struct *iibm); -static int thinkpad_acpi_driver_read(char *p); - - -/* - * Bay subdriver - */ - -#ifdef CONFIG_THINKPAD_ACPI_BAY -static acpi_handle bay_handle, bay_ej_handle; -static acpi_handle bay2_handle, bay2_ej_handle; - -static int bay_init(struct ibm_init_struct *iibm); -static void bay_notify(struct ibm_struct *ibm, u32 event); -static int bay_read(char *p); -static int bay_write(char *buf); -#endif /* CONFIG_THINKPAD_ACPI_BAY */ - - -/* - * Beep subdriver - */ - -static acpi_handle beep_handle; - -static int beep_read(char *p); -static int beep_write(char *buf); - - -/* - * Bluetooth subdriver - */ - -enum { - /* ACPI GBDC/SBDC bits */ - TP_ACPI_BLUETOOTH_HWPRESENT = 0x01, /* Bluetooth hw available */ - TP_ACPI_BLUETOOTH_RADIOSSW = 0x02, /* Bluetooth radio enabled */ - TP_ACPI_BLUETOOTH_UNK = 0x04, /* unknown function */ -}; - -static int bluetooth_init(struct ibm_init_struct *iibm); -static int bluetooth_get_radiosw(void); -static int bluetooth_set_radiosw(int radio_on); -static int bluetooth_read(char *p); -static int bluetooth_write(char *buf); - - -/* - * Brightness (backlight) subdriver - */ - -#define TPACPI_BACKLIGHT_DEV_NAME "thinkpad_screen" - -static struct backlight_device *ibm_backlight_device; -static int brightness_offset = 0x31; -static int brightness_mode; -static unsigned int brightness_enable; /* 0 = no, 1 = yes, 2 = auto */ - -static int brightness_init(struct ibm_init_struct *iibm); -static void brightness_exit(void); -static int brightness_get(struct backlight_device *bd); -static int brightness_set(int value); -static int brightness_update_status(struct backlight_device *bd); -static int brightness_read(char *p); -static int brightness_write(char *buf); - - -/* - * CMOS subdriver - */ - -static int cmos_read(char *p); -static int cmos_write(char *buf); - - -/* - * Dock subdriver - */ - -#ifdef CONFIG_THINKPAD_ACPI_DOCK -static acpi_handle pci_handle; -static acpi_handle dock_handle; - -static void dock_notify(struct ibm_struct *ibm, u32 event); -static int dock_read(char *p); -static int dock_write(char *buf); -#endif /* CONFIG_THINKPAD_ACPI_DOCK */ - - -/* - * EC dump subdriver - */ - -static int ecdump_read(char *p) ; -static int ecdump_write(char *buf); - - -/* - * Fan subdriver - */ - -enum { /* Fan control constants */ - fan_status_offset = 0x2f, /* EC register 0x2f */ - fan_rpm_offset = 0x84, /* EC register 0x84: LSB, 0x85 MSB (RPM) - * 0x84 must be read before 0x85 */ - - TP_EC_FAN_FULLSPEED = 0x40, /* EC fan mode: full speed */ - TP_EC_FAN_AUTO = 0x80, /* EC fan mode: auto fan control */ - - TPACPI_FAN_LAST_LEVEL = 0x100, /* Use cached last-seen fan level */ -}; - -enum fan_status_access_mode { - TPACPI_FAN_NONE = 0, /* No fan status or control */ - TPACPI_FAN_RD_ACPI_GFAN, /* Use ACPI GFAN */ - TPACPI_FAN_RD_TPEC, /* Use ACPI EC regs 0x2f, 0x84-0x85 */ -}; - -enum fan_control_access_mode { - TPACPI_FAN_WR_NONE = 0, /* No fan control */ - TPACPI_FAN_WR_ACPI_SFAN, /* Use ACPI SFAN */ - TPACPI_FAN_WR_TPEC, /* Use ACPI EC reg 0x2f */ - TPACPI_FAN_WR_ACPI_FANS, /* Use ACPI FANS and EC reg 0x2f */ -}; - -enum fan_control_commands { - TPACPI_FAN_CMD_SPEED = 0x0001, /* speed command */ - TPACPI_FAN_CMD_LEVEL = 0x0002, /* level command */ - TPACPI_FAN_CMD_ENABLE = 0x0004, /* enable/disable cmd, - * and also watchdog cmd */ -}; - -static int fan_control_allowed; - -static enum fan_status_access_mode fan_status_access_mode; -static enum fan_control_access_mode fan_control_access_mode; -static enum fan_control_commands fan_control_commands; -static u8 fan_control_initial_status; -static u8 fan_control_desired_level; -static int fan_watchdog_maxinterval; - -static struct mutex fan_mutex; - -static acpi_handle fans_handle, gfan_handle, sfan_handle; - -static int fan_init(struct ibm_init_struct *iibm); -static void fan_exit(void); -static int fan_get_status(u8 *status); -static int fan_get_status_safe(u8 *status); -static int fan_get_speed(unsigned int *speed); -static void fan_update_desired_level(u8 status); -static void fan_watchdog_fire(struct work_struct *ignored); -static void fan_watchdog_reset(void); -static int fan_set_level(int level); -static int fan_set_level_safe(int level); -static int fan_set_enable(void); -static int fan_set_disable(void); -static int fan_set_speed(int speed); -static int fan_read(char *p); -static int fan_write(char *buf); -static int fan_write_cmd_level(const char *cmd, int *rc); -static int fan_write_cmd_enable(const char *cmd, int *rc); -static int fan_write_cmd_disable(const char *cmd, int *rc); -static int fan_write_cmd_speed(const char *cmd, int *rc); -static int fan_write_cmd_watchdog(const char *cmd, int *rc); - - -/* - * Hotkey subdriver - */ - -enum { /* hot key scan codes (derived from ACPI DSDT) */ - TP_ACPI_HOTKEYSCAN_FNF1 = 0, - TP_ACPI_HOTKEYSCAN_FNF2, - TP_ACPI_HOTKEYSCAN_FNF3, - TP_ACPI_HOTKEYSCAN_FNF4, - TP_ACPI_HOTKEYSCAN_FNF5, - TP_ACPI_HOTKEYSCAN_FNF6, - TP_ACPI_HOTKEYSCAN_FNF7, - TP_ACPI_HOTKEYSCAN_FNF8, - TP_ACPI_HOTKEYSCAN_FNF9, - TP_ACPI_HOTKEYSCAN_FNF10, - TP_ACPI_HOTKEYSCAN_FNF11, - TP_ACPI_HOTKEYSCAN_FNF12, - TP_ACPI_HOTKEYSCAN_FNBACKSPACE, - TP_ACPI_HOTKEYSCAN_FNINSERT, - TP_ACPI_HOTKEYSCAN_FNDELETE, - TP_ACPI_HOTKEYSCAN_FNHOME, - TP_ACPI_HOTKEYSCAN_FNEND, - TP_ACPI_HOTKEYSCAN_FNPAGEUP, - TP_ACPI_HOTKEYSCAN_FNPAGEDOWN, - TP_ACPI_HOTKEYSCAN_FNSPACE, - TP_ACPI_HOTKEYSCAN_VOLUMEUP, - TP_ACPI_HOTKEYSCAN_VOLUMEDOWN, - TP_ACPI_HOTKEYSCAN_MUTE, - TP_ACPI_HOTKEYSCAN_THINKPAD, -}; - -static int hotkey_orig_status; -static u32 hotkey_orig_mask; - -static struct mutex hotkey_mutex; - -static int hotkey_init(struct ibm_init_struct *iibm); -static void hotkey_exit(void); -static void hotkey_notify(struct ibm_struct *ibm, u32 event); -static int hotkey_read(char *p); -static int hotkey_write(char *buf); - - -/* - * LED subdriver - */ - -enum led_access_mode { - TPACPI_LED_NONE = 0, - TPACPI_LED_570, /* 570 */ - TPACPI_LED_OLD, /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */ - TPACPI_LED_NEW, /* all others */ -}; - -enum { /* For TPACPI_LED_OLD */ - TPACPI_LED_EC_HLCL = 0x0c, /* EC reg to get led to power on */ - TPACPI_LED_EC_HLBL = 0x0d, /* EC reg to blink a lit led */ - TPACPI_LED_EC_HLMS = 0x0e, /* EC reg to select led to command */ -}; - -static enum led_access_mode led_supported; -static acpi_handle led_handle; - -static int led_init(struct ibm_init_struct *iibm); -static int led_read(char *p); -static int led_write(char *buf); - -/* - * Light (thinklight) subdriver - */ - -static acpi_handle lght_handle, ledb_handle; - -static int light_init(struct ibm_init_struct *iibm); -static int light_read(char *p); -static int light_write(char *buf); - - -/* - * Thermal subdriver - */ - -enum thermal_access_mode { - TPACPI_THERMAL_NONE = 0, /* No thermal support */ - TPACPI_THERMAL_ACPI_TMP07, /* Use ACPI TMP0-7 */ - TPACPI_THERMAL_ACPI_UPDT, /* Use ACPI TMP0-7 with UPDT */ - TPACPI_THERMAL_TPEC_8, /* Use ACPI EC regs, 8 sensors */ - TPACPI_THERMAL_TPEC_16, /* Use ACPI EC regs, 16 sensors */ -}; - -enum { /* TPACPI_THERMAL_TPEC_* */ - TP_EC_THERMAL_TMP0 = 0x78, /* ACPI EC regs TMP 0..7 */ - TP_EC_THERMAL_TMP8 = 0xC0, /* ACPI EC regs TMP 8..15 */ - TP_EC_THERMAL_TMP_NA = -128, /* ACPI EC sensor not available */ -}; - -#define TPACPI_MAX_THERMAL_SENSORS 16 /* Max thermal sensors supported */ -struct ibm_thermal_sensors_struct { - s32 temp[TPACPI_MAX_THERMAL_SENSORS]; -}; - -static enum thermal_access_mode thermal_read_mode; - -static int thermal_init(struct ibm_init_struct *iibm); -static int thermal_get_sensor(int idx, s32 *value); -static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s); -static int thermal_read(char *p); - - -/* - * Video subdriver - */ - -enum video_access_mode { - TPACPI_VIDEO_NONE = 0, - TPACPI_VIDEO_570, /* 570 */ - TPACPI_VIDEO_770, /* 600e/x, 770e, 770x */ - TPACPI_VIDEO_NEW, /* all others */ -}; - -enum { /* video status flags, based on VIDEO_570 */ - TP_ACPI_VIDEO_S_LCD = 0x01, /* LCD output enabled */ - TP_ACPI_VIDEO_S_CRT = 0x02, /* CRT output enabled */ - TP_ACPI_VIDEO_S_DVI = 0x08, /* DVI output enabled */ -}; - -enum { /* TPACPI_VIDEO_570 constants */ - TP_ACPI_VIDEO_570_PHSCMD = 0x87, /* unknown magic constant :( */ - TP_ACPI_VIDEO_570_PHSMASK = 0x03, /* PHS bits that map to - * video_status_flags */ - TP_ACPI_VIDEO_570_PHS2CMD = 0x8b, /* unknown magic constant :( */ - TP_ACPI_VIDEO_570_PHS2SET = 0x80, /* unknown magic constant :( */ -}; - -static enum video_access_mode video_supported; -static int video_orig_autosw; -static acpi_handle vid_handle, vid2_handle; - -static int video_init(struct ibm_init_struct *iibm); -static void video_exit(void); -static int video_outputsw_get(void); -static int video_outputsw_set(int status); -static int video_autosw_get(void); -static int video_autosw_set(int enable); -static int video_outputsw_cycle(void); -static int video_expand_toggle(void); -static int video_read(char *p); -static int video_write(char *buf); - - -/* - * Volume subdriver - */ - -static int volume_offset = 0x30; - -static int volume_read(char *p); -static int volume_write(char *buf); - - -/* - * Wan subdriver - */ - -enum { - /* ACPI GWAN/SWAN bits */ - TP_ACPI_WANCARD_HWPRESENT = 0x01, /* Wan hw available */ - TP_ACPI_WANCARD_RADIOSSW = 0x02, /* Wan radio enabled */ - TP_ACPI_WANCARD_UNK = 0x04, /* unknown function */ -}; - -static int wan_init(struct ibm_init_struct *iibm); -static int wan_get_radiosw(void); -static int wan_set_radiosw(int radio_on); -static int wan_read(char *p); -static int wan_write(char *buf); - - -#endif /* __THINKPAD_ACPI_H */ -- cgit v1.2.3 From f74a27d4bda42ee779940adaa34c5c196dda5d32 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Tue, 8 Jan 2008 13:02:44 -0200 Subject: ACPI: thinkpad-acpi: spring cleanup part 2 Move most subdriver-related stuff imported from the header file closer to their subdriver code. Also, delete unneeded forward declarations. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 613 +++++++++++++------------------------------ 1 file changed, 185 insertions(+), 428 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 59b127cff1e..e435b554a00 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -82,8 +82,6 @@ * 2004-08-09 0.1 initial release, support for X series */ -/* ==================================================== BEGIN HEADER */ - #include #include #include @@ -199,79 +197,22 @@ static const char *str_supported(int is_supported); /* ACPI HIDs */ #define IBM_HKEY_HID "IBM0068" -/* ACPI helpers */ -static int __must_check acpi_evalf(acpi_handle handle, - void *res, char *method, char *fmt, ...); -static int __must_check acpi_ec_read(int i, u8 * p); -static int __must_check acpi_ec_write(int i, u8 v); -static int __must_check _sta(acpi_handle handle); - -/* ACPI handles */ -static acpi_handle root_handle; /* root namespace */ -static acpi_handle ec_handle; /* EC */ -static acpi_handle ecrd_handle, ecwr_handle; /* 570 EC access */ -static acpi_handle cmos_handle, hkey_handle; /* basic thinkpad handles */ - -static void drv_acpi_handle_init(char *name, - acpi_handle *handle, acpi_handle parent, - char **paths, int num_paths, char **path); -#define IBM_ACPIHANDLE_INIT(object) \ - drv_acpi_handle_init(#object, &object##_handle, *object##_parent, \ - object##_paths, ARRAY_SIZE(object##_paths), &object##_path) - -/* ThinkPad ACPI helpers */ -static int issue_thinkpad_cmos_command(int cmos_cmd); - -/* procfs support */ -static struct proc_dir_entry *proc_dir; - -/* procfs helpers */ -static int dispatch_procfs_read(char *page, char **start, off_t off, - int count, int *eof, void *data); -static int dispatch_procfs_write(struct file *file, - const char __user * userbuf, - unsigned long count, void *data); -static char *next_cmd(char **cmds); - /* sysfs support */ struct attribute_set { unsigned int members, max_members; struct attribute_group group; }; -static struct attribute_set *create_attr_set(unsigned int max_members, - const char* name); -#define destroy_attr_set(_set) \ - kfree(_set); -static int add_to_attr_set(struct attribute_set* s, struct attribute *attr); -static int add_many_to_attr_set(struct attribute_set* s, - struct attribute **attr, - unsigned int count); -#define register_attr_set_with_sysfs(_attr_set, _kobj) \ - sysfs_create_group(_kobj, &_attr_set->group) -static void delete_attr_set(struct attribute_set* s, struct kobject *kobj); - +/* Helpers */ static int parse_strtoul(const char *buf, unsigned long max, unsigned long *value); -/* Device model */ -static struct platform_device *tpacpi_pdev; -static struct platform_device *tpacpi_sensors_pdev; -static struct device *tpacpi_hwmon; -static struct platform_driver tpacpi_pdriver; -static struct input_dev *tpacpi_inputdev; -static int tpacpi_create_driver_attributes(struct device_driver *drv); -static void tpacpi_remove_driver_attributes(struct device_driver *drv); - /* Module */ static int experimental; static u32 dbg_level; static int force_load; static unsigned int hotkey_report_mode; -static int thinkpad_acpi_module_init(void); -static void thinkpad_acpi_module_exit(void); - /**************************************************************************** * Subdrivers @@ -354,365 +295,9 @@ struct thinkpad_id_data { char *model_str; }; - static struct thinkpad_id_data thinkpad_id; -static struct list_head tpacpi_all_drivers; - -static struct ibm_init_struct ibms_init[]; -static int set_ibm_param(const char *val, struct kernel_param *kp); -static int ibm_init(struct ibm_init_struct *iibm); -static void ibm_exit(struct ibm_struct *ibm); - - -/* - * procfs master subdriver - */ -static int thinkpad_acpi_driver_init(struct ibm_init_struct *iibm); -static int thinkpad_acpi_driver_read(char *p); - - -/* - * Bay subdriver - */ - -#ifdef CONFIG_THINKPAD_ACPI_BAY -static acpi_handle bay_handle, bay_ej_handle; -static acpi_handle bay2_handle, bay2_ej_handle; - -static int bay_init(struct ibm_init_struct *iibm); -static void bay_notify(struct ibm_struct *ibm, u32 event); -static int bay_read(char *p); -static int bay_write(char *buf); -#endif /* CONFIG_THINKPAD_ACPI_BAY */ - - -/* - * Beep subdriver - */ - -static acpi_handle beep_handle; - -static int beep_read(char *p); -static int beep_write(char *buf); - - -/* - * Bluetooth subdriver - */ - -enum { - /* ACPI GBDC/SBDC bits */ - TP_ACPI_BLUETOOTH_HWPRESENT = 0x01, /* Bluetooth hw available */ - TP_ACPI_BLUETOOTH_RADIOSSW = 0x02, /* Bluetooth radio enabled */ - TP_ACPI_BLUETOOTH_UNK = 0x04, /* unknown function */ -}; - -static int bluetooth_init(struct ibm_init_struct *iibm); -static int bluetooth_get_radiosw(void); -static int bluetooth_set_radiosw(int radio_on); -static int bluetooth_read(char *p); -static int bluetooth_write(char *buf); - - -/* - * Brightness (backlight) subdriver - */ - -#define TPACPI_BACKLIGHT_DEV_NAME "thinkpad_screen" - -static struct backlight_device *ibm_backlight_device; -static int brightness_offset = 0x31; -static int brightness_mode; -static unsigned int brightness_enable; /* 0 = no, 1 = yes, 2 = auto */ - -static int brightness_init(struct ibm_init_struct *iibm); -static void brightness_exit(void); -static int brightness_get(struct backlight_device *bd); -static int brightness_set(int value); -static int brightness_update_status(struct backlight_device *bd); -static int brightness_read(char *p); -static int brightness_write(char *buf); - - -/* - * CMOS subdriver - */ - -static int cmos_read(char *p); -static int cmos_write(char *buf); - - -/* - * Dock subdriver - */ - -#ifdef CONFIG_THINKPAD_ACPI_DOCK -static acpi_handle pci_handle; -static acpi_handle dock_handle; - -static void dock_notify(struct ibm_struct *ibm, u32 event); -static int dock_read(char *p); -static int dock_write(char *buf); -#endif /* CONFIG_THINKPAD_ACPI_DOCK */ - - -/* - * EC dump subdriver - */ - -static int ecdump_read(char *p) ; -static int ecdump_write(char *buf); - - -/* - * Fan subdriver - */ - -enum { /* Fan control constants */ - fan_status_offset = 0x2f, /* EC register 0x2f */ - fan_rpm_offset = 0x84, /* EC register 0x84: LSB, 0x85 MSB (RPM) - * 0x84 must be read before 0x85 */ - - TP_EC_FAN_FULLSPEED = 0x40, /* EC fan mode: full speed */ - TP_EC_FAN_AUTO = 0x80, /* EC fan mode: auto fan control */ - - TPACPI_FAN_LAST_LEVEL = 0x100, /* Use cached last-seen fan level */ -}; - -enum fan_status_access_mode { - TPACPI_FAN_NONE = 0, /* No fan status or control */ - TPACPI_FAN_RD_ACPI_GFAN, /* Use ACPI GFAN */ - TPACPI_FAN_RD_TPEC, /* Use ACPI EC regs 0x2f, 0x84-0x85 */ -}; - -enum fan_control_access_mode { - TPACPI_FAN_WR_NONE = 0, /* No fan control */ - TPACPI_FAN_WR_ACPI_SFAN, /* Use ACPI SFAN */ - TPACPI_FAN_WR_TPEC, /* Use ACPI EC reg 0x2f */ - TPACPI_FAN_WR_ACPI_FANS, /* Use ACPI FANS and EC reg 0x2f */ -}; - -enum fan_control_commands { - TPACPI_FAN_CMD_SPEED = 0x0001, /* speed command */ - TPACPI_FAN_CMD_LEVEL = 0x0002, /* level command */ - TPACPI_FAN_CMD_ENABLE = 0x0004, /* enable/disable cmd, - * and also watchdog cmd */ -}; - -static int fan_control_allowed; - -static enum fan_status_access_mode fan_status_access_mode; -static enum fan_control_access_mode fan_control_access_mode; -static enum fan_control_commands fan_control_commands; -static u8 fan_control_initial_status; -static u8 fan_control_desired_level; -static int fan_watchdog_maxinterval; - -static struct mutex fan_mutex; - -static acpi_handle fans_handle, gfan_handle, sfan_handle; - -static int fan_init(struct ibm_init_struct *iibm); -static void fan_exit(void); -static int fan_get_status(u8 *status); -static int fan_get_status_safe(u8 *status); -static int fan_get_speed(unsigned int *speed); -static void fan_update_desired_level(u8 status); -static void fan_watchdog_fire(struct work_struct *ignored); -static void fan_watchdog_reset(void); -static int fan_set_level(int level); -static int fan_set_level_safe(int level); -static int fan_set_enable(void); -static int fan_set_disable(void); -static int fan_set_speed(int speed); -static int fan_read(char *p); -static int fan_write(char *buf); -static int fan_write_cmd_level(const char *cmd, int *rc); -static int fan_write_cmd_enable(const char *cmd, int *rc); -static int fan_write_cmd_disable(const char *cmd, int *rc); -static int fan_write_cmd_speed(const char *cmd, int *rc); -static int fan_write_cmd_watchdog(const char *cmd, int *rc); - - -/* - * Hotkey subdriver - */ - -enum { /* hot key scan codes (derived from ACPI DSDT) */ - TP_ACPI_HOTKEYSCAN_FNF1 = 0, - TP_ACPI_HOTKEYSCAN_FNF2, - TP_ACPI_HOTKEYSCAN_FNF3, - TP_ACPI_HOTKEYSCAN_FNF4, - TP_ACPI_HOTKEYSCAN_FNF5, - TP_ACPI_HOTKEYSCAN_FNF6, - TP_ACPI_HOTKEYSCAN_FNF7, - TP_ACPI_HOTKEYSCAN_FNF8, - TP_ACPI_HOTKEYSCAN_FNF9, - TP_ACPI_HOTKEYSCAN_FNF10, - TP_ACPI_HOTKEYSCAN_FNF11, - TP_ACPI_HOTKEYSCAN_FNF12, - TP_ACPI_HOTKEYSCAN_FNBACKSPACE, - TP_ACPI_HOTKEYSCAN_FNINSERT, - TP_ACPI_HOTKEYSCAN_FNDELETE, - TP_ACPI_HOTKEYSCAN_FNHOME, - TP_ACPI_HOTKEYSCAN_FNEND, - TP_ACPI_HOTKEYSCAN_FNPAGEUP, - TP_ACPI_HOTKEYSCAN_FNPAGEDOWN, - TP_ACPI_HOTKEYSCAN_FNSPACE, - TP_ACPI_HOTKEYSCAN_VOLUMEUP, - TP_ACPI_HOTKEYSCAN_VOLUMEDOWN, - TP_ACPI_HOTKEYSCAN_MUTE, - TP_ACPI_HOTKEYSCAN_THINKPAD, -}; - -static int hotkey_orig_status; -static u32 hotkey_orig_mask; - -static struct mutex hotkey_mutex; - -static int hotkey_init(struct ibm_init_struct *iibm); -static void hotkey_exit(void); -static void hotkey_notify(struct ibm_struct *ibm, u32 event); -static int hotkey_read(char *p); -static int hotkey_write(char *buf); - - -/* - * LED subdriver - */ - -enum led_access_mode { - TPACPI_LED_NONE = 0, - TPACPI_LED_570, /* 570 */ - TPACPI_LED_OLD, /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */ - TPACPI_LED_NEW, /* all others */ -}; - -enum { /* For TPACPI_LED_OLD */ - TPACPI_LED_EC_HLCL = 0x0c, /* EC reg to get led to power on */ - TPACPI_LED_EC_HLBL = 0x0d, /* EC reg to blink a lit led */ - TPACPI_LED_EC_HLMS = 0x0e, /* EC reg to select led to command */ -}; - -static enum led_access_mode led_supported; -static acpi_handle led_handle; - -static int led_init(struct ibm_init_struct *iibm); -static int led_read(char *p); -static int led_write(char *buf); - -/* - * Light (thinklight) subdriver - */ - -static acpi_handle lght_handle, ledb_handle; - -static int light_init(struct ibm_init_struct *iibm); -static int light_read(char *p); -static int light_write(char *buf); - - -/* - * Thermal subdriver - */ - -enum thermal_access_mode { - TPACPI_THERMAL_NONE = 0, /* No thermal support */ - TPACPI_THERMAL_ACPI_TMP07, /* Use ACPI TMP0-7 */ - TPACPI_THERMAL_ACPI_UPDT, /* Use ACPI TMP0-7 with UPDT */ - TPACPI_THERMAL_TPEC_8, /* Use ACPI EC regs, 8 sensors */ - TPACPI_THERMAL_TPEC_16, /* Use ACPI EC regs, 16 sensors */ -}; - -enum { /* TPACPI_THERMAL_TPEC_* */ - TP_EC_THERMAL_TMP0 = 0x78, /* ACPI EC regs TMP 0..7 */ - TP_EC_THERMAL_TMP8 = 0xC0, /* ACPI EC regs TMP 8..15 */ - TP_EC_THERMAL_TMP_NA = -128, /* ACPI EC sensor not available */ -}; - -#define TPACPI_MAX_THERMAL_SENSORS 16 /* Max thermal sensors supported */ -struct ibm_thermal_sensors_struct { - s32 temp[TPACPI_MAX_THERMAL_SENSORS]; -}; - -static enum thermal_access_mode thermal_read_mode; - -static int thermal_init(struct ibm_init_struct *iibm); -static int thermal_get_sensor(int idx, s32 *value); -static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s); -static int thermal_read(char *p); - - -/* - * Video subdriver - */ - -enum video_access_mode { - TPACPI_VIDEO_NONE = 0, - TPACPI_VIDEO_570, /* 570 */ - TPACPI_VIDEO_770, /* 600e/x, 770e, 770x */ - TPACPI_VIDEO_NEW, /* all others */ -}; - -enum { /* video status flags, based on VIDEO_570 */ - TP_ACPI_VIDEO_S_LCD = 0x01, /* LCD output enabled */ - TP_ACPI_VIDEO_S_CRT = 0x02, /* CRT output enabled */ - TP_ACPI_VIDEO_S_DVI = 0x08, /* DVI output enabled */ -}; - -enum { /* TPACPI_VIDEO_570 constants */ - TP_ACPI_VIDEO_570_PHSCMD = 0x87, /* unknown magic constant :( */ - TP_ACPI_VIDEO_570_PHSMASK = 0x03, /* PHS bits that map to - * video_status_flags */ - TP_ACPI_VIDEO_570_PHS2CMD = 0x8b, /* unknown magic constant :( */ - TP_ACPI_VIDEO_570_PHS2SET = 0x80, /* unknown magic constant :( */ -}; - -static enum video_access_mode video_supported; -static int video_orig_autosw; -static acpi_handle vid_handle, vid2_handle; - -static int video_init(struct ibm_init_struct *iibm); -static void video_exit(void); -static int video_outputsw_get(void); -static int video_outputsw_set(int status); -static int video_autosw_get(void); -static int video_autosw_set(int enable); -static int video_outputsw_cycle(void); -static int video_expand_toggle(void); -static int video_read(char *p); -static int video_write(char *buf); - - -/* - * Volume subdriver - */ - -static int volume_offset = 0x30; - -static int volume_read(char *p); -static int volume_write(char *buf); - - -/* - * Wan subdriver - */ - -enum { - /* ACPI GWAN/SWAN bits */ - TP_ACPI_WANCARD_HWPRESENT = 0x01, /* Wan hw available */ - TP_ACPI_WANCARD_RADIOSSW = 0x02, /* Wan radio enabled */ - TP_ACPI_WANCARD_UNK = 0x04, /* unknown function */ -}; - -static int wan_init(struct ibm_init_struct *iibm); -static int wan_get_radiosw(void); -static int wan_set_radiosw(int radio_on); -static int wan_read(char *p); -static int wan_write(char *buf); - -/* ==================================================== END HEADER */ +static LIST_HEAD(tpacpi_all_drivers); MODULE_AUTHOR("Borislav Deianov, Henrique de Moraes Holschuh"); MODULE_DESCRIPTION(IBM_DESC); @@ -948,6 +533,10 @@ static int issue_thinkpad_cmos_command(int cmos_cmd) * ACPI device model */ +#define IBM_ACPIHANDLE_INIT(object) \ + drv_acpi_handle_init(#object, &object##_handle, *object##_parent, \ + object##_paths, ARRAY_SIZE(object##_paths), &object##_path) + static void drv_acpi_handle_init(char *name, acpi_handle *handle, acpi_handle parent, char **paths, int num_paths, char **path) @@ -1298,6 +887,9 @@ static struct attribute_set *create_attr_set(unsigned int max_members, return &sobj->s; } +#define destroy_attr_set(_set) \ + kfree(_set); + /* not multi-threaded safe, use it in a single thread per set */ static int add_to_attr_set(struct attribute_set* s, struct attribute *attr) { @@ -1334,6 +926,9 @@ static void delete_attr_set(struct attribute_set* s, struct kobject *kobj) destroy_attr_set(s); } +#define register_attr_set_with_sysfs(_attr_set, _kobj) \ + sysfs_create_group(_kobj, &_attr_set->group) + static int parse_strtoul(const char *buf, unsigned long max, unsigned long *value) { @@ -1403,6 +998,33 @@ static struct ibm_struct thinkpad_acpi_driver_data = { * Hotkey subdriver */ +enum { /* hot key scan codes (derived from ACPI DSDT) */ + TP_ACPI_HOTKEYSCAN_FNF1 = 0, + TP_ACPI_HOTKEYSCAN_FNF2, + TP_ACPI_HOTKEYSCAN_FNF3, + TP_ACPI_HOTKEYSCAN_FNF4, + TP_ACPI_HOTKEYSCAN_FNF5, + TP_ACPI_HOTKEYSCAN_FNF6, + TP_ACPI_HOTKEYSCAN_FNF7, + TP_ACPI_HOTKEYSCAN_FNF8, + TP_ACPI_HOTKEYSCAN_FNF9, + TP_ACPI_HOTKEYSCAN_FNF10, + TP_ACPI_HOTKEYSCAN_FNF11, + TP_ACPI_HOTKEYSCAN_FNF12, + TP_ACPI_HOTKEYSCAN_FNBACKSPACE, + TP_ACPI_HOTKEYSCAN_FNINSERT, + TP_ACPI_HOTKEYSCAN_FNDELETE, + TP_ACPI_HOTKEYSCAN_FNHOME, + TP_ACPI_HOTKEYSCAN_FNEND, + TP_ACPI_HOTKEYSCAN_FNPAGEUP, + TP_ACPI_HOTKEYSCAN_FNPAGEDOWN, + TP_ACPI_HOTKEYSCAN_FNSPACE, + TP_ACPI_HOTKEYSCAN_VOLUMEUP, + TP_ACPI_HOTKEYSCAN_VOLUMEDOWN, + TP_ACPI_HOTKEYSCAN_MUTE, + TP_ACPI_HOTKEYSCAN_THINKPAD, +}; + enum { /* Keys available through NVRAM polling */ TPACPI_HKEY_NVRAM_KNOWN_MASK = 0x00fb88c0U, TPACPI_HKEY_NVRAM_GOOD_MASK = 0x00fb8000U, @@ -1464,6 +1086,8 @@ static unsigned int hotkey_config_change; #endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ +static struct mutex hotkey_mutex; + static int hotkey_orig_status; static u32 hotkey_orig_mask; static u32 hotkey_all_mask; @@ -2635,6 +2259,16 @@ static struct ibm_struct hotkey_driver_data = { * Bluetooth subdriver */ +enum { + /* ACPI GBDC/SBDC bits */ + TP_ACPI_BLUETOOTH_HWPRESENT = 0x01, /* Bluetooth hw available */ + TP_ACPI_BLUETOOTH_RADIOSSW = 0x02, /* Bluetooth radio enabled */ + TP_ACPI_BLUETOOTH_UNK = 0x04, /* unknown function */ +}; + +static int bluetooth_get_radiosw(void); +static int bluetooth_set_radiosw(int radio_on); + /* sysfs bluetooth enable ---------------------------------------------- */ static ssize_t bluetooth_enable_show(struct device *dev, struct device_attribute *attr, @@ -2799,6 +2433,16 @@ static struct ibm_struct bluetooth_driver_data = { * Wan subdriver */ +enum { + /* ACPI GWAN/SWAN bits */ + TP_ACPI_WANCARD_HWPRESENT = 0x01, /* Wan hw available */ + TP_ACPI_WANCARD_RADIOSSW = 0x02, /* Wan radio enabled */ + TP_ACPI_WANCARD_UNK = 0x04, /* unknown function */ +}; + +static int wan_get_radiosw(void); +static int wan_set_radiosw(int radio_on); + /* sysfs wan enable ---------------------------------------------------- */ static ssize_t wan_enable_show(struct device *dev, struct device_attribute *attr, @@ -2962,9 +2606,33 @@ static struct ibm_struct wan_driver_data = { * Video subdriver */ +enum video_access_mode { + TPACPI_VIDEO_NONE = 0, + TPACPI_VIDEO_570, /* 570 */ + TPACPI_VIDEO_770, /* 600e/x, 770e, 770x */ + TPACPI_VIDEO_NEW, /* all others */ +}; + +enum { /* video status flags, based on VIDEO_570 */ + TP_ACPI_VIDEO_S_LCD = 0x01, /* LCD output enabled */ + TP_ACPI_VIDEO_S_CRT = 0x02, /* CRT output enabled */ + TP_ACPI_VIDEO_S_DVI = 0x08, /* DVI output enabled */ +}; + +enum { /* TPACPI_VIDEO_570 constants */ + TP_ACPI_VIDEO_570_PHSCMD = 0x87, /* unknown magic constant :( */ + TP_ACPI_VIDEO_570_PHSMASK = 0x03, /* PHS bits that map to + * video_status_flags */ + TP_ACPI_VIDEO_570_PHS2CMD = 0x8b, /* unknown magic constant :( */ + TP_ACPI_VIDEO_570_PHS2SET = 0x80, /* unknown magic constant :( */ +}; + static enum video_access_mode video_supported; static int video_orig_autosw; +static int video_autosw_get(void); +static int video_autosw_set(int enable); + IBM_HANDLE(vid, root, "\\_SB.PCI.AGP.VGA", /* 570 */ "\\_SB.PCI0.AGP0.VID0", /* 600e/x, 770x */ "\\_SB.PCI0.VID0", /* 770e */ @@ -3370,6 +3038,10 @@ static struct ibm_struct light_driver_data = { #ifdef CONFIG_THINKPAD_ACPI_DOCK +static void dock_notify(struct ibm_struct *ibm, u32 event); +static int dock_read(char *p); +static int dock_write(char *buf); + IBM_HANDLE(dock, root, "\\_SB.GDCK", /* X30, X31, X40 */ "\\_SB.PCI0.DOCK", /* 600e/x,770e,770x,A2xm/p,T20-22,X20-21 */ "\\_SB.PCI0.PCI1.DOCK", /* all others */ @@ -3524,6 +3196,7 @@ static int dock_write(char *buf) */ #ifdef CONFIG_THINKPAD_ACPI_BAY + IBM_HANDLE(bay, root, "\\_SB.PCI.IDE.SECN.MAST", /* 570 */ "\\_SB.PCI0.IDE0.IDES.IDSM", /* 600e/x, 770e, 770x */ "\\_SB.PCI0.SATA.SCND.MSTR", /* T60, X60, Z60 */ @@ -3741,6 +3414,19 @@ static struct ibm_struct cmos_driver_data = { * LED subdriver */ +enum led_access_mode { + TPACPI_LED_NONE = 0, + TPACPI_LED_570, /* 570 */ + TPACPI_LED_OLD, /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */ + TPACPI_LED_NEW, /* all others */ +}; + +enum { /* For TPACPI_LED_OLD */ + TPACPI_LED_EC_HLCL = 0x0c, /* EC reg to get led to power on */ + TPACPI_LED_EC_HLBL = 0x0d, /* EC reg to blink a lit led */ + TPACPI_LED_EC_HLMS = 0x0e, /* EC reg to select led to command */ +}; + static enum led_access_mode led_supported; IBM_HANDLE(led, ec, "SLED", /* 570 */ @@ -3930,8 +3616,30 @@ static struct ibm_struct beep_driver_data = { * Thermal subdriver */ +enum thermal_access_mode { + TPACPI_THERMAL_NONE = 0, /* No thermal support */ + TPACPI_THERMAL_ACPI_TMP07, /* Use ACPI TMP0-7 */ + TPACPI_THERMAL_ACPI_UPDT, /* Use ACPI TMP0-7 with UPDT */ + TPACPI_THERMAL_TPEC_8, /* Use ACPI EC regs, 8 sensors */ + TPACPI_THERMAL_TPEC_16, /* Use ACPI EC regs, 16 sensors */ +}; + +enum { /* TPACPI_THERMAL_TPEC_* */ + TP_EC_THERMAL_TMP0 = 0x78, /* ACPI EC regs TMP 0..7 */ + TP_EC_THERMAL_TMP8 = 0xC0, /* ACPI EC regs TMP 8..15 */ + TP_EC_THERMAL_TMP_NA = -128, /* ACPI EC sensor not available */ +}; + +#define TPACPI_MAX_THERMAL_SENSORS 16 /* Max thermal sensors supported */ +struct ibm_thermal_sensors_struct { + s32 temp[TPACPI_MAX_THERMAL_SENSORS]; +}; + static enum thermal_access_mode thermal_read_mode; +static int thermal_get_sensor(int idx, s32 *value); +static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s); + /* sysfs temp##_input -------------------------------------------------- */ static ssize_t thermal_temp_input_show(struct device *dev, @@ -4306,7 +4014,16 @@ static struct ibm_struct ecdump_driver_data = { * Backlight/brightness subdriver */ +#define TPACPI_BACKLIGHT_DEV_NAME "thinkpad_screen" + static struct backlight_device *ibm_backlight_device; +static int brightness_offset = 0x31; +static int brightness_mode; +static unsigned int brightness_enable = 2; /* 2 = auto, 0 = no, 1 = yes */ + +static int brightness_get(struct backlight_device *bd); +static int brightness_set(int value); +static int brightness_update_status(struct backlight_device *bd); static struct backlight_ops ibm_backlight_data = { .get_brightness = brightness_get, @@ -4628,6 +4345,8 @@ static struct ibm_struct brightness_driver_data = { * Volume subdriver */ +static int volume_offset = 0x30; + static int volume_read(char *p) { int len = 0; @@ -4819,15 +4538,59 @@ static struct ibm_struct volume_driver_data = { * but the ACPI tables just mention level 7. */ +enum { /* Fan control constants */ + fan_status_offset = 0x2f, /* EC register 0x2f */ + fan_rpm_offset = 0x84, /* EC register 0x84: LSB, 0x85 MSB (RPM) + * 0x84 must be read before 0x85 */ + + TP_EC_FAN_FULLSPEED = 0x40, /* EC fan mode: full speed */ + TP_EC_FAN_AUTO = 0x80, /* EC fan mode: auto fan control */ + + TPACPI_FAN_LAST_LEVEL = 0x100, /* Use cached last-seen fan level */ +}; + +enum fan_status_access_mode { + TPACPI_FAN_NONE = 0, /* No fan status or control */ + TPACPI_FAN_RD_ACPI_GFAN, /* Use ACPI GFAN */ + TPACPI_FAN_RD_TPEC, /* Use ACPI EC regs 0x2f, 0x84-0x85 */ +}; + +enum fan_control_access_mode { + TPACPI_FAN_WR_NONE = 0, /* No fan control */ + TPACPI_FAN_WR_ACPI_SFAN, /* Use ACPI SFAN */ + TPACPI_FAN_WR_TPEC, /* Use ACPI EC reg 0x2f */ + TPACPI_FAN_WR_ACPI_FANS, /* Use ACPI FANS and EC reg 0x2f */ +}; + +enum fan_control_commands { + TPACPI_FAN_CMD_SPEED = 0x0001, /* speed command */ + TPACPI_FAN_CMD_LEVEL = 0x0002, /* level command */ + TPACPI_FAN_CMD_ENABLE = 0x0004, /* enable/disable cmd, + * and also watchdog cmd */ +}; + +static int fan_control_allowed; + static enum fan_status_access_mode fan_status_access_mode; static enum fan_control_access_mode fan_control_access_mode; static enum fan_control_commands fan_control_commands; static u8 fan_control_initial_status; static u8 fan_control_desired_level; +static int fan_watchdog_maxinterval; + +static struct mutex fan_mutex; +static int fan_get_status(u8 *status); +static int fan_get_status_safe(u8 *status); +static int fan_get_speed(unsigned int *speed); +static void fan_update_desired_level(u8 status); static void fan_watchdog_fire(struct work_struct *ignored); -static int fan_watchdog_maxinterval; +static void fan_watchdog_reset(void); +static int fan_set_level(int level); +static int fan_set_level_safe(int level); +static int fan_set_enable(void); + static DECLARE_DELAYED_WORK(fan_watchdog_task, fan_watchdog_fire); IBM_HANDLE(fans, ec, "FANS"); /* X31, X40, X41 */ @@ -5710,9 +5473,6 @@ static struct device_attribute dev_attr_thinkpad_acpi_pdev_name = /* /proc support */ static struct proc_dir_entry *proc_dir; -/* Subdriver registry */ -static LIST_HEAD(tpacpi_all_drivers); - /* * Module and infrastructure proble, init and exit handling @@ -5727,6 +5487,8 @@ static const char * __init str_supported(int is_supported) } #endif /* CONFIG_THINKPAD_ACPI_DEBUG */ +static void ibm_exit(struct ibm_struct *ibm); + static int __init ibm_init(struct ibm_init_struct *iibm) { int ret; @@ -6042,25 +5804,18 @@ static int __init set_ibm_param(const char *val, struct kernel_param *kp) return -EINVAL; } -static int experimental; module_param(experimental, int, 0); -static u32 dbg_level; module_param_named(debug, dbg_level, uint, 0); -static int force_load; module_param(force_load, bool, 0); -static int fan_control_allowed; module_param_named(fan_control, fan_control_allowed, bool, 0); -static int brightness_mode; module_param_named(brightness_mode, brightness_mode, int, 0); -static unsigned int brightness_enable = 2; /* 2 = auto, 0 = no, 1 = yes */ module_param(brightness_enable, uint, 0); -static unsigned int hotkey_report_mode; module_param(hotkey_report_mode, uint, 0); #define IBM_PARAM(feature) \ @@ -6084,6 +5839,8 @@ IBM_PARAM(brightness); IBM_PARAM(volume); IBM_PARAM(fan); +static void thinkpad_acpi_module_exit(void); + static int __init thinkpad_acpi_module_init(void) { int ret, i; -- cgit v1.2.3 From b21a15f6d065e837076cf417720afe1c3d6ed10d Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Tue, 8 Jan 2008 13:02:45 -0200 Subject: ACPI: thinkpad-acpi: spring cleanup part 3 Reorder code in the file to get rid of more of the forward declarations, and to make things cleaner and more organized. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 1905 +++++++++++++++++++++--------------------- 1 file changed, 940 insertions(+), 965 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index e435b554a00..b6293a40132 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -113,28 +113,6 @@ #include -/**************************************************************************** - * Main driver - */ - -#define IBM_NAME "thinkpad" -#define IBM_DESC "ThinkPad ACPI Extras" -#define IBM_FILE IBM_NAME "_acpi" -#define IBM_URL "http://ibm-acpi.sf.net/" -#define IBM_MAIL "ibm-acpi-devel@lists.sourceforge.net" - -#define IBM_PROC_DIR "ibm" -#define IBM_ACPI_EVENT_PREFIX "ibm" -#define IBM_DRVR_NAME IBM_FILE -#define IBM_HWMON_DRVR_NAME IBM_NAME "_hwmon" - -#define IBM_LOG IBM_FILE ": " -#define IBM_ERR KERN_ERR IBM_LOG -#define IBM_NOTICE KERN_NOTICE IBM_LOG -#define IBM_INFO KERN_INFO IBM_LOG -#define IBM_DEBUG KERN_DEBUG IBM_LOG - -#define IBM_MAX_ACPI_ARGS 3 /* ThinkPad CMOS commands */ #define TP_CMOS_VOLUME_DOWN 0 @@ -169,11 +147,70 @@ enum { TP_NVRAM_POS_LEVEL_VOLUME = 0, }; -#define onoff(status,bit) ((status) & (1 << (bit)) ? "on" : "off") -#define enabled(status,bit) ((status) & (1 << (bit)) ? "enabled" : "disabled") -#define strlencmp(a,b) (strncmp((a), (b), strlen(b))) +/* ACPI HIDs */ +#define IBM_HKEY_HID "IBM0068" + +/* Input IDs */ +#define TPACPI_HKEY_INPUT_PRODUCT 0x5054 /* "TP" */ +#define TPACPI_HKEY_INPUT_VERSION 0x4101 + + +/**************************************************************************** + * Main driver + */ + +/* Module */ +#define IBM_NAME "thinkpad" +#define IBM_DESC "ThinkPad ACPI Extras" +#define IBM_FILE IBM_NAME "_acpi" +#define IBM_URL "http://ibm-acpi.sf.net/" +#define IBM_MAIL "ibm-acpi-devel@lists.sourceforge.net" + +#define IBM_PROC_DIR "ibm" +#define IBM_ACPI_EVENT_PREFIX "ibm" +#define IBM_DRVR_NAME IBM_FILE +#define IBM_HWMON_DRVR_NAME IBM_NAME "_hwmon" + +#define IBM_MAX_ACPI_ARGS 3 + +MODULE_AUTHOR("Borislav Deianov, Henrique de Moraes Holschuh"); +MODULE_DESCRIPTION(IBM_DESC); +MODULE_VERSION(IBM_VERSION); +MODULE_LICENSE("GPL"); + +/* Please remove this in year 2009 */ +MODULE_ALIAS("ibm_acpi"); + +/* + * DMI matching for module autoloading + * + * See http://thinkwiki.org/wiki/List_of_DMI_IDs + * See http://thinkwiki.org/wiki/BIOS_Upgrade_Downloads + * + * Only models listed in thinkwiki will be supported, so add yours + * if it is not there yet. + */ +#define IBM_BIOS_MODULE_ALIAS(__type) \ + MODULE_ALIAS("dmi:bvnIBM:bvr" __type "ET??WW") + +/* Non-ancient thinkpads */ +MODULE_ALIAS("dmi:bvnIBM:*:svnIBM:*:pvrThinkPad*:rvnIBM:*"); +MODULE_ALIAS("dmi:bvnLENOVO:*:svnLENOVO:*:pvrThinkPad*:rvnLENOVO:*"); + +/* Ancient thinkpad BIOSes have to be identified by + * BIOS type or model number, and there are far less + * BIOS types than model numbers... */ +IBM_BIOS_MODULE_ALIAS("I[B,D,H,I,M,N,O,T,W,V,Y,Z]"); +IBM_BIOS_MODULE_ALIAS("1[0,3,6,8,A-G,I,K,M-P,S,T]"); +IBM_BIOS_MODULE_ALIAS("K[U,X-Z]"); /* Debugging */ +#define IBM_LOG IBM_FILE ": " +#define IBM_ERR KERN_ERR IBM_LOG +#define IBM_NOTICE KERN_NOTICE IBM_LOG +#define IBM_INFO KERN_INFO IBM_LOG +#define IBM_DEBUG KERN_DEBUG IBM_LOG + #define TPACPI_DBG_ALL 0xffff #define TPACPI_DBG_ALL 0xffff #define TPACPI_DBG_INIT 0x0001 @@ -189,33 +226,13 @@ static const char *str_supported(int is_supported); #define vdbg_printk(a_dbg_level, format, arg...) #endif -/* Input IDs */ -#define TPACPI_HKEY_INPUT_VENDOR PCI_VENDOR_ID_IBM -#define TPACPI_HKEY_INPUT_PRODUCT 0x5054 /* "TP" */ -#define TPACPI_HKEY_INPUT_VERSION 0x4101 - -/* ACPI HIDs */ -#define IBM_HKEY_HID "IBM0068" - -/* sysfs support */ -struct attribute_set { - unsigned int members, max_members; - struct attribute_group group; -}; - -/* Helpers */ -static int parse_strtoul(const char *buf, unsigned long max, - unsigned long *value); - -/* Module */ -static int experimental; -static u32 dbg_level; -static int force_load; -static unsigned int hotkey_report_mode; +#define onoff(status,bit) ((status) & (1 << (bit)) ? "on" : "off") +#define enabled(status,bit) ((status) & (1 << (bit)) ? "enabled" : "disabled") +#define strlencmp(a,b) (strncmp((a), (b), strlen(b))) /**************************************************************************** - * Subdrivers + * Driver-wide structs and misc. variables */ struct ibm_struct; @@ -297,39 +314,6 @@ struct thinkpad_id_data { }; static struct thinkpad_id_data thinkpad_id; -static LIST_HEAD(tpacpi_all_drivers); - -MODULE_AUTHOR("Borislav Deianov, Henrique de Moraes Holschuh"); -MODULE_DESCRIPTION(IBM_DESC); -MODULE_VERSION(IBM_VERSION); -MODULE_LICENSE("GPL"); - -/* Please remove this in year 2009 */ -MODULE_ALIAS("ibm_acpi"); - -/* - * DMI matching for module autoloading - * - * See http://thinkwiki.org/wiki/List_of_DMI_IDs - * See http://thinkwiki.org/wiki/BIOS_Upgrade_Downloads - * - * Only models listed in thinkwiki will be supported, so add yours - * if it is not there yet. - */ -#define IBM_BIOS_MODULE_ALIAS(__type) \ - MODULE_ALIAS("dmi:bvnIBM:bvr" __type "ET??WW") - -/* Non-ancient thinkpads */ -MODULE_ALIAS("dmi:bvnIBM:*:svnIBM:*:pvrThinkPad*:rvnIBM:*"); -MODULE_ALIAS("dmi:bvnLENOVO:*:svnLENOVO:*:pvrThinkPad*:rvnLENOVO:*"); - -/* Ancient thinkpad BIOSes have to be identified by - * BIOS type or model number, and there are far less - * BIOS types than model numbers... */ -IBM_BIOS_MODULE_ALIAS("I[B,D,H,I,M,N,O,T,W,V,Y,Z]"); -IBM_BIOS_MODULE_ALIAS("1[0,3,6,8,A-G,I,K,M-P,S,T]"); -IBM_BIOS_MODULE_ALIAS("K[U,X-Z]"); - #define __unused __attribute__ ((unused)) static enum { @@ -338,6 +322,9 @@ static enum { TPACPI_LIFE_EXITING, } tpacpi_lifecycle; +static int experimental; +static u32 dbg_level; + /**************************************************************************** **************************************************************************** * @@ -370,11 +357,6 @@ IBM_HANDLE(ec, root, "\\_SB.PCI0.ISA.EC0", /* 240, 240x */ IBM_HANDLE(ecrd, ec, "ECRD"); /* 570 */ IBM_HANDLE(ecwr, ec, "ECWR"); /* 570 */ - -/************************************************************************* - * Misc ACPI handles - */ - IBM_HANDLE(cmos, root, "\\UCMS", /* R50, R50e, R50p, R51, T4x, X31, X40 */ "\\CMOS", /* A3x, G4x, R32, T23, T30, X22-24, X30 */ "\\CMS", /* R40, R40e */ @@ -749,7 +731,7 @@ static struct platform_device *tpacpi_sensors_pdev; static struct device *tpacpi_hwmon; static struct input_dev *tpacpi_inputdev; static struct mutex tpacpi_inputdev_send_mutex; - +static LIST_HEAD(tpacpi_all_drivers); static int tpacpi_resume_handler(struct platform_device *pdev) { @@ -781,86 +763,14 @@ static struct platform_driver tpacpi_hwmon_pdriver = { }; /************************************************************************* - * thinkpad-acpi driver attributes + * sysfs support helpers */ -/* interface_version --------------------------------------------------- */ -static ssize_t tpacpi_driver_interface_version_show( - struct device_driver *drv, - char *buf) -{ - return snprintf(buf, PAGE_SIZE, "0x%08x\n", TPACPI_SYSFS_VERSION); -} - -static DRIVER_ATTR(interface_version, S_IRUGO, - tpacpi_driver_interface_version_show, NULL); - -/* debug_level --------------------------------------------------------- */ -static ssize_t tpacpi_driver_debug_show(struct device_driver *drv, - char *buf) -{ - return snprintf(buf, PAGE_SIZE, "0x%04x\n", dbg_level); -} - -static ssize_t tpacpi_driver_debug_store(struct device_driver *drv, - const char *buf, size_t count) -{ - unsigned long t; - - if (parse_strtoul(buf, 0xffff, &t)) - return -EINVAL; - - dbg_level = t; - - return count; -} - -static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO, - tpacpi_driver_debug_show, tpacpi_driver_debug_store); - -/* version ------------------------------------------------------------- */ -static ssize_t tpacpi_driver_version_show(struct device_driver *drv, - char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%s v%s\n", IBM_DESC, IBM_VERSION); -} - -static DRIVER_ATTR(version, S_IRUGO, - tpacpi_driver_version_show, NULL); - -/* --------------------------------------------------------------------- */ - -static struct driver_attribute* tpacpi_driver_attributes[] = { - &driver_attr_debug_level, &driver_attr_version, - &driver_attr_interface_version, +struct attribute_set { + unsigned int members, max_members; + struct attribute_group group; }; -static int __init tpacpi_create_driver_attributes(struct device_driver *drv) -{ - int i, res; - - i = 0; - res = 0; - while (!res && i < ARRAY_SIZE(tpacpi_driver_attributes)) { - res = driver_create_file(drv, tpacpi_driver_attributes[i]); - i++; - } - - return res; -} - -static void tpacpi_remove_driver_attributes(struct device_driver *drv) -{ - int i; - - for(i = 0; i < ARRAY_SIZE(tpacpi_driver_attributes); i++) - driver_remove_file(drv, tpacpi_driver_attributes[i]); -} - -/************************************************************************* - * sysfs support helpers - */ - struct attribute_set_obj { struct attribute_set s; struct attribute *a; @@ -945,28 +855,105 @@ static int parse_strtoul(const char *buf, return 0; } -/**************************************************************************** - **************************************************************************** - * - * Subdrivers - * - **************************************************************************** - ****************************************************************************/ - /************************************************************************* - * thinkpad-acpi init subdriver + * thinkpad-acpi driver attributes */ -static int __init thinkpad_acpi_driver_init(struct ibm_init_struct *iibm) +/* interface_version --------------------------------------------------- */ +static ssize_t tpacpi_driver_interface_version_show( + struct device_driver *drv, + char *buf) { - printk(IBM_INFO "%s v%s\n", IBM_DESC, IBM_VERSION); - printk(IBM_INFO "%s\n", IBM_URL); - - printk(IBM_INFO "ThinkPad BIOS %s, EC %s\n", - (thinkpad_id.bios_version_str) ? - thinkpad_id.bios_version_str : "unknown", - (thinkpad_id.ec_version_str) ? - thinkpad_id.ec_version_str : "unknown"); + return snprintf(buf, PAGE_SIZE, "0x%08x\n", TPACPI_SYSFS_VERSION); +} + +static DRIVER_ATTR(interface_version, S_IRUGO, + tpacpi_driver_interface_version_show, NULL); + +/* debug_level --------------------------------------------------------- */ +static ssize_t tpacpi_driver_debug_show(struct device_driver *drv, + char *buf) +{ + return snprintf(buf, PAGE_SIZE, "0x%04x\n", dbg_level); +} + +static ssize_t tpacpi_driver_debug_store(struct device_driver *drv, + const char *buf, size_t count) +{ + unsigned long t; + + if (parse_strtoul(buf, 0xffff, &t)) + return -EINVAL; + + dbg_level = t; + + return count; +} + +static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO, + tpacpi_driver_debug_show, tpacpi_driver_debug_store); + +/* version ------------------------------------------------------------- */ +static ssize_t tpacpi_driver_version_show(struct device_driver *drv, + char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%s v%s\n", IBM_DESC, IBM_VERSION); +} + +static DRIVER_ATTR(version, S_IRUGO, + tpacpi_driver_version_show, NULL); + +/* --------------------------------------------------------------------- */ + +static struct driver_attribute* tpacpi_driver_attributes[] = { + &driver_attr_debug_level, &driver_attr_version, + &driver_attr_interface_version, +}; + +static int __init tpacpi_create_driver_attributes(struct device_driver *drv) +{ + int i, res; + + i = 0; + res = 0; + while (!res && i < ARRAY_SIZE(tpacpi_driver_attributes)) { + res = driver_create_file(drv, tpacpi_driver_attributes[i]); + i++; + } + + return res; +} + +static void tpacpi_remove_driver_attributes(struct device_driver *drv) +{ + int i; + + for(i = 0; i < ARRAY_SIZE(tpacpi_driver_attributes); i++) + driver_remove_file(drv, tpacpi_driver_attributes[i]); +} + +/**************************************************************************** + **************************************************************************** + * + * Subdrivers + * + **************************************************************************** + ****************************************************************************/ + +/************************************************************************* + * thinkpad-acpi init subdriver + */ + +static int __init thinkpad_acpi_driver_init(struct ibm_init_struct *iibm) +{ + printk(IBM_INFO "%s v%s\n", IBM_DESC, IBM_VERSION); + printk(IBM_INFO "%s\n", IBM_URL); + + printk(IBM_INFO "ThinkPad BIOS %s, EC %s\n", + (thinkpad_id.bios_version_str) ? + thinkpad_id.bios_version_str : "unknown", + (thinkpad_id.ec_version_str) ? + thinkpad_id.ec_version_str : "unknown"); if (thinkpad_id.vendor && thinkpad_id.model_str) printk(IBM_INFO "%s %s\n", @@ -1094,6 +1081,8 @@ static u32 hotkey_all_mask; static u32 hotkey_reserved_mask; static u32 hotkey_mask; +static unsigned int hotkey_report_mode; + static u16 *hotkey_keycode_map; static struct attribute_set *hotkey_dev_attributes; @@ -3637,8 +3626,87 @@ struct ibm_thermal_sensors_struct { static enum thermal_access_mode thermal_read_mode; -static int thermal_get_sensor(int idx, s32 *value); -static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s); +/* idx is zero-based */ +static int thermal_get_sensor(int idx, s32 *value) +{ + int t; + s8 tmp; + char tmpi[5]; + + t = TP_EC_THERMAL_TMP0; + + switch (thermal_read_mode) { +#if TPACPI_MAX_THERMAL_SENSORS >= 16 + case TPACPI_THERMAL_TPEC_16: + if (idx >= 8 && idx <= 15) { + t = TP_EC_THERMAL_TMP8; + idx -= 8; + } + /* fallthrough */ +#endif + case TPACPI_THERMAL_TPEC_8: + if (idx <= 7) { + if (!acpi_ec_read(t + idx, &tmp)) + return -EIO; + *value = tmp * 1000; + return 0; + } + break; + + case TPACPI_THERMAL_ACPI_UPDT: + if (idx <= 7) { + snprintf(tmpi, sizeof(tmpi), "TMP%c", '0' + idx); + if (!acpi_evalf(ec_handle, NULL, "UPDT", "v")) + return -EIO; + if (!acpi_evalf(ec_handle, &t, tmpi, "d")) + return -EIO; + *value = (t - 2732) * 100; + return 0; + } + break; + + case TPACPI_THERMAL_ACPI_TMP07: + if (idx <= 7) { + snprintf(tmpi, sizeof(tmpi), "TMP%c", '0' + idx); + if (!acpi_evalf(ec_handle, &t, tmpi, "d")) + return -EIO; + if (t > 127 || t < -127) + t = TP_EC_THERMAL_TMP_NA; + *value = t * 1000; + return 0; + } + break; + + case TPACPI_THERMAL_NONE: + default: + return -ENOSYS; + } + + return -EINVAL; +} + +static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s) +{ + int res, i; + int n; + + n = 8; + i = 0; + + if (!s) + return -EINVAL; + + if (thermal_read_mode == TPACPI_THERMAL_TPEC_16) + n = 16; + + for(i = 0 ; i < n; i++) { + res = thermal_get_sensor(i, &s->temp[i]); + if (res) + return res; + } + + return n; +} /* sysfs temp##_input -------------------------------------------------- */ @@ -3830,88 +3898,6 @@ static void thermal_exit(void) } } -/* idx is zero-based */ -static int thermal_get_sensor(int idx, s32 *value) -{ - int t; - s8 tmp; - char tmpi[5]; - - t = TP_EC_THERMAL_TMP0; - - switch (thermal_read_mode) { -#if TPACPI_MAX_THERMAL_SENSORS >= 16 - case TPACPI_THERMAL_TPEC_16: - if (idx >= 8 && idx <= 15) { - t = TP_EC_THERMAL_TMP8; - idx -= 8; - } - /* fallthrough */ -#endif - case TPACPI_THERMAL_TPEC_8: - if (idx <= 7) { - if (!acpi_ec_read(t + idx, &tmp)) - return -EIO; - *value = tmp * 1000; - return 0; - } - break; - - case TPACPI_THERMAL_ACPI_UPDT: - if (idx <= 7) { - snprintf(tmpi, sizeof(tmpi), "TMP%c", '0' + idx); - if (!acpi_evalf(ec_handle, NULL, "UPDT", "v")) - return -EIO; - if (!acpi_evalf(ec_handle, &t, tmpi, "d")) - return -EIO; - *value = (t - 2732) * 100; - return 0; - } - break; - - case TPACPI_THERMAL_ACPI_TMP07: - if (idx <= 7) { - snprintf(tmpi, sizeof(tmpi), "TMP%c", '0' + idx); - if (!acpi_evalf(ec_handle, &t, tmpi, "d")) - return -EIO; - if (t > 127 || t < -127) - t = TP_EC_THERMAL_TMP_NA; - *value = t * 1000; - return 0; - } - break; - - case TPACPI_THERMAL_NONE: - default: - return -ENOSYS; - } - - return -EINVAL; -} - -static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s) -{ - int res, i; - int n; - - n = 8; - i = 0; - - if (!s) - return -EINVAL; - - if (thermal_read_mode == TPACPI_THERMAL_TPEC_16) - n = 16; - - for(i = 0 ; i < n; i++) { - res = thermal_get_sensor(i, &s->temp[i]); - if (res) - return res; - } - - return n; -} - static int thermal_read(char *p) { int len = 0; @@ -4021,16 +4007,103 @@ static int brightness_offset = 0x31; static int brightness_mode; static unsigned int brightness_enable = 2; /* 2 = auto, 0 = no, 1 = yes */ -static int brightness_get(struct backlight_device *bd); -static int brightness_set(int value); -static int brightness_update_status(struct backlight_device *bd); +static struct mutex brightness_mutex; -static struct backlight_ops ibm_backlight_data = { - .get_brightness = brightness_get, +/* + * ThinkPads can read brightness from two places: EC 0x31, or + * CMOS NVRAM byte 0x5E, bits 0-3. + */ +static int brightness_get(struct backlight_device *bd) +{ + u8 lec = 0, lcmos = 0, level = 0; + + if (brightness_mode & 1) { + if (!acpi_ec_read(brightness_offset, &lec)) + return -EIO; + lec &= (tp_features.bright_16levels)? 0x0f : 0x07; + level = lec; + }; + if (brightness_mode & 2) { + lcmos = (nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS) + & TP_NVRAM_MASK_LEVEL_BRIGHTNESS) + >> TP_NVRAM_POS_LEVEL_BRIGHTNESS; + lcmos &= (tp_features.bright_16levels)? 0x0f : 0x07; + level = lcmos; + } + + if (brightness_mode == 3 && lec != lcmos) { + printk(IBM_ERR + "CMOS NVRAM (%u) and EC (%u) do not agree " + "on display brightness level\n", + (unsigned int) lcmos, + (unsigned int) lec); + return -EIO; + } + + return level; +} + +/* May return EINTR which can always be mapped to ERESTARTSYS */ +static int brightness_set(int value) +{ + int cmos_cmd, inc, i, res; + int current_value; + + if (value > ((tp_features.bright_16levels)? 15 : 7)) + return -EINVAL; + + res = mutex_lock_interruptible(&brightness_mutex); + if (res < 0) + return res; + + current_value = brightness_get(NULL); + if (current_value < 0) { + res = current_value; + goto errout; + } + + cmos_cmd = value > current_value ? + TP_CMOS_BRIGHTNESS_UP : + TP_CMOS_BRIGHTNESS_DOWN; + inc = (value > current_value)? 1 : -1; + + res = 0; + for (i = current_value; i != value; i += inc) { + if ((brightness_mode & 2) && + issue_thinkpad_cmos_command(cmos_cmd)) { + res = -EIO; + goto errout; + } + if ((brightness_mode & 1) && + !acpi_ec_write(brightness_offset, i + inc)) { + res = -EIO; + goto errout;; + } + } + +errout: + mutex_unlock(&brightness_mutex); + return res; +} + +/* sysfs backlight class ----------------------------------------------- */ + +static int brightness_update_status(struct backlight_device *bd) +{ + /* it is the backlight class's job (caller) to handle + * EINTR and other errors properly */ + return brightness_set( + (bd->props.fb_blank == FB_BLANK_UNBLANK && + bd->props.power == FB_BLANK_UNBLANK) ? + bd->props.brightness : 0); +} + +static struct backlight_ops ibm_backlight_data = { + .get_brightness = brightness_get, .update_status = brightness_update_status, }; -static struct mutex brightness_mutex; +/* --------------------------------------------------------------------- */ static int __init tpacpi_query_bcll_levels(acpi_handle handle) { @@ -4196,93 +4269,6 @@ static void brightness_exit(void) } } -static int brightness_update_status(struct backlight_device *bd) -{ - /* it is the backlight class's job (caller) to handle - * EINTR and other errors properly */ - return brightness_set( - (bd->props.fb_blank == FB_BLANK_UNBLANK && - bd->props.power == FB_BLANK_UNBLANK) ? - bd->props.brightness : 0); -} - -/* - * ThinkPads can read brightness from two places: EC 0x31, or - * CMOS NVRAM byte 0x5E, bits 0-3. - */ -static int brightness_get(struct backlight_device *bd) -{ - u8 lec = 0, lcmos = 0, level = 0; - - if (brightness_mode & 1) { - if (!acpi_ec_read(brightness_offset, &lec)) - return -EIO; - lec &= (tp_features.bright_16levels)? 0x0f : 0x07; - level = lec; - }; - if (brightness_mode & 2) { - lcmos = (nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS) - & TP_NVRAM_MASK_LEVEL_BRIGHTNESS) - >> TP_NVRAM_POS_LEVEL_BRIGHTNESS; - lcmos &= (tp_features.bright_16levels)? 0x0f : 0x07; - level = lcmos; - } - - if (brightness_mode == 3 && lec != lcmos) { - printk(IBM_ERR - "CMOS NVRAM (%u) and EC (%u) do not agree " - "on display brightness level\n", - (unsigned int) lcmos, - (unsigned int) lec); - return -EIO; - } - - return level; -} - -/* May return EINTR which can always be mapped to ERESTARTSYS */ -static int brightness_set(int value) -{ - int cmos_cmd, inc, i, res; - int current_value; - - if (value > ((tp_features.bright_16levels)? 15 : 7)) - return -EINVAL; - - res = mutex_lock_interruptible(&brightness_mutex); - if (res < 0) - return res; - - current_value = brightness_get(NULL); - if (current_value < 0) { - res = current_value; - goto errout; - } - - cmos_cmd = value > current_value ? - TP_CMOS_BRIGHTNESS_UP : - TP_CMOS_BRIGHTNESS_DOWN; - inc = (value > current_value)? 1 : -1; - - res = 0; - for (i = current_value; i != value; i += inc) { - if ((brightness_mode & 2) && - issue_thinkpad_cmos_command(cmos_cmd)) { - res = -EIO; - goto errout; - } - if ((brightness_mode & 1) && - !acpi_ec_write(brightness_offset, i + inc)) { - res = -EIO; - goto errout;; - } - } - -errout: - mutex_unlock(&brightness_mutex); - return res; -} - static int brightness_read(char *p) { int len = 0; @@ -4581,16 +4567,7 @@ static int fan_watchdog_maxinterval; static struct mutex fan_mutex; -static int fan_get_status(u8 *status); -static int fan_get_status_safe(u8 *status); -static int fan_get_speed(unsigned int *speed); -static void fan_update_desired_level(u8 status); static void fan_watchdog_fire(struct work_struct *ignored); -static void fan_watchdog_reset(void); -static int fan_set_level(int level); -static int fan_set_level_safe(int level); -static int fan_set_enable(void); - static DECLARE_DELAYED_WORK(fan_watchdog_task, fan_watchdog_fire); IBM_HANDLE(fans, ec, "FANS"); /* X31, X40, X41 */ @@ -4602,458 +4579,278 @@ IBM_HANDLE(sfan, ec, "SFAN", /* 570 */ ); /* all others */ /* - * SYSFS fan layout: hwmon compatible (device) - * - * pwm*_enable: - * 0: "disengaged" mode - * 1: manual mode - * 2: native EC "auto" mode (recommended, hardware default) - * - * pwm*: set speed in manual mode, ignored otherwise. - * 0 is level 0; 255 is level 7. Intermediate points done with linear - * interpolation. - * - * fan*_input: tachometer reading, RPM - * - * - * SYSFS fan layout: extensions - * - * fan_watchdog (driver): - * fan watchdog interval in seconds, 0 disables (default), max 120 + * Call with fan_mutex held */ - -/* sysfs fan pwm1_enable ----------------------------------------------- */ -static ssize_t fan_pwm1_enable_show(struct device *dev, - struct device_attribute *attr, - char *buf) +static void fan_update_desired_level(u8 status) { - int res, mode; - u8 status; + if ((status & + (TP_EC_FAN_AUTO | TP_EC_FAN_FULLSPEED)) == 0) { + if (status > 7) + fan_control_desired_level = 7; + else + fan_control_desired_level = status; + } +} - res = fan_get_status_safe(&status); - if (res) - return res; +static int fan_get_status(u8 *status) +{ + u8 s; - if (unlikely(tp_features.fan_ctrl_status_undef)) { - if (status != fan_control_initial_status) { - tp_features.fan_ctrl_status_undef = 0; - } else { - /* Return most likely status. In fact, it - * might be the only possible status */ - status = TP_EC_FAN_AUTO; - } - } + /* TODO: + * Add TPACPI_FAN_RD_ACPI_FANS ? */ - if (status & TP_EC_FAN_FULLSPEED) { - mode = 0; - } else if (status & TP_EC_FAN_AUTO) { - mode = 2; - } else - mode = 1; + switch (fan_status_access_mode) { + case TPACPI_FAN_RD_ACPI_GFAN: + /* 570, 600e/x, 770e, 770x */ - return snprintf(buf, PAGE_SIZE, "%d\n", mode); -} + if (unlikely(!acpi_evalf(gfan_handle, &s, NULL, "d"))) + return -EIO; -static ssize_t fan_pwm1_enable_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - unsigned long t; - int res, level; + if (likely(status)) + *status = s & 0x07; - if (parse_strtoul(buf, 2, &t)) - return -EINVAL; + break; + + case TPACPI_FAN_RD_TPEC: + /* all except 570, 600e/x, 770e, 770x */ + if (unlikely(!acpi_ec_read(fan_status_offset, &s))) + return -EIO; + + if (likely(status)) + *status = s; - switch (t) { - case 0: - level = TP_EC_FAN_FULLSPEED; - break; - case 1: - level = TPACPI_FAN_LAST_LEVEL; - break; - case 2: - level = TP_EC_FAN_AUTO; break; - case 3: - /* reserved for software-controlled auto mode */ - return -ENOSYS; + default: - return -EINVAL; + return -ENXIO; } - res = fan_set_level_safe(level); - if (res == -ENXIO) - return -EINVAL; - else if (res < 0) - return res; + return 0; +} - fan_watchdog_reset(); +static int fan_get_status_safe(u8 *status) +{ + int rc; + u8 s; - return count; -} + if (mutex_lock_interruptible(&fan_mutex)) + return -ERESTARTSYS; + rc = fan_get_status(&s); + if (!rc) + fan_update_desired_level(s); + mutex_unlock(&fan_mutex); -static struct device_attribute dev_attr_fan_pwm1_enable = - __ATTR(pwm1_enable, S_IWUSR | S_IRUGO, - fan_pwm1_enable_show, fan_pwm1_enable_store); + if (status) + *status = s; -/* sysfs fan pwm1 ------------------------------------------------------ */ -static ssize_t fan_pwm1_show(struct device *dev, - struct device_attribute *attr, - char *buf) + return rc; +} + +static int fan_get_speed(unsigned int *speed) { - int res; - u8 status; + u8 hi, lo; - res = fan_get_status_safe(&status); - if (res) - return res; + switch (fan_status_access_mode) { + case TPACPI_FAN_RD_TPEC: + /* all except 570, 600e/x, 770e, 770x */ + if (unlikely(!acpi_ec_read(fan_rpm_offset, &lo) || + !acpi_ec_read(fan_rpm_offset + 1, &hi))) + return -EIO; - if (unlikely(tp_features.fan_ctrl_status_undef)) { - if (status != fan_control_initial_status) { - tp_features.fan_ctrl_status_undef = 0; - } else { - status = TP_EC_FAN_AUTO; - } - } + if (likely(speed)) + *speed = (hi << 8) | lo; - if ((status & - (TP_EC_FAN_AUTO | TP_EC_FAN_FULLSPEED)) != 0) - status = fan_control_desired_level; + break; - if (status > 7) - status = 7; + default: + return -ENXIO; + } - return snprintf(buf, PAGE_SIZE, "%u\n", (status * 255) / 7); + return 0; } -static ssize_t fan_pwm1_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static int fan_set_level(int level) { - unsigned long s; - int rc; - u8 status, newlevel; + if (!fan_control_allowed) + return -EPERM; - if (parse_strtoul(buf, 255, &s)) - return -EINVAL; + switch (fan_control_access_mode) { + case TPACPI_FAN_WR_ACPI_SFAN: + if (level >= 0 && level <= 7) { + if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", level)) + return -EIO; + } else + return -EINVAL; + break; - /* scale down from 0-255 to 0-7 */ - newlevel = (s >> 5) & 0x07; + case TPACPI_FAN_WR_ACPI_FANS: + case TPACPI_FAN_WR_TPEC: + if ((level != TP_EC_FAN_AUTO) && + (level != TP_EC_FAN_FULLSPEED) && + ((level < 0) || (level > 7))) + return -EINVAL; - if (mutex_lock_interruptible(&fan_mutex)) - return -ERESTARTSYS; + /* safety net should the EC not support AUTO + * or FULLSPEED mode bits and just ignore them */ + if (level & TP_EC_FAN_FULLSPEED) + level |= 7; /* safety min speed 7 */ + else if (level & TP_EC_FAN_FULLSPEED) + level |= 4; /* safety min speed 4 */ - rc = fan_get_status(&status); - if (!rc && (status & - (TP_EC_FAN_AUTO | TP_EC_FAN_FULLSPEED)) == 0) { - rc = fan_set_level(newlevel); - if (rc == -ENXIO) - rc = -EINVAL; - else if (!rc) { - fan_update_desired_level(newlevel); - fan_watchdog_reset(); - } - } + if (!acpi_ec_write(fan_status_offset, level)) + return -EIO; + else + tp_features.fan_ctrl_status_undef = 0; + break; - mutex_unlock(&fan_mutex); - return (rc)? rc : count; + default: + return -ENXIO; + } + return 0; } -static struct device_attribute dev_attr_fan_pwm1 = - __ATTR(pwm1, S_IWUSR | S_IRUGO, - fan_pwm1_show, fan_pwm1_store); - -/* sysfs fan fan1_input ------------------------------------------------ */ -static ssize_t fan_fan1_input_show(struct device *dev, - struct device_attribute *attr, - char *buf) +static int fan_set_level_safe(int level) { - int res; - unsigned int speed; + int rc; - res = fan_get_speed(&speed); - if (res < 0) - return res; + if (!fan_control_allowed) + return -EPERM; - return snprintf(buf, PAGE_SIZE, "%u\n", speed); -} + if (mutex_lock_interruptible(&fan_mutex)) + return -ERESTARTSYS; -static struct device_attribute dev_attr_fan_fan1_input = - __ATTR(fan1_input, S_IRUGO, - fan_fan1_input_show, NULL); + if (level == TPACPI_FAN_LAST_LEVEL) + level = fan_control_desired_level; -/* sysfs fan fan_watchdog (hwmon driver) ------------------------------- */ -static ssize_t fan_fan_watchdog_show(struct device_driver *drv, - char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%u\n", fan_watchdog_maxinterval); + rc = fan_set_level(level); + if (!rc) + fan_update_desired_level(level); + + mutex_unlock(&fan_mutex); + return rc; } -static ssize_t fan_fan_watchdog_store(struct device_driver *drv, - const char *buf, size_t count) +static int fan_set_enable(void) { - unsigned long t; - - if (parse_strtoul(buf, 120, &t)) - return -EINVAL; + u8 s; + int rc; if (!fan_control_allowed) return -EPERM; - fan_watchdog_maxinterval = t; - fan_watchdog_reset(); + if (mutex_lock_interruptible(&fan_mutex)) + return -ERESTARTSYS; - return count; -} + switch (fan_control_access_mode) { + case TPACPI_FAN_WR_ACPI_FANS: + case TPACPI_FAN_WR_TPEC: + rc = fan_get_status(&s); + if (rc < 0) + break; -static DRIVER_ATTR(fan_watchdog, S_IWUSR | S_IRUGO, - fan_fan_watchdog_show, fan_fan_watchdog_store); + /* Don't go out of emergency fan mode */ + if (s != 7) { + s &= 0x07; + s |= TP_EC_FAN_AUTO | 4; /* min fan speed 4 */ + } -/* --------------------------------------------------------------------- */ -static struct attribute *fan_attributes[] = { - &dev_attr_fan_pwm1_enable.attr, &dev_attr_fan_pwm1.attr, - &dev_attr_fan_fan1_input.attr, - NULL -}; + if (!acpi_ec_write(fan_status_offset, s)) + rc = -EIO; + else { + tp_features.fan_ctrl_status_undef = 0; + rc = 0; + } + break; -static const struct attribute_group fan_attr_group = { - .attrs = fan_attributes, -}; + case TPACPI_FAN_WR_ACPI_SFAN: + rc = fan_get_status(&s); + if (rc < 0) + break; -static int __init fan_init(struct ibm_init_struct *iibm) -{ - int rc; + s &= 0x07; - vdbg_printk(TPACPI_DBG_INIT, "initializing fan subdriver\n"); + /* Set fan to at least level 4 */ + s |= 4; - mutex_init(&fan_mutex); - fan_status_access_mode = TPACPI_FAN_NONE; - fan_control_access_mode = TPACPI_FAN_WR_NONE; - fan_control_commands = 0; - fan_watchdog_maxinterval = 0; - tp_features.fan_ctrl_status_undef = 0; - fan_control_desired_level = 7; + if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", s)) + rc= -EIO; + else + rc = 0; + break; - IBM_ACPIHANDLE_INIT(fans); - IBM_ACPIHANDLE_INIT(gfan); - IBM_ACPIHANDLE_INIT(sfan); + default: + rc = -ENXIO; + } - if (gfan_handle) { - /* 570, 600e/x, 770e, 770x */ - fan_status_access_mode = TPACPI_FAN_RD_ACPI_GFAN; - } else { - /* all other ThinkPads: note that even old-style - * ThinkPad ECs supports the fan control register */ - if (likely(acpi_ec_read(fan_status_offset, - &fan_control_initial_status))) { - fan_status_access_mode = TPACPI_FAN_RD_TPEC; - - /* In some ThinkPads, neither the EC nor the ACPI - * DSDT initialize the fan status, and it ends up - * being set to 0x07 when it *could* be either - * 0x07 or 0x80. - * - * Enable for TP-1Y (T43), TP-78 (R51e), - * TP-76 (R52), TP-70 (T43, R52), which are known - * to be buggy. */ - if (fan_control_initial_status == 0x07) { - switch (thinkpad_id.ec_model) { - case 0x5931: /* TP-1Y */ - case 0x3837: /* TP-78 */ - case 0x3637: /* TP-76 */ - case 0x3037: /* TP-70 */ - printk(IBM_NOTICE - "fan_init: initial fan status is " - "unknown, assuming it is in auto " - "mode\n"); - tp_features.fan_ctrl_status_undef = 1; - ;; - } - } - } else { - printk(IBM_ERR - "ThinkPad ACPI EC access misbehaving, " - "fan status and control unavailable\n"); - return 1; - } - } - - if (sfan_handle) { - /* 570, 770x-JL */ - fan_control_access_mode = TPACPI_FAN_WR_ACPI_SFAN; - fan_control_commands |= - TPACPI_FAN_CMD_LEVEL | TPACPI_FAN_CMD_ENABLE; - } else { - if (!gfan_handle) { - /* gfan without sfan means no fan control */ - /* all other models implement TP EC 0x2f control */ - - if (fans_handle) { - /* X31, X40, X41 */ - fan_control_access_mode = - TPACPI_FAN_WR_ACPI_FANS; - fan_control_commands |= - TPACPI_FAN_CMD_SPEED | - TPACPI_FAN_CMD_LEVEL | - TPACPI_FAN_CMD_ENABLE; - } else { - fan_control_access_mode = TPACPI_FAN_WR_TPEC; - fan_control_commands |= - TPACPI_FAN_CMD_LEVEL | - TPACPI_FAN_CMD_ENABLE; - } - } - } - - vdbg_printk(TPACPI_DBG_INIT, "fan is %s, modes %d, %d\n", - str_supported(fan_status_access_mode != TPACPI_FAN_NONE || - fan_control_access_mode != TPACPI_FAN_WR_NONE), - fan_status_access_mode, fan_control_access_mode); - - /* fan control master switch */ - if (!fan_control_allowed) { - fan_control_access_mode = TPACPI_FAN_WR_NONE; - fan_control_commands = 0; - dbg_printk(TPACPI_DBG_INIT, - "fan control features disabled by parameter\n"); - } - - /* update fan_control_desired_level */ - if (fan_status_access_mode != TPACPI_FAN_NONE) - fan_get_status_safe(NULL); - - if (fan_status_access_mode != TPACPI_FAN_NONE || - fan_control_access_mode != TPACPI_FAN_WR_NONE) { - rc = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj, - &fan_attr_group); - if (!(rc < 0)) - rc = driver_create_file(&tpacpi_hwmon_pdriver.driver, - &driver_attr_fan_watchdog); - if (rc < 0) - return rc; - return 0; - } else - return 1; -} - -/* - * Call with fan_mutex held - */ -static void fan_update_desired_level(u8 status) -{ - if ((status & - (TP_EC_FAN_AUTO | TP_EC_FAN_FULLSPEED)) == 0) { - if (status > 7) - fan_control_desired_level = 7; - else - fan_control_desired_level = status; - } + mutex_unlock(&fan_mutex); + return rc; } -static int fan_get_status(u8 *status) +static int fan_set_disable(void) { - u8 s; - - /* TODO: - * Add TPACPI_FAN_RD_ACPI_FANS ? */ - - switch (fan_status_access_mode) { - case TPACPI_FAN_RD_ACPI_GFAN: - /* 570, 600e/x, 770e, 770x */ + int rc; - if (unlikely(!acpi_evalf(gfan_handle, &s, NULL, "d"))) - return -EIO; + if (!fan_control_allowed) + return -EPERM; - if (likely(status)) - *status = s & 0x07; + if (mutex_lock_interruptible(&fan_mutex)) + return -ERESTARTSYS; + rc = 0; + switch (fan_control_access_mode) { + case TPACPI_FAN_WR_ACPI_FANS: + case TPACPI_FAN_WR_TPEC: + if (!acpi_ec_write(fan_status_offset, 0x00)) + rc = -EIO; + else { + fan_control_desired_level = 0; + tp_features.fan_ctrl_status_undef = 0; + } break; - case TPACPI_FAN_RD_TPEC: - /* all except 570, 600e/x, 770e, 770x */ - if (unlikely(!acpi_ec_read(fan_status_offset, &s))) - return -EIO; - - if (likely(status)) - *status = s; - + case TPACPI_FAN_WR_ACPI_SFAN: + if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", 0x00)) + rc = -EIO; + else + fan_control_desired_level = 0; break; default: - return -ENXIO; + rc = -ENXIO; } - return 0; -} - -static int fan_get_status_safe(u8 *status) -{ - int rc; - u8 s; - if (mutex_lock_interruptible(&fan_mutex)) - return -ERESTARTSYS; - rc = fan_get_status(&s); - if (!rc) - fan_update_desired_level(s); mutex_unlock(&fan_mutex); - - if (status) - *status = s; - return rc; } -static void fan_exit(void) -{ - vdbg_printk(TPACPI_DBG_EXIT, "cancelling any pending fan watchdog tasks\n"); - - /* FIXME: can we really do this unconditionally? */ - sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj, &fan_attr_group); - driver_remove_file(&tpacpi_hwmon_pdriver.driver, &driver_attr_fan_watchdog); - - cancel_delayed_work(&fan_watchdog_task); - flush_scheduled_work(); -} - -static int fan_get_speed(unsigned int *speed) +static int fan_set_speed(int speed) { - u8 hi, lo; + int rc; - switch (fan_status_access_mode) { - case TPACPI_FAN_RD_TPEC: - /* all except 570, 600e/x, 770e, 770x */ - if (unlikely(!acpi_ec_read(fan_rpm_offset, &lo) || - !acpi_ec_read(fan_rpm_offset + 1, &hi))) - return -EIO; + if (!fan_control_allowed) + return -EPERM; - if (likely(speed)) - *speed = (hi << 8) | lo; + if (mutex_lock_interruptible(&fan_mutex)) + return -ERESTARTSYS; + rc = 0; + switch (fan_control_access_mode) { + case TPACPI_FAN_WR_ACPI_FANS: + if (speed >= 0 && speed <= 65535) { + if (!acpi_evalf(fans_handle, NULL, NULL, "vddd", + speed, speed, speed)) + rc = -EIO; + } else + rc = -EINVAL; break; default: - return -ENXIO; + rc = -ENXIO; } - return 0; -} - -static void fan_watchdog_fire(struct work_struct *ignored) -{ - int rc; - - if (tpacpi_lifecycle != TPACPI_LIFE_RUNNING) - return; - - printk(IBM_NOTICE "fan watchdog: enabling fan\n"); - rc = fan_set_enable(); - if (rc < 0) { - printk(IBM_ERR "fan watchdog: error %d while enabling fan, " - "will try again later...\n", -rc); - /* reschedule for later */ - fan_watchdog_reset(); - } + mutex_unlock(&fan_mutex); + return rc; } static void fan_watchdog_reset(void) @@ -5079,188 +4876,368 @@ static void fan_watchdog_reset(void) fan_watchdog_active = 0; } -static int fan_set_level(int level) +static void fan_watchdog_fire(struct work_struct *ignored) { - if (!fan_control_allowed) - return -EPERM; - - switch (fan_control_access_mode) { - case TPACPI_FAN_WR_ACPI_SFAN: - if (level >= 0 && level <= 7) { - if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", level)) - return -EIO; - } else - return -EINVAL; - break; + int rc; - case TPACPI_FAN_WR_ACPI_FANS: - case TPACPI_FAN_WR_TPEC: - if ((level != TP_EC_FAN_AUTO) && - (level != TP_EC_FAN_FULLSPEED) && - ((level < 0) || (level > 7))) - return -EINVAL; + if (tpacpi_lifecycle != TPACPI_LIFE_RUNNING) + return; - /* safety net should the EC not support AUTO - * or FULLSPEED mode bits and just ignore them */ - if (level & TP_EC_FAN_FULLSPEED) - level |= 7; /* safety min speed 7 */ - else if (level & TP_EC_FAN_FULLSPEED) - level |= 4; /* safety min speed 4 */ + printk(IBM_NOTICE "fan watchdog: enabling fan\n"); + rc = fan_set_enable(); + if (rc < 0) { + printk(IBM_ERR "fan watchdog: error %d while enabling fan, " + "will try again later...\n", -rc); + /* reschedule for later */ + fan_watchdog_reset(); + } +} - if (!acpi_ec_write(fan_status_offset, level)) - return -EIO; - else +/* + * SYSFS fan layout: hwmon compatible (device) + * + * pwm*_enable: + * 0: "disengaged" mode + * 1: manual mode + * 2: native EC "auto" mode (recommended, hardware default) + * + * pwm*: set speed in manual mode, ignored otherwise. + * 0 is level 0; 255 is level 7. Intermediate points done with linear + * interpolation. + * + * fan*_input: tachometer reading, RPM + * + * + * SYSFS fan layout: extensions + * + * fan_watchdog (driver): + * fan watchdog interval in seconds, 0 disables (default), max 120 + */ + +/* sysfs fan pwm1_enable ----------------------------------------------- */ +static ssize_t fan_pwm1_enable_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int res, mode; + u8 status; + + res = fan_get_status_safe(&status); + if (res) + return res; + + if (unlikely(tp_features.fan_ctrl_status_undef)) { + if (status != fan_control_initial_status) { tp_features.fan_ctrl_status_undef = 0; - break; + } else { + /* Return most likely status. In fact, it + * might be the only possible status */ + status = TP_EC_FAN_AUTO; + } + } + + if (status & TP_EC_FAN_FULLSPEED) { + mode = 0; + } else if (status & TP_EC_FAN_AUTO) { + mode = 2; + } else + mode = 1; + + return snprintf(buf, PAGE_SIZE, "%d\n", mode); +} +static ssize_t fan_pwm1_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long t; + int res, level; + + if (parse_strtoul(buf, 2, &t)) + return -EINVAL; + + switch (t) { + case 0: + level = TP_EC_FAN_FULLSPEED; + break; + case 1: + level = TPACPI_FAN_LAST_LEVEL; + break; + case 2: + level = TP_EC_FAN_AUTO; + break; + case 3: + /* reserved for software-controlled auto mode */ + return -ENOSYS; default: - return -ENXIO; + return -EINVAL; } - return 0; + + res = fan_set_level_safe(level); + if (res == -ENXIO) + return -EINVAL; + else if (res < 0) + return res; + + fan_watchdog_reset(); + + return count; } -static int fan_set_level_safe(int level) +static struct device_attribute dev_attr_fan_pwm1_enable = + __ATTR(pwm1_enable, S_IWUSR | S_IRUGO, + fan_pwm1_enable_show, fan_pwm1_enable_store); + +/* sysfs fan pwm1 ------------------------------------------------------ */ +static ssize_t fan_pwm1_show(struct device *dev, + struct device_attribute *attr, + char *buf) { - int rc; + int res; + u8 status; - if (!fan_control_allowed) - return -EPERM; + res = fan_get_status_safe(&status); + if (res) + return res; - if (mutex_lock_interruptible(&fan_mutex)) - return -ERESTARTSYS; + if (unlikely(tp_features.fan_ctrl_status_undef)) { + if (status != fan_control_initial_status) { + tp_features.fan_ctrl_status_undef = 0; + } else { + status = TP_EC_FAN_AUTO; + } + } - if (level == TPACPI_FAN_LAST_LEVEL) - level = fan_control_desired_level; + if ((status & + (TP_EC_FAN_AUTO | TP_EC_FAN_FULLSPEED)) != 0) + status = fan_control_desired_level; - rc = fan_set_level(level); - if (!rc) - fan_update_desired_level(level); + if (status > 7) + status = 7; - mutex_unlock(&fan_mutex); - return rc; + return snprintf(buf, PAGE_SIZE, "%u\n", (status * 255) / 7); } -static int fan_set_enable(void) +static ssize_t fan_pwm1_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { - u8 s; + unsigned long s; int rc; + u8 status, newlevel; - if (!fan_control_allowed) - return -EPERM; + if (parse_strtoul(buf, 255, &s)) + return -EINVAL; + + /* scale down from 0-255 to 0-7 */ + newlevel = (s >> 5) & 0x07; if (mutex_lock_interruptible(&fan_mutex)) return -ERESTARTSYS; - switch (fan_control_access_mode) { - case TPACPI_FAN_WR_ACPI_FANS: - case TPACPI_FAN_WR_TPEC: - rc = fan_get_status(&s); - if (rc < 0) - break; - - /* Don't go out of emergency fan mode */ - if (s != 7) { - s &= 0x07; - s |= TP_EC_FAN_AUTO | 4; /* min fan speed 4 */ + rc = fan_get_status(&status); + if (!rc && (status & + (TP_EC_FAN_AUTO | TP_EC_FAN_FULLSPEED)) == 0) { + rc = fan_set_level(newlevel); + if (rc == -ENXIO) + rc = -EINVAL; + else if (!rc) { + fan_update_desired_level(newlevel); + fan_watchdog_reset(); } + } - if (!acpi_ec_write(fan_status_offset, s)) - rc = -EIO; - else { - tp_features.fan_ctrl_status_undef = 0; - rc = 0; - } - break; + mutex_unlock(&fan_mutex); + return (rc)? rc : count; +} - case TPACPI_FAN_WR_ACPI_SFAN: - rc = fan_get_status(&s); - if (rc < 0) - break; +static struct device_attribute dev_attr_fan_pwm1 = + __ATTR(pwm1, S_IWUSR | S_IRUGO, + fan_pwm1_show, fan_pwm1_store); - s &= 0x07; +/* sysfs fan fan1_input ------------------------------------------------ */ +static ssize_t fan_fan1_input_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int res; + unsigned int speed; - /* Set fan to at least level 4 */ - s |= 4; + res = fan_get_speed(&speed); + if (res < 0) + return res; - if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", s)) - rc= -EIO; - else - rc = 0; - break; + return snprintf(buf, PAGE_SIZE, "%u\n", speed); +} - default: - rc = -ENXIO; - } +static struct device_attribute dev_attr_fan_fan1_input = + __ATTR(fan1_input, S_IRUGO, + fan_fan1_input_show, NULL); - mutex_unlock(&fan_mutex); - return rc; +/* sysfs fan fan_watchdog (hwmon driver) ------------------------------- */ +static ssize_t fan_fan_watchdog_show(struct device_driver *drv, + char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%u\n", fan_watchdog_maxinterval); } -static int fan_set_disable(void) +static ssize_t fan_fan_watchdog_store(struct device_driver *drv, + const char *buf, size_t count) { - int rc; + unsigned long t; + + if (parse_strtoul(buf, 120, &t)) + return -EINVAL; if (!fan_control_allowed) return -EPERM; - if (mutex_lock_interruptible(&fan_mutex)) - return -ERESTARTSYS; + fan_watchdog_maxinterval = t; + fan_watchdog_reset(); - rc = 0; - switch (fan_control_access_mode) { - case TPACPI_FAN_WR_ACPI_FANS: - case TPACPI_FAN_WR_TPEC: - if (!acpi_ec_write(fan_status_offset, 0x00)) - rc = -EIO; - else { - fan_control_desired_level = 0; - tp_features.fan_ctrl_status_undef = 0; + return count; +} + +static DRIVER_ATTR(fan_watchdog, S_IWUSR | S_IRUGO, + fan_fan_watchdog_show, fan_fan_watchdog_store); + +/* --------------------------------------------------------------------- */ +static struct attribute *fan_attributes[] = { + &dev_attr_fan_pwm1_enable.attr, &dev_attr_fan_pwm1.attr, + &dev_attr_fan_fan1_input.attr, + NULL +}; + +static const struct attribute_group fan_attr_group = { + .attrs = fan_attributes, +}; + +static int __init fan_init(struct ibm_init_struct *iibm) +{ + int rc; + + vdbg_printk(TPACPI_DBG_INIT, "initializing fan subdriver\n"); + + mutex_init(&fan_mutex); + fan_status_access_mode = TPACPI_FAN_NONE; + fan_control_access_mode = TPACPI_FAN_WR_NONE; + fan_control_commands = 0; + fan_watchdog_maxinterval = 0; + tp_features.fan_ctrl_status_undef = 0; + fan_control_desired_level = 7; + + IBM_ACPIHANDLE_INIT(fans); + IBM_ACPIHANDLE_INIT(gfan); + IBM_ACPIHANDLE_INIT(sfan); + + if (gfan_handle) { + /* 570, 600e/x, 770e, 770x */ + fan_status_access_mode = TPACPI_FAN_RD_ACPI_GFAN; + } else { + /* all other ThinkPads: note that even old-style + * ThinkPad ECs supports the fan control register */ + if (likely(acpi_ec_read(fan_status_offset, + &fan_control_initial_status))) { + fan_status_access_mode = TPACPI_FAN_RD_TPEC; + + /* In some ThinkPads, neither the EC nor the ACPI + * DSDT initialize the fan status, and it ends up + * being set to 0x07 when it *could* be either + * 0x07 or 0x80. + * + * Enable for TP-1Y (T43), TP-78 (R51e), + * TP-76 (R52), TP-70 (T43, R52), which are known + * to be buggy. */ + if (fan_control_initial_status == 0x07) { + switch (thinkpad_id.ec_model) { + case 0x5931: /* TP-1Y */ + case 0x3837: /* TP-78 */ + case 0x3637: /* TP-76 */ + case 0x3037: /* TP-70 */ + printk(IBM_NOTICE + "fan_init: initial fan status is " + "unknown, assuming it is in auto " + "mode\n"); + tp_features.fan_ctrl_status_undef = 1; + ;; + } + } + } else { + printk(IBM_ERR + "ThinkPad ACPI EC access misbehaving, " + "fan status and control unavailable\n"); + return 1; + } + } + + if (sfan_handle) { + /* 570, 770x-JL */ + fan_control_access_mode = TPACPI_FAN_WR_ACPI_SFAN; + fan_control_commands |= + TPACPI_FAN_CMD_LEVEL | TPACPI_FAN_CMD_ENABLE; + } else { + if (!gfan_handle) { + /* gfan without sfan means no fan control */ + /* all other models implement TP EC 0x2f control */ + + if (fans_handle) { + /* X31, X40, X41 */ + fan_control_access_mode = + TPACPI_FAN_WR_ACPI_FANS; + fan_control_commands |= + TPACPI_FAN_CMD_SPEED | + TPACPI_FAN_CMD_LEVEL | + TPACPI_FAN_CMD_ENABLE; + } else { + fan_control_access_mode = TPACPI_FAN_WR_TPEC; + fan_control_commands |= + TPACPI_FAN_CMD_LEVEL | + TPACPI_FAN_CMD_ENABLE; + } } - break; + } - case TPACPI_FAN_WR_ACPI_SFAN: - if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", 0x00)) - rc = -EIO; - else - fan_control_desired_level = 0; - break; + vdbg_printk(TPACPI_DBG_INIT, "fan is %s, modes %d, %d\n", + str_supported(fan_status_access_mode != TPACPI_FAN_NONE || + fan_control_access_mode != TPACPI_FAN_WR_NONE), + fan_status_access_mode, fan_control_access_mode); - default: - rc = -ENXIO; + /* fan control master switch */ + if (!fan_control_allowed) { + fan_control_access_mode = TPACPI_FAN_WR_NONE; + fan_control_commands = 0; + dbg_printk(TPACPI_DBG_INIT, + "fan control features disabled by parameter\n"); } + /* update fan_control_desired_level */ + if (fan_status_access_mode != TPACPI_FAN_NONE) + fan_get_status_safe(NULL); - mutex_unlock(&fan_mutex); - return rc; + if (fan_status_access_mode != TPACPI_FAN_NONE || + fan_control_access_mode != TPACPI_FAN_WR_NONE) { + rc = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj, + &fan_attr_group); + if (!(rc < 0)) + rc = driver_create_file(&tpacpi_hwmon_pdriver.driver, + &driver_attr_fan_watchdog); + if (rc < 0) + return rc; + return 0; + } else + return 1; } -static int fan_set_speed(int speed) +static void fan_exit(void) { - int rc; - - if (!fan_control_allowed) - return -EPERM; - - if (mutex_lock_interruptible(&fan_mutex)) - return -ERESTARTSYS; - - rc = 0; - switch (fan_control_access_mode) { - case TPACPI_FAN_WR_ACPI_FANS: - if (speed >= 0 && speed <= 65535) { - if (!acpi_evalf(fans_handle, NULL, NULL, "vddd", - speed, speed, speed)) - rc = -EIO; - } else - rc = -EINVAL; - break; + vdbg_printk(TPACPI_DBG_EXIT, "cancelling any pending fan watchdog tasks\n"); - default: - rc = -ENXIO; - } + /* FIXME: can we really do this unconditionally? */ + sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj, &fan_attr_group); + driver_remove_file(&tpacpi_hwmon_pdriver.driver, &driver_attr_fan_watchdog); - mutex_unlock(&fan_mutex); - return rc; + cancel_delayed_work(&fan_watchdog_task); + flush_scheduled_work(); } static int fan_read(char *p) @@ -5473,11 +5450,12 @@ static struct device_attribute dev_attr_thinkpad_acpi_pdev_name = /* /proc support */ static struct proc_dir_entry *proc_dir; - /* * Module and infrastructure proble, init and exit handling */ +static int force_load; + #ifdef CONFIG_THINKPAD_ACPI_DEBUG static const char * __init str_supported(int is_supported) { @@ -5487,7 +5465,47 @@ static const char * __init str_supported(int is_supported) } #endif /* CONFIG_THINKPAD_ACPI_DEBUG */ -static void ibm_exit(struct ibm_struct *ibm); +static void ibm_exit(struct ibm_struct *ibm) +{ + dbg_printk(TPACPI_DBG_EXIT, "removing %s\n", ibm->name); + + list_del_init(&ibm->all_drivers); + + if (ibm->flags.acpi_notify_installed) { + dbg_printk(TPACPI_DBG_EXIT, + "%s: acpi_remove_notify_handler\n", ibm->name); + BUG_ON(!ibm->acpi); + acpi_remove_notify_handler(*ibm->acpi->handle, + ibm->acpi->type, + dispatch_acpi_notify); + ibm->flags.acpi_notify_installed = 0; + ibm->flags.acpi_notify_installed = 0; + } + + if (ibm->flags.proc_created) { + dbg_printk(TPACPI_DBG_EXIT, + "%s: remove_proc_entry\n", ibm->name); + remove_proc_entry(ibm->name, proc_dir); + ibm->flags.proc_created = 0; + } + + if (ibm->flags.acpi_driver_registered) { + dbg_printk(TPACPI_DBG_EXIT, + "%s: acpi_bus_unregister_driver\n", ibm->name); + BUG_ON(!ibm->acpi); + acpi_bus_unregister_driver(ibm->acpi->driver); + kfree(ibm->acpi->driver); + ibm->acpi->driver = NULL; + ibm->flags.acpi_driver_registered = 0; + } + + if (ibm->flags.init_called && ibm->exit) { + ibm->exit(); + ibm->flags.init_called = 0; + } + + dbg_printk(TPACPI_DBG_INIT, "finished removing %s\n", ibm->name); +} static int __init ibm_init(struct ibm_init_struct *iibm) { @@ -5569,48 +5587,6 @@ err_out: return (ret < 0)? ret : 0; } -static void ibm_exit(struct ibm_struct *ibm) -{ - dbg_printk(TPACPI_DBG_EXIT, "removing %s\n", ibm->name); - - list_del_init(&ibm->all_drivers); - - if (ibm->flags.acpi_notify_installed) { - dbg_printk(TPACPI_DBG_EXIT, - "%s: acpi_remove_notify_handler\n", ibm->name); - BUG_ON(!ibm->acpi); - acpi_remove_notify_handler(*ibm->acpi->handle, - ibm->acpi->type, - dispatch_acpi_notify); - ibm->flags.acpi_notify_installed = 0; - ibm->flags.acpi_notify_installed = 0; - } - - if (ibm->flags.proc_created) { - dbg_printk(TPACPI_DBG_EXIT, - "%s: remove_proc_entry\n", ibm->name); - remove_proc_entry(ibm->name, proc_dir); - ibm->flags.proc_created = 0; - } - - if (ibm->flags.acpi_driver_registered) { - dbg_printk(TPACPI_DBG_EXIT, - "%s: acpi_bus_unregister_driver\n", ibm->name); - BUG_ON(!ibm->acpi); - acpi_bus_unregister_driver(ibm->acpi->driver); - kfree(ibm->acpi->driver); - ibm->acpi->driver = NULL; - ibm->flags.acpi_driver_registered = 0; - } - - if (ibm->flags.init_called && ibm->exit) { - ibm->exit(); - ibm->flags.init_called = 0; - } - - dbg_printk(TPACPI_DBG_INIT, "finished removing %s\n", ibm->name); -} - /* Probing */ static void __init get_thinkpad_model_data(struct thinkpad_id_data *tp) @@ -5839,7 +5815,57 @@ IBM_PARAM(brightness); IBM_PARAM(volume); IBM_PARAM(fan); -static void thinkpad_acpi_module_exit(void); +static void thinkpad_acpi_module_exit(void) +{ + struct ibm_struct *ibm, *itmp; + + tpacpi_lifecycle = TPACPI_LIFE_EXITING; + + list_for_each_entry_safe_reverse(ibm, itmp, + &tpacpi_all_drivers, + all_drivers) { + ibm_exit(ibm); + } + + dbg_printk(TPACPI_DBG_INIT, "finished subdriver exit path...\n"); + + if (tpacpi_inputdev) { + if (tp_features.input_device_registered) + input_unregister_device(tpacpi_inputdev); + else + input_free_device(tpacpi_inputdev); + } + + if (tpacpi_hwmon) + hwmon_device_unregister(tpacpi_hwmon); + + if (tp_features.sensors_pdev_attrs_registered) + device_remove_file(&tpacpi_sensors_pdev->dev, + &dev_attr_thinkpad_acpi_pdev_name); + if (tpacpi_sensors_pdev) + platform_device_unregister(tpacpi_sensors_pdev); + if (tpacpi_pdev) + platform_device_unregister(tpacpi_pdev); + + if (tp_features.sensors_pdrv_attrs_registered) + tpacpi_remove_driver_attributes(&tpacpi_hwmon_pdriver.driver); + if (tp_features.platform_drv_attrs_registered) + tpacpi_remove_driver_attributes(&tpacpi_pdriver.driver); + + if (tp_features.sensors_pdrv_registered) + platform_driver_unregister(&tpacpi_hwmon_pdriver); + + if (tp_features.platform_drv_registered) + platform_driver_unregister(&tpacpi_pdriver); + + if (proc_dir) + remove_proc_entry(IBM_PROC_DIR, acpi_root_dir); + + kfree(thinkpad_id.bios_version_str); + kfree(thinkpad_id.ec_version_str); + kfree(thinkpad_id.model_str); +} + static int __init thinkpad_acpi_module_init(void) { @@ -5978,56 +6004,5 @@ static int __init thinkpad_acpi_module_init(void) return 0; } -static void thinkpad_acpi_module_exit(void) -{ - struct ibm_struct *ibm, *itmp; - - tpacpi_lifecycle = TPACPI_LIFE_EXITING; - - list_for_each_entry_safe_reverse(ibm, itmp, - &tpacpi_all_drivers, - all_drivers) { - ibm_exit(ibm); - } - - dbg_printk(TPACPI_DBG_INIT, "finished subdriver exit path...\n"); - - if (tpacpi_inputdev) { - if (tp_features.input_device_registered) - input_unregister_device(tpacpi_inputdev); - else - input_free_device(tpacpi_inputdev); - } - - if (tpacpi_hwmon) - hwmon_device_unregister(tpacpi_hwmon); - - if (tp_features.sensors_pdev_attrs_registered) - device_remove_file(&tpacpi_sensors_pdev->dev, - &dev_attr_thinkpad_acpi_pdev_name); - if (tpacpi_sensors_pdev) - platform_device_unregister(tpacpi_sensors_pdev); - if (tpacpi_pdev) - platform_device_unregister(tpacpi_pdev); - - if (tp_features.sensors_pdrv_attrs_registered) - tpacpi_remove_driver_attributes(&tpacpi_hwmon_pdriver.driver); - if (tp_features.platform_drv_attrs_registered) - tpacpi_remove_driver_attributes(&tpacpi_pdriver.driver); - - if (tp_features.sensors_pdrv_registered) - platform_driver_unregister(&tpacpi_hwmon_pdriver); - - if (tp_features.platform_drv_registered) - platform_driver_unregister(&tpacpi_pdriver); - - if (proc_dir) - remove_proc_entry(IBM_PROC_DIR, acpi_root_dir); - - kfree(thinkpad_id.bios_version_str); - kfree(thinkpad_id.ec_version_str); - kfree(thinkpad_id.model_str); -} - module_init(thinkpad_acpi_module_init); module_exit(thinkpad_acpi_module_exit); -- cgit v1.2.3 From 4b45cc076bc1964352f4a603a18c511ac182b98f Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Tue, 8 Jan 2008 13:02:46 -0200 Subject: ACPI: thinkpad-acpi: spring cleanup part 4 Remove dead code, and anything in the old changelog that is not a thank you credit, or a key point to track down history. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 55 ++++---------------------------------------- 1 file changed, 4 insertions(+), 51 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index b6293a40132..45be8e5f935 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -26,6 +26,8 @@ /* * Changelog: + * 2007-10-20 changelog trimmed down + * * 2007-03-27 0.14 renamed to thinkpad_acpi and moved to * drivers/misc. * @@ -33,53 +35,16 @@ * changelog now lives in git commit history, and will * not be updated further in-file. * - * 2005-08-17 0.12 fix compilation on 2.6.13-rc kernels * 2005-03-17 0.11 support for 600e, 770x * thanks to Jamie Lentin - * support for 770e, G41 - * G40 and G41 don't have a thinklight - * temperatures no longer experimental - * experimental brightness control - * experimental volume control - * experimental fan enable/disable - * 2005-01-16 0.10 fix module loading on R30, R31 - * 2005-01-16 0.9 support for 570, R30, R31 - * ultrabay support on A22p, A3x - * limit arg for cmos, led, beep, drop experimental status - * more capable led control on A21e, A22p, T20-22, X20 - * experimental temperatures and fan speed - * experimental embedded controller register dump - * mark more functions as __init, drop incorrect __exit - * use MODULE_VERSION + * + * 2005-01-16 0.9 use MODULE_VERSION * thanks to Henrik Brix Andersen * fix parameter passing on module loading * thanks to Rusty Russell * thanks to Jim Radford * 2004-11-08 0.8 fix init error case, don't return from a macro * thanks to Chris Wright - * 2004-10-23 0.7 fix module loading on A21e, A22p, T20, T21, X20 - * fix led control on A21e - * 2004-10-19 0.6 use acpi_bus_register_driver() to claim HKEY device - * 2004-10-18 0.5 thinklight support on A21e, G40, R32, T20, T21, X20 - * proc file format changed - * video_switch command - * experimental cmos control - * experimental led control - * experimental acpi sounds - * 2004-09-16 0.4 support for module parameters - * hotkey mask can be prefixed by 0x - * video output switching - * video expansion control - * ultrabay eject support - * removed lcd brightness/on/off control, didn't work - * 2004-08-17 0.3 support for R40 - * lcd off, brightness control - * thinklight on/off - * 2004-08-14 0.2 support for T series, X20 - * bluetooth enable/disable - * hotkey events disabled by default - * removed fan control, currently useless - * 2004-08-09 0.1 initial release, support for X series */ #include @@ -314,8 +279,6 @@ struct thinkpad_id_data { }; static struct thinkpad_id_data thinkpad_id; -#define __unused __attribute__ ((unused)) - static enum { TPACPI_LIFE_INIT = 0, TPACPI_LIFE_RUNNING, @@ -451,16 +414,6 @@ static int acpi_evalf(acpi_handle handle, return success; } -static void __unused acpi_print_int(acpi_handle handle, char *method) -{ - int i; - - if (acpi_evalf(handle, &i, method, "d")) - printk(IBM_INFO "%s = 0x%x\n", method, i); - else - printk(IBM_ERR "error calling %s\n", method); -} - static int acpi_ec_read(int i, u8 * p) { int v; -- cgit v1.2.3 From f68080f86d8b43bf3ff4c309f1bc9aa4d3fdf735 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Tue, 8 Jan 2008 13:02:47 -0200 Subject: ACPI: thinkpad-acpi: module glue cleanups General cleanup of module glue: Do some code reordering, and add missing parameter help text. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 83 ++++++++++++++++++++++++++------------------ 1 file changed, 50 insertions(+), 33 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 45be8e5f935..be04f1c94d6 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -124,7 +124,6 @@ enum { * Main driver */ -/* Module */ #define IBM_NAME "thinkpad" #define IBM_DESC "ThinkPad ACPI Extras" #define IBM_FILE IBM_NAME "_acpi" @@ -138,37 +137,6 @@ enum { #define IBM_MAX_ACPI_ARGS 3 -MODULE_AUTHOR("Borislav Deianov, Henrique de Moraes Holschuh"); -MODULE_DESCRIPTION(IBM_DESC); -MODULE_VERSION(IBM_VERSION); -MODULE_LICENSE("GPL"); - -/* Please remove this in year 2009 */ -MODULE_ALIAS("ibm_acpi"); - -/* - * DMI matching for module autoloading - * - * See http://thinkwiki.org/wiki/List_of_DMI_IDs - * See http://thinkwiki.org/wiki/BIOS_Upgrade_Downloads - * - * Only models listed in thinkwiki will be supported, so add yours - * if it is not there yet. - */ -#define IBM_BIOS_MODULE_ALIAS(__type) \ - MODULE_ALIAS("dmi:bvnIBM:bvr" __type "ET??WW") - -/* Non-ancient thinkpads */ -MODULE_ALIAS("dmi:bvnIBM:*:svnIBM:*:pvrThinkPad*:rvnIBM:*"); -MODULE_ALIAS("dmi:bvnLENOVO:*:svnLENOVO:*:pvrThinkPad*:rvnLENOVO:*"); - -/* Ancient thinkpad BIOSes have to be identified by - * BIOS type or model number, and there are far less - * BIOS types than model numbers... */ -IBM_BIOS_MODULE_ALIAS("I[B,D,H,I,M,N,O,T,W,V,Y,Z]"); -IBM_BIOS_MODULE_ALIAS("1[0,3,6,8,A-G,I,K,M-P,S,T]"); -IBM_BIOS_MODULE_ALIAS("K[U,X-Z]"); - /* Debugging */ #define IBM_LOG IBM_FILE ": " #define IBM_ERR KERN_ERR IBM_LOG @@ -5734,21 +5702,39 @@ static int __init set_ibm_param(const char *val, struct kernel_param *kp) } module_param(experimental, int, 0); +MODULE_PARM_DESC(experimental, + "Enables experimental features when non-zero"); module_param_named(debug, dbg_level, uint, 0); +MODULE_PARM_DESC(debug, "Sets debug level bit-mask"); module_param(force_load, bool, 0); +MODULE_PARM_DESC(force_load, + "Attempts to load the driver even on a " + "mis-identified ThinkPad when true"); module_param_named(fan_control, fan_control_allowed, bool, 0); +MODULE_PARM_DESC(fan_control, + "Enables setting fan parameters features when true"); module_param_named(brightness_mode, brightness_mode, int, 0); +MODULE_PARM_DESC(brightness_mode, + "Selects brightness control strategy: " + "0=auto, 1=EC, 2=CMOS, 3=both"); module_param(brightness_enable, uint, 0); +MODULE_PARM_DESC(brightness_enable, + "Enables backlight control when 1, disables when 0"); module_param(hotkey_report_mode, uint, 0); +MODULE_PARM_DESC(hotkey_report_mode, + "used for backwards compatibility with userspace, " + "see documentation"); #define IBM_PARAM(feature) \ - module_param_call(feature, set_ibm_param, NULL, NULL, 0) + module_param_call(feature, set_ibm_param, NULL, NULL, 0); \ + MODULE_PARM_DESC(feature, "Simulates thinkpad-aci procfs command " \ + "at module load, see documentation") IBM_PARAM(hotkey); IBM_PARAM(bluetooth); @@ -5957,5 +5943,36 @@ static int __init thinkpad_acpi_module_init(void) return 0; } +/* Please remove this in year 2009 */ +MODULE_ALIAS("ibm_acpi"); + +/* + * DMI matching for module autoloading + * + * See http://thinkwiki.org/wiki/List_of_DMI_IDs + * See http://thinkwiki.org/wiki/BIOS_Upgrade_Downloads + * + * Only models listed in thinkwiki will be supported, so add yours + * if it is not there yet. + */ +#define IBM_BIOS_MODULE_ALIAS(__type) \ + MODULE_ALIAS("dmi:bvnIBM:bvr" __type "ET??WW") + +/* Non-ancient thinkpads */ +MODULE_ALIAS("dmi:bvnIBM:*:svnIBM:*:pvrThinkPad*:rvnIBM:*"); +MODULE_ALIAS("dmi:bvnLENOVO:*:svnLENOVO:*:pvrThinkPad*:rvnLENOVO:*"); + +/* Ancient thinkpad BIOSes have to be identified by + * BIOS type or model number, and there are far less + * BIOS types than model numbers... */ +IBM_BIOS_MODULE_ALIAS("I[B,D,H,I,M,N,O,T,W,V,Y,Z]"); +IBM_BIOS_MODULE_ALIAS("1[0,3,6,8,A-G,I,K,M-P,S,T]"); +IBM_BIOS_MODULE_ALIAS("K[U,X-Z]"); + +MODULE_AUTHOR("Borislav Deianov, Henrique de Moraes Holschuh"); +MODULE_DESCRIPTION(IBM_DESC); +MODULE_VERSION(IBM_VERSION); +MODULE_LICENSE("GPL"); + module_init(thinkpad_acpi_module_init); module_exit(thinkpad_acpi_module_exit); -- cgit v1.2.3 From e0c7dfe70170ccee2b538494f92e61de8edab990 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Tue, 8 Jan 2008 13:02:48 -0200 Subject: ACPI: thinkpad-acpi: rename IBM in defines Rename defines with IBM in their name that are related to the older driver name (ibm-acpi) to TPACPI, unless they are specific to IBM ThinkPads. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 324 +++++++++++++++++++++---------------------- 1 file changed, 162 insertions(+), 162 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index be04f1c94d6..c92ae8d92b2 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -21,7 +21,7 @@ * 02110-1301, USA. */ -#define IBM_VERSION "0.18" +#define TPACPI_VERSION "0.18" #define TPACPI_SYSFS_VERSION 0x020101 /* @@ -113,7 +113,7 @@ enum { }; /* ACPI HIDs */ -#define IBM_HKEY_HID "IBM0068" +#define TPACPI_ACPI_HKEY_HID "IBM0068" /* Input IDs */ #define TPACPI_HKEY_INPUT_PRODUCT 0x5054 /* "TP" */ @@ -124,25 +124,25 @@ enum { * Main driver */ -#define IBM_NAME "thinkpad" -#define IBM_DESC "ThinkPad ACPI Extras" -#define IBM_FILE IBM_NAME "_acpi" -#define IBM_URL "http://ibm-acpi.sf.net/" -#define IBM_MAIL "ibm-acpi-devel@lists.sourceforge.net" +#define TPACPI_NAME "thinkpad" +#define TPACPI_DESC "ThinkPad ACPI Extras" +#define TPACPI_FILE TPACPI_NAME "_acpi" +#define TPACPI_URL "http://ibm-acpi.sf.net/" +#define TPACPI_MAIL "ibm-acpi-devel@lists.sourceforge.net" -#define IBM_PROC_DIR "ibm" -#define IBM_ACPI_EVENT_PREFIX "ibm" -#define IBM_DRVR_NAME IBM_FILE -#define IBM_HWMON_DRVR_NAME IBM_NAME "_hwmon" +#define TPACPI_PROC_DIR "ibm" +#define TPACPI_ACPI_EVENT_PREFIX "ibm" +#define TPACPI_DRVR_NAME TPACPI_FILE +#define TPACPI_HWMON_DRVR_NAME TPACPI_NAME "_hwmon" -#define IBM_MAX_ACPI_ARGS 3 +#define TPACPI_MAX_ACPI_ARGS 3 /* Debugging */ -#define IBM_LOG IBM_FILE ": " -#define IBM_ERR KERN_ERR IBM_LOG -#define IBM_NOTICE KERN_NOTICE IBM_LOG -#define IBM_INFO KERN_INFO IBM_LOG -#define IBM_DEBUG KERN_DEBUG IBM_LOG +#define TPACPI_LOG TPACPI_FILE ": " +#define TPACPI_ERR KERN_ERR TPACPI_LOG +#define TPACPI_NOTICE KERN_NOTICE TPACPI_LOG +#define TPACPI_INFO KERN_INFO TPACPI_LOG +#define TPACPI_DEBUG KERN_DEBUG TPACPI_LOG #define TPACPI_DBG_ALL 0xffff #define TPACPI_DBG_ALL 0xffff @@ -150,7 +150,7 @@ enum { #define TPACPI_DBG_EXIT 0x0002 #define dbg_printk(a_dbg_level, format, arg...) \ do { if (dbg_level & a_dbg_level) \ - printk(IBM_DEBUG "%s: " format, __func__ , ## arg); } while (0) + printk(TPACPI_DEBUG "%s: " format, __func__ , ## arg); } while (0) #ifdef CONFIG_THINKPAD_ACPI_DEBUG #define vdbg_printk(a_dbg_level, format, arg...) \ dbg_printk(a_dbg_level, format, ## arg) @@ -270,13 +270,13 @@ static u32 dbg_level; static acpi_handle root_handle; -#define IBM_HANDLE(object, parent, paths...) \ +#define TPACPI_HANDLE(object, parent, paths...) \ static acpi_handle object##_handle; \ static acpi_handle *object##_parent = &parent##_handle; \ static char *object##_path; \ static char *object##_paths[] = { paths } -IBM_HANDLE(ec, root, "\\_SB.PCI0.ISA.EC0", /* 240, 240x */ +TPACPI_HANDLE(ec, root, "\\_SB.PCI0.ISA.EC0", /* 240, 240x */ "\\_SB.PCI.ISA.EC", /* 570 */ "\\_SB.PCI0.ISA0.EC0", /* 600e/x, 770e, 770x */ "\\_SB.PCI0.ISA.EC", /* A21e, A2xm/p, T20-22, X20-21 */ @@ -285,15 +285,15 @@ IBM_HANDLE(ec, root, "\\_SB.PCI0.ISA.EC0", /* 240, 240x */ "\\_SB.PCI0.LPC.EC", /* all others */ ); -IBM_HANDLE(ecrd, ec, "ECRD"); /* 570 */ -IBM_HANDLE(ecwr, ec, "ECWR"); /* 570 */ +TPACPI_HANDLE(ecrd, ec, "ECRD"); /* 570 */ +TPACPI_HANDLE(ecwr, ec, "ECWR"); /* 570 */ -IBM_HANDLE(cmos, root, "\\UCMS", /* R50, R50e, R50p, R51, T4x, X31, X40 */ +TPACPI_HANDLE(cmos, root, "\\UCMS", /* R50, R50e, R50p, R51, T4x, X31, X40 */ "\\CMOS", /* A3x, G4x, R32, T23, T30, X22-24, X30 */ "\\CMS", /* R40, R40e */ ); /* all others */ -IBM_HANDLE(hkey, ec, "\\_SB.HKEY", /* 600e/x, 770e, 770x */ +TPACPI_HANDLE(hkey, ec, "\\_SB.HKEY", /* 600e/x, 770e, 770x */ "^HKEY", /* R30, R31 */ "HKEY", /* all others */ ); /* 570 */ @@ -308,7 +308,7 @@ static int acpi_evalf(acpi_handle handle, { char *fmt0 = fmt; struct acpi_object_list params; - union acpi_object in_objs[IBM_MAX_ACPI_ARGS]; + union acpi_object in_objs[TPACPI_MAX_ACPI_ARGS]; struct acpi_buffer result, *resultp; union acpi_object out_obj; acpi_status status; @@ -318,7 +318,7 @@ static int acpi_evalf(acpi_handle handle, int quiet; if (!*fmt) { - printk(IBM_ERR "acpi_evalf() called with empty format\n"); + printk(TPACPI_ERR "acpi_evalf() called with empty format\n"); return 0; } @@ -343,7 +343,7 @@ static int acpi_evalf(acpi_handle handle, break; /* add more types as needed */ default: - printk(IBM_ERR "acpi_evalf() called " + printk(TPACPI_ERR "acpi_evalf() called " "with invalid format character '%c'\n", c); return 0; } @@ -370,13 +370,13 @@ static int acpi_evalf(acpi_handle handle, break; /* add more types as needed */ default: - printk(IBM_ERR "acpi_evalf() called " + printk(TPACPI_ERR "acpi_evalf() called " "with invalid format character '%c'\n", res_type); return 0; } if (!success && !quiet) - printk(IBM_ERR "acpi_evalf(%s, %s, ...) failed: %d\n", + printk(TPACPI_ERR "acpi_evalf(%s, %s, ...) failed: %d\n", method, fmt0, status); return success; @@ -436,7 +436,7 @@ static int issue_thinkpad_cmos_command(int cmos_cmd) * ACPI device model */ -#define IBM_ACPIHANDLE_INIT(object) \ +#define TPACPI_ACPIHANDLE_INIT(object) \ drv_acpi_handle_init(#object, &object##_handle, *object##_parent, \ object##_paths, ARRAY_SIZE(object##_paths), &object##_path) @@ -494,24 +494,24 @@ static int __init setup_acpi_notify(struct ibm_struct *ibm) rc = acpi_bus_get_device(*ibm->acpi->handle, &ibm->acpi->device); if (rc < 0) { - printk(IBM_ERR "acpi_bus_get_device(%s) failed: %d\n", + printk(TPACPI_ERR "acpi_bus_get_device(%s) failed: %d\n", ibm->name, rc); return -ENODEV; } acpi_driver_data(ibm->acpi->device) = ibm; sprintf(acpi_device_class(ibm->acpi->device), "%s/%s", - IBM_ACPI_EVENT_PREFIX, + TPACPI_ACPI_EVENT_PREFIX, ibm->name); status = acpi_install_notify_handler(*ibm->acpi->handle, ibm->acpi->type, dispatch_acpi_notify, ibm); if (ACPI_FAILURE(status)) { if (status == AE_ALREADY_EXISTS) { - printk(IBM_NOTICE "another device driver is already handling %s events\n", + printk(TPACPI_NOTICE "another device driver is already handling %s events\n", ibm->name); } else { - printk(IBM_ERR "acpi_install_notify_handler(%s) failed: %d\n", + printk(TPACPI_ERR "acpi_install_notify_handler(%s) failed: %d\n", ibm->name, status); } return -ENODEV; @@ -536,18 +536,18 @@ static int __init register_tpacpi_subdriver(struct ibm_struct *ibm) ibm->acpi->driver = kzalloc(sizeof(struct acpi_driver), GFP_KERNEL); if (!ibm->acpi->driver) { - printk(IBM_ERR "kzalloc(ibm->driver) failed\n"); + printk(TPACPI_ERR "kzalloc(ibm->driver) failed\n"); return -ENOMEM; } - sprintf(ibm->acpi->driver->name, "%s_%s", IBM_NAME, ibm->name); + sprintf(ibm->acpi->driver->name, "%s_%s", TPACPI_NAME, ibm->name); ibm->acpi->driver->ids = ibm->acpi->hid; ibm->acpi->driver->ops.add = &tpacpi_device_add; rc = acpi_bus_register_driver(ibm->acpi->driver); if (rc < 0) { - printk(IBM_ERR "acpi_bus_register_driver(%s) failed: %d\n", + printk(TPACPI_ERR "acpi_bus_register_driver(%s) failed: %d\n", ibm->name, rc); kfree(ibm->acpi->driver); ibm->acpi->driver = NULL; @@ -670,7 +670,7 @@ static int tpacpi_resume_handler(struct platform_device *pdev) static struct platform_driver tpacpi_pdriver = { .driver = { - .name = IBM_DRVR_NAME, + .name = TPACPI_DRVR_NAME, .owner = THIS_MODULE, }, .resume = tpacpi_resume_handler, @@ -678,7 +678,7 @@ static struct platform_driver tpacpi_pdriver = { static struct platform_driver tpacpi_hwmon_pdriver = { .driver = { - .name = IBM_HWMON_DRVR_NAME, + .name = TPACPI_HWMON_DRVR_NAME, .owner = THIS_MODULE, }, }; @@ -818,7 +818,7 @@ static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO, static ssize_t tpacpi_driver_version_show(struct device_driver *drv, char *buf) { - return snprintf(buf, PAGE_SIZE, "%s v%s\n", IBM_DESC, IBM_VERSION); + return snprintf(buf, PAGE_SIZE, "%s v%s\n", TPACPI_DESC, TPACPI_VERSION); } static DRIVER_ATTR(version, S_IRUGO, @@ -867,17 +867,17 @@ static void tpacpi_remove_driver_attributes(struct device_driver *drv) static int __init thinkpad_acpi_driver_init(struct ibm_init_struct *iibm) { - printk(IBM_INFO "%s v%s\n", IBM_DESC, IBM_VERSION); - printk(IBM_INFO "%s\n", IBM_URL); + printk(TPACPI_INFO "%s v%s\n", TPACPI_DESC, TPACPI_VERSION); + printk(TPACPI_INFO "%s\n", TPACPI_URL); - printk(IBM_INFO "ThinkPad BIOS %s, EC %s\n", + printk(TPACPI_INFO "ThinkPad BIOS %s, EC %s\n", (thinkpad_id.bios_version_str) ? thinkpad_id.bios_version_str : "unknown", (thinkpad_id.ec_version_str) ? thinkpad_id.ec_version_str : "unknown"); if (thinkpad_id.vendor && thinkpad_id.model_str) - printk(IBM_INFO "%s %s\n", + printk(TPACPI_INFO "%s %s\n", (thinkpad_id.vendor == PCI_VENDOR_ID_IBM) ? "IBM" : ((thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO) ? @@ -891,8 +891,8 @@ static int thinkpad_acpi_driver_read(char *p) { int len = 0; - len += sprintf(p + len, "driver:\t\t%s\n", IBM_DESC); - len += sprintf(p + len, "version:\t%s\n", IBM_VERSION); + len += sprintf(p + len, "driver:\t\t%s\n", TPACPI_DESC); + len += sprintf(p + len, "version:\t%s\n", TPACPI_VERSION); return len; } @@ -1073,7 +1073,7 @@ static int hotkey_mask_set(u32 mask) if (!hotkey_mask_get() && !rc && (hotkey_mask & ~hotkey_source_mask) != (mask & ~hotkey_source_mask)) { - printk(IBM_NOTICE + printk(TPACPI_NOTICE "requested hot key mask 0x%08x, but " "firmware forced it to 0x%08x\n", mask, hotkey_mask); @@ -1085,7 +1085,7 @@ static int hotkey_mask_set(u32 mask) HOTKEY_CONFIG_CRITICAL_END hotkey_mask_get(); if (hotkey_mask != mask) { - printk(IBM_NOTICE + printk(TPACPI_NOTICE "requested hot key mask 0x%08x, " "forced to 0x%08x (NVRAM poll mask is " "0x%08x): no firmware mask support\n", @@ -1352,10 +1352,10 @@ static void hotkey_poll_setup(int may_warn) (tpacpi_inputdev->users > 0 || hotkey_report_mode < 2)) { if (!tpacpi_hotkey_task) { tpacpi_hotkey_task = kthread_run(hotkey_kthread, - NULL, IBM_FILE "d"); + NULL, TPACPI_FILE "d"); if (IS_ERR(tpacpi_hotkey_task)) { tpacpi_hotkey_task = NULL; - printk(IBM_ERR "could not create kernel thread " + printk(TPACPI_ERR "could not create kernel thread " "for hotkey polling\n"); } } @@ -1363,7 +1363,7 @@ static void hotkey_poll_setup(int may_warn) hotkey_poll_stop_sync(); if (may_warn && hotkey_source_mask != 0 && hotkey_poll_freq == 0) { - printk(IBM_NOTICE "hot keys 0x%08x require polling, " + printk(TPACPI_NOTICE "hot keys 0x%08x require polling, " "which is currently disabled\n", hotkey_source_mask); } @@ -1777,7 +1777,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) BUG_ON(tpacpi_inputdev->open != NULL || tpacpi_inputdev->close != NULL); - IBM_ACPIHANDLE_INIT(hkey); + TPACPI_ACPIHANDLE_INIT(hkey); mutex_init(&hotkey_mutex); #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL @@ -1806,10 +1806,10 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) for HKEY interface version 0x100 */ if (acpi_evalf(hkey_handle, &hkeyv, "MHKV", "qd")) { if ((hkeyv >> 8) != 1) { - printk(IBM_ERR "unknown version of the " + printk(TPACPI_ERR "unknown version of the " "HKEY interface: 0x%x\n", hkeyv); - printk(IBM_ERR "please report this to %s\n", - IBM_MAIL); + printk(TPACPI_ERR "please report this to %s\n", + TPACPI_MAIL); } else { /* * MHKV 0x100 in A31, R40, R40e, @@ -1825,10 +1825,10 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) if (tp_features.hotkey_mask) { if (!acpi_evalf(hkey_handle, &hotkey_all_mask, "MHKA", "qd")) { - printk(IBM_ERR + printk(TPACPI_ERR "missing MHKA handler, " "please report this to %s\n", - IBM_MAIL); + TPACPI_MAIL); hotkey_all_mask = 0x080cU; /* FN+F12, FN+F4, FN+F3 */ } } @@ -1863,7 +1863,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) /* Not all thinkpads have a hardware radio switch */ if (!res && acpi_evalf(hkey_handle, &status, "WLSW", "qd")) { tp_features.hotkey_wlsw = 1; - printk(IBM_INFO + printk(TPACPI_INFO "radio switch found; radios are %s\n", enabled(status, 0)); res = add_to_attr_set(hotkey_dev_attributes, @@ -1882,7 +1882,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) hotkey_keycode_map = kmalloc(TPACPI_HOTKEY_MAP_SIZE, GFP_KERNEL); if (!hotkey_keycode_map) { - printk(IBM_ERR "failed to allocate memory for key map\n"); + printk(TPACPI_ERR "failed to allocate memory for key map\n"); return -ENOMEM; } @@ -1957,7 +1957,7 @@ static void hotkey_exit(void) /* no short-circuit boolean operator below! */ if ((hotkey_mask_set(hotkey_orig_mask) | hotkey_status_set(hotkey_orig_status)) != 0) - printk(IBM_ERR "failed to restore hot key mask to BIOS defaults\n"); + printk(TPACPI_ERR "failed to restore hot key mask to BIOS defaults\n"); } if (hotkey_dev_attributes) { @@ -1974,7 +1974,7 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) int ignore_acpi_ev; if (event != 0x80) { - printk(IBM_ERR "unknown HKEY notification event %d\n", event); + printk(TPACPI_ERR "unknown HKEY notification event %d\n", event); /* forward it to userspace, maybe it knows how to handle it */ acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class, ibm->acpi->device->dev.bus_id, @@ -1984,7 +1984,7 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) while (1) { if (!acpi_evalf(hkey_handle, &hkey, "MHKP", "d")) { - printk(IBM_ERR "failed to retrieve HKEY event\n"); + printk(TPACPI_ERR "failed to retrieve HKEY event\n"); return; } @@ -2008,7 +2008,7 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) ignore_acpi_ev = 1; } } else { - printk(IBM_ERR + printk(TPACPI_ERR "hotkey 0x%04x out of range for keyboard map\n", hkey); send_acpi_ev = 1; @@ -2019,7 +2019,7 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) /* we don't handle it through this path, just * eat up known LID events */ if (hkey != 0x5001 && hkey != 0x5002) { - printk(IBM_ERR + printk(TPACPI_ERR "unknown LID-related HKEY event: 0x%04x\n", hkey); send_acpi_ev = 1; @@ -2039,7 +2039,7 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) /* 0x2305 - T43 waking up due to bay lever eject while aslept */ /* case 3: ultra-bay related. maybe bay in dock? */ /* 0x3003 - T43 after wake up by bay lever eject (0x2305) */ - printk(IBM_NOTICE "unhandled HKEY event 0x%04x\n", hkey); + printk(TPACPI_NOTICE "unhandled HKEY event 0x%04x\n", hkey); send_acpi_ev = 1; } @@ -2060,7 +2060,7 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) static void hotkey_resume(void) { if (hotkey_mask_get()) - printk(IBM_ERR "error while trying to read hot key mask from firmware\n"); + printk(TPACPI_ERR "error while trying to read hot key mask from firmware\n"); tpacpi_input_send_radiosw(); #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL hotkey_poll_setup_safe(0); @@ -2145,7 +2145,7 @@ errexit: } static const struct acpi_device_id ibm_htk_device_ids[] = { - {IBM_HKEY_HID, 0}, + {TPACPI_ACPI_HKEY_HID, 0}, {"", 0}, }; @@ -2230,7 +2230,7 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm) vdbg_printk(TPACPI_DBG_INIT, "initializing bluetooth subdriver\n"); - IBM_ACPIHANDLE_INIT(hkey); + TPACPI_ACPIHANDLE_INIT(hkey); /* bluetooth not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p, G4x, R30, R31, R40e, R50e, T20-22, X20-21 */ @@ -2404,7 +2404,7 @@ static int __init wan_init(struct ibm_init_struct *iibm) vdbg_printk(TPACPI_DBG_INIT, "initializing wan subdriver\n"); - IBM_ACPIHANDLE_INIT(hkey); + TPACPI_ACPIHANDLE_INIT(hkey); tp_features.wan = hkey_handle && acpi_evalf(hkey_handle, &status, "GWAN", "qd"); @@ -2543,14 +2543,14 @@ static int video_orig_autosw; static int video_autosw_get(void); static int video_autosw_set(int enable); -IBM_HANDLE(vid, root, "\\_SB.PCI.AGP.VGA", /* 570 */ +TPACPI_HANDLE(vid, root, "\\_SB.PCI.AGP.VGA", /* 570 */ "\\_SB.PCI0.AGP0.VID0", /* 600e/x, 770x */ "\\_SB.PCI0.VID0", /* 770e */ "\\_SB.PCI0.VID", /* A21e, G4x, R50e, X30, X40 */ "\\_SB.PCI0.AGP.VID", /* all others */ ); /* R30, R31 */ -IBM_HANDLE(vid2, root, "\\_SB.PCI0.AGPB.VID"); /* G41 */ +TPACPI_HANDLE(vid2, root, "\\_SB.PCI0.AGPB.VID"); /* G41 */ static int __init video_init(struct ibm_init_struct *iibm) { @@ -2558,8 +2558,8 @@ static int __init video_init(struct ibm_init_struct *iibm) vdbg_printk(TPACPI_DBG_INIT, "initializing video subdriver\n"); - IBM_ACPIHANDLE_INIT(vid); - IBM_ACPIHANDLE_INIT(vid2); + TPACPI_ACPIHANDLE_INIT(vid); + TPACPI_ACPIHANDLE_INIT(vid2); if (vid2_handle && acpi_evalf(NULL, &ivga, "\\IVGA", "d") && ivga) /* G41, assume IVGA doesn't change */ @@ -2590,7 +2590,7 @@ static void video_exit(void) dbg_printk(TPACPI_DBG_EXIT, "restoring original video autoswitch mode\n"); if (video_autosw_set(video_orig_autosw)) - printk(IBM_ERR "error while trying to restore original " + printk(TPACPI_ERR "error while trying to restore original " "video autoswitch mode\n"); } @@ -2663,7 +2663,7 @@ static int video_outputsw_set(int status) res = acpi_evalf(vid_handle, NULL, "ASWT", "vdd", status * 0x100, 0); if (!autosw && video_autosw_set(autosw)) { - printk(IBM_ERR "video auto-switch left enabled due to error\n"); + printk(TPACPI_ERR "video auto-switch left enabled due to error\n"); return -EIO; } break; @@ -2732,7 +2732,7 @@ static int video_outputsw_cycle(void) return -ENOSYS; } if (!autosw && video_autosw_set(autosw)) { - printk(IBM_ERR "video auto-switch left enabled due to error\n"); + printk(TPACPI_ERR "video auto-switch left enabled due to error\n"); return -EIO; } @@ -2861,16 +2861,16 @@ static struct ibm_struct video_driver_data = { * Light (thinklight) subdriver */ -IBM_HANDLE(lght, root, "\\LGHT"); /* A21e, A2xm/p, T20-22, X20-21 */ -IBM_HANDLE(ledb, ec, "LEDB"); /* G4x */ +TPACPI_HANDLE(lght, root, "\\LGHT"); /* A21e, A2xm/p, T20-22, X20-21 */ +TPACPI_HANDLE(ledb, ec, "LEDB"); /* G4x */ static int __init light_init(struct ibm_init_struct *iibm) { vdbg_printk(TPACPI_DBG_INIT, "initializing light subdriver\n"); - IBM_ACPIHANDLE_INIT(ledb); - IBM_ACPIHANDLE_INIT(lght); - IBM_ACPIHANDLE_INIT(cmos); + TPACPI_ACPIHANDLE_INIT(ledb); + TPACPI_ACPIHANDLE_INIT(lght); + TPACPI_ACPIHANDLE_INIT(cmos); /* light not supported on 570, 600e/x, 770e, 770x, G4x, R30, R31 */ tp_features.light = (cmos_handle || lght_handle) && !ledb_handle; @@ -2952,14 +2952,14 @@ static void dock_notify(struct ibm_struct *ibm, u32 event); static int dock_read(char *p); static int dock_write(char *buf); -IBM_HANDLE(dock, root, "\\_SB.GDCK", /* X30, X31, X40 */ +TPACPI_HANDLE(dock, root, "\\_SB.GDCK", /* X30, X31, X40 */ "\\_SB.PCI0.DOCK", /* 600e/x,770e,770x,A2xm/p,T20-22,X20-21 */ "\\_SB.PCI0.PCI1.DOCK", /* all others */ "\\_SB.PCI.ISA.SLCE", /* 570 */ ); /* A21e,G4x,R30,R31,R32,R40,R40e,R50e */ /* don't list other alternatives as we install a notify handler on the 570 */ -IBM_HANDLE(pci, root, "\\_SB.PCI"); /* 570 */ +TPACPI_HANDLE(pci, root, "\\_SB.PCI"); /* 570 */ static const struct acpi_device_id ibm_pci_device_ids[] = { {PCI_ROOT_HID_STRING, 0}, @@ -3002,7 +3002,7 @@ static int __init dock_init(struct ibm_init_struct *iibm) { vdbg_printk(TPACPI_DBG_INIT, "initializing dock subdriver\n"); - IBM_ACPIHANDLE_INIT(dock); + TPACPI_ACPIHANDLE_INIT(dock); vdbg_printk(TPACPI_DBG_INIT, "dock is %s\n", str_supported(dock_handle != NULL)); @@ -3018,7 +3018,7 @@ static int __init dock_init2(struct ibm_init_struct *iibm) if (dock_driver_data[0].flags.acpi_driver_registered && dock_driver_data[0].flags.acpi_notify_installed) { - IBM_ACPIHANDLE_INIT(pci); + TPACPI_ACPIHANDLE_INIT(pci); dock2_needed = (pci_handle != NULL); vdbg_printk(TPACPI_DBG_INIT, "dock PCI handler for the TP 570 is %s\n", @@ -3050,7 +3050,7 @@ static void dock_notify(struct ibm_struct *ibm, u32 event) else if (event == 0 && docked) data = 3; /* dock */ else { - printk(IBM_ERR "unknown dock event %d, status %d\n", + printk(TPACPI_ERR "unknown dock event %d, status %d\n", event, _sta(dock_handle)); data = 0; /* unknown */ } @@ -3107,18 +3107,18 @@ static int dock_write(char *buf) #ifdef CONFIG_THINKPAD_ACPI_BAY -IBM_HANDLE(bay, root, "\\_SB.PCI.IDE.SECN.MAST", /* 570 */ +TPACPI_HANDLE(bay, root, "\\_SB.PCI.IDE.SECN.MAST", /* 570 */ "\\_SB.PCI0.IDE0.IDES.IDSM", /* 600e/x, 770e, 770x */ "\\_SB.PCI0.SATA.SCND.MSTR", /* T60, X60, Z60 */ "\\_SB.PCI0.IDE0.SCND.MSTR", /* all others */ ); /* A21e, R30, R31 */ -IBM_HANDLE(bay_ej, bay, "_EJ3", /* 600e/x, A2xm/p, A3x */ +TPACPI_HANDLE(bay_ej, bay, "_EJ3", /* 600e/x, A2xm/p, A3x */ "_EJ0", /* all others */ ); /* 570,A21e,G4x,R30,R31,R32,R40e,R50e */ -IBM_HANDLE(bay2, root, "\\_SB.PCI0.IDE0.PRIM.SLAV", /* A3x, R32 */ +TPACPI_HANDLE(bay2, root, "\\_SB.PCI0.IDE0.PRIM.SLAV", /* A3x, R32 */ "\\_SB.PCI0.IDE0.IDEP.IDPS", /* 600e/x, 770e, 770x */ ); /* all others */ -IBM_HANDLE(bay2_ej, bay2, "_EJ3", /* 600e/x, 770e, A3x */ +TPACPI_HANDLE(bay2_ej, bay2, "_EJ3", /* 600e/x, 770e, A3x */ "_EJ0", /* 770x */ ); /* all others */ @@ -3126,12 +3126,12 @@ static int __init bay_init(struct ibm_init_struct *iibm) { vdbg_printk(TPACPI_DBG_INIT, "initializing bay subdriver\n"); - IBM_ACPIHANDLE_INIT(bay); + TPACPI_ACPIHANDLE_INIT(bay); if (bay_handle) - IBM_ACPIHANDLE_INIT(bay_ej); - IBM_ACPIHANDLE_INIT(bay2); + TPACPI_ACPIHANDLE_INIT(bay_ej); + TPACPI_ACPIHANDLE_INIT(bay2); if (bay2_handle) - IBM_ACPIHANDLE_INIT(bay2_ej); + TPACPI_ACPIHANDLE_INIT(bay2_ej); tp_features.bay_status = bay_handle && acpi_evalf(bay_handle, NULL, "_STA", "qv"); @@ -3260,7 +3260,7 @@ static int __init cmos_init(struct ibm_init_struct *iibm) vdbg_printk(TPACPI_DBG_INIT, "initializing cmos commands subdriver\n"); - IBM_ACPIHANDLE_INIT(cmos); + TPACPI_ACPIHANDLE_INIT(cmos); vdbg_printk(TPACPI_DBG_INIT, "cmos commands are %s\n", str_supported(cmos_handle != NULL)); @@ -3339,7 +3339,7 @@ enum { /* For TPACPI_LED_OLD */ static enum led_access_mode led_supported; -IBM_HANDLE(led, ec, "SLED", /* 570 */ +TPACPI_HANDLE(led, ec, "SLED", /* 570 */ "SYSL", /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */ "LED", /* all others */ ); /* R30, R31 */ @@ -3348,7 +3348,7 @@ static int __init led_init(struct ibm_init_struct *iibm) { vdbg_printk(TPACPI_DBG_INIT, "initializing LED subdriver\n"); - IBM_ACPIHANDLE_INIT(led); + TPACPI_ACPIHANDLE_INIT(led); if (!led_handle) /* led not supported on R30, R31 */ @@ -3467,13 +3467,13 @@ static struct ibm_struct led_driver_data = { * Beep subdriver */ -IBM_HANDLE(beep, ec, "BEEP"); /* all except R30, R31 */ +TPACPI_HANDLE(beep, ec, "BEEP"); /* all except R30, R31 */ static int __init beep_init(struct ibm_init_struct *iibm) { vdbg_printk(TPACPI_DBG_INIT, "initializing beep subdriver\n"); - IBM_ACPIHANDLE_INIT(beep); + TPACPI_ACPIHANDLE_INIT(beep); vdbg_printk(TPACPI_DBG_INIT, "beep is %s\n", str_supported(beep_handle != NULL)); @@ -3745,12 +3745,12 @@ static int __init thermal_init(struct ibm_init_struct *iibm) if (ta1 == 0) { /* This is sheer paranoia, but we handle it anyway */ if (acpi_tmp7) { - printk(IBM_ERR + printk(TPACPI_ERR "ThinkPad ACPI EC access misbehaving, " "falling back to ACPI TMPx access mode\n"); thermal_read_mode = TPACPI_THERMAL_ACPI_TMP07; } else { - printk(IBM_ERR + printk(TPACPI_ERR "ThinkPad ACPI EC access misbehaving, " "disabling thermal sensors access\n"); thermal_read_mode = TPACPI_THERMAL_NONE; @@ -3953,7 +3953,7 @@ static int brightness_get(struct backlight_device *bd) } if (brightness_mode == 3 && lec != lcmos) { - printk(IBM_ERR + printk(TPACPI_ERR "CMOS NVRAM (%u) and EC (%u) do not agree " "on display brightness level\n", (unsigned int) lcmos, @@ -4035,8 +4035,8 @@ static int __init tpacpi_query_bcll_levels(acpi_handle handle) if (ACPI_SUCCESS(acpi_evaluate_object(handle, NULL, NULL, &buffer))) { obj = (union acpi_object *)buffer.pointer; if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) { - printk(IBM_ERR "Unknown BCLL data, " - "please report this to %s\n", IBM_MAIL); + printk(TPACPI_ERR "Unknown BCLL data, " + "please report this to %s\n", TPACPI_MAIL); rc = 0; } else { rc = obj->package.count; @@ -4074,7 +4074,7 @@ static int __init brightness_check_levels(void) void *found_node = NULL; if (!vid_handle) { - IBM_ACPIHANDLE_INIT(vid); + TPACPI_ACPIHANDLE_INIT(vid); } if (!vid_handle) return 0; @@ -4107,7 +4107,7 @@ static int __init brightness_check_std_acpi_support(void) void *found_node = NULL; if (!vid_handle) { - IBM_ACPIHANDLE_INIT(vid); + TPACPI_ACPIHANDLE_INIT(vid); } if (!vid_handle) return 0; @@ -4133,7 +4133,7 @@ static int __init brightness_init(struct ibm_init_struct *iibm) return 1; } else if (brightness_enable > 1) { if (brightness_check_std_acpi_support()) { - printk(IBM_NOTICE + printk(TPACPI_NOTICE "standard ACPI backlight interface available, not loading native one...\n"); return 1; } @@ -4161,13 +4161,13 @@ static int __init brightness_init(struct ibm_init_struct *iibm) return 1; if (tp_features.bright_16levels) - printk(IBM_INFO "detected a 16-level brightness capable ThinkPad\n"); + printk(TPACPI_INFO "detected a 16-level brightness capable ThinkPad\n"); ibm_backlight_device = backlight_device_register( TPACPI_BACKLIGHT_DEV_NAME, NULL, NULL, &ibm_backlight_data); if (IS_ERR(ibm_backlight_device)) { - printk(IBM_ERR "Could not register backlight device\n"); + printk(TPACPI_ERR "Could not register backlight device\n"); return PTR_ERR(ibm_backlight_device); } vdbg_printk(TPACPI_DBG_INIT, "brightness is supported\n"); @@ -4491,11 +4491,11 @@ static struct mutex fan_mutex; static void fan_watchdog_fire(struct work_struct *ignored); static DECLARE_DELAYED_WORK(fan_watchdog_task, fan_watchdog_fire); -IBM_HANDLE(fans, ec, "FANS"); /* X31, X40, X41 */ -IBM_HANDLE(gfan, ec, "GFAN", /* 570 */ +TPACPI_HANDLE(fans, ec, "FANS"); /* X31, X40, X41 */ +TPACPI_HANDLE(gfan, ec, "GFAN", /* 570 */ "\\FSPD", /* 600e/x, 770e, 770x */ ); /* all others */ -IBM_HANDLE(sfan, ec, "SFAN", /* 570 */ +TPACPI_HANDLE(sfan, ec, "SFAN", /* 570 */ "JFNS", /* 770x-JL */ ); /* all others */ @@ -4790,7 +4790,7 @@ static void fan_watchdog_reset(void) if (!schedule_delayed_work(&fan_watchdog_task, msecs_to_jiffies(fan_watchdog_maxinterval * 1000))) { - printk(IBM_ERR "failed to schedule the fan watchdog, " + printk(TPACPI_ERR "failed to schedule the fan watchdog, " "watchdog will not trigger\n"); } } else @@ -4804,10 +4804,10 @@ static void fan_watchdog_fire(struct work_struct *ignored) if (tpacpi_lifecycle != TPACPI_LIFE_RUNNING) return; - printk(IBM_NOTICE "fan watchdog: enabling fan\n"); + printk(TPACPI_NOTICE "fan watchdog: enabling fan\n"); rc = fan_set_enable(); if (rc < 0) { - printk(IBM_ERR "fan watchdog: error %d while enabling fan, " + printk(TPACPI_ERR "fan watchdog: error %d while enabling fan, " "will try again later...\n", -rc); /* reschedule for later */ fan_watchdog_reset(); @@ -5047,9 +5047,9 @@ static int __init fan_init(struct ibm_init_struct *iibm) tp_features.fan_ctrl_status_undef = 0; fan_control_desired_level = 7; - IBM_ACPIHANDLE_INIT(fans); - IBM_ACPIHANDLE_INIT(gfan); - IBM_ACPIHANDLE_INIT(sfan); + TPACPI_ACPIHANDLE_INIT(fans); + TPACPI_ACPIHANDLE_INIT(gfan); + TPACPI_ACPIHANDLE_INIT(sfan); if (gfan_handle) { /* 570, 600e/x, 770e, 770x */ @@ -5075,7 +5075,7 @@ static int __init fan_init(struct ibm_init_struct *iibm) case 0x3837: /* TP-78 */ case 0x3637: /* TP-76 */ case 0x3037: /* TP-70 */ - printk(IBM_NOTICE + printk(TPACPI_NOTICE "fan_init: initial fan status is " "unknown, assuming it is in auto " "mode\n"); @@ -5084,7 +5084,7 @@ static int __init fan_init(struct ibm_init_struct *iibm) } } } else { - printk(IBM_ERR + printk(TPACPI_ERR "ThinkPad ACPI EC access misbehaving, " "fan status and control unavailable\n"); return 1; @@ -5255,7 +5255,7 @@ static int fan_write_cmd_level(const char *cmd, int *rc) return 0; if ((*rc = fan_set_level_safe(level)) == -ENXIO) - printk(IBM_ERR "level command accepted for unsupported " + printk(TPACPI_ERR "level command accepted for unsupported " "access mode %d", fan_control_access_mode); return 1; @@ -5267,7 +5267,7 @@ static int fan_write_cmd_enable(const char *cmd, int *rc) return 0; if ((*rc = fan_set_enable()) == -ENXIO) - printk(IBM_ERR "enable command accepted for unsupported " + printk(TPACPI_ERR "enable command accepted for unsupported " "access mode %d", fan_control_access_mode); return 1; @@ -5279,7 +5279,7 @@ static int fan_write_cmd_disable(const char *cmd, int *rc) return 0; if ((*rc = fan_set_disable()) == -ENXIO) - printk(IBM_ERR "disable command accepted for unsupported " + printk(TPACPI_ERR "disable command accepted for unsupported " "access mode %d", fan_control_access_mode); return 1; @@ -5296,7 +5296,7 @@ static int fan_write_cmd_speed(const char *cmd, int *rc) return 0; if ((*rc = fan_set_speed(speed)) == -ENXIO) - printk(IBM_ERR "speed command accepted for unsupported " + printk(TPACPI_ERR "speed command accepted for unsupported " "access mode %d", fan_control_access_mode); return 1; @@ -5360,7 +5360,7 @@ static ssize_t thinkpad_acpi_pdev_name_show(struct device *dev, struct device_attribute *attr, char *buf) { - return snprintf(buf, PAGE_SIZE, "%s\n", IBM_NAME); + return snprintf(buf, PAGE_SIZE, "%s\n", TPACPI_NAME); } static struct device_attribute dev_attr_thinkpad_acpi_pdev_name = @@ -5464,7 +5464,7 @@ static int __init ibm_init(struct ibm_init_struct *iibm) if (ibm->acpi->notify) { ret = setup_acpi_notify(ibm); if (ret == -ENODEV) { - printk(IBM_NOTICE "disabling subdriver %s\n", + printk(TPACPI_NOTICE "disabling subdriver %s\n", ibm->name); ret = 0; goto err_out; @@ -5482,7 +5482,7 @@ static int __init ibm_init(struct ibm_init_struct *iibm) S_IFREG | S_IRUGO | S_IWUSR, proc_dir); if (!entry) { - printk(IBM_ERR "unable to create proc entry %s\n", + printk(TPACPI_ERR "unable to create proc entry %s\n", ibm->name); ret = -ENODEV; goto err_out; @@ -5577,10 +5577,10 @@ static int __init probe_for_thinkpad(void) is_thinkpad = (thinkpad_id.model_str != NULL); /* ec is required because many other handles are relative to it */ - IBM_ACPIHANDLE_INIT(ec); + TPACPI_ACPIHANDLE_INIT(ec); if (!ec_handle) { if (is_thinkpad) - printk(IBM_ERR + printk(TPACPI_ERR "Not yet supported ThinkPad detected!\n"); return -ENODEV; } @@ -5731,28 +5731,28 @@ MODULE_PARM_DESC(hotkey_report_mode, "used for backwards compatibility with userspace, " "see documentation"); -#define IBM_PARAM(feature) \ +#define TPACPI_PARAM(feature) \ module_param_call(feature, set_ibm_param, NULL, NULL, 0); \ MODULE_PARM_DESC(feature, "Simulates thinkpad-aci procfs command " \ "at module load, see documentation") -IBM_PARAM(hotkey); -IBM_PARAM(bluetooth); -IBM_PARAM(video); -IBM_PARAM(light); +TPACPI_PARAM(hotkey); +TPACPI_PARAM(bluetooth); +TPACPI_PARAM(video); +TPACPI_PARAM(light); #ifdef CONFIG_THINKPAD_ACPI_DOCK -IBM_PARAM(dock); +TPACPI_PARAM(dock); #endif #ifdef CONFIG_THINKPAD_ACPI_BAY -IBM_PARAM(bay); +TPACPI_PARAM(bay); #endif /* CONFIG_THINKPAD_ACPI_BAY */ -IBM_PARAM(cmos); -IBM_PARAM(led); -IBM_PARAM(beep); -IBM_PARAM(ecdump); -IBM_PARAM(brightness); -IBM_PARAM(volume); -IBM_PARAM(fan); +TPACPI_PARAM(cmos); +TPACPI_PARAM(led); +TPACPI_PARAM(beep); +TPACPI_PARAM(ecdump); +TPACPI_PARAM(brightness); +TPACPI_PARAM(volume); +TPACPI_PARAM(fan); static void thinkpad_acpi_module_exit(void) { @@ -5798,7 +5798,7 @@ static void thinkpad_acpi_module_exit(void) platform_driver_unregister(&tpacpi_pdriver); if (proc_dir) - remove_proc_entry(IBM_PROC_DIR, acpi_root_dir); + remove_proc_entry(TPACPI_PROC_DIR, acpi_root_dir); kfree(thinkpad_id.bios_version_str); kfree(thinkpad_id.ec_version_str); @@ -5827,12 +5827,12 @@ static int __init thinkpad_acpi_module_init(void) /* Driver initialization */ - IBM_ACPIHANDLE_INIT(ecrd); - IBM_ACPIHANDLE_INIT(ecwr); + TPACPI_ACPIHANDLE_INIT(ecrd); + TPACPI_ACPIHANDLE_INIT(ecwr); - proc_dir = proc_mkdir(IBM_PROC_DIR, acpi_root_dir); + proc_dir = proc_mkdir(TPACPI_PROC_DIR, acpi_root_dir); if (!proc_dir) { - printk(IBM_ERR "unable to create proc dir " IBM_PROC_DIR); + printk(TPACPI_ERR "unable to create proc dir " TPACPI_PROC_DIR); thinkpad_acpi_module_exit(); return -ENODEV; } @@ -5840,7 +5840,7 @@ static int __init thinkpad_acpi_module_init(void) ret = platform_driver_register(&tpacpi_pdriver); if (ret) { - printk(IBM_ERR "unable to register main platform driver\n"); + printk(TPACPI_ERR "unable to register main platform driver\n"); thinkpad_acpi_module_exit(); return ret; } @@ -5848,7 +5848,7 @@ static int __init thinkpad_acpi_module_init(void) ret = platform_driver_register(&tpacpi_hwmon_pdriver); if (ret) { - printk(IBM_ERR "unable to register hwmon platform driver\n"); + printk(TPACPI_ERR "unable to register hwmon platform driver\n"); thinkpad_acpi_module_exit(); return ret; } @@ -5860,7 +5860,7 @@ static int __init thinkpad_acpi_module_init(void) ret = tpacpi_create_driver_attributes(&tpacpi_hwmon_pdriver.driver); } if (ret) { - printk(IBM_ERR "unable to create sysfs driver attributes\n"); + printk(TPACPI_ERR "unable to create sysfs driver attributes\n"); thinkpad_acpi_module_exit(); return ret; } @@ -5868,29 +5868,29 @@ static int __init thinkpad_acpi_module_init(void) /* Device initialization */ - tpacpi_pdev = platform_device_register_simple(IBM_DRVR_NAME, -1, + tpacpi_pdev = platform_device_register_simple(TPACPI_DRVR_NAME, -1, NULL, 0); if (IS_ERR(tpacpi_pdev)) { ret = PTR_ERR(tpacpi_pdev); tpacpi_pdev = NULL; - printk(IBM_ERR "unable to register platform device\n"); + printk(TPACPI_ERR "unable to register platform device\n"); thinkpad_acpi_module_exit(); return ret; } tpacpi_sensors_pdev = platform_device_register_simple( - IBM_HWMON_DRVR_NAME, + TPACPI_HWMON_DRVR_NAME, -1, NULL, 0); if (IS_ERR(tpacpi_sensors_pdev)) { ret = PTR_ERR(tpacpi_sensors_pdev); tpacpi_sensors_pdev = NULL; - printk(IBM_ERR "unable to register hwmon platform device\n"); + printk(TPACPI_ERR "unable to register hwmon platform device\n"); thinkpad_acpi_module_exit(); return ret; } ret = device_create_file(&tpacpi_sensors_pdev->dev, &dev_attr_thinkpad_acpi_pdev_name); if (ret) { - printk(IBM_ERR + printk(TPACPI_ERR "unable to create sysfs hwmon device attributes\n"); thinkpad_acpi_module_exit(); return ret; @@ -5900,20 +5900,20 @@ static int __init thinkpad_acpi_module_init(void) if (IS_ERR(tpacpi_hwmon)) { ret = PTR_ERR(tpacpi_hwmon); tpacpi_hwmon = NULL; - printk(IBM_ERR "unable to register hwmon device\n"); + printk(TPACPI_ERR "unable to register hwmon device\n"); thinkpad_acpi_module_exit(); return ret; } mutex_init(&tpacpi_inputdev_send_mutex); tpacpi_inputdev = input_allocate_device(); if (!tpacpi_inputdev) { - printk(IBM_ERR "unable to allocate input device\n"); + printk(TPACPI_ERR "unable to allocate input device\n"); thinkpad_acpi_module_exit(); return -ENOMEM; } else { /* Prepare input device, but don't register */ tpacpi_inputdev->name = "ThinkPad Extra Buttons"; - tpacpi_inputdev->phys = IBM_DRVR_NAME "/input0"; + tpacpi_inputdev->phys = TPACPI_DRVR_NAME "/input0"; tpacpi_inputdev->id.bustype = BUS_HOST; tpacpi_inputdev->id.vendor = (thinkpad_id.vendor) ? thinkpad_id.vendor : @@ -5932,7 +5932,7 @@ static int __init thinkpad_acpi_module_init(void) } ret = input_register_device(tpacpi_inputdev); if (ret < 0) { - printk(IBM_ERR "unable to register input device\n"); + printk(TPACPI_ERR "unable to register input device\n"); thinkpad_acpi_module_exit(); return ret; } else { @@ -5970,8 +5970,8 @@ IBM_BIOS_MODULE_ALIAS("1[0,3,6,8,A-G,I,K,M-P,S,T]"); IBM_BIOS_MODULE_ALIAS("K[U,X-Z]"); MODULE_AUTHOR("Borislav Deianov, Henrique de Moraes Holschuh"); -MODULE_DESCRIPTION(IBM_DESC); -MODULE_VERSION(IBM_VERSION); +MODULE_DESCRIPTION(TPACPI_DESC); +MODULE_VERSION(TPACPI_VERSION); MODULE_LICENSE("GPL"); module_init(thinkpad_acpi_module_init); -- cgit v1.2.3 From 35ff8b9fa90d97f3a19ea3e2311385927535ebc9 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Tue, 8 Jan 2008 13:02:49 -0200 Subject: ACPI: thinkpad-acpi: some checkpatch.pl fluff Fix some of the crap reported by checkpatch.pl. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 291 ++++++++++++++++++++++++++----------------- 1 file changed, 175 insertions(+), 116 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index c92ae8d92b2..dd6fa81fa86 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -150,7 +150,8 @@ enum { #define TPACPI_DBG_EXIT 0x0002 #define dbg_printk(a_dbg_level, format, arg...) \ do { if (dbg_level & a_dbg_level) \ - printk(TPACPI_DEBUG "%s: " format, __func__ , ## arg); } while (0) + printk(TPACPI_DEBUG "%s: " format, __func__ , ## arg); \ + } while (0) #ifdef CONFIG_THINKPAD_ACPI_DEBUG #define vdbg_printk(a_dbg_level, format, arg...) \ dbg_printk(a_dbg_level, format, ## arg) @@ -159,9 +160,9 @@ static const char *str_supported(int is_supported); #define vdbg_printk(a_dbg_level, format, arg...) #endif -#define onoff(status,bit) ((status) & (1 << (bit)) ? "on" : "off") -#define enabled(status,bit) ((status) & (1 << (bit)) ? "enabled" : "disabled") -#define strlencmp(a,b) (strncmp((a), (b), strlen(b))) +#define onoff(status, bit) ((status) & (1 << (bit)) ? "on" : "off") +#define enabled(status, bit) ((status) & (1 << (bit)) ? "enabled" : "disabled") +#define strlencmp(a, b) (strncmp((a), (b), strlen(b))) /**************************************************************************** @@ -288,7 +289,8 @@ TPACPI_HANDLE(ec, root, "\\_SB.PCI0.ISA.EC0", /* 240, 240x */ TPACPI_HANDLE(ecrd, ec, "ECRD"); /* 570 */ TPACPI_HANDLE(ecwr, ec, "ECWR"); /* 570 */ -TPACPI_HANDLE(cmos, root, "\\UCMS", /* R50, R50e, R50p, R51, T4x, X31, X40 */ +TPACPI_HANDLE(cmos, root, "\\UCMS", /* R50, R50e, R50p, R51, */ + /* T4x, X31, X40 */ "\\CMOS", /* A3x, G4x, R32, T23, T30, X22-24, X30 */ "\\CMS", /* R40, R40e */ ); /* all others */ @@ -382,7 +384,7 @@ static int acpi_evalf(acpi_handle handle, return success; } -static int acpi_ec_read(int i, u8 * p) +static int acpi_ec_read(int i, u8 *p) { int v; @@ -436,8 +438,8 @@ static int issue_thinkpad_cmos_command(int cmos_cmd) * ACPI device model */ -#define TPACPI_ACPIHANDLE_INIT(object) \ - drv_acpi_handle_init(#object, &object##_handle, *object##_parent, \ +#define TPACPI_ACPIHANDLE_INIT(object) \ + drv_acpi_handle_init(#object, &object##_handle, *object##_parent, \ object##_paths, ARRAY_SIZE(object##_paths), &object##_path) static void drv_acpi_handle_init(char *name, @@ -508,11 +510,13 @@ static int __init setup_acpi_notify(struct ibm_struct *ibm) ibm->acpi->type, dispatch_acpi_notify, ibm); if (ACPI_FAILURE(status)) { if (status == AE_ALREADY_EXISTS) { - printk(TPACPI_NOTICE "another device driver is already handling %s events\n", - ibm->name); + printk(TPACPI_NOTICE + "another device driver is already " + "handling %s events\n", ibm->name); } else { - printk(TPACPI_ERR "acpi_install_notify_handler(%s) failed: %d\n", - ibm->name, status); + printk(TPACPI_ERR + "acpi_install_notify_handler(%s) failed: %d\n", + ibm->name, status); } return -ENODEV; } @@ -592,7 +596,7 @@ static int dispatch_procfs_read(char *page, char **start, off_t off, } static int dispatch_procfs_write(struct file *file, - const char __user * userbuf, + const char __user *userbuf, unsigned long count, void *data) { struct ibm_struct *ibm = data; @@ -698,7 +702,7 @@ struct attribute_set_obj { } __attribute__((packed)); static struct attribute_set *create_attr_set(unsigned int max_members, - const char* name) + const char *name) { struct attribute_set_obj *sobj; @@ -722,7 +726,7 @@ static struct attribute_set *create_attr_set(unsigned int max_members, kfree(_set); /* not multi-threaded safe, use it in a single thread per set */ -static int add_to_attr_set(struct attribute_set* s, struct attribute *attr) +static int add_to_attr_set(struct attribute_set *s, struct attribute *attr) { if (!s || !attr) return -EINVAL; @@ -736,7 +740,7 @@ static int add_to_attr_set(struct attribute_set* s, struct attribute *attr) return 0; } -static int add_many_to_attr_set(struct attribute_set* s, +static int add_many_to_attr_set(struct attribute_set *s, struct attribute **attr, unsigned int count) { @@ -751,7 +755,7 @@ static int add_many_to_attr_set(struct attribute_set* s, return 0; } -static void delete_attr_set(struct attribute_set* s, struct kobject *kobj) +static void delete_attr_set(struct attribute_set *s, struct kobject *kobj) { sysfs_remove_group(kobj, &s->group); destroy_attr_set(s); @@ -818,7 +822,8 @@ static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO, static ssize_t tpacpi_driver_version_show(struct device_driver *drv, char *buf) { - return snprintf(buf, PAGE_SIZE, "%s v%s\n", TPACPI_DESC, TPACPI_VERSION); + return snprintf(buf, PAGE_SIZE, "%s v%s\n", + TPACPI_DESC, TPACPI_VERSION); } static DRIVER_ATTR(version, S_IRUGO, @@ -826,7 +831,7 @@ static DRIVER_ATTR(version, S_IRUGO, /* --------------------------------------------------------------------- */ -static struct driver_attribute* tpacpi_driver_attributes[] = { +static struct driver_attribute *tpacpi_driver_attributes[] = { &driver_attr_debug_level, &driver_attr_version, &driver_attr_interface_version, }; @@ -849,7 +854,7 @@ static void tpacpi_remove_driver_attributes(struct device_driver *drv) { int i; - for(i = 0; i < ARRAY_SIZE(tpacpi_driver_attributes); i++) + for (i = 0; i < ARRAY_SIZE(tpacpi_driver_attributes); i++) driver_remove_file(drv, tpacpi_driver_attributes[i]); } @@ -1010,8 +1015,10 @@ static struct attribute_set *hotkey_dev_attributes; #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL #define HOTKEY_CONFIG_CRITICAL_START \ - mutex_lock(&hotkey_thread_data_mutex); \ - hotkey_config_change++; + do { \ + mutex_lock(&hotkey_thread_data_mutex); \ + hotkey_config_change++; \ + } while (0); #define HOTKEY_CONFIG_CRITICAL_END \ mutex_unlock(&hotkey_thread_data_mutex); #else @@ -1205,15 +1212,18 @@ static void hotkey_read_nvram(struct tp_nvram_state *n, u32 m) } #define TPACPI_COMPARE_KEY(__scancode, __member) \ - do { if ((mask & (1 << __scancode)) && oldn->__member != newn->__member) \ - tpacpi_hotkey_send_key(__scancode); } while (0) + do { \ + if ((mask & (1 << __scancode)) && \ + oldn->__member != newn->__member) \ + tpacpi_hotkey_send_key(__scancode); \ + } while (0) #define TPACPI_MAY_SEND_KEY(__scancode) \ do { if (mask & (1 << __scancode)) \ tpacpi_hotkey_send_key(__scancode); } while (0) static void hotkey_compare_and_issue_event(struct tp_nvram_state *oldn, - struct tp_nvram_state *newn, + struct tp_nvram_state *newn, u32 mask) { TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_THINKPAD, thinkpad_toggle); @@ -1316,7 +1326,7 @@ static int hotkey_kthread(void *data) hotkey_read_nvram(&s[si], mask); if (likely(si != so)) { hotkey_compare_and_issue_event(&s[so], &s[si], - mask); + mask); } } @@ -1352,10 +1362,12 @@ static void hotkey_poll_setup(int may_warn) (tpacpi_inputdev->users > 0 || hotkey_report_mode < 2)) { if (!tpacpi_hotkey_task) { tpacpi_hotkey_task = kthread_run(hotkey_kthread, - NULL, TPACPI_FILE "d"); + NULL, + TPACPI_FILE "d"); if (IS_ERR(tpacpi_hotkey_task)) { tpacpi_hotkey_task = NULL; - printk(TPACPI_ERR "could not create kernel thread " + printk(TPACPI_ERR + "could not create kernel thread " "for hotkey polling\n"); } } @@ -1363,7 +1375,8 @@ static void hotkey_poll_setup(int may_warn) hotkey_poll_stop_sync(); if (may_warn && hotkey_source_mask != 0 && hotkey_poll_freq == 0) { - printk(TPACPI_NOTICE "hot keys 0x%08x require polling, " + printk(TPACPI_NOTICE + "hot keys 0x%08x require polling, " "which is currently disabled\n", hotkey_source_mask); } @@ -1829,7 +1842,8 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) "missing MHKA handler, " "please report this to %s\n", TPACPI_MAIL); - hotkey_all_mask = 0x080cU; /* FN+F12, FN+F4, FN+F3 */ + /* FN+F12, FN+F4, FN+F3 */ + hotkey_all_mask = 0x080cU; } } @@ -1882,7 +1896,8 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) hotkey_keycode_map = kmalloc(TPACPI_HOTKEY_MAP_SIZE, GFP_KERNEL); if (!hotkey_keycode_map) { - printk(TPACPI_ERR "failed to allocate memory for key map\n"); + printk(TPACPI_ERR + "failed to allocate memory for key map\n"); return -ENOMEM; } @@ -1953,11 +1968,14 @@ static void hotkey_exit(void) #endif if (tp_features.hotkey) { - dbg_printk(TPACPI_DBG_EXIT, "restoring original hot key mask\n"); + dbg_printk(TPACPI_DBG_EXIT, + "restoring original hot key mask\n"); /* no short-circuit boolean operator below! */ if ((hotkey_mask_set(hotkey_orig_mask) | hotkey_status_set(hotkey_orig_status)) != 0) - printk(TPACPI_ERR "failed to restore hot key mask to BIOS defaults\n"); + printk(TPACPI_ERR + "failed to restore hot key mask " + "to BIOS defaults\n"); } if (hotkey_dev_attributes) { @@ -1974,11 +1992,13 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) int ignore_acpi_ev; if (event != 0x80) { - printk(TPACPI_ERR "unknown HKEY notification event %d\n", event); + printk(TPACPI_ERR + "unknown HKEY notification event %d\n", event); /* forward it to userspace, maybe it knows how to handle it */ - acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class, - ibm->acpi->device->dev.bus_id, - event, 0); + acpi_bus_generate_netlink_event( + ibm->acpi->device->pnp.device_class, + ibm->acpi->device->dev.bus_id, + event, 0); return; } @@ -2009,8 +2029,8 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) } } else { printk(TPACPI_ERR - "hotkey 0x%04x out of range for keyboard map\n", - hkey); + "hotkey 0x%04x out of range " + "for keyboard map\n", hkey); send_acpi_ev = 1; } break; @@ -2020,8 +2040,8 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) * eat up known LID events */ if (hkey != 0x5001 && hkey != 0x5002) { printk(TPACPI_ERR - "unknown LID-related HKEY event: 0x%04x\n", - hkey); + "unknown LID-related HKEY event: " + "0x%04x\n", hkey); send_acpi_ev = 1; } else { ignore_acpi_ev = 1; @@ -2036,23 +2056,29 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) /* fallthrough to default */ default: /* case 2: dock-related */ - /* 0x2305 - T43 waking up due to bay lever eject while aslept */ + /* 0x2305 - T43 waking up due to bay lever + * eject while aslept */ /* case 3: ultra-bay related. maybe bay in dock? */ - /* 0x3003 - T43 after wake up by bay lever eject (0x2305) */ - printk(TPACPI_NOTICE "unhandled HKEY event 0x%04x\n", hkey); + /* 0x3003 - T43 after wake up by bay lever + * eject (0x2305) */ + printk(TPACPI_NOTICE + "unhandled HKEY event 0x%04x\n", hkey); send_acpi_ev = 1; } /* Legacy events */ - if (!ignore_acpi_ev && (send_acpi_ev || hotkey_report_mode < 2)) { - acpi_bus_generate_proc_event(ibm->acpi->device, event, hkey); + if (!ignore_acpi_ev && + (send_acpi_ev || hotkey_report_mode < 2)) { + acpi_bus_generate_proc_event(ibm->acpi->device, + event, hkey); } /* netlink events */ if (!ignore_acpi_ev && send_acpi_ev) { - acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class, - ibm->acpi->device->dev.bus_id, - event, hkey); + acpi_bus_generate_netlink_event( + ibm->acpi->device->pnp.device_class, + ibm->acpi->device->dev.bus_id, + event, hkey); } } } @@ -2060,7 +2086,9 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) static void hotkey_resume(void) { if (hotkey_mask_get()) - printk(TPACPI_ERR "error while trying to read hot key mask from firmware\n"); + printk(TPACPI_ERR + "error while trying to read hot key mask " + "from firmware\n"); tpacpi_input_send_radiosw(); #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL hotkey_poll_setup_safe(0); @@ -2663,13 +2691,14 @@ static int video_outputsw_set(int status) res = acpi_evalf(vid_handle, NULL, "ASWT", "vdd", status * 0x100, 0); if (!autosw && video_autosw_set(autosw)) { - printk(TPACPI_ERR "video auto-switch left enabled due to error\n"); + printk(TPACPI_ERR + "video auto-switch left enabled due to error\n"); return -EIO; } break; case TPACPI_VIDEO_NEW: res = acpi_evalf(NULL, NULL, "\\VUPS", "vd", 0x80) && - acpi_evalf(NULL, NULL, "\\VSDS", "vdd", status, 1); + acpi_evalf(NULL, NULL, "\\VSDS", "vdd", status, 1); break; default: return -ENOSYS; @@ -2732,7 +2761,8 @@ static int video_outputsw_cycle(void) return -ENOSYS; } if (!autosw && video_autosw_set(autosw)) { - printk(TPACPI_ERR "video auto-switch left enabled due to error\n"); + printk(TPACPI_ERR + "video auto-switch left enabled due to error\n"); return -EIO; } @@ -3340,7 +3370,8 @@ enum { /* For TPACPI_LED_OLD */ static enum led_access_mode led_supported; TPACPI_HANDLE(led, ec, "SLED", /* 570 */ - "SYSL", /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */ + "SYSL", /* 600e/x, 770e, 770x, A21e, A2xm/p, */ + /* T20-22, X20-21 */ "LED", /* all others */ ); /* R30, R31 */ @@ -3437,13 +3468,11 @@ static int led_write(char *buf) led = 1 << led; ret = ec_write(TPACPI_LED_EC_HLMS, led); if (ret >= 0) - ret = - ec_write(TPACPI_LED_EC_HLBL, - led * led_exp_hlbl[ind]); + ret = ec_write(TPACPI_LED_EC_HLBL, + led * led_exp_hlbl[ind]); if (ret >= 0) - ret = - ec_write(TPACPI_LED_EC_HLCL, - led * led_exp_hlcl[ind]); + ret = ec_write(TPACPI_LED_EC_HLCL, + led * led_exp_hlcl[ind]); if (ret < 0) return ret; } else { @@ -3620,7 +3649,7 @@ static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s) if (thermal_read_mode == TPACPI_THERMAL_TPEC_16) n = 16; - for(i = 0 ; i < n; i++) { + for (i = 0 ; i < n; i++) { res = thermal_get_sensor(i, &s->temp[i]); if (res) return res; @@ -3651,7 +3680,8 @@ static ssize_t thermal_temp_input_show(struct device *dev, } #define THERMAL_SENSOR_ATTR_TEMP(_idxA, _idxB) \ - SENSOR_ATTR(temp##_idxA##_input, S_IRUGO, thermal_temp_input_show, NULL, _idxB) + SENSOR_ATTR(temp##_idxA##_input, S_IRUGO, \ + thermal_temp_input_show, NULL, _idxB) static struct sensor_device_attribute sensor_dev_attr_thermal_temp_input[] = { THERMAL_SENSOR_ATTR_TEMP(1, 0), @@ -3747,7 +3777,8 @@ static int __init thermal_init(struct ibm_init_struct *iibm) if (acpi_tmp7) { printk(TPACPI_ERR "ThinkPad ACPI EC access misbehaving, " - "falling back to ACPI TMPx access mode\n"); + "falling back to ACPI TMPx access " + "mode\n"); thermal_read_mode = TPACPI_THERMAL_ACPI_TMP07; } else { printk(TPACPI_ERR @@ -3777,7 +3808,7 @@ static int __init thermal_init(struct ibm_init_struct *iibm) str_supported(thermal_read_mode != TPACPI_THERMAL_NONE), thermal_read_mode); - switch(thermal_read_mode) { + switch (thermal_read_mode) { case TPACPI_THERMAL_TPEC_16: res = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj, &thermal_temp_input16_group); @@ -3802,7 +3833,7 @@ static int __init thermal_init(struct ibm_init_struct *iibm) static void thermal_exit(void) { - switch(thermal_read_mode) { + switch (thermal_read_mode) { case TPACPI_THERMAL_TPEC_16: sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj, &thermal_temp_input16_group); @@ -4020,8 +4051,8 @@ static int brightness_update_status(struct backlight_device *bd) } static struct backlight_ops ibm_backlight_data = { - .get_brightness = brightness_get, - .update_status = brightness_update_status, + .get_brightness = brightness_get, + .update_status = brightness_update_status, }; /* --------------------------------------------------------------------- */ @@ -4081,7 +4112,8 @@ static int __init brightness_check_levels(void) /* Search for a BCLL package with 16 levels */ status = acpi_walk_namespace(ACPI_TYPE_PACKAGE, vid_handle, 3, - brightness_find_bcll, NULL, &found_node); + brightness_find_bcll, NULL, + &found_node); return (ACPI_SUCCESS(status) && found_node != NULL); } @@ -4114,7 +4146,7 @@ static int __init brightness_check_std_acpi_support(void) /* Search for a _BCL method, but don't execute it */ status = acpi_walk_namespace(ACPI_TYPE_METHOD, vid_handle, 3, - brightness_find_bcl, NULL, &found_node); + brightness_find_bcl, NULL, &found_node); return (ACPI_SUCCESS(status) && found_node != NULL); } @@ -4129,12 +4161,14 @@ static int __init brightness_init(struct ibm_init_struct *iibm) if (!brightness_enable) { dbg_printk(TPACPI_DBG_INIT, - "brightness support disabled by module parameter\n"); + "brightness support disabled by " + "module parameter\n"); return 1; } else if (brightness_enable > 1) { if (brightness_check_std_acpi_support()) { printk(TPACPI_NOTICE - "standard ACPI backlight interface available, not loading native one...\n"); + "standard ACPI backlight interface " + "available, not loading native one...\n"); return 1; } } @@ -4161,7 +4195,8 @@ static int __init brightness_init(struct ibm_init_struct *iibm) return 1; if (tp_features.bright_16levels) - printk(TPACPI_INFO "detected a 16-level brightness capable ThinkPad\n"); + printk(TPACPI_INFO + "detected a 16-level brightness capable ThinkPad\n"); ibm_backlight_device = backlight_device_register( TPACPI_BACKLIGHT_DEV_NAME, NULL, NULL, @@ -4195,7 +4230,8 @@ static int brightness_read(char *p) int len = 0; int level; - if ((level = brightness_get(NULL)) < 0) { + level = brightness_get(NULL); + if (level < 0) { len += sprintf(p + len, "level:\t\tunreadable\n"); } else { len += sprintf(p + len, "level:\t\t%d\n", level); @@ -4303,8 +4339,11 @@ static int volume_write(char *buf) } else return -EINVAL; - if (new_level != level) { /* mute doesn't change */ - cmos_cmd = new_level > level ? TP_CMOS_VOLUME_UP : TP_CMOS_VOLUME_DOWN; + if (new_level != level) { + /* mute doesn't change */ + + cmos_cmd = (new_level > level) ? + TP_CMOS_VOLUME_UP : TP_CMOS_VOLUME_DOWN; inc = new_level > level ? 1 : -1; if (mute && (issue_thinkpad_cmos_command(cmos_cmd) || @@ -4316,14 +4355,18 @@ static int volume_write(char *buf) !acpi_ec_write(volume_offset, i + inc)) return -EIO; - if (mute && (issue_thinkpad_cmos_command(TP_CMOS_VOLUME_MUTE) || - !acpi_ec_write(volume_offset, - new_level + mute))) + if (mute && + (issue_thinkpad_cmos_command(TP_CMOS_VOLUME_MUTE) || + !acpi_ec_write(volume_offset, new_level + mute))) { return -EIO; + } } - if (new_mute != mute) { /* level doesn't change */ - cmos_cmd = new_mute ? TP_CMOS_VOLUME_MUTE : TP_CMOS_VOLUME_UP; + if (new_mute != mute) { + /* level doesn't change */ + + cmos_cmd = (new_mute) ? + TP_CMOS_VOLUME_MUTE : TP_CMOS_VOLUME_UP; if (issue_thinkpad_cmos_command(cmos_cmd) || !acpi_ec_write(volume_offset, level + new_mute)) @@ -4694,7 +4737,7 @@ static int fan_set_enable(void) s |= 4; if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", s)) - rc= -EIO; + rc = -EIO; else rc = 0; break; @@ -4790,7 +4833,8 @@ static void fan_watchdog_reset(void) if (!schedule_delayed_work(&fan_watchdog_task, msecs_to_jiffies(fan_watchdog_maxinterval * 1000))) { - printk(TPACPI_ERR "failed to schedule the fan watchdog, " + printk(TPACPI_ERR + "failed to schedule the fan watchdog, " "watchdog will not trigger\n"); } } else @@ -5076,9 +5120,9 @@ static int __init fan_init(struct ibm_init_struct *iibm) case 0x3637: /* TP-76 */ case 0x3037: /* TP-70 */ printk(TPACPI_NOTICE - "fan_init: initial fan status is " - "unknown, assuming it is in auto " - "mode\n"); + "fan_init: initial fan status " + "is unknown, assuming it is " + "in auto mode\n"); tp_features.fan_ctrl_status_undef = 1; ;; } @@ -5151,11 +5195,13 @@ static int __init fan_init(struct ibm_init_struct *iibm) static void fan_exit(void) { - vdbg_printk(TPACPI_DBG_EXIT, "cancelling any pending fan watchdog tasks\n"); + vdbg_printk(TPACPI_DBG_EXIT, + "cancelling any pending fan watchdog tasks\n"); /* FIXME: can we really do this unconditionally? */ sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj, &fan_attr_group); - driver_remove_file(&tpacpi_hwmon_pdriver.driver, &driver_attr_fan_watchdog); + driver_remove_file(&tpacpi_hwmon_pdriver.driver, + &driver_attr_fan_watchdog); cancel_delayed_work(&fan_watchdog_task); flush_scheduled_work(); @@ -5171,7 +5217,8 @@ static int fan_read(char *p) switch (fan_status_access_mode) { case TPACPI_FAN_RD_ACPI_GFAN: /* 570, 600e/x, 770e, 770x */ - if ((rc = fan_get_status_safe(&status)) < 0) + rc = fan_get_status_safe(&status); + if (rc < 0) return rc; len += sprintf(p + len, "status:\t\t%s\n" @@ -5181,7 +5228,8 @@ static int fan_read(char *p) case TPACPI_FAN_RD_TPEC: /* all except 570, 600e/x, 770e, 770x */ - if ((rc = fan_get_status_safe(&status)) < 0) + rc = fan_get_status_safe(&status); + if (rc < 0) return rc; if (unlikely(tp_features.fan_ctrl_status_undef)) { @@ -5196,7 +5244,8 @@ static int fan_read(char *p) len += sprintf(p + len, "status:\t\t%s\n", (status != 0) ? "enabled" : "disabled"); - if ((rc = fan_get_speed(&speed)) < 0) + rc = fan_get_speed(&speed); + if (rc < 0) return rc; len += sprintf(p + len, "speed:\t\t%d\n", speed); @@ -5232,8 +5281,8 @@ static int fan_read(char *p) if (fan_control_commands & TPACPI_FAN_CMD_ENABLE) len += sprintf(p + len, "commands:\tenable, disable\n" - "commands:\twatchdog ( is 0 (off), " - "1-120 (seconds))\n"); + "commands:\twatchdog ( " + "is 0 (off), 1-120 (seconds))\n"); if (fan_control_commands & TPACPI_FAN_CMD_SPEED) len += sprintf(p + len, "commands:\tspeed " @@ -5249,12 +5298,13 @@ static int fan_write_cmd_level(const char *cmd, int *rc) if (strlencmp(cmd, "level auto") == 0) level = TP_EC_FAN_AUTO; else if ((strlencmp(cmd, "level disengaged") == 0) | - (strlencmp(cmd, "level full-speed") == 0)) + (strlencmp(cmd, "level full-speed") == 0)) level = TP_EC_FAN_FULLSPEED; else if (sscanf(cmd, "level %d", &level) != 1) return 0; - if ((*rc = fan_set_level_safe(level)) == -ENXIO) + *rc = fan_set_level_safe(level); + if (*rc == -ENXIO) printk(TPACPI_ERR "level command accepted for unsupported " "access mode %d", fan_control_access_mode); @@ -5266,7 +5316,8 @@ static int fan_write_cmd_enable(const char *cmd, int *rc) if (strlencmp(cmd, "enable") != 0) return 0; - if ((*rc = fan_set_enable()) == -ENXIO) + *rc = fan_set_enable(); + if (*rc == -ENXIO) printk(TPACPI_ERR "enable command accepted for unsupported " "access mode %d", fan_control_access_mode); @@ -5278,7 +5329,8 @@ static int fan_write_cmd_disable(const char *cmd, int *rc) if (strlencmp(cmd, "disable") != 0) return 0; - if ((*rc = fan_set_disable()) == -ENXIO) + *rc = fan_set_disable(); + if (*rc == -ENXIO) printk(TPACPI_ERR "disable command accepted for unsupported " "access mode %d", fan_control_access_mode); @@ -5295,7 +5347,8 @@ static int fan_write_cmd_speed(const char *cmd, int *rc) if (sscanf(cmd, "speed %d", &speed) != 1) return 0; - if ((*rc = fan_set_speed(speed)) == -ENXIO) + *rc = fan_set_speed(speed); + if (*rc == -ENXIO) printk(TPACPI_ERR "speed command accepted for unsupported " "access mode %d", fan_control_access_mode); @@ -5703,38 +5756,38 @@ static int __init set_ibm_param(const char *val, struct kernel_param *kp) module_param(experimental, int, 0); MODULE_PARM_DESC(experimental, - "Enables experimental features when non-zero"); + "Enables experimental features when non-zero"); module_param_named(debug, dbg_level, uint, 0); MODULE_PARM_DESC(debug, "Sets debug level bit-mask"); module_param(force_load, bool, 0); MODULE_PARM_DESC(force_load, - "Attempts to load the driver even on a " - "mis-identified ThinkPad when true"); + "Attempts to load the driver even on a " + "mis-identified ThinkPad when true"); module_param_named(fan_control, fan_control_allowed, bool, 0); MODULE_PARM_DESC(fan_control, - "Enables setting fan parameters features when true"); + "Enables setting fan parameters features when true"); module_param_named(brightness_mode, brightness_mode, int, 0); MODULE_PARM_DESC(brightness_mode, - "Selects brightness control strategy: " - "0=auto, 1=EC, 2=CMOS, 3=both"); + "Selects brightness control strategy: " + "0=auto, 1=EC, 2=CMOS, 3=both"); module_param(brightness_enable, uint, 0); MODULE_PARM_DESC(brightness_enable, - "Enables backlight control when 1, disables when 0"); + "Enables backlight control when 1, disables when 0"); module_param(hotkey_report_mode, uint, 0); MODULE_PARM_DESC(hotkey_report_mode, - "used for backwards compatibility with userspace, " - "see documentation"); + "used for backwards compatibility with userspace, " + "see documentation"); #define TPACPI_PARAM(feature) \ module_param_call(feature, set_ibm_param, NULL, NULL, 0); \ MODULE_PARM_DESC(feature, "Simulates thinkpad-aci procfs command " \ - "at module load, see documentation") + "at module load, see documentation") TPACPI_PARAM(hotkey); TPACPI_PARAM(bluetooth); @@ -5832,7 +5885,8 @@ static int __init thinkpad_acpi_module_init(void) proc_dir = proc_mkdir(TPACPI_PROC_DIR, acpi_root_dir); if (!proc_dir) { - printk(TPACPI_ERR "unable to create proc dir " TPACPI_PROC_DIR); + printk(TPACPI_ERR + "unable to create proc dir " TPACPI_PROC_DIR); thinkpad_acpi_module_exit(); return -ENODEV; } @@ -5840,7 +5894,8 @@ static int __init thinkpad_acpi_module_init(void) ret = platform_driver_register(&tpacpi_pdriver); if (ret) { - printk(TPACPI_ERR "unable to register main platform driver\n"); + printk(TPACPI_ERR + "unable to register main platform driver\n"); thinkpad_acpi_module_exit(); return ret; } @@ -5848,7 +5903,8 @@ static int __init thinkpad_acpi_module_init(void) ret = platform_driver_register(&tpacpi_hwmon_pdriver); if (ret) { - printk(TPACPI_ERR "unable to register hwmon platform driver\n"); + printk(TPACPI_ERR + "unable to register hwmon platform driver\n"); thinkpad_acpi_module_exit(); return ret; } @@ -5857,10 +5913,12 @@ static int __init thinkpad_acpi_module_init(void) ret = tpacpi_create_driver_attributes(&tpacpi_pdriver.driver); if (!ret) { tp_features.platform_drv_attrs_registered = 1; - ret = tpacpi_create_driver_attributes(&tpacpi_hwmon_pdriver.driver); + ret = tpacpi_create_driver_attributes( + &tpacpi_hwmon_pdriver.driver); } if (ret) { - printk(TPACPI_ERR "unable to create sysfs driver attributes\n"); + printk(TPACPI_ERR + "unable to create sysfs driver attributes\n"); thinkpad_acpi_module_exit(); return ret; } @@ -5878,12 +5936,13 @@ static int __init thinkpad_acpi_module_init(void) return ret; } tpacpi_sensors_pdev = platform_device_register_simple( - TPACPI_HWMON_DRVR_NAME, - -1, NULL, 0); + TPACPI_HWMON_DRVR_NAME, + -1, NULL, 0); if (IS_ERR(tpacpi_sensors_pdev)) { ret = PTR_ERR(tpacpi_sensors_pdev); tpacpi_sensors_pdev = NULL; - printk(TPACPI_ERR "unable to register hwmon platform device\n"); + printk(TPACPI_ERR + "unable to register hwmon platform device\n"); thinkpad_acpi_module_exit(); return ret; } @@ -5891,7 +5950,7 @@ static int __init thinkpad_acpi_module_init(void) &dev_attr_thinkpad_acpi_pdev_name); if (ret) { printk(TPACPI_ERR - "unable to create sysfs hwmon device attributes\n"); + "unable to create sysfs hwmon device attributes\n"); thinkpad_acpi_module_exit(); return ret; } -- cgit v1.2.3 From 083f17606f624c79555e313d87cf37ac1486b073 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Tue, 8 Jan 2008 13:02:50 -0200 Subject: ACPI: thinkpad-acpi: add suspend handler Add a handler for suspend events. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'drivers/misc') diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index dd6fa81fa86..c6c25a460c9 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -188,6 +188,7 @@ struct ibm_struct { int (*write) (char *); void (*exit) (void); void (*resume) (void); + void (*suspend) (pm_message_t state); struct list_head all_drivers; @@ -658,6 +659,21 @@ static struct input_dev *tpacpi_inputdev; static struct mutex tpacpi_inputdev_send_mutex; static LIST_HEAD(tpacpi_all_drivers); +static int tpacpi_suspend_handler(struct platform_device *pdev, + pm_message_t state) +{ + struct ibm_struct *ibm, *itmp; + + list_for_each_entry_safe(ibm, itmp, + &tpacpi_all_drivers, + all_drivers) { + if (ibm->suspend) + (ibm->suspend)(state); + } + + return 0; +} + static int tpacpi_resume_handler(struct platform_device *pdev) { struct ibm_struct *ibm, *itmp; @@ -677,6 +693,7 @@ static struct platform_driver tpacpi_pdriver = { .name = TPACPI_DRVR_NAME, .owner = THIS_MODULE, }, + .suspend = tpacpi_suspend_handler, .resume = tpacpi_resume_handler, }; -- cgit v1.2.3 From 3b64b51d20d9b633bb2efe63af785a49f8092898 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Tue, 8 Jan 2008 13:02:51 -0200 Subject: ACPI: thinkpad-acpi: cleanup hotkey_notify and HKEY log messages Use a generic message on hotkey_notify to log unknown and unhandled events, and cleanup hotkey_notify a little. Also, document event 0x5010 (brightness changed notification) and do not log it as an unknown event (even if we do not use it for anything right now). Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index c6c25a460c9..f5f306ae441 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -2007,6 +2007,7 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) unsigned int scancode; int send_acpi_ev; int ignore_acpi_ev; + int unk_ev; if (event != 0x80) { printk(TPACPI_ERR @@ -2030,8 +2031,9 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) return; } - send_acpi_ev = 0; + send_acpi_ev = 1; ignore_acpi_ev = 0; + unk_ev = 0; switch (hkey >> 12) { case 1: @@ -2041,33 +2043,34 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) scancode--; if (!(hotkey_source_mask & (1 << scancode))) { tpacpi_input_send_key(scancode); + send_acpi_ev = 0; } else { ignore_acpi_ev = 1; } } else { - printk(TPACPI_ERR - "hotkey 0x%04x out of range " - "for keyboard map\n", hkey); - send_acpi_ev = 1; + unk_ev = 1; } break; case 5: - /* 0x5000-0x5FFF: LID */ - /* we don't handle it through this path, just - * eat up known LID events */ - if (hkey != 0x5001 && hkey != 0x5002) { - printk(TPACPI_ERR - "unknown LID-related HKEY event: " - "0x%04x\n", hkey); - send_acpi_ev = 1; - } else { + /* 0x5000-0x5FFF: On screen display helpers */ + switch (hkey) { + case 0x5010: + /* Lenovo Vista BIOS: brightness changed */ + break; + case 0x5001: + case 0x5002: + /* LID switch events. Do not propagate */ ignore_acpi_ev = 1; + break; + default: + unk_ev = 1; } break; case 7: /* 0x7000-0x7FFF: misc */ if (tp_features.hotkey_wlsw && hkey == 0x7000) { tpacpi_input_send_radiosw(); + send_acpi_ev = 0; break; } /* fallthrough to default */ @@ -2078,9 +2081,11 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) /* case 3: ultra-bay related. maybe bay in dock? */ /* 0x3003 - T43 after wake up by bay lever * eject (0x2305) */ + unk_ev = 1; + } + if (unk_ev) { printk(TPACPI_NOTICE "unhandled HKEY event 0x%04x\n", hkey); - send_acpi_ev = 1; } /* Legacy events */ -- cgit v1.2.3 From a713b4d7bca51e56cdb5357507f46674111d032c Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Tue, 8 Jan 2008 13:02:52 -0200 Subject: ACPI: thinkpad-acpi: wakeup on hotunplug reporting Handle some HKEY events that the firmware uses to report the reason for a wake up, and to also notify that the system could go back to sleep (if it woke up just to eject something from the bay, or to undock). The driver will report the reason of the last wake up in the sysfs attribute "wakeup_reason": 0 for "none, unknown, or standard ACPI wake up event", 1 for "bay ejection request" and 2 for "undock request". The firmware will also report if the operation that triggered the wake up has been completed, by issuing an HKEY 0x3003 or 0x4003 event. If the operation fails, no event is sent. When such a hotunplug sucessfull notification is issued, the driver sets the attribute "wakeup_hotunplug_complete" to 1. While the firmware does tell us whether we are waking from a suspend or hibernation scenario, the Linux way of hibernating makes this information not reliable, and therefore it is not reported. The idea is that if any of these attributes are non-zero, userspace might want to do something at the end of the "wake up from sleep" procedures, such as offering to send the machine back into sleep as soon as it is safe to do so. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 91 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 84 insertions(+), 7 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index f5f306ae441..9b0235dc530 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -1018,6 +1018,14 @@ static unsigned int hotkey_config_change; static struct mutex hotkey_mutex; +static enum { /* Reasons for waking up */ + TP_ACPI_WAKEUP_NONE = 0, /* None or unknown */ + TP_ACPI_WAKEUP_BAYEJ, /* Bay ejection request */ + TP_ACPI_WAKEUP_UNDOCK, /* Undock request */ +} hotkey_wakeup_reason; + +static int hotkey_autosleep_ack; + static int hotkey_orig_status; static u32 hotkey_orig_mask; static u32 hotkey_all_mask; @@ -1661,6 +1669,29 @@ static ssize_t hotkey_report_mode_show(struct device *dev, static struct device_attribute dev_attr_hotkey_report_mode = __ATTR(hotkey_report_mode, S_IRUGO, hotkey_report_mode_show, NULL); +/* sysfs wakeup reason ------------------------------------------------- */ +static ssize_t hotkey_wakeup_reason_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", hotkey_wakeup_reason); +} + +static struct device_attribute dev_attr_hotkey_wakeup_reason = + __ATTR(wakeup_reason, S_IRUGO, hotkey_wakeup_reason_show, NULL); + +/* sysfs wakeup hotunplug_complete ------------------------------------- */ +static ssize_t hotkey_wakeup_hotunplug_complete_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", hotkey_autosleep_ack); +} + +static struct device_attribute dev_attr_hotkey_wakeup_hotunplug_complete = + __ATTR(wakeup_hotunplug_complete, S_IRUGO, + hotkey_wakeup_hotunplug_complete_show, NULL); + /* --------------------------------------------------------------------- */ static struct attribute *hotkey_attributes[] __initdata = { @@ -1683,6 +1714,8 @@ static struct attribute *hotkey_mask_attributes[] __initdata = { &dev_attr_hotkey_all_mask.attr, &dev_attr_hotkey_recommended_mask.attr, #endif + &dev_attr_hotkey_wakeup_reason.attr, + &dev_attr_hotkey_wakeup_hotunplug_complete.attr, }; static int __init hotkey_init(struct ibm_init_struct *iibm) @@ -1822,7 +1855,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) str_supported(tp_features.hotkey)); if (tp_features.hotkey) { - hotkey_dev_attributes = create_attr_set(10, NULL); + hotkey_dev_attributes = create_attr_set(12, NULL); if (!hotkey_dev_attributes) return -ENOMEM; res = add_many_to_attr_set(hotkey_dev_attributes, @@ -2051,6 +2084,48 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) unk_ev = 1; } break; + case 2: + /* Wakeup reason */ + switch (hkey) { + case 0x2304: /* suspend, undock */ + case 0x2404: /* hibernation, undock */ + hotkey_wakeup_reason = TP_ACPI_WAKEUP_UNDOCK; + ignore_acpi_ev = 1; + break; + case 0x2305: /* suspend, bay eject */ + case 0x2405: /* hibernation, bay eject */ + hotkey_wakeup_reason = TP_ACPI_WAKEUP_BAYEJ; + ignore_acpi_ev = 1; + break; + default: + unk_ev = 1; + } + if (hotkey_wakeup_reason != TP_ACPI_WAKEUP_NONE) { + printk(TPACPI_INFO + "woke up due to a hot-unplug " + "request...\n"); + } + break; + case 3: + /* bay-related wakeups */ + if (hkey == 0x3003) { + hotkey_autosleep_ack = 1; + printk(TPACPI_INFO + "bay ejected\n"); + } else { + unk_ev = 1; + } + break; + case 4: + /* dock-related wakeups */ + if (hkey == 0x4003) { + hotkey_autosleep_ack = 1; + printk(TPACPI_INFO + "undocked\n"); + } else { + unk_ev = 1; + } + break; case 5: /* 0x5000-0x5FFF: On screen display helpers */ switch (hkey) { @@ -2075,12 +2150,6 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) } /* fallthrough to default */ default: - /* case 2: dock-related */ - /* 0x2305 - T43 waking up due to bay lever - * eject while aslept */ - /* case 3: ultra-bay related. maybe bay in dock? */ - /* 0x3003 - T43 after wake up by bay lever - * eject (0x2305) */ unk_ev = 1; } if (unk_ev) { @@ -2105,6 +2174,13 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) } } +static void hotkey_suspend(pm_message_t state) +{ + /* Do these on suspend, we get the events on early resume! */ + hotkey_wakeup_reason = TP_ACPI_WAKEUP_NONE; + hotkey_autosleep_ack = 0; +} + static void hotkey_resume(void) { if (hotkey_mask_get()) @@ -2212,6 +2288,7 @@ static struct ibm_struct hotkey_driver_data = { .write = hotkey_write, .exit = hotkey_exit, .resume = hotkey_resume, + .suspend = hotkey_suspend, .acpi = &ibm_hotkey_acpidriver, }; -- cgit v1.2.3 From d1edb2b5f1d016d679600cccf2716e0134fff917 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Tue, 8 Jan 2008 13:02:53 -0200 Subject: ACPI: thinkpad-acpi: add X61t HKEY events Tomas Carnecky reports that events 0x5009 and 0x500a are swivel events, and that 0x500b/0x500c are tablet pen storage bay events. Document these events, and avoid nasty messages when they happen. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 9b0235dc530..049ec42c77b 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -2127,10 +2127,13 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) } break; case 5: - /* 0x5000-0x5FFF: On screen display helpers */ + /* 0x5000-0x5FFF: human interface helpers */ switch (hkey) { - case 0x5010: - /* Lenovo Vista BIOS: brightness changed */ + case 0x5010: /* Lenovo new BIOS: brightness changed */ + case 0x5009: /* X61t: swivel up (tablet mode) */ + case 0x500a: /* X61t: swivel down (normal mode) */ + case 0x500b: /* X61t: tablet pen inserted into bay */ + case 0x500c: /* X61t: tablet pen removed from bay */ break; case 0x5001: case 0x5002: -- cgit v1.2.3 From 013c40e457ac573b29daa0e369c2ba6729c23557 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Tue, 8 Jan 2008 13:02:54 -0200 Subject: ACPI: thinkpad-acpi: silence _sta warning When both CONFIG_THINKPAD_ACPI_DOCK and CONFIG_THINKPAD_ACPI_BAY are undefined, _sta is not used and that causes a gcc warning. Fix it (and I think this is a regression, I am pretty sure I fixed this once before, sorry about that). Issue reported by: Pritt Laes. Signed-off-by: Henrique de Moraes Holschuh Cc: Pritt Laes Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/misc') diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 049ec42c77b..e18f1e18781 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -414,6 +414,7 @@ static int acpi_ec_write(int i, u8 v) return 1; } +#if defined(CONFIG_THINKPAD_ACPI_DOCK) || defined(CONFIG_THINKPAD_ACPI_BAY) static int _sta(acpi_handle handle) { int status; @@ -423,6 +424,7 @@ static int _sta(acpi_handle handle) return status; } +#endif static int issue_thinkpad_cmos_command(int cmos_cmd) { -- cgit v1.2.3 From 50ebec09f1a79df27afeceb14a3059944f327e1d Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Tue, 8 Jan 2008 13:02:55 -0200 Subject: ACPI: thinkpad-acpi: add poll() support to some sysfs attributes Implement poll()/select() support through sysfs_notify() for some key attributes which userspace might want to poll() or select() on. In order to let userspace know poll()/select() support is available for an attribute, the thinkpad-acpi sysfs interface version is also bumped up. Further changes that add poll()/select() capabilities to any pre-existing attributes will also increment the sysfs interface version. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index e18f1e18781..91bda316a51 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -22,7 +22,7 @@ */ #define TPACPI_VERSION "0.18" -#define TPACPI_SYSFS_VERSION 0x020101 +#define TPACPI_SYSFS_VERSION 0x020200 /* * Changelog: @@ -1643,7 +1643,7 @@ static struct device_attribute dev_attr_hotkey_poll_freq = #endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ -/* sysfs hotkey radio_sw ----------------------------------------------- */ +/* sysfs hotkey radio_sw (pollable) ------------------------------------ */ static ssize_t hotkey_radio_sw_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -1659,6 +1659,13 @@ static ssize_t hotkey_radio_sw_show(struct device *dev, static struct device_attribute dev_attr_hotkey_radio_sw = __ATTR(hotkey_radio_sw, S_IRUGO, hotkey_radio_sw_show, NULL); +static void hotkey_radio_sw_notify_change(void) +{ + if (tp_features.hotkey_wlsw) + sysfs_notify(&tpacpi_pdev->dev.kobj, NULL, + "hotkey_radio_sw"); +} + /* sysfs hotkey report_mode -------------------------------------------- */ static ssize_t hotkey_report_mode_show(struct device *dev, struct device_attribute *attr, @@ -1671,7 +1678,7 @@ static ssize_t hotkey_report_mode_show(struct device *dev, static struct device_attribute dev_attr_hotkey_report_mode = __ATTR(hotkey_report_mode, S_IRUGO, hotkey_report_mode_show, NULL); -/* sysfs wakeup reason ------------------------------------------------- */ +/* sysfs wakeup reason (pollable) -------------------------------------- */ static ssize_t hotkey_wakeup_reason_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -1682,7 +1689,14 @@ static ssize_t hotkey_wakeup_reason_show(struct device *dev, static struct device_attribute dev_attr_hotkey_wakeup_reason = __ATTR(wakeup_reason, S_IRUGO, hotkey_wakeup_reason_show, NULL); -/* sysfs wakeup hotunplug_complete ------------------------------------- */ +void hotkey_wakeup_reason_notify_change(void) +{ + if (tp_features.hotkey_mask) + sysfs_notify(&tpacpi_pdev->dev.kobj, NULL, + "wakeup_reason"); +} + +/* sysfs wakeup hotunplug_complete (pollable) -------------------------- */ static ssize_t hotkey_wakeup_hotunplug_complete_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -1694,6 +1708,13 @@ static struct device_attribute dev_attr_hotkey_wakeup_hotunplug_complete = __ATTR(wakeup_hotunplug_complete, S_IRUGO, hotkey_wakeup_hotunplug_complete_show, NULL); +void hotkey_wakeup_hotunplug_complete_notify_change(void) +{ + if (tp_features.hotkey_mask) + sysfs_notify(&tpacpi_pdev->dev.kobj, NULL, + "wakeup_hotunplug_complete"); +} + /* --------------------------------------------------------------------- */ static struct attribute *hotkey_attributes[] __initdata = { @@ -2106,6 +2127,7 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) printk(TPACPI_INFO "woke up due to a hot-unplug " "request...\n"); + hotkey_wakeup_reason_notify_change(); } break; case 3: @@ -2114,6 +2136,7 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) hotkey_autosleep_ack = 1; printk(TPACPI_INFO "bay ejected\n"); + hotkey_wakeup_hotunplug_complete_notify_change(); } else { unk_ev = 1; } @@ -2124,6 +2147,7 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) hotkey_autosleep_ack = 1; printk(TPACPI_INFO "undocked\n"); + hotkey_wakeup_hotunplug_complete_notify_change(); } else { unk_ev = 1; } @@ -2150,6 +2174,7 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) /* 0x7000-0x7FFF: misc */ if (tp_features.hotkey_wlsw && hkey == 0x7000) { tpacpi_input_send_radiosw(); + hotkey_radio_sw_notify_change(); send_acpi_ev = 0; break; } @@ -2193,6 +2218,9 @@ static void hotkey_resume(void) "error while trying to read hot key mask " "from firmware\n"); tpacpi_input_send_radiosw(); + hotkey_radio_sw_notify_change(); + hotkey_wakeup_reason_notify_change(); + hotkey_wakeup_hotunplug_complete_notify_change(); #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL hotkey_poll_setup_safe(0); #endif -- cgit v1.2.3 From 6a2e293c34a41446c091cb18758cf64117021b72 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Tue, 8 Jan 2008 13:02:56 -0200 Subject: ACPI: thinkpad-acpi: update copyright dates to 2008 Update the copyright headers to include 2008. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/misc') diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 91bda316a51..05f5329c822 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -3,7 +3,7 @@ * * * Copyright (C) 2004-2005 Borislav Deianov - * Copyright (C) 2006-2007 Henrique de Moraes Holschuh + * Copyright (C) 2006-2008 Henrique de Moraes Holschuh * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by -- cgit v1.2.3 From 1cee5cce9776d88778b6c00e3f72fffbcbec40d4 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Tue, 8 Jan 2008 13:02:57 -0200 Subject: ACPI: thinkpad-acpi: bump up version to 0.19 The major code reorganization and cleanups, and new HKEY events, plus poll()/select() support are good reasons to checkpoint a new version... Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/misc') diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 05f5329c822..8ef0afc8869 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -21,7 +21,7 @@ * 02110-1301, USA. */ -#define TPACPI_VERSION "0.18" +#define TPACPI_VERSION "0.19" #define TPACPI_SYSFS_VERSION 0x020200 /* -- cgit v1.2.3 From cc0573b3250214034062ddf8c64359596d8af521 Mon Sep 17 00:00:00 2001 From: Thomas Sujith Date: Fri, 25 Jan 2008 11:45:44 +0800 Subject: intel_menlo: introduce new platform specific driver Intel menlow platform specific driver for thermal management extension. Signed-off-by: Thomas Sujith Signed-off-by: Zhang Rui Signed-off-by: Len Brown --- drivers/misc/Kconfig | 9 + drivers/misc/Makefile | 1 + drivers/misc/intel_menlow.c | 526 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 536 insertions(+) create mode 100644 drivers/misc/intel_menlow.c (limited to 'drivers/misc') diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index b5e67c0ff43..d1380a5a003 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -232,4 +232,13 @@ config ATMEL_SSC If unsure, say N. +config INTEL_MENLOW + tristate "Thermal Management driver for Intel menlow platform" + depends on ACPI_THERMAL + ---help--- + ACPI thermal management enhancement driver on + Intel Menlow platform. + + If unsure, say N. + endif # MISC_DEVICES diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 87f2685d728..a9e8faffc1b 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -17,3 +17,4 @@ obj-$(CONFIG_SONY_LAPTOP) += sony-laptop.o obj-$(CONFIG_THINKPAD_ACPI) += thinkpad_acpi.o obj-$(CONFIG_FUJITSU_LAPTOP) += fujitsu-laptop.o obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o +obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o diff --git a/drivers/misc/intel_menlow.c b/drivers/misc/intel_menlow.c new file mode 100644 index 00000000000..f70984ab1e1 --- /dev/null +++ b/drivers/misc/intel_menlow.c @@ -0,0 +1,526 @@ +/* + * intel_menlow.c - Intel menlow Driver for thermal management extension + * + * Copyright (C) 2008 Intel Corp + * Copyright (C) 2008 Sujith Thomas + * Copyright (C) 2008 Zhang Rui + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This driver creates the sys I/F for programming the sensors. + * It also implements the driver for intel menlow memory controller (hardware + * id is INT0002) which makes use of the platform specific ACPI methods + * to get/set bandwidth. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +MODULE_AUTHOR("Thomas Sujith"); +MODULE_AUTHOR("Zhang Rui"); +MODULE_DESCRIPTION("Intel Menlow platform specific driver"); +MODULE_LICENSE("GPL"); + +/* + * Memory controller device control + */ + +#define MEMORY_GET_BANDWIDTH "GTHS" +#define MEMORY_SET_BANDWIDTH "STHS" +#define MEMORY_ARG_CUR_BANDWIDTH 1 +#define MEMORY_ARG_MAX_BANDWIDTH 0 + +static int memory_get_int_max_bandwidth(struct thermal_cooling_device *cdev, + unsigned long *max_state) +{ + struct acpi_device *device = cdev->devdata; + acpi_handle handle = device->handle; + unsigned long value; + struct acpi_object_list arg_list; + union acpi_object arg; + acpi_status status = AE_OK; + + arg_list.count = 1; + arg_list.pointer = &arg; + arg.type = ACPI_TYPE_INTEGER; + arg.integer.value = MEMORY_ARG_MAX_BANDWIDTH; + status = acpi_evaluate_integer(handle, MEMORY_GET_BANDWIDTH, + &arg_list, &value); + if (ACPI_FAILURE(status)) + return -EFAULT; + + *max_state = value - 1; + return 0; +} + +static int memory_get_max_bandwidth(struct thermal_cooling_device *cdev, + char *buf) +{ + unsigned long value; + if (memory_get_int_max_bandwidth(cdev, &value)) + return -EINVAL; + + return sprintf(buf, "%ld\n", value); +} + +static int memory_get_cur_bandwidth(struct thermal_cooling_device *cdev, + char *buf) +{ + struct acpi_device *device = cdev->devdata; + acpi_handle handle = device->handle; + unsigned long value; + struct acpi_object_list arg_list; + union acpi_object arg; + acpi_status status = AE_OK; + + arg_list.count = 1; + arg_list.pointer = &arg; + arg.type = ACPI_TYPE_INTEGER; + arg.integer.value = MEMORY_ARG_CUR_BANDWIDTH; + status = acpi_evaluate_integer(handle, MEMORY_GET_BANDWIDTH, + &arg_list, &value); + if (ACPI_FAILURE(status)) + return -EFAULT; + + return sprintf(buf, "%ld\n", value); +} + +static int memory_set_cur_bandwidth(struct thermal_cooling_device *cdev, + unsigned int state) +{ + struct acpi_device *device = cdev->devdata; + acpi_handle handle = device->handle; + struct acpi_object_list arg_list; + union acpi_object arg; + acpi_status status; + int temp; + unsigned long max_state; + + if (memory_get_int_max_bandwidth(cdev, &max_state)) + return -EFAULT; + + if (max_state < 0 || state > max_state) + return -EINVAL; + + arg_list.count = 1; + arg_list.pointer = &arg; + arg.type = ACPI_TYPE_INTEGER; + arg.integer.value = state; + + status = + acpi_evaluate_integer(handle, MEMORY_SET_BANDWIDTH, &arg_list, + (unsigned long *)&temp); + + printk(KERN_INFO + "Bandwidth value was %d: status is %d\n", state, status); + if (ACPI_FAILURE(status)) + return -EFAULT; + + return 0; +} + +static struct thermal_cooling_device_ops memory_cooling_ops = { + .get_max_state = memory_get_max_bandwidth, + .get_cur_state = memory_get_cur_bandwidth, + .set_cur_state = memory_set_cur_bandwidth, +}; + +/* + * Memory Device Management + */ +static int intel_menlow_memory_add(struct acpi_device *device) +{ + int result = -ENODEV; + acpi_status status = AE_OK; + acpi_handle dummy; + struct thermal_cooling_device *cdev; + + if (!device) + return -EINVAL; + + status = acpi_get_handle(device->handle, MEMORY_GET_BANDWIDTH, &dummy); + if (ACPI_FAILURE(status)) + goto end; + + status = acpi_get_handle(device->handle, MEMORY_SET_BANDWIDTH, &dummy); + if (ACPI_FAILURE(status)) + goto end; + + cdev = thermal_cooling_device_register("Memory controller", device, + &memory_cooling_ops); + acpi_driver_data(device) = cdev; + if (!cdev) + result = -ENODEV; + else { + result = sysfs_create_link(&device->dev.kobj, + &cdev->device.kobj, "thermal_cooling"); + if (result) + goto unregister; + + result = sysfs_create_link(&cdev->device.kobj, + &device->dev.kobj, "device"); + if (result) { + sysfs_remove_link(&device->dev.kobj, "thermal_cooling"); + goto unregister; + } + } + + end: + return result; + + unregister: + thermal_cooling_device_unregister(cdev); + return result; + +} + +static int intel_menlow_memory_remove(struct acpi_device *device, int type) +{ + struct thermal_cooling_device *cdev = acpi_driver_data(device); + + if (!device || !cdev) + return -EINVAL; + + sysfs_remove_link(&device->dev.kobj, "thermal_cooling"); + sysfs_remove_link(&cdev->device.kobj, "device"); + thermal_cooling_device_unregister(cdev); + + return 0; +} + +const static struct acpi_device_id intel_menlow_memory_ids[] = { + {"INT0002", 0}, + {"", 0}, +}; + +static struct acpi_driver intel_menlow_memory_driver = { + .name = "intel_menlow_thermal_control", + .ids = intel_menlow_memory_ids, + .ops = { + .add = intel_menlow_memory_add, + .remove = intel_menlow_memory_remove, + }, +}; + +/* + * Sensor control on menlow platform + */ + +#define THERMAL_AUX0 0 +#define THERMAL_AUX1 1 +#define GET_AUX0 "GAX0" +#define GET_AUX1 "GAX1" +#define SET_AUX0 "SAX0" +#define SET_AUX1 "SAX1" + +struct intel_menlow_attribute { + struct device_attribute attr; + struct device *device; + acpi_handle handle; + struct list_head node; +}; + +static LIST_HEAD(intel_menlow_attr_list); +static DEFINE_MUTEX(intel_menlow_attr_lock); + +/* + * sensor_get_auxtrip - get the current auxtrip value from sensor + * @name: Thermalzone name + * @auxtype : AUX0/AUX1 + * @buf: syfs buffer + */ +static int sensor_get_auxtrip(acpi_handle handle, int index, int *value) +{ + acpi_status status; + + if ((index != 0 && index != 1) || !value) + return -EINVAL; + + status = acpi_evaluate_integer(handle, index ? GET_AUX1 : GET_AUX0, + NULL, (unsigned long *)value); + if (ACPI_FAILURE(status)) + return -EIO; + + return 0; +} + +/* + * sensor_set_auxtrip - set the new auxtrip value to sensor + * @name: Thermalzone name + * @auxtype : AUX0/AUX1 + * @buf: syfs buffer + */ +static int sensor_set_auxtrip(acpi_handle handle, int index, int value) +{ + acpi_status status; + union acpi_object arg = { + ACPI_TYPE_INTEGER + }; + struct acpi_object_list args = { + 1, &arg + }; + int temp; + + if (index != 0 && index != 1) + return -EINVAL; + + status = acpi_evaluate_integer(handle, index ? GET_AUX0 : GET_AUX1, + NULL, (unsigned long *)&temp); + if (ACPI_FAILURE(status)) + return -EIO; + if ((index && value < temp) || (!index && value > temp)) + return -EINVAL; + + arg.integer.value = value; + status = acpi_evaluate_integer(handle, index ? SET_AUX1 : SET_AUX0, + &args, (unsigned long *)&temp); + if (ACPI_FAILURE(status)) + return -EIO; + + /* do we need to check the return value of SAX0/SAX1 ? */ + + return 0; +} + +#define to_intel_menlow_attr(_attr) \ + container_of(_attr, struct intel_menlow_attribute, attr) + +static ssize_t aux0_show(struct device *dev, + struct device_attribute *dev_attr, char *buf) +{ + struct intel_menlow_attribute *attr = to_intel_menlow_attr(dev_attr); + int value; + int result; + + result = sensor_get_auxtrip(attr->handle, 0, &value); + + return result ? result : sprintf(buf, "%lu", KELVIN_TO_CELSIUS(value)); +} + +static ssize_t aux1_show(struct device *dev, + struct device_attribute *dev_attr, char *buf) +{ + struct intel_menlow_attribute *attr = to_intel_menlow_attr(dev_attr); + int value; + int result; + + result = sensor_get_auxtrip(attr->handle, 1, &value); + + return result ? result : sprintf(buf, "%lu", KELVIN_TO_CELSIUS(value)); +} + +static ssize_t aux0_store(struct device *dev, + struct device_attribute *dev_attr, + const char *buf, size_t count) +{ + struct intel_menlow_attribute *attr = to_intel_menlow_attr(dev_attr); + int value; + int result; + + /*Sanity check; should be a positive integer */ + if (!sscanf(buf, "%d", &value)) + return -EINVAL; + + if (value < 0) + return -EINVAL; + + result = sensor_set_auxtrip(attr->handle, 0, CELSIUS_TO_KELVIN(value)); + return result ? result : count; +} + +static ssize_t aux1_store(struct device *dev, + struct device_attribute *dev_attr, + const char *buf, size_t count) +{ + struct intel_menlow_attribute *attr = to_intel_menlow_attr(dev_attr); + int value; + int result; + + /*Sanity check; should be a positive integer */ + if (!sscanf(buf, "%d", &value)) + return -EINVAL; + + if (value < 0) + return -EINVAL; + + result = sensor_set_auxtrip(attr->handle, 1, CELSIUS_TO_KELVIN(value)); + return result ? result : count; +} + +/* BIOS can enable/disable the thermal user application in dabney platform */ +#define BIOS_ENABLED "\\_TZ.GSTS" +static ssize_t bios_enabled_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + acpi_status status; + unsigned long bios_enabled; + + status = acpi_evaluate_integer(NULL, BIOS_ENABLED, NULL, &bios_enabled); + if (ACPI_FAILURE(status)) + return -ENODEV; + + return sprintf(buf, "%s\n", bios_enabled ? "enabled" : "disabled"); +} + +static int intel_menlow_add_one_attribute(char *name, int mode, void *show, + void *store, struct device *dev, + acpi_handle handle) +{ + struct intel_menlow_attribute *attr; + int result; + + attr = kzalloc(sizeof(struct intel_menlow_attribute), GFP_KERNEL); + if (!attr) + return -ENOMEM; + + attr->attr.attr.name = name; + attr->attr.attr.mode = mode; + attr->attr.show = show; + attr->attr.store = store; + attr->device = dev; + attr->handle = handle; + + result = device_create_file(dev, &attr->attr); + if (result) + return result; + + mutex_lock(&intel_menlow_attr_lock); + list_add_tail(&attr->node, &intel_menlow_attr_list); + mutex_unlock(&intel_menlow_attr_lock); + + return 0; +} + +static acpi_status intel_menlow_register_sensor(acpi_handle handle, u32 lvl, + void *context, void **rv) +{ + acpi_status status; + acpi_handle dummy; + struct thermal_zone_device *thermal; + int result; + + result = acpi_bus_get_private_data(handle, (void **)&thermal); + if (result) + return 0; + + /* _TZ must have the AUX0/1 methods */ + status = acpi_get_handle(handle, GET_AUX0, &dummy); + if (ACPI_FAILURE(status)) + goto not_found; + + status = acpi_get_handle(handle, SET_AUX0, &dummy); + if (ACPI_FAILURE(status)) + goto not_found; + + result = intel_menlow_add_one_attribute("aux0", 0644, + aux0_show, aux0_store, + &thermal->device, handle); + if (result) + return AE_ERROR; + + status = acpi_get_handle(handle, GET_AUX1, &dummy); + if (ACPI_FAILURE(status)) + goto not_found; + + status = acpi_get_handle(handle, SET_AUX1, &dummy); + if (ACPI_FAILURE(status)) + goto not_found; + + result = intel_menlow_add_one_attribute("aux1", 0644, + aux1_show, aux1_store, + &thermal->device, handle); + if (result) + return AE_ERROR; + + /* + * create the "dabney_enabled" attribute which means the user app + * should be loaded or not + */ + + result = intel_menlow_add_one_attribute("bios_enabled", 0444, + bios_enabled_show, NULL, + &thermal->device, handle); + if (result) + return AE_ERROR; + + not_found: + if (status == AE_NOT_FOUND) + return AE_OK; + else + return status; +} + +static void intel_menlow_unregister_sensor(void) +{ + struct intel_menlow_attribute *pos, *next; + + mutex_lock(&intel_menlow_attr_lock); + list_for_each_entry_safe(pos, next, &intel_menlow_attr_list, node) { + list_del(&pos->node); + device_remove_file(pos->device, &pos->attr); + kfree(pos); + } + mutex_unlock(&intel_menlow_attr_lock); + + return; +} + +static int __init intel_menlow_module_init(void) +{ + int result = -ENODEV; + acpi_status status; + unsigned long enable; + + if (acpi_disabled) + return result; + + /* Looking for the \_TZ.GSTS method */ + status = acpi_evaluate_integer(NULL, BIOS_ENABLED, NULL, &enable); + if (ACPI_FAILURE(status) || !enable) + return -ENODEV; + + /* Looking for ACPI device MEM0 with hardware id INT0002 */ + result = acpi_bus_register_driver(&intel_menlow_memory_driver); + if (result) + return result; + + /* Looking for sensors in each ACPI thermal zone */ + status = acpi_walk_namespace(ACPI_TYPE_THERMAL, ACPI_ROOT_OBJECT, + ACPI_UINT32_MAX, + intel_menlow_register_sensor, NULL, NULL); + if (ACPI_FAILURE(status)) + return -ENODEV; + + return 0; +} + +static void __exit intel_menlow_module_exit(void) +{ + acpi_bus_unregister_driver(&intel_menlow_memory_driver); + intel_menlow_unregister_sensor(); +} + +module_init(intel_menlow_module_init); +module_exit(intel_menlow_module_exit); -- cgit v1.2.3 From 745a5d2126926808295742932d0e36d485efa485 Mon Sep 17 00:00:00 2001 From: Carlos Corbacho Date: Tue, 5 Feb 2008 02:17:10 +0000 Subject: acer-wmi: Add driver for newer Acer laptops This is a driver for newer Acer (and Wistron) laptops. It adds wireless radio and bluetooth control, and on some laptops, exposes the mail LED and LCD backlight. v1: * Initial release v2: * Replace left over ACPI references with WMI * Add GUID based autoloading (depends on future work to WMI) * Add DMI based autoloading (backup solution until WMI sysfs/ class work is available) * Checkpatch fixes v3: * Add new EC quirks for Aspire 3100 & 5100, and Extensa 5220 v4: * Simplified internal handling of WMID and AMW0 devices * Add autodetection for bluetooth and maximum brightness on AMW0 V2 and WMID laptops. v5: * Add EC quirk for Medion MD 98000 * Add autodetection for AMW0, and mail LED on AMW0 and AMW0 V2. * Improve error handling * Fix AMW0 V2 bluetooth and wireless, by using both WMID and AMW0 methods to ensure that the correct value is always set. v6: * Fix 'use before initialisation' bug with quirks. v7 * Fix bug on AMW0 where acer-wmi would exit if a mail LED was not detected. * Add Acer Aspire 9110 mail LED support * Fix section mismatch warnings Signed-off-by: Carlos Corbacho CC: Matthew Garrett Signed-off-by: Len Brown --- drivers/misc/Kconfig | 16 + drivers/misc/Makefile | 1 + drivers/misc/acer-wmi.c | 1109 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1126 insertions(+) create mode 100644 drivers/misc/acer-wmi.c (limited to 'drivers/misc') diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index b5e67c0ff43..35d2c22c5d2 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -92,6 +92,22 @@ config TIFM_7XX1 To compile this driver as a module, choose M here: the module will be called tifm_7xx1. +config ACER_WMI + tristate "Acer WMI Laptop Extras (EXPERIMENTAL)" + depends on X86 + depends on EXPERIMENTAL + depends on ACPI + depends on ACPI_WMI + depends on LEDS_CLASS + depends on BACKLIGHT_CLASS_DEVICE + ---help--- + This is a driver for newer Acer (and Wistron) laptops. It adds + wireless radio and bluetooth control, and on some laptops, + exposes the mail LED and LCD backlight. + + If you have an ACPI-WMI compatible Acer/ Wistron laptop, say Y or M + here. + config ASUS_LAPTOP tristate "Asus Laptop Extras (EXPERIMENTAL)" depends on X86 diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 87f2685d728..3da1491f662 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -6,6 +6,7 @@ obj- := misc.o # Dummy rule to force built-in.o to be made obj-$(CONFIG_IBM_ASM) += ibmasm/ obj-$(CONFIG_HDPU_FEATURES) += hdpuftrs/ obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o +obj-$(CONFIG_ACER_WMI) += acer-wmi.o obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o obj-$(CONFIG_LKDTM) += lkdtm.o diff --git a/drivers/misc/acer-wmi.c b/drivers/misc/acer-wmi.c new file mode 100644 index 00000000000..a4d67750425 --- /dev/null +++ b/drivers/misc/acer-wmi.c @@ -0,0 +1,1109 @@ +/* + * Acer WMI Laptop Extras + * + * Copyright (C) 2007-2008 Carlos Corbacho + * + * Based on acer_acpi: + * Copyright (C) 2005-2007 E.M. Smith + * Copyright (C) 2007-2008 Carlos Corbacho + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define ACER_WMI_VERSION "0.1" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +MODULE_AUTHOR("Carlos Corbacho"); +MODULE_DESCRIPTION("Acer Laptop WMI Extras Driver"); +MODULE_LICENSE("GPL"); + +#define ACER_LOGPREFIX "acer-wmi: " +#define ACER_ERR KERN_ERR ACER_LOGPREFIX +#define ACER_NOTICE KERN_NOTICE ACER_LOGPREFIX +#define ACER_INFO KERN_INFO ACER_LOGPREFIX + +/* + * The following defines quirks to get some specific functions to work + * which are known to not be supported over ACPI-WMI (such as the mail LED + * on WMID based Acer's) + */ +struct acer_quirks { + const char *vendor; + const char *model; + u16 quirks; +}; + +/* + * Magic Number + * Meaning is unknown - this number is required for writing to ACPI for AMW0 + * (it's also used in acerhk when directly accessing the BIOS) + */ +#define ACER_AMW0_WRITE 0x9610 + +/* + * Bit masks for the AMW0 interface + */ +#define ACER_AMW0_WIRELESS_MASK 0x35 +#define ACER_AMW0_BLUETOOTH_MASK 0x34 +#define ACER_AMW0_MAILLED_MASK 0x31 + +/* + * Method IDs for WMID interface + */ +#define ACER_WMID_GET_WIRELESS_METHODID 1 +#define ACER_WMID_GET_BLUETOOTH_METHODID 2 +#define ACER_WMID_GET_BRIGHTNESS_METHODID 3 +#define ACER_WMID_SET_WIRELESS_METHODID 4 +#define ACER_WMID_SET_BLUETOOTH_METHODID 5 +#define ACER_WMID_SET_BRIGHTNESS_METHODID 6 +#define ACER_WMID_GET_THREEG_METHODID 10 +#define ACER_WMID_SET_THREEG_METHODID 11 + +/* + * Acer ACPI method GUIDs + */ +#define AMW0_GUID1 "67C3371D-95A3-4C37-BB61-DD47B491DAAB" +#define WMID_GUID1 "6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3" +#define WMID_GUID2 "95764E09-FB56-4e83-B31A-37761F60994A" + +MODULE_ALIAS("wmi:67C3371D-95A3-4C37-BB61-DD47B491DAAB"); +MODULE_ALIAS("wmi:6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3"); + +/* Temporary workaround until the WMI sysfs interface goes in */ +MODULE_ALIAS("dmi:*:*Acer*:*:"); + +/* + * Interface capability flags + */ +#define ACER_CAP_MAILLED (1<<0) +#define ACER_CAP_WIRELESS (1<<1) +#define ACER_CAP_BLUETOOTH (1<<2) +#define ACER_CAP_BRIGHTNESS (1<<3) +#define ACER_CAP_THREEG (1<<4) +#define ACER_CAP_ANY (0xFFFFFFFF) + +/* + * Interface type flags + */ +enum interface_flags { + ACER_AMW0, + ACER_AMW0_V2, + ACER_WMID, +}; + +#define ACER_DEFAULT_WIRELESS 0 +#define ACER_DEFAULT_BLUETOOTH 0 +#define ACER_DEFAULT_MAILLED 0 +#define ACER_DEFAULT_THREEG 0 + +static int max_brightness = 0xF; + +static int wireless = -1; +static int bluetooth = -1; +static int mailled = -1; +static int brightness = -1; +static int threeg = -1; +static int force_series; + +module_param(mailled, int, 0444); +module_param(wireless, int, 0444); +module_param(bluetooth, int, 0444); +module_param(brightness, int, 0444); +module_param(threeg, int, 0444); +module_param(force_series, int, 0444); +MODULE_PARM_DESC(wireless, "Set initial state of Wireless hardware"); +MODULE_PARM_DESC(bluetooth, "Set initial state of Bluetooth hardware"); +MODULE_PARM_DESC(mailled, "Set initial state of Mail LED"); +MODULE_PARM_DESC(brightness, "Set initial LCD backlight brightness"); +MODULE_PARM_DESC(threeg, "Set initial state of 3G hardware"); +MODULE_PARM_DESC(force_series, "Force a different laptop series"); + +struct acer_data { + int mailled; + int wireless; + int bluetooth; + int threeg; + int brightness; +}; + +/* Each low-level interface must define at least some of the following */ +struct wmi_interface { + /* The WMI device type */ + u32 type; + + /* The capabilities this interface provides */ + u32 capability; + + /* Private data for the current interface */ + struct acer_data data; +}; + +/* The static interface pointer, points to the currently detected interface */ +static struct wmi_interface *interface; + +/* + * Embedded Controller quirks + * Some laptops require us to directly access the EC to either enable or query + * features that are not available through WMI. + */ + +struct quirk_entry { + u8 wireless; + u8 mailled; + u8 brightness; + u8 bluetooth; +}; + +static struct quirk_entry *quirks; + +static void set_quirks(void) +{ + if (quirks->mailled) + interface->capability |= ACER_CAP_MAILLED; + + if (quirks->brightness) + interface->capability |= ACER_CAP_BRIGHTNESS; +} + +static int dmi_matched(const struct dmi_system_id *dmi) +{ + quirks = dmi->driver_data; + return 0; +} + +static struct quirk_entry quirk_unknown = { +}; + +static struct quirk_entry quirk_acer_travelmate_2490 = { + .mailled = 1, +}; + +/* This AMW0 laptop has no bluetooth */ +static struct quirk_entry quirk_medion_md_98300 = { + .wireless = 1, +}; + +static struct dmi_system_id acer_quirks[] = { + { + .callback = dmi_matched, + .ident = "Acer Aspire 3100", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3100"), + }, + .driver_data = &quirk_acer_travelmate_2490, + }, + { + .callback = dmi_matched, + .ident = "Acer Aspire 5100", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5100"), + }, + .driver_data = &quirk_acer_travelmate_2490, + }, + { + .callback = dmi_matched, + .ident = "Acer Aspire 5630", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5630"), + }, + .driver_data = &quirk_acer_travelmate_2490, + }, + { + .callback = dmi_matched, + .ident = "Acer Aspire 5650", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5650"), + }, + .driver_data = &quirk_acer_travelmate_2490, + }, + { + .callback = dmi_matched, + .ident = "Acer Aspire 5680", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5680"), + }, + .driver_data = &quirk_acer_travelmate_2490, + }, + { + .callback = dmi_matched, + .ident = "Acer Aspire 9110", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 9110"), + }, + .driver_data = &quirk_acer_travelmate_2490, + }, + { + .callback = dmi_matched, + .ident = "Acer TravelMate 2490", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2490"), + }, + .driver_data = &quirk_acer_travelmate_2490, + }, + { + .callback = dmi_matched, + .ident = "Medion MD 98300", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "MEDION"), + DMI_MATCH(DMI_PRODUCT_NAME, "WAM2030"), + }, + .driver_data = &quirk_medion_md_98300, + }, + {} +}; + +/* Find which quirks are needed for a particular vendor/ model pair */ +static void find_quirks(void) +{ + if (!force_series) { + dmi_check_system(acer_quirks); + } else if (force_series == 2490) { + quirks = &quirk_acer_travelmate_2490; + } + + if (quirks == NULL) + quirks = &quirk_unknown; + + set_quirks(); +} + +/* + * General interface convenience methods + */ + +static bool has_cap(u32 cap) +{ + if ((interface->capability & cap) != 0) + return 1; + + return 0; +} + +/* + * AMW0 (V1) interface + */ +struct wmab_args { + u32 eax; + u32 ebx; + u32 ecx; + u32 edx; +}; + +struct wmab_ret { + u32 eax; + u32 ebx; + u32 ecx; + u32 edx; + u32 eex; +}; + +static acpi_status wmab_execute(struct wmab_args *regbuf, +struct acpi_buffer *result) +{ + struct acpi_buffer input; + acpi_status status; + input.length = sizeof(struct wmab_args); + input.pointer = (u8 *)regbuf; + + status = wmi_evaluate_method(AMW0_GUID1, 1, 1, &input, result); + + return status; +} + +static acpi_status AMW0_get_u32(u32 *value, u32 cap, +struct wmi_interface *iface) +{ + int err; + u8 result; + + switch (cap) { + case ACER_CAP_MAILLED: + switch (quirks->mailled) { + default: + err = ec_read(0xA, &result); + if (err) + return AE_ERROR; + *value = (result >> 7) & 0x1; + return AE_OK; + } + break; + case ACER_CAP_WIRELESS: + switch (quirks->wireless) { + case 1: + err = ec_read(0x7B, &result); + if (err) + return AE_ERROR; + *value = result & 0x1; + return AE_OK; + default: + err = ec_read(0xA, &result); + if (err) + return AE_ERROR; + *value = (result >> 2) & 0x1; + return AE_OK; + } + break; + case ACER_CAP_BLUETOOTH: + switch (quirks->bluetooth) { + default: + err = ec_read(0xA, &result); + if (err) + return AE_ERROR; + *value = (result >> 4) & 0x1; + return AE_OK; + } + break; + case ACER_CAP_BRIGHTNESS: + switch (quirks->brightness) { + default: + err = ec_read(0x83, &result); + if (err) + return AE_ERROR; + *value = result; + return AE_OK; + } + break; + default: + return AE_BAD_ADDRESS; + } + return AE_OK; +} + +static acpi_status AMW0_set_u32(u32 value, u32 cap, struct wmi_interface *iface) +{ + struct wmab_args args; + + args.eax = ACER_AMW0_WRITE; + args.ebx = value ? (1<<8) : 0; + args.ecx = args.edx = 0; + + switch (cap) { + case ACER_CAP_MAILLED: + if (value > 1) + return AE_BAD_PARAMETER; + args.ebx |= ACER_AMW0_MAILLED_MASK; + break; + case ACER_CAP_WIRELESS: + if (value > 1) + return AE_BAD_PARAMETER; + args.ebx |= ACER_AMW0_WIRELESS_MASK; + break; + case ACER_CAP_BLUETOOTH: + if (value > 1) + return AE_BAD_PARAMETER; + args.ebx |= ACER_AMW0_BLUETOOTH_MASK; + break; + case ACER_CAP_BRIGHTNESS: + if (value > max_brightness) + return AE_BAD_PARAMETER; + switch (quirks->brightness) { + case 1: + return ec_write(0x83, value); + default: + return AE_BAD_ADDRESS; + break; + } + default: + return AE_BAD_ADDRESS; + } + + /* Actually do the set */ + return wmab_execute(&args, NULL); +} + +static acpi_status AMW0_find_mailled(void) +{ + struct wmab_args args; + struct wmab_ret ret; + acpi_status status = AE_OK; + struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object *obj; + + args.eax = 0x86; + args.ebx = args.ecx = args.edx = 0; + + status = wmab_execute(&args, &out); + if (ACPI_FAILURE(status)) + return status; + + obj = (union acpi_object *) out.pointer; + if (obj && obj->type == ACPI_TYPE_BUFFER && + obj->buffer.length == sizeof(struct wmab_ret)) { + ret = *((struct wmab_ret *) obj->buffer.pointer); + } else { + return AE_ERROR; + } + + if (ret.eex & 0x1) + interface->capability |= ACER_CAP_MAILLED; + + kfree(out.pointer); + + return AE_OK; +} + +static acpi_status AMW0_set_capabilities(void) +{ + struct wmab_args args; + struct wmab_ret ret; + acpi_status status = AE_OK; + struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object *obj; + + args.eax = ACER_AMW0_WRITE; + args.ecx = args.edx = 0; + + args.ebx = 0xa2 << 8; + args.ebx |= ACER_AMW0_WIRELESS_MASK; + + status = wmab_execute(&args, &out); + if (ACPI_FAILURE(status)) + return status; + + obj = (union acpi_object *) out.pointer; + if (obj && obj->type == ACPI_TYPE_BUFFER && + obj->buffer.length == sizeof(struct wmab_ret)) { + ret = *((struct wmab_ret *) obj->buffer.pointer); + } else { + return AE_ERROR; + } + + if (ret.eax & 0x1) + interface->capability |= ACER_CAP_WIRELESS; + + args.ebx = 2 << 8; + args.ebx |= ACER_AMW0_BLUETOOTH_MASK; + + status = wmab_execute(&args, &out); + if (ACPI_FAILURE(status)) + return status; + + obj = (union acpi_object *) out.pointer; + if (obj && obj->type == ACPI_TYPE_BUFFER + && obj->buffer.length == sizeof(struct wmab_ret)) { + ret = *((struct wmab_ret *) obj->buffer.pointer); + } else { + return AE_ERROR; + } + + if (ret.eax & 0x1) + interface->capability |= ACER_CAP_BLUETOOTH; + + kfree(out.pointer); + + /* + * This appears to be safe to enable, since all Wistron based laptops + * appear to use the same EC register for brightness, even if they + * differ for wireless, etc + */ + interface->capability |= ACER_CAP_BRIGHTNESS; + + return AE_OK; +} + +static struct wmi_interface AMW0_interface = { + .type = ACER_AMW0, +}; + +static struct wmi_interface AMW0_V2_interface = { + .type = ACER_AMW0_V2, +}; + +/* + * New interface (The WMID interface) + */ +static acpi_status +WMI_execute_u32(u32 method_id, u32 in, u32 *out) +{ + struct acpi_buffer input = { (acpi_size) sizeof(u32), (void *)(&in) }; + struct acpi_buffer result = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object *obj; + u32 tmp; + acpi_status status; + + status = wmi_evaluate_method(WMID_GUID1, 1, method_id, &input, &result); + + if (ACPI_FAILURE(status)) + return status; + + obj = (union acpi_object *) result.pointer; + if (obj && obj->type == ACPI_TYPE_BUFFER && + obj->buffer.length == sizeof(u32)) { + tmp = *((u32 *) obj->buffer.pointer); + } else { + tmp = 0; + } + + if (out) + *out = tmp; + + kfree(result.pointer); + + return status; +} + +static acpi_status WMID_get_u32(u32 *value, u32 cap, +struct wmi_interface *iface) +{ + acpi_status status; + u8 tmp; + u32 result, method_id = 0; + + switch (cap) { + case ACER_CAP_WIRELESS: + method_id = ACER_WMID_GET_WIRELESS_METHODID; + break; + case ACER_CAP_BLUETOOTH: + method_id = ACER_WMID_GET_BLUETOOTH_METHODID; + break; + case ACER_CAP_BRIGHTNESS: + method_id = ACER_WMID_GET_BRIGHTNESS_METHODID; + break; + case ACER_CAP_THREEG: + method_id = ACER_WMID_GET_THREEG_METHODID; + break; + case ACER_CAP_MAILLED: + if (quirks->mailled == 1) { + ec_read(0x9f, &tmp); + *value = tmp & 0x1; + return 0; + } + default: + return AE_BAD_ADDRESS; + } + status = WMI_execute_u32(method_id, 0, &result); + + if (ACPI_SUCCESS(status)) + *value = (u8)result; + + return status; +} + +static acpi_status WMID_set_u32(u32 value, u32 cap, struct wmi_interface *iface) +{ + u32 method_id = 0; + char param; + + switch (cap) { + case ACER_CAP_BRIGHTNESS: + if (value > max_brightness) + return AE_BAD_PARAMETER; + method_id = ACER_WMID_SET_BRIGHTNESS_METHODID; + break; + case ACER_CAP_WIRELESS: + if (value > 1) + return AE_BAD_PARAMETER; + method_id = ACER_WMID_SET_WIRELESS_METHODID; + break; + case ACER_CAP_BLUETOOTH: + if (value > 1) + return AE_BAD_PARAMETER; + method_id = ACER_WMID_SET_BLUETOOTH_METHODID; + break; + case ACER_CAP_THREEG: + if (value > 1) + return AE_BAD_PARAMETER; + method_id = ACER_WMID_SET_THREEG_METHODID; + break; + case ACER_CAP_MAILLED: + if (value > 1) + return AE_BAD_PARAMETER; + if (quirks->mailled == 1) { + param = value ? 0x92 : 0x93; + i8042_command(¶m, 0x1059); + return 0; + } + break; + default: + return AE_BAD_ADDRESS; + } + return WMI_execute_u32(method_id, (u32)value, NULL); +} + +static acpi_status WMID_set_capabilities(void) +{ + struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL}; + union acpi_object *obj; + acpi_status status; + u32 devices; + + status = wmi_query_block(WMID_GUID2, 1, &out); + if (ACPI_FAILURE(status)) + return status; + + obj = (union acpi_object *) out.pointer; + if (obj && obj->type == ACPI_TYPE_BUFFER && + obj->buffer.length == sizeof(u32)) { + devices = *((u32 *) obj->buffer.pointer); + } else { + return AE_ERROR; + } + + /* Not sure on the meaning of the relevant bits yet to detect these */ + interface->capability |= ACER_CAP_WIRELESS; + interface->capability |= ACER_CAP_THREEG; + + /* WMID always provides brightness methods */ + interface->capability |= ACER_CAP_BRIGHTNESS; + + if (devices & 0x10) + interface->capability |= ACER_CAP_BLUETOOTH; + + if (!(devices & 0x20)) + max_brightness = 0x9; + + return status; +} + +static struct wmi_interface wmid_interface = { + .type = ACER_WMID, +}; + +/* + * Generic Device (interface-independent) + */ + +static acpi_status get_u32(u32 *value, u32 cap) +{ + acpi_status status = AE_BAD_ADDRESS; + + switch (interface->type) { + case ACER_AMW0: + status = AMW0_get_u32(value, cap, interface); + break; + case ACER_AMW0_V2: + if (cap == ACER_CAP_MAILLED) { + status = AMW0_get_u32(value, cap, interface); + break; + } + case ACER_WMID: + status = WMID_get_u32(value, cap, interface); + break; + } + + return status; +} + +static acpi_status set_u32(u32 value, u32 cap) +{ + if (interface->capability & cap) { + switch (interface->type) { + case ACER_AMW0: + return AMW0_set_u32(value, cap, interface); + case ACER_AMW0_V2: + case ACER_WMID: + return WMID_set_u32(value, cap, interface); + default: + return AE_BAD_PARAMETER; + } + } + return AE_BAD_PARAMETER; +} + +static void __init acer_commandline_init(void) +{ + /* + * These will all fail silently if the value given is invalid, or the + * capability isn't available on the given interface + */ + set_u32(mailled, ACER_CAP_MAILLED); + set_u32(wireless, ACER_CAP_WIRELESS); + set_u32(bluetooth, ACER_CAP_BLUETOOTH); + set_u32(threeg, ACER_CAP_THREEG); + set_u32(brightness, ACER_CAP_BRIGHTNESS); +} + +/* + * LED device (Mail LED only, no other LEDs known yet) + */ +static void mail_led_set(struct led_classdev *led_cdev, +enum led_brightness value) +{ + set_u32(value, ACER_CAP_MAILLED); +} + +static struct led_classdev mail_led = { + .name = "acer-mail:green", + .brightness_set = mail_led_set, +}; + +static int __init acer_led_init(struct device *dev) +{ + return led_classdev_register(dev, &mail_led); +} + +static void acer_led_exit(void) +{ + led_classdev_unregister(&mail_led); +} + +/* + * Backlight device + */ +static struct backlight_device *acer_backlight_device; + +static int read_brightness(struct backlight_device *bd) +{ + u32 value; + get_u32(&value, ACER_CAP_BRIGHTNESS); + return value; +} + +static int update_bl_status(struct backlight_device *bd) +{ + set_u32(bd->props.brightness, ACER_CAP_BRIGHTNESS); + return 0; +} + +static struct backlight_ops acer_bl_ops = { + .get_brightness = read_brightness, + .update_status = update_bl_status, +}; + +static int __init acer_backlight_init(struct device *dev) +{ + struct backlight_device *bd; + + bd = backlight_device_register("acer-wmi", dev, NULL, &acer_bl_ops); + if (IS_ERR(bd)) { + printk(ACER_ERR "Could not register Acer backlight device\n"); + acer_backlight_device = NULL; + return PTR_ERR(bd); + } + + acer_backlight_device = bd; + + bd->props.max_brightness = max_brightness; + bd->props.brightness = read_brightness(NULL); + backlight_update_status(bd); + return 0; +} + +static void __exit acer_backlight_exit(void) +{ + backlight_device_unregister(acer_backlight_device); +} + +/* + * Read/ write bool sysfs macro + */ +#define show_set_bool(value, cap) \ +static ssize_t \ +show_bool_##value(struct device *dev, struct device_attribute *attr, \ + char *buf) \ +{ \ + u32 result; \ + acpi_status status = get_u32(&result, cap); \ + if (ACPI_SUCCESS(status)) \ + return sprintf(buf, "%u\n", result); \ + return sprintf(buf, "Read error\n"); \ +} \ +\ +static ssize_t \ +set_bool_##value(struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + u32 tmp = simple_strtoul(buf, NULL, 10); \ + acpi_status status = set_u32(tmp, cap); \ + if (ACPI_FAILURE(status)) \ + return -EINVAL; \ + return count; \ +} \ +static DEVICE_ATTR(value, S_IWUGO | S_IRUGO | S_IWUSR, \ + show_bool_##value, set_bool_##value); + +show_set_bool(wireless, ACER_CAP_WIRELESS); +show_set_bool(bluetooth, ACER_CAP_BLUETOOTH); +show_set_bool(threeg, ACER_CAP_THREEG); + +/* + * Read interface sysfs macro + */ +static ssize_t show_interface(struct device *dev, struct device_attribute *attr, + char *buf) +{ + switch (interface->type) { + case ACER_AMW0: + return sprintf(buf, "AMW0\n"); + case ACER_AMW0_V2: + return sprintf(buf, "AMW0 v2\n"); + case ACER_WMID: + return sprintf(buf, "WMID\n"); + default: + return sprintf(buf, "Error!\n"); + } +} + +static DEVICE_ATTR(interface, S_IWUGO | S_IRUGO | S_IWUSR, + show_interface, NULL); + +/* + * Platform device + */ +static int __devinit acer_platform_probe(struct platform_device *device) +{ + int err; + + if (has_cap(ACER_CAP_MAILLED)) { + err = acer_led_init(&device->dev); + if (err) + goto error_mailled; + } + + if (has_cap(ACER_CAP_BRIGHTNESS)) { + err = acer_backlight_init(&device->dev); + if (err) + goto error_brightness; + } + + return 0; + +error_brightness: + acer_led_exit(); +error_mailled: + return err; +} + +static int acer_platform_remove(struct platform_device *device) +{ + if (has_cap(ACER_CAP_MAILLED)) + acer_led_exit(); + if (has_cap(ACER_CAP_BRIGHTNESS)) + acer_backlight_exit(); + return 0; +} + +static int acer_platform_suspend(struct platform_device *dev, +pm_message_t state) +{ + u32 value; + struct acer_data *data = &interface->data; + + if (!data) + return -ENOMEM; + + if (has_cap(ACER_CAP_WIRELESS)) { + get_u32(&value, ACER_CAP_WIRELESS); + data->wireless = value; + } + + if (has_cap(ACER_CAP_BLUETOOTH)) { + get_u32(&value, ACER_CAP_BLUETOOTH); + data->bluetooth = value; + } + + if (has_cap(ACER_CAP_MAILLED)) { + get_u32(&value, ACER_CAP_MAILLED); + data->mailled = value; + } + + if (has_cap(ACER_CAP_BRIGHTNESS)) { + get_u32(&value, ACER_CAP_BRIGHTNESS); + data->brightness = value; + } + + return 0; +} + +static int acer_platform_resume(struct platform_device *device) +{ + struct acer_data *data = &interface->data; + + if (!data) + return -ENOMEM; + + if (has_cap(ACER_CAP_WIRELESS)) + set_u32(data->wireless, ACER_CAP_WIRELESS); + + if (has_cap(ACER_CAP_BLUETOOTH)) + set_u32(data->bluetooth, ACER_CAP_BLUETOOTH); + + if (has_cap(ACER_CAP_THREEG)) + set_u32(data->threeg, ACER_CAP_THREEG); + + if (has_cap(ACER_CAP_MAILLED)) + set_u32(data->mailled, ACER_CAP_MAILLED); + + if (has_cap(ACER_CAP_BRIGHTNESS)) + set_u32(data->brightness, ACER_CAP_BRIGHTNESS); + + return 0; +} + +static struct platform_driver acer_platform_driver = { + .driver = { + .name = "acer-wmi", + .owner = THIS_MODULE, + }, + .probe = acer_platform_probe, + .remove = acer_platform_remove, + .suspend = acer_platform_suspend, + .resume = acer_platform_resume, +}; + +static struct platform_device *acer_platform_device; + +static int remove_sysfs(struct platform_device *device) +{ + if (has_cap(ACER_CAP_WIRELESS)) + device_remove_file(&device->dev, &dev_attr_wireless); + + if (has_cap(ACER_CAP_BLUETOOTH)) + device_remove_file(&device->dev, &dev_attr_bluetooth); + + if (has_cap(ACER_CAP_THREEG)) + device_remove_file(&device->dev, &dev_attr_threeg); + + device_remove_file(&device->dev, &dev_attr_interface); + + return 0; +} + +static int create_sysfs(void) +{ + int retval = -ENOMEM; + + if (has_cap(ACER_CAP_WIRELESS)) { + retval = device_create_file(&acer_platform_device->dev, + &dev_attr_wireless); + if (retval) + goto error_sysfs; + } + + if (has_cap(ACER_CAP_BLUETOOTH)) { + retval = device_create_file(&acer_platform_device->dev, + &dev_attr_bluetooth); + if (retval) + goto error_sysfs; + } + + if (has_cap(ACER_CAP_THREEG)) { + retval = device_create_file(&acer_platform_device->dev, + &dev_attr_threeg); + if (retval) + goto error_sysfs; + } + + retval = device_create_file(&acer_platform_device->dev, + &dev_attr_interface); + if (retval) + goto error_sysfs; + + return 0; + +error_sysfs: + remove_sysfs(acer_platform_device); + return retval; +} + +static int __init acer_wmi_init(void) +{ + int err; + + printk(ACER_INFO "Acer Laptop ACPI-WMI Extras version %s\n", + ACER_WMI_VERSION); + + /* + * Detect which ACPI-WMI interface we're using. + */ + if (wmi_has_guid(AMW0_GUID1) && wmi_has_guid(WMID_GUID1)) + interface = &AMW0_V2_interface; + + if (!wmi_has_guid(AMW0_GUID1) && wmi_has_guid(WMID_GUID1)) + interface = &wmid_interface; + + if (wmi_has_guid(WMID_GUID2) && interface) { + if (ACPI_FAILURE(WMID_set_capabilities())) { + printk(ACER_ERR "Unable to detect available devices\n"); + return -ENODEV; + } + } else if (!wmi_has_guid(WMID_GUID2) && interface) { + printk(ACER_ERR "Unable to detect available devices\n"); + return -ENODEV; + } + + if (wmi_has_guid(AMW0_GUID1) && !wmi_has_guid(WMID_GUID1)) { + interface = &AMW0_interface; + + if (ACPI_FAILURE(AMW0_set_capabilities())) { + printk(ACER_ERR "Unable to detect available devices\n"); + return -ENODEV; + } + } + + if (wmi_has_guid(AMW0_GUID1)) { + if (ACPI_FAILURE(AMW0_find_mailled())) + printk(ACER_ERR "Unable to detect mail LED\n"); + } + + find_quirks(); + + if (!interface) { + printk(ACER_ERR "No or unsupported WMI interface, unable to "); + printk(KERN_CONT "load.\n"); + return -ENODEV; + } + + if (platform_driver_register(&acer_platform_driver)) { + printk(ACER_ERR "Unable to register platform driver.\n"); + goto error_platform_register; + } + acer_platform_device = platform_device_alloc("acer-wmi", -1); + platform_device_add(acer_platform_device); + + err = create_sysfs(); + if (err) + return err; + + /* Override any initial settings with values from the commandline */ + acer_commandline_init(); + + return 0; + +error_platform_register: + return -ENODEV; +} + +static void __exit acer_wmi_exit(void) +{ + remove_sysfs(acer_platform_device); + platform_device_del(acer_platform_device); + platform_driver_unregister(&acer_platform_driver); + + printk(ACER_INFO "Acer Laptop WMI Extras unloaded\n"); + return; +} + +module_init(acer_wmi_init); +module_exit(acer_wmi_exit); -- cgit v1.2.3 From dd8cd7793781c87be47bbfee65efa3fb5110f898 Mon Sep 17 00:00:00 2001 From: Carlos Corbacho Date: Tue, 5 Feb 2008 02:17:15 +0000 Subject: tc1100-wmi: Add driver for HP Compaq TC1100 Tablets This is based on the 2004 out-of-tree work of Jamey Hicks, to add support via WMI for controlling the jog dial and wireless on these tablets. v1: Original release v2: As per Joshua Wise's comments, change bluetooth to jogdial (an error from the original driver). Signed-off-by: Carlos Corbacho CC: Matthew Garrett CC: Jamey Hicks CC: Joshua Wise Signed-off-by: Len Brown --- drivers/misc/Kconfig | 9 ++ drivers/misc/Makefile | 1 + drivers/misc/tc1100-wmi.c | 290 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 300 insertions(+) create mode 100644 drivers/misc/tc1100-wmi.c (limited to 'drivers/misc') diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 35d2c22c5d2..05997411bc4 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -142,6 +142,15 @@ config FUJITSU_LAPTOP If you have a Fujitsu laptop, say Y or M here. +config TC1100_WMI + tristate "HP Compaq TC1100 Tablet WMI Extras" + depends on X86 && !X86_64 + depends on ACPI + depends on ACPI_WMI + ---help--- + This is a driver for the WMI extensions (wireless and bluetooth power + control) of the HP Compaq TC1100 tablet. + config MSI_LAPTOP tristate "MSI Laptop Extras" depends on X86 diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 3da1491f662..51196c09e25 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o obj-$(CONFIG_ACER_WMI) += acer-wmi.o obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o +obj-$(CONFIG_TC1100_WMI) += tc1100-wmi.o obj-$(CONFIG_LKDTM) += lkdtm.o obj-$(CONFIG_TIFM_CORE) += tifm_core.o obj-$(CONFIG_TIFM_7XX1) += tifm_7xx1.o diff --git a/drivers/misc/tc1100-wmi.c b/drivers/misc/tc1100-wmi.c new file mode 100644 index 00000000000..f25e4c974dc --- /dev/null +++ b/drivers/misc/tc1100-wmi.c @@ -0,0 +1,290 @@ +/* + * HP Compaq TC1100 Tablet WMI Extras Driver + * + * Copyright (C) 2007 Carlos Corbacho + * Copyright (C) 2004 Jamey Hicks + * Copyright (C) 2001, 2002 Andy Grover + * Copyright (C) 2001, 2002 Paul Diefenbaugh + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define GUID "C364AC71-36DB-495A-8494-B439D472A505" + +#define TC1100_INSTANCE_WIRELESS 1 +#define TC1100_INSTANCE_JOGDIAL 2 + +#define TC1100_LOGPREFIX "tc1100-wmi: " +#define TC1100_INFO KERN_INFO TC1100_LOGPREFIX + +MODULE_AUTHOR("Jamey Hicks, Carlos Corbacho"); +MODULE_DESCRIPTION("HP Compaq TC1100 Tablet WMI Extras"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("wmi:C364AC71-36DB-495A-8494-B439D472A505"); + +static int tc1100_probe(struct platform_device *device); +static int tc1100_remove(struct platform_device *device); +static int tc1100_suspend(struct platform_device *device, pm_message_t state); +static int tc1100_resume(struct platform_device *device); + +static struct platform_driver tc1100_driver = { + .driver = { + .name = "tc1100-wmi", + .owner = THIS_MODULE, + }, + .probe = tc1100_probe, + .remove = tc1100_remove, + .suspend = tc1100_suspend, + .resume = tc1100_resume, +}; + +static struct platform_device *tc1100_device; + +struct tc1100_data { + u32 wireless; + u32 jogdial; +}; + +static struct tc1100_data suspend_data; + +/* -------------------------------------------------------------------------- + Device Management + -------------------------------------------------------------------------- */ + +static int get_state(u32 *out, u8 instance) +{ + u32 tmp; + acpi_status status; + struct acpi_buffer result = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object *obj; + + if (!out) + return -EINVAL; + + if (instance > 2) + return -ENODEV; + + status = wmi_query_block(GUID, instance, &result); + if (ACPI_FAILURE(status)) + return -ENODEV; + + obj = (union acpi_object *) result.pointer; + if (obj && obj->type == ACPI_TYPE_BUFFER && + obj->buffer.length == sizeof(u32)) { + tmp = *((u32 *) obj->buffer.pointer); + } else { + tmp = 0; + } + + if (result.length > 0 && result.pointer) + kfree(result.pointer); + + switch (instance) { + case TC1100_INSTANCE_WIRELESS: + *out = (tmp == 3) ? 1 : 0; + return 0; + case TC1100_INSTANCE_JOGDIAL: + *out = (tmp == 1) ? 1 : 0; + return 0; + default: + return -ENODEV; + } +} + +static int set_state(u32 *in, u8 instance) +{ + u32 value; + acpi_status status; + struct acpi_buffer input; + + if (!in) + return -EINVAL; + + if (instance > 2) + return -ENODEV; + + switch (instance) { + case TC1100_INSTANCE_WIRELESS: + value = (*in) ? 1 : 2; + break; + case TC1100_INSTANCE_JOGDIAL: + value = (*in) ? 0 : 1; + break; + default: + return -ENODEV; + } + + input.length = sizeof(u32); + input.pointer = &value; + + status = wmi_set_block(GUID, instance, &input); + if (ACPI_FAILURE(status)) + return -ENODEV; + + return 0; +} + +/* -------------------------------------------------------------------------- + FS Interface (/sys) + -------------------------------------------------------------------------- */ + +/* + * Read/ write bool sysfs macro + */ +#define show_set_bool(value, instance) \ +static ssize_t \ +show_bool_##value(struct device *dev, struct device_attribute *attr, \ + char *buf) \ +{ \ + u32 result; \ + acpi_status status = get_state(&result, instance); \ + if (ACPI_SUCCESS(status)) \ + return sprintf(buf, "%d\n", result); \ + return sprintf(buf, "Read error\n"); \ +} \ +\ +static ssize_t \ +set_bool_##value(struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + u32 tmp = simple_strtoul(buf, NULL, 10); \ + acpi_status status = set_state(&tmp, instance); \ + if (ACPI_FAILURE(status)) \ + return -EINVAL; \ + return count; \ +} \ +static DEVICE_ATTR(value, S_IWUGO | S_IRUGO | S_IWUSR, \ + show_bool_##value, set_bool_##value); + +show_set_bool(wireless, TC1100_INSTANCE_WIRELESS); +show_set_bool(jogdial, TC1100_INSTANCE_JOGDIAL); + +static void remove_fs(void) +{ + device_remove_file(&tc1100_device->dev, &dev_attr_wireless); + device_remove_file(&tc1100_device->dev, &dev_attr_jogdial); +} + +static int add_fs(void) +{ + int ret; + + ret = device_create_file(&tc1100_device->dev, &dev_attr_wireless); + if (ret) + goto add_sysfs_error; + + ret = device_create_file(&tc1100_device->dev, &dev_attr_jogdial); + if (ret) + goto add_sysfs_error; + + return ret; + +add_sysfs_error: + remove_fs(); + return ret; +} + +/* -------------------------------------------------------------------------- + Driver Model + -------------------------------------------------------------------------- */ + +static int tc1100_probe(struct platform_device *device) +{ + int result = 0; + + result = add_fs(); + return result; +} + + +static int tc1100_remove(struct platform_device *device) +{ + remove_fs(); + return 0; +} + +static int tc1100_suspend(struct platform_device *dev, pm_message_t state) +{ + int ret; + + ret = get_state(&suspend_data.wireless, TC1100_INSTANCE_WIRELESS); + if (ret) + return ret; + + ret = get_state(&suspend_data.jogdial, TC1100_INSTANCE_JOGDIAL); + if (ret) + return ret; + + return ret; +} + +static int tc1100_resume(struct platform_device *dev) +{ + int ret; + + ret = set_state(&suspend_data.wireless, TC1100_INSTANCE_WIRELESS); + if (ret) + return ret; + + ret = set_state(&suspend_data.jogdial, TC1100_INSTANCE_JOGDIAL); + if (ret) + return ret; + + return ret; +} + +static int __init tc1100_init(void) +{ + int result = 0; + + if (!wmi_has_guid(GUID)) + return -ENODEV; + + result = platform_driver_register(&tc1100_driver); + if (result) + return result; + + tc1100_device = platform_device_alloc("tc1100-wmi", -1); + platform_device_add(tc1100_device); + + printk(TC1100_INFO "HP Compaq TC1100 Tablet WMI Extras loaded\n"); + + return result; +} + +static void __exit tc1100_exit(void) +{ + platform_device_del(tc1100_device); + platform_driver_unregister(&tc1100_driver); + + printk(TC1100_INFO "HP Compaq TC1100 Tablet WMI Extras unloaded\n"); +} + +module_init(tc1100_init); +module_exit(tc1100_exit); -- cgit v1.2.3 From f8d1c94b346b62747322728e00e11f552cd90902 Mon Sep 17 00:00:00 2001 From: Corentin CHARY Date: Wed, 16 Jan 2008 16:56:42 +0100 Subject: asus-laptop new write_acpi_int Just a little modification of write_acpi_int Signed-off-by: Corentin Chary Signed-off-by: Len Brown --- drivers/misc/asus-laptop.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/asus-laptop.c b/drivers/misc/asus-laptop.c index 0846c33296b..34666ff60d3 100644 --- a/drivers/misc/asus-laptop.c +++ b/drivers/misc/asus-laptop.c @@ -254,7 +254,7 @@ ASUS_LED(gled, "gaming"); * method is searched within the scope of the handle, can be NULL. The output * of the method is written is output, which can also be NULL * - * returns 1 if write is successful, 0 else. + * returns 0 if write is successful, -1 else. */ static int write_acpi_int(acpi_handle handle, const char *method, int val, struct acpi_buffer *output) @@ -263,13 +263,19 @@ static int write_acpi_int(acpi_handle handle, const char *method, int val, union acpi_object in_obj; //the only param we use acpi_status status; + if (!handle) + return 0; + params.count = 1; params.pointer = &in_obj; in_obj.type = ACPI_TYPE_INTEGER; in_obj.integer.value = val; status = acpi_evaluate_object(handle, (char *)method, ¶ms, output); - return (status == AE_OK); + if (status == AE_OK) + return 0; + else + return -1; } static int read_wireless_status(int mask) @@ -335,7 +341,7 @@ static void write_status(acpi_handle handle, int out, int mask) break; } - if (handle && !write_acpi_int(handle, NULL, out, NULL)) + if (write_acpi_int(handle, NULL, out, NULL)) printk(ASUS_WARNING " write failed %x\n", mask); } @@ -415,7 +421,7 @@ static int set_brightness(struct backlight_device *bd, int value) value = (0 < value) ? ((15 < value) ? 15 : value) : 0; /* 0 <= value <= 15 */ - if (!write_acpi_int(brightness_set_handle, NULL, value, NULL)) { + if (write_acpi_int(brightness_set_handle, NULL, value, NULL)) { printk(ASUS_WARNING "Error changing brightness\n"); ret = -EIO; } @@ -545,7 +551,7 @@ static ssize_t store_ledd(struct device *dev, struct device_attribute *attr, rv = parse_arg(buf, count, &value); if (rv > 0) { - if (!write_acpi_int(ledd_set_handle, NULL, value, NULL)) + if (write_acpi_int(ledd_set_handle, NULL, value, NULL)) printk(ASUS_WARNING "LED display write failed\n"); else hotk->ledd_status = (u32) value; @@ -590,7 +596,7 @@ static ssize_t store_bluetooth(struct device *dev, static void set_display(int value) { /* no sanity check needed for now */ - if (!write_acpi_int(display_set_handle, NULL, value, NULL)) + if (write_acpi_int(display_set_handle, NULL, value, NULL)) printk(ASUS_WARNING "Error setting display\n"); return; } @@ -647,7 +653,7 @@ static ssize_t store_disp(struct device *dev, struct device_attribute *attr, */ static void set_light_sens_switch(int value) { - if (!write_acpi_int(ls_switch_handle, NULL, value, NULL)) + if (write_acpi_int(ls_switch_handle, NULL, value, NULL)) printk(ASUS_WARNING "Error setting light sensor switch\n"); hotk->light_switch = value; } @@ -672,7 +678,7 @@ static ssize_t store_lssw(struct device *dev, struct device_attribute *attr, static void set_light_sens_level(int value) { - if (!write_acpi_int(ls_level_handle, NULL, value, NULL)) + if (write_acpi_int(ls_level_handle, NULL, value, NULL)) printk(ASUS_WARNING "Error setting light sensor level\n"); hotk->light_level = value; } @@ -860,7 +866,7 @@ static int asus_hotk_get_info(void) printk(ASUS_WARNING "Couldn't get the DSDT table header\n"); /* We have to write 0 on init this far for all ASUS models */ - if (!write_acpi_int(hotk->handle, "INIT", 0, &buffer)) { + if (write_acpi_int(hotk->handle, "INIT", 0, &buffer)) { printk(ASUS_ERR "Hotkey initialization failed\n"); return -ENODEV; } -- cgit v1.2.3 From e1af14e4b3d5f2a348987e3069ec835b782782b0 Mon Sep 17 00:00:00 2001 From: Roel Kluin <12o3l@tiscali.nl> Date: Sat, 2 Feb 2008 21:07:38 +0100 Subject: asus-laptop: add parentheses '!' has a higher priority than '&': bitanding has no effect. Signed-off-by: Roel Kluin <12o3l@tiscali.nl> Signed-off-by: Len Brown --- drivers/misc/asus-laptop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/misc') diff --git a/drivers/misc/asus-laptop.c b/drivers/misc/asus-laptop.c index 34666ff60d3..3bd883166e3 100644 --- a/drivers/misc/asus-laptop.c +++ b/drivers/misc/asus-laptop.c @@ -327,7 +327,7 @@ static void write_status(acpi_handle handle, int out, int mask) switch (mask) { case MLED_ON: - out = !out & 0x1; + out = !(out & 0x1); break; case GLED_ON: out = (out & 0x1) + 1; -- cgit v1.2.3 From 547266e46cc0b35ce51bd1f37f261d831927431f Mon Sep 17 00:00:00 2001 From: Roel Kluin <12o3l@tiscali.nl> Date: Tue, 5 Feb 2008 00:24:56 +0100 Subject: ACPI: thinkpad-acpi: second TP_EC_FAN_FULLSPEED should be TP_EC_FAN_AUTO fix bug in safety net for TPEC fan control mode eaa7571b2d1a08873e4bdd8e6db3431df61cd9ad Signed-off-by: Roel Kluin <12o3l@tiscali.nl> Acked-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/misc') diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 8ef0afc8869..7ba1acad540 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -4790,7 +4790,7 @@ static int fan_set_level(int level) * or FULLSPEED mode bits and just ignore them */ if (level & TP_EC_FAN_FULLSPEED) level |= 7; /* safety min speed 7 */ - else if (level & TP_EC_FAN_FULLSPEED) + else if (level & TP_EC_FAN_AUTO) level |= 4; /* safety min speed 4 */ if (!acpi_ec_write(fan_status_offset, level)) -- cgit v1.2.3