diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..dd7e7b2 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,21 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true + +[*.c] +indent_size = 8 +indent_style = tab + +[{Makefile,Makefile.*,*.mk}] +indent_size = 8 +indent_style = tab + +[*.md] +indent_size = 2 +indent_style = space diff --git a/Kbuild b/Kbuild new file mode 100644 index 0000000..d44f743 --- /dev/null +++ b/Kbuild @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +obj-y += src/ diff --git a/Makefile b/Makefile index e151d35..3908fa8 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,5 @@ -obj-m := system76.o +# SPDX-License-Identifier: GPL-2.0-or-later + KERNEL_DIR = /lib/modules/$(shell uname -r)/build all: diff --git a/README.md b/README.md index 2efa364..178760a 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ make # Remove any old instances sudo modprobe -r system76 # Insert the new module -sudo insmod system76.ko +sudo insmod src/system76.ko # View log messages dmesg | grep system76 ``` diff --git a/debian/changelog b/debian/changelog index 6bf67dc..48abee9 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +system76-dkms (1.0.19) focal; urgency=medium + + * Add serw14 + + -- Tim Crawford Thu, 05 Jun 2025 17:27:15 -0600 + system76-dkms (1.0.18) focal; urgency=medium * Add bonw16 diff --git a/debian/rules b/debian/rules index bba04bb..4f8927f 100755 --- a/debian/rules +++ b/debian/rules @@ -6,9 +6,9 @@ include /usr/share/dpkg/pkg-info.mk dh $@ --with dkms override_dh_install: - dh_install Makefile *.c usr/src/system76-$(DEB_VERSION_UPSTREAM)/ + dh_install Makefile Kbuild src/Kbuild src/*.c usr/src/system76-$(DEB_VERSION_UPSTREAM)/ override_dh_dkms: dh_dkms -V $(DEB_VERSION_UPSTREAM) -override_dh_auto_configure override_dh_auto_build override_dh_auto_test override_dh_auto_install override_dh_auto_clean: \ No newline at end of file +override_dh_auto_configure override_dh_auto_build override_dh_auto_test override_dh_auto_install override_dh_auto_clean: diff --git a/src/Kbuild b/src/Kbuild new file mode 100644 index 0000000..b426c19 --- /dev/null +++ b/src/Kbuild @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +obj-m += system76.o diff --git a/system76_ap-led.c b/src/ap-led.c similarity index 82% rename from system76_ap-led.c rename to src/ap-led.c index 80d9289..01b87c3 100644 --- a/system76_ap-led.c +++ b/src/ap-led.c @@ -21,18 +21,20 @@ static enum led_brightness ap_led_brightness = 1; static bool ap_led_invert = TRUE; -static enum led_brightness ap_led_get(struct led_classdev *led_cdev) { +static enum led_brightness ap_led_get(struct led_classdev *led_cdev) +{ return ap_led_brightness; } -static int ap_led_set(struct led_classdev *led_cdev, enum led_brightness value) { +static int ap_led_set(struct led_classdev *led_cdev, enum led_brightness value) +{ u8 byte; - + ec_read(0xD9, &byte); - + if (value > 0) { ap_led_brightness = 1; - + if (ap_led_invert) { byte &= ~0x40; } else { @@ -40,32 +42,34 @@ static int ap_led_set(struct led_classdev *led_cdev, enum led_brightness value) } } else { ap_led_brightness = 0; - + if (ap_led_invert) { byte |= 0x40; } else { byte &= ~0x40; } } - + ec_write(0xD9, byte); - + return 0; } static struct led_classdev ap_led = { - .name = "system76::airplane", - .brightness_get = ap_led_get, - .brightness_set_blocking = ap_led_set, - .max_brightness = 1, - .default_trigger = "rfkill-any" + .name = "system76::airplane", + .brightness_get = ap_led_get, + .brightness_set_blocking = ap_led_set, + .max_brightness = 1, + .default_trigger = "rfkill-any" }; -static ssize_t ap_led_invert_show(struct device *dev, struct device_attribute *attr, char *buf) { +static ssize_t ap_led_invert_show(struct device *dev, struct device_attribute *attr, char *buf) +{ return sprintf(buf, "%d\n", (int)ap_led_invert); } -static ssize_t ap_led_invert_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { +static ssize_t ap_led_invert_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ unsigned int val; int ret; enum led_brightness brightness; @@ -74,17 +78,17 @@ static ssize_t ap_led_invert_store(struct device *dev, struct device_attribute * if (ret) { return ret; } - + brightness = ap_led_get(&ap_led); - + if (val) { ap_led_invert = TRUE; } else { ap_led_invert = FALSE; } - + ap_led_set(&ap_led, brightness); - + return size; } @@ -97,30 +101,33 @@ static struct device_attribute ap_led_invert_dev_attr = { .store = ap_led_invert_store, }; -static void ap_led_resume(void) { +static void ap_led_resume(void) +{ ap_led_set(&ap_led, ap_led_brightness); } -static int __init ap_led_init(struct device *dev) { +static int __init ap_led_init(struct device *dev) +{ int err; err = led_classdev_register(dev, &ap_led); if (unlikely(err)) { return err; } - + if (device_create_file(ap_led.dev, &ap_led_invert_dev_attr) != 0) { - S76_ERROR("failed to create ap_led_invert\n"); + pr_err("failed to create ap_led_invert\n"); } - + ap_led_resume(); return 0; } -static void __exit ap_led_exit(void) { +static void __exit ap_led_exit(void) +{ device_remove_file(ap_led.dev, &ap_led_invert_dev_attr); - + if (!IS_ERR_OR_NULL(ap_led.dev)) { led_classdev_unregister(&ap_led); } diff --git a/system76_hwmon.c b/src/hwmon.c similarity index 77% rename from system76_hwmon.c rename to src/hwmon.c index 045035c..e69fda6 100644 --- a/system76_hwmon.c +++ b/src/hwmon.c @@ -22,14 +22,15 @@ #define EXPERIMENTAL #if S76_HAS_HWMON + struct s76_hwmon { struct device *dev; }; static struct s76_hwmon *s76_hwmon = NULL; -static int -s76_read_fan(int idx) { +static int s76_read_fan(int idx) +{ u8 value; int raw_rpm; ec_read(0xd0 + 0x2 * idx, &value); @@ -41,43 +42,40 @@ s76_read_fan(int idx) { return 2156220 / raw_rpm; } -static int -s76_read_pwm(int idx) { +static int s76_read_pwm(int idx) +{ u8 value; ec_read(0xce + idx, &value); return value; } -static int -s76_write_pwm(int idx, u8 duty) { +static int s76_write_pwm(int idx, u8 duty) +{ u8 values[] = {idx + 1, duty}; return ec_transaction(0x99, values, sizeof(values), NULL, 0); } -static int -s76_write_pwm_auto(int idx) { +static int s76_write_pwm_auto(int idx) +{ u8 values[] = {0xff, idx + 1}; return ec_transaction(0x99, values, sizeof(values), NULL, 0); } -static ssize_t -s76_hwmon_show_name(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t s76_hwmon_show_name(struct device *dev, + struct device_attribute *attr, char *buf) { return sprintf(buf, S76_DRIVER_NAME "\n"); } -static ssize_t -s76_hwmon_show_fan_input(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t s76_hwmon_show_fan_input(struct device *dev, + struct device_attribute *attr, char *buf) { int index = to_sensor_dev_attr(attr)->index; return sprintf(buf, "%i\n", s76_read_fan(index)); } -static ssize_t -s76_hwmon_show_fan_label(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t s76_hwmon_show_fan_label(struct device *dev, + struct device_attribute *attr, char *buf) { switch (to_sensor_dev_attr(attr)->index) { case 0: @@ -90,92 +88,99 @@ s76_hwmon_show_fan_label(struct device *dev, struct device_attribute *attr, static int pwm_enabled[] = {2, 2}; -static ssize_t -s76_hwmon_show_pwm(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t s76_hwmon_show_pwm(struct device *dev, + struct device_attribute *attr, char *buf) { int index = to_sensor_dev_attr(attr)->index; return sprintf(buf, "%i\n", s76_read_pwm(index)); } -static ssize_t -s76_hwmon_set_pwm(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t s76_hwmon_set_pwm(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) { u32 value; int err; int index = to_sensor_dev_attr(attr)->index; err = kstrtou32(buf, 10, &value); - if (err) return err; - if (value > 255) return -EINVAL; + if (err) + return err; + if (value > 255) + return -EINVAL; err = s76_write_pwm(index, value); - if (err) return err; + if (err) + return err; pwm_enabled[index] = 1; return count; } -static ssize_t -s76_hwmon_show_pwm_enable(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t s76_hwmon_show_pwm_enable(struct device *dev, + struct device_attribute *attr, char *buf) { int index = to_sensor_dev_attr(attr)->index; return sprintf(buf, "%i\n", pwm_enabled[index]); } -static ssize_t -s76_hwmon_set_pwm_enable(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t s76_hwmon_set_pwm_enable(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) { u32 value; int err; int index = to_sensor_dev_attr(attr)->index; err = kstrtou32(buf, 10, &value); - if (err) return err; + if (err) + return err; if (value == 0) { err = s76_write_pwm(index, 255); - if (err) return err; + if (err) + return err; pwm_enabled[index] = value; return count; } if (value == 1) { err = s76_write_pwm(index, 0); - if (err) return err; + if (err) + return err; pwm_enabled[index] = value; return count; } if (value == 2) { err = s76_write_pwm_auto(index); - if (err) return err; + if (err) + return err; pwm_enabled[index] = value; return count; } return -EINVAL; } -static ssize_t -s76_hwmon_show_temp1_input(struct device *dev, struct device_attribute *attr, char *buf) { +static ssize_t s76_hwmon_show_temp1_input(struct device *dev, + struct device_attribute *attr, char *buf) +{ u8 value; ec_read(0x07, &value); return sprintf(buf, "%i\n", value * 1000); } -static ssize_t -s76_hwmon_show_temp1_label(struct device *dev, struct device_attribute *attr, char *buf) { +static ssize_t s76_hwmon_show_temp1_label(struct device *dev, + struct device_attribute *attr, char *buf) +{ return sprintf(buf, "CPU temperature\n"); } #ifdef EXPERIMENTAL -static ssize_t -s76_hwmon_show_temp2_input(struct device *dev, struct device_attribute *attr, char *buf) { +static ssize_t s76_hwmon_show_temp2_input(struct device *dev, + struct device_attribute *attr, char *buf) +{ u8 value; ec_read(0xcd, &value); return sprintf(buf, "%i\n", value * 1000); } -static ssize_t -s76_hwmon_show_temp2_label(struct device *dev, struct device_attribute *attr, char *buf) { +static ssize_t s76_hwmon_show_temp2_label(struct device *dev, + struct device_attribute *attr, char *buf) +{ return sprintf(buf, "GPU temperature\n"); } #endif @@ -224,7 +229,8 @@ static const struct attribute_group hwmon_default_attrgroup = { }; static int s76_hwmon_reboot_callback(struct notifier_block *nb, - unsigned long action, void *data) { + unsigned long action, void *data) +{ s76_write_pwm_auto(0); #ifdef EXPERIMENTAL s76_write_pwm_auto(1); @@ -236,8 +242,8 @@ static struct notifier_block s76_hwmon_reboot_notifier = { .notifier_call = s76_hwmon_reboot_callback }; -static int -s76_hwmon_init(struct device *dev) { +static int s76_hwmon_init(struct device *dev) +{ int ret; s76_hwmon = kzalloc(sizeof(*s76_hwmon), GFP_KERNEL); @@ -257,18 +263,18 @@ s76_hwmon_init(struct device *dev) { register_reboot_notifier(&s76_hwmon_reboot_notifier); s76_write_pwm_auto(0); #ifdef EXPERIMENTAL - s76_write_pwm_auto(1); + s76_write_pwm_auto(1); #endif return 0; } -static int -s76_hwmon_fini(struct device *dev) { +static int s76_hwmon_fini(struct device *dev) +{ if (!s76_hwmon || !s76_hwmon->dev) return 0; s76_write_pwm_auto(0); #ifdef EXPERIMENTAL - s76_write_pwm_auto(1); + s76_write_pwm_auto(1); #endif unregister_reboot_notifier(&s76_hwmon_reboot_notifier); sysfs_remove_group(&s76_hwmon->dev->kobj, &hwmon_default_attrgroup); @@ -276,4 +282,5 @@ s76_hwmon_fini(struct device *dev) { kfree(s76_hwmon); return 0; } + #endif // S76_HAS_HWMON diff --git a/system76_input.c b/src/input.c similarity index 82% rename from system76_input.c rename to src/input.c index 9ad0d1d..b23264c 100644 --- a/system76_input.c +++ b/src/input.c @@ -56,8 +56,9 @@ MODULE_PARM_DESC(poll_freq, "Set polling frequency"); static struct task_struct *s76_input_polling_task; -static void s76_input_key(unsigned int code) { - S76_DEBUG("Send key %x\n", code); +static void s76_input_key(unsigned int code) +{ + pr_debug("Send key %x\n", code); mutex_lock(&s76_input_report_mutex); @@ -70,8 +71,9 @@ static void s76_input_key(unsigned int code) { mutex_unlock(&s76_input_report_mutex); } -static int s76_input_polling_thread(void *data) { - S76_DEBUG("Polling thread started (PID: %i), polling at %i Hz\n", +static int s76_input_polling_thread(void *data) +{ + pr_debug("Polling thread started (PID: %i), polling at %i Hz\n", current->pid, param_poll_freq); while (!kthread_should_stop()) { @@ -81,7 +83,7 @@ static int s76_input_polling_thread(void *data) { if (byte & 0x40) { ec_write(0xDB, byte & ~0x40); - S76_DEBUG("Airplane-Mode Hotkey pressed (EC)\n"); + pr_debug("Airplane-Mode Hotkey pressed (EC)\n"); s76_input_key(AIRPLANE_KEY); } @@ -89,24 +91,27 @@ static int s76_input_polling_thread(void *data) { msleep_interruptible(1000 / param_poll_freq); } - S76_DEBUG("Polling thread exiting\n"); + pr_debug("Polling thread exiting\n"); return 0; } -static void s76_input_airplane_wmi(void) { - S76_DEBUG("Airplane-Mode Hotkey pressed (WMI)\n"); +static void s76_input_airplane_wmi(void) +{ + pr_debug("Airplane-Mode Hotkey pressed (WMI)\n"); s76_input_key(AIRPLANE_KEY); } -static void s76_input_screen_wmi(void) { - S76_DEBUG("Screen Hotkey pressed (WMI)\n"); +static void s76_input_screen_wmi(void) +{ + pr_debug("Screen Hotkey pressed (WMI)\n"); s76_input_key(SCREEN_KEY); } -static int s76_input_open(struct input_dev *dev) { +static int s76_input_open(struct input_dev *dev) +{ int res = 0; // Run polling thread if AP key driver is used and WMI is not supported @@ -118,7 +123,7 @@ static int s76_input_open(struct input_dev *dev) { if (unlikely(IS_ERR(s76_input_polling_task))) { res = PTR_ERR(s76_input_polling_task); s76_input_polling_task = NULL; - S76_ERROR("Could not create polling thread: %d\n", res); + pr_err("Could not create polling thread: %d\n", res); return res; } } @@ -126,7 +131,8 @@ static int s76_input_open(struct input_dev *dev) { return res; } -static void s76_input_close(struct input_dev *dev) { +static void s76_input_close(struct input_dev *dev) +{ if (unlikely(IS_ERR_OR_NULL(s76_input_polling_task))) { return; } @@ -135,13 +141,14 @@ static void s76_input_close(struct input_dev *dev) { s76_input_polling_task = NULL; } -static int __init s76_input_init(struct device *dev) { +static int __init s76_input_init(struct device *dev) +{ int err; u8 byte; s76_input_device = input_allocate_device(); if (unlikely(!s76_input_device)) { - S76_ERROR("Error allocating input device\n"); + pr_err("Error allocating input device\n"); return -ENOMEM; } @@ -164,7 +171,7 @@ static int __init s76_input_init(struct device *dev) { err = input_register_device(s76_input_device); if (unlikely(err)) { - S76_ERROR("Error registering input device\n"); + pr_err("Error registering input device\n"); goto err_free_input_device; } @@ -176,7 +183,8 @@ err_free_input_device: return err; } -static void __exit s76_input_exit(void) { +static void __exit s76_input_exit(void) +{ if (unlikely(!s76_input_device)) { return; } diff --git a/system76_kb-led.c b/src/kb-led.c similarity index 67% rename from system76_kb-led.c rename to src/kb-led.c index 28c65d0..684ef5b 100644 --- a/system76_kb-led.c +++ b/src/kb-led.c @@ -25,10 +25,10 @@ union kb_led_color { }; enum kb_led_region { - KB_LED_REGION_LEFT, - KB_LED_REGION_CENTER, - KB_LED_REGION_RIGHT, - KB_LED_REGION_EXTRA, + KB_LED_REGION_LEFT, + KB_LED_REGION_CENTER, + KB_LED_REGION_RIGHT, + KB_LED_REGION_EXTRA, }; static enum led_brightness kb_led_brightness = 0; @@ -56,12 +56,14 @@ static union kb_led_color kb_led_colors[] = { { .rgb = 0xFFFF00 } }; -static enum led_brightness kb_led_get(struct led_classdev *led_cdev) { +static enum led_brightness kb_led_get(struct led_classdev *led_cdev) +{ return kb_led_brightness; } -static int kb_led_set(struct led_classdev *led_cdev, enum led_brightness value) { - S76_DEBUG("kb_led_set %d\n", (int)value); +static int kb_led_set(struct led_classdev *led_cdev, enum led_brightness value) +{ + pr_debug("kb_led_set %d\n", (int)value); if (!s76_wmbb(SET_KB_LED, 0xF4000000 | value, NULL)) { kb_led_brightness = value; @@ -70,10 +72,11 @@ static int kb_led_set(struct led_classdev *led_cdev, enum led_brightness value) return 0; } -static void kb_led_color_set(enum kb_led_region region, union kb_led_color color) { +static void kb_led_color_set_wmi(enum kb_led_region region, union kb_led_color color) +{ u32 cmd; - S76_DEBUG("kb_led_color_set %d %06X\n", (int)region, (int)color.rgb); + pr_debug("%s %d %06X\n", __func__, (int)region, (int)color.rgb); switch (region) { case KB_LED_REGION_LEFT: @@ -101,6 +104,71 @@ static void kb_led_color_set(enum kb_led_region region, union kb_led_color color } } +// HACK: Directly call ECMD to fix serw14 +static void kb_led_color_set(enum kb_led_region region, union kb_led_color color) +{ + struct acpi_object_list input; + union acpi_object obj; + acpi_handle handle; + acpi_status status; + u8 *buf; + + buf = (u8 *)kzalloc(8, GFP_KERNEL); + + pr_debug("%s %d %06X\n", __func__, (int)region, (int)color.rgb); + + buf[0] = 5; + buf[2] = 0xCA; + buf[4] = color.b; + buf[5] = color.r; + buf[6] = color.g; + + switch (region) { + case KB_LED_REGION_LEFT: + buf[3] = 0x03; + break; + case KB_LED_REGION_CENTER: + buf[3] = 0x04; + break; + case KB_LED_REGION_RIGHT: + buf[3] = 0x05; + break; + case KB_LED_REGION_EXTRA: + buf[3] = 0x0B; + break; + } + + obj.type = ACPI_TYPE_BUFFER; + obj.buffer.length = 8; + obj.buffer.pointer = buf; + + input.count = 1; + input.pointer = &obj; + + status = acpi_get_handle(NULL, (acpi_string)"\\_SB.PC00.LPCB.EC", &handle); + if (ACPI_FAILURE(status)) { + pr_err("%s failed to get handle: %x\n", __func__, status); + return; + } + + status = acpi_evaluate_object(handle, "ECMD", &input, NULL); + if (ACPI_FAILURE(status)) { + pr_err("%s failed to call EC_CMD: %x\n", __func__, status); + return; + } + + // Update lightbar to match keyboard color + buf[3] = 0x07; + status = acpi_evaluate_object(handle, "ECMD", &input, NULL); + if (ACPI_FAILURE(status)) { + pr_err("%s failed to call EC_CMD: %x\n", __func__, status); + return; + } + + kfree(buf); + kb_led_regions[region] = color; +} + static struct led_classdev kb_led = { .name = "system76::kbd_backlight", .flags = LED_BRIGHT_HW_CHANGED, @@ -109,11 +177,13 @@ static struct led_classdev kb_led = { .max_brightness = 255, }; -static ssize_t kb_led_color_show(enum kb_led_region region, char *buf) { +static ssize_t kb_led_color_show(enum kb_led_region region, char *buf) +{ return sprintf(buf, "%06X\n", (int)kb_led_regions[region].rgb); } -static ssize_t kb_led_color_store(enum kb_led_region region, const char *buf, size_t size) { +static ssize_t kb_led_color_store(enum kb_led_region region, const char *buf, size_t size) +{ unsigned int val; int ret; union kb_led_color color; @@ -124,16 +194,21 @@ static ssize_t kb_led_color_store(enum kb_led_region region, const char *buf, si } color.rgb = (u32)val; - kb_led_color_set(region, color); + if (driver_flags & DRIVER_KB_LED_WMI) + kb_led_color_set_wmi(region, color); + else + kb_led_color_set(region, color); return size; } -static ssize_t kb_led_color_left_show(struct device *dev, struct device_attribute *attr, char *buf) { +static ssize_t kb_led_color_left_show(struct device *dev, struct device_attribute *attr, char *buf) +{ return kb_led_color_show(KB_LED_REGION_LEFT, buf); } -static ssize_t kb_led_color_left_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { +static ssize_t kb_led_color_left_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ return kb_led_color_store(KB_LED_REGION_LEFT, buf, size); } @@ -146,11 +221,13 @@ static struct device_attribute kb_led_color_left_dev_attr = { .store = kb_led_color_left_store, }; -static ssize_t kb_led_color_center_show(struct device *dev, struct device_attribute *attr, char *buf) { +static ssize_t kb_led_color_center_show(struct device *dev, struct device_attribute *attr, char *buf) +{ return kb_led_color_show(KB_LED_REGION_CENTER, buf); } -static ssize_t kb_led_color_center_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { +static ssize_t kb_led_color_center_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ return kb_led_color_store(KB_LED_REGION_CENTER, buf, size); } @@ -163,11 +240,13 @@ static struct device_attribute kb_led_color_center_dev_attr = { .store = kb_led_color_center_store, }; -static ssize_t kb_led_color_right_show(struct device *dev, struct device_attribute *attr, char *buf) { +static ssize_t kb_led_color_right_show(struct device *dev, struct device_attribute *attr, char *buf) +{ return kb_led_color_show(KB_LED_REGION_RIGHT, buf); } -static ssize_t kb_led_color_right_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { +static ssize_t kb_led_color_right_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ return kb_led_color_store(KB_LED_REGION_RIGHT, buf, size); } @@ -180,11 +259,13 @@ static struct device_attribute kb_led_color_right_dev_attr = { .store = kb_led_color_right_store, }; -static ssize_t kb_led_color_extra_show(struct device *dev, struct device_attribute *attr, char *buf) { +static ssize_t kb_led_color_extra_show(struct device *dev, struct device_attribute *attr, char *buf) +{ return kb_led_color_show(KB_LED_REGION_EXTRA, buf); } -static ssize_t kb_led_color_extra_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { +static ssize_t kb_led_color_extra_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ return kb_led_color_store(KB_LED_REGION_EXTRA, buf, size); } @@ -197,36 +278,43 @@ static struct device_attribute kb_led_color_extra_dev_attr = { .store = kb_led_color_extra_store, }; -static void kb_led_enable(void) { - S76_DEBUG("kb_led_enable\n"); +static void kb_led_enable(void) +{ + pr_debug("kb_led_enable\n"); s76_wmbb(SET_KB_LED, 0xE007F001, NULL); } -static void kb_led_disable(void) { - S76_DEBUG("kb_led_disable\n"); +static void kb_led_disable(void) +{ + pr_debug("kb_led_disable\n"); s76_wmbb(SET_KB_LED, 0xE0003001, NULL); } -static void kb_led_suspend(void) { - S76_DEBUG("kb_led_suspend\n"); +static void kb_led_suspend(void) +{ + pr_debug("kb_led_suspend\n"); // Disable keyboard backlight kb_led_disable(); } -static void kb_led_resume(void) { +static void kb_led_resume(void) +{ enum kb_led_region region; - S76_DEBUG("kb_led_resume\n"); + pr_debug("kb_led_resume\n"); // Disable keyboard backlight kb_led_disable(); // Reset current color for (region = 0; region < sizeof(kb_led_regions)/sizeof(union kb_led_color); region++) { - kb_led_color_set(region, kb_led_regions[region]); + if (driver_flags & DRIVER_KB_LED_WMI) + kb_led_color_set_wmi(region, kb_led_regions[region]); + else + kb_led_color_set(region, kb_led_regions[region]); } // Reset current brightness @@ -236,7 +324,8 @@ static void kb_led_resume(void) { kb_led_enable(); } -static int __init kb_led_init(struct device *dev) { +static int __init kb_led_init(struct device *dev) +{ int err; err = led_classdev_register(dev, &kb_led); @@ -245,19 +334,19 @@ static int __init kb_led_init(struct device *dev) { } if (device_create_file(kb_led.dev, &kb_led_color_left_dev_attr) != 0) { - S76_ERROR("failed to create kb_led_color_left\n"); + pr_err("failed to create kb_led_color_left\n"); } if (device_create_file(kb_led.dev, &kb_led_color_center_dev_attr) != 0) { - S76_ERROR("failed to create kb_led_color_center\n"); + pr_err("failed to create kb_led_color_center\n"); } if (device_create_file(kb_led.dev, &kb_led_color_right_dev_attr) != 0) { - S76_ERROR("failed to create kb_led_color_right\n"); + pr_err("failed to create kb_led_color_right\n"); } if (device_create_file(kb_led.dev, &kb_led_color_extra_dev_attr) != 0) { - S76_ERROR("failed to create kb_led_color_extra\n"); + pr_err("failed to create kb_led_color_extra\n"); } kb_led_resume(); @@ -265,7 +354,8 @@ static int __init kb_led_init(struct device *dev) { return 0; } -static void __exit kb_led_exit(void) { +static void __exit kb_led_exit(void) +{ device_remove_file(kb_led.dev, &kb_led_color_extra_dev_attr); device_remove_file(kb_led.dev, &kb_led_color_right_dev_attr); device_remove_file(kb_led.dev, &kb_led_color_center_dev_attr); @@ -276,14 +366,16 @@ static void __exit kb_led_exit(void) { } } -static void kb_wmi_brightness(enum led_brightness value) { - S76_DEBUG("kb_wmi_brightness %d\n", (int)value); +static void kb_wmi_brightness(enum led_brightness value) +{ + pr_debug("kb_wmi_brightness %d\n", (int)value); kb_led_set(&kb_led, value); led_classdev_notify_brightness_hw_changed(&kb_led, value); } -static void kb_wmi_toggle(void) { +static void kb_wmi_toggle(void) +{ if (kb_led_brightness > 0) { kb_led_toggle_brightness = kb_led_brightness; kb_wmi_brightness(LED_OFF); @@ -292,7 +384,8 @@ static void kb_wmi_toggle(void) { } } -static void kb_wmi_dec(void) { +static void kb_wmi_dec(void) +{ int i; if (kb_led_brightness > 0) { @@ -307,7 +400,8 @@ static void kb_wmi_dec(void) { } } -static void kb_wmi_inc(void) { +static void kb_wmi_inc(void) +{ int i; if (kb_led_brightness > 0) { @@ -322,7 +416,8 @@ static void kb_wmi_inc(void) { } } -static void kb_wmi_color(void) { +static void kb_wmi_color(void) +{ enum kb_led_region region; kb_led_colors_i += 1; @@ -331,7 +426,10 @@ static void kb_wmi_color(void) { } for (region = 0; region < sizeof(kb_led_regions)/sizeof(union kb_led_color); region++) { - kb_led_color_set(region, kb_led_colors[kb_led_colors_i]); + if (driver_flags & DRIVER_KB_LED_WMI) + kb_led_color_set_wmi(region, kb_led_colors[kb_led_colors_i]); + else + kb_led_color_set(region, kb_led_colors[kb_led_colors_i]); } led_classdev_notify_brightness_hw_changed(&kb_led, kb_led_brightness); diff --git a/src/nv_hda.c b/src/nv_hda.c new file mode 100644 index 0000000..6c818df --- /dev/null +++ b/src/nv_hda.c @@ -0,0 +1,182 @@ +/* Based on bbswitch, + * Copyright (C) 2011-2013 Bumblebee Project + * Author: Peter Wu + * + * 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 + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +enum { + CARD_UNCHANGED = -1, + CARD_OFF = 0, + CARD_ON = 1, +}; + +static struct pci_dev *dis_dev; +static struct pci_dev *sub_dev = NULL; + +// Returns 1 if the card is disabled, 0 if enabled +static int is_card_disabled(void) +{ + // check for: 1.bit is set 2.sub-function is available. + u32 cfg_word; + struct pci_dev *tmp_dev = NULL; + + sub_dev = NULL; + + // read config word at 0x488 + pci_read_config_dword(dis_dev, 0x488, &cfg_word); + if ((cfg_word & 0x2000000)==0x2000000) { + // check for subdevice. read first config dword of sub function 1 + while ((tmp_dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, tmp_dev)) != NULL) { + int pci_class = tmp_dev->class >> 8; + + if (pci_class != 0x403) + continue; + + if (tmp_dev->vendor == PCI_VENDOR_ID_NVIDIA) { + sub_dev = tmp_dev; + pr_info("Found NVIDIA audio device %s\n", dev_name(&tmp_dev->dev)); + } + } + + if (sub_dev == NULL) { + pr_info("No NVIDIA audio device found, unsetting config bit.\n"); + cfg_word|=0x2000000; + pci_write_config_dword(dis_dev, 0x488, cfg_word); + return 1; + } + + return 0; + } else { + return 1; + } +} + +static void nv_hda_off(void) +{ + u32 cfg_word; + if (is_card_disabled()) { + return; + } + + // remove device + pci_dev_put(sub_dev); + pci_stop_and_remove_bus_device(sub_dev); + + pr_info("NVIDIA audio: disabling\n"); + + // setting bit to turn off + pci_read_config_dword(dis_dev, 0x488, &cfg_word); + cfg_word&=0xfdffffff; + pci_write_config_dword(dis_dev, 0x488, cfg_word); +} + +static void nv_hda_on(void) +{ + u32 cfg_word; + u8 hdr_type; + + if (!is_card_disabled()) { + return; + } + + pr_info("NVIDIA audio: enabling\n"); + + // read,set bit, write config word at 0x488 + pci_read_config_dword(dis_dev, 0x488, &cfg_word); + cfg_word|=0x2000000; + pci_write_config_dword(dis_dev, 0x488, cfg_word); + + //pci_scan_single_device + pci_read_config_byte(dis_dev, PCI_HEADER_TYPE, &hdr_type); + + if (!(hdr_type & 0x80)) { + pr_err("NVIDIA not multifunction, no audio\n"); + return; + } + + sub_dev = pci_scan_single_device(dis_dev->bus, 1); + if (!sub_dev) { + pr_err("No NVIDIA audio device found\n"); + return; + } + + pr_info("NVIDIA audio found, adding\n"); + pci_assign_unassigned_bus_resources(dis_dev->bus); + pci_bus_add_devices(dis_dev->bus); + pci_dev_get(sub_dev); +} + +/* power bus so we can read PCI configuration space */ +static void dis_dev_get(void) +{ + if (dis_dev->bus && dis_dev->bus->self) { + pm_runtime_get_sync(&dis_dev->bus->self->dev); + } +} + +static void dis_dev_put(void) +{ + if (dis_dev->bus && dis_dev->bus->self) { + pm_runtime_put_sync(&dis_dev->bus->self->dev); + } +} + + +static int __init nv_hda_init(struct device *dev) +{ + struct pci_dev *pdev = NULL; + + while ((pdev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) { + int pci_class = pdev->class >> 8; + + if (pci_class != PCI_CLASS_DISPLAY_VGA && pci_class != PCI_CLASS_DISPLAY_3D) { + continue; + } + + if (pdev->vendor == PCI_VENDOR_ID_NVIDIA) { + dis_dev = pdev; + pr_info("NVIDIA device %s\n", dev_name(&pdev->dev)); + } + } + + if (dis_dev == NULL) { + pr_err("No NVIDIA device found\n"); + return -ENODEV; + } + + dis_dev_get(); + + nv_hda_on(); + + pr_info("NVIDIA Audio %s is %s\n", dev_name(&dis_dev->dev), is_card_disabled() ? "off" : "on"); + + dis_dev_put(); + + return 0; +} + +static void __exit nv_hda_exit(void) +{ + if (dis_dev == NULL) + return; + + dis_dev_get(); + + nv_hda_off(); + + pr_info("NVIDIA Audio %s is %s\n", dev_name(&dis_dev->dev), is_card_disabled() ? "off" : "on"); + + dis_dev_put(); +} diff --git a/system76.c b/src/system76.c similarity index 73% rename from system76.c rename to src/system76.c index 15c7526..ed10262 100644 --- a/system76.c +++ b/src/system76.c @@ -43,13 +43,6 @@ #include #include -#define __S76_PR(lvl, fmt, ...) do { pr_##lvl(fmt, ##__VA_ARGS__); } \ - while (0) -#define S76_INFO(fmt, ...) __S76_PR(info, fmt, ##__VA_ARGS__) -#define S76_ERROR(fmt, ...) __S76_PR(err, fmt, ##__VA_ARGS__) -#define S76_DEBUG(fmt, ...) __S76_PR(debug, "[%s:%u] " fmt, \ - __func__, __LINE__, ##__VA_ARGS__) - #define S76_EVENT_GUID "ABBC0F6B-8EA1-11D1-00A0-C90629100000" #define S76_WMBB_GUID "ABBC0F6D-8EA1-11D1-00A0-C90629100000" @@ -58,12 +51,13 @@ /* method IDs for S76_GET */ #define GET_EVENT 0x01 /* 1 */ -#define DRIVER_AP_KEY (1 << 0) -#define DRIVER_AP_LED (1 << 1) -#define DRIVER_HWMON (1 << 2) -#define DRIVER_KB_LED (1 << 3) -#define DRIVER_OLED (1 << 4) -#define DRIVER_AP_WMI (1 << 5) +#define DRIVER_AP_KEY (1 << 0) +#define DRIVER_AP_LED (1 << 1) +#define DRIVER_HWMON (1 << 2) +#define DRIVER_KB_LED_WMI (1 << 3) +#define DRIVER_OLED (1 << 4) +#define DRIVER_AP_WMI (1 << 5) +#define DRIVER_KB_LED (1 << 6) #define DRIVER_INPUT (DRIVER_AP_KEY | DRIVER_OLED) @@ -71,14 +65,15 @@ static uint64_t driver_flags = 0; struct platform_device *s76_platform_device; -static int s76_wmbb(u32 method_id, u32 arg, u32 *retval) { +static int s76_wmbb(u32 method_id, u32 arg, u32 *retval) +{ struct acpi_buffer in = { (acpi_size) sizeof(arg), &arg }; struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL }; union acpi_object *obj; acpi_status status; u32 tmp; - S76_DEBUG("%0#4x IN : %0#6x\n", method_id, arg); + pr_debug("%0#4x IN : %0#6x\n", method_id, arg); status = wmi_evaluate_method(S76_WMBB_GUID, 0, method_id, &in, &out); @@ -93,7 +88,7 @@ static int s76_wmbb(u32 method_id, u32 arg, u32 *retval) { tmp = 0; } - S76_DEBUG("%0#4x OUT: %0#6x (IN: %0#6x)\n", method_id, tmp, arg); + pr_debug("%0#4x OUT: %0#6x (IN: %0#6x)\n", method_id, tmp, arg); if (likely(retval)) { *retval = tmp; @@ -104,48 +99,49 @@ static int s76_wmbb(u32 method_id, u32 arg, u32 *retval) { return 0; } -#include "system76_ap-led.c" -#include "system76_input.c" -#include "system76_kb-led.c" -#include "system76_hwmon.c" -#include "system76_nv_hda.c" +#include "ap-led.c" +#include "input.c" +#include "kb-led.c" +#include "hwmon.c" +#include "nv_hda.c" #if LINUX_VERSION_CODE >= KERNEL_VERSION(6,12,0) -static void s76_wmi_notify(union acpi_object *obj, void *context) { +static void s76_wmi_notify(union acpi_object *obj, void *context) #else -static void s76_wmi_notify(u32 value, void *context) { +static void s76_wmi_notify(u32 value, void *context) #endif +{ u32 event; #if LINUX_VERSION_CODE >= KERNEL_VERSION(6,12,0) if (obj->type != ACPI_TYPE_INTEGER) { - S76_DEBUG("Unexpected WMI event (%0#6x)\n", obj); + pr_debug("Unexpected WMI event (%0#6x)\n", obj); return; } #else if (value != 0xD0) { - S76_DEBUG("Unexpected WMI event (%0#6x)\n", value); + pr_debug("Unexpected WMI event (%0#6x)\n", value); return; } #endif s76_wmbb(GET_EVENT, 0, &event); - S76_DEBUG("WMI event code (%x)\n", event); + pr_debug("WMI event code (%x)\n", event); switch (event) { case 0x81: - if (driver_flags & DRIVER_KB_LED) { + if (driver_flags & (DRIVER_KB_LED_WMI | DRIVER_KB_LED)) { kb_wmi_dec(); } break; case 0x82: - if (driver_flags & DRIVER_KB_LED) { + if (driver_flags & (DRIVER_KB_LED_WMI | DRIVER_KB_LED)) { kb_wmi_inc(); } break; case 0x83: - if (driver_flags & DRIVER_KB_LED) { + if (driver_flags & (DRIVER_KB_LED_WMI | DRIVER_KB_LED)) { kb_wmi_color(); } break; @@ -156,7 +152,7 @@ static void s76_wmi_notify(u32 value, void *context) { //TODO: Fn+ESC break; case 0x9F: - if (driver_flags & DRIVER_KB_LED) { + if (driver_flags & (DRIVER_KB_LED_WMI | DRIVER_KB_LED)) { kb_wmi_toggle(); } break; @@ -178,32 +174,33 @@ static void s76_wmi_notify(u32 value, void *context) { // Touchpad WMI (enable) break; default: - S76_DEBUG("Unknown WMI event code (%x)\n", event); + pr_debug("Unknown WMI event code (%x)\n", event); break; } } -static int __init s76_probe(struct platform_device *dev) { +static int __init s76_probe(struct platform_device *dev) +{ int err; if (driver_flags & DRIVER_AP_LED) { err = ap_led_init(&dev->dev); if (unlikely(err)) { - S76_ERROR("Could not register LED device\n"); + pr_err("Could not register LED device\n"); } } - if (driver_flags & DRIVER_KB_LED) { + if (driver_flags & (DRIVER_KB_LED_WMI | DRIVER_KB_LED)) { err = kb_led_init(&dev->dev); if (unlikely(err)) { - S76_ERROR("Could not register LED device\n"); + pr_err("Could not register LED device\n"); } } if (driver_flags & DRIVER_INPUT) { err = s76_input_init(&dev->dev); if (unlikely(err)) { - S76_ERROR("Could not register input device\n"); + pr_err("Could not register input device\n"); } } @@ -215,12 +212,12 @@ static int __init s76_probe(struct platform_device *dev) { err = nv_hda_init(&dev->dev); if (unlikely(err)) { - S76_ERROR("Could not register NVIDIA audio device\n"); + pr_err("Could not register NVIDIA audio device\n"); } err = wmi_install_notify_handler(S76_EVENT_GUID, s76_wmi_notify, NULL); if (unlikely(ACPI_FAILURE(err))) { - S76_ERROR("Could not register WMI notify handler (%0#6x)\n", err); + pr_err("Could not register WMI notify handler (%0#6x)\n", err); return -EIO; } @@ -236,10 +233,11 @@ static int __init s76_probe(struct platform_device *dev) { } #if LINUX_VERSION_CODE >= KERNEL_VERSION(6,11,0) -static void s76_remove(struct platform_device *dev) { +static void s76_remove(struct platform_device *dev) #else -static int s76_remove(struct platform_device *dev) { +static int s76_remove(struct platform_device *dev) #endif +{ wmi_remove_notify_handler(S76_EVENT_GUID); nv_hda_exit(); @@ -251,7 +249,7 @@ static int s76_remove(struct platform_device *dev) { if (driver_flags & DRIVER_INPUT) { s76_input_exit(); } - if (driver_flags & DRIVER_KB_LED) { + if (driver_flags & (DRIVER_KB_LED_WMI | DRIVER_KB_LED)) { kb_led_exit(); } if (driver_flags & DRIVER_AP_LED) { @@ -263,25 +261,27 @@ static int s76_remove(struct platform_device *dev) { #endif } -static int s76_suspend(struct platform_device *dev, pm_message_t status) { - S76_DEBUG("s76_suspend\n"); +static int s76_suspend(struct platform_device *dev, pm_message_t status) +{ + pr_debug("s76_suspend\n"); - if (driver_flags & DRIVER_KB_LED) { + if (driver_flags & (DRIVER_KB_LED_WMI | DRIVER_KB_LED)) { kb_led_suspend(); } return 0; } -static int s76_resume(struct platform_device *dev) { - S76_DEBUG("s76_resume\n"); +static int s76_resume(struct platform_device *dev) +{ + pr_debug("s76_resume\n"); msleep(2000); if (driver_flags & DRIVER_AP_LED) { ap_led_resume(); } - if (driver_flags & DRIVER_KB_LED) { + if (driver_flags & (DRIVER_KB_LED_WMI | DRIVER_KB_LED)) { kb_led_resume(); } @@ -306,8 +306,9 @@ static struct platform_driver s76_platform_driver = { }, }; -static int __init s76_dmi_matched(const struct dmi_system_id *id) { - S76_INFO("Model %s found\n", id->ident); +static int __init s76_dmi_matched(const struct dmi_system_id *id) +{ + pr_info("Model %s found\n", id->ident); driver_flags = (uint64_t)id->driver_data; return 1; } @@ -334,56 +335,57 @@ static int __init s76_dmi_matched(const struct dmi_system_id *id) { } static struct dmi_system_id s76_dmi_table[] __initdata = { - DMI_TABLE_LEGACY("bonw13", DRIVER_HWMON | DRIVER_KB_LED), - DMI_TABLE("addw1", DRIVER_AP_LED | DRIVER_KB_LED | DRIVER_OLED), - DMI_TABLE("addw2", DRIVER_AP_LED | DRIVER_KB_LED | DRIVER_OLED), - DMI_TABLE("bonw15-b", DRIVER_HWMON | DRIVER_KB_LED), - DMI_TABLE("bonw16", DRIVER_HWMON | DRIVER_KB_LED), - DMI_TABLE("darp5", DRIVER_AP_LED | DRIVER_HWMON | DRIVER_KB_LED), - DMI_TABLE("darp6", DRIVER_AP_LED | DRIVER_HWMON | DRIVER_KB_LED), + DMI_TABLE_LEGACY("bonw13", DRIVER_HWMON | DRIVER_KB_LED_WMI), + DMI_TABLE("addw1", DRIVER_AP_LED | DRIVER_KB_LED_WMI | DRIVER_OLED), + DMI_TABLE("addw2", DRIVER_AP_LED | DRIVER_KB_LED_WMI | DRIVER_OLED), + DMI_TABLE("bonw15-b", DRIVER_HWMON | DRIVER_KB_LED_WMI), + DMI_TABLE("bonw16", DRIVER_HWMON | DRIVER_KB_LED_WMI), + DMI_TABLE("darp5", DRIVER_AP_LED | DRIVER_HWMON | DRIVER_KB_LED_WMI), + DMI_TABLE("darp6", DRIVER_AP_LED | DRIVER_HWMON | DRIVER_KB_LED_WMI), DMI_TABLE("galp2", DRIVER_HWMON), DMI_TABLE("galp3", DRIVER_HWMON), DMI_TABLE("galp3-b", DRIVER_AP_KEY | DRIVER_AP_LED | DRIVER_HWMON), DMI_TABLE("galp3-c", DRIVER_AP_LED | DRIVER_HWMON), DMI_TABLE("galp4", DRIVER_AP_LED | DRIVER_HWMON), DMI_TABLE("gaze13", DRIVER_AP_KEY | DRIVER_AP_LED | DRIVER_HWMON), - DMI_TABLE("gaze14", DRIVER_AP_LED | DRIVER_KB_LED), - DMI_TABLE("gaze15", DRIVER_AP_LED | DRIVER_KB_LED), + DMI_TABLE("gaze14", DRIVER_AP_LED | DRIVER_KB_LED_WMI), + DMI_TABLE("gaze15", DRIVER_AP_LED | DRIVER_KB_LED_WMI), DMI_TABLE("kudu5", DRIVER_AP_KEY | DRIVER_AP_LED | DRIVER_HWMON), - DMI_TABLE("kudu6", DRIVER_AP_KEY | DRIVER_AP_WMI | DRIVER_KB_LED), - DMI_TABLE("oryp3-jeremy", DRIVER_AP_KEY | DRIVER_AP_LED | DRIVER_HWMON | DRIVER_KB_LED), - DMI_TABLE("oryp4", DRIVER_AP_KEY | DRIVER_AP_LED | DRIVER_HWMON | DRIVER_KB_LED), - DMI_TABLE("oryp4-b", DRIVER_AP_KEY | DRIVER_AP_LED | DRIVER_HWMON | DRIVER_KB_LED), - DMI_TABLE("oryp5", DRIVER_AP_LED | DRIVER_HWMON | DRIVER_KB_LED), - DMI_TABLE("oryp6", DRIVER_AP_LED | DRIVER_KB_LED), - DMI_TABLE("pang10", DRIVER_AP_KEY | DRIVER_AP_WMI | DRIVER_KB_LED), - DMI_TABLE("pang11", DRIVER_AP_KEY | DRIVER_AP_WMI | DRIVER_KB_LED), - DMI_TABLE("serw11", DRIVER_AP_KEY | DRIVER_AP_LED | DRIVER_HWMON | DRIVER_KB_LED), - DMI_TABLE("serw11-b", DRIVER_AP_KEY | DRIVER_AP_LED | DRIVER_HWMON | DRIVER_KB_LED), - DMI_TABLE("serw12", DRIVER_AP_KEY | DRIVER_AP_LED | DRIVER_AP_WMI | DRIVER_KB_LED), + DMI_TABLE("kudu6", DRIVER_AP_KEY | DRIVER_AP_WMI | DRIVER_KB_LED_WMI), + DMI_TABLE("oryp3-jeremy", DRIVER_AP_KEY | DRIVER_AP_LED | DRIVER_HWMON | DRIVER_KB_LED_WMI), + DMI_TABLE("oryp4", DRIVER_AP_KEY | DRIVER_AP_LED | DRIVER_HWMON | DRIVER_KB_LED_WMI), + DMI_TABLE("oryp4-b", DRIVER_AP_KEY | DRIVER_AP_LED | DRIVER_HWMON | DRIVER_KB_LED_WMI), + DMI_TABLE("oryp5", DRIVER_AP_LED | DRIVER_HWMON | DRIVER_KB_LED_WMI), + DMI_TABLE("oryp6", DRIVER_AP_LED | DRIVER_KB_LED_WMI), + DMI_TABLE("pang10", DRIVER_AP_KEY | DRIVER_AP_WMI | DRIVER_KB_LED_WMI), + DMI_TABLE("pang11", DRIVER_AP_KEY | DRIVER_AP_WMI | DRIVER_KB_LED_WMI), + DMI_TABLE("serw11", DRIVER_AP_KEY | DRIVER_AP_LED | DRIVER_HWMON | DRIVER_KB_LED_WMI), + DMI_TABLE("serw11-b", DRIVER_AP_KEY | DRIVER_AP_LED | DRIVER_HWMON | DRIVER_KB_LED_WMI), + DMI_TABLE("serw12", DRIVER_AP_KEY | DRIVER_AP_LED | DRIVER_AP_WMI | DRIVER_KB_LED_WMI), + DMI_TABLE("serw14", DRIVER_HWMON | DRIVER_KB_LED), {} }; - MODULE_DEVICE_TABLE(dmi, s76_dmi_table); -static int __init s76_init(void) { +static int __init s76_init(void) +{ if (!dmi_check_system(s76_dmi_table)) { - S76_INFO("Model does not utilize this driver"); + pr_info("Model does not utilize this driver"); return -ENODEV; } if (!driver_flags) { - S76_INFO("Driver data not defined"); + pr_info("Driver data not defined"); return -ENODEV; } if (!wmi_has_guid(S76_EVENT_GUID)) { - S76_INFO("No known WMI event notification GUID found\n"); + pr_info("No known WMI event notification GUID found\n"); return -ENODEV; } if (!wmi_has_guid(S76_WMBB_GUID)) { - S76_INFO("No known WMI control method GUID found\n"); + pr_info("No known WMI control method GUID found\n"); return -ENODEV; } @@ -396,13 +398,13 @@ static int __init s76_init(void) { return 0; } +module_init(s76_init); -static void __exit s76_exit(void) { +static void __exit s76_exit(void) +{ platform_device_unregister(s76_platform_device); platform_driver_unregister(&s76_platform_driver); } - -module_init(s76_init); module_exit(s76_exit); MODULE_AUTHOR("Jeremy Soller "); diff --git a/system76_nv_hda.c b/system76_nv_hda.c deleted file mode 100644 index 7c2de34..0000000 --- a/system76_nv_hda.c +++ /dev/null @@ -1,176 +0,0 @@ -/* Based on bbswitch, - * Copyright (C) 2011-2013 Bumblebee Project - * Author: Peter Wu - * - * 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 - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -enum { - CARD_UNCHANGED = -1, - CARD_OFF = 0, - CARD_ON = 1, -}; - -static struct pci_dev *dis_dev; -static struct pci_dev *sub_dev = NULL; - -// Returns 1 if the card is disabled, 0 if enabled -static int is_card_disabled(void) { - //check for: 1.bit is set 2.sub-function is available. - u32 cfg_word; - struct pci_dev *tmp_dev = NULL; - - sub_dev = NULL; - - // read config word at 0x488 - pci_read_config_dword(dis_dev, 0x488, &cfg_word); - if ((cfg_word & 0x2000000)==0x2000000) { - //check for subdevice. read first config dword of sub function 1 - while ((tmp_dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, tmp_dev)) != NULL) { - int pci_class = tmp_dev->class >> 8; - - if (pci_class != 0x403) - continue; - - if (tmp_dev->vendor == PCI_VENDOR_ID_NVIDIA) { - sub_dev = tmp_dev; - S76_INFO("Found NVIDIA audio device %s\n", dev_name(&tmp_dev->dev)); - } - } - - if (sub_dev == NULL) { - S76_INFO("No NVIDIA audio device found, unsetting config bit.\n"); - cfg_word|=0x2000000; - pci_write_config_dword(dis_dev, 0x488, cfg_word); - return 1; - } - - return 0; - } else { - return 1; - } -} - -static void nv_hda_off(void) { - u32 cfg_word; - if (is_card_disabled()) { - return; - } - - //remove device - pci_dev_put(sub_dev); - pci_stop_and_remove_bus_device(sub_dev); - - S76_INFO("NVIDIA audio: disabling\n"); - - //setting bit to turn off - pci_read_config_dword(dis_dev, 0x488, &cfg_word); - cfg_word&=0xfdffffff; - pci_write_config_dword(dis_dev, 0x488, cfg_word); -} - -static void nv_hda_on(void) { - u32 cfg_word; - u8 hdr_type; - - if (!is_card_disabled()) { - return; - } - - S76_INFO("NVIDIA audio: enabling\n"); - - // read,set bit, write config word at 0x488 - pci_read_config_dword(dis_dev, 0x488, &cfg_word); - cfg_word|=0x2000000; - pci_write_config_dword(dis_dev, 0x488, cfg_word); - - //pci_scan_single_device - pci_read_config_byte(dis_dev, PCI_HEADER_TYPE, &hdr_type); - - if (!(hdr_type & 0x80)) { - S76_ERROR("NVIDIA not multifunction, no audio\n"); - return; - } - - sub_dev = pci_scan_single_device(dis_dev->bus, 1); - if (!sub_dev) { - S76_ERROR("No NVIDIA audio device found\n"); - return; - } - - S76_INFO("NVIDIA audio found, adding\n"); - pci_assign_unassigned_bus_resources(dis_dev->bus); - pci_bus_add_devices(dis_dev->bus); - pci_dev_get(sub_dev); -} - -/* power bus so we can read PCI configuration space */ -static void dis_dev_get(void) { - if (dis_dev->bus && dis_dev->bus->self) { - pm_runtime_get_sync(&dis_dev->bus->self->dev); - } -} - -static void dis_dev_put(void) { - if (dis_dev->bus && dis_dev->bus->self) { - pm_runtime_put_sync(&dis_dev->bus->self->dev); - } -} - - -static int __init nv_hda_init(struct device *dev) { - struct pci_dev *pdev = NULL; - - while ((pdev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) { - int pci_class = pdev->class >> 8; - - if (pci_class != PCI_CLASS_DISPLAY_VGA && pci_class != PCI_CLASS_DISPLAY_3D) { - continue; - } - - if (pdev->vendor == PCI_VENDOR_ID_NVIDIA) { - dis_dev = pdev; - S76_INFO("NVIDIA device %s\n", dev_name(&pdev->dev)); - } - } - - if (dis_dev == NULL) { - S76_ERROR("No NVIDIA device found\n"); - return -ENODEV; - } - - dis_dev_get(); - - nv_hda_on(); - - S76_INFO("NVIDIA Audio %s is %s\n", dev_name(&dis_dev->dev), is_card_disabled() ? "off" : "on"); - - dis_dev_put(); - - return 0; -} - -static void __exit nv_hda_exit(void) { - if (dis_dev == NULL) - return; - - dis_dev_get(); - - nv_hda_off(); - - pr_info("NVIDIA Audio %s is %s\n", dev_name(&dis_dev->dev), is_card_disabled() ? "off" : "on"); - - dis_dev_put(); - -}