Mageia Bugzilla – Attachment 2093 Details for
Bug 5570
apple_bl module does not support Macbook Pro 8,2 laptops
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
Log In
[x]
|
New Account
|
Forgot Password
Alternate apple_bl.c file
apple_bl.c (text/x-csrc), 9.20 KB, created by
Andy Liebman
on 2012-04-24 15:57:18 CEST
(
hide
)
Description:
Alternate apple_bl.c file
Filename:
MIME Type:
Creator:
Andy Liebman
Created:
2012-04-24 15:57:18 CEST
Size:
9.20 KB
patch
obsolete
>/* > * Backlight Driver for Intel-based Apples > * > * Copyright (c) Red Hat <mjg@redhat.com> > * Based on code from Pommed: > * Copyright (C) 2006 Nicolas Boichat <nicolas @boichat.ch> > * Copyright (C) 2006 Felipe Alfaro Solana <felipe_alfaro @linuxmail.org> > * Copyright (C) 2007 Julien BLACHE <jb@jblache.org> > * > * This program is free software; you can redistribute it and/or modify > * it under the terms of the GNU General Public License version 2 as > * published by the Free Software Foundation. > * > * This driver triggers SMIs which cause the firmware to change the > * backlight brightness. This is icky in many ways, but it's impractical to > * get at the firmware code in order to figure out what it's actually doing. > */ > >#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt > >#include <linux/module.h> >#include <linux/kernel.h> >#include <linux/init.h> >#include <linux/backlight.h> >#include <linux/err.h> >#include <linux/io.h> >#include <linux/pci.h> >#include <linux/acpi.h> > >#define APPLE_BL_ID "APP0002" >#define APPLE_GMUX_ID "APP000B" > >struct apple_bl_data { > const char *name; > int max_brightness; > > /* I/O resource to allocate. */ > unsigned long iostart; > unsigned long iolen; > > /* Backlight device */ > struct backlight_device *bdev; > > /* Backlight operations structure. */ > int (*get_brightness)(struct apple_bl_data *); > void (*set_brightness)(struct apple_bl_data *, int); >}; > >/* > * gmux port offsets. Many of these are not yet used, but may be in the > * future, and it's useful to have them documented here anyhow. > */ >#define GMUX_PORT_VERSION_MAJOR 0x04 >#define GMUX_PORT_VERSION_MINOR 0x05 >#define GMUX_PORT_VERSION_RELEASE 0x06 >#define GMUX_PORT_SWITCH_DISPLAY 0x10 >#define GMUX_PORT_SWITCH_GET_DISPLAY 0x11 >#define GMUX_PORT_INTERRUPT_ENABLE 0x14 >#define GMUX_PORT_INTERRUPT_STATUS 0x16 >#define GMUX_PORT_SWITCH_DDC 0x28 >#define GMUX_PORT_SWITCH_EXTERNAL 0x40 >#define GMUX_PORT_SWITCH_GET_EXTERNAL 0x41 >#define GMUX_PORT_DISCRETE_POWER 0x50 >#define GMUX_PORT_MAX_BRIGHTNESS 0x70 >#define GMUX_PORT_BRIGHTNESS 0x74 > >#define GMUX_MIN_IO_LEN (GMUX_PORT_BRIGHTNESS + 4) > >#define GMUX_INTERRUPT_ENABLE 0xff >#define GMUX_INTERRUPT_DISABLE 0x00 > >#define GMUX_INTERRUPT_STATUS_ACTIVE 0 >#define GMUX_INTERRUPT_STATUS_DISPLAY (1 << 0) >#define GMUX_INTERRUPT_STATUS_POWER (1 << 2) >#define GMUX_INTERRUPT_STATUS_HOTPLUG (1 << 3) > >#define GMUX_BRIGHTNESS_MASK 0x00ffffff >#define GMUX_MAX_BRIGHTNESS GMUX_BRIGHTNESS_MASK > >/* > * Implementation for machines with Intel chipset. > */ >static void intel_chipset_set_brightness(struct apple_bl_data *bl_data, > int intensity) >{ > outb(0x04 | (intensity << 4), 0xb3); > outb(0xbf, 0xb2); >} > >static int intel_chipset_get_brightness(struct apple_bl_data *bl_data) >{ > int intensity; > > outb(0x03, 0xb3); > outb(0xbf, 0xb2); > intensity = inb(0xb3) >> 4; > > pr_debug("read brightness of %d\n", intensity); > > return intensity; >} > >/* > * Implementation for machines with Nvidia chipset. > */ >static void nvidia_chipset_set_brightness(struct apple_bl_data *bl_data, > int intensity) >{ > outb(0x04 | (intensity << 4), 0x52f); > outb(0xbf, 0x52e); >} > >static int nvidia_chipset_get_brightness(struct apple_bl_data *bl_data) >{ > int intensity; > > outb(0x03, 0x52f); > outb(0xbf, 0x52e); > intensity = inb(0x52f) >> 4; > > pr_debug("read brightness of %d\n", intensity); > > return intensity; >} > >/* > * Implementation for gmux backlight control > */ >static void gmux_set_brightness(struct apple_bl_data *bl_data, int intensity) >{ > /* > * Older versions of gmux require writing out lower bytes first > * then setting upper byte to 0 to flush values. Newer versions > * accept a single u32 write, but the old method works as well > * so just use it for everything. > */ > outb(intensity, bl_data->iostart + GMUX_PORT_BRIGHTNESS); > outb(intensity >> 8, bl_data->iostart + GMUX_PORT_BRIGHTNESS + 1); > outb(intensity >> 16, bl_data->iostart + GMUX_PORT_BRIGHTNESS + 2); > outb(0, bl_data->iostart + GMUX_PORT_BRIGHTNESS + 3); >} > >static int gmux_get_brightness(struct apple_bl_data *bl_data) >{ > return inl(bl_data->iostart + GMUX_PORT_BRIGHTNESS) & GMUX_BRIGHTNESS_MASK; >} > >/* > * Backlight device class operations > */ >static int apple_bl_get_brightness(struct backlight_device *bd) >{ > struct apple_bl_data *bl_data = bl_get_data(bd); > return bl_data->get_brightness(bl_data); >} > >static int apple_bl_update_status(struct backlight_device *bd) >{ > struct apple_bl_data *bl_data = bl_get_data(bd); > > bl_data->set_brightness(bl_data, bd->props.brightness); > return 0; >} > >static const struct backlight_ops apple_bl_ops = { > .get_brightness = apple_bl_get_brightness, > .update_status = apple_bl_update_status, >}; > >static int __devinit legacy_bl_init(struct apple_bl_data *bl_data, > struct acpi_device *dev) >{ > struct pci_dev *host; > unsigned short vendor; > > host = pci_get_bus_and_slot(0, 0); > if (!host) { > pr_err("unable to find PCI host\n"); > return -ENODEV; > } > > vendor = host->vendor; > pci_dev_put(host); > > switch (host->vendor) { > case PCI_VENDOR_ID_INTEL: > bl_data->iostart = 0xb2; > bl_data->iolen = 2; > bl_data->get_brightness = intel_chipset_get_brightness; > bl_data->set_brightness = intel_chipset_set_brightness; > break; > case PCI_VENDOR_ID_NVIDIA: > bl_data->iostart = 0x52e; > bl_data->iolen = 2; > bl_data->get_brightness = nvidia_chipset_get_brightness; > bl_data->set_brightness = nvidia_chipset_set_brightness; > break; > default: > pr_err("no backlight support for PCI vendor %hu\n", host->vendor); > return -ENODEV; > } > > bl_data->name = "apple_backlight"; > bl_data->max_brightness = 15; > return 0; >} > >static acpi_status __devinit gmux_get_resources(struct acpi_resource *res, > void *context) >{ > struct apple_bl_data *bl_data = context; > struct acpi_resource_io *io; > > if (res->type == ACPI_RESOURCE_TYPE_IO) { > io = &res->data.io; > bl_data->iostart = io->minimum; > bl_data->iolen = io->maximum - io->minimum; > > return AE_CTRL_TERMINATE; > } > > return AE_OK; >} > >static int __devinit gmux_init(struct apple_bl_data *bl_data, > struct acpi_device *dev) >{ > acpi_status status; > > status = acpi_walk_resources(dev->handle, METHOD_NAME__CRS, > gmux_get_resources, bl_data); > if (ACPI_FAILURE(status)) > return -ENXIO; > > if (!bl_data->iostart) { > pr_err("Failed to find gmux I/O resources\n"); > return -ENXIO; > } > > if (bl_data->iolen < GMUX_MIN_IO_LEN) { > pr_err("gmux I/O region too small (%lu < %u)\n", > bl_data->iolen, GMUX_MIN_IO_LEN); > return -ENXIO; > } > > bl_data->name = "gmux_backlight"; > bl_data->get_brightness = gmux_get_brightness; > bl_data->set_brightness = gmux_set_brightness; > bl_data->max_brightness = > inl(bl_data->iostart + GMUX_PORT_MAX_BRIGHTNESS); > > /* > * Currently it's assumed that the maximum brightness is less > * than 2^24 for compatibility with old gmux versions. Cap the > * max brightness at this max value, but print a warning if > * the hardware reports something higher so it can be fixed. > */ > if (WARN_ON(bl_data->max_brightness > GMUX_MAX_BRIGHTNESS)) > bl_data->max_brightness = GMUX_MAX_BRIGHTNESS; > > return 0; >} > >static int __devinit apple_bl_add(struct acpi_device *dev) >{ > struct apple_bl_data *bl_data; > struct backlight_properties props; > struct backlight_device *bdev; > int intensity; > int ret = -ENODEV; > > bl_data = kzalloc(sizeof(*bl_data), GFP_KERNEL); > if (!bl_data) > return -ENOMEM; > dev->driver_data = bl_data; > > if (!strcmp(acpi_device_hid(dev), APPLE_GMUX_ID)) > ret = gmux_init(bl_data, dev); > else > ret = legacy_bl_init(bl_data, dev); > > if (ret) > goto err_free; > > /* Check that the hardware responds - this may not work under EFI */ > > intensity = bl_data->get_brightness(bl_data); > > if (!intensity) { > bl_data->set_brightness(bl_data, 1); > if (!bl_data->get_brightness(bl_data)) { > ret = -ENODEV; > goto err_free; > } > > bl_data->set_brightness(bl_data, 0); > } > > if (!request_region(bl_data->iostart, bl_data->iolen, > "Apple backlight")) { > ret = -ENXIO; > goto err_free; > } > > memset(&props, 0, sizeof(struct backlight_properties)); > props.type = BACKLIGHT_PLATFORM; > props.max_brightness = bl_data->max_brightness; > bdev = backlight_device_register(bl_data->name, &dev->dev, bl_data, > &apple_bl_ops, &props); > > if (IS_ERR(bdev)) { > ret = PTR_ERR(bdev); > goto err_release; > } > > bl_data->bdev = bdev; > bdev->props.brightness = intensity; > backlight_update_status(bdev); > > return 0; > >err_release: > release_region(bl_data->iostart, bl_data->iolen); >err_free: > kfree(bl_data); > return ret; >} > >static int __devexit apple_bl_remove(struct acpi_device *dev, int type) >{ > struct apple_bl_data *bl_data = dev->driver_data; > > backlight_device_unregister(bl_data->bdev); > release_region(bl_data->iostart, bl_data->iolen); > kfree(bl_data); > > return 0; >} > >static const struct acpi_device_id apple_bl_ids[] = { > {APPLE_BL_ID, 0}, > {APPLE_GMUX_ID, 0}, > {"", 0}, >}; > >static struct acpi_driver apple_bl_driver = { > .name = "Apple backlight", > .ids = apple_bl_ids, > .ops = { > .add = apple_bl_add, > .remove = __devexit_p(apple_bl_remove), > }, >}; > >static int __init apple_bl_init(void) >{ > return acpi_bus_register_driver(&apple_bl_driver); >} > >static void __exit apple_bl_exit(void) >{ > acpi_bus_unregister_driver(&apple_bl_driver); >} > >module_init(apple_bl_init); >module_exit(apple_bl_exit); > >MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>"); >MODULE_DESCRIPTION("Apple Backlight Driver"); >MODULE_LICENSE("GPL"); >MODULE_DEVICE_TABLE(acpi, apple_bl_ids); >MODULE_ALIAS("mbp_nvidia_bl");
/* * Backlight Driver for Intel-based Apples * * Copyright (c) Red Hat <mjg@redhat.com> * Based on code from Pommed: * Copyright (C) 2006 Nicolas Boichat <nicolas @boichat.ch> * Copyright (C) 2006 Felipe Alfaro Solana <felipe_alfaro @linuxmail.org> * Copyright (C) 2007 Julien BLACHE <jb@jblache.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This driver triggers SMIs which cause the firmware to change the * backlight brightness. This is icky in many ways, but it's impractical to * get at the firmware code in order to figure out what it's actually doing. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/backlight.h> #include <linux/err.h> #include <linux/io.h> #include <linux/pci.h> #include <linux/acpi.h> #define APPLE_BL_ID "APP0002" #define APPLE_GMUX_ID "APP000B" struct apple_bl_data { const char *name; int max_brightness; /* I/O resource to allocate. */ unsigned long iostart; unsigned long iolen; /* Backlight device */ struct backlight_device *bdev; /* Backlight operations structure. */ int (*get_brightness)(struct apple_bl_data *); void (*set_brightness)(struct apple_bl_data *, int); }; /* * gmux port offsets. Many of these are not yet used, but may be in the * future, and it's useful to have them documented here anyhow. */ #define GMUX_PORT_VERSION_MAJOR 0x04 #define GMUX_PORT_VERSION_MINOR 0x05 #define GMUX_PORT_VERSION_RELEASE 0x06 #define GMUX_PORT_SWITCH_DISPLAY 0x10 #define GMUX_PORT_SWITCH_GET_DISPLAY 0x11 #define GMUX_PORT_INTERRUPT_ENABLE 0x14 #define GMUX_PORT_INTERRUPT_STATUS 0x16 #define GMUX_PORT_SWITCH_DDC 0x28 #define GMUX_PORT_SWITCH_EXTERNAL 0x40 #define GMUX_PORT_SWITCH_GET_EXTERNAL 0x41 #define GMUX_PORT_DISCRETE_POWER 0x50 #define GMUX_PORT_MAX_BRIGHTNESS 0x70 #define GMUX_PORT_BRIGHTNESS 0x74 #define GMUX_MIN_IO_LEN (GMUX_PORT_BRIGHTNESS + 4) #define GMUX_INTERRUPT_ENABLE 0xff #define GMUX_INTERRUPT_DISABLE 0x00 #define GMUX_INTERRUPT_STATUS_ACTIVE 0 #define GMUX_INTERRUPT_STATUS_DISPLAY (1 << 0) #define GMUX_INTERRUPT_STATUS_POWER (1 << 2) #define GMUX_INTERRUPT_STATUS_HOTPLUG (1 << 3) #define GMUX_BRIGHTNESS_MASK 0x00ffffff #define GMUX_MAX_BRIGHTNESS GMUX_BRIGHTNESS_MASK /* * Implementation for machines with Intel chipset. */ static void intel_chipset_set_brightness(struct apple_bl_data *bl_data, int intensity) { outb(0x04 | (intensity << 4), 0xb3); outb(0xbf, 0xb2); } static int intel_chipset_get_brightness(struct apple_bl_data *bl_data) { int intensity; outb(0x03, 0xb3); outb(0xbf, 0xb2); intensity = inb(0xb3) >> 4; pr_debug("read brightness of %d\n", intensity); return intensity; } /* * Implementation for machines with Nvidia chipset. */ static void nvidia_chipset_set_brightness(struct apple_bl_data *bl_data, int intensity) { outb(0x04 | (intensity << 4), 0x52f); outb(0xbf, 0x52e); } static int nvidia_chipset_get_brightness(struct apple_bl_data *bl_data) { int intensity; outb(0x03, 0x52f); outb(0xbf, 0x52e); intensity = inb(0x52f) >> 4; pr_debug("read brightness of %d\n", intensity); return intensity; } /* * Implementation for gmux backlight control */ static void gmux_set_brightness(struct apple_bl_data *bl_data, int intensity) { /* * Older versions of gmux require writing out lower bytes first * then setting upper byte to 0 to flush values. Newer versions * accept a single u32 write, but the old method works as well * so just use it for everything. */ outb(intensity, bl_data->iostart + GMUX_PORT_BRIGHTNESS); outb(intensity >> 8, bl_data->iostart + GMUX_PORT_BRIGHTNESS + 1); outb(intensity >> 16, bl_data->iostart + GMUX_PORT_BRIGHTNESS + 2); outb(0, bl_data->iostart + GMUX_PORT_BRIGHTNESS + 3); } static int gmux_get_brightness(struct apple_bl_data *bl_data) { return inl(bl_data->iostart + GMUX_PORT_BRIGHTNESS) & GMUX_BRIGHTNESS_MASK; } /* * Backlight device class operations */ static int apple_bl_get_brightness(struct backlight_device *bd) { struct apple_bl_data *bl_data = bl_get_data(bd); return bl_data->get_brightness(bl_data); } static int apple_bl_update_status(struct backlight_device *bd) { struct apple_bl_data *bl_data = bl_get_data(bd); bl_data->set_brightness(bl_data, bd->props.brightness); return 0; } static const struct backlight_ops apple_bl_ops = { .get_brightness = apple_bl_get_brightness, .update_status = apple_bl_update_status, }; static int __devinit legacy_bl_init(struct apple_bl_data *bl_data, struct acpi_device *dev) { struct pci_dev *host; unsigned short vendor; host = pci_get_bus_and_slot(0, 0); if (!host) { pr_err("unable to find PCI host\n"); return -ENODEV; } vendor = host->vendor; pci_dev_put(host); switch (host->vendor) { case PCI_VENDOR_ID_INTEL: bl_data->iostart = 0xb2; bl_data->iolen = 2; bl_data->get_brightness = intel_chipset_get_brightness; bl_data->set_brightness = intel_chipset_set_brightness; break; case PCI_VENDOR_ID_NVIDIA: bl_data->iostart = 0x52e; bl_data->iolen = 2; bl_data->get_brightness = nvidia_chipset_get_brightness; bl_data->set_brightness = nvidia_chipset_set_brightness; break; default: pr_err("no backlight support for PCI vendor %hu\n", host->vendor); return -ENODEV; } bl_data->name = "apple_backlight"; bl_data->max_brightness = 15; return 0; } static acpi_status __devinit gmux_get_resources(struct acpi_resource *res, void *context) { struct apple_bl_data *bl_data = context; struct acpi_resource_io *io; if (res->type == ACPI_RESOURCE_TYPE_IO) { io = &res->data.io; bl_data->iostart = io->minimum; bl_data->iolen = io->maximum - io->minimum; return AE_CTRL_TERMINATE; } return AE_OK; } static int __devinit gmux_init(struct apple_bl_data *bl_data, struct acpi_device *dev) { acpi_status status; status = acpi_walk_resources(dev->handle, METHOD_NAME__CRS, gmux_get_resources, bl_data); if (ACPI_FAILURE(status)) return -ENXIO; if (!bl_data->iostart) { pr_err("Failed to find gmux I/O resources\n"); return -ENXIO; } if (bl_data->iolen < GMUX_MIN_IO_LEN) { pr_err("gmux I/O region too small (%lu < %u)\n", bl_data->iolen, GMUX_MIN_IO_LEN); return -ENXIO; } bl_data->name = "gmux_backlight"; bl_data->get_brightness = gmux_get_brightness; bl_data->set_brightness = gmux_set_brightness; bl_data->max_brightness = inl(bl_data->iostart + GMUX_PORT_MAX_BRIGHTNESS); /* * Currently it's assumed that the maximum brightness is less * than 2^24 for compatibility with old gmux versions. Cap the * max brightness at this max value, but print a warning if * the hardware reports something higher so it can be fixed. */ if (WARN_ON(bl_data->max_brightness > GMUX_MAX_BRIGHTNESS)) bl_data->max_brightness = GMUX_MAX_BRIGHTNESS; return 0; } static int __devinit apple_bl_add(struct acpi_device *dev) { struct apple_bl_data *bl_data; struct backlight_properties props; struct backlight_device *bdev; int intensity; int ret = -ENODEV; bl_data = kzalloc(sizeof(*bl_data), GFP_KERNEL); if (!bl_data) return -ENOMEM; dev->driver_data = bl_data; if (!strcmp(acpi_device_hid(dev), APPLE_GMUX_ID)) ret = gmux_init(bl_data, dev); else ret = legacy_bl_init(bl_data, dev); if (ret) goto err_free; /* Check that the hardware responds - this may not work under EFI */ intensity = bl_data->get_brightness(bl_data); if (!intensity) { bl_data->set_brightness(bl_data, 1); if (!bl_data->get_brightness(bl_data)) { ret = -ENODEV; goto err_free; } bl_data->set_brightness(bl_data, 0); } if (!request_region(bl_data->iostart, bl_data->iolen, "Apple backlight")) { ret = -ENXIO; goto err_free; } memset(&props, 0, sizeof(struct backlight_properties)); props.type = BACKLIGHT_PLATFORM; props.max_brightness = bl_data->max_brightness; bdev = backlight_device_register(bl_data->name, &dev->dev, bl_data, &apple_bl_ops, &props); if (IS_ERR(bdev)) { ret = PTR_ERR(bdev); goto err_release; } bl_data->bdev = bdev; bdev->props.brightness = intensity; backlight_update_status(bdev); return 0; err_release: release_region(bl_data->iostart, bl_data->iolen); err_free: kfree(bl_data); return ret; } static int __devexit apple_bl_remove(struct acpi_device *dev, int type) { struct apple_bl_data *bl_data = dev->driver_data; backlight_device_unregister(bl_data->bdev); release_region(bl_data->iostart, bl_data->iolen); kfree(bl_data); return 0; } static const struct acpi_device_id apple_bl_ids[] = { {APPLE_BL_ID, 0}, {APPLE_GMUX_ID, 0}, {"", 0}, }; static struct acpi_driver apple_bl_driver = { .name = "Apple backlight", .ids = apple_bl_ids, .ops = { .add = apple_bl_add, .remove = __devexit_p(apple_bl_remove), }, }; static int __init apple_bl_init(void) { return acpi_bus_register_driver(&apple_bl_driver); } static void __exit apple_bl_exit(void) { acpi_bus_unregister_driver(&apple_bl_driver); } module_init(apple_bl_init); module_exit(apple_bl_exit); MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>"); MODULE_DESCRIPTION("Apple Backlight Driver"); MODULE_LICENSE("GPL"); MODULE_DEVICE_TABLE(acpi, apple_bl_ids); MODULE_ALIAS("mbp_nvidia_bl");
View Attachment As Raw
Actions:
View
Attachments on
bug 5570
:
2079
|
2080
| 2093 |
2094
|
2095
|
2096
|
2097