於 五,2012-11-30 於 18:04 +0200,Maxim Mikityanskiy 提到: > From: Lee, Chun-Yi <jlee@xxxxxxxx> > > This patch introduced a quirk_entry struct, then we merged all quirk > tables to msi_dmi_table. Then we can more easily to set different quirk > attributes for different machine. > > Signed-off-by: Lee, Chun-Yi <jlee@xxxxxxxx> > > Changed this patch so that it could be applied before MSI Wind U100 > support patch. Changed rfkill logic for ec_read_only quirk support. > Removed delays if ec_delay = false. > > Signed-off-by: Maxim Mikityanskiy <maxtram95@xxxxxxxxx> Acked-by: Lee, Chun-Yi <jlee@xxxxxxxx> Thanks for your patch Joey Lee > --- > drivers/platform/x86/msi-laptop.c | 196 ++++++++++++++++++++++++-------------- > 1 file changed, 127 insertions(+), 69 deletions(-) > > diff --git a/drivers/platform/x86/msi-laptop.c b/drivers/platform/x86/msi-laptop.c > index 7ba107a..0bf94b5 100644 > --- a/drivers/platform/x86/msi-laptop.c > +++ b/drivers/platform/x86/msi-laptop.c > @@ -108,23 +108,38 @@ static const struct key_entry msi_laptop_keymap[] = { > > static struct input_dev *msi_laptop_input_dev; > > -static bool old_ec_model; > static int wlan_s, bluetooth_s, threeg_s; > static int threeg_exists; > - > -/* Some MSI 3G netbook only have one fn key to control Wlan/Bluetooth/3G, > - * those netbook will load the SCM (windows app) to disable the original > - * Wlan/Bluetooth control by BIOS when user press fn key, then control > - * Wlan/Bluetooth/3G by SCM (software control by OS). Without SCM, user > - * cann't on/off 3G module on those 3G netbook. > - * On Linux, msi-laptop driver will do the same thing to disable the > - * original BIOS control, then might need use HAL or other userland > - * application to do the software control that simulate with SCM. > - * e.g. MSI N034 netbook > - */ > -static bool load_scm_model; > static struct rfkill *rfk_wlan, *rfk_bluetooth, *rfk_threeg; > > +/* MSI laptop quirks */ > +struct quirk_entry { > + bool old_ec_model; > + > + /* Some MSI 3G netbook only have one fn key to control > + * Wlan/Bluetooth/3G, those netbook will load the SCM (windows app) to > + * disable the original Wlan/Bluetooth control by BIOS when user press > + * fn key, then control Wlan/Bluetooth/3G by SCM (software control by > + * OS). Without SCM, user cann't on/off 3G module on those 3G netbook. > + * On Linux, msi-laptop driver will do the same thing to disable the > + * original BIOS control, then might need use HAL or other userland > + * application to do the software control that simulate with SCM. > + * e.g. MSI N034 netbook > + */ > + bool load_scm_model; > + > + /* Some MSI laptops need delay before reading from EC */ > + bool ec_delay; > + > + /* Some MSI Wind netbooks (e.g. MSI Wind U100) need loading SCM to get > + * some features working (e.g. ECO mode), but we cannot change > + * Wlan/Bluetooth state in software and we can only read its state. > + */ > + bool ec_read_only; > +}; > + > +static struct quirk_entry *quirks; > + > /* Hardware access */ > > static int set_lcd_level(int level) > @@ -195,6 +210,9 @@ static ssize_t set_device_state(const char *buf, size_t count, u8 mask) > if (sscanf(buf, "%i", &status) != 1 || (status < 0 || status > 1)) > return -EINVAL; > > + if (quirks->ec_read_only) > + return -EOPNOTSUPP; > + > /* read current device state */ > result = ec_read(MSI_STANDARD_EC_COMMAND_ADDRESS, &rdata); > if (result < 0) > @@ -293,7 +311,7 @@ static ssize_t show_wlan(struct device *dev, > > int ret, enabled = 0; > > - if (old_ec_model) { > + if (quirks->old_ec_model) { > ret = get_wireless_state(&enabled, NULL); > } else { > ret = get_wireless_state_ec_standard(); > @@ -317,7 +335,7 @@ static ssize_t show_bluetooth(struct device *dev, > > int ret, enabled = 0; > > - if (old_ec_model) { > + if (quirks->old_ec_model) { > ret = get_wireless_state(NULL, &enabled); > } else { > ret = get_wireless_state_ec_standard(); > @@ -342,7 +360,7 @@ static ssize_t show_threeg(struct device *dev, > int ret; > > /* old msi ec not support 3G */ > - if (old_ec_model) > + if (quirks->old_ec_model) > return -ENODEV; > > ret = get_wireless_state_ec_standard(); > @@ -448,9 +466,26 @@ static struct platform_device *msipf_device; > > /* Initialization */ > > -static int dmi_check_cb(const struct dmi_system_id *id) > +static struct quirk_entry quirk_old_ec_model = { > + .old_ec_model = true, > +}; > + > +static struct quirk_entry quirk_load_scm_model = { > + .load_scm_model = true, > + .ec_delay = true, > +}; > + > +static struct quirk_entry quirk_load_scm_ro_model = { > + .load_scm_model = true, > + .ec_read_only = true, > +}; > + > +static int dmi_check_cb(const struct dmi_system_id *dmi) > { > - pr_info("Identified laptop model '%s'\n", id->ident); > + pr_info("Identified laptop model '%s'\n", dmi->ident); > + > + quirks = dmi->driver_data; > + > return 1; > } > > @@ -464,6 +499,7 @@ static struct dmi_system_id __initdata msi_dmi_table[] = { > DMI_MATCH(DMI_CHASSIS_VENDOR, > "MICRO-STAR INT'L CO.,LTD") > }, > + .driver_data = &quirk_old_ec_model, > .callback = dmi_check_cb > }, > { > @@ -474,6 +510,7 @@ static struct dmi_system_id __initdata msi_dmi_table[] = { > DMI_MATCH(DMI_PRODUCT_VERSION, "0581"), > DMI_MATCH(DMI_BOARD_NAME, "MS-1058") > }, > + .driver_data = &quirk_old_ec_model, > .callback = dmi_check_cb > }, > { > @@ -484,6 +521,7 @@ static struct dmi_system_id __initdata msi_dmi_table[] = { > DMI_MATCH(DMI_BOARD_VENDOR, "MSI"), > DMI_MATCH(DMI_BOARD_NAME, "MS-1412") > }, > + .driver_data = &quirk_old_ec_model, > .callback = dmi_check_cb > }, > { > @@ -495,12 +533,9 @@ static struct dmi_system_id __initdata msi_dmi_table[] = { > DMI_MATCH(DMI_CHASSIS_VENDOR, > "MICRO-STAR INT'L CO.,LTD") > }, > + .driver_data = &quirk_old_ec_model, > .callback = dmi_check_cb > }, > - { } > -}; > - > -static struct dmi_system_id __initdata msi_load_scm_models_dmi_table[] = { > { > .ident = "MSI N034", > .matches = { > @@ -510,6 +545,7 @@ static struct dmi_system_id __initdata msi_load_scm_models_dmi_table[] = { > DMI_MATCH(DMI_CHASSIS_VENDOR, > "MICRO-STAR INTERNATIONAL CO., LTD") > }, > + .driver_data = &quirk_load_scm_model, > .callback = dmi_check_cb > }, > { > @@ -521,6 +557,7 @@ static struct dmi_system_id __initdata msi_load_scm_models_dmi_table[] = { > DMI_MATCH(DMI_CHASSIS_VENDOR, > "MICRO-STAR INTERNATIONAL CO., LTD") > }, > + .driver_data = &quirk_load_scm_model, > .callback = dmi_check_cb > }, > { > @@ -530,6 +567,7 @@ static struct dmi_system_id __initdata msi_load_scm_models_dmi_table[] = { > "MICRO-STAR INTERNATIONAL CO., LTD"), > DMI_MATCH(DMI_PRODUCT_NAME, "MS-N014"), > }, > + .driver_data = &quirk_load_scm_model, > .callback = dmi_check_cb > }, > { > @@ -539,6 +577,7 @@ static struct dmi_system_id __initdata msi_load_scm_models_dmi_table[] = { > "Micro-Star International"), > DMI_MATCH(DMI_PRODUCT_NAME, "CR620"), > }, > + .driver_data = &quirk_load_scm_model, > .callback = dmi_check_cb > }, > { > @@ -548,6 +587,7 @@ static struct dmi_system_id __initdata msi_load_scm_models_dmi_table[] = { > "Micro-Star International Co., Ltd."), > DMI_MATCH(DMI_PRODUCT_NAME, "U270 series"), > }, > + .driver_data = &quirk_load_scm_model, > .callback = dmi_check_cb > }, > { } > @@ -560,32 +600,26 @@ static int rfkill_bluetooth_set(void *data, bool blocked) > * blocked == false is on > * blocked == true is off > */ > - if (blocked) > - set_device_state("0", 0, MSI_STANDARD_EC_BLUETOOTH_MASK); > - else > - set_device_state("1", 0, MSI_STANDARD_EC_BLUETOOTH_MASK); > + int result = set_device_state(blocked ? "0" : "1", 0, > + MSI_STANDARD_EC_BLUETOOTH_MASK); > > - return 0; > + return min(result, 0); > } > > static int rfkill_wlan_set(void *data, bool blocked) > { > - if (blocked) > - set_device_state("0", 0, MSI_STANDARD_EC_WLAN_MASK); > - else > - set_device_state("1", 0, MSI_STANDARD_EC_WLAN_MASK); > + int result = set_device_state(blocked ? "0" : "1", 0, > + MSI_STANDARD_EC_WLAN_MASK); > > - return 0; > + return min(result, 0); > } > > static int rfkill_threeg_set(void *data, bool blocked) > { > - if (blocked) > - set_device_state("0", 0, MSI_STANDARD_EC_3G_MASK); > - else > - set_device_state("1", 0, MSI_STANDARD_EC_3G_MASK); > + int result = set_device_state(blocked ? "0" : "1", 0, > + MSI_STANDARD_EC_3G_MASK); > > - return 0; > + return min(result, 0); > } > > static const struct rfkill_ops rfkill_bluetooth_ops = { > @@ -618,18 +652,27 @@ static void rfkill_cleanup(void) > } > } > > +static bool msi_rfkill_set_state(struct rfkill *rfkill, bool blocked) > +{ > + if (quirks->ec_read_only) > + return rfkill_set_hw_state(rfkill, blocked); > + else > + return rfkill_set_sw_state(rfkill, blocked); > +} > + > static void msi_update_rfkill(struct work_struct *ignored) > { > get_wireless_state_ec_standard(); > > if (rfk_wlan) > - rfkill_set_sw_state(rfk_wlan, !wlan_s); > + msi_rfkill_set_state(rfk_wlan, !wlan_s); > if (rfk_bluetooth) > - rfkill_set_sw_state(rfk_bluetooth, !bluetooth_s); > + msi_rfkill_set_state(rfk_bluetooth, !bluetooth_s); > if (rfk_threeg) > - rfkill_set_sw_state(rfk_threeg, !threeg_s); > + msi_rfkill_set_state(rfk_threeg, !threeg_s); > } > -static DECLARE_DELAYED_WORK(msi_rfkill_work, msi_update_rfkill); > +static DECLARE_DELAYED_WORK(msi_rfkill_dwork, msi_update_rfkill); > +static DECLARE_WORK(msi_rfkill_work, msi_update_rfkill); > > static void msi_send_touchpad_key(struct work_struct *ignored) > { > @@ -644,7 +687,8 @@ static void msi_send_touchpad_key(struct work_struct *ignored) > (rdata & MSI_STANDARD_EC_TOUCHPAD_MASK) ? > KEY_TOUCHPAD_ON : KEY_TOUCHPAD_OFF, 1, true); > } > -static DECLARE_DELAYED_WORK(msi_touchpad_work, msi_send_touchpad_key); > +static DECLARE_DELAYED_WORK(msi_touchpad_dwork, msi_send_touchpad_key); > +static DECLARE_WORK(msi_touchpad_work, msi_send_touchpad_key); > > static bool msi_laptop_i8042_filter(unsigned char data, unsigned char str, > struct serio *port) > @@ -662,14 +706,20 @@ static bool msi_laptop_i8042_filter(unsigned char data, unsigned char str, > extended = false; > switch (data) { > case 0xE4: > - schedule_delayed_work(&msi_touchpad_work, > - round_jiffies_relative(0.5 * HZ)); > + if (quirks->ec_delay) { > + schedule_delayed_work(&msi_touchpad_dwork, > + round_jiffies_relative(0.5 * HZ)); > + } else > + schedule_work(&msi_touchpad_work); > break; > case 0x54: > case 0x62: > case 0x76: > - schedule_delayed_work(&msi_rfkill_work, > - round_jiffies_relative(0.5 * HZ)); > + if (quirks->ec_delay) { > + schedule_delayed_work(&msi_rfkill_dwork, > + round_jiffies_relative(0.5 * HZ)); > + } else > + schedule_work(&msi_rfkill_work); > break; > } > } > @@ -736,8 +786,11 @@ static int rfkill_init(struct platform_device *sdev) > } > > /* schedule to run rfkill state initial */ > - schedule_delayed_work(&msi_rfkill_init, > - round_jiffies_relative(1 * HZ)); > + if (quirks->ec_delay) { > + schedule_delayed_work(&msi_rfkill_init, > + round_jiffies_relative(1 * HZ)); > + } else > + schedule_work(&msi_rfkill_work); > > return 0; > > @@ -761,7 +814,7 @@ static int msi_laptop_resume(struct device *device) > u8 data; > int result; > > - if (!load_scm_model) > + if (!quirks->load_scm_model) > return 0; > > /* set load SCM to disable hardware control by fn key */ > @@ -819,13 +872,15 @@ static int __init load_scm_model_init(struct platform_device *sdev) > u8 data; > int result; > > - /* allow userland write sysfs file */ > - dev_attr_bluetooth.store = store_bluetooth; > - dev_attr_wlan.store = store_wlan; > - dev_attr_threeg.store = store_threeg; > - dev_attr_bluetooth.attr.mode |= S_IWUSR; > - dev_attr_wlan.attr.mode |= S_IWUSR; > - dev_attr_threeg.attr.mode |= S_IWUSR; > + if (!quirks->ec_read_only) { > + /* allow userland write sysfs file */ > + dev_attr_bluetooth.store = store_bluetooth; > + dev_attr_wlan.store = store_wlan; > + dev_attr_threeg.store = store_threeg; > + dev_attr_bluetooth.attr.mode |= S_IWUSR; > + dev_attr_wlan.attr.mode |= S_IWUSR; > + dev_attr_threeg.attr.mode |= S_IWUSR; > + } > > /* disable hardware control by fn key */ > result = ec_read(MSI_STANDARD_EC_SCM_LOAD_ADDRESS, &data); > @@ -874,15 +929,16 @@ static int __init msi_init(void) > if (acpi_disabled) > return -ENODEV; > > - if (force || dmi_check_system(msi_dmi_table)) > - old_ec_model = 1; > + dmi_check_system(msi_dmi_table); > + if (!quirks) > + /* quirks may be NULL if no match in DMI table */ > + quirks = &quirk_load_scm_model; > + if (force) > + quirks = &quirk_old_ec_model; > > - if (!old_ec_model) > + if (!quirks->old_ec_model) > get_threeg_exists(); > > - if (!old_ec_model && dmi_check_system(msi_load_scm_models_dmi_table)) > - load_scm_model = 1; > - > if (auto_brightness < 0 || auto_brightness > 2) > return -EINVAL; > > @@ -918,7 +974,7 @@ static int __init msi_init(void) > if (ret) > goto fail_platform_device1; > > - if (load_scm_model && (load_scm_model_init(msipf_device) < 0)) { > + if (quirks->load_scm_model && (load_scm_model_init(msipf_device) < 0)) { > ret = -EINVAL; > goto fail_platform_device1; > } > @@ -928,7 +984,7 @@ static int __init msi_init(void) > if (ret) > goto fail_platform_device2; > > - if (!old_ec_model) { > + if (!quirks->old_ec_model) { > if (threeg_exists) > ret = device_create_file(&msipf_device->dev, > &dev_attr_threeg); > @@ -949,9 +1005,10 @@ static int __init msi_init(void) > > fail_platform_device2: > > - if (load_scm_model) { > + if (quirks->load_scm_model) { > i8042_remove_filter(msi_laptop_i8042_filter); > - cancel_delayed_work_sync(&msi_rfkill_work); > + cancel_delayed_work_sync(&msi_rfkill_dwork); > + cancel_work_sync(&msi_rfkill_work); > rfkill_cleanup(); > } > platform_device_del(msipf_device); > @@ -973,15 +1030,16 @@ fail_backlight: > > static void __exit msi_cleanup(void) > { > - if (load_scm_model) { > + if (quirks->load_scm_model) { > i8042_remove_filter(msi_laptop_i8042_filter); > msi_laptop_input_destroy(); > - cancel_delayed_work_sync(&msi_rfkill_work); > + cancel_delayed_work_sync(&msi_rfkill_dwork); > + cancel_work_sync(&msi_rfkill_work); > rfkill_cleanup(); > } > > sysfs_remove_group(&msipf_device->dev.kobj, &msipf_attribute_group); > - if (!old_ec_model && threeg_exists) > + if (!quirks->old_ec_model && threeg_exists) > device_remove_file(&msipf_device->dev, &dev_attr_threeg); > platform_device_unregister(msipf_device); > platform_driver_unregister(&msipf_driver); -- To unsubscribe from this list: send the line "unsubscribe platform-driver-x86" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html