#define HCI_WIRELESS_BT_PRESENT 0x0f
#define HCI_WIRELESS_BT_ATTACH 0x40
#define HCI_WIRELESS_BT_POWER 0x80
+#define SCI_KBD_MODE_MASK 0x1f
#define SCI_KBD_MODE_FNZ 0x1
#define SCI_KBD_MODE_AUTO 0x2
+#define SCI_KBD_MODE_ON 0x8
+#define SCI_KBD_MODE_OFF 0x10
+#define SCI_KBD_TIME_MAX 0x3c001a
struct toshiba_acpi_dev {
struct acpi_device *acpi_dev;
int force_fan;
int last_key_event;
int key_event_valid;
+ int kbd_type;
int kbd_mode;
int kbd_time;
}
/* KBD Illumination */
+static int toshiba_kbd_illum_available(struct toshiba_acpi_dev *dev)
+{
+ u32 in[HCI_WORDS] = { SCI_GET, SCI_KBD_ILLUM_STATUS, 0, 0, 0, 0 };
+ u32 out[HCI_WORDS];
+ acpi_status status;
+
+ if (!sci_open(dev))
+ return 0;
+
+ status = hci_raw(dev, in, out);
+ sci_close(dev);
+ if (ACPI_FAILURE(status) || out[0] == SCI_INPUT_DATA_ERROR) {
+ pr_err("ACPI call to query kbd illumination support failed\n");
+ return 0;
+ } else if (out[0] == HCI_NOT_SUPPORTED) {
+ pr_info("Keyboard illumination not available\n");
+ return 0;
+ }
+
+ /* Check for keyboard backlight timeout max value,
+ * previous kbd backlight implementation set this to
+ * 0x3c0003, and now the new implementation set this
+ * to 0x3c001a, use this to distinguish between them
+ */
+ if (out[3] == SCI_KBD_TIME_MAX)
+ dev->kbd_type = 2;
+ else
+ dev->kbd_type = 1;
+ /* Get the current keyboard backlight mode */
+ dev->kbd_mode = out[2] & SCI_KBD_MODE_MASK;
+ /* Get the current time (1-60 seconds) */
+ dev->kbd_time = out[2] >> HCI_MISC_SHIFT;
+
+ return 1;
+}
+
static int toshiba_kbd_illum_status_set(struct toshiba_acpi_dev *dev, u32 time)
{
u32 result;
/*
* Sysfs files
*/
+static ssize_t toshiba_kbd_bl_mode_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count);
+static ssize_t toshiba_kbd_bl_mode_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf);
+static ssize_t toshiba_kbd_type_show(struct device *dev,
+ struct device_attribute *attr,
+ 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,
+ char *buf);
+
+static DEVICE_ATTR(kbd_backlight_mode, S_IRUGO | S_IWUSR,
+ toshiba_kbd_bl_mode_show, toshiba_kbd_bl_mode_store);
+static DEVICE_ATTR(kbd_type, S_IRUGO, toshiba_kbd_type_show, NULL);
+static DEVICE_ATTR(available_kbd_modes, S_IRUGO,
+ 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[] = {
+ &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,
+ NULL,
+};
+
+static umode_t toshiba_sysfs_is_visible(struct kobject *,
+ struct attribute *, int);
+
+static struct attribute_group toshiba_attr_group = {
+ .is_visible = toshiba_sysfs_is_visible,
+ .attrs = toshiba_attributes,
+};
static ssize_t toshiba_kbd_bl_mode_store(struct device *dev,
struct device_attribute *attr,
ret = kstrtoint(buf, 0, &mode);
if (ret)
return ret;
- if (mode != SCI_KBD_MODE_FNZ && mode != SCI_KBD_MODE_AUTO)
- return -EINVAL;
+
+ /* Check for supported modes depending on keyboard backlight type */
+ if (toshiba->kbd_type == 1) {
+ /* Type 1 supports SCI_KBD_MODE_FNZ and SCI_KBD_MODE_AUTO */
+ if (mode != SCI_KBD_MODE_FNZ && mode != SCI_KBD_MODE_AUTO)
+ return -EINVAL;
+ } else if (toshiba->kbd_type == 2) {
+ /* Type 2 doesn't support SCI_KBD_MODE_FNZ */
+ if (mode != SCI_KBD_MODE_AUTO && mode != SCI_KBD_MODE_ON &&
+ mode != SCI_KBD_MODE_OFF)
+ return -EINVAL;
+ }
/* Set the Keyboard Backlight Mode where:
- * Mode - Auto (2) | FN-Z (1)
* Auto - KBD backlight turns off automatically in given time
* FN-Z - KBD backlight "toggles" when hotkey pressed
+ * ON - KBD backlight is always on
+ * OFF - KBD backlight is always off
*/
+
+ /* Only make a change if the actual mode has changed */
if (toshiba->kbd_mode != mode) {
+ /* Shift the time to "base time" (0x3c0000 == 60 seconds) */
time = toshiba->kbd_time << HCI_MISC_SHIFT;
- time = time + toshiba->kbd_mode;
+
+ /* OR the "base time" to the actual method format */
+ if (toshiba->kbd_type == 1) {
+ /* Type 1 requires the current mode */
+ time |= toshiba->kbd_mode;
+ } else if (toshiba->kbd_type == 2) {
+ /* Type 2 requires the desired mode */
+ time |= mode;
+ }
+
ret = toshiba_kbd_illum_status_set(toshiba, time);
if (ret)
return ret;
+
+ /* Update sysfs entries on successful mode change*/
+ ret = sysfs_update_group(&toshiba->acpi_dev->dev.kobj,
+ &toshiba_attr_group);
+ if (ret)
+ return ret;
+
toshiba->kbd_mode = mode;
}
if (toshiba_kbd_illum_status_get(toshiba, &time) < 0)
return -EIO;
- return sprintf(buf, "%i\n", time & 0x07);
+ return sprintf(buf, "%i\n", time & SCI_KBD_MODE_MASK);
+}
+
+static ssize_t toshiba_kbd_type_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%d\n", toshiba->kbd_type);
+}
+
+static ssize_t toshiba_available_kbd_modes_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
+
+ if (toshiba->kbd_type == 1)
+ return sprintf(buf, "%x %x\n",
+ SCI_KBD_MODE_FNZ, SCI_KBD_MODE_AUTO);
+
+ return sprintf(buf, "%x %x %x\n",
+ SCI_KBD_MODE_AUTO, SCI_KBD_MODE_ON, SCI_KBD_MODE_OFF);
}
static ssize_t toshiba_kbd_bl_timeout_store(struct device *dev,
return sprintf(buf, "%d %d %d\n", x, y, z);
}
-static DEVICE_ATTR(kbd_backlight_mode, S_IRUGO | S_IWUSR,
- toshiba_kbd_bl_mode_show, toshiba_kbd_bl_mode_store);
-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[] = {
- &dev_attr_kbd_backlight_mode.attr,
- &dev_attr_kbd_backlight_timeout.attr,
- &dev_attr_touchpad.attr,
- &dev_attr_position.attr,
- NULL,
-};
-
static umode_t toshiba_sysfs_is_visible(struct kobject *kobj,
struct attribute *attr, int idx)
{
return exists ? attr->mode : 0;
}
-static struct attribute_group toshiba_attr_group = {
- .is_visible = toshiba_sysfs_is_visible,
- .attrs = toshiba_attributes,
-};
-
static bool toshiba_acpi_i8042_filter(unsigned char data, unsigned char str,
struct serio *port)
{
dev->eco_supported = 1;
}
- ret = toshiba_kbd_illum_status_get(dev, &dummy);
- if (!ret) {
- dev->kbd_time = dummy >> HCI_MISC_SHIFT;
- dev->kbd_mode = dummy & 0x07;
- }
- dev->kbd_illum_supported = !ret;
+ dev->kbd_illum_supported = toshiba_kbd_illum_available(dev);
/*
* Only register the LED if KBD illumination is supported
* and the keyboard backlight operation mode is set to FN-Z