Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9bff9dbd authored by David S. Miller's avatar David S. Miller
Browse files
parents e2a6b852 d10c4ec8
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -260,6 +260,9 @@ config ACPI_ASUS
config ACPI_TOSHIBA
	tristate "Toshiba Laptop Extras"
	depends on X86
	select INPUT_POLLDEV
	select NET
	select RFKILL
	select BACKLIGHT_CLASS_DEVICE
	---help---
	  This driver adds support for access to certain system settings
+253 −8
Original line number Diff line number Diff line
@@ -3,6 +3,7 @@
 *
 *
 *  Copyright (C) 2002-2004 John Belmonte
 *  Copyright (C) 2008 Philip Langdale
 *
 *  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
@@ -33,7 +34,7 @@
 *
 */

#define TOSHIBA_ACPI_VERSION	"0.18"
#define TOSHIBA_ACPI_VERSION	"0.19"
#define PROC_INTERFACE_VERSION	1

#include <linux/kernel.h>
@@ -42,6 +43,9 @@
#include <linux/types.h>
#include <linux/proc_fs.h>
#include <linux/backlight.h>
#include <linux/platform_device.h>
#include <linux/rfkill.h>
#include <linux/input-polldev.h>

#include <asm/uaccess.h>

@@ -90,6 +94,7 @@ MODULE_LICENSE("GPL");
#define HCI_VIDEO_OUT			0x001c
#define HCI_HOTKEY_EVENT		0x001e
#define HCI_LCD_BRIGHTNESS		0x002a
#define HCI_WIRELESS			0x0056

/* field definitions */
#define HCI_LCD_BRIGHTNESS_BITS		3
@@ -98,9 +103,14 @@ MODULE_LICENSE("GPL");
#define HCI_VIDEO_OUT_LCD		0x1
#define HCI_VIDEO_OUT_CRT		0x2
#define HCI_VIDEO_OUT_TV		0x4
#define HCI_WIRELESS_KILL_SWITCH	0x01
#define HCI_WIRELESS_BT_PRESENT		0x0f
#define HCI_WIRELESS_BT_ATTACH		0x40
#define HCI_WIRELESS_BT_POWER		0x80

static const struct acpi_device_id toshiba_device_ids[] = {
	{"TOS6200", 0},
	{"TOS6208", 0},
	{"TOS1900", 0},
	{"", 0},
};
@@ -193,7 +203,7 @@ static acpi_status hci_raw(const u32 in[HCI_WORDS], u32 out[HCI_WORDS])
	return status;
}

/* common hci tasks (get or set one value)
/* common hci tasks (get or set one or two value)
 *
 * In addition to the ACPI status, the HCI system returns a result which
 * may be useful (such as "not supported").
@@ -218,6 +228,152 @@ static acpi_status hci_read1(u32 reg, u32 * out1, u32 * result)
	return status;
}

static acpi_status hci_write2(u32 reg, u32 in1, u32 in2, u32 *result)
{
	u32 in[HCI_WORDS] = { HCI_SET, reg, in1, in2, 0, 0 };
	u32 out[HCI_WORDS];
	acpi_status status = hci_raw(in, out);
	*result = (status == AE_OK) ? out[0] : HCI_FAILURE;
	return status;
}

static acpi_status hci_read2(u32 reg, u32 *out1, u32 *out2, u32 *result)
{
	u32 in[HCI_WORDS] = { HCI_GET, reg, *out1, *out2, 0, 0 };
	u32 out[HCI_WORDS];
	acpi_status status = hci_raw(in, out);
	*out1 = out[2];
	*out2 = out[3];
	*result = (status == AE_OK) ? out[0] : HCI_FAILURE;
	return status;
}

struct toshiba_acpi_dev {
	struct platform_device *p_dev;
	struct rfkill *rfk_dev;
	struct input_polled_dev *poll_dev;

	const char *bt_name;
	const char *rfk_name;

	bool last_rfk_state;

	struct mutex mutex;
};

static struct toshiba_acpi_dev toshiba_acpi = {
	.bt_name = "Toshiba Bluetooth",
	.rfk_name = "Toshiba RFKill Switch",
	.last_rfk_state = false,
};

/* Bluetooth rfkill handlers */

static u32 hci_get_bt_present(bool *present)
{
	u32 hci_result;
	u32 value, value2;

	value = 0;
	value2 = 0;
	hci_read2(HCI_WIRELESS, &value, &value2, &hci_result);
	if (hci_result == HCI_SUCCESS)
		*present = (value & HCI_WIRELESS_BT_PRESENT) ? true : false;

	return hci_result;
}

static u32 hci_get_bt_on(bool *on)
{
	u32 hci_result;
	u32 value, value2;

	value = 0;
	value2 = 0x0001;
	hci_read2(HCI_WIRELESS, &value, &value2, &hci_result);
	if (hci_result == HCI_SUCCESS)
		*on = (value & HCI_WIRELESS_BT_POWER) &&
		      (value & HCI_WIRELESS_BT_ATTACH);

	return hci_result;
}

static u32 hci_get_radio_state(bool *radio_state)
{
	u32 hci_result;
	u32 value, value2;

	value = 0;
	value2 = 0x0001;
	hci_read2(HCI_WIRELESS, &value, &value2, &hci_result);

	*radio_state = value & HCI_WIRELESS_KILL_SWITCH;
	return hci_result;
}

static int bt_rfkill_toggle_radio(void *data, enum rfkill_state state)
{
	u32 result1, result2;
	u32 value;
	bool radio_state;
	struct toshiba_acpi_dev *dev = data;

	value = (state == RFKILL_STATE_UNBLOCKED);

	if (hci_get_radio_state(&radio_state) != HCI_SUCCESS)
		return -EFAULT;

	switch (state) {
	case RFKILL_STATE_UNBLOCKED:
		if (!radio_state)
			return -EPERM;
		break;
	case RFKILL_STATE_SOFT_BLOCKED:
		break;
	default:
		return -EINVAL;
	}

	mutex_lock(&dev->mutex);
	hci_write2(HCI_WIRELESS, value, HCI_WIRELESS_BT_POWER, &result1);
	hci_write2(HCI_WIRELESS, value, HCI_WIRELESS_BT_ATTACH, &result2);
	mutex_unlock(&dev->mutex);

	if (result1 != HCI_SUCCESS || result2 != HCI_SUCCESS)
		return -EFAULT;

	return 0;
}

static void bt_poll_rfkill(struct input_polled_dev *poll_dev)
{
	bool state_changed;
	bool new_rfk_state;
	bool value;
	u32 hci_result;
	struct toshiba_acpi_dev *dev = poll_dev->private;

	hci_result = hci_get_radio_state(&value);
	if (hci_result != HCI_SUCCESS)
		return; /* Can't do anything useful */

	new_rfk_state = value;

	mutex_lock(&dev->mutex);
	state_changed = new_rfk_state != dev->last_rfk_state;
	dev->last_rfk_state = new_rfk_state;
	mutex_unlock(&dev->mutex);

	if (unlikely(state_changed)) {
		rfkill_force_state(dev->rfk_dev,
				   new_rfk_state ?
				   RFKILL_STATE_SOFT_BLOCKED :
				   RFKILL_STATE_HARD_BLOCKED);
		input_report_switch(poll_dev->input, SW_RFKILL_ALL,
				    new_rfk_state);
	}
}

static struct proc_dir_entry *toshiba_proc_dir /*= 0*/ ;
static struct backlight_device *toshiba_backlight_device;
static int force_fan;
@@ -547,6 +703,14 @@ static struct backlight_ops toshiba_backlight_data = {

static void toshiba_acpi_exit(void)
{
	if (toshiba_acpi.poll_dev) {
		input_unregister_polled_device(toshiba_acpi.poll_dev);
		input_free_polled_device(toshiba_acpi.poll_dev);
	}

	if (toshiba_acpi.rfk_dev)
		rfkill_unregister(toshiba_acpi.rfk_dev);

	if (toshiba_backlight_device)
		backlight_device_unregister(toshiba_backlight_device);

@@ -555,6 +719,8 @@ static void toshiba_acpi_exit(void)
	if (toshiba_proc_dir)
		remove_proc_entry(PROC_TOSHIBA, acpi_root_dir);

	platform_device_unregister(toshiba_acpi.p_dev);

	return;
}

@@ -562,6 +728,10 @@ static int __init toshiba_acpi_init(void)
{
	acpi_status status = AE_OK;
	u32 hci_result;
	bool bt_present;
	bool bt_on;
	bool radio_on;
	int ret = 0;

	if (acpi_disabled)
		return -ENODEV;
@@ -578,6 +748,18 @@ static int __init toshiba_acpi_init(void)
	       TOSHIBA_ACPI_VERSION);
	printk(MY_INFO "    HCI method: %s\n", method_hci);

	mutex_init(&toshiba_acpi.mutex);

	toshiba_acpi.p_dev = platform_device_register_simple("toshiba_acpi",
							      -1, NULL, 0);
	if (IS_ERR(toshiba_acpi.p_dev)) {
		ret = PTR_ERR(toshiba_acpi.p_dev);
		printk(MY_ERR "unable to register platform device\n");
		toshiba_acpi.p_dev = NULL;
		toshiba_acpi_exit();
		return ret;
	}

	force_fan = 0;
	key_event_valid = 0;

@@ -586,19 +768,23 @@ static int __init toshiba_acpi_init(void)

	toshiba_proc_dir = proc_mkdir(PROC_TOSHIBA, acpi_root_dir);
	if (!toshiba_proc_dir) {
		status = AE_ERROR;
		toshiba_acpi_exit();
		return -ENODEV;
	} else {
		toshiba_proc_dir->owner = THIS_MODULE;
		status = add_device();
		if (ACPI_FAILURE(status))
			remove_proc_entry(PROC_TOSHIBA, acpi_root_dir);
		if (ACPI_FAILURE(status)) {
			toshiba_acpi_exit();
			return -ENODEV;
		}
	}

	toshiba_backlight_device = backlight_device_register("toshiba",NULL,
	toshiba_backlight_device = backlight_device_register("toshiba",
						&toshiba_acpi.p_dev->dev,
						NULL,
						&toshiba_backlight_data);
        if (IS_ERR(toshiba_backlight_device)) {
		int ret = PTR_ERR(toshiba_backlight_device);
		ret = PTR_ERR(toshiba_backlight_device);

		printk(KERN_ERR "Could not register toshiba backlight device\n");
		toshiba_backlight_device = NULL;
@@ -607,7 +793,66 @@ static int __init toshiba_acpi_init(void)
	}
        toshiba_backlight_device->props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1;

	return (ACPI_SUCCESS(status)) ? 0 : -ENODEV;
	/* Register rfkill switch for Bluetooth */
	if (hci_get_bt_present(&bt_present) == HCI_SUCCESS && bt_present) {
		toshiba_acpi.rfk_dev = rfkill_allocate(&toshiba_acpi.p_dev->dev,
							RFKILL_TYPE_BLUETOOTH);
		if (!toshiba_acpi.rfk_dev) {
			printk(MY_ERR "unable to allocate rfkill device\n");
			toshiba_acpi_exit();
			return -ENOMEM;
		}

		toshiba_acpi.rfk_dev->name = toshiba_acpi.bt_name;
		toshiba_acpi.rfk_dev->toggle_radio = bt_rfkill_toggle_radio;
		toshiba_acpi.rfk_dev->user_claim_unsupported = 1;
		toshiba_acpi.rfk_dev->data = &toshiba_acpi;

		if (hci_get_bt_on(&bt_on) == HCI_SUCCESS && bt_on) {
			toshiba_acpi.rfk_dev->state = RFKILL_STATE_UNBLOCKED;
		} else if (hci_get_radio_state(&radio_on) == HCI_SUCCESS &&
			   radio_on) {
			toshiba_acpi.rfk_dev->state = RFKILL_STATE_SOFT_BLOCKED;
		} else {
			toshiba_acpi.rfk_dev->state = RFKILL_STATE_HARD_BLOCKED;
		}

		ret = rfkill_register(toshiba_acpi.rfk_dev);
		if (ret) {
			printk(MY_ERR "unable to register rfkill device\n");
			toshiba_acpi_exit();
			return -ENOMEM;
		}
	}

	/* Register input device for kill switch */
	toshiba_acpi.poll_dev = input_allocate_polled_device();
	if (!toshiba_acpi.poll_dev) {
		printk(MY_ERR "unable to allocate kill-switch input device\n");
		toshiba_acpi_exit();
		return -ENOMEM;
	}
	toshiba_acpi.poll_dev->private = &toshiba_acpi;
	toshiba_acpi.poll_dev->poll = bt_poll_rfkill;
	toshiba_acpi.poll_dev->poll_interval = 1000; /* msecs */

	toshiba_acpi.poll_dev->input->name = toshiba_acpi.rfk_name;
	toshiba_acpi.poll_dev->input->id.bustype = BUS_HOST;
	toshiba_acpi.poll_dev->input->id.vendor = 0x0930; /* Toshiba USB ID */
	set_bit(EV_SW, toshiba_acpi.poll_dev->input->evbit);
	set_bit(SW_RFKILL_ALL, toshiba_acpi.poll_dev->input->swbit);
	input_report_switch(toshiba_acpi.poll_dev->input, SW_RFKILL_ALL, TRUE);

	ret = input_register_polled_device(toshiba_acpi.poll_dev);
	if (ret) {
		printk(MY_ERR "unable to register kill-switch input device\n");
		rfkill_free(toshiba_acpi.rfk_dev);
		toshiba_acpi.rfk_dev = NULL;
		toshiba_acpi_exit();
		return ret;
	}

	return 0;
}

module_init(toshiba_acpi_init);
+1 −0
Original line number Diff line number Diff line
@@ -1884,6 +1884,7 @@ static int __devinit adm8211_probe(struct pci_dev *pdev,
	dev->extra_tx_headroom = sizeof(struct adm8211_tx_hdr);
	/* dev->flags = IEEE80211_HW_RX_INCLUDES_FCS in promisc mode */
	dev->flags = IEEE80211_HW_SIGNAL_UNSPEC;
	dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);

	dev->channel_change_time = 1000;
	dev->max_signal = 100;    /* FIXME: find better value */
+10 −2
Original line number Diff line number Diff line
ath5k-y				+= base.o
ath5k-y				+= hw.o
ath5k-y				+= caps.o
ath5k-y				+= initvals.o
ath5k-y				+= eeprom.o
ath5k-y				+= gpio.o
ath5k-y				+= desc.o
ath5k-y				+= dma.o
ath5k-y				+= qcu.o
ath5k-y				+= pcu.o
ath5k-y				+= phy.o
ath5k-y				+= reset.o
ath5k-y				+= attach.o
ath5k-y				+= base.o
ath5k-$(CONFIG_ATH5K_DEBUG)	+= debug.o
obj-$(CONFIG_ATH5K)		+= ath5k.o
+315 −75

File changed.

Preview size limit exceeded, changes collapsed.

Loading