10 Commits

Author SHA1 Message Date
e0313a70c3 try again! 2020-08-09 23:15:16 +00:00
fd987219fc try again 2020-08-09 23:05:16 +00:00
219c34f5a9 Update bbswitch.c 2020-08-09 22:54:07 +00:00
8ff86a7eff try another idea 2020-08-09 22:47:39 +00:00
c38a3e084d Initial changes 2020-08-09 20:45:42 +00:00
ddbd243638 Add missing proc_fs.h header
Required for 'struct proc_ops' since v5.7-rc1 with commit df23e2be3d24
("acpi: Remove header dependency").
2020-05-26 21:43:35 +02:00
07b110df46 Merge pull request #196 from mateuszmandera/kernel_560
Fix the build with Linux 5.6.0
2020-05-19 23:38:51 +02:00
b0fdcfd847 Use proc_ops structure for kernel version >= 5.6.0
Since 5.6.0, proc_create requires a `struct proc_ops *` argument instead
of `struct file_operations *`.
Commit with the migration in the kernel source can be found at
d56c0d45f0
2020-05-19 23:34:06 +02:00
9dd227019a Merge pull request #158 from karolherbst/fix_4.12
fix building against 4.12

Should work with older kernels too, it was first introduced with torvalds/linux@c22ce14 which includes asm/uaccess.h
2017-07-16 23:53:37 +02:00
322c9625c2 fix building against 4.12 2017-07-09 15:51:10 +02:00
3 changed files with 17 additions and 142 deletions

View File

@ -165,9 +165,3 @@ issues on this module in the issue tracker and provide the following details:
Upload the generated tarball on the above Launchpad URL and provide a link to Upload the generated tarball on the above Launchpad URL and provide a link to
the comment containing your report. the comment containing your report.
TODO
----
With the new PCI device approach, if load_state=0, then starting bumblebeed will
unload bbswitch. Fix Bumblebee not to unload the module when the PM method is
bbswitch and the loaded module is bbswitch.

View File

@ -8,16 +8,6 @@
* # echo ON > /proc/acpi/bbswitch * # echo ON > /proc/acpi/bbswitch
* Get status * Get status
* # cat /proc/acpi/bbswitch * # cat /proc/acpi/bbswitch
*
* Note: only one PCI driver (bbswitch, nouveau, etc.) can bind to a PCI device.
* When turning a device OFF, bbswitch tries to bind itself to the PCI device.
* When turning a device ON, bbswitch unbinds a device (if it was bound) before
* returning from the write.
*
* TODO is this true?
* The new dual module approach is used to allow for backwards compatibility,
* Bumblebee unloads any driver that is loaded for a device, that would however
* result in unloading the main bbswitch module.
*/ */
/* /*
* Copyright (C) 2011-2013 Bumblebee Project * Copyright (C) 2011-2013 Bumblebee Project
@ -41,10 +31,12 @@
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/module.h> #include <linux/module.h>
#include <asm/uaccess.h> #include <linux/uaccess.h>
#include <linux/suspend.h> #include <linux/suspend.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/proc_fs.h>
#include <linux/version.h>
#define BBSWITCH_VERSION "0.8" #define BBSWITCH_VERSION "0.8"
@ -207,26 +199,6 @@ static int bbswitch_optimus_dsm(void) {
return 0; return 0;
} }
// Windows 8/8.1/10 do not use DSM to put the device in D3cold state,
// instead it disables power resources on the parent PCIe port device.
static bool has_pr3_support(void) {
acpi_handle parent_handle;
struct acpi_device *ad = NULL;
if (ACPI_FAILURE(acpi_get_parent(dis_handle, &parent_handle))) {
pr_warn("Failed to obtain the parent device\n");
return false;
}
acpi_bus_get_device(parent_handle, &ad);
if (!ad) {
pr_warn("Failed to obtain an ACPI device for handle\n");
return false;
}
return ad->power.flags.power_resources;
}
static int bbswitch_acpi_off(void) { static int bbswitch_acpi_off(void) {
if (dsm_type == DSM_TYPE_NVIDIA) { if (dsm_type == DSM_TYPE_NVIDIA) {
char args[] = {2, 0, 0, 0}; char args[] = {2, 0, 0, 0};
@ -315,7 +287,7 @@ static void bbswitch_on(void) {
return; return;
pr_info("enabling discrete graphics\n"); pr_info("enabling discrete graphics\n");
//pci_bridge_secondary_bus_reset(dis_dev);
if (bbswitch_acpi_on()) if (bbswitch_acpi_on())
pr_warn("The discrete card could not be enabled by a _DSM call\n"); pr_warn("The discrete card could not be enabled by a _DSM call\n");
@ -405,6 +377,15 @@ static int bbswitch_pm_handler(struct notifier_block *nbp,
return 0; return 0;
} }
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
static struct proc_ops bbswitch_fops = {
.proc_open = bbswitch_proc_open,
.proc_read = seq_read,
.proc_write = bbswitch_proc_write,
.proc_lseek = seq_lseek,
.proc_release= single_release
};
#else
static struct file_operations bbswitch_fops = { static struct file_operations bbswitch_fops = {
.open = bbswitch_proc_open, .open = bbswitch_proc_open,
.read = seq_read, .read = seq_read,
@ -412,6 +393,7 @@ static struct file_operations bbswitch_fops = {
.llseek = seq_lseek, .llseek = seq_lseek,
.release= single_release .release= single_release
}; };
#endif
static struct notifier_block nb = { static struct notifier_block nb = {
.notifier_call = &bbswitch_pm_handler .notifier_call = &bbswitch_pm_handler
@ -448,12 +430,13 @@ static int __init bbswitch_init(void) {
acpi_get_name(handle, ACPI_FULL_PATHNAME, &buf); acpi_get_name(handle, ACPI_FULL_PATHNAME, &buf);
if (pdev->vendor == PCI_VENDOR_ID_INTEL) { if (pdev->vendor == PCI_VENDOR_ID_ATI) {
igd_handle = handle; igd_handle = handle;
pr_info("Found integrated VGA device %s: %s\n", pr_info("Found integrated VGA device %s: %s\n",
dev_name(&pdev->dev), (char *)buf.pointer); dev_name(&pdev->dev), (char *)buf.pointer);
} else { } else {
dis_dev = pdev; dis_dev = pdev;
pci_d3cold_enable(pdev);
dis_handle = handle; dis_handle = handle;
pr_info("Found discrete VGA device %s: %s\n", pr_info("Found discrete VGA device %s: %s\n",
dev_name(&pdev->dev), (char *)buf.pointer); dev_name(&pdev->dev), (char *)buf.pointer);
@ -466,9 +449,7 @@ static int __init bbswitch_init(void) {
return -ENODEV; return -ENODEV;
} }
if (has_pr3_support()) { if (!skip_optimus_dsm &&
pr_info("skipping _DSM as _PR3 support is detected\n");
} else if (!skip_optimus_dsm &&
has_dsm_func(acpi_optimus_dsm_muid, 0x100, 0x1A)) { has_dsm_func(acpi_optimus_dsm_muid, 0x100, 0x1A)) {
dsm_type = DSM_TYPE_OPTIMUS; dsm_type = DSM_TYPE_OPTIMUS;
pr_info("detected an Optimus _DSM function\n"); pr_info("detected an Optimus _DSM function\n");

View File

@ -1,100 +0,0 @@
/*
* TODO merge into main bbswitch module.
* TODO on ON call device_release_driver
* TODO how to bind to a specific device from kernel space? Can't use
* driver_probe_device (https://lkml.org/lkml/2014/2/14/628). Maybe use
* driver_override or new_id/bind/remove_id from userspace?
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/pci.h>
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <linux/delay.h>
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Toggle the discrete graphics card (PCI driver)");
MODULE_AUTHOR("Peter Wu <peter@lekensteyn.nl>");
static int bbswitch_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
/* TODO how to discover devices? */
/* Prevent kernel from detaching the PCI device for some devices that
* generate hotplug events. The graphics card is typically not physically
* removable. */
pci_ignore_hotplug(dev);
pm_runtime_set_active(&dev->dev); /* clear any errors */
/* Use autosuspend to avoid lspci waking up the device multiple times. */
pm_runtime_set_autosuspend_delay(&dev->dev, 2000);
pm_runtime_use_autosuspend(&dev->dev);
pm_runtime_allow(&dev->dev);
pm_runtime_put_autosuspend(&dev->dev);
return 0;
}
static void bbswitch_pci_remove(struct pci_dev *dev)
{
pm_runtime_get_noresume(&dev->dev);
pm_runtime_dont_use_autosuspend(&dev->dev);
pm_runtime_forbid(&dev->dev);
}
static int bbswitch_runtime_suspend(struct device *dev) {
struct pci_dev *pdev = to_pci_dev(dev);
pr_info("disabling discrete graphics\n");
/* TODO if _PR3 is not supported, call Optimus DSM here. */
/* TODO for v1 Optimus, call DSM here. */
/* Save state now that the device is still awake, makes PCI layer happy */
pci_save_state(pdev);
/* TODO if _PR3 is supported, should this be PCI_D3hot? */
pci_set_power_state(pdev, PCI_D3cold);
return 0;
}
static int bbswitch_runtime_resume(struct device *dev) {
pr_info("enabling discrete graphics\n");
/* TODO for v1 Optimus, call DSM here. */
/* Nothing to do for Optimus, the PCI layer already moved into D0 state. */
return 0;
}
static struct dev_pm_ops bbswitch_pm_ops = {
.runtime_suspend = bbswitch_runtime_suspend,
.runtime_resume = bbswitch_runtime_resume,
/* No runtime_idle callback, the default zero delay is sufficient. */
};
static struct pci_driver bbswitch_pci_driver = {
.name = KBUILD_MODNAME,
.id_table = NULL, /* will be added dynamically */
.probe = bbswitch_pci_probe,
.remove = bbswitch_pci_remove,
.driver.pm = &bbswitch_pm_ops,
};
static int __init bbswitch_dev_init(void) {
int ret;
ret = pci_register_driver(&bbswitch_pci_driver);
#if 0
ret = pci_add_dynid(&bbswitch_pci_driver, PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID,
PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16, 0xff0000);
#endif
return ret;
}
static void __exit bbswitch_dev_exit(void) {
pci_unregister_driver(&bbswitch_pci_driver);
}
module_init(bbswitch_dev_init);
module_exit(bbswitch_dev_exit);
/* vim: set sw=4 ts=4 et: */