--- 4226e535273874fb06aea0344c4c8ce00a8b957c +++ c533b1c6556c9565fa50ca84e7942af6439ac794 @@ -34,6 +34,7 @@ #include #include #include +#include #define EEEPC_LAPTOP_VERSION "0.1" @@ -135,6 +136,8 @@ struct eeepc_hotk { acpi_handle handle; /* the handle of the hotk device */ u32 cm_supported; /* the control methods supported by this BIOS */ + bool cpufv_disabled; + bool hotplug_disabled; uint init_flag; /* Init flags */ u16 event_count[128]; /* count for each event */ struct input_dev *inputdev; @@ -251,6 +254,14 @@ MODULE_AUTHOR("Corentin Chary, Eric Coop MODULE_DESCRIPTION(EEEPC_HOTK_NAME); MODULE_LICENSE("GPL"); +static bool hotplug_disabled; + +module_param(hotplug_disabled, bool, 0644); +MODULE_PARM_DESC(hotplug_disabled, + "Disable hotplug for wireless device. " + "If your laptop need that, please report to " + "acpi4asus-user@lists.sourceforge.net."); + /* * ACPI Helpers */ @@ -467,6 +478,8 @@ static ssize_t store_cpufv(struct device struct eeepc_cpufv c; int rv, value; + if (ehotk->cpufv_disabled) + return -EPERM; if (get_cpufv(&c)) return -ENODEV; rv = parse_arg(buf, count, &value); @@ -478,6 +491,38 @@ static ssize_t store_cpufv(struct device return rv; } +static ssize_t show_cpufv_disabled(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%d\n", ehotk->cpufv_disabled); +} + +static ssize_t store_cpufv_disabled(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int rv, value; + + rv = parse_arg(buf, count, &value); + if (rv < 0) + return rv; + + switch (value) { + case 0: + if (ehotk->cpufv_disabled) + pr_warning("cpufv enabled (not officially supported " + "on this model)\n"); + ehotk->cpufv_disabled = false; + return rv; + case 1: + return -EPERM; + default: + return -EINVAL; + } +} + + static struct device_attribute dev_attr_cpufv = { .attr = { .name = "cpufv", @@ -493,12 +538,22 @@ static struct device_attribute dev_attr_ .show = show_available_cpufv }; +static struct device_attribute dev_attr_cpufv_disabled = { + .attr = { + .name = "cpufv_disabled", + .mode = 0644 }, + .show = show_cpufv_disabled, + .store = store_cpufv_disabled +}; + + static struct attribute *platform_attributes[] = { &dev_attr_camera.attr, &dev_attr_cardr.attr, &dev_attr_disp.attr, &dev_attr_cpufv.attr, &dev_attr_available_cpufv.attr, + &dev_attr_cpufv_disabled.attr, NULL }; @@ -564,6 +619,54 @@ static int eeepc_setkeycode(struct input return -EINVAL; } +static void eeepc_dmi_check(void) +{ + const char *model; + + model = dmi_get_system_info(DMI_PRODUCT_NAME); + if (!model) + return; + + /* + * Blacklist for setting cpufv (cpu speed). + * + * EeePC 4G ("701") implements CFVS, but it is not supported + * by the pre-installed OS, and the original option to change it + * in the BIOS setup screen was removed in later versions. + * + * Judging by the lack of "Super Hybrid Engine" on Asus product pages, + * this applies to all "701" models (4G/4G Surf/2G Surf). + * + * So Asus made a deliberate decision not to support it on this model. + * We have several reports that using it can cause the system to hang + * + * The hang has also been reported on a "702" (Model name "8G"?). + * + * We avoid dmi_check_system() / dmi_match(), because they use + * substring matching. We don't want to affect the "701SD" + * and "701SDX" models, because they do support S.H.E. + */ + if (strcmp(model, "701") == 0 || strcmp(model, "702") == 0) { + ehotk->cpufv_disabled = true; + pr_info("model %s does not officially support setting cpu " + "speed\n", model); + pr_info("cpufv disabled to avoid instability\n"); + } + + /* + * Blacklist for wlan hotplug + * + * Eeepc 1005HA doesn't work like others models and don't need the + * hotplug code. In fact, current hotplug code seems to unplug another + * device... + */ + if (strcmp(model, "1005HA") == 0 || strcmp(model, "1201N") == 0 || + strcmp(model, "1005PE") == 0) { + ehotk->hotplug_disabled = true; + pr_info("wlan hotplug disabled\n"); + } +} + static void cmsg_quirk(int cm, const char *name) { int dummy; @@ -649,6 +752,8 @@ static void eeepc_rfkill_hotplug(void) struct pci_dev *dev; struct pci_bus *bus; bool blocked = eeepc_wlan_rfkill_blocked(); + bool absent; + u32 l; if (ehotk->wlan_rfkill) rfkill_set_sw_state(ehotk->wlan_rfkill, blocked); @@ -662,6 +767,22 @@ static void eeepc_rfkill_hotplug(void) goto out_unlock; } + if (pci_bus_read_config_dword(bus, 0, PCI_VENDOR_ID, &l)) { + pr_err("Unable to read PCI config space?\n"); + goto out_unlock; + } + absent = (l == 0xffffffff); + + if (blocked != absent) { + pr_warning("BIOS says wireless lan is %s, " + "but the pci device is %s\n", + blocked ? "blocked" : "unblocked", + absent ? "absent" : "present"); + pr_warning("skipped wireless hotplug as probably " + "inappropriate for this model\n"); + goto out_unlock; + } + if (!blocked) { dev = pci_get_slot(bus, 0); if (dev) { @@ -1095,6 +1216,9 @@ static int eeepc_rfkill_init(struct devi if (result && result != -ENODEV) goto exit; + if (ehotk->hotplug_disabled) + return 0; + result = eeepc_setup_pci_hotplug(); /* * If we get -EBUSY then something else is handling the PCI hotplug - @@ -1208,6 +1332,10 @@ static int __devinit eeepc_hotk_add(stru device->driver_data = ehotk; ehotk->device = device; + ehotk->hotplug_disabled = hotplug_disabled; + + eeepc_dmi_check(); + result = eeepc_hotk_check(); if (result) goto fail_platform_driver;