Skip to content

Instantly share code, notes, and snippets.

Created June 24, 2010 20:03
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anonymous/451904 to your computer and use it in GitHub Desktop.
Save anonymous/451904 to your computer and use it in GitHub Desktop.
/*
* Display backlight driver for Nvidia graphics adapters.
*
* Copyright (c) 2008-2010 Mario Schwalbe <schwalbe@inf.tu-dresden.de>
* Based on the mechanism dicovered by the author of NvClock:
* Copyright (c) 2001-2009 Roderick Colenbrander
* Site: http://nvclock.sourceforge.net
* Fixes and suggestions by:
* Guillaume Zin <guillaume.zin@gmail.com>
* Steven Barrett <damentz@gmail.com>
*
* 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.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/backlight.h>
#include <linux/dmi.h>
#include <linux/pci.h>
#include <linux/err.h>
#include <linux/version.h>
/*
* Maybe the check against the subsystem vendor should be removed,
* but there's no guarantee that the chip's smartdimmer signals
* are actually connected to the display logic. Right now, these
* are the supported (read connected) vendors according to NvClock.
*
* TODO: Remove this stuff. Shouldn't be necessary.
*/
/* #define CONFIG_NVIDIA_BL_CHECK_SUBSYSTEM_VENDOR */
/* Check for the new backlight suspend/resume feature */
#if defined(BL_CORE_SUSPENDRESUME)
#define USE_BACKLIGHT_SUSPEND
/* Otherwise use a platform driver if PM is enabled */
#elif defined(CONFIG_PM)
/*
* TODO: Remove this stuff. Shouldn't be necessary anymore
* unless to be able to compile against very old kernels.
*/
#warning USE_PLATFORM_DRIVER
#define USE_PLATFORM_DRIVER
#undef __initdata
#define __initdata /* nothing */
#undef __devinitconst
#define __devinitconst /* nothing */
#endif
/* Check whether backlight props.state is present */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31)
#define HAVE_BACKLIGHT_PROPS_STATE
#endif
/* Check whether we have to initialize backlight props */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34)
#define INIT_BACKLIGHT_PROPS
#endif
/* Register constants */
#define NV4X_BRIGHTNESS_OFFSET 0x15f2
#define NV4X_BRIGHTNESS_MASK 0x001f
#define NV5X_PDISPLAY_OFFSET 0x00610000
#define NV5X_PDISPLAY_BRIGHTNESS_OFFSET 0x0000c084
#define NV5X_PDIPSLAY_BRIGHTNESS_CONTROL_ENABLED 0x80000000
/*
* Driver private data structure
*/
struct driver_data {
/* PCI region (BAR) the smartdimmer register is in */
unsigned bar;
/* Register offset into this region */
unsigned long reg_offset;
/* Register size in byte */
unsigned reg_size;
/* Register mask to apply while updating the register (NV5X only) */
unsigned reg_mask;
/* Maximum brightness level in the range 0 ... max_level */
unsigned max_level;
/* Hardware register get/set functions */
struct driver_data_ops {
unsigned (*get_intensity)(const struct driver_data *dd);
int (*set_intensity)(struct driver_data *dd,
unsigned intensity);
} ops;
/* The device we drive */
struct pci_dev *dev;
/* Pointer to the mapped smartdimmer register */
/* volatile */ void __iomem *smartdimmer;
};
/*
* Machine quirks
*/
struct machine_quirks {
/* Request to drive a specific device for machines
* incorporating several graphics adapters */
unsigned dev_id;
/* Some machines seem to ignore higher levels
* although supported by the graphics adapter. */
unsigned max_level;
};
/*
* Module parameters
*/
static unsigned debug = 0;
module_param_named(debug, debug, int, 0644);
MODULE_PARM_DESC(debug, "Set to one to enable debugging messages.");
static unsigned shift = 0;
module_param_named(shift, shift, int, 0444);
MODULE_PARM_DESC(shift, "Shift the value by n bits to reduce the range.");
static unsigned dev_id = PCI_ANY_ID;
module_param_named(dev_id, dev_id, int, 0444);
MODULE_PARM_DESC(dev_id, "Disable auto-detection and attempt to drive exactly "
"the device of this PCI ID if present.");
static unsigned max_level = 0;
module_param_named(max_level, max_level, int, 0444);
MODULE_PARM_DESC(max_level, "Maximum brightness level to use in the range "
"0 ... max_level. Use with care.");
static unsigned force = 0;
module_param_named(force, force, int, 0444);
MODULE_PARM_DESC(force, "Force loading of the driver even if the device "
"is an unknown Nvidia graphics adapter. Use with care.");
/*
* Implementation for NV4X chips
* (NV40, NV41, NV43, NV44, NV46, NV47, NV49, NV4B, C51)
*/
static unsigned nv4x_get_intensity(const struct driver_data *dd)
{
const unsigned value = ioread16(dd->smartdimmer);
if (unlikely(debug))
printk(KERN_DEBUG "nvidia_bl: register read: 0x%04x\n", value);
return value & NV4X_BRIGHTNESS_MASK;
}
static int nv4x_set_intensity(struct driver_data *dd, unsigned intensity)
{
const unsigned value =
(ioread16(dd->smartdimmer) & ~NV4X_BRIGHTNESS_MASK) |
intensity;
if (unlikely(debug))
printk(KERN_DEBUG "nvidia_bl: register write: 0x%04x\n", value);
iowrite16(value, dd->smartdimmer);
return 0;
}
static const struct driver_data nv4x_driver_data __devinitconst = {
.bar = 0,
.reg_offset = NV4X_BRIGHTNESS_OFFSET,
.reg_size = 2,
.max_level = 31,
.ops = {
.get_intensity = &nv4x_get_intensity,
.set_intensity = &nv4x_set_intensity,
}
};
/*
* Implementation for NV5X chips
* (NV50, G84, G86, G92, G94, G96, GT200)
*/
static unsigned nv5x_get_intensity(const struct driver_data *dd)
{
unsigned value = ioread32(dd->smartdimmer);
if (unlikely(debug))
printk(KERN_DEBUG "nvidia_bl: register read: 0x%08x\n", value);
value &= dd->reg_mask;
return (value <= dd->max_level) ? value : dd->max_level;
}
static int nv5x_set_intensity(struct driver_data *dd, unsigned intensity)
{
const unsigned value = (intensity & dd->reg_mask)
| NV5X_PDIPSLAY_BRIGHTNESS_CONTROL_ENABLED;
if (unlikely(debug))
printk(KERN_DEBUG "nvidia_bl: register write: 0x%08x\n", value);
iowrite32(value, dd->smartdimmer);
return 0;
}
static const struct driver_data nv5x_driver_data __devinitconst = {
.bar = 0,
.reg_offset = NV5X_PDISPLAY_OFFSET + NV5X_PDISPLAY_BRIGHTNESS_OFFSET,
.reg_size = 4,
/* Could set up to 11 bits. More got ignored. */
.max_level = 2047,
.ops = {
.get_intensity = &nv5x_get_intensity,
.set_intensity = &nv5x_set_intensity,
}
};
/*
* Device matching.
*
* The list of supported devices was primarily taken from Nvidia's driver
* documentation appendix A, available at:
* http://download.nvidia.com/XFree86/Linux-x86_64/195.30/README/supportedchips.html
* http://download.nvidia.com/XFree86/Linux-x86_64/195.36.24/README/supportedchips.html
* and completed with NvClock's device table and posts by users of Nvidia's forum at:
* http://www.nvnews.net/vbulletin/showthread.php?t=143025.
*
* Please send reports to Mario Schwalbe <schwalbe@inf.tu-dresden.de>
* and also include the output of:
* $ cat /sys/class/dmi/id/sys_vendor
* $ cat /sys/class/dmi/id/product_name
*/
static DEFINE_PCI_DEVICE_TABLE(nvidia_bl_device_table) = {
/* Geforce Go 7800 */
{ PCI_VDEVICE(NVIDIA, 0x0098), (kernel_ulong_t)&nv4x_driver_data },
/* Geforce Go 7800 GTX */
{ PCI_VDEVICE(NVIDIA, 0x0099), (kernel_ulong_t)&nv4x_driver_data },
/* Geforce Go 6800 */
{ PCI_VDEVICE(NVIDIA, 0x00c8), (kernel_ulong_t)&nv4x_driver_data },
/* Geforce Go 6800 Ultra */
{ PCI_VDEVICE(NVIDIA, 0x00c9), (kernel_ulong_t)&nv4x_driver_data },
/* Quadro FX Go 1400 */
{ PCI_VDEVICE(NVIDIA, 0x00cc), (kernel_ulong_t)&nv4x_driver_data },
/* Geforce Go 6600 */
{ PCI_VDEVICE(NVIDIA, 0x0144), (kernel_ulong_t)&nv4x_driver_data },
/* Geforce Go 6600 TE/6200 TE */
{ PCI_VDEVICE(NVIDIA, 0x0146), (kernel_ulong_t)&nv4x_driver_data },
/* Geforce Go 6600 */
{ PCI_VDEVICE(NVIDIA, 0x0148), (kernel_ulong_t)&nv4x_driver_data },
/* Geforce Go 6600 GT */
{ PCI_VDEVICE(NVIDIA, 0x0149), (kernel_ulong_t)&nv4x_driver_data },
/* Quadro FX 540M */
{ PCI_VDEVICE(NVIDIA, 0x014c), (kernel_ulong_t)&nv4x_driver_data },
/* Geforce Go 6200 */
{ PCI_VDEVICE(NVIDIA, 0x0164), (kernel_ulong_t)&nv4x_driver_data },
/* Geforce Go 6400 */
{ PCI_VDEVICE(NVIDIA, 0x0166), (kernel_ulong_t)&nv4x_driver_data },
/* Geforce Go 6200 */
{ PCI_VDEVICE(NVIDIA, 0x0167), (kernel_ulong_t)&nv4x_driver_data },
/* Geforce Go 6400 */
{ PCI_VDEVICE(NVIDIA, 0x0168), (kernel_ulong_t)&nv4x_driver_data },
/* Geforce Go 7200 */
{ PCI_VDEVICE(NVIDIA, 0x01d6), (kernel_ulong_t)&nv4x_driver_data },
/* Geforce Go 7300 */
{ PCI_VDEVICE(NVIDIA, 0x01d7), (kernel_ulong_t)&nv4x_driver_data },
/* Geforce Go 7400 */
{ PCI_VDEVICE(NVIDIA, 0x01d8), (kernel_ulong_t)&nv4x_driver_data },
/* Geforce Go 7400GS (NvClock) */
{ PCI_VDEVICE(NVIDIA, 0x01d9), (kernel_ulong_t)&nv4x_driver_data },
/* Quadro NVS 110M */
{ PCI_VDEVICE(NVIDIA, 0x01da), (kernel_ulong_t)&nv4x_driver_data },
/* Quadro NVS 120M */
{ PCI_VDEVICE(NVIDIA, 0x01db), (kernel_ulong_t)&nv4x_driver_data },
/* Quadro FX 350M */
{ PCI_VDEVICE(NVIDIA, 0x01dc), (kernel_ulong_t)&nv4x_driver_data },
/* Geforce 7500 LE */
{ PCI_VDEVICE(NVIDIA, 0x01dd), (kernel_ulong_t)&nv4x_driver_data },
/* NV44M (NvClock) */
{ PCI_VDEVICE(NVIDIA, 0x0228), (kernel_ulong_t)&nv4x_driver_data },
/* Geforce Go 6150 */
{ PCI_VDEVICE(NVIDIA, 0x0244), (kernel_ulong_t)&nv4x_driver_data },
/* Geforce Go 6100 */
{ PCI_VDEVICE(NVIDIA, 0x0247), (kernel_ulong_t)&nv4x_driver_data },
/* Geforce Go 7950 GTX */
{ PCI_VDEVICE(NVIDIA, 0x0297), (kernel_ulong_t)&nv4x_driver_data },
/* Geforce Go 7900 GS */
{ PCI_VDEVICE(NVIDIA, 0x0298), (kernel_ulong_t)&nv4x_driver_data },
/* Geforce Go 7900GTX (NvClock) / Quadro NVS 510M */
{ PCI_VDEVICE(NVIDIA, 0x0299), (kernel_ulong_t)&nv4x_driver_data },
/* Quadro FX 2500M */
{ PCI_VDEVICE(NVIDIA, 0x029a), (kernel_ulong_t)&nv4x_driver_data },
/* Quadro FX 1500M */
{ PCI_VDEVICE(NVIDIA, 0x029b), (kernel_ulong_t)&nv4x_driver_data },
/* Geforce Go 7700 */
{ PCI_VDEVICE(NVIDIA, 0x0397), (kernel_ulong_t)&nv4x_driver_data },
/* Geforce Go 7600 */
{ PCI_VDEVICE(NVIDIA, 0x0398), (kernel_ulong_t)&nv4x_driver_data },
/* Geforce Go 7600 GT */
{ PCI_VDEVICE(NVIDIA, 0x0399), (kernel_ulong_t)&nv4x_driver_data },
/* Quadro NVS 300M (NvClock) */
{ PCI_VDEVICE(NVIDIA, 0x039a), (kernel_ulong_t)&nv4x_driver_data },
/* Geforce Go 7900SE (NvClock) */
{ PCI_VDEVICE(NVIDIA, 0x039b), (kernel_ulong_t)&nv4x_driver_data },
/* QuadroFX 550M (NvClock) */
{ PCI_VDEVICE(NVIDIA, 0x039c), (kernel_ulong_t)&nv4x_driver_data },
/* Geforce 9500M GS */
{ PCI_VDEVICE(NVIDIA, 0x0405), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce NB9P-GE (NvClock) */
{ PCI_VDEVICE(NVIDIA, 0x0406), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce 8600M GT */
{ PCI_VDEVICE(NVIDIA, 0x0407), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce 9650M GS */
{ PCI_VDEVICE(NVIDIA, 0x0408), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce 8700M GT */
{ PCI_VDEVICE(NVIDIA, 0x0409), (kernel_ulong_t)&nv5x_driver_data },
/* Quadro NVS 370M (NvClock) */
{ PCI_VDEVICE(NVIDIA, 0x040a), (kernel_ulong_t)&nv5x_driver_data },
/* Quadro NVS 320M */
{ PCI_VDEVICE(NVIDIA, 0x040b), (kernel_ulong_t)&nv5x_driver_data },
/* Quadro FX 570M */
{ PCI_VDEVICE(NVIDIA, 0x040c), (kernel_ulong_t)&nv5x_driver_data },
/* Quadro FX 1600M */
{ PCI_VDEVICE(NVIDIA, 0x040d), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce 8600M GS */
{ PCI_VDEVICE(NVIDIA, 0x0425), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce 8400M GT */
{ PCI_VDEVICE(NVIDIA, 0x0426), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce 8400M GS */
{ PCI_VDEVICE(NVIDIA, 0x0427), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce 8400M G */
{ PCI_VDEVICE(NVIDIA, 0x0428), (kernel_ulong_t)&nv5x_driver_data },
/* Quadro NVS 140M */
{ PCI_VDEVICE(NVIDIA, 0x0429), (kernel_ulong_t)&nv5x_driver_data },
/* Quadro NVS 130M */
{ PCI_VDEVICE(NVIDIA, 0x042a), (kernel_ulong_t)&nv5x_driver_data },
/* Quadro NVS 135M */
{ PCI_VDEVICE(NVIDIA, 0x042b), (kernel_ulong_t)&nv5x_driver_data },
/* Quadro FX 360M */
{ PCI_VDEVICE(NVIDIA, 0x042d), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce 9300M G */
{ PCI_VDEVICE(NVIDIA, 0x042e), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce 7150M / nForce 630M */
{ PCI_VDEVICE(NVIDIA, 0x0531), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce 7000M / nForce 610M */
{ PCI_VDEVICE(NVIDIA, 0x0533), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce 9800M GTX */
{ PCI_VDEVICE(NVIDIA, 0x0608), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce 8800M GTS */
{ PCI_VDEVICE(NVIDIA, 0x0609), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce GTX 280M */
{ PCI_VDEVICE(NVIDIA, 0x060a), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce 9800M GT */
{ PCI_VDEVICE(NVIDIA, 0x060b), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce 8800M GTX */
{ PCI_VDEVICE(NVIDIA, 0x060c), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce GTX 285M */
{ PCI_VDEVICE(NVIDIA, 0x060f), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce 9800M GTX */
{ PCI_VDEVICE(NVIDIA, 0x0617), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce GTX 260M */
{ PCI_VDEVICE(NVIDIA, 0x0618), (kernel_ulong_t)&nv5x_driver_data },
/* Quadro FX 3600M */
{ PCI_VDEVICE(NVIDIA, 0x061c), (kernel_ulong_t)&nv5x_driver_data },
/* Quadro FX 2800M */
{ PCI_VDEVICE(NVIDIA, 0x061d), (kernel_ulong_t)&nv5x_driver_data },
/* Quadro FX 3700M */
{ PCI_VDEVICE(NVIDIA, 0x061e), (kernel_ulong_t)&nv5x_driver_data },
/* Quadro FX 3800M */
{ PCI_VDEVICE(NVIDIA, 0x061f), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce 9800M GTS */
{ PCI_VDEVICE(NVIDIA, 0x0628), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce 9700M GTS */
{ PCI_VDEVICE(NVIDIA, 0x062a), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce 9800M GS */
{ PCI_VDEVICE(NVIDIA, 0x062b), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce 9800M GTS */
{ PCI_VDEVICE(NVIDIA, 0x062c), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce GTS 160M */
{ PCI_VDEVICE(NVIDIA, 0x0631), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce GTS 150M */
{ PCI_VDEVICE(NVIDIA, 0x0632), (kernel_ulong_t)&nv5x_driver_data },
/* Quadro FX 2700M */
{ PCI_VDEVICE(NVIDIA, 0x063a), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce 9600M GT */
{ PCI_VDEVICE(NVIDIA, 0x0647), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce 9600M GS */
{ PCI_VDEVICE(NVIDIA, 0x0648), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce 9600M GT */
{ PCI_VDEVICE(NVIDIA, 0x0649), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce 9700M GT */
{ PCI_VDEVICE(NVIDIA, 0x064a), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce 9500M G */
{ PCI_VDEVICE(NVIDIA, 0x064b), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce 9650M GT */
{ PCI_VDEVICE(NVIDIA, 0x064c), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce G 110M */
{ PCI_VDEVICE(NVIDIA, 0x0651), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce GT 130M */
{ PCI_VDEVICE(NVIDIA, 0x0652), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce GT 120M */
{ PCI_VDEVICE(NVIDIA, 0x0653), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce GT 220M */
{ PCI_VDEVICE(NVIDIA, 0x0654), (kernel_ulong_t)&nv5x_driver_data },
/* Quadro FX 1700M */
{ PCI_VDEVICE(NVIDIA, 0x065a), (kernel_ulong_t)&nv5x_driver_data },
/* Quadro FX 770M */
{ PCI_VDEVICE(NVIDIA, 0x065c), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce 9300M GS */
{ PCI_VDEVICE(NVIDIA, 0x06e5), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce 9200M GS */
{ PCI_VDEVICE(NVIDIA, 0x06e8), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce 9300M GS */
{ PCI_VDEVICE(NVIDIA, 0x06e9), (kernel_ulong_t)&nv5x_driver_data },
/* Quadro NVS 150M */
{ PCI_VDEVICE(NVIDIA, 0x06ea), (kernel_ulong_t)&nv5x_driver_data },
/* Quadro NVS 160M */
{ PCI_VDEVICE(NVIDIA, 0x06eb), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce G 105M */
{ PCI_VDEVICE(NVIDIA, 0x06ec), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce G 103M */
{ PCI_VDEVICE(NVIDIA, 0x06ef), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce G 105M */
{ PCI_VDEVICE(NVIDIA, 0x06f1), (kernel_ulong_t)&nv5x_driver_data },
/* Quadro NVS 420 */
{ PCI_VDEVICE(NVIDIA, 0x06f8), (kernel_ulong_t)&nv5x_driver_data },
/* Quadro FX 370 LP */
{ PCI_VDEVICE(NVIDIA, 0x06f9), (kernel_ulong_t)&nv5x_driver_data },
/* Quadro FX 370M */
{ PCI_VDEVICE(NVIDIA, 0x06fb), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce 9100M G */
{ PCI_VDEVICE(NVIDIA, 0x0844), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce 8200M G */
{ PCI_VDEVICE(NVIDIA, 0x0845), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce 9400M G */
{ PCI_VDEVICE(NVIDIA, 0x0862), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce 9400M */
{ PCI_VDEVICE(NVIDIA, 0x0863), (kernel_ulong_t)&nv5x_driver_data },
/* ION */
{ PCI_VDEVICE(NVIDIA, 0x0865), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce 9400M G */
{ PCI_VDEVICE(NVIDIA, 0x0866), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce 9100M G */
{ PCI_VDEVICE(NVIDIA, 0x086e), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce 8200M G */
{ PCI_VDEVICE(NVIDIA, 0x086f), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce 9400M */
{ PCI_VDEVICE(NVIDIA, 0x0870), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce 9200 (NvClock) */
{ PCI_VDEVICE(NVIDIA, 0x0871), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce G 102M */
{ PCI_VDEVICE(NVIDIA, 0x0872), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce G 102M */
{ PCI_VDEVICE(NVIDIA, 0x0873), (kernel_ulong_t)&nv5x_driver_data },
/* ION */
{ PCI_VDEVICE(NVIDIA, 0x0874), (kernel_ulong_t)&nv5x_driver_data },
/* ION */
{ PCI_VDEVICE(NVIDIA, 0x0876), (kernel_ulong_t)&nv5x_driver_data },
/* Quadro FX 470 */
{ PCI_VDEVICE(NVIDIA, 0x087a), (kernel_ulong_t)&nv5x_driver_data },
/* ION */
{ PCI_VDEVICE(NVIDIA, 0x087d), (kernel_ulong_t)&nv5x_driver_data },
/* ION LE */
{ PCI_VDEVICE(NVIDIA, 0x087e), (kernel_ulong_t)&nv5x_driver_data },
/* ION LE */
{ PCI_VDEVICE(NVIDIA, 0x087f), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce 320M */
{ PCI_VDEVICE(NVIDIA, 0x08a0), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce GT 230M */
{ PCI_VDEVICE(NVIDIA, 0x0a28), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce GT 330M */
{ PCI_VDEVICE(NVIDIA, 0x0a29), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce GT 230M */
{ PCI_VDEVICE(NVIDIA, 0x0a2a), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce GT 330M */
{ PCI_VDEVICE(NVIDIA, 0x0a2b), (kernel_ulong_t)&nv5x_driver_data },
/* NVS 5100M */
{ PCI_VDEVICE(NVIDIA, 0x0a2c), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce GT 320M */
{ PCI_VDEVICE(NVIDIA, 0x0a2d), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce GT 240M */
{ PCI_VDEVICE(NVIDIA, 0x0a34), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce GT 325M */
{ PCI_VDEVICE(NVIDIA, 0x0a35), (kernel_ulong_t)&nv5x_driver_data },
/* Quadro FX 880M */
{ PCI_VDEVICE(NVIDIA, 0x0a3c), (kernel_ulong_t)&nv5x_driver_data },
/* ION */
{ PCI_VDEVICE(NVIDIA, 0x0a64), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce G 105M */
{ PCI_VDEVICE(NVIDIA, 0x0a68), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce G 105M */
{ PCI_VDEVICE(NVIDIA, 0x0a69), (kernel_ulong_t)&nv5x_driver_data },
/* NVS 2100M */
{ PCI_VDEVICE(NVIDIA, 0x0a6a), (kernel_ulong_t)&nv5x_driver_data },
/* NVS 3100M */
{ PCI_VDEVICE(NVIDIA, 0x0a6c), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce 305M */
{ PCI_VDEVICE(NVIDIA, 0x0a6e), (kernel_ulong_t)&nv5x_driver_data },
/* ION */
{ PCI_VDEVICE(NVIDIA, 0x0a6f), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce 310M */
{ PCI_VDEVICE(NVIDIA, 0x0a70), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce 305M */
{ PCI_VDEVICE(NVIDIA, 0x0a71), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce 310M */
{ PCI_VDEVICE(NVIDIA, 0x0a72), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce 305M */
{ PCI_VDEVICE(NVIDIA, 0x0a73), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce G 210M */
{ PCI_VDEVICE(NVIDIA, 0x0a74), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce 310M */
{ PCI_VDEVICE(NVIDIA, 0x0a75), (kernel_ulong_t)&nv5x_driver_data },
/* Quadro FX 380M */
{ PCI_VDEVICE(NVIDIA, 0x0a7c), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce GTS 260M */
{ PCI_VDEVICE(NVIDIA, 0x0ca8), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce GTS 250M */
{ PCI_VDEVICE(NVIDIA, 0x0ca9), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce GT 335M */
{ PCI_VDEVICE(NVIDIA, 0x0caf), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce GTS 350M */
{ PCI_VDEVICE(NVIDIA, 0x0cb0), (kernel_ulong_t)&nv5x_driver_data },
/* Geforce GTS 360M */
{ PCI_VDEVICE(NVIDIA, 0x0cb1), (kernel_ulong_t)&nv5x_driver_data },
/* Quadro FX 1800M */
{ PCI_VDEVICE(NVIDIA, 0x0cbc), (kernel_ulong_t)&nv5x_driver_data },
/* end of list */
{ }
};
#ifdef CONFIG_NVIDIA_BL_CHECK_SUBSYSTEM_VENDOR
/*
* Supported subsystem vendors.
* Defined separately to not unnecessarily enlarge the previous array.
*/
static const unsigned nvidia_bl_subvendors[] __initdata = {
PCI_VENDOR_ID_APPLE,
PCI_VENDOR_ID_HP,
PCI_VENDOR_ID_SAMSUNG,
PCI_VENDOR_ID_SONY,
PCI_VENDOR_ID_TOSHIBA,
PCI_VENDOR_ID_DELL,
0x1a46, /* PCI_VENDOR_ID_ZEPTO not defined */
};
#endif
/*
* Machine specific quirks used below.
*/
static const struct machine_quirks apple_quirks __initdata = {
.dev_id = PCI_ANY_ID,
.max_level = 1023
};
static const struct machine_quirks apple_quirks_320m __initdata = {
.dev_id = PCI_ANY_ID,
.max_level = 44000
};
static const struct machine_quirks sony_vpccw27fx_quirks __initdata = {
.dev_id = PCI_ANY_ID,
.max_level = 127000 /* might be wrong. maybe also 0x1ffff */
};
static const struct machine_quirks max_level_0x1ffff __initdata = {
.dev_id = PCI_ANY_ID,
.max_level = 0x1ffff
};
/*
* DMI matching.
*/
static const struct dmi_system_id *nvidia_bl_dmi_system_id;
static int nvidia_bl_dmi_match(const struct dmi_system_id *id)
{
printk(KERN_INFO "nvidia_bl: %s detected\n", id->ident);
nvidia_bl_dmi_system_id = id;
return 1;
}
static const struct dmi_system_id nvidia_bl_machine_table[] __initdata = {
/*
* Apple machines: Intel chipset, Nvidia graphics
*/
{
.callback = &nvidia_bl_dmi_match,
.ident = "MacBookPro 3,1",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro3,1"),
},
.driver_data = (void *)&apple_quirks,
},
{
.callback = &nvidia_bl_dmi_match,
.ident = "MacBookPro 3,2",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro3,2"),
},
.driver_data = (void *)&apple_quirks,
},
{
.callback = &nvidia_bl_dmi_match,
.ident = "MacBookPro 4,1",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro4,1"),
},
.driver_data = (void *)&apple_quirks,
},
/*
* Apple machines: Nvidia chipset, Nvidia graphics
*/
{
.callback = &nvidia_bl_dmi_match,
.ident = "MacBook 5,1",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "MacBook5,1"),
},
.driver_data = (void *)&apple_quirks,
},
{
.callback = &nvidia_bl_dmi_match,
.ident = "MacBook 5,2",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "MacBook5,2"),
},
.driver_data = (void *)&apple_quirks,
},
{
.callback = &nvidia_bl_dmi_match,
.ident = "MacBookAir 2,1",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir2,1"),
},
.driver_data = (void *)&apple_quirks,
},
{
.callback = &nvidia_bl_dmi_match,
.ident = "MacBookPro 5,1",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,1"),
},
.driver_data = (void *)&apple_quirks,
},
{
.callback = &nvidia_bl_dmi_match,
.ident = "MacBookPro 5,2",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,2"),
},
.driver_data = (void *)&apple_quirks,
},
{
.callback = &nvidia_bl_dmi_match,
.ident = "MacBookPro 5,3",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,3"),
},
.driver_data = (void *)&apple_quirks,
},
{
.callback = &nvidia_bl_dmi_match,
.ident = "MacBookPro 5,4",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,4"),
},
.driver_data = (void *)&apple_quirks,
},
{
.callback = &nvidia_bl_dmi_match,
.ident = "MacBookPro 5,5",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,5"),
},
.driver_data = (void *)&apple_quirks,
},
{
.callback = &nvidia_bl_dmi_match,
.ident = "MacBook 6,1",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "MacBook6,1"),
},
.driver_data = (void *)&apple_quirks,
},
{
.callback = &nvidia_bl_dmi_match,
.ident = "MacBook 7,1",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "MacBook7,1"),
},
.driver_data = (void *)&apple_quirks_320m,
},
{
.callback = &nvidia_bl_dmi_match,
.ident = "MacBookPro 7,1",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro7,1"),
},
.driver_data = (void *)&apple_quirks_320m,
},
/*
* Sony machines: Nvidia graphics
*/
{
.callback = &nvidia_bl_dmi_match,
.ident = "Sony VGN-AW11",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
DMI_MATCH(DMI_PRODUCT_NAME, "VGN-AW11"),
},
.driver_data = NULL, /* defaults */
},
{
.callback = &nvidia_bl_dmi_match,
.ident = "Sony VGN-FZ38M",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FZ38M"),
},
.driver_data = NULL, /* defaults */
},
{
.callback = &nvidia_bl_dmi_match,
.ident = "Sony VGN-FZ11E",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FZ11E"),
},
.driver_data = NULL, /* defaults */
},
{
.callback = &nvidia_bl_dmi_match,
.ident = "Sony VPCCW27FX",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
DMI_MATCH(DMI_PRODUCT_NAME, "VPCCW27FX"),
},
.driver_data = (void *)&sony_vpccw27fx_quirks,
},
/*
* Dell machines: Nvidia graphics
*/
{
.callback = &nvidia_bl_dmi_match,
.ident = "Dell Inspiron 1370",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1370"),
},
.driver_data = NULL, /* defaults */
},
{
.callback = &nvidia_bl_dmi_match,
.ident = "Dell Vostro 3500",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 3500"),
},
.driver_data = (void *)&max_level_0x1ffff,
},
/*
* Toshiba machines: Nvidia graphics
*/
{
.callback = &nvidia_bl_dmi_match,
.ident = "Toshiba Satellite Pro U500",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
DMI_MATCH(DMI_PRODUCT_NAME, "SATELLITE PRO U500"),
},
.driver_data = (void *)&max_level_0x1ffff,
},
/* end of list */
{ }
};
/*
* Driver data implementation
*/
static unsigned nvidia_bl_max_level_to_mask(unsigned max_level)
{
int i;
for (i = sizeof(unsigned) * 8 - 1; i >= 0; i--) {
const unsigned bit = 1 << i;
if (max_level & bit)
return (bit << 1) - 1;
}
return (unsigned)-1;
}
/* missing annotation __devinitconst */
static const struct pci_device_id *nvidia_bl_match_id(struct pci_dev *dev)
{
/* Search id in table */
const struct pci_device_id *id =
pci_match_id(nvidia_bl_device_table, dev);
#ifdef CONFIG_NVIDIA_BL_CHECK_SUBSYSTEM_VENDOR
int i;
if (id)
/* ... and check subsystem vendor */
for (i = 0; i < ARRAY_SIZE(nvidia_bl_subvendors); i++)
if (dev->subsystem_vendor == nvidia_bl_subvendors[i])
return id;
return NULL;
#else
return id;
#endif
}
/* missing annotation __devinitconst */
static int nvidia_bl_find_device(struct driver_data *dd)
{
const struct pci_device_id *id = NULL;
struct pci_dev *dev = NULL;
/* For each PCI device */
while ((dev = pci_get_device(PCI_VENDOR_ID_NVIDIA, dev_id, dev))) {
/* ... Lookup id struct */
if ((id = nvidia_bl_match_id(dev))) {
dev_id = id->device;
printk(KERN_INFO "nvidia_bl: Nvidia graphics adapter"
" %04x:%04x (%04x:%04x) detected\n",
id->vendor, id->device,
dev->subsystem_vendor, dev->subsystem_device);
/* Setup driver data */
*dd = *((struct driver_data *)id->driver_data);
dd->dev = dev;
return 0;
}
/* Load if forced unless not a graphics adapter */
else if (force && (dev->class == PCI_CLASS_DISPLAY_VGA << 8)) {
dev_id = id->device;
printk(KERN_INFO "nvidia_bl: Nvidia graphics adapter"
" %04x:%04x (%04x:%04x) forced\n",
id->vendor, id->device,
dev->subsystem_vendor, dev->subsystem_device);
/* Setup driver data (assume NV5X generation) */
*dd = nv5x_driver_data;
dd->dev = dev;
return 0;
}
}
/* Nothing found */
if (dev_id != PCI_ANY_ID)
printk(KERN_INFO "nvidia_bl: No Nvidia graphics adapter"
" with IDs %04x:%04x found\n",
PCI_VENDOR_ID_NVIDIA, dev_id);
else
printk(KERN_INFO "nvidia_bl: No supported Nvidia graphics"
" adapter found\n");
return -ENODEV;
}
static int nvidia_bl_map_smartdimmer(struct driver_data *dd)
{
/* Get resource properties */
const unsigned long bar_start = pci_resource_start(dd->dev, dd->bar),
bar_end = pci_resource_end(dd->dev, dd->bar),
bar_flags = pci_resource_flags(dd->dev, dd->bar);
/* Calculate register address */
const unsigned long reg_addr = bar_start + dd->reg_offset;
/* Sanity check 1: Should be a memory region containing registers */
if (!(bar_flags & IORESOURCE_MEM))
return -ENODEV;
if (bar_flags & IORESOURCE_PREFETCH)
return -ENODEV;
/* Sanity check 2: Address should not exceed the PCI BAR */
if (reg_addr + dd->reg_size - 1 > bar_end)
return -ENODEV;
if (unlikely(debug))
printk(KERN_DEBUG "nvidia_bl: using BAR #%d at 0x%lx, "
"smartdimmer at 0x%lx\n", dd->bar, bar_start, reg_addr);
/* Now really map (The address need not be page-aligned.) */
dd->smartdimmer = ioremap_nocache(reg_addr, dd->reg_size);
if (!dd->smartdimmer)
return -ENXIO;
return 0;
}
static void nvidia_bl_unmap_smartdimmer(struct driver_data *dd)
{
iounmap(dd->smartdimmer);
}
/*
* Backlight framework implementation.
*/
static int nvidia_bl_get_intensity(struct backlight_device *bd)
{
const struct driver_data *dd = bl_get_data(bd);
unsigned intensity = dd->ops.get_intensity(dd);
intensity >>= shift;
if (unlikely(debug))
printk(KERN_DEBUG "nvidia_bl: read brightness of %d\n",
intensity);
return intensity;
}
static int nvidia_bl_set_intensity(struct backlight_device *bd)
{
struct driver_data *dd = bl_get_data(bd);
unsigned intensity = bd->props.brightness;
#ifdef HAVE_BACKLIGHT_PROPS_STATE
if (bd->props.state & BL_CORE_FBBLANK)
intensity = 0;
else if (bd->props.state & BL_CORE_SUSPENDED)
intensity = 0;
#endif
if (unlikely(debug))
printk(KERN_DEBUG "nvidia_bl: setting brightness to %d\n",
intensity);
intensity <<= shift;
return dd->ops.set_intensity(dd, intensity);
}
static const struct backlight_ops nvidia_bl_backlight_ops = {
#ifdef USE_BACKLIGHT_SUSPEND
.options = BL_CORE_SUSPENDRESUME,
#endif
.get_brightness = &nvidia_bl_get_intensity,
.update_status = &nvidia_bl_set_intensity,
};
/*
* Driver implementation
*/
static struct driver_data driver_data;
static struct backlight_device *nvidia_bl_device;
#ifdef USE_PLATFORM_DRIVER
static int nvidia_bl_probe(struct platform_device *pdev)
#else
static int __init nvidia_bl_init(void)
#endif
{
#ifdef INIT_BACKLIGHT_PROPS
struct backlight_properties props;
#endif
int err;
/* Bail-out if PCI subsystem is not initialized */
if (no_pci_devices())
return -ENODEV;
/* Check DMI */
dmi_check_system(nvidia_bl_machine_table);
/*
* Use the machine quirks from the machine table if present and not
* overridden by parameter
*/
if (nvidia_bl_dmi_system_id) {
const struct machine_quirks *quirks =
nvidia_bl_dmi_system_id->driver_data;
if (quirks) {
if (dev_id == PCI_ANY_ID)
dev_id = quirks->dev_id;
if (max_level == 0)
max_level = quirks->max_level;
}
}
/* Look for a supported PCI device */
err = nvidia_bl_find_device(&driver_data);
if (err)
return err;
/* Map smartdimmer */
err = nvidia_bl_map_smartdimmer(&driver_data);
if (err)
return err;
#ifdef INIT_BACKLIGHT_PROPS
/* Use a dummy here. Will be initialized later. */
memset(&props, 0, sizeof(struct backlight_properties));
/* Register at backlight framework */
nvidia_bl_device = backlight_device_register("nvidia_backlight", NULL,
&driver_data,
&nvidia_bl_backlight_ops,
&props);
#else
/* Register at backlight framework */
nvidia_bl_device = backlight_device_register("nvidia_backlight", NULL,
&driver_data,
&nvidia_bl_backlight_ops);
#endif
if (IS_ERR(nvidia_bl_device)) {
nvidia_bl_unmap_smartdimmer(&driver_data);
return PTR_ERR(nvidia_bl_device);
}
/* Use the max_level parameter only if it is in reasonable range */
if (max_level > 0)
driver_data.max_level = max_level;
else
max_level = driver_data.max_level;
/* Compute the register mask */
driver_data.reg_mask =
nvidia_bl_max_level_to_mask(driver_data.max_level);
/* Set up backlight device */
nvidia_bl_device->props.brightness =
nvidia_bl_device->props.max_brightness = driver_data.max_level >> shift;
/* dump initial state if in debugging mode */
if (unlikely(debug)) {
printk(KERN_DEBUG "nvidia_bl: register mask: 0x%08x\n",
driver_data.reg_mask);
nvidia_bl_device->ops->get_brightness(nvidia_bl_device);
}
/*
* MacBook Pro 5: Hardware might report the wrong value (maximum),
* so make sure it is right by resetting the brightness here.
*/
backlight_update_status(nvidia_bl_device);
return 0;
}
#ifdef USE_PLATFORM_DRIVER
static int nvidia_bl_remove(struct platform_device *pdev)
#else
static void __exit nvidia_bl_exit(void)
#endif
{
/* Unregister at backlight framework */
if (nvidia_bl_device)
backlight_device_unregister(nvidia_bl_device);
/* Unmap smartdimmer */
if (driver_data.smartdimmer)
nvidia_bl_unmap_smartdimmer(&driver_data);
/* Release PCI device */
if (driver_data.dev)
pci_dev_put(driver_data.dev);
#ifdef USE_PLATFORM_DRIVER
return 0;
#endif
}
#ifdef USE_PLATFORM_DRIVER
/*
* Platform driver implementation
*/
static int nvidia_bl_resume(struct platform_device *pdev)
{
if (unlikely(debug))
printk(KERN_DEBUG "nvidia_bl: resuming with"
" brightness %d\n", nvidia_bl_device->props.brightness);
backlight_update_status(nvidia_bl_device);
return 0;
}
static struct platform_driver nvidia_bl_driver = {
.probe = nvidia_bl_probe,
.remove = nvidia_bl_remove,
.resume = nvidia_bl_resume,
.driver = {
.owner = THIS_MODULE,
.name = "nvidia_bl"
},
};
static struct platform_device *nvidia_bl_platform_device;
static int __init nvidia_bl_init(void)
{
int err;
err = platform_driver_register(&nvidia_bl_driver);
if (err)
return err;
nvidia_bl_platform_device =
platform_device_register_simple("nvidia_bl", -1, NULL, 0);
if (!nvidia_bl_platform_device) {
platform_driver_unregister(&nvidia_bl_driver);
return -ENOMEM;
}
return 0;
}
static void __exit nvidia_bl_exit(void)
{
platform_device_unregister(nvidia_bl_platform_device);
platform_driver_unregister(&nvidia_bl_driver);
}
#endif /* USE_PLATFORM_DRIVER */
module_init(nvidia_bl_init);
module_exit(nvidia_bl_exit);
MODULE_AUTHOR("Mario Schwalbe <schwalbe@inf.tu-dresden.de>");
MODULE_DESCRIPTION("Nvidia-based graphics adapter display backlight driver");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(dmi, nvidia_bl_machine_table);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment