From 0f218d949a166e063e27899180d66e340ee55b01 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Fri, 25 Jul 2008 20:06:09 -0300 Subject: [PATCH] Add patches accepted for 2.6.27-rc1 Signed-off-by: Henrique de Moraes Holschuh --- ...nkpad-acpi-minor-refactor-on-radio-switch.patch | 94 ++++ ...kpad-acpi-consolidate-wlsw-notification-f.patch | 95 ++++ ...nkpad-acpi-prepare-for-bluetooth-and-wwan.patch | 216 +++++++++ ...kpad-acpi-WLSW-overrides-other-rfkill-swi.patch | 77 ++++ ...kpad-acpi-add-bluetooth-and-WWAN-rfkill-s.patch | 487 +++++++++++++++++++++ ...CPI-thinkpad-acpi-bump-up-version-to-0.21.patch | 43 ++ ...kpad-acpi-don-t-misdetect-in-get_thinkpad.patch | 114 +++++ 7 files changed, 1126 insertions(+) create mode 100644 releases/upstream/2.6.27-rc1/0001-ACPI-thinkpad-acpi-minor-refactor-on-radio-switch.patch create mode 100644 releases/upstream/2.6.27-rc1/0002-ACPI-thinkpad-acpi-consolidate-wlsw-notification-f.patch create mode 100644 releases/upstream/2.6.27-rc1/0003-ACPI-thinkpad-acpi-prepare-for-bluetooth-and-wwan.patch create mode 100644 releases/upstream/2.6.27-rc1/0004-ACPI-thinkpad-acpi-WLSW-overrides-other-rfkill-swi.patch create mode 100644 releases/upstream/2.6.27-rc1/0005-ACPI-thinkpad-acpi-add-bluetooth-and-WWAN-rfkill-s.patch create mode 100644 releases/upstream/2.6.27-rc1/0006-ACPI-thinkpad-acpi-bump-up-version-to-0.21.patch create mode 100644 releases/upstream/2.6.27-rc1/0007-ACPI-thinkpad-acpi-don-t-misdetect-in-get_thinkpad.patch diff --git a/releases/upstream/2.6.27-rc1/0001-ACPI-thinkpad-acpi-minor-refactor-on-radio-switch.patch b/releases/upstream/2.6.27-rc1/0001-ACPI-thinkpad-acpi-minor-refactor-on-radio-switch.patch new file mode 100644 index 00000000000..a5f2277dc52 --- /dev/null +++ b/releases/upstream/2.6.27-rc1/0001-ACPI-thinkpad-acpi-minor-refactor-on-radio-switch.patch @@ -0,0 +1,94 @@ +From 3a87208028ef59215a88a143c723ac0b83c11df0 Mon Sep 17 00:00:00 2001 +From: Henrique de Moraes Holschuh +Date: Mon, 21 Jul 2008 09:15:49 -0300 +Subject: ACPI: thinkpad-acpi: minor refactor on radio switch init + +Change the code of hotkey_init, wan_init and bluetooth_init a bit to make it +much easier to add some Kconfig-selected debugging code later. + +Signed-off-by: Henrique de Moraes Holschuh +--- + drivers/misc/thinkpad_acpi.c | 49 ++++++++++++++++++++++------------------- + 1 files changed, 26 insertions(+), 23 deletions(-) + +diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c +index b596929..c800855 100644 +--- a/drivers/misc/thinkpad_acpi.c ++++ b/drivers/misc/thinkpad_acpi.c +@@ -2167,9 +2167,10 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) + printk(TPACPI_INFO + "radio switch found; radios are %s\n", + enabled(status, 0)); ++ } ++ if (tp_features.hotkey_wlsw) + res = add_to_attr_set(hotkey_dev_attributes, + &dev_attr_hotkey_radio_sw.attr); +- } + + /* For X41t, X60t, X61t Tablets... */ + if (!res && acpi_evalf(hkey_handle, &status, "MHKG", "qd")) { +@@ -2646,18 +2647,19 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm) + str_supported(tp_features.bluetooth), + status); + ++ if (tp_features.bluetooth && ++ !(status & TP_ACPI_BLUETOOTH_HWPRESENT)) { ++ /* no bluetooth hardware present in system */ ++ tp_features.bluetooth = 0; ++ dbg_printk(TPACPI_DBG_INIT, ++ "bluetooth hardware not installed\n"); ++ } ++ + if (tp_features.bluetooth) { +- if (!(status & TP_ACPI_BLUETOOTH_HWPRESENT)) { +- /* no bluetooth hardware present in system */ +- tp_features.bluetooth = 0; +- dbg_printk(TPACPI_DBG_INIT, +- "bluetooth hardware not installed\n"); +- } else { +- res = sysfs_create_group(&tpacpi_pdev->dev.kobj, +- &bluetooth_attr_group); +- if (res) +- return res; +- } ++ res = sysfs_create_group(&tpacpi_pdev->dev.kobj, ++ &bluetooth_attr_group); ++ if (res) ++ return res; + } + + return (tp_features.bluetooth)? 0 : 1; +@@ -2818,18 +2820,19 @@ static int __init wan_init(struct ibm_init_struct *iibm) + str_supported(tp_features.wan), + status); + ++ if (tp_features.wan && ++ !(status & TP_ACPI_WANCARD_HWPRESENT)) { ++ /* no wan hardware present in system */ ++ tp_features.wan = 0; ++ dbg_printk(TPACPI_DBG_INIT, ++ "wan hardware not installed\n"); ++ } ++ + if (tp_features.wan) { +- if (!(status & TP_ACPI_WANCARD_HWPRESENT)) { +- /* no wan hardware present in system */ +- tp_features.wan = 0; +- dbg_printk(TPACPI_DBG_INIT, +- "wan hardware not installed\n"); +- } else { +- res = sysfs_create_group(&tpacpi_pdev->dev.kobj, +- &wan_attr_group); +- if (res) +- return res; +- } ++ res = sysfs_create_group(&tpacpi_pdev->dev.kobj, ++ &wan_attr_group); ++ if (res) ++ return res; + } + + return (tp_features.wan)? 0 : 1; +-- +1.5.6.2 + diff --git a/releases/upstream/2.6.27-rc1/0002-ACPI-thinkpad-acpi-consolidate-wlsw-notification-f.patch b/releases/upstream/2.6.27-rc1/0002-ACPI-thinkpad-acpi-consolidate-wlsw-notification-f.patch new file mode 100644 index 00000000000..0363bbefd72 --- /dev/null +++ b/releases/upstream/2.6.27-rc1/0002-ACPI-thinkpad-acpi-consolidate-wlsw-notification-f.patch @@ -0,0 +1,95 @@ +From 733e27c1cc86afae2d9481838693661b3d839950 Mon Sep 17 00:00:00 2001 +From: Henrique de Moraes Holschuh +Date: Mon, 21 Jul 2008 09:15:49 -0300 +Subject: ACPI: thinkpad-acpi: consolidate wlsw notification function + +Rename tpacpi_input_send_radiosw() to tpacpi_send_radiosw_update(), and +make it a central point to issue "radio switch changed state" notifications +by consolidating also the poll() notification in the same function. + +Signed-off-by: Henrique de Moraes Holschuh +--- + drivers/misc/thinkpad_acpi.c | 39 +++++++++++++++++++-------------------- + 1 files changed, 19 insertions(+), 20 deletions(-) + +diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c +index c800855..9179f23 100644 +--- a/drivers/misc/thinkpad_acpi.c ++++ b/drivers/misc/thinkpad_acpi.c +@@ -1285,21 +1285,6 @@ static int hotkey_status_set(int status) + return 0; + } + +-static void tpacpi_input_send_radiosw(void) +-{ +- int wlsw; +- +- if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw)) { +- mutex_lock(&tpacpi_inputdev_send_mutex); +- +- input_report_switch(tpacpi_inputdev, +- SW_RFKILL_ALL, !!wlsw); +- input_sync(tpacpi_inputdev); +- +- mutex_unlock(&tpacpi_inputdev_send_mutex); +- } +-} +- + static void tpacpi_input_send_tabletsw(void) + { + int state; +@@ -1921,6 +1906,22 @@ static struct attribute *hotkey_mask_attributes[] __initdata = { + &dev_attr_hotkey_wakeup_hotunplug_complete.attr, + }; + ++static void tpacpi_send_radiosw_update(void) ++{ ++ int wlsw; ++ ++ if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw)) { ++ mutex_lock(&tpacpi_inputdev_send_mutex); ++ ++ input_report_switch(tpacpi_inputdev, ++ SW_RFKILL_ALL, !!wlsw); ++ input_sync(tpacpi_inputdev); ++ ++ mutex_unlock(&tpacpi_inputdev_send_mutex); ++ } ++ hotkey_radio_sw_notify_change(); ++} ++ + static void hotkey_exit(void) + { + #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL +@@ -2288,7 +2289,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) + tpacpi_inputdev->close = &hotkey_inputdev_close; + + hotkey_poll_setup_safe(1); +- tpacpi_input_send_radiosw(); ++ tpacpi_send_radiosw_update(); + tpacpi_input_send_tabletsw(); + + return 0; +@@ -2420,8 +2421,7 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) + case 7: + /* 0x7000-0x7FFF: misc */ + if (tp_features.hotkey_wlsw && hkey == 0x7000) { +- tpacpi_input_send_radiosw(); +- hotkey_radio_sw_notify_change(); ++ tpacpi_send_radiosw_update(); + send_acpi_ev = 0; + break; + } +@@ -2464,8 +2464,7 @@ static void hotkey_resume(void) + printk(TPACPI_ERR + "error while trying to read hot key mask " + "from firmware\n"); +- tpacpi_input_send_radiosw(); +- hotkey_radio_sw_notify_change(); ++ tpacpi_send_radiosw_update(); + hotkey_tablet_mode_notify_change(); + hotkey_wakeup_reason_notify_change(); + hotkey_wakeup_hotunplug_complete_notify_change(); +-- +1.5.6.2 + diff --git a/releases/upstream/2.6.27-rc1/0003-ACPI-thinkpad-acpi-prepare-for-bluetooth-and-wwan.patch b/releases/upstream/2.6.27-rc1/0003-ACPI-thinkpad-acpi-prepare-for-bluetooth-and-wwan.patch new file mode 100644 index 00000000000..39fde4eb055 --- /dev/null +++ b/releases/upstream/2.6.27-rc1/0003-ACPI-thinkpad-acpi-prepare-for-bluetooth-and-wwan.patch @@ -0,0 +1,216 @@ +From 07431ec82bf9dc74b470a1d820b41c92c4d86e6f Mon Sep 17 00:00:00 2001 +From: Henrique de Moraes Holschuh +Date: Mon, 21 Jul 2008 09:15:50 -0300 +Subject: ACPI: thinkpad-acpi: prepare for bluetooth and wwan rfkill support + +Get rid of some forward definitions by moving code around, this will make +the rfkill conversion of wwan and bluetooth a bit cleaner. + +Signed-off-by: Henrique de Moraes Holschuh +--- + drivers/misc/thinkpad_acpi.c | 154 ++++++++++++++++++++---------------------- + 1 files changed, 74 insertions(+), 80 deletions(-) + +diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c +index 9179f23..743a4d6 100644 +--- a/drivers/misc/thinkpad_acpi.c ++++ b/drivers/misc/thinkpad_acpi.c +@@ -2581,8 +2581,37 @@ enum { + TP_ACPI_BLUETOOTH_UNK = 0x04, /* unknown function */ + }; + +-static int bluetooth_get_radiosw(void); +-static int bluetooth_set_radiosw(int radio_on); ++static int bluetooth_get_radiosw(void) ++{ ++ int status; ++ ++ if (!tp_features.bluetooth) ++ return -ENODEV; ++ ++ if (!acpi_evalf(hkey_handle, &status, "GBDC", "d")) ++ return -EIO; ++ ++ return (status & TP_ACPI_BLUETOOTH_RADIOSSW) != 0; ++} ++ ++static int bluetooth_set_radiosw(int radio_on) ++{ ++ int status; ++ ++ if (!tp_features.bluetooth) ++ return -ENODEV; ++ ++ if (!acpi_evalf(hkey_handle, &status, "GBDC", "d")) ++ return -EIO; ++ if (radio_on) ++ status |= TP_ACPI_BLUETOOTH_RADIOSSW; ++ else ++ status &= ~TP_ACPI_BLUETOOTH_RADIOSSW; ++ if (!acpi_evalf(hkey_handle, NULL, "SBDC", "vd", status)) ++ return -EIO; ++ ++ return 0; ++} + + /* sysfs bluetooth enable ---------------------------------------------- */ + static ssize_t bluetooth_enable_show(struct device *dev, +@@ -2628,6 +2657,12 @@ static const struct attribute_group bluetooth_attr_group = { + .attrs = bluetooth_attributes, + }; + ++static void bluetooth_exit(void) ++{ ++ sysfs_remove_group(&tpacpi_pdev->dev.kobj, ++ &bluetooth_attr_group); ++} ++ + static int __init bluetooth_init(struct ibm_init_struct *iibm) + { + int res; +@@ -2664,44 +2699,6 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm) + return (tp_features.bluetooth)? 0 : 1; + } + +-static void bluetooth_exit(void) +-{ +- sysfs_remove_group(&tpacpi_pdev->dev.kobj, +- &bluetooth_attr_group); +-} +- +-static int bluetooth_get_radiosw(void) +-{ +- int status; +- +- if (!tp_features.bluetooth) +- return -ENODEV; +- +- if (!acpi_evalf(hkey_handle, &status, "GBDC", "d")) +- return -EIO; +- +- return ((status & TP_ACPI_BLUETOOTH_RADIOSSW) != 0); +-} +- +-static int bluetooth_set_radiosw(int radio_on) +-{ +- int status; +- +- if (!tp_features.bluetooth) +- return -ENODEV; +- +- if (!acpi_evalf(hkey_handle, &status, "GBDC", "d")) +- return -EIO; +- if (radio_on) +- status |= TP_ACPI_BLUETOOTH_RADIOSSW; +- else +- status &= ~TP_ACPI_BLUETOOTH_RADIOSSW; +- if (!acpi_evalf(hkey_handle, NULL, "SBDC", "vd", status)) +- return -EIO; +- +- return 0; +-} +- + /* procfs -------------------------------------------------------------- */ + static int bluetooth_read(char *p) + { +@@ -2756,8 +2753,37 @@ enum { + TP_ACPI_WANCARD_UNK = 0x04, /* unknown function */ + }; + +-static int wan_get_radiosw(void); +-static int wan_set_radiosw(int radio_on); ++static int wan_get_radiosw(void) ++{ ++ int status; ++ ++ if (!tp_features.wan) ++ return -ENODEV; ++ ++ if (!acpi_evalf(hkey_handle, &status, "GWAN", "d")) ++ return -EIO; ++ ++ return (status & TP_ACPI_WANCARD_RADIOSSW) != 0; ++} ++ ++static int wan_set_radiosw(int radio_on) ++{ ++ int status; ++ ++ if (!tp_features.wan) ++ return -ENODEV; ++ ++ if (!acpi_evalf(hkey_handle, &status, "GWAN", "d")) ++ return -EIO; ++ if (radio_on) ++ status |= TP_ACPI_WANCARD_RADIOSSW; ++ else ++ status &= ~TP_ACPI_WANCARD_RADIOSSW; ++ if (!acpi_evalf(hkey_handle, NULL, "SWAN", "vd", status)) ++ return -EIO; ++ ++ return 0; ++} + + /* sysfs wan enable ---------------------------------------------------- */ + static ssize_t wan_enable_show(struct device *dev, +@@ -2803,6 +2829,12 @@ static const struct attribute_group wan_attr_group = { + .attrs = wan_attributes, + }; + ++static void wan_exit(void) ++{ ++ sysfs_remove_group(&tpacpi_pdev->dev.kobj, ++ &wan_attr_group); ++} ++ + static int __init wan_init(struct ibm_init_struct *iibm) + { + int res; +@@ -2837,44 +2869,6 @@ static int __init wan_init(struct ibm_init_struct *iibm) + return (tp_features.wan)? 0 : 1; + } + +-static void wan_exit(void) +-{ +- sysfs_remove_group(&tpacpi_pdev->dev.kobj, +- &wan_attr_group); +-} +- +-static int wan_get_radiosw(void) +-{ +- int status; +- +- if (!tp_features.wan) +- return -ENODEV; +- +- if (!acpi_evalf(hkey_handle, &status, "GWAN", "d")) +- return -EIO; +- +- return ((status & TP_ACPI_WANCARD_RADIOSSW) != 0); +-} +- +-static int wan_set_radiosw(int radio_on) +-{ +- int status; +- +- if (!tp_features.wan) +- return -ENODEV; +- +- if (!acpi_evalf(hkey_handle, &status, "GWAN", "d")) +- return -EIO; +- if (radio_on) +- status |= TP_ACPI_WANCARD_RADIOSSW; +- else +- status &= ~TP_ACPI_WANCARD_RADIOSSW; +- if (!acpi_evalf(hkey_handle, NULL, "SWAN", "vd", status)) +- return -EIO; +- +- return 0; +-} +- + /* procfs -------------------------------------------------------------- */ + static int wan_read(char *p) + { +-- +1.5.6.2 + diff --git a/releases/upstream/2.6.27-rc1/0004-ACPI-thinkpad-acpi-WLSW-overrides-other-rfkill-swi.patch b/releases/upstream/2.6.27-rc1/0004-ACPI-thinkpad-acpi-WLSW-overrides-other-rfkill-swi.patch new file mode 100644 index 00000000000..c664dc72190 --- /dev/null +++ b/releases/upstream/2.6.27-rc1/0004-ACPI-thinkpad-acpi-WLSW-overrides-other-rfkill-swi.patch @@ -0,0 +1,77 @@ +From 133ec3bd3ae409895eacdce326cdc8d73c249e8a Mon Sep 17 00:00:00 2001 +From: Henrique de Moraes Holschuh +Date: Mon, 21 Jul 2008 09:15:50 -0300 +Subject: ACPI: thinkpad-acpi: WLSW overrides other rfkill switches + +On ThinkPads where the WLSW switch exists, the firmware or the hardware +ANDs the WLSW state with the device-specific switches (WWAN, Bluetooth). +It is downright impossible to enable WWAN or Bluetooth when WLSW is +blocking the radios. + +This reality does not necessarily carry over to the WWAN and Bluetooth +firmware interfaces, though... so the state thinkpad-acpi was reporting +could be incorrect. + +Tie the three switches in the driver so that we keep their state sane. +When WLSL is off, force the other switches to off as well. + +Signed-off-by: Henrique de Moraes Holschuh +--- + drivers/misc/thinkpad_acpi.c | 20 ++++++++++++++++++++ + 1 files changed, 20 insertions(+), 0 deletions(-) + +diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c +index 743a4d6..202d63e 100644 +--- a/drivers/misc/thinkpad_acpi.c ++++ b/drivers/misc/thinkpad_acpi.c +@@ -2588,6 +2588,10 @@ static int bluetooth_get_radiosw(void) + if (!tp_features.bluetooth) + return -ENODEV; + ++ /* WLSW overrides bluetooth in firmware/hardware, reflect that */ ++ if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status) ++ return 0; ++ + if (!acpi_evalf(hkey_handle, &status, "GBDC", "d")) + return -EIO; + +@@ -2601,6 +2605,12 @@ static int bluetooth_set_radiosw(int radio_on) + if (!tp_features.bluetooth) + return -ENODEV; + ++ /* WLSW overrides bluetooth in firmware/hardware, but there is no ++ * reason to risk weird behaviour. */ ++ if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status ++ && radio_on) ++ return -EPERM; ++ + if (!acpi_evalf(hkey_handle, &status, "GBDC", "d")) + return -EIO; + if (radio_on) +@@ -2760,6 +2770,10 @@ static int wan_get_radiosw(void) + if (!tp_features.wan) + return -ENODEV; + ++ /* WLSW overrides WWAN in firmware/hardware, reflect that */ ++ if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status) ++ return 0; ++ + if (!acpi_evalf(hkey_handle, &status, "GWAN", "d")) + return -EIO; + +@@ -2773,6 +2787,12 @@ static int wan_set_radiosw(int radio_on) + if (!tp_features.wan) + return -ENODEV; + ++ /* WLSW overrides bluetooth in firmware/hardware, but there is no ++ * reason to risk weird behaviour. */ ++ if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status ++ && radio_on) ++ return -EPERM; ++ + if (!acpi_evalf(hkey_handle, &status, "GWAN", "d")) + return -EIO; + if (radio_on) +-- +1.5.6.2 + diff --git a/releases/upstream/2.6.27-rc1/0005-ACPI-thinkpad-acpi-add-bluetooth-and-WWAN-rfkill-s.patch b/releases/upstream/2.6.27-rc1/0005-ACPI-thinkpad-acpi-add-bluetooth-and-WWAN-rfkill-s.patch new file mode 100644 index 00000000000..73f0cc08220 --- /dev/null +++ b/releases/upstream/2.6.27-rc1/0005-ACPI-thinkpad-acpi-add-bluetooth-and-WWAN-rfkill-s.patch @@ -0,0 +1,487 @@ +From 0e74dc2646db04b644faa8ea10ff4f408d55cf90 Mon Sep 17 00:00:00 2001 +From: Henrique de Moraes Holschuh +Date: Mon, 21 Jul 2008 09:15:51 -0300 +Subject: ACPI: thinkpad-acpi: add bluetooth and WWAN rfkill support + +Add a read/write rfkill interface to the bluetooth radio switch on the +bluetooth submodule, and one for the wireless wan radio switch to the wan +submodule. + +Since rfkill does care for when a switch changes state, use WLSW +notifications to also check if the WWAN or Bluetooth switches did not +change state (due to them being slaves of WLSW in firmware/hardware, but +that reality not being always properly exported by the thinkpad firmware). + +Signed-off-by: Henrique de Moraes Holschuh +Cc: Ivo van Doorn +Cc: John W. Linville +--- + Documentation/laptops/thinkpad-acpi.txt | 22 +++- + drivers/misc/Kconfig | 2 + + drivers/misc/thinkpad_acpi.c | 208 +++++++++++++++++++++++++++---- + 3 files changed, 200 insertions(+), 32 deletions(-) + +diff --git a/Documentation/laptops/thinkpad-acpi.txt b/Documentation/laptops/thinkpad-acpi.txt +index 64b3f14..1c1c021 100644 +--- a/Documentation/laptops/thinkpad-acpi.txt ++++ b/Documentation/laptops/thinkpad-acpi.txt +@@ -621,7 +621,8 @@ Bluetooth + --------- + + procfs: /proc/acpi/ibm/bluetooth +-sysfs device attribute: bluetooth_enable ++sysfs device attribute: bluetooth_enable (deprecated) ++sysfs rfkill class: switch "tpacpi_bluetooth_sw" + + This feature shows the presence and current state of a ThinkPad + Bluetooth device in the internal ThinkPad CDC slot. +@@ -643,8 +644,12 @@ Sysfs notes: + 0: disables Bluetooth / Bluetooth is disabled + 1: enables Bluetooth / Bluetooth is enabled. + +- Note: this interface will be probably be superseded by the +- generic rfkill class, so it is NOT to be considered stable yet. ++ Note: this interface has been superseded by the generic rfkill ++ class. It has been deprecated, and it will be removed in year ++ 2010. ++ ++ rfkill controller switch "tpacpi_bluetooth_sw": refer to ++ Documentation/rfkill.txt for details. + + Video output control -- /proc/acpi/ibm/video + -------------------------------------------- +@@ -1374,7 +1379,8 @@ EXPERIMENTAL: WAN + ----------------- + + procfs: /proc/acpi/ibm/wan +-sysfs device attribute: wwan_enable ++sysfs device attribute: wwan_enable (deprecated) ++sysfs rfkill class: switch "tpacpi_wwan_sw" + + This feature is marked EXPERIMENTAL because the implementation + directly accesses hardware registers and may not work as expected. USE +@@ -1404,8 +1410,12 @@ Sysfs notes: + 0: disables WWAN card / WWAN card is disabled + 1: enables WWAN card / WWAN card is enabled. + +- Note: this interface will be probably be superseded by the +- generic rfkill class, so it is NOT to be considered stable yet. ++ Note: this interface has been superseded by the generic rfkill ++ class. It has been deprecated, and it will be removed in year ++ 2010. ++ ++ rfkill controller switch "tpacpi_wwan_sw": refer to ++ Documentation/rfkill.txt for details. + + Multiple Commands, Module Parameters + ------------------------------------ +diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig +index 1921b8d..b27ca91 100644 +--- a/drivers/misc/Kconfig ++++ b/drivers/misc/Kconfig +@@ -279,6 +279,8 @@ config THINKPAD_ACPI + select INPUT + select NEW_LEDS + select LEDS_CLASS ++ select NET ++ select RFKILL + ---help--- + This is a driver for the IBM and Lenovo ThinkPad laptops. It adds + support for Fn-Fx key combinations, Bluetooth control, video +diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c +index 202d63e..dc8d00a 100644 +--- a/drivers/misc/thinkpad_acpi.c ++++ b/drivers/misc/thinkpad_acpi.c +@@ -68,6 +68,7 @@ + #include + #include + #include ++#include + #include + + #include +@@ -144,6 +145,12 @@ enum { + + #define TPACPI_MAX_ACPI_ARGS 3 + ++/* rfkill switches */ ++enum { ++ TPACPI_RFK_BLUETOOTH_SW_ID = 0, ++ TPACPI_RFK_WWAN_SW_ID, ++}; ++ + /* Debugging */ + #define TPACPI_LOG TPACPI_FILE ": " + #define TPACPI_ERR KERN_ERR TPACPI_LOG +@@ -905,6 +912,43 @@ static int __init tpacpi_check_std_acpi_brightness_support(void) + return 0; + } + ++static int __init tpacpi_new_rfkill(const unsigned int id, ++ struct rfkill **rfk, ++ const enum rfkill_type rfktype, ++ const char *name, ++ int (*toggle_radio)(void *, enum rfkill_state), ++ int (*get_state)(void *, enum rfkill_state *)) ++{ ++ int res; ++ enum rfkill_state initial_state; ++ ++ *rfk = rfkill_allocate(&tpacpi_pdev->dev, rfktype); ++ if (!*rfk) { ++ printk(TPACPI_ERR ++ "failed to allocate memory for rfkill class\n"); ++ return -ENOMEM; ++ } ++ ++ (*rfk)->name = name; ++ (*rfk)->get_state = get_state; ++ (*rfk)->toggle_radio = toggle_radio; ++ ++ if (!get_state(NULL, &initial_state)) ++ (*rfk)->state = initial_state; ++ ++ res = rfkill_register(*rfk); ++ if (res < 0) { ++ printk(TPACPI_ERR ++ "failed to register %s rfkill switch: %d\n", ++ name, res); ++ rfkill_free(*rfk); ++ *rfk = NULL; ++ return res; ++ } ++ ++ return 0; ++} ++ + /************************************************************************* + * thinkpad-acpi driver attributes + */ +@@ -1906,10 +1950,18 @@ static struct attribute *hotkey_mask_attributes[] __initdata = { + &dev_attr_hotkey_wakeup_hotunplug_complete.attr, + }; + ++static void bluetooth_update_rfk(void); ++static void wan_update_rfk(void); + static void tpacpi_send_radiosw_update(void) + { + int wlsw; + ++ /* Sync these BEFORE sending any rfkill events */ ++ if (tp_features.bluetooth) ++ bluetooth_update_rfk(); ++ if (tp_features.wan) ++ wan_update_rfk(); ++ + if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw)) { + mutex_lock(&tpacpi_inputdev_send_mutex); + +@@ -2581,6 +2633,8 @@ enum { + TP_ACPI_BLUETOOTH_UNK = 0x04, /* unknown function */ + }; + ++static struct rfkill *tpacpi_bluetooth_rfkill; ++ + static int bluetooth_get_radiosw(void) + { + int status; +@@ -2590,15 +2644,29 @@ static int bluetooth_get_radiosw(void) + + /* WLSW overrides bluetooth in firmware/hardware, reflect that */ + if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status) +- return 0; ++ return RFKILL_STATE_HARD_BLOCKED; + + if (!acpi_evalf(hkey_handle, &status, "GBDC", "d")) + return -EIO; + +- return (status & TP_ACPI_BLUETOOTH_RADIOSSW) != 0; ++ return ((status & TP_ACPI_BLUETOOTH_RADIOSSW) != 0) ? ++ RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED; + } + +-static int bluetooth_set_radiosw(int radio_on) ++static void bluetooth_update_rfk(void) ++{ ++ int status; ++ ++ if (!tpacpi_bluetooth_rfkill) ++ return; ++ ++ status = bluetooth_get_radiosw(); ++ if (status < 0) ++ return; ++ rfkill_force_state(tpacpi_bluetooth_rfkill, status); ++} ++ ++static int bluetooth_set_radiosw(int radio_on, int update_rfk) + { + int status; + +@@ -2620,6 +2688,9 @@ static int bluetooth_set_radiosw(int radio_on) + if (!acpi_evalf(hkey_handle, NULL, "SBDC", "vd", status)) + return -EIO; + ++ if (update_rfk) ++ bluetooth_update_rfk(); ++ + return 0; + } + +@@ -2634,7 +2705,8 @@ static ssize_t bluetooth_enable_show(struct device *dev, + if (status < 0) + return status; + +- return snprintf(buf, PAGE_SIZE, "%d\n", status ? 1 : 0); ++ return snprintf(buf, PAGE_SIZE, "%d\n", ++ (status == RFKILL_STATE_UNBLOCKED) ? 1 : 0); + } + + static ssize_t bluetooth_enable_store(struct device *dev, +@@ -2647,7 +2719,7 @@ static ssize_t bluetooth_enable_store(struct device *dev, + if (parse_strtoul(buf, 1, &t)) + return -EINVAL; + +- res = bluetooth_set_radiosw(t); ++ res = bluetooth_set_radiosw(t, 1); + + return (res) ? res : count; + } +@@ -2667,8 +2739,27 @@ static const struct attribute_group bluetooth_attr_group = { + .attrs = bluetooth_attributes, + }; + ++static int tpacpi_bluetooth_rfk_get(void *data, enum rfkill_state *state) ++{ ++ int bts = bluetooth_get_radiosw(); ++ ++ if (bts < 0) ++ return bts; ++ ++ *state = bts; ++ return 0; ++} ++ ++static int tpacpi_bluetooth_rfk_set(void *data, enum rfkill_state state) ++{ ++ return bluetooth_set_radiosw((state == RFKILL_STATE_UNBLOCKED), 0); ++} ++ + static void bluetooth_exit(void) + { ++ if (tpacpi_bluetooth_rfkill) ++ rfkill_unregister(tpacpi_bluetooth_rfkill); ++ + sysfs_remove_group(&tpacpi_pdev->dev.kobj, + &bluetooth_attr_group); + } +@@ -2699,14 +2790,26 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm) + "bluetooth hardware not installed\n"); + } + +- if (tp_features.bluetooth) { +- res = sysfs_create_group(&tpacpi_pdev->dev.kobj, ++ if (!tp_features.bluetooth) ++ return 1; ++ ++ res = sysfs_create_group(&tpacpi_pdev->dev.kobj, + &bluetooth_attr_group); +- if (res) +- return res; ++ if (res) ++ return res; ++ ++ res = tpacpi_new_rfkill(TPACPI_RFK_BLUETOOTH_SW_ID, ++ &tpacpi_bluetooth_rfkill, ++ RFKILL_TYPE_BLUETOOTH, ++ "tpacpi_bluetooth_sw", ++ tpacpi_bluetooth_rfk_set, ++ tpacpi_bluetooth_rfk_get); ++ if (res) { ++ bluetooth_exit(); ++ return res; + } + +- return (tp_features.bluetooth)? 0 : 1; ++ return 0; + } + + /* procfs -------------------------------------------------------------- */ +@@ -2719,7 +2822,8 @@ static int bluetooth_read(char *p) + len += sprintf(p + len, "status:\t\tnot supported\n"); + else { + len += sprintf(p + len, "status:\t\t%s\n", +- (status)? "enabled" : "disabled"); ++ (status == RFKILL_STATE_UNBLOCKED) ? ++ "enabled" : "disabled"); + len += sprintf(p + len, "commands:\tenable, disable\n"); + } + +@@ -2735,9 +2839,9 @@ static int bluetooth_write(char *buf) + + while ((cmd = next_cmd(&buf))) { + if (strlencmp(cmd, "enable") == 0) { +- bluetooth_set_radiosw(1); ++ bluetooth_set_radiosw(1, 1); + } else if (strlencmp(cmd, "disable") == 0) { +- bluetooth_set_radiosw(0); ++ bluetooth_set_radiosw(0, 1); + } else + return -EINVAL; + } +@@ -2763,6 +2867,8 @@ enum { + TP_ACPI_WANCARD_UNK = 0x04, /* unknown function */ + }; + ++static struct rfkill *tpacpi_wan_rfkill; ++ + static int wan_get_radiosw(void) + { + int status; +@@ -2772,15 +2878,29 @@ static int wan_get_radiosw(void) + + /* WLSW overrides WWAN in firmware/hardware, reflect that */ + if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status) +- return 0; ++ return RFKILL_STATE_HARD_BLOCKED; + + if (!acpi_evalf(hkey_handle, &status, "GWAN", "d")) + return -EIO; + +- return (status & TP_ACPI_WANCARD_RADIOSSW) != 0; ++ return ((status & TP_ACPI_WANCARD_RADIOSSW) != 0) ? ++ RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED; + } + +-static int wan_set_radiosw(int radio_on) ++static void wan_update_rfk(void) ++{ ++ int status; ++ ++ if (!tpacpi_wan_rfkill) ++ return; ++ ++ status = wan_get_radiosw(); ++ if (status < 0) ++ return; ++ rfkill_force_state(tpacpi_wan_rfkill, status); ++} ++ ++static int wan_set_radiosw(int radio_on, int update_rfk) + { + int status; + +@@ -2802,6 +2922,9 @@ static int wan_set_radiosw(int radio_on) + if (!acpi_evalf(hkey_handle, NULL, "SWAN", "vd", status)) + return -EIO; + ++ if (update_rfk) ++ wan_update_rfk(); ++ + return 0; + } + +@@ -2816,7 +2939,8 @@ static ssize_t wan_enable_show(struct device *dev, + if (status < 0) + return status; + +- return snprintf(buf, PAGE_SIZE, "%d\n", status ? 1 : 0); ++ return snprintf(buf, PAGE_SIZE, "%d\n", ++ (status == RFKILL_STATE_UNBLOCKED) ? 1 : 0); + } + + static ssize_t wan_enable_store(struct device *dev, +@@ -2829,7 +2953,7 @@ static ssize_t wan_enable_store(struct device *dev, + if (parse_strtoul(buf, 1, &t)) + return -EINVAL; + +- res = wan_set_radiosw(t); ++ res = wan_set_radiosw(t, 1); + + return (res) ? res : count; + } +@@ -2849,8 +2973,27 @@ static const struct attribute_group wan_attr_group = { + .attrs = wan_attributes, + }; + ++static int tpacpi_wan_rfk_get(void *data, enum rfkill_state *state) ++{ ++ int wans = wan_get_radiosw(); ++ ++ if (wans < 0) ++ return wans; ++ ++ *state = wans; ++ return 0; ++} ++ ++static int tpacpi_wan_rfk_set(void *data, enum rfkill_state state) ++{ ++ return wan_set_radiosw((state == RFKILL_STATE_UNBLOCKED), 0); ++} ++ + static void wan_exit(void) + { ++ if (tpacpi_wan_rfkill) ++ rfkill_unregister(tpacpi_wan_rfkill); ++ + sysfs_remove_group(&tpacpi_pdev->dev.kobj, + &wan_attr_group); + } +@@ -2879,14 +3022,26 @@ static int __init wan_init(struct ibm_init_struct *iibm) + "wan hardware not installed\n"); + } + +- if (tp_features.wan) { +- res = sysfs_create_group(&tpacpi_pdev->dev.kobj, ++ if (!tp_features.wan) ++ return 1; ++ ++ res = sysfs_create_group(&tpacpi_pdev->dev.kobj, + &wan_attr_group); +- if (res) +- return res; ++ if (res) ++ return res; ++ ++ res = tpacpi_new_rfkill(TPACPI_RFK_WWAN_SW_ID, ++ &tpacpi_wan_rfkill, ++ RFKILL_TYPE_WWAN, ++ "tpacpi_wwan_sw", ++ tpacpi_wan_rfk_set, ++ tpacpi_wan_rfk_get); ++ if (res) { ++ wan_exit(); ++ return res; + } + +- return (tp_features.wan)? 0 : 1; ++ return 0; + } + + /* procfs -------------------------------------------------------------- */ +@@ -2899,7 +3054,8 @@ static int wan_read(char *p) + len += sprintf(p + len, "status:\t\tnot supported\n"); + else { + len += sprintf(p + len, "status:\t\t%s\n", +- (status)? "enabled" : "disabled"); ++ (status == RFKILL_STATE_UNBLOCKED) ? ++ "enabled" : "disabled"); + len += sprintf(p + len, "commands:\tenable, disable\n"); + } + +@@ -2915,9 +3071,9 @@ static int wan_write(char *buf) + + while ((cmd = next_cmd(&buf))) { + if (strlencmp(cmd, "enable") == 0) { +- wan_set_radiosw(1); ++ wan_set_radiosw(1, 1); + } else if (strlencmp(cmd, "disable") == 0) { +- wan_set_radiosw(0); ++ wan_set_radiosw(0, 1); + } else + return -EINVAL; + } +-- +1.5.6.2 + diff --git a/releases/upstream/2.6.27-rc1/0006-ACPI-thinkpad-acpi-bump-up-version-to-0.21.patch b/releases/upstream/2.6.27-rc1/0006-ACPI-thinkpad-acpi-bump-up-version-to-0.21.patch new file mode 100644 index 00000000000..0f423b507e9 --- /dev/null +++ b/releases/upstream/2.6.27-rc1/0006-ACPI-thinkpad-acpi-bump-up-version-to-0.21.patch @@ -0,0 +1,43 @@ +From 490673dc98adfc7de1703cc88508902bd10f446b Mon Sep 17 00:00:00 2001 +From: Henrique de Moraes Holschuh +Date: Mon, 21 Jul 2008 09:15:51 -0300 +Subject: ACPI: thinkpad-acpi: bump up version to 0.21 + +rfkill support deserves a new version checkpoint... + +Signed-off-by: Henrique de Moraes Holschuh +--- + Documentation/laptops/thinkpad-acpi.txt | 4 ++-- + drivers/misc/thinkpad_acpi.c | 2 +- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/Documentation/laptops/thinkpad-acpi.txt b/Documentation/laptops/thinkpad-acpi.txt +index 1c1c021..02dc748 100644 +--- a/Documentation/laptops/thinkpad-acpi.txt ++++ b/Documentation/laptops/thinkpad-acpi.txt +@@ -1,7 +1,7 @@ + ThinkPad ACPI Extras Driver + +- Version 0.20 +- April 09th, 2008 ++ Version 0.21 ++ May 29th, 2008 + + Borislav Deianov + Henrique de Moraes Holschuh +diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c +index dc8d00a..3eb01af 100644 +--- a/drivers/misc/thinkpad_acpi.c ++++ b/drivers/misc/thinkpad_acpi.c +@@ -21,7 +21,7 @@ + * 02110-1301, USA. + */ + +-#define TPACPI_VERSION "0.20" ++#define TPACPI_VERSION "0.21" + #define TPACPI_SYSFS_VERSION 0x020200 + + /* +-- +1.5.6.2 + diff --git a/releases/upstream/2.6.27-rc1/0007-ACPI-thinkpad-acpi-don-t-misdetect-in-get_thinkpad.patch b/releases/upstream/2.6.27-rc1/0007-ACPI-thinkpad-acpi-don-t-misdetect-in-get_thinkpad.patch new file mode 100644 index 00000000000..81aa88b14ec --- /dev/null +++ b/releases/upstream/2.6.27-rc1/0007-ACPI-thinkpad-acpi-don-t-misdetect-in-get_thinkpad.patch @@ -0,0 +1,114 @@ +From bf20e740a4bcc686de02e2fd1c1810a58872f46e Mon Sep 17 00:00:00 2001 +From: Henrique de Moraes Holschuh +Date: Mon, 21 Jul 2008 09:15:51 -0300 +Subject: ACPI: thinkpad-acpi: don't misdetect in get_thinkpad_model_data() on -ENOMEM + +Explicitly check for memory allocation failures, and return status to +indicate that we could not collect data due to errors. + +This lets the driver have a far more predictable failure mode on ENOMEM in +that codepath: it will refuse to load. This is far better than trying to +proceed with missing data which is used to detect quirks, etc. + +Signed-off-by: Henrique de Moraes Holschuh +--- + drivers/misc/thinkpad_acpi.c | 47 +++++++++++++++++++++++++++++------------ + 1 files changed, 33 insertions(+), 14 deletions(-) + +diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c +index 3eb01af..d3eb790 100644 +--- a/drivers/misc/thinkpad_acpi.c ++++ b/drivers/misc/thinkpad_acpi.c +@@ -6340,13 +6340,18 @@ err_out: + + /* Probing */ + +-static void __init get_thinkpad_model_data(struct thinkpad_id_data *tp) ++/* returns 0 - probe ok, or < 0 - probe error. ++ * Probe ok doesn't mean thinkpad found. ++ * On error, kfree() cleanup on tp->* is not performed, caller must do it */ ++static int __must_check __init get_thinkpad_model_data( ++ struct thinkpad_id_data *tp) + { + const struct dmi_device *dev = NULL; + char ec_fw_string[18]; ++ char const *s; + + if (!tp) +- return; ++ return -EINVAL; + + memset(tp, 0, sizeof(*tp)); + +@@ -6355,12 +6360,14 @@ static void __init get_thinkpad_model_data(struct thinkpad_id_data *tp) + else if (dmi_name_in_vendors("LENOVO")) + tp->vendor = PCI_VENDOR_ID_LENOVO; + else +- return; ++ return 0; + +- tp->bios_version_str = kstrdup(dmi_get_system_info(DMI_BIOS_VERSION), +- GFP_KERNEL); ++ s = dmi_get_system_info(DMI_BIOS_VERSION); ++ tp->bios_version_str = kstrdup(s, GFP_KERNEL); ++ if (s && !tp->bios_version_str) ++ return -ENOMEM; + if (!tp->bios_version_str) +- return; ++ return 0; + tp->bios_model = tp->bios_version_str[0] + | (tp->bios_version_str[1] << 8); + +@@ -6379,21 +6386,27 @@ static void __init get_thinkpad_model_data(struct thinkpad_id_data *tp) + ec_fw_string[strcspn(ec_fw_string, " ]")] = 0; + + tp->ec_version_str = kstrdup(ec_fw_string, GFP_KERNEL); ++ if (!tp->ec_version_str) ++ return -ENOMEM; + tp->ec_model = ec_fw_string[0] + | (ec_fw_string[1] << 8); + break; + } + } + +- tp->model_str = kstrdup(dmi_get_system_info(DMI_PRODUCT_VERSION), +- GFP_KERNEL); +- if (tp->model_str && strnicmp(tp->model_str, "ThinkPad", 8) != 0) { +- kfree(tp->model_str); +- tp->model_str = NULL; ++ s = dmi_get_system_info(DMI_PRODUCT_VERSION); ++ if (s && !strnicmp(s, "ThinkPad", 8)) { ++ tp->model_str = kstrdup(s, GFP_KERNEL); ++ if (!tp->model_str) ++ return -ENOMEM; + } + +- tp->nummodel_str = kstrdup(dmi_get_system_info(DMI_PRODUCT_NAME), +- GFP_KERNEL); ++ s = dmi_get_system_info(DMI_PRODUCT_NAME); ++ tp->nummodel_str = kstrdup(s, GFP_KERNEL); ++ if (s && !tp->nummodel_str) ++ return -ENOMEM; ++ ++ return 0; + } + + static int __init probe_for_thinkpad(void) +@@ -6656,7 +6669,13 @@ static int __init thinkpad_acpi_module_init(void) + + /* Driver-level probe */ + +- get_thinkpad_model_data(&thinkpad_id); ++ ret = get_thinkpad_model_data(&thinkpad_id); ++ if (ret) { ++ printk(TPACPI_ERR ++ "unable to get DMI data: %d\n", ret); ++ thinkpad_acpi_module_exit(); ++ return ret; ++ } + ret = probe_for_thinkpad(); + if (ret) { + thinkpad_acpi_module_exit(); +-- +1.5.6.2 + -- 2.11.4.GIT