Commit 6ed3e57f authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'platform-drivers-x86-v3.20-1' of...

Merge tag 'platform-drivers-x86-v3.20-1' of git://git.infradead.org/users/dvhart/linux-platform-drivers-x86

Pull platform driver update from Darren Hart:
 "This includes a significant update to the toshiba_acpi driver,
  bringing it to feature parity with the Windows driver, followed by
  some needed cleanups.

  The other changes are mostly minor updates, quirks, sparse fixes, or
  cleanups.

  Details:

   - toshiba_acpi:
       Add support for missing features from the Windows driver, bump the
       sysfs version, and clean up the driver.

   - thinkpad_acpi:
       BIOS string versions, unhandled hkey events.

   - msamsung-laptop:
       Add native backlight quirk, enable better lid handling.

   - intel_scu_ipc:
       Read resources from PCI configuration

   - other:
       Fix sparse warnings, general cleanups"

* tag 'platform-drivers-x86-v3.20-1' of git://git.infradead.org/users/dvhart/linux-platform-drivers-x86: (34 commits)
  toshiba_acpi: Cleanup GPL header
  toshiba_acpi: Cleanup comment blocks and capitalization
  toshiba_acpi: Make use of DEVICE_ATTR_{RO, RW} macros
  toshiba_acpi: Drop the toshiba_ prefix from sysfs function names
  toshiba_acpi: Move sysfs function and struct declarations further down
  Documentation/ABI: Add file describing the sysfs entries for toshiba_acpi
  toshiba_acpi: Clean file according to coding style
  toshiba_acpi: Bump version number to 0.21
  toshiba_acpi: Add support to enable/disable USB 3
  toshiba_acpi: Add support for Panel Power ON
  toshiba_acpi: Add support for Keyboard functions mode
  toshiba_acpi: Add fan entry to sysfs
  toshiba_acpi: Add version entry to sysfs
  thinkpad_acpi: support new BIOS version string pattern
  thinkpad_acpi: unhandled hkey event
  toshiba_acpi: Make toshiba_eco_mode_available more robust
  classmate-laptop: Fix sparse warning (0 as NULL)
  Sony-laptop: Fix sparse warning (make undeclared var static)
  thinkpad_acpi.c: Fix sparse warning (make undeclared var static)
  samsung-laptop.c: Prefer kstrtoint over single variable sscanf
  ...
parents b11a2783 c57c0fa4
...@@ -35,3 +35,11 @@ Contact: Corentin Chary <corentin.chary@gmail.com> ...@@ -35,3 +35,11 @@ Contact: Corentin Chary <corentin.chary@gmail.com>
Description: Use your USB ports to charge devices, even Description: Use your USB ports to charge devices, even
when your laptop is powered off. when your laptop is powered off.
1 means enabled, 0 means disabled. 1 means enabled, 0 means disabled.
What: /sys/devices/platform/samsung/lid_handling
Date: December 11, 2014
KernelVersion: 3.19
Contact: Julijonas Kikutis <julijonas.kikutis@gmail.com>
Description: Some Samsung laptops handle lid closing quicker and
only handle lid opening with this mode enabled.
1 means enabled, 0 means disabled.
What: /sys/devices/LNXSYSTM:00/LNXSYBUS:00/TOS{1900,620{0,7,8}}:00/kbd_backlight_mode
Date: June 8, 2014
KernelVersion: 3.15
Contact: Azael Avalos <coproscefalo@gmail.com>
Description: This file controls the keyboard backlight operation mode, valid
values are:
* 0x1 -> FN-Z
* 0x2 -> AUTO (also called TIMER)
* 0x8 -> ON
* 0x10 -> OFF
Note that the kernel 3.16 onwards this file accepts all listed
parameters, kernel 3.15 only accepts the first two (FN-Z and
AUTO).
Users: KToshiba
What: /sys/devices/LNXSYSTM:00/LNXSYBUS:00/TOS{1900,620{0,7,8}}:00/kbd_backlight_timeout
Date: June 8, 2014
KernelVersion: 3.15
Contact: Azael Avalos <coproscefalo@gmail.com>
Description: This file controls the timeout of the keyboard backlight
whenever the operation mode is set to AUTO (or TIMER),
valid values range from 0-60.
Note that the kernel 3.15 only had support for the first
keyboard type, the kernel 3.16 added support for the second
type and the range accepted for type 2 is 1-60.
See the entry named "kbd_type"
Users: KToshiba
What: /sys/devices/LNXSYSTM:00/LNXSYBUS:00/TOS{1900,620{0,7,8}}:00/position
Date: June 8, 2014
KernelVersion: 3.15
Contact: Azael Avalos <coproscefalo@gmail.com>
Description: This file shows the absolute position of the built-in
accelereometer.
What: /sys/devices/LNXSYSTM:00/LNXSYBUS:00/TOS{1900,620{0,7,8}}:00/touchpad
Date: June 8, 2014
KernelVersion: 3.15
Contact: Azael Avalos <coproscefalo@gmail.com>
Description: This files controls the status of the touchpad and pointing
stick (if available), valid values are:
* 0 -> OFF
* 1 -> ON
Users: KToshiba
What: /sys/devices/LNXSYSTM:00/LNXSYBUS:00/TOS{1900,620{0,7,8}}:00/available_kbd_modes
Date: August 3, 2014
KernelVersion: 3.16
Contact: Azael Avalos <coproscefalo@gmail.com>
Description: This file shows the supported keyboard backlight modes
the system supports, which can be:
* 0x1 -> FN-Z
* 0x2 -> AUTO (also called TIMER)
* 0x8 -> ON
* 0x10 -> OFF
Note that not all keyboard types support the listed modes.
See the entry named "available_kbd_modes"
Users: KToshiba
What: /sys/devices/LNXSYSTM:00/LNXSYBUS:00/TOS{1900,620{0,7,8}}:00/kbd_type
Date: August 3, 2014
KernelVersion: 3.16
Contact: Azael Avalos <coproscefalo@gmail.com>
Description: This file shows the current keyboard backlight type,
which can be:
* 1 -> Type 1, supporting modes FN-Z and AUTO
* 2 -> Type 2, supporting modes TIMER, ON and OFF
Users: KToshiba
What: /sys/devices/LNXSYSTM:00/LNXSYBUS:00/TOS{1900,620{0,7,8}}:00/version
Date: February, 2015
KernelVersion: 3.20
Contact: Azael Avalos <coproscefalo@gmail.com>
Description: This file shows the current version of the driver
What: /sys/devices/LNXSYSTM:00/LNXSYBUS:00/TOS{1900,620{0,7,8}}:00/fan
Date: February, 2015
KernelVersion: 3.20
Contact: Azael Avalos <coproscefalo@gmail.com>
Description: This file controls the state of the internal fan, valid
values are:
* 0 -> OFF
* 1 -> ON
What: /sys/devices/LNXSYSTM:00/LNXSYBUS:00/TOS{1900,620{0,7,8}}:00/kbd_function_keys
Date: February, 2015
KernelVersion: 3.20
Contact: Azael Avalos <coproscefalo@gmail.com>
Description: This file controls the Special Functions (hotkeys) operation
mode, valid values are:
* 0 -> Normal Operation
* 1 -> Special Functions
In the "Normal Operation" mode, the F{1-12} keys are as usual
and the hotkeys are accessed via FN-F{1-12}.
In the "Special Functions" mode, the F{1-12} keys trigger the
hotkey and the F{1-12} keys are accessed via FN-F{1-12}.
What: /sys/devices/LNXSYSTM:00/LNXSYBUS:00/TOS{1900,620{0,7,8}}:00/panel_power_on
Date: February, 2015
KernelVersion: 3.20
Contact: Azael Avalos <coproscefalo@gmail.com>
Description: This file controls whether the laptop should turn ON whenever
the LID is opened, valid values are:
* 0 -> Disabled
* 1 -> Enabled
What: /sys/devices/LNXSYSTM:00/LNXSYBUS:00/TOS{1900,620{0,7,8}}:00/usb_three
Date: February, 2015
KernelVersion: 3.20
Contact: Azael Avalos <coproscefalo@gmail.com>
Description: This file controls whether the USB 3 functionality, valid
values are:
* 0 -> Disabled (Acts as a regular USB 2)
* 1 -> Enabled (Full USB 3 functionality)
...@@ -856,8 +856,8 @@ static void asus_backlight_exit(struct asus_laptop *asus) ...@@ -856,8 +856,8 @@ static void asus_backlight_exit(struct asus_laptop *asus)
* than count bytes. We set eof to 1 if we handle those 2 values. We return the * than count bytes. We set eof to 1 if we handle those 2 values. We return the
* number of bytes written in page * number of bytes written in page
*/ */
static ssize_t show_infos(struct device *dev, static ssize_t infos_show(struct device *dev, struct device_attribute *attr,
struct device_attribute *attr, char *page) char *page)
{ {
struct asus_laptop *asus = dev_get_drvdata(dev); struct asus_laptop *asus = dev_get_drvdata(dev);
int len = 0; int len = 0;
...@@ -926,6 +926,7 @@ static ssize_t show_infos(struct device *dev, ...@@ -926,6 +926,7 @@ static ssize_t show_infos(struct device *dev,
return len; return len;
} }
static DEVICE_ATTR_RO(infos);
static int parse_arg(const char *buf, unsigned long count, int *val) static int parse_arg(const char *buf, unsigned long count, int *val)
{ {
...@@ -957,15 +958,15 @@ static ssize_t sysfs_acpi_set(struct asus_laptop *asus, ...@@ -957,15 +958,15 @@ static ssize_t sysfs_acpi_set(struct asus_laptop *asus,
/* /*
* LEDD display * LEDD display
*/ */
static ssize_t show_ledd(struct device *dev, static ssize_t ledd_show(struct device *dev, struct device_attribute *attr,
struct device_attribute *attr, char *buf) char *buf)
{ {
struct asus_laptop *asus = dev_get_drvdata(dev); struct asus_laptop *asus = dev_get_drvdata(dev);
return sprintf(buf, "0x%08x\n", asus->ledd_status); return sprintf(buf, "0x%08x\n", asus->ledd_status);
} }
static ssize_t store_ledd(struct device *dev, struct device_attribute *attr, static ssize_t ledd_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct asus_laptop *asus = dev_get_drvdata(dev); struct asus_laptop *asus = dev_get_drvdata(dev);
...@@ -981,6 +982,7 @@ static ssize_t store_ledd(struct device *dev, struct device_attribute *attr, ...@@ -981,6 +982,7 @@ static ssize_t store_ledd(struct device *dev, struct device_attribute *attr,
} }
return rv; return rv;
} }
static DEVICE_ATTR_RW(ledd);
/* /*
* Wireless * Wireless
...@@ -1014,21 +1016,22 @@ static int asus_wlan_set(struct asus_laptop *asus, int status) ...@@ -1014,21 +1016,22 @@ static int asus_wlan_set(struct asus_laptop *asus, int status)
return 0; return 0;
} }
static ssize_t show_wlan(struct device *dev, static ssize_t wlan_show(struct device *dev, struct device_attribute *attr,
struct device_attribute *attr, char *buf) char *buf)
{ {
struct asus_laptop *asus = dev_get_drvdata(dev); struct asus_laptop *asus = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", asus_wireless_status(asus, WL_RSTS)); return sprintf(buf, "%d\n", asus_wireless_status(asus, WL_RSTS));
} }
static ssize_t store_wlan(struct device *dev, struct device_attribute *attr, static ssize_t wlan_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct asus_laptop *asus = dev_get_drvdata(dev); struct asus_laptop *asus = dev_get_drvdata(dev);
return sysfs_acpi_set(asus, buf, count, METHOD_WLAN); return sysfs_acpi_set(asus, buf, count, METHOD_WLAN);
} }
static DEVICE_ATTR_RW(wlan);
/*e /*e
* Bluetooth * Bluetooth
...@@ -1042,15 +1045,15 @@ static int asus_bluetooth_set(struct asus_laptop *asus, int status) ...@@ -1042,15 +1045,15 @@ static int asus_bluetooth_set(struct asus_laptop *asus, int status)
return 0; return 0;
} }
static ssize_t show_bluetooth(struct device *dev, static ssize_t bluetooth_show(struct device *dev, struct device_attribute *attr,
struct device_attribute *attr, char *buf) char *buf)
{ {
struct asus_laptop *asus = dev_get_drvdata(dev); struct asus_laptop *asus = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", asus_wireless_status(asus, BT_RSTS)); return sprintf(buf, "%d\n", asus_wireless_status(asus, BT_RSTS));
} }
static ssize_t store_bluetooth(struct device *dev, static ssize_t bluetooth_store(struct device *dev,
struct device_attribute *attr, const char *buf, struct device_attribute *attr, const char *buf,
size_t count) size_t count)
{ {
...@@ -1058,6 +1061,7 @@ static ssize_t store_bluetooth(struct device *dev, ...@@ -1058,6 +1061,7 @@ static ssize_t store_bluetooth(struct device *dev,
return sysfs_acpi_set(asus, buf, count, METHOD_BLUETOOTH); return sysfs_acpi_set(asus, buf, count, METHOD_BLUETOOTH);
} }
static DEVICE_ATTR_RW(bluetooth);
/* /*
* Wimax * Wimax
...@@ -1071,22 +1075,22 @@ static int asus_wimax_set(struct asus_laptop *asus, int status) ...@@ -1071,22 +1075,22 @@ static int asus_wimax_set(struct asus_laptop *asus, int status)
return 0; return 0;
} }
static ssize_t show_wimax(struct device *dev, static ssize_t wimax_show(struct device *dev, struct device_attribute *attr,
struct device_attribute *attr, char *buf) char *buf)
{ {
struct asus_laptop *asus = dev_get_drvdata(dev); struct asus_laptop *asus = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", asus_wireless_status(asus, WM_RSTS)); return sprintf(buf, "%d\n", asus_wireless_status(asus, WM_RSTS));
} }
static ssize_t store_wimax(struct device *dev, static ssize_t wimax_store(struct device *dev, struct device_attribute *attr,
struct device_attribute *attr, const char *buf, const char *buf, size_t count)
size_t count)
{ {
struct asus_laptop *asus = dev_get_drvdata(dev); struct asus_laptop *asus = dev_get_drvdata(dev);
return sysfs_acpi_set(asus, buf, count, METHOD_WIMAX); return sysfs_acpi_set(asus, buf, count, METHOD_WIMAX);
} }
static DEVICE_ATTR_RW(wimax);
/* /*
* Wwan * Wwan
...@@ -1100,22 +1104,22 @@ static int asus_wwan_set(struct asus_laptop *asus, int status) ...@@ -1100,22 +1104,22 @@ static int asus_wwan_set(struct asus_laptop *asus, int status)
return 0; return 0;
} }
static ssize_t show_wwan(struct device *dev, static ssize_t wwan_show(struct device *dev, struct device_attribute *attr,
struct device_attribute *attr, char *buf) char *buf)
{ {
struct asus_laptop *asus = dev_get_drvdata(dev); struct asus_laptop *asus = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", asus_wireless_status(asus, WW_RSTS)); return sprintf(buf, "%d\n", asus_wireless_status(asus, WW_RSTS));
} }
static ssize_t store_wwan(struct device *dev, static ssize_t wwan_store(struct device *dev, struct device_attribute *attr,
struct device_attribute *attr, const char *buf, const char *buf, size_t count)
size_t count)
{ {
struct asus_laptop *asus = dev_get_drvdata(dev); struct asus_laptop *asus = dev_get_drvdata(dev);
return sysfs_acpi_set(asus, buf, count, METHOD_WWAN); return sysfs_acpi_set(asus, buf, count, METHOD_WWAN);
} }
static DEVICE_ATTR_RW(wwan);
/* /*
* Display * Display
...@@ -1135,7 +1139,7 @@ static void asus_set_display(struct asus_laptop *asus, int value) ...@@ -1135,7 +1139,7 @@ static void asus_set_display(struct asus_laptop *asus, int value)
* displays hooked up simultaneously, so be warned. See the acpi4asus README * displays hooked up simultaneously, so be warned. See the acpi4asus README
* for more info. * for more info.
*/ */
static ssize_t store_disp(struct device *dev, struct device_attribute *attr, static ssize_t display_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct asus_laptop *asus = dev_get_drvdata(dev); struct asus_laptop *asus = dev_get_drvdata(dev);
...@@ -1146,6 +1150,7 @@ static ssize_t store_disp(struct device *dev, struct device_attribute *attr, ...@@ -1146,6 +1150,7 @@ static ssize_t store_disp(struct device *dev, struct device_attribute *attr,
asus_set_display(asus, value); asus_set_display(asus, value);
return rv; return rv;
} }
static DEVICE_ATTR_WO(display);
/* /*
* Light Sens * Light Sens
...@@ -1167,16 +1172,17 @@ static void asus_als_switch(struct asus_laptop *asus, int value) ...@@ -1167,16 +1172,17 @@ static void asus_als_switch(struct asus_laptop *asus, int value)
asus->light_switch = value; asus->light_switch = value;
} }
static ssize_t show_lssw(struct device *dev, static ssize_t ls_switch_show(struct device *dev, struct device_attribute *attr,
struct device_attribute *attr, char *buf) char *buf)
{ {
struct asus_laptop *asus = dev_get_drvdata(dev); struct asus_laptop *asus = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", asus->light_switch); return sprintf(buf, "%d\n", asus->light_switch);
} }
static ssize_t store_lssw(struct device *dev, struct device_attribute *attr, static ssize_t ls_switch_store(struct device *dev,
const char *buf, size_t count) struct device_attribute *attr, const char *buf,
size_t count)
{ {
struct asus_laptop *asus = dev_get_drvdata(dev); struct asus_laptop *asus = dev_get_drvdata(dev);
int rv, value; int rv, value;
...@@ -1187,6 +1193,7 @@ static ssize_t store_lssw(struct device *dev, struct device_attribute *attr, ...@@ -1187,6 +1193,7 @@ static ssize_t store_lssw(struct device *dev, struct device_attribute *attr,
return rv; return rv;
} }
static DEVICE_ATTR_RW(ls_switch);
static void asus_als_level(struct asus_laptop *asus, int value) static void asus_als_level(struct asus_laptop *asus, int value)
{ {
...@@ -1195,15 +1202,15 @@ static void asus_als_level(struct asus_laptop *asus, int value) ...@@ -1195,15 +1202,15 @@ static void asus_als_level(struct asus_laptop *asus, int value)
asus->light_level = value; asus->light_level = value;
} }
static ssize_t show_lslvl(struct device *dev, static ssize_t ls_level_show(struct device *dev, struct device_attribute *attr,
struct device_attribute *attr, char *buf) char *buf)
{ {
struct asus_laptop *asus = dev_get_drvdata(dev); struct asus_laptop *asus = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", asus->light_level); return sprintf(buf, "%d\n", asus->light_level);
} }
static ssize_t store_lslvl(struct device *dev, struct device_attribute *attr, static ssize_t ls_level_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct asus_laptop *asus = dev_get_drvdata(dev); struct asus_laptop *asus = dev_get_drvdata(dev);
...@@ -1218,6 +1225,7 @@ static ssize_t store_lslvl(struct device *dev, struct device_attribute *attr, ...@@ -1218,6 +1225,7 @@ static ssize_t store_lslvl(struct device *dev, struct device_attribute *attr,
return rv; return rv;
} }
static DEVICE_ATTR_RW(ls_level);
static int pega_int_read(struct asus_laptop *asus, int arg, int *result) static int pega_int_read(struct asus_laptop *asus, int arg, int *result)
{ {
...@@ -1234,8 +1242,8 @@ static int pega_int_read(struct asus_laptop *asus, int arg, int *result) ...@@ -1234,8 +1242,8 @@ static int pega_int_read(struct asus_laptop *asus, int arg, int *result)
return err; return err;
} }
static ssize_t show_lsvalue(struct device *dev, static ssize_t ls_value_show(struct device *dev, struct device_attribute *attr,
struct device_attribute *attr, char *buf) char *buf)
{ {
struct asus_laptop *asus = dev_get_drvdata(dev); struct asus_laptop *asus = dev_get_drvdata(dev);
int err, hi, lo; int err, hi, lo;
...@@ -1247,6 +1255,7 @@ static ssize_t show_lsvalue(struct device *dev, ...@@ -1247,6 +1255,7 @@ static ssize_t show_lsvalue(struct device *dev,
return sprintf(buf, "%d\n", 10 * hi + lo); return sprintf(buf, "%d\n", 10 * hi + lo);
return err; return err;
} }
static DEVICE_ATTR_RO(ls_value);
/* /*
* GPS * GPS
...@@ -1274,15 +1283,15 @@ static int asus_gps_switch(struct asus_laptop *asus, int status) ...@@ -1274,15 +1283,15 @@ static int asus_gps_switch(struct asus_laptop *asus, int status)
return 0; return 0;
} }
static ssize_t show_gps(struct device *dev, static ssize_t gps_show(struct device *dev, struct device_attribute *attr,
struct device_attribute *attr, char *buf) char *buf)
{ {
struct asus_laptop *asus = dev_get_drvdata(dev); struct asus_laptop *asus = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", asus_gps_status(asus)); return sprintf(buf, "%d\n", asus_gps_status(asus));
} }
static ssize_t store_gps(struct device *dev, struct device_attribute *attr, static ssize_t gps_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct asus_laptop *asus = dev_get_drvdata(dev); struct asus_laptop *asus = dev_get_drvdata(dev);
...@@ -1298,6 +1307,7 @@ static ssize_t store_gps(struct device *dev, struct device_attribute *attr, ...@@ -1298,6 +1307,7 @@ static ssize_t store_gps(struct device *dev, struct device_attribute *attr,
rfkill_set_sw_state(asus->gps.rfkill, !value); rfkill_set_sw_state(asus->gps.rfkill, !value);
return rv; return rv;
} }
static DEVICE_ATTR_RW(gps);
/* /*
* rfkill * rfkill
...@@ -1569,19 +1579,6 @@ static void asus_acpi_notify(struct acpi_device *device, u32 event) ...@@ -1569,19 +1579,6 @@ static void asus_acpi_notify(struct acpi_device *device, u32 event)
asus_input_notify(asus, event); asus_input_notify(asus, event);
} }
static DEVICE_ATTR(infos, S_IRUGO, show_infos, NULL);
static DEVICE_ATTR(wlan, S_IRUGO | S_IWUSR, show_wlan, store_wlan);
static DEVICE_ATTR(bluetooth, S_IRUGO | S_IWUSR,
show_bluetooth, store_bluetooth);
static DEVICE_ATTR(wimax, S_IRUGO | S_IWUSR, show_wimax, store_wimax);
static DEVICE_ATTR(wwan, S_IRUGO | S_IWUSR, show_wwan, store_wwan);
static DEVICE_ATTR(display, S_IWUSR, NULL, store_disp);
static DEVICE_ATTR(ledd, S_IRUGO | S_IWUSR, show_ledd, store_ledd);
static DEVICE_ATTR(ls_value, S_IRUGO, show_lsvalue, NULL);
static DEVICE_ATTR(ls_level, S_IRUGO | S_IWUSR, show_lslvl, store_lslvl);
static DEVICE_ATTR(ls_switch, S_IRUGO | S_IWUSR, show_lssw, store_lssw);
static DEVICE_ATTR(gps, S_IRUGO | S_IWUSR, show_gps, store_gps);
static struct attribute *asus_attributes[] = { static struct attribute *asus_attributes[] = {
&dev_attr_infos.attr, &dev_attr_infos.attr,
&dev_attr_wlan.attr, &dev_attr_wlan.attr,
...@@ -1616,7 +1613,7 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj, ...@@ -1616,7 +1613,7 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj,
else else
goto normal; goto normal;
return supported; return supported ? attr->mode : 0;
} }
normal: normal:
......
...@@ -520,7 +520,7 @@ static acpi_status cmpc_get_accel(acpi_handle handle, ...@@ -520,7 +520,7 @@ static acpi_status cmpc_get_accel(acpi_handle handle,
{ {
union acpi_object param[2]; union acpi_object param[2];
struct acpi_object_list input; struct acpi_object_list input;
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, 0 }; struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
unsigned char *locs; unsigned char *locs;
acpi_status status; acpi_status status;
......
...@@ -64,6 +64,7 @@ ...@@ -64,6 +64,7 @@
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/dmi.h> #include <linux/dmi.h>
#include <linux/backlight.h> #include <linux/backlight.h>
#include <linux/fb.h>
#include <linux/input.h> #include <linux/input.h>
#include <linux/kfifo.h> #include <linux/kfifo.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
...@@ -398,7 +399,7 @@ static int bl_get_brightness(struct backlight_device *b) ...@@ -398,7 +399,7 @@ static int bl_get_brightness(struct backlight_device *b)
static int bl_update_status(struct backlight_device *b) static int bl_update_status(struct backlight_device *b)
{ {
int ret; int ret;
if (b->props.power == 4) if (b->props.power == FB_BLANK_POWERDOWN)
ret = call_fext_func(FUNC_BACKLIGHT, 0x1, 0x4, 0x3); ret = call_fext_func(FUNC_BACKLIGHT, 0x1, 0x4, 0x3);
else else
ret = call_fext_func(FUNC_BACKLIGHT, 0x1, 0x4, 0x0); ret = call_fext_func(FUNC_BACKLIGHT, 0x1, 0x4, 0x0);
...@@ -1139,9 +1140,9 @@ static int __init fujitsu_init(void) ...@@ -1139,9 +1140,9 @@ static int __init fujitsu_init(void)
if (!acpi_video_backlight_support()) { if (!acpi_video_backlight_support()) {
if (call_fext_func(FUNC_BACKLIGHT, 0x2, 0x4, 0x0) == 3) if (call_fext_func(FUNC_BACKLIGHT, 0x2, 0x4, 0x0) == 3)
fujitsu->bl_device->props.power = 4; fujitsu->bl_device->props.power = FB_BLANK_POWERDOWN;
else else
fujitsu->bl_device->props.power = 0; fujitsu->bl_device->props.power = FB_BLANK_UNBLANK;
} }
pr_info("driver " FUJITSU_DRIVER_VERSION " successfully loaded\n"); pr_info("driver " FUJITSU_DRIVER_VERSION " successfully loaded\n");
......
/* /*
* intel_scu_ipc.c: Driver for the Intel SCU IPC mechanism * intel_scu_ipc.c: Driver for the Intel SCU IPC mechanism
* *
* (C) Copyright 2008-2010 Intel Corporation * (C) Copyright 2008-2010,2015 Intel Corporation
* Author: Sreedhara DS (sreedhara.ds@intel.com) * Author: Sreedhara DS (sreedhara.ds@intel.com)
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
...@@ -43,10 +43,9 @@ ...@@ -43,10 +43,9 @@
/* /*
* IPC register summary * IPC register summary
* *
* IPC register blocks are memory mapped at fixed address of 0xFF11C000 * IPC register blocks are memory mapped at fixed address of PCI BAR 0.
* To read or write information to the SCU, driver writes to IPC-1 memory * To read or write information to the SCU, driver writes to IPC-1 memory
* mapped registers (base address 0xFF11C000). The following is the IPC * mapped registers. The following is the IPC mechanism
* mechanism
* *
* 1. IA core cDMI interface claims this transaction and converts it to a * 1. IA core cDMI interface claims this transaction and converts it to a
* Transaction Layer Packet (TLP) message which is sent across the cDMI. * Transaction Layer Packet (TLP) message which is sent across the cDMI.
...@@ -67,36 +66,28 @@ ...@@ -67,36 +66,28 @@
#define PCI_DEVICE_ID_CLOVERVIEW 0x08ea #define PCI_DEVICE_ID_CLOVERVIEW 0x08ea
#define PCI_DEVICE_ID_TANGIER 0x11a0 #define PCI_DEVICE_ID_TANGIER 0x11a0
/* intel scu ipc driver data*/ /* intel scu ipc driver data */
struct intel_scu_ipc_pdata_t { struct intel_scu_ipc_pdata_t {
u32 ipc_base;
u32 i2c_base; u32 i2c_base;
u32 ipc_len;
u32 i2c_len; u32 i2c_len;
u8 irq_mode; u8 irq_mode;
}; };
static struct intel_scu_ipc_pdata_t intel_scu_ipc_lincroft_pdata = { static struct intel_scu_ipc_pdata_t intel_scu_ipc_lincroft_pdata = {
.ipc_base = 0xff11c000,
.i2c_base = 0xff12b000, .i2c_base = 0xff12b000,
.ipc_len = 0x100,
.i2c_len = 0x10, .i2c_len = 0x10,
.irq_mode = 0, .irq_mode = 0,
}; };
/* Penwell and Cloverview */ /* Penwell and Cloverview */
static struct intel_scu_ipc_pdata_t intel_scu_ipc_penwell_pdata = { static struct intel_scu_ipc_pdata_t intel_scu_ipc_penwell_pdata = {
.ipc_base = 0xff11c000,
.i2c_base = 0xff12b000, .i2c_base = 0xff12b000,
.ipc_len = 0x100,
.i2c_len = 0x10, .i2c_len = 0x10,
.irq_mode = 1, .irq_mode = 1,
}; };
static struct intel_scu_ipc_pdata_t intel_scu_ipc_tangier_pdata = { static struct intel_scu_ipc_pdata_t intel_scu_ipc_tangier_pdata = {
.ipc_base = 0xff009000,
.i2c_base = 0xff00d000, .i2c_base = 0xff00d000,
.ipc_len = 0x100,
.i2c_len = 0x10, .i2c_len = 0x10,
.irq_mode = 0, .irq_mode = 0,
}; };
...@@ -114,8 +105,6 @@ struct intel_scu_ipc_dev { ...@@ -114,8 +105,6 @@ struct intel_scu_ipc_dev {
static struct intel_scu_ipc_dev ipcdev; /* Only one for now */ static struct intel_scu_ipc_dev ipcdev; /* Only one for now */
static int platform; /* Platform type */
/* /*
* IPC Read Buffer (Read Only): * IPC Read Buffer (Read Only):
* 16 byte buffer for receiving data from SCU, if IPC command * 16 byte buffer for receiving data from SCU, if IPC command
...@@ -160,7 +149,6 @@ static inline void ipc_data_writel(u32 data, u32 offset) /* Write ipc data */ ...@@ -160,7 +149,6 @@ static inline void ipc_data_writel(u32 data, u32 offset) /* Write ipc data */
* Format: * Format:
* |rfu3(8)|error code(8)|initiator id(8)|cmd id(4)|rfu1(2)|error(1)|busy(1)| * |rfu3(8)|error code(8)|initiator id(8)|cmd id(4)|rfu1(2)|error(1)|busy(1)|
*/ */
static inline u8 ipc_read_status(void) static inline u8 ipc_read_status(void)
{ {
return __raw_readl(ipcdev.ipc_base + 0x04); return __raw_readl(ipcdev.ipc_base + 0x04);
...@@ -176,23 +164,24 @@ static inline u32 ipc_data_readl(u32 offset) /* Read ipc u32 data */ ...@@ -176,23 +164,24 @@ static inline u32 ipc_data_readl(u32 offset) /* Read ipc u32 data */
return readl(ipcdev.ipc_base + IPC_READ_BUFFER + offset); return readl(ipcdev.ipc_base + IPC_READ_BUFFER + offset);
} }
static inline int busy_loop(void) /* Wait till scu status is busy */ /* Wait till scu status is busy */
static inline int busy_loop(void)
{ {
u32 status = 0; u32 status = ipc_read_status();
u32 loop_count = 0; u32 loop_count = 100000;
status = ipc_read_status(); /* break if scu doesn't reset busy bit after huge retry */
while (status & 1) { while ((status & BIT(0)) && --loop_count) {
udelay(1); /* scu processing time is in few u secods */ udelay(1); /* scu processing time is in few u secods */
status = ipc_read_status(); status = ipc_read_status();
loop_count++; }
/* break if scu doesn't reset busy bit after huge retry */
if (loop_count > 100000) { if (status & BIT(0)) {
dev_err(&ipcdev.pdev->dev, "IPC timed out"); dev_err(&ipcdev.pdev->dev, "IPC timed out");
return -ETIMEDOUT; return -ETIMEDOUT;
} }
}
if ((status >> 1) & 1) if (status & BIT(1))
return -EIO; return -EIO;
return 0; return 0;
...@@ -210,14 +199,13 @@ static inline int ipc_wait_for_interrupt(void) ...@@ -210,14 +199,13 @@ static inline int ipc_wait_for_interrupt(void)
} }
status = ipc_read_status(); status = ipc_read_status();
if (status & BIT(1))
if ((status >> 1) & 1)
return -EIO; return -EIO;
return 0; return 0;
} }
int intel_scu_ipc_check_status(void) static int intel_scu_ipc_check_status(void)
{ {
return ipcdev.irq_mode ? ipc_wait_for_interrupt() : busy_loop(); return ipcdev.irq_mode ? ipc_wait_for_interrupt() : busy_loop();
} }
...@@ -248,13 +236,13 @@ static int pwr_reg_rdwr(u16 *addr, u8 *data, u32 count, u32 op, u32 id) ...@@ -248,13 +236,13 @@ static int pwr_reg_rdwr(u16 *addr, u8 *data, u32 count, u32 op, u32 id)
if (id == IPC_CMD_PCNTRL_R) { if (id == IPC_CMD_PCNTRL_R) {
for (nc = 0, offset = 0; nc < count; nc++, offset += 4) for (nc = 0, offset = 0; nc < count; nc++, offset += 4)
ipc_data_writel(wbuf[nc], offset); ipc_data_writel(wbuf[nc], offset);
ipc_command((count*2) << 16 | id << 12 | 0 << 8 | op); ipc_command((count * 2) << 16 | id << 12 | 0 << 8 | op);
} else if (id == IPC_CMD_PCNTRL_W) { } else if (id == IPC_CMD_PCNTRL_W) {
for (nc = 0; nc < count; nc++, offset += 1) for (nc = 0; nc < count; nc++, offset += 1)
cbuf[offset] = data[nc]; cbuf[offset] = data[nc];
for (nc = 0, offset = 0; nc < count; nc++, offset += 4) for (nc = 0, offset = 0; nc < count; nc++, offset += 4)
ipc_data_writel(wbuf[nc], offset); ipc_data_writel(wbuf[nc], offset);
ipc_command((count*3) << 16 | id << 12 | 0 << 8 | op); ipc_command((count * 3) << 16 | id << 12 | 0 << 8 | op);
} else if (id == IPC_CMD_PCNTRL_M) { } else if (id == IPC_CMD_PCNTRL_M) {
cbuf[offset] = data[0]; cbuf[offset] = data[0];
cbuf[offset + 1] = data[1]; cbuf[offset + 1] = data[1];
...@@ -301,7 +289,7 @@ EXPORT_SYMBOL(intel_scu_ipc_ioread8); ...@@ -301,7 +289,7 @@ EXPORT_SYMBOL(intel_scu_ipc_ioread8);
*/ */
int intel_scu_ipc_ioread16(u16 addr, u16 *data) int intel_scu_ipc_ioread16(u16 addr, u16 *data)
{ {
u16 x[2] = {addr, addr + 1 }; u16 x[2] = {addr, addr + 1};
return pwr_reg_rdwr(x, (u8 *)data, 2, IPCMSG_PCNTRL, IPC_CMD_PCNTRL_R); return pwr_reg_rdwr(x, (u8 *)data, 2, IPCMSG_PCNTRL, IPC_CMD_PCNTRL_R);
} }
EXPORT_SYMBOL(intel_scu_ipc_ioread16); EXPORT_SYMBOL(intel_scu_ipc_ioread16);
...@@ -351,7 +339,7 @@ EXPORT_SYMBOL(intel_scu_ipc_iowrite8); ...@@ -351,7 +339,7 @@ EXPORT_SYMBOL(intel_scu_ipc_iowrite8);
*/ */
int intel_scu_ipc_iowrite16(u16 addr, u16 data) int intel_scu_ipc_iowrite16(u16 addr, u16 data)
{ {
u16 x[2] = {addr, addr + 1 }; u16 x[2] = {addr, addr + 1};
return pwr_reg_rdwr(x, (u8 *)&data, 2, IPCMSG_PCNTRL, IPC_CMD_PCNTRL_W); return pwr_reg_rdwr(x, (u8 *)&data, 2, IPCMSG_PCNTRL, IPC_CMD_PCNTRL_W);
} }
EXPORT_SYMBOL(intel_scu_ipc_iowrite16); EXPORT_SYMBOL(intel_scu_ipc_iowrite16);
...@@ -412,7 +400,6 @@ int intel_scu_ipc_writev(u16 *addr, u8 *data, int len) ...@@ -412,7 +400,6 @@ int intel_scu_ipc_writev(u16 *addr, u8 *data, int len)
} }
EXPORT_SYMBOL(intel_scu_ipc_writev); EXPORT_SYMBOL(intel_scu_ipc_writev);
/** /**
* intel_scu_ipc_update_register - r/m/w a register * intel_scu_ipc_update_register - r/m/w a register
* @addr: register address * @addr: register address
...@@ -475,7 +462,6 @@ EXPORT_SYMBOL(intel_scu_ipc_simple_command); ...@@ -475,7 +462,6 @@ EXPORT_SYMBOL(intel_scu_ipc_simple_command);
* Issue a command to the SCU which involves data transfers. Do the * Issue a command to the SCU which involves data transfers. Do the
* data copies under the lock but leave it for the caller to interpret * data copies under the lock but leave it for the caller to interpret
*/ */
int intel_scu_ipc_command(int cmd, int sub, u32 *in, int inlen, int intel_scu_ipc_command(int cmd, int sub, u32 *in, int inlen,
u32 *out, int outlen) u32 *out, int outlen)
{ {
...@@ -503,7 +489,7 @@ int intel_scu_ipc_command(int cmd, int sub, u32 *in, int inlen, ...@@ -503,7 +489,7 @@ int intel_scu_ipc_command(int cmd, int sub, u32 *in, int inlen,
} }
EXPORT_SYMBOL(intel_scu_ipc_command); EXPORT_SYMBOL(intel_scu_ipc_command);
/*I2C commands */ /* I2C commands */
#define IPC_I2C_WRITE 1 /* I2C Write command */ #define IPC_I2C_WRITE 1 /* I2C Write command */
#define IPC_I2C_READ 2 /* I2C Read command */ #define IPC_I2C_READ 2 /* I2C Read command */
...@@ -577,7 +563,7 @@ static int ipc_probe(struct pci_dev *dev, const struct pci_device_id *id) ...@@ -577,7 +563,7 @@ static int ipc_probe(struct pci_dev *dev, const struct pci_device_id *id)
{ {
int err; int err;
struct intel_scu_ipc_pdata_t *pdata; struct intel_scu_ipc_pdata_t *pdata;
resource_size_t pci_resource; resource_size_t base;
if (ipcdev.pdev) /* We support only one SCU */ if (ipcdev.pdev) /* We support only one SCU */
return -EBUSY; return -EBUSY;
...@@ -595,8 +581,8 @@ static int ipc_probe(struct pci_dev *dev, const struct pci_device_id *id) ...@@ -595,8 +581,8 @@ static int ipc_probe(struct pci_dev *dev, const struct pci_device_id *id)
if (err) if (err)
return err; return err;
pci_resource = pci_resource_start(dev, 0); base = pci_resource_start(dev, 0);
if (!pci_resource) if (!base)
return -ENOMEM; return -ENOMEM;
init_completion(&ipcdev.cmd_complete); init_completion(&ipcdev.cmd_complete);
...@@ -604,7 +590,7 @@ static int ipc_probe(struct pci_dev *dev, const struct pci_device_id *id) ...@@ -604,7 +590,7 @@ static int ipc_probe(struct pci_dev *dev, const struct pci_device_id *id)
if (request_irq(dev->irq, ioc, 0, "intel_scu_ipc", &ipcdev)) if (request_irq(dev->irq, ioc, 0, "intel_scu_ipc", &ipcdev))
return -EBUSY; return -EBUSY;
ipcdev.ipc_base = ioremap_nocache(pdata->ipc_base, pdata->ipc_len); ipcdev.ipc_base = ioremap_nocache(base, pci_resource_len(dev, 0));
if (!ipcdev.ipc_base) if (!ipcdev.ipc_base)
return -ENOMEM; return -ENOMEM;
...@@ -666,9 +652,10 @@ static struct pci_driver ipc_driver = { ...@@ -666,9 +652,10 @@ static struct pci_driver ipc_driver = {
.remove = ipc_remove, .remove = ipc_remove,
}; };
static int __init intel_scu_ipc_init(void) static int __init intel_scu_ipc_init(void)
{ {
int platform; /* Platform type */
platform = intel_mid_identify_cpu(); platform = intel_mid_identify_cpu();
if (platform == 0) if (platform == 0)
return -ENODEV; return -ENODEV;
......
...@@ -124,6 +124,10 @@ struct sabi_commands { ...@@ -124,6 +124,10 @@ struct sabi_commands {
u16 get_wireless_status; u16 get_wireless_status;
u16 set_wireless_status; u16 set_wireless_status;
/* 0x80 is off, 0x81 is on */
u16 get_lid_handling;
u16 set_lid_handling;
/* 0x81 to read, (0x82 | level << 8) to set, 0xaabb to enable */ /* 0x81 to read, (0x82 | level << 8) to set, 0xaabb to enable */
u16 kbd_backlight; u16 kbd_backlight;
...@@ -194,6 +198,9 @@ static const struct sabi_config sabi_configs[] = { ...@@ -194,6 +198,9 @@ static const struct sabi_config sabi_configs[] = {
.get_wireless_status = 0xFFFF, .get_wireless_status = 0xFFFF,
.set_wireless_status = 0xFFFF, .set_wireless_status = 0xFFFF,
.get_lid_handling = 0xFFFF,
.set_lid_handling = 0xFFFF,
.kbd_backlight = 0xFFFF, .kbd_backlight = 0xFFFF,
.set_linux = 0x0a, .set_linux = 0x0a,
...@@ -254,6 +261,9 @@ static const struct sabi_config sabi_configs[] = { ...@@ -254,6 +261,9 @@ static const struct sabi_config sabi_configs[] = {
.get_wireless_status = 0x69, .get_wireless_status = 0x69,
.set_wireless_status = 0x6a, .set_wireless_status = 0x6a,
.get_lid_handling = 0x6d,
.set_lid_handling = 0x6e,
.kbd_backlight = 0x78, .kbd_backlight = 0x78,
.set_linux = 0xff, .set_linux = 0xff,
...@@ -353,6 +363,8 @@ struct samsung_quirks { ...@@ -353,6 +363,8 @@ struct samsung_quirks {
bool broken_acpi_video; bool broken_acpi_video;
bool four_kbd_backlight_levels; bool four_kbd_backlight_levels;
bool enable_kbd_backlight; bool enable_kbd_backlight;
bool use_native_backlight;
bool lid_handling;
}; };
static struct samsung_quirks samsung_unknown = {}; static struct samsung_quirks samsung_unknown = {};
...@@ -361,11 +373,19 @@ static struct samsung_quirks samsung_broken_acpi_video = { ...@@ -361,11 +373,19 @@ static struct samsung_quirks samsung_broken_acpi_video = {
.broken_acpi_video = true, .broken_acpi_video = true,
}; };
static struct samsung_quirks samsung_use_native_backlight = {
.use_native_backlight = true,
};
static struct samsung_quirks samsung_np740u3e = { static struct samsung_quirks samsung_np740u3e = {
.four_kbd_backlight_levels = true, .four_kbd_backlight_levels = true,
.enable_kbd_backlight = true, .enable_kbd_backlight = true,
}; };
static struct samsung_quirks samsung_lid_handling = {
.lid_handling = true,
};
static bool force; static bool force;
module_param(force, bool, 0); module_param(force, bool, 0);
MODULE_PARM_DESC(force, MODULE_PARM_DESC(force,
...@@ -748,7 +768,7 @@ static ssize_t set_battery_life_extender(struct device *dev, ...@@ -748,7 +768,7 @@ static ssize_t set_battery_life_extender(struct device *dev,
struct samsung_laptop *samsung = dev_get_drvdata(dev); struct samsung_laptop *samsung = dev_get_drvdata(dev);
int ret, value; int ret, value;
if (!count || sscanf(buf, "%i", &value) != 1) if (!count || kstrtoint(buf, 0, &value) != 0)
return -EINVAL; return -EINVAL;
ret = write_battery_life_extender(samsung, !!value); ret = write_battery_life_extender(samsung, !!value);
...@@ -817,7 +837,7 @@ static ssize_t set_usb_charge(struct device *dev, ...@@ -817,7 +837,7 @@ static ssize_t set_usb_charge(struct device *dev,
struct samsung_laptop *samsung = dev_get_drvdata(dev); struct samsung_laptop *samsung = dev_get_drvdata(dev);
int ret, value; int ret, value;
if (!count || sscanf(buf, "%i", &value) != 1) if (!count || kstrtoint(buf, 0, &value) != 0)
return -EINVAL; return -EINVAL;
ret = write_usb_charge(samsung, !!value); ret = write_usb_charge(samsung, !!value);
...@@ -830,10 +850,76 @@ static ssize_t set_usb_charge(struct device *dev, ...@@ -830,10 +850,76 @@ static ssize_t set_usb_charge(struct device *dev,
static DEVICE_ATTR(usb_charge, S_IWUSR | S_IRUGO, static DEVICE_ATTR(usb_charge, S_IWUSR | S_IRUGO,
get_usb_charge, set_usb_charge); get_usb_charge, set_usb_charge);
static int read_lid_handling(struct samsung_laptop *samsung)
{
const struct sabi_commands *commands = &samsung->config->commands;
struct sabi_data data;
int retval;
if (commands->get_lid_handling == 0xFFFF)
return -ENODEV;
memset(&data, 0, sizeof(data));
retval = sabi_command(samsung, commands->get_lid_handling,
&data, &data);
if (retval)
return retval;
return data.data[0] & 0x1;
}
static int write_lid_handling(struct samsung_laptop *samsung,
int enabled)
{
const struct sabi_commands *commands = &samsung->config->commands;
struct sabi_data data;
memset(&data, 0, sizeof(data));
data.data[0] = 0x80 | enabled;
return sabi_command(samsung, commands->set_lid_handling,
&data, NULL);
}
static ssize_t get_lid_handling(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct samsung_laptop *samsung = dev_get_drvdata(dev);
int ret;
ret = read_lid_handling(samsung);
if (ret < 0)
return ret;
return sprintf(buf, "%d\n", ret);
}
static ssize_t set_lid_handling(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct samsung_laptop *samsung = dev_get_drvdata(dev);
int ret, value;
if (!count || kstrtoint(buf, 0, &value) != 0)
return -EINVAL;
ret = write_lid_handling(samsung, !!value);
if (ret < 0)
return ret;
return count;
}
static DEVICE_ATTR(lid_handling, S_IWUSR | S_IRUGO,
get_lid_handling, set_lid_handling);
static struct attribute *platform_attributes[] = { static struct attribute *platform_attributes[] = {
&dev_attr_performance_level.attr, &dev_attr_performance_level.attr,
&dev_attr_battery_life_extender.attr, &dev_attr_battery_life_extender.attr,
&dev_attr_usb_charge.attr, &dev_attr_usb_charge.attr,
&dev_attr_lid_handling.attr,
NULL NULL
}; };
...@@ -956,6 +1042,22 @@ static int __init samsung_rfkill_init(struct samsung_laptop *samsung) ...@@ -956,6 +1042,22 @@ static int __init samsung_rfkill_init(struct samsung_laptop *samsung)
return 0; return 0;
} }
static void samsung_lid_handling_exit(struct samsung_laptop *samsung)
{
if (samsung->quirks->lid_handling)
write_lid_handling(samsung, 0);
}
static int __init samsung_lid_handling_init(struct samsung_laptop *samsung)
{
int retval = 0;
if (samsung->quirks->lid_handling)
retval = write_lid_handling(samsung, 1);
return retval;
}
static int kbd_backlight_enable(struct samsung_laptop *samsung) static int kbd_backlight_enable(struct samsung_laptop *samsung)
{ {
const struct sabi_commands *commands = &samsung->config->commands; const struct sabi_commands *commands = &samsung->config->commands;
...@@ -1124,6 +1226,8 @@ static umode_t samsung_sysfs_is_visible(struct kobject *kobj, ...@@ -1124,6 +1226,8 @@ static umode_t samsung_sysfs_is_visible(struct kobject *kobj,
ok = !!(read_battery_life_extender(samsung) >= 0); ok = !!(read_battery_life_extender(samsung) >= 0);
if (attr == &dev_attr_usb_charge.attr) if (attr == &dev_attr_usb_charge.attr)
ok = !!(read_usb_charge(samsung) >= 0); ok = !!(read_usb_charge(samsung) >= 0);
if (attr == &dev_attr_lid_handling.attr)
ok = !!(read_lid_handling(samsung) >= 0);
return ok ? attr->mode : 0; return ok ? attr->mode : 0;
} }
...@@ -1357,7 +1461,7 @@ static int __init samsung_sabi_init(struct samsung_laptop *samsung) ...@@ -1357,7 +1461,7 @@ static int __init samsung_sabi_init(struct samsung_laptop *samsung)
samsung_sabi_diag(samsung); samsung_sabi_diag(samsung);
/* Try to find one of the signatures in memory to find the header */ /* Try to find one of the signatures in memory to find the header */
for (i = 0; sabi_configs[i].test_string != 0; ++i) { for (i = 0; sabi_configs[i].test_string != NULL; ++i) {
samsung->config = &sabi_configs[i]; samsung->config = &sabi_configs[i];
loca = find_signature(samsung->f0000_segment, loca = find_signature(samsung->f0000_segment,
samsung->config->test_string); samsung->config->test_string);
...@@ -1436,6 +1540,9 @@ static int samsung_pm_notification(struct notifier_block *nb, ...@@ -1436,6 +1540,9 @@ static int samsung_pm_notification(struct notifier_block *nb,
samsung->quirks->enable_kbd_backlight) samsung->quirks->enable_kbd_backlight)
kbd_backlight_enable(samsung); kbd_backlight_enable(samsung);
if (val == PM_POST_HIBERNATION && samsung->quirks->lid_handling)
write_lid_handling(samsung, 1);
return 0; return 0;
} }
...@@ -1507,7 +1614,7 @@ static struct dmi_system_id __initdata samsung_dmi_table[] = { ...@@ -1507,7 +1614,7 @@ static struct dmi_system_id __initdata samsung_dmi_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "N150P"), DMI_MATCH(DMI_PRODUCT_NAME, "N150P"),
DMI_MATCH(DMI_BOARD_NAME, "N150P"), DMI_MATCH(DMI_BOARD_NAME, "N150P"),
}, },
.driver_data = &samsung_broken_acpi_video, .driver_data = &samsung_use_native_backlight,
}, },
{ {
.callback = samsung_dmi_matched, .callback = samsung_dmi_matched,
...@@ -1517,7 +1624,7 @@ static struct dmi_system_id __initdata samsung_dmi_table[] = { ...@@ -1517,7 +1624,7 @@ static struct dmi_system_id __initdata samsung_dmi_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "N145P/N250P/N260P"), DMI_MATCH(DMI_PRODUCT_NAME, "N145P/N250P/N260P"),
DMI_MATCH(DMI_BOARD_NAME, "N145P/N250P/N260P"), DMI_MATCH(DMI_BOARD_NAME, "N145P/N250P/N260P"),
}, },
.driver_data = &samsung_broken_acpi_video, .driver_data = &samsung_use_native_backlight,
}, },
{ {
.callback = samsung_dmi_matched, .callback = samsung_dmi_matched,
...@@ -1557,7 +1664,7 @@ static struct dmi_system_id __initdata samsung_dmi_table[] = { ...@@ -1557,7 +1664,7 @@ static struct dmi_system_id __initdata samsung_dmi_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "N250P"), DMI_MATCH(DMI_PRODUCT_NAME, "N250P"),
DMI_MATCH(DMI_BOARD_NAME, "N250P"), DMI_MATCH(DMI_BOARD_NAME, "N250P"),
}, },
.driver_data = &samsung_broken_acpi_video, .driver_data = &samsung_use_native_backlight,
}, },
{ {
.callback = samsung_dmi_matched, .callback = samsung_dmi_matched,
...@@ -1578,6 +1685,15 @@ static struct dmi_system_id __initdata samsung_dmi_table[] = { ...@@ -1578,6 +1685,15 @@ static struct dmi_system_id __initdata samsung_dmi_table[] = {
}, },
.driver_data = &samsung_np740u3e, .driver_data = &samsung_np740u3e,
}, },
{
.callback = samsung_dmi_matched,
.ident = "300V3Z/300V4Z/300V5Z",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
DMI_MATCH(DMI_PRODUCT_NAME, "300V3Z/300V4Z/300V5Z"),
},
.driver_data = &samsung_lid_handling,
},
{ }, { },
}; };
MODULE_DEVICE_TABLE(dmi, samsung_dmi_table); MODULE_DEVICE_TABLE(dmi, samsung_dmi_table);
...@@ -1616,6 +1732,15 @@ static int __init samsung_init(void) ...@@ -1616,6 +1732,15 @@ static int __init samsung_init(void)
pr_info("Disabling ACPI video driver\n"); pr_info("Disabling ACPI video driver\n");
acpi_video_unregister(); acpi_video_unregister();
} }
if (samsung->quirks->use_native_backlight) {
pr_info("Using native backlight driver\n");
/* Tell acpi-video to not handle the backlight */
acpi_video_dmi_promote_vendor();
acpi_video_unregister();
/* And also do not handle it ourselves */
samsung->handle_backlight = false;
}
#endif #endif
ret = samsung_platform_init(samsung); ret = samsung_platform_init(samsung);
...@@ -1648,6 +1773,10 @@ static int __init samsung_init(void) ...@@ -1648,6 +1773,10 @@ static int __init samsung_init(void)
if (ret) if (ret)
goto error_leds; goto error_leds;
ret = samsung_lid_handling_init(samsung);
if (ret)
goto error_lid_handling;
ret = samsung_debugfs_init(samsung); ret = samsung_debugfs_init(samsung);
if (ret) if (ret)
goto error_debugfs; goto error_debugfs;
...@@ -1659,6 +1788,8 @@ static int __init samsung_init(void) ...@@ -1659,6 +1788,8 @@ static int __init samsung_init(void)
return ret; return ret;
error_debugfs: error_debugfs:
samsung_lid_handling_exit(samsung);
error_lid_handling:
samsung_leds_exit(samsung); samsung_leds_exit(samsung);
error_leds: error_leds:
samsung_rfkill_exit(samsung); samsung_rfkill_exit(samsung);
...@@ -1683,6 +1814,7 @@ static void __exit samsung_exit(void) ...@@ -1683,6 +1814,7 @@ static void __exit samsung_exit(void)
unregister_pm_notifier(&samsung->pm_nb); unregister_pm_notifier(&samsung->pm_nb);
samsung_debugfs_exit(samsung); samsung_debugfs_exit(samsung);
samsung_lid_handling_exit(samsung);
samsung_leds_exit(samsung); samsung_leds_exit(samsung);
samsung_rfkill_exit(samsung); samsung_rfkill_exit(samsung);
samsung_backlight_exit(samsung); samsung_backlight_exit(samsung);
......
...@@ -1032,7 +1032,7 @@ struct sony_backlight_props { ...@@ -1032,7 +1032,7 @@ struct sony_backlight_props {
u8 offset; u8 offset;
u8 maxlvl; u8 maxlvl;
}; };
struct sony_backlight_props sony_bl_props; static struct sony_backlight_props sony_bl_props;
static int sony_backlight_update_status(struct backlight_device *bd) static int sony_backlight_update_status(struct backlight_device *bd)
{ {
......
...@@ -196,6 +196,7 @@ enum tpacpi_hkey_event_t { ...@@ -196,6 +196,7 @@ enum tpacpi_hkey_event_t {
/* Key-related user-interface events */ /* Key-related user-interface events */
TP_HKEY_EV_KEY_NUMLOCK = 0x6000, /* NumLock key pressed */ TP_HKEY_EV_KEY_NUMLOCK = 0x6000, /* NumLock key pressed */
TP_HKEY_EV_KEY_FN = 0x6005, /* Fn key pressed? E420 */ TP_HKEY_EV_KEY_FN = 0x6005, /* Fn key pressed? E420 */
TP_HKEY_EV_KEY_FN_ESC = 0x6060, /* Fn+Esc key pressed X240 */
/* Thermal events */ /* Thermal events */
TP_HKEY_EV_ALARM_BAT_HOT = 0x6011, /* battery too hot */ TP_HKEY_EV_ALARM_BAT_HOT = 0x6011, /* battery too hot */
...@@ -3456,7 +3457,7 @@ enum ADAPTIVE_KEY_MODE { ...@@ -3456,7 +3457,7 @@ enum ADAPTIVE_KEY_MODE {
LAYFLAT_MODE LAYFLAT_MODE
}; };
const int adaptive_keyboard_modes[] = { static const int adaptive_keyboard_modes[] = {
HOME_MODE, HOME_MODE,
/* WEB_BROWSER_MODE = 2, /* WEB_BROWSER_MODE = 2,
WEB_CONFERENCE_MODE = 3, */ WEB_CONFERENCE_MODE = 3, */
...@@ -3712,6 +3713,7 @@ static bool hotkey_notify_6xxx(const u32 hkey, ...@@ -3712,6 +3713,7 @@ static bool hotkey_notify_6xxx(const u32 hkey,
case TP_HKEY_EV_KEY_NUMLOCK: case TP_HKEY_EV_KEY_NUMLOCK:
case TP_HKEY_EV_KEY_FN: case TP_HKEY_EV_KEY_FN:
case TP_HKEY_EV_KEY_FN_ESC:
/* key press events, we just ignore them as long as the EC /* key press events, we just ignore them as long as the EC
* is still reporting them in the normal keyboard stream */ * is still reporting them in the normal keyboard stream */
*send_acpi_ev = false; *send_acpi_ev = false;
...@@ -8883,17 +8885,31 @@ static bool __pure __init tpacpi_is_fw_digit(const char c) ...@@ -8883,17 +8885,31 @@ static bool __pure __init tpacpi_is_fw_digit(const char c)
return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z'); return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z');
} }
/* Most models: xxyTkkWW (#.##c); Ancient 570/600 and -SL lacks (#.##c) */
static bool __pure __init tpacpi_is_valid_fw_id(const char * const s, static bool __pure __init tpacpi_is_valid_fw_id(const char * const s,
const char t) const char t)
{ {
return s && strlen(s) >= 8 && /*
* Most models: xxyTkkWW (#.##c)
* Ancient 570/600 and -SL lacks (#.##c)
*/
if (s && strlen(s) >= 8 &&
tpacpi_is_fw_digit(s[0]) && tpacpi_is_fw_digit(s[0]) &&
tpacpi_is_fw_digit(s[1]) && tpacpi_is_fw_digit(s[1]) &&
s[2] == t && s[2] == t &&
(s[3] == 'T' || s[3] == 'N') && (s[3] == 'T' || s[3] == 'N') &&
tpacpi_is_fw_digit(s[4]) && tpacpi_is_fw_digit(s[4]) &&
tpacpi_is_fw_digit(s[5]); tpacpi_is_fw_digit(s[5]))
return true;
/* New models: xxxyTkkW (#.##c); T550 and some others */
return s && strlen(s) >= 8 &&
tpacpi_is_fw_digit(s[0]) &&
tpacpi_is_fw_digit(s[1]) &&
tpacpi_is_fw_digit(s[2]) &&
s[3] == t &&
(s[4] == 'T' || s[4] == 'N') &&
tpacpi_is_fw_digit(s[5]) &&
tpacpi_is_fw_digit(s[6]);
} }
/* returns 0 - probe ok, or < 0 - probe error. /* returns 0 - probe ok, or < 0 - probe error.
......
/* /*
* toshiba_acpi.c - Toshiba Laptop ACPI Extras * toshiba_acpi.c - Toshiba Laptop ACPI Extras
* *
*
* Copyright (C) 2002-2004 John Belmonte * Copyright (C) 2002-2004 John Belmonte
* Copyright (C) 2008 Philip Langdale * Copyright (C) 2008 Philip Langdale
* Copyright (C) 2010 Pierre Ducroquet * Copyright (C) 2010 Pierre Ducroquet
* Copyright (C) 2014 Azael Avalos * Copyright (C) 2014-2015 Azael Avalos
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
...@@ -17,10 +16,8 @@ ...@@ -17,10 +16,8 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * The full GNU General Public License is included in this distribution in
* along with this program; if not, write to the Free Software * the file called "COPYING".
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* *
* The devolpment page for this driver is located at * The devolpment page for this driver is located at
* http://memebeam.org/toys/ToshibaAcpiDriver. * http://memebeam.org/toys/ToshibaAcpiDriver.
...@@ -30,15 +27,11 @@ ...@@ -30,15 +27,11 @@
* engineering the Windows drivers * engineering the Windows drivers
* Yasushi Nagato - changes for linux kernel 2.4 -> 2.5 * Yasushi Nagato - changes for linux kernel 2.4 -> 2.5
* Rob Miller - TV out and hotkeys help * Rob Miller - TV out and hotkeys help
*
*
* TODO
*
*/ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#define TOSHIBA_ACPI_VERSION "0.20" #define TOSHIBA_ACPI_VERSION "0.21"
#define PROC_INTERFACE_VERSION 1 #define PROC_INTERFACE_VERSION 1
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -57,7 +50,7 @@ ...@@ -57,7 +50,7 @@
#include <linux/i8042.h> #include <linux/i8042.h>
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/dmi.h> #include <linux/dmi.h>
#include <asm/uaccess.h> #include <linux/uaccess.h>
MODULE_AUTHOR("John Belmonte"); MODULE_AUTHOR("John Belmonte");
MODULE_DESCRIPTION("Toshiba Laptop ACPI Extras Driver"); MODULE_DESCRIPTION("Toshiba Laptop ACPI Extras Driver");
...@@ -71,7 +64,8 @@ MODULE_LICENSE("GPL"); ...@@ -71,7 +64,8 @@ MODULE_LICENSE("GPL");
/* Toshiba ACPI method paths */ /* Toshiba ACPI method paths */
#define METHOD_VIDEO_OUT "\\_SB_.VALX.DSSX" #define METHOD_VIDEO_OUT "\\_SB_.VALX.DSSX"
/* The Toshiba configuration interface is composed of the HCI and the SCI, /*
* The Toshiba configuration interface is composed of the HCI and the SCI,
* which are defined as follows: * which are defined as follows:
* *
* HCI is Toshiba's "Hardware Control Interface" which is supposed to * HCI is Toshiba's "Hardware Control Interface" which is supposed to
...@@ -108,6 +102,7 @@ MODULE_LICENSE("GPL"); ...@@ -108,6 +102,7 @@ MODULE_LICENSE("GPL");
#define TOS_FIFO_EMPTY 0x8c00 #define TOS_FIFO_EMPTY 0x8c00
#define TOS_DATA_NOT_AVAILABLE 0x8d20 #define TOS_DATA_NOT_AVAILABLE 0x8d20
#define TOS_NOT_INITIALIZED 0x8d50 #define TOS_NOT_INITIALIZED 0x8d50
#define TOS_NOT_INSTALLED 0x8e00
/* registers */ /* registers */
#define HCI_FAN 0x0004 #define HCI_FAN 0x0004
...@@ -121,9 +116,14 @@ MODULE_LICENSE("GPL"); ...@@ -121,9 +116,14 @@ MODULE_LICENSE("GPL");
#define HCI_KBD_ILLUMINATION 0x0095 #define HCI_KBD_ILLUMINATION 0x0095
#define HCI_ECO_MODE 0x0097 #define HCI_ECO_MODE 0x0097
#define HCI_ACCELEROMETER2 0x00a6 #define HCI_ACCELEROMETER2 0x00a6
#define SCI_PANEL_POWER_ON 0x010d
#define SCI_ILLUMINATION 0x014e #define SCI_ILLUMINATION 0x014e
#define SCI_USB_SLEEP_CHARGE 0x0150
#define SCI_KBD_ILLUM_STATUS 0x015c #define SCI_KBD_ILLUM_STATUS 0x015c
#define SCI_USB_SLEEP_MUSIC 0x015e
#define SCI_USB_THREE 0x0169
#define SCI_TOUCHPAD 0x050e #define SCI_TOUCHPAD 0x050e
#define SCI_KBD_FUNCTION_KEYS 0x0522
/* field definitions */ /* field definitions */
#define HCI_ACCEL_MASK 0x7fff #define HCI_ACCEL_MASK 0x7fff
...@@ -146,6 +146,15 @@ MODULE_LICENSE("GPL"); ...@@ -146,6 +146,15 @@ MODULE_LICENSE("GPL");
#define SCI_KBD_MODE_ON 0x8 #define SCI_KBD_MODE_ON 0x8
#define SCI_KBD_MODE_OFF 0x10 #define SCI_KBD_MODE_OFF 0x10
#define SCI_KBD_TIME_MAX 0x3c001a #define SCI_KBD_TIME_MAX 0x3c001a
#define SCI_USB_CHARGE_MODE_MASK 0xff
#define SCI_USB_CHARGE_DISABLED 0x30000
#define SCI_USB_CHARGE_ALTERNATE 0x30009
#define SCI_USB_CHARGE_AUTO 0x30021
#define SCI_USB_CHARGE_BAT_MASK 0x7
#define SCI_USB_CHARGE_BAT_LVL_OFF 0x1
#define SCI_USB_CHARGE_BAT_LVL_ON 0x4
#define SCI_USB_CHARGE_BAT_LVL 0x0200
#define SCI_USB_CHARGE_RAPID_DSP 0x0300
struct toshiba_acpi_dev { struct toshiba_acpi_dev {
struct acpi_device *acpi_dev; struct acpi_device *acpi_dev;
...@@ -164,6 +173,7 @@ struct toshiba_acpi_dev { ...@@ -164,6 +173,7 @@ struct toshiba_acpi_dev {
int kbd_type; int kbd_type;
int kbd_mode; int kbd_mode;
int kbd_time; int kbd_time;
int usbsc_bat_level;
unsigned int illumination_supported:1; unsigned int illumination_supported:1;
unsigned int video_supported:1; unsigned int video_supported:1;
...@@ -177,6 +187,12 @@ struct toshiba_acpi_dev { ...@@ -177,6 +187,12 @@ struct toshiba_acpi_dev {
unsigned int touchpad_supported:1; unsigned int touchpad_supported:1;
unsigned int eco_supported:1; unsigned int eco_supported:1;
unsigned int accelerometer_supported:1; unsigned int accelerometer_supported:1;
unsigned int usb_sleep_charge_supported:1;
unsigned int usb_rapid_charge_supported:1;
unsigned int usb_sleep_music_supported:1;
unsigned int kbd_function_keys_supported:1;
unsigned int panel_power_on_supported:1;
unsigned int usb_three_supported:1;
unsigned int sysfs_created:1; unsigned int sysfs_created:1;
struct mutex mutex; struct mutex mutex;
...@@ -264,15 +280,17 @@ static const struct key_entry toshiba_acpi_alt_keymap[] = { ...@@ -264,15 +280,17 @@ static const struct key_entry toshiba_acpi_alt_keymap[] = {
{ KE_END, 0 }, { KE_END, 0 },
}; };
/* utility /*
* Utility
*/ */
static __inline__ void _set_bit(u32 * word, u32 mask, int value) static inline void _set_bit(u32 *word, u32 mask, int value)
{ {
*word = (*word & ~mask) | (mask * value); *word = (*word & ~mask) | (mask * value);
} }
/* acpi interface wrappers /*
* ACPI interface wrappers
*/ */
static int write_acpi_int(const char *methodName, int val) static int write_acpi_int(const char *methodName, int val)
...@@ -283,7 +301,8 @@ static int write_acpi_int(const char *methodName, int val) ...@@ -283,7 +301,8 @@ static int write_acpi_int(const char *methodName, int val)
return (status == AE_OK) ? 0 : -EIO; return (status == AE_OK) ? 0 : -EIO;
} }
/* Perform a raw configuration call. Here we don't care about input or output /*
* Perform a raw configuration call. Here we don't care about input or output
* buffer format. * buffer format.
*/ */
static acpi_status tci_raw(struct toshiba_acpi_dev *dev, static acpi_status tci_raw(struct toshiba_acpi_dev *dev,
...@@ -310,15 +329,15 @@ static acpi_status tci_raw(struct toshiba_acpi_dev *dev, ...@@ -310,15 +329,15 @@ static acpi_status tci_raw(struct toshiba_acpi_dev *dev,
(char *)dev->method_hci, &params, (char *)dev->method_hci, &params,
&results); &results);
if ((status == AE_OK) && (out_objs->package.count <= TCI_WORDS)) { if ((status == AE_OK) && (out_objs->package.count <= TCI_WORDS)) {
for (i = 0; i < out_objs->package.count; ++i) { for (i = 0; i < out_objs->package.count; ++i)
out[i] = out_objs->package.elements[i].integer.value; out[i] = out_objs->package.elements[i].integer.value;
} }
}
return status; return status;
} }
/* common hci tasks (get or set one or two value) /*
* Common hci tasks (get or set one or two value)
* *
* In addition to the ACPI status, the HCI system returns a result which * In addition to the ACPI status, the HCI system returns a result which
* may be useful (such as "not supported"). * may be useful (such as "not supported").
...@@ -338,6 +357,7 @@ static u32 hci_read1(struct toshiba_acpi_dev *dev, u32 reg, u32 *out1) ...@@ -338,6 +357,7 @@ static u32 hci_read1(struct toshiba_acpi_dev *dev, u32 reg, u32 *out1)
u32 in[TCI_WORDS] = { HCI_GET, reg, 0, 0, 0, 0 }; u32 in[TCI_WORDS] = { HCI_GET, reg, 0, 0, 0, 0 };
u32 out[TCI_WORDS]; u32 out[TCI_WORDS];
acpi_status status = tci_raw(dev, in, out); acpi_status status = tci_raw(dev, in, out);
if (ACPI_FAILURE(status)) if (ACPI_FAILURE(status))
return TOS_FAILURE; return TOS_FAILURE;
...@@ -355,11 +375,13 @@ static u32 hci_write2(struct toshiba_acpi_dev *dev, u32 reg, u32 in1, u32 in2) ...@@ -355,11 +375,13 @@ static u32 hci_write2(struct toshiba_acpi_dev *dev, u32 reg, u32 in1, u32 in2)
return ACPI_SUCCESS(status) ? out[0] : TOS_FAILURE; return ACPI_SUCCESS(status) ? out[0] : TOS_FAILURE;
} }
static u32 hci_read2(struct toshiba_acpi_dev *dev, u32 reg, u32 *out1, u32 *out2) static u32 hci_read2(struct toshiba_acpi_dev *dev,
u32 reg, u32 *out1, u32 *out2)
{ {
u32 in[TCI_WORDS] = { HCI_GET, reg, *out1, *out2, 0, 0 }; u32 in[TCI_WORDS] = { HCI_GET, reg, *out1, *out2, 0, 0 };
u32 out[TCI_WORDS]; u32 out[TCI_WORDS];
acpi_status status = tci_raw(dev, in, out); acpi_status status = tci_raw(dev, in, out);
if (ACPI_FAILURE(status)) if (ACPI_FAILURE(status))
return TOS_FAILURE; return TOS_FAILURE;
...@@ -369,7 +391,8 @@ static u32 hci_read2(struct toshiba_acpi_dev *dev, u32 reg, u32 *out1, u32 *out2 ...@@ -369,7 +391,8 @@ static u32 hci_read2(struct toshiba_acpi_dev *dev, u32 reg, u32 *out1, u32 *out2
return out[0]; return out[0];
} }
/* common sci tasks /*
* Common sci tasks
*/ */
static int sci_open(struct toshiba_acpi_dev *dev) static int sci_open(struct toshiba_acpi_dev *dev)
...@@ -389,6 +412,20 @@ static int sci_open(struct toshiba_acpi_dev *dev) ...@@ -389,6 +412,20 @@ static int sci_open(struct toshiba_acpi_dev *dev)
} else if (out[0] == TOS_ALREADY_OPEN) { } else if (out[0] == TOS_ALREADY_OPEN) {
pr_info("Toshiba SCI already opened\n"); pr_info("Toshiba SCI already opened\n");
return 1; return 1;
} else if (out[0] == TOS_NOT_SUPPORTED) {
/*
* Some BIOSes do not have the SCI open/close functions
* implemented and return 0x8000 (Not Supported), failing to
* register some supported features.
*
* Simply return 1 if we hit those affected laptops to make the
* supported features work.
*
* In the case that some laptops really do not support the SCI,
* all the SCI dependent functions check for TOS_NOT_SUPPORTED,
* and thus, not registering support for the queried feature.
*/
return 1;
} else if (out[0] == TOS_NOT_PRESENT) { } else if (out[0] == TOS_NOT_PRESENT) {
pr_info("Toshiba SCI is not present\n"); pr_info("Toshiba SCI is not present\n");
} }
...@@ -421,6 +458,7 @@ static u32 sci_read(struct toshiba_acpi_dev *dev, u32 reg, u32 *out1) ...@@ -421,6 +458,7 @@ static u32 sci_read(struct toshiba_acpi_dev *dev, u32 reg, u32 *out1)
u32 in[TCI_WORDS] = { SCI_GET, reg, 0, 0, 0, 0 }; u32 in[TCI_WORDS] = { SCI_GET, reg, 0, 0, 0, 0 };
u32 out[TCI_WORDS]; u32 out[TCI_WORDS];
acpi_status status = tci_raw(dev, in, out); acpi_status status = tci_raw(dev, in, out);
if (ACPI_FAILURE(status)) if (ACPI_FAILURE(status))
return TOS_FAILURE; return TOS_FAILURE;
...@@ -529,10 +567,11 @@ static int toshiba_kbd_illum_available(struct toshiba_acpi_dev *dev) ...@@ -529,10 +567,11 @@ static int toshiba_kbd_illum_available(struct toshiba_acpi_dev *dev)
return 0; return 0;
} }
/* Check for keyboard backlight timeout max value, /*
* Check for keyboard backlight timeout max value,
* previous kbd backlight implementation set this to * previous kbd backlight implementation set this to
* 0x3c0003, and now the new implementation set this * 0x3c0003, and now the new implementation set this
* to 0x3c001a, use this to distinguish between them * to 0x3c001a, use this to distinguish between them.
*/ */
if (out[3] == SCI_KBD_TIME_MAX) if (out[3] == SCI_KBD_TIME_MAX)
dev->kbd_type = 2; dev->kbd_type = 2;
...@@ -667,19 +706,37 @@ static int toshiba_touchpad_get(struct toshiba_acpi_dev *dev, u32 *state) ...@@ -667,19 +706,37 @@ static int toshiba_touchpad_get(struct toshiba_acpi_dev *dev, u32 *state)
static int toshiba_eco_mode_available(struct toshiba_acpi_dev *dev) static int toshiba_eco_mode_available(struct toshiba_acpi_dev *dev)
{ {
acpi_status status; acpi_status status;
u32 in[TCI_WORDS] = { HCI_GET, HCI_ECO_MODE, 0, 1, 0, 0 }; u32 in[TCI_WORDS] = { HCI_GET, HCI_ECO_MODE, 0, 0, 0, 0 };
u32 out[TCI_WORDS]; u32 out[TCI_WORDS];
status = tci_raw(dev, in, out); status = tci_raw(dev, in, out);
if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) { if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) {
pr_info("ACPI call to get ECO led failed\n"); pr_err("ACPI call to get ECO led failed\n");
return 0; } else if (out[0] == TOS_NOT_INSTALLED) {
pr_info("ECO led not installed");
} else if (out[0] == TOS_INPUT_DATA_ERROR) {
/*
* If we receive 0x8300 (Input Data Error), it means that the
* LED device is present, but that we just screwed the input
* parameters.
*
* Let's query the status of the LED to see if we really have a
* success response, indicating the actual presense of the LED,
* bail out otherwise.
*/
in[3] = 1;
status = tci_raw(dev, in, out);
if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE)
pr_err("ACPI call to get ECO led failed\n");
else if (out[0] == TOS_SUCCESS)
return 1;
} }
return 1; return 0;
} }
static enum led_brightness toshiba_eco_mode_get_status(struct led_classdev *cdev) static enum led_brightness
toshiba_eco_mode_get_status(struct led_classdev *cdev)
{ {
struct toshiba_acpi_dev *dev = container_of(cdev, struct toshiba_acpi_dev *dev = container_of(cdev,
struct toshiba_acpi_dev, eco_led); struct toshiba_acpi_dev, eco_led);
...@@ -721,7 +778,8 @@ static int toshiba_accelerometer_supported(struct toshiba_acpi_dev *dev) ...@@ -721,7 +778,8 @@ static int toshiba_accelerometer_supported(struct toshiba_acpi_dev *dev)
u32 out[TCI_WORDS]; u32 out[TCI_WORDS];
acpi_status status; acpi_status status;
/* Check if the accelerometer call exists, /*
* Check if the accelerometer call exists,
* this call also serves as initialization * this call also serves as initialization
*/ */
status = tci_raw(dev, in, out); status = tci_raw(dev, in, out);
...@@ -760,199 +818,534 @@ static int toshiba_accelerometer_get(struct toshiba_acpi_dev *dev, ...@@ -760,199 +818,534 @@ static int toshiba_accelerometer_get(struct toshiba_acpi_dev *dev,
return 0; return 0;
} }
/* Bluetooth rfkill handlers */ /* Sleep (Charge and Music) utilities support */
static int toshiba_usb_sleep_charge_get(struct toshiba_acpi_dev *dev,
static u32 hci_get_bt_present(struct toshiba_acpi_dev *dev, bool *present) u32 *mode)
{ {
u32 hci_result; u32 result;
u32 value, value2;
value = 0;
value2 = 0;
hci_result = hci_read2(dev, HCI_WIRELESS, &value, &value2);
if (hci_result == TOS_SUCCESS)
*present = (value & HCI_WIRELESS_BT_PRESENT) ? true : false;
return hci_result;
}
static u32 hci_get_radio_state(struct toshiba_acpi_dev *dev, bool *radio_state) if (!sci_open(dev))
{ return -EIO;
u32 hci_result;
u32 value, value2;
value = 0; result = sci_read(dev, SCI_USB_SLEEP_CHARGE, mode);
value2 = 0x0001; sci_close(dev);
hci_result = hci_read2(dev, HCI_WIRELESS, &value, &value2); if (result == TOS_FAILURE) {
pr_err("ACPI call to set USB S&C mode failed\n");
return -EIO;
} else if (result == TOS_NOT_SUPPORTED) {
pr_info("USB Sleep and Charge not supported\n");
return -ENODEV;
} else if (result == TOS_INPUT_DATA_ERROR) {
return -EIO;
}
*radio_state = value & HCI_WIRELESS_KILL_SWITCH; return 0;
return hci_result;
} }
static int bt_rfkill_set_block(void *data, bool blocked) static int toshiba_usb_sleep_charge_set(struct toshiba_acpi_dev *dev,
u32 mode)
{ {
struct toshiba_acpi_dev *dev = data; u32 result;
u32 result1, result2;
u32 value;
int err;
bool radio_state;
value = (blocked == false);
mutex_lock(&dev->mutex); if (!sci_open(dev))
if (hci_get_radio_state(dev, &radio_state) != TOS_SUCCESS) { return -EIO;
err = -EIO;
goto out;
}
if (!radio_state) { result = sci_write(dev, SCI_USB_SLEEP_CHARGE, mode);
err = 0; sci_close(dev);
goto out; if (result == TOS_FAILURE) {
pr_err("ACPI call to set USB S&C mode failed\n");
return -EIO;
} else if (result == TOS_NOT_SUPPORTED) {
pr_info("USB Sleep and Charge not supported\n");
return -ENODEV;
} else if (result == TOS_INPUT_DATA_ERROR) {
return -EIO;
} }
result1 = hci_write2(dev, HCI_WIRELESS, value, HCI_WIRELESS_BT_POWER); return 0;
result2 = hci_write2(dev, HCI_WIRELESS, value, HCI_WIRELESS_BT_ATTACH);
if (result1 != TOS_SUCCESS || result2 != TOS_SUCCESS)
err = -EIO;
else
err = 0;
out:
mutex_unlock(&dev->mutex);
return err;
} }
static void bt_rfkill_poll(struct rfkill *rfkill, void *data) static int toshiba_sleep_functions_status_get(struct toshiba_acpi_dev *dev,
u32 *mode)
{ {
bool new_rfk_state; u32 in[TCI_WORDS] = { SCI_GET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 };
bool value; u32 out[TCI_WORDS];
u32 hci_result; acpi_status status;
struct toshiba_acpi_dev *dev = data;
mutex_lock(&dev->mutex); if (!sci_open(dev))
return -EIO;
hci_result = hci_get_radio_state(dev, &value); in[5] = SCI_USB_CHARGE_BAT_LVL;
if (hci_result != TOS_SUCCESS) { status = tci_raw(dev, in, out);
/* Can't do anything useful */ sci_close(dev);
mutex_unlock(&dev->mutex); if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) {
return; pr_err("ACPI call to get USB S&C battery level failed\n");
return -EIO;
} else if (out[0] == TOS_NOT_SUPPORTED) {
pr_info("USB Sleep and Charge not supported\n");
return -ENODEV;
} else if (out[0] == TOS_INPUT_DATA_ERROR) {
return -EIO;
} }
new_rfk_state = value; *mode = out[2];
mutex_unlock(&dev->mutex);
if (rfkill_set_hw_state(rfkill, !new_rfk_state)) return 0;
bt_rfkill_set_block(data, true);
} }
static const struct rfkill_ops toshiba_rfk_ops = { static int toshiba_sleep_functions_status_set(struct toshiba_acpi_dev *dev,
.set_block = bt_rfkill_set_block, u32 mode)
.poll = bt_rfkill_poll,
};
static int get_tr_backlight_status(struct toshiba_acpi_dev *dev, bool *enabled)
{ {
u32 hci_result; u32 in[TCI_WORDS] = { SCI_SET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 };
u32 status; u32 out[TCI_WORDS];
acpi_status status;
hci_result = hci_read1(dev, HCI_TR_BACKLIGHT, &status); if (!sci_open(dev))
*enabled = !status; return -EIO;
return hci_result == TOS_SUCCESS ? 0 : -EIO;
}
static int set_tr_backlight_status(struct toshiba_acpi_dev *dev, bool enable) in[2] = mode;
{ in[5] = SCI_USB_CHARGE_BAT_LVL;
u32 hci_result; status = tci_raw(dev, in, out);
u32 value = !enable; sci_close(dev);
if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) {
pr_err("ACPI call to set USB S&C battery level failed\n");
return -EIO;
} else if (out[0] == TOS_NOT_SUPPORTED) {
pr_info("USB Sleep and Charge not supported\n");
return -ENODEV;
} else if (out[0] == TOS_INPUT_DATA_ERROR) {
return -EIO;
}
hci_result = hci_write1(dev, HCI_TR_BACKLIGHT, value); return 0;
return hci_result == TOS_SUCCESS ? 0 : -EIO;
} }
static struct proc_dir_entry *toshiba_proc_dir /*= 0*/ ; static int toshiba_usb_rapid_charge_get(struct toshiba_acpi_dev *dev,
u32 *state)
static int __get_lcd_brightness(struct toshiba_acpi_dev *dev)
{ {
u32 hci_result; u32 in[TCI_WORDS] = { SCI_GET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 };
u32 value; u32 out[TCI_WORDS];
int brightness = 0; acpi_status status;
if (dev->tr_backlight_supported) { if (!sci_open(dev))
bool enabled; return -EIO;
int ret = get_tr_backlight_status(dev, &enabled);
if (ret) in[5] = SCI_USB_CHARGE_RAPID_DSP;
return ret; status = tci_raw(dev, in, out);
if (enabled) sci_close(dev);
return 0; if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) {
brightness++; pr_err("ACPI call to get USB S&C battery level failed\n");
return -EIO;
} else if (out[0] == TOS_NOT_SUPPORTED ||
out[0] == TOS_INPUT_DATA_ERROR) {
pr_info("USB Sleep and Charge not supported\n");
return -ENODEV;
} }
hci_result = hci_read1(dev, HCI_LCD_BRIGHTNESS, &value); *state = out[2];
if (hci_result == TOS_SUCCESS)
return brightness + (value >> HCI_LCD_BRIGHTNESS_SHIFT);
return -EIO; return 0;
} }
static int get_lcd_brightness(struct backlight_device *bd) static int toshiba_usb_rapid_charge_set(struct toshiba_acpi_dev *dev,
u32 state)
{ {
struct toshiba_acpi_dev *dev = bl_get_data(bd); u32 in[TCI_WORDS] = { SCI_SET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 };
return __get_lcd_brightness(dev); u32 out[TCI_WORDS];
} acpi_status status;
static int lcd_proc_show(struct seq_file *m, void *v) if (!sci_open(dev))
{ return -EIO;
struct toshiba_acpi_dev *dev = m->private;
int value;
int levels;
if (!dev->backlight_dev) in[2] = state;
in[5] = SCI_USB_CHARGE_RAPID_DSP;
status = tci_raw(dev, in, out);
sci_close(dev);
if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) {
pr_err("ACPI call to set USB S&C battery level failed\n");
return -EIO;
} else if (out[0] == TOS_NOT_SUPPORTED) {
pr_info("USB Sleep and Charge not supported\n");
return -ENODEV; return -ENODEV;
} else if (out[0] == TOS_INPUT_DATA_ERROR) {
levels = dev->backlight_dev->props.max_brightness + 1; return -EIO;
value = get_lcd_brightness(dev->backlight_dev);
if (value >= 0) {
seq_printf(m, "brightness: %d\n", value);
seq_printf(m, "brightness_levels: %d\n", levels);
return 0;
} }
pr_err("Error reading LCD brightness\n"); return 0;
return -EIO;
} }
static int lcd_proc_open(struct inode *inode, struct file *file) static int toshiba_usb_sleep_music_get(struct toshiba_acpi_dev *dev, u32 *state)
{ {
return single_open(file, lcd_proc_show, PDE_DATA(inode)); u32 result;
}
static int set_lcd_brightness(struct toshiba_acpi_dev *dev, int value) if (!sci_open(dev))
{ return -EIO;
u32 hci_result;
if (dev->tr_backlight_supported) { result = sci_read(dev, SCI_USB_SLEEP_MUSIC, state);
bool enable = !value; sci_close(dev);
int ret = set_tr_backlight_status(dev, enable); if (result == TOS_FAILURE) {
if (ret) pr_err("ACPI call to set USB S&C mode failed\n");
return ret; return -EIO;
if (value) } else if (result == TOS_NOT_SUPPORTED) {
value--; pr_info("USB Sleep and Charge not supported\n");
return -ENODEV;
} else if (result == TOS_INPUT_DATA_ERROR) {
return -EIO;
} }
value = value << HCI_LCD_BRIGHTNESS_SHIFT; return 0;
hci_result = hci_write1(dev, HCI_LCD_BRIGHTNESS, value);
return hci_result == TOS_SUCCESS ? 0 : -EIO;
} }
static int set_lcd_status(struct backlight_device *bd) static int toshiba_usb_sleep_music_set(struct toshiba_acpi_dev *dev, u32 state)
{ {
struct toshiba_acpi_dev *dev = bl_get_data(bd); u32 result;
return set_lcd_brightness(dev, bd->props.brightness);
}
static ssize_t lcd_proc_write(struct file *file, const char __user *buf, if (!sci_open(dev))
size_t count, loff_t *pos) return -EIO;
result = sci_write(dev, SCI_USB_SLEEP_MUSIC, state);
sci_close(dev);
if (result == TOS_FAILURE) {
pr_err("ACPI call to set USB S&C mode failed\n");
return -EIO;
} else if (result == TOS_NOT_SUPPORTED) {
pr_info("USB Sleep and Charge not supported\n");
return -ENODEV;
} else if (result == TOS_INPUT_DATA_ERROR) {
return -EIO;
}
return 0;
}
/* Keyboard function keys */
static int toshiba_function_keys_get(struct toshiba_acpi_dev *dev, u32 *mode)
{
u32 result;
if (!sci_open(dev))
return -EIO;
result = sci_read(dev, SCI_KBD_FUNCTION_KEYS, mode);
sci_close(dev);
if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) {
pr_err("ACPI call to get KBD function keys failed\n");
return -EIO;
} else if (result == TOS_NOT_SUPPORTED) {
pr_info("KBD function keys not supported\n");
return -ENODEV;
}
return 0;
}
static int toshiba_function_keys_set(struct toshiba_acpi_dev *dev, u32 mode)
{
u32 result;
if (!sci_open(dev))
return -EIO;
result = sci_write(dev, SCI_KBD_FUNCTION_KEYS, mode);
sci_close(dev);
if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) {
pr_err("ACPI call to set KBD function keys failed\n");
return -EIO;
} else if (result == TOS_NOT_SUPPORTED) {
pr_info("KBD function keys not supported\n");
return -ENODEV;
}
return 0;
}
/* Panel Power ON */
static int toshiba_panel_power_on_get(struct toshiba_acpi_dev *dev, u32 *state)
{
u32 result;
if (!sci_open(dev))
return -EIO;
result = sci_read(dev, SCI_PANEL_POWER_ON, state);
sci_close(dev);
if (result == TOS_FAILURE) {
pr_err("ACPI call to get Panel Power ON failed\n");
return -EIO;
} else if (result == TOS_NOT_SUPPORTED) {
pr_info("Panel Power on not supported\n");
return -ENODEV;
} else if (result == TOS_INPUT_DATA_ERROR) {
return -EIO;
}
return 0;
}
static int toshiba_panel_power_on_set(struct toshiba_acpi_dev *dev, u32 state)
{
u32 result;
if (!sci_open(dev))
return -EIO;
result = sci_write(dev, SCI_PANEL_POWER_ON, state);
sci_close(dev);
if (result == TOS_FAILURE) {
pr_err("ACPI call to set Panel Power ON failed\n");
return -EIO;
} else if (result == TOS_NOT_SUPPORTED) {
pr_info("Panel Power ON not supported\n");
return -ENODEV;
} else if (result == TOS_INPUT_DATA_ERROR) {
return -EIO;
}
return 0;
}
/* USB Three */
static int toshiba_usb_three_get(struct toshiba_acpi_dev *dev, u32 *state)
{
u32 result;
if (!sci_open(dev))
return -EIO;
result = sci_read(dev, SCI_USB_THREE, state);
sci_close(dev);
if (result == TOS_FAILURE) {
pr_err("ACPI call to get USB 3 failed\n");
return -EIO;
} else if (result == TOS_NOT_SUPPORTED) {
pr_info("USB 3 not supported\n");
return -ENODEV;
} else if (result == TOS_INPUT_DATA_ERROR) {
return -EIO;
}
return 0;
}
static int toshiba_usb_three_set(struct toshiba_acpi_dev *dev, u32 state)
{
u32 result;
if (!sci_open(dev))
return -EIO;
result = sci_write(dev, SCI_USB_THREE, state);
sci_close(dev);
if (result == TOS_FAILURE) {
pr_err("ACPI call to set USB 3 failed\n");
return -EIO;
} else if (result == TOS_NOT_SUPPORTED) {
pr_info("USB 3 not supported\n");
return -ENODEV;
} else if (result == TOS_INPUT_DATA_ERROR) {
return -EIO;
}
return 0;
}
/* Bluetooth rfkill handlers */
static u32 hci_get_bt_present(struct toshiba_acpi_dev *dev, bool *present)
{
u32 hci_result;
u32 value, value2;
value = 0;
value2 = 0;
hci_result = hci_read2(dev, HCI_WIRELESS, &value, &value2);
if (hci_result == TOS_SUCCESS)
*present = (value & HCI_WIRELESS_BT_PRESENT) ? true : false;
return hci_result;
}
static u32 hci_get_radio_state(struct toshiba_acpi_dev *dev, bool *radio_state)
{
u32 hci_result;
u32 value, value2;
value = 0;
value2 = 0x0001;
hci_result = hci_read2(dev, HCI_WIRELESS, &value, &value2);
*radio_state = value & HCI_WIRELESS_KILL_SWITCH;
return hci_result;
}
static int bt_rfkill_set_block(void *data, bool blocked)
{
struct toshiba_acpi_dev *dev = data;
u32 result1, result2;
u32 value;
int err;
bool radio_state;
value = (blocked == false);
mutex_lock(&dev->mutex);
if (hci_get_radio_state(dev, &radio_state) != TOS_SUCCESS) {
err = -EIO;
goto out;
}
if (!radio_state) {
err = 0;
goto out;
}
result1 = hci_write2(dev, HCI_WIRELESS, value, HCI_WIRELESS_BT_POWER);
result2 = hci_write2(dev, HCI_WIRELESS, value, HCI_WIRELESS_BT_ATTACH);
if (result1 != TOS_SUCCESS || result2 != TOS_SUCCESS)
err = -EIO;
else
err = 0;
out:
mutex_unlock(&dev->mutex);
return err;
}
static void bt_rfkill_poll(struct rfkill *rfkill, void *data)
{
bool new_rfk_state;
bool value;
u32 hci_result;
struct toshiba_acpi_dev *dev = data;
mutex_lock(&dev->mutex);
hci_result = hci_get_radio_state(dev, &value);
if (hci_result != TOS_SUCCESS) {
/* Can't do anything useful */
mutex_unlock(&dev->mutex);
return;
}
new_rfk_state = value;
mutex_unlock(&dev->mutex);
if (rfkill_set_hw_state(rfkill, !new_rfk_state))
bt_rfkill_set_block(data, true);
}
static const struct rfkill_ops toshiba_rfk_ops = {
.set_block = bt_rfkill_set_block,
.poll = bt_rfkill_poll,
};
static int get_tr_backlight_status(struct toshiba_acpi_dev *dev, bool *enabled)
{
u32 hci_result;
u32 status;
hci_result = hci_read1(dev, HCI_TR_BACKLIGHT, &status);
*enabled = !status;
return hci_result == TOS_SUCCESS ? 0 : -EIO;
}
static int set_tr_backlight_status(struct toshiba_acpi_dev *dev, bool enable)
{
u32 hci_result;
u32 value = !enable;
hci_result = hci_write1(dev, HCI_TR_BACKLIGHT, value);
return hci_result == TOS_SUCCESS ? 0 : -EIO;
}
static struct proc_dir_entry *toshiba_proc_dir /*= 0*/;
static int __get_lcd_brightness(struct toshiba_acpi_dev *dev)
{
u32 hci_result;
u32 value;
int brightness = 0;
if (dev->tr_backlight_supported) {
bool enabled;
int ret = get_tr_backlight_status(dev, &enabled);
if (ret)
return ret;
if (enabled)
return 0;
brightness++;
}
hci_result = hci_read1(dev, HCI_LCD_BRIGHTNESS, &value);
if (hci_result == TOS_SUCCESS)
return brightness + (value >> HCI_LCD_BRIGHTNESS_SHIFT);
return -EIO;
}
static int get_lcd_brightness(struct backlight_device *bd)
{
struct toshiba_acpi_dev *dev = bl_get_data(bd);
return __get_lcd_brightness(dev);
}
static int lcd_proc_show(struct seq_file *m, void *v)
{
struct toshiba_acpi_dev *dev = m->private;
int value;
int levels;
if (!dev->backlight_dev)
return -ENODEV;
levels = dev->backlight_dev->props.max_brightness + 1;
value = get_lcd_brightness(dev->backlight_dev);
if (value >= 0) {
seq_printf(m, "brightness: %d\n", value);
seq_printf(m, "brightness_levels: %d\n", levels);
return 0;
}
pr_err("Error reading LCD brightness\n");
return -EIO;
}
static int lcd_proc_open(struct inode *inode, struct file *file)
{
return single_open(file, lcd_proc_show, PDE_DATA(inode));
}
static int set_lcd_brightness(struct toshiba_acpi_dev *dev, int value)
{
u32 hci_result;
if (dev->tr_backlight_supported) {
bool enable = !value;
int ret = set_tr_backlight_status(dev, enable);
if (ret)
return ret;
if (value)
value--;
}
value = value << HCI_LCD_BRIGHTNESS_SHIFT;
hci_result = hci_write1(dev, HCI_LCD_BRIGHTNESS, value);
return hci_result == TOS_SUCCESS ? 0 : -EIO;
}
static int set_lcd_status(struct backlight_device *bd)
{
struct toshiba_acpi_dev *dev = bl_get_data(bd);
return set_lcd_brightness(dev, bd->props.brightness);
}
static ssize_t lcd_proc_write(struct file *file, const char __user *buf,
size_t count, loff_t *pos)
{ {
struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file)); struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file));
char cmd[42]; char cmd[42];
...@@ -1005,6 +1398,7 @@ static int video_proc_show(struct seq_file *m, void *v) ...@@ -1005,6 +1398,7 @@ static int video_proc_show(struct seq_file *m, void *v)
int is_lcd = (value & HCI_VIDEO_OUT_LCD) ? 1 : 0; int is_lcd = (value & HCI_VIDEO_OUT_LCD) ? 1 : 0;
int is_crt = (value & HCI_VIDEO_OUT_CRT) ? 1 : 0; int is_crt = (value & HCI_VIDEO_OUT_CRT) ? 1 : 0;
int is_tv = (value & HCI_VIDEO_OUT_TV) ? 1 : 0; int is_tv = (value & HCI_VIDEO_OUT_TV) ? 1 : 0;
seq_printf(m, "lcd_out: %d\n", is_lcd); seq_printf(m, "lcd_out: %d\n", is_lcd);
seq_printf(m, "crt_out: %d\n", is_crt); seq_printf(m, "crt_out: %d\n", is_crt);
seq_printf(m, "tv_out: %d\n", is_tv); seq_printf(m, "tv_out: %d\n", is_tv);
...@@ -1042,9 +1436,9 @@ static ssize_t video_proc_write(struct file *file, const char __user *buf, ...@@ -1042,9 +1436,9 @@ static ssize_t video_proc_write(struct file *file, const char __user *buf,
buffer = cmd; buffer = cmd;
/* scan expression. Multiple expressions may be delimited with ; /*
* * Scan expression. Multiple expressions may be delimited with ;
* NOTE: to keep scanning simple, invalid fields are ignored * NOTE: To keep scanning simple, invalid fields are ignored.
*/ */
while (remain) { while (remain) {
if (sscanf(buffer, " lcd_out : %i", &value) == 1) if (sscanf(buffer, " lcd_out : %i", &value) == 1)
...@@ -1053,12 +1447,11 @@ static ssize_t video_proc_write(struct file *file, const char __user *buf, ...@@ -1053,12 +1447,11 @@ static ssize_t video_proc_write(struct file *file, const char __user *buf,
crt_out = value & 1; crt_out = value & 1;
else if (sscanf(buffer, " tv_out : %i", &value) == 1) else if (sscanf(buffer, " tv_out : %i", &value) == 1)
tv_out = value & 1; tv_out = value & 1;
/* advance to one character past the next ; */ /* Advance to one character past the next ; */
do { do {
++buffer; ++buffer;
--remain; --remain;
} } while (remain && *(buffer - 1) != ';');
while (remain && *(buffer - 1) != ';');
} }
kfree(cmd); kfree(cmd);
...@@ -1066,13 +1459,15 @@ static ssize_t video_proc_write(struct file *file, const char __user *buf, ...@@ -1066,13 +1459,15 @@ static ssize_t video_proc_write(struct file *file, const char __user *buf,
ret = get_video_status(dev, &video_out); ret = get_video_status(dev, &video_out);
if (!ret) { if (!ret) {
unsigned int new_video_out = video_out; unsigned int new_video_out = video_out;
if (lcd_out != -1) if (lcd_out != -1)
_set_bit(&new_video_out, HCI_VIDEO_OUT_LCD, lcd_out); _set_bit(&new_video_out, HCI_VIDEO_OUT_LCD, lcd_out);
if (crt_out != -1) if (crt_out != -1)
_set_bit(&new_video_out, HCI_VIDEO_OUT_CRT, crt_out); _set_bit(&new_video_out, HCI_VIDEO_OUT_CRT, crt_out);
if (tv_out != -1) if (tv_out != -1)
_set_bit(&new_video_out, HCI_VIDEO_OUT_TV, tv_out); _set_bit(&new_video_out, HCI_VIDEO_OUT_TV, tv_out);
/* To avoid unnecessary video disruption, only write the new /*
* To avoid unnecessary video disruption, only write the new
* video setting if something changed. */ * video setting if something changed. */
if (new_video_out != video_out) if (new_video_out != video_out)
ret = write_acpi_int(METHOD_VIDEO_OUT, new_video_out); ret = write_acpi_int(METHOD_VIDEO_OUT, new_video_out);
...@@ -1135,10 +1530,10 @@ static ssize_t fan_proc_write(struct file *file, const char __user *buf, ...@@ -1135,10 +1530,10 @@ static ssize_t fan_proc_write(struct file *file, const char __user *buf,
if (sscanf(cmd, " force_on : %i", &value) == 1 && if (sscanf(cmd, " force_on : %i", &value) == 1 &&
value >= 0 && value <= 1) { value >= 0 && value <= 1) {
hci_result = hci_write1(dev, HCI_FAN, value); hci_result = hci_write1(dev, HCI_FAN, value);
if (hci_result != TOS_SUCCESS) if (hci_result == TOS_SUCCESS)
return -EIO;
else
dev->force_fan = value; dev->force_fan = value;
else
return -EIO;
} else { } else {
return -EINVAL; return -EINVAL;
} }
...@@ -1167,11 +1562,13 @@ static int keys_proc_show(struct seq_file *m, void *v) ...@@ -1167,11 +1562,13 @@ static int keys_proc_show(struct seq_file *m, void *v)
dev->key_event_valid = 1; dev->key_event_valid = 1;
dev->last_key_event = value; dev->last_key_event = value;
} else if (hci_result == TOS_FIFO_EMPTY) { } else if (hci_result == TOS_FIFO_EMPTY) {
/* better luck next time */ /* Better luck next time */
} else if (hci_result == TOS_NOT_SUPPORTED) { } else if (hci_result == TOS_NOT_SUPPORTED) {
/* This is a workaround for an unresolved issue on /*
* This is a workaround for an unresolved issue on
* some machines where system events sporadically * some machines where system events sporadically
* become disabled. */ * become disabled.
*/
hci_result = hci_write1(dev, HCI_SYSTEM_EVENT, 1); hci_result = hci_write1(dev, HCI_SYSTEM_EVENT, 1);
pr_notice("Re-enabled hotkeys\n"); pr_notice("Re-enabled hotkeys\n");
} else { } else {
...@@ -1203,11 +1600,10 @@ static ssize_t keys_proc_write(struct file *file, const char __user *buf, ...@@ -1203,11 +1600,10 @@ static ssize_t keys_proc_write(struct file *file, const char __user *buf,
return -EFAULT; return -EFAULT;
cmd[len] = '\0'; cmd[len] = '\0';
if (sscanf(cmd, " hotkey_ready : %i", &value) == 1 && value == 0) { if (sscanf(cmd, " hotkey_ready : %i", &value) == 1 && value == 0)
dev->key_event_valid = 0; dev->key_event_valid = 0;
} else { else
return -EINVAL; return -EINVAL;
}
return count; return count;
} }
...@@ -1241,7 +1637,8 @@ static const struct file_operations version_proc_fops = { ...@@ -1241,7 +1637,8 @@ static const struct file_operations version_proc_fops = {
.release = single_release, .release = single_release,
}; };
/* proc and module init /*
* Proc and module init
*/ */
#define PROC_TOSHIBA "toshiba" #define PROC_TOSHIBA "toshiba"
...@@ -1286,64 +1683,54 @@ static const struct backlight_ops toshiba_backlight_data = { ...@@ -1286,64 +1683,54 @@ static const struct backlight_ops toshiba_backlight_data = {
/* /*
* Sysfs files * Sysfs files
*/ */
static ssize_t toshiba_kbd_bl_mode_store(struct device *dev, static ssize_t version_show(struct device *dev,
struct device_attribute *attr, struct device_attribute *attr, char *buf)
const char *buf, size_t count); {
static ssize_t toshiba_kbd_bl_mode_show(struct device *dev, return sprintf(buf, "%s\n", TOSHIBA_ACPI_VERSION);
struct device_attribute *attr, }
char *buf); static DEVICE_ATTR_RO(version);
static ssize_t toshiba_kbd_type_show(struct device *dev,
struct device_attribute *attr, static ssize_t fan_store(struct device *dev,
char *buf);
static ssize_t toshiba_available_kbd_modes_show(struct device *dev,
struct device_attribute *attr,
char *buf);
static ssize_t toshiba_kbd_bl_timeout_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count);
static ssize_t toshiba_kbd_bl_timeout_show(struct device *dev,
struct device_attribute *attr,
char *buf);
static ssize_t toshiba_touchpad_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count);
static ssize_t toshiba_touchpad_show(struct device *dev,
struct device_attribute *attr,
char *buf);
static ssize_t toshiba_position_show(struct device *dev,
struct device_attribute *attr, struct device_attribute *attr,
char *buf); const char *buf, size_t count)
{
static DEVICE_ATTR(kbd_backlight_mode, S_IRUGO | S_IWUSR, struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
toshiba_kbd_bl_mode_show, toshiba_kbd_bl_mode_store); u32 result;
static DEVICE_ATTR(kbd_type, S_IRUGO, toshiba_kbd_type_show, NULL); int state;
static DEVICE_ATTR(available_kbd_modes, S_IRUGO, int ret;
toshiba_available_kbd_modes_show, NULL);
static DEVICE_ATTR(kbd_backlight_timeout, S_IRUGO | S_IWUSR,
toshiba_kbd_bl_timeout_show, toshiba_kbd_bl_timeout_store);
static DEVICE_ATTR(touchpad, S_IRUGO | S_IWUSR,
toshiba_touchpad_show, toshiba_touchpad_store);
static DEVICE_ATTR(position, S_IRUGO, toshiba_position_show, NULL);
static struct attribute *toshiba_attributes[] = { ret = kstrtoint(buf, 0, &state);
&dev_attr_kbd_backlight_mode.attr, if (ret)
&dev_attr_kbd_type.attr, return ret;
&dev_attr_available_kbd_modes.attr,
&dev_attr_kbd_backlight_timeout.attr, if (state != 0 && state != 1)
&dev_attr_touchpad.attr, return -EINVAL;
&dev_attr_position.attr,
NULL, result = hci_write1(toshiba, HCI_FAN, state);
}; if (result == TOS_FAILURE)
return -EIO;
else if (result == TOS_NOT_SUPPORTED)
return -ENODEV;
return count;
}
static ssize_t fan_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
u32 value;
int ret;
static umode_t toshiba_sysfs_is_visible(struct kobject *, ret = get_fan_status(toshiba, &value);
struct attribute *, int); if (ret)
return ret;
static struct attribute_group toshiba_attr_group = { return sprintf(buf, "%d\n", value);
.is_visible = toshiba_sysfs_is_visible, }
.attrs = toshiba_attributes, static DEVICE_ATTR_RW(fan);
};
static ssize_t toshiba_kbd_bl_mode_store(struct device *dev, static ssize_t kbd_backlight_mode_store(struct device *dev,
struct device_attribute *attr, struct device_attribute *attr,
const char *buf, size_t count) const char *buf, size_t count)
{ {
...@@ -1369,7 +1756,8 @@ static ssize_t toshiba_kbd_bl_mode_store(struct device *dev, ...@@ -1369,7 +1756,8 @@ static ssize_t toshiba_kbd_bl_mode_store(struct device *dev,
return -EINVAL; return -EINVAL;
} }
/* Set the Keyboard Backlight Mode where: /*
* Set the Keyboard Backlight Mode where:
* Auto - KBD backlight turns off automatically in given time * Auto - KBD backlight turns off automatically in given time
* FN-Z - KBD backlight "toggles" when hotkey pressed * FN-Z - KBD backlight "toggles" when hotkey pressed
* ON - KBD backlight is always on * ON - KBD backlight is always on
...@@ -1400,7 +1788,7 @@ static ssize_t toshiba_kbd_bl_mode_store(struct device *dev, ...@@ -1400,7 +1788,7 @@ static ssize_t toshiba_kbd_bl_mode_store(struct device *dev,
return count; return count;
} }
static ssize_t toshiba_kbd_bl_mode_show(struct device *dev, static ssize_t kbd_backlight_mode_show(struct device *dev,
struct device_attribute *attr, struct device_attribute *attr,
char *buf) char *buf)
{ {
...@@ -1412,17 +1800,18 @@ static ssize_t toshiba_kbd_bl_mode_show(struct device *dev, ...@@ -1412,17 +1800,18 @@ static ssize_t toshiba_kbd_bl_mode_show(struct device *dev,
return sprintf(buf, "%i\n", time & SCI_KBD_MODE_MASK); return sprintf(buf, "%i\n", time & SCI_KBD_MODE_MASK);
} }
static DEVICE_ATTR_RW(kbd_backlight_mode);
static ssize_t toshiba_kbd_type_show(struct device *dev, static ssize_t kbd_type_show(struct device *dev,
struct device_attribute *attr, struct device_attribute *attr, char *buf)
char *buf)
{ {
struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", toshiba->kbd_type); return sprintf(buf, "%d\n", toshiba->kbd_type);
} }
static DEVICE_ATTR_RO(kbd_type);
static ssize_t toshiba_available_kbd_modes_show(struct device *dev, static ssize_t available_kbd_modes_show(struct device *dev,
struct device_attribute *attr, struct device_attribute *attr,
char *buf) char *buf)
{ {
...@@ -1435,8 +1824,9 @@ static ssize_t toshiba_available_kbd_modes_show(struct device *dev, ...@@ -1435,8 +1824,9 @@ static ssize_t toshiba_available_kbd_modes_show(struct device *dev,
return sprintf(buf, "%x %x %x\n", return sprintf(buf, "%x %x %x\n",
SCI_KBD_MODE_AUTO, SCI_KBD_MODE_ON, SCI_KBD_MODE_OFF); SCI_KBD_MODE_AUTO, SCI_KBD_MODE_ON, SCI_KBD_MODE_OFF);
} }
static DEVICE_ATTR_RO(available_kbd_modes);
static ssize_t toshiba_kbd_bl_timeout_store(struct device *dev, static ssize_t kbd_backlight_timeout_store(struct device *dev,
struct device_attribute *attr, struct device_attribute *attr,
const char *buf, size_t count) const char *buf, size_t count)
{ {
...@@ -1479,7 +1869,7 @@ static ssize_t toshiba_kbd_bl_timeout_store(struct device *dev, ...@@ -1479,7 +1869,7 @@ static ssize_t toshiba_kbd_bl_timeout_store(struct device *dev,
return count; return count;
} }
static ssize_t toshiba_kbd_bl_timeout_show(struct device *dev, static ssize_t kbd_backlight_timeout_show(struct device *dev,
struct device_attribute *attr, struct device_attribute *attr,
char *buf) char *buf)
{ {
...@@ -1491,8 +1881,9 @@ static ssize_t toshiba_kbd_bl_timeout_show(struct device *dev, ...@@ -1491,8 +1881,9 @@ static ssize_t toshiba_kbd_bl_timeout_show(struct device *dev,
return sprintf(buf, "%i\n", time >> HCI_MISC_SHIFT); return sprintf(buf, "%i\n", time >> HCI_MISC_SHIFT);
} }
static DEVICE_ATTR_RW(kbd_backlight_timeout);
static ssize_t toshiba_touchpad_store(struct device *dev, static ssize_t touchpad_store(struct device *dev,
struct device_attribute *attr, struct device_attribute *attr,
const char *buf, size_t count) const char *buf, size_t count)
{ {
...@@ -1514,7 +1905,7 @@ static ssize_t toshiba_touchpad_store(struct device *dev, ...@@ -1514,7 +1905,7 @@ static ssize_t toshiba_touchpad_store(struct device *dev,
return count; return count;
} }
static ssize_t toshiba_touchpad_show(struct device *dev, static ssize_t touchpad_show(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
...@@ -1527,8 +1918,9 @@ static ssize_t toshiba_touchpad_show(struct device *dev, ...@@ -1527,8 +1918,9 @@ static ssize_t toshiba_touchpad_show(struct device *dev,
return sprintf(buf, "%i\n", state); return sprintf(buf, "%i\n", state);
} }
static DEVICE_ATTR_RW(touchpad);
static ssize_t toshiba_position_show(struct device *dev, static ssize_t position_show(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
...@@ -1548,6 +1940,336 @@ static ssize_t toshiba_position_show(struct device *dev, ...@@ -1548,6 +1940,336 @@ static ssize_t toshiba_position_show(struct device *dev,
return sprintf(buf, "%d %d %d\n", x, y, z); return sprintf(buf, "%d %d %d\n", x, y, z);
} }
static DEVICE_ATTR_RO(position);
static ssize_t usb_sleep_charge_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
u32 mode;
int ret;
ret = toshiba_usb_sleep_charge_get(toshiba, &mode);
if (ret < 0)
return ret;
return sprintf(buf, "%x\n", mode & SCI_USB_CHARGE_MODE_MASK);
}
static ssize_t usb_sleep_charge_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
u32 mode;
int state;
int ret;
ret = kstrtoint(buf, 0, &state);
if (ret)
return ret;
/*
* Check for supported values, where:
* 0 - Disabled
* 1 - Alternate (Non USB conformant devices that require more power)
* 2 - Auto (USB conformant devices)
*/
if (state != 0 && state != 1 && state != 2)
return -EINVAL;
/* Set the USB charging mode to internal value */
if (state == 0)
mode = SCI_USB_CHARGE_DISABLED;
else if (state == 1)
mode = SCI_USB_CHARGE_ALTERNATE;
else if (state == 2)
mode = SCI_USB_CHARGE_AUTO;
ret = toshiba_usb_sleep_charge_set(toshiba, mode);
if (ret)
return ret;
return count;
}
static DEVICE_ATTR_RW(usb_sleep_charge);
static ssize_t sleep_functions_on_battery_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
u32 state;
int bat_lvl;
int status;
int ret;
int tmp;
ret = toshiba_sleep_functions_status_get(toshiba, &state);
if (ret < 0)
return ret;
/* Determine the status: 0x4 - Enabled | 0x1 - Disabled */
tmp = state & SCI_USB_CHARGE_BAT_MASK;
status = (tmp == 0x4) ? 1 : 0;
/* Determine the battery level set */
bat_lvl = state >> HCI_MISC_SHIFT;
return sprintf(buf, "%d %d\n", status, bat_lvl);
}
static ssize_t sleep_functions_on_battery_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
u32 status;
int value;
int ret;
int tmp;
ret = kstrtoint(buf, 0, &value);
if (ret)
return ret;
/*
* Set the status of the function:
* 0 - Disabled
* 1-100 - Enabled
*/
if (value < 0 || value > 100)
return -EINVAL;
if (value == 0) {
tmp = toshiba->usbsc_bat_level << HCI_MISC_SHIFT;
status = tmp | SCI_USB_CHARGE_BAT_LVL_OFF;
} else {
tmp = value << HCI_MISC_SHIFT;
status = tmp | SCI_USB_CHARGE_BAT_LVL_ON;
}
ret = toshiba_sleep_functions_status_set(toshiba, status);
if (ret < 0)
return ret;
toshiba->usbsc_bat_level = status >> HCI_MISC_SHIFT;
return count;
}
static DEVICE_ATTR_RW(sleep_functions_on_battery);
static ssize_t usb_rapid_charge_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
u32 state;
int ret;
ret = toshiba_usb_rapid_charge_get(toshiba, &state);
if (ret < 0)
return ret;
return sprintf(buf, "%d\n", state);
}
static ssize_t usb_rapid_charge_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
int state;
int ret;
ret = kstrtoint(buf, 0, &state);
if (ret)
return ret;
if (state != 0 && state != 1)
return -EINVAL;
ret = toshiba_usb_rapid_charge_set(toshiba, state);
if (ret)
return ret;
return count;
}
static DEVICE_ATTR_RW(usb_rapid_charge);
static ssize_t usb_sleep_music_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
u32 state;
int ret;
ret = toshiba_usb_sleep_music_get(toshiba, &state);
if (ret < 0)
return ret;
return sprintf(buf, "%d\n", state);
}
static ssize_t usb_sleep_music_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
int state;
int ret;
ret = kstrtoint(buf, 0, &state);
if (ret)
return ret;
if (state != 0 && state != 1)
return -EINVAL;
ret = toshiba_usb_sleep_music_set(toshiba, state);
if (ret)
return ret;
return count;
}
static DEVICE_ATTR_RW(usb_sleep_music);
static ssize_t kbd_function_keys_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
int mode;
int ret;
ret = toshiba_function_keys_get(toshiba, &mode);
if (ret < 0)
return ret;
return sprintf(buf, "%d\n", mode);
}
static ssize_t kbd_function_keys_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
int mode;
int ret;
ret = kstrtoint(buf, 0, &mode);
if (ret)
return ret;
/*
* Check for the function keys mode where:
* 0 - Normal operation (F{1-12} as usual and hotkeys via FN-F{1-12})
* 1 - Special functions (Opposite of the above setting)
*/
if (mode != 0 && mode != 1)
return -EINVAL;
ret = toshiba_function_keys_set(toshiba, mode);
if (ret)
return ret;
pr_info("Reboot for changes to KBD Function Keys to take effect");
return count;
}
static DEVICE_ATTR_RW(kbd_function_keys);
static ssize_t panel_power_on_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
u32 state;
int ret;
ret = toshiba_panel_power_on_get(toshiba, &state);
if (ret < 0)
return ret;
return sprintf(buf, "%d\n", state);
}
static ssize_t panel_power_on_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
int state;
int ret;
ret = kstrtoint(buf, 0, &state);
if (ret)
return ret;
if (state != 0 && state != 1)
return -EINVAL;
ret = toshiba_panel_power_on_set(toshiba, state);
if (ret)
return ret;
pr_info("Reboot for changes to Panel Power ON to take effect");
return count;
}
static DEVICE_ATTR_RW(panel_power_on);
static ssize_t usb_three_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
u32 state;
int ret;
ret = toshiba_usb_three_get(toshiba, &state);
if (ret < 0)
return ret;
return sprintf(buf, "%d\n", state);
}
static ssize_t usb_three_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
int state;
int ret;
ret = kstrtoint(buf, 0, &state);
if (ret)
return ret;
/*
* Check for USB 3 mode where:
* 0 - Disabled (Acts like a USB 2 port, saving power)
* 1 - Enabled
*/
if (state != 0 && state != 1)
return -EINVAL;
ret = toshiba_usb_three_set(toshiba, state);
if (ret)
return ret;
pr_info("Reboot for changes to USB 3 to take effect");
return count;
}
static DEVICE_ATTR_RW(usb_three);
static struct attribute *toshiba_attributes[] = {
&dev_attr_version.attr,
&dev_attr_fan.attr,
&dev_attr_kbd_backlight_mode.attr,
&dev_attr_kbd_type.attr,
&dev_attr_available_kbd_modes.attr,
&dev_attr_kbd_backlight_timeout.attr,
&dev_attr_touchpad.attr,
&dev_attr_position.attr,
&dev_attr_usb_sleep_charge.attr,
&dev_attr_sleep_functions_on_battery.attr,
&dev_attr_usb_rapid_charge.attr,
&dev_attr_usb_sleep_music.attr,
&dev_attr_kbd_function_keys.attr,
&dev_attr_panel_power_on.attr,
&dev_attr_usb_three.attr,
NULL,
};
static umode_t toshiba_sysfs_is_visible(struct kobject *kobj, static umode_t toshiba_sysfs_is_visible(struct kobject *kobj,
struct attribute *attr, int idx) struct attribute *attr, int idx)
...@@ -1556,7 +2278,9 @@ static umode_t toshiba_sysfs_is_visible(struct kobject *kobj, ...@@ -1556,7 +2278,9 @@ static umode_t toshiba_sysfs_is_visible(struct kobject *kobj,
struct toshiba_acpi_dev *drv = dev_get_drvdata(dev); struct toshiba_acpi_dev *drv = dev_get_drvdata(dev);
bool exists = true; bool exists = true;
if (attr == &dev_attr_kbd_backlight_mode.attr) if (attr == &dev_attr_fan.attr)
exists = (drv->fan_supported) ? true : false;
else if (attr == &dev_attr_kbd_backlight_mode.attr)
exists = (drv->kbd_illum_supported) ? true : false; exists = (drv->kbd_illum_supported) ? true : false;
else if (attr == &dev_attr_kbd_backlight_timeout.attr) else if (attr == &dev_attr_kbd_backlight_timeout.attr)
exists = (drv->kbd_mode == SCI_KBD_MODE_AUTO) ? true : false; exists = (drv->kbd_mode == SCI_KBD_MODE_AUTO) ? true : false;
...@@ -1564,10 +2288,29 @@ static umode_t toshiba_sysfs_is_visible(struct kobject *kobj, ...@@ -1564,10 +2288,29 @@ static umode_t toshiba_sysfs_is_visible(struct kobject *kobj,
exists = (drv->touchpad_supported) ? true : false; exists = (drv->touchpad_supported) ? true : false;
else if (attr == &dev_attr_position.attr) else if (attr == &dev_attr_position.attr)
exists = (drv->accelerometer_supported) ? true : false; exists = (drv->accelerometer_supported) ? true : false;
else if (attr == &dev_attr_usb_sleep_charge.attr)
exists = (drv->usb_sleep_charge_supported) ? true : false;
else if (attr == &dev_attr_sleep_functions_on_battery.attr)
exists = (drv->usb_sleep_charge_supported) ? true : false;
else if (attr == &dev_attr_usb_rapid_charge.attr)
exists = (drv->usb_rapid_charge_supported) ? true : false;
else if (attr == &dev_attr_usb_sleep_music.attr)
exists = (drv->usb_sleep_music_supported) ? true : false;
else if (attr == &dev_attr_kbd_function_keys.attr)
exists = (drv->kbd_function_keys_supported) ? true : false;
else if (attr == &dev_attr_panel_power_on.attr)
exists = (drv->panel_power_on_supported) ? true : false;
else if (attr == &dev_attr_usb_three.attr)
exists = (drv->usb_three_supported) ? true : false;
return exists ? attr->mode : 0; return exists ? attr->mode : 0;
} }
static struct attribute_group toshiba_attr_group = {
.is_visible = toshiba_sysfs_is_visible,
.attrs = toshiba_attributes,
};
/* /*
* Hotkeys * Hotkeys
*/ */
...@@ -1644,7 +2387,7 @@ static void toshiba_acpi_report_hotkey(struct toshiba_acpi_dev *dev, ...@@ -1644,7 +2387,7 @@ static void toshiba_acpi_report_hotkey(struct toshiba_acpi_dev *dev,
if (scancode == 0x100) if (scancode == 0x100)
return; return;
/* act on key press; ignore key release */ /* Act on key press; ignore key release */
if (scancode & 0x80) if (scancode & 0x80)
return; return;
...@@ -1680,7 +2423,7 @@ static void toshiba_acpi_process_hotkeys(struct toshiba_acpi_dev *dev) ...@@ -1680,7 +2423,7 @@ static void toshiba_acpi_process_hotkeys(struct toshiba_acpi_dev *dev)
hci_result = hci_result =
hci_write1(dev, HCI_SYSTEM_EVENT, 1); hci_write1(dev, HCI_SYSTEM_EVENT, 1);
pr_notice("Re-enabled hotkeys\n"); pr_notice("Re-enabled hotkeys\n");
/* fall through */ /* Fall through */
default: default:
retries--; retries--;
break; break;
...@@ -1802,7 +2545,7 @@ static int toshiba_acpi_setup_backlight(struct toshiba_acpi_dev *dev) ...@@ -1802,7 +2545,7 @@ static int toshiba_acpi_setup_backlight(struct toshiba_acpi_dev *dev)
props.type = BACKLIGHT_PLATFORM; props.type = BACKLIGHT_PLATFORM;
props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1; props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1;
/* adding an extra level and having 0 change to transflective mode */ /* Adding an extra level and having 0 change to transflective mode */
if (dev->tr_backlight_supported) if (dev->tr_backlight_supported)
props.max_brightness++; props.max_brightness++;
...@@ -1973,6 +2716,24 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev) ...@@ -1973,6 +2716,24 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev)
ret = toshiba_accelerometer_supported(dev); ret = toshiba_accelerometer_supported(dev);
dev->accelerometer_supported = !ret; dev->accelerometer_supported = !ret;
ret = toshiba_usb_sleep_charge_get(dev, &dummy);
dev->usb_sleep_charge_supported = !ret;
ret = toshiba_usb_rapid_charge_get(dev, &dummy);
dev->usb_rapid_charge_supported = !ret;
ret = toshiba_usb_sleep_music_get(dev, &dummy);
dev->usb_sleep_music_supported = !ret;
ret = toshiba_function_keys_get(dev, &dummy);
dev->kbd_function_keys_supported = !ret;
ret = toshiba_panel_power_on_get(dev, &dummy);
dev->panel_power_on_supported = !ret;
ret = toshiba_usb_three_get(dev, &dummy);
dev->usb_three_supported = !ret;
/* Determine whether or not BIOS supports fan and video interfaces */ /* Determine whether or not BIOS supports fan and video interfaces */
ret = get_video_status(dev, &dummy); ret = get_video_status(dev, &dummy);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment