Login
[x]
Log in using an account from:
Fedora Account System
Red Hat Associate
Red Hat Customer
Or login using a Red Hat Bugzilla account
Forgot Password
Login:
Hide Forgot
Create an Account
Red Hat Bugzilla – Attachment 627318 Details for
Bug 837461
VGASWITCHEROO not available for macbookpro
[?]
New
Simple Search
Advanced Search
My Links
Browse
Requests
Reports
Current State
Search
Tabular reports
Graphical reports
Duplicates
Other Reports
User Changes
Plotly Reports
Bug Status
Bug Severity
Non-Defaults
|
Product Dashboard
Help
Page Help!
Bug Writing Guidelines
What's new
Browser Support Policy
5.0.4.rh83 Release notes
FAQ
Guides index
User guide
Web Services
Contact
Legal
This site requires JavaScript to be enabled to function correctly, please enable it.
[patch]
Rejects from the patch
rejected.diff (text/plain), 25.00 KB, created by
William Brown
on 2012-10-15 11:21:15 UTC
(
hide
)
Description:
Rejects from the patch
Filename:
MIME Type:
Creator:
William Brown
Created:
2012-10-15 11:21:15 UTC
Size:
25.00 KB
patch
obsolete
>--- arch/x86/boot/compressed/eboot.c 2012-07-22 06:28:29.000000000 +0930 >+++ arch/x86/boot/compressed/eboot.c 2012-07-30 08:31:43.000000000 +0930 >@@ -851,32 +973,68 @@ > * need to create one ourselves (usually the bootloader would create > * one for us). > */ >-static efi_status_t make_boot_params(struct boot_params *boot_params, >- efi_loaded_image_t *image, >- void *handle) >+struct boot_params *make_boot_params(void *handle, efi_system_table_t *_table) > { >- struct efi_info *efi = &boot_params->efi_info; >- struct apm_bios_info *bi = &boot_params->apm_bios_info; >- struct sys_desc_table *sdt = &boot_params->sys_desc_table; >- struct e820entry *e820_map = &boot_params->e820_map[0]; >- struct e820entry *prev = NULL; >- struct setup_header *hdr = &boot_params->hdr; >- unsigned long size, key, desc_size, _size; >- efi_memory_desc_t *mem_map; >- void *options = image->load_options; >- u32 load_options_size = image->load_options_size / 2; /* ASCII */ >+ struct boot_params *boot_params; >+ struct sys_desc_table *sdt; >+ struct apm_bios_info *bi; >+ struct setup_header *hdr; >+ struct efi_info *efi; >+ efi_loaded_image_t *image; >+ void *options; >+ u32 load_options_size; >+ efi_guid_t proto = LOADED_IMAGE_PROTOCOL_GUID; > int options_size = 0; > efi_status_t status; >- __u32 desc_version; > unsigned long cmdline; >- u8 nr_entries; > u16 *s2; > u8 *s1; > int i; > >+ sys_table = _table; >+ >+ /* Check if we were booted by the EFI firmware */ >+ if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) >+ return NULL; >+ >+ status = efi_call_phys3(sys_table->boottime->handle_protocol, >+ handle, &proto, (void *)&image); >+ if (status != EFI_SUCCESS) { >+ efi_printk("Failed to get handle for LOADED_IMAGE_PROTOCOL\n"); >+ return NULL; >+ } >+ >+ status = low_alloc(0x4000, 1, (unsigned long *)&boot_params); >+ if (status != EFI_SUCCESS) { >+ efi_printk("Failed to alloc lowmem for boot params\n"); >+ return NULL; >+ } >+ >+ memset(boot_params, 0x0, 0x4000); >+ >+ hdr = &boot_params->hdr; >+ efi = &boot_params->efi_info; >+ bi = &boot_params->apm_bios_info; >+ sdt = &boot_params->sys_desc_table; >+ >+ /* Copy the second sector to boot_params */ >+ memcpy(&hdr->jump, image->image_base + 512, 512); >+ >+ /* >+ * Fill out some of the header fields ourselves because the >+ * EFI firmware loader doesn't load the first sector. >+ */ >+ hdr->root_flags = 1; >+ hdr->vid_mode = 0xffff; >+ hdr->boot_flag = 0xAA55; >+ >+ hdr->code32_start = (__u64)(unsigned long)image->image_base; >+ > hdr->type_of_loader = 0x21; > > /* Convert unicode cmdline to ascii */ >+ options = image->load_options; >+ load_options_size = image->load_options_size / 2; /* ASCII */ > cmdline = 0; > s2 = (u16 *)options; > >@@ -913,18 +1071,36 @@ > hdr->ramdisk_image = 0; > hdr->ramdisk_size = 0; > >- status = handle_ramdisks(image, hdr); >- if (status != EFI_SUCCESS) >- goto free_cmdline; >- >- setup_graphics(boot_params); >- > /* Clear APM BIOS info */ > memset(bi, 0, sizeof(*bi)); > > memset(sdt, 0, sizeof(*sdt)); > >- memcpy(&efi->efi_loader_signature, EFI_LOADER_SIGNATURE, sizeof(__u32)); >+ status = handle_ramdisks(image, hdr); >+ if (status != EFI_SUCCESS) >+ goto fail2; >+ >+ return boot_params; >+fail2: >+ if (options_size) >+ low_free(options_size, hdr->cmd_line_ptr); >+fail: >+ low_free(0x4000, (unsigned long)boot_params); >+ return NULL; >+} >+ >+static efi_status_t exit_boot(struct boot_params *boot_params, >+ void *handle) >+{ >+ struct efi_info *efi = &boot_params->efi_info; >+ struct e820entry *e820_map = &boot_params->e820_map[0]; >+ struct e820entry *prev = NULL; >+ unsigned long size, key, desc_size, _size; >+ efi_memory_desc_t *mem_map; >+ efi_status_t status; >+ __u32 desc_version; >+ u8 nr_entries; >+ int i; > > size = sizeof(*mem_map) * 32; > >@@ -933,7 +1109,7 @@ > _size = size; > status = low_alloc(size, 1, (unsigned long *)&mem_map); > if (status != EFI_SUCCESS) >- goto free_cmdline; >+ return status; > > status = efi_call_phys5(sys_table->boottime->get_memory_map, &size, > mem_map, &key, &desc_size, &desc_version); >@@ -945,6 +1121,7 @@ > if (status != EFI_SUCCESS) > goto free_mem_map; > >+ memcpy(&efi->efi_loader_signature, EFI_LOADER_SIGNATURE, sizeof(__u32)); > efi->efi_systab = (unsigned long)sys_table; > efi->efi_memdesc_size = desc_size; > efi->efi_memdesc_version = desc_version; >@@ -1028,61 +1205,13 @@ > > free_mem_map: > low_free(_size, (unsigned long)mem_map); >-free_cmdline: >- if (options_size) >- low_free(options_size, hdr->cmd_line_ptr); >-fail: > return status; > } > >-/* >- * On success we return a pointer to a boot_params structure, and NULL >- * on failure. >- */ >-struct boot_params *efi_main(void *handle, efi_system_table_t *_table) >+static efi_status_t relocate_kernel(struct setup_header *hdr) > { >- struct boot_params *boot_params; > unsigned long start, nr_pages; >- struct desc_ptr *gdt, *idt; >- efi_loaded_image_t *image; >- struct setup_header *hdr; > efi_status_t status; >- efi_guid_t proto = LOADED_IMAGE_PROTOCOL_GUID; >- struct desc_struct *desc; >- >- sys_table = _table; >- >- /* Check if we were booted by the EFI firmware */ >- if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) >- goto fail; >- >- status = efi_call_phys3(sys_table->boottime->handle_protocol, >- handle, &proto, (void *)&image); >- if (status != EFI_SUCCESS) { >- efi_printk("Failed to get handle for LOADED_IMAGE_PROTOCOL\n"); >- goto fail; >- } >- >- status = low_alloc(0x4000, 1, (unsigned long *)&boot_params); >- if (status != EFI_SUCCESS) { >- efi_printk("Failed to alloc lowmem for boot params\n"); >- goto fail; >- } >- >- memset(boot_params, 0x0, 0x4000); >- >- hdr = &boot_params->hdr; >- >- /* Copy the second sector to boot_params */ >- memcpy(&hdr->jump, image->image_base + 512, 512); >- >- /* >- * Fill out some of the header fields ourselves because the >- * EFI firmware loader doesn't load the first sector. >- */ >- hdr->root_flags = 1; >- hdr->vid_mode = 0xffff; >- hdr->boot_flag = 0xAA55; > > /* > * The EFI firmware loader could have placed the kernel image >@@ -1100,16 +1229,42 @@ > if (status != EFI_SUCCESS) { > status = low_alloc(hdr->init_size, hdr->kernel_alignment, > &start); >- if (status != EFI_SUCCESS) { >+ if (status != EFI_SUCCESS) > efi_printk("Failed to alloc mem for kernel\n"); >- goto fail; >- } > } > >+ if (status == EFI_SUCCESS) >+ memcpy((void *)start, (void *)(unsigned long)hdr->code32_start, >+ hdr->init_size); >+ >+ hdr->pref_address = hdr->code32_start; > hdr->code32_start = (__u32)start; >- hdr->pref_address = (__u64)(unsigned long)image->image_base; > >- memcpy((void *)start, image->image_base, image->image_size); >+ return status; >+} >+ >+/* >+ * On success we return a pointer to a boot_params structure, and NULL >+ * on failure. >+ */ >+struct boot_params *efi_main(void *handle, efi_system_table_t *_table, >+ struct boot_params *boot_params) >+{ >+ struct desc_ptr *gdt, *idt; >+ efi_loaded_image_t *image; >+ struct setup_header *hdr = &boot_params->hdr; >+ efi_status_t status; >+ struct desc_struct *desc; >+ >+ sys_table = _table; >+ >+ /* Check if we were booted by the EFI firmware */ >+ if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) >+ goto fail; >+ >+ setup_graphics(boot_params); >+ >+ setup_efi_pci(boot_params); > > status = efi_call_phys3(sys_table->boottime->allocate_pool, > EFI_LOADER_DATA, sizeof(*gdt), >@@ -1137,7 +1292,18 @@ > idt->size = 0; > idt->address = 0; > >- status = make_boot_params(boot_params, image, handle); >+ /* >+ * If the kernel isn't already loaded at the preferred load >+ * address, relocate it. >+ */ >+ if (hdr->pref_address != hdr->code32_start) { >+ status = relocate_kernel(hdr); >+ >+ if (status != EFI_SUCCESS) >+ goto fail; >+ } >+ >+ status = exit_boot(boot_params, handle); > if (status != EFI_SUCCESS) > goto fail; > >--- arch/x86/boot/compressed/head_32.S 2012-07-22 06:28:29.000000000 +0930 >+++ arch/x86/boot/compressed/head_32.S 2012-07-30 08:31:43.000000000 +0930 >@@ -42,6 +42,16 @@ > */ > add $0x4, %esp > >+ call make_boot_params >+ cmpl $0, %eax >+ je 1f >+ movl 0x4(%esp), %esi >+ movl (%esp), %ecx >+ pushl %eax >+ pushl %esi >+ pushl %ecx >+ >+ .org 0x30,0x90 > call efi_main > cmpl $0, %eax > movl %eax, %esi >--- arch/x86/boot/compressed/head_64.S 2012-07-22 06:28:29.000000000 +0930 >+++ arch/x86/boot/compressed/head_64.S 2012-07-30 08:31:43.000000000 +0930 >@@ -209,6 +209,16 @@ > .org 0x210 > mov %rcx, %rdi > mov %rdx, %rsi >+ pushq %rdi >+ pushq %rsi >+ call make_boot_params >+ cmpq $0,%rax >+ je 1f >+ mov %rax, %rdx >+ popq %rsi >+ popq %rdi >+ >+ .org 0x230,0x90 > call efi_main > movq %rax,%rsi > cmpq $0,%rax >--- arch/x86/boot/header.S 2012-07-22 06:28:29.000000000 +0930 >+++ arch/x86/boot/header.S 2012-07-30 08:31:43.000000000 +0930 >@@ -283,7 +283,7 @@ > # Part 2 of the header, from the old setup.S > > .ascii "HdrS" # header signature >- .word 0x020a # header version number (>= 0x0105) >+ .word 0x020b # header version number (>= 0x0105) > # or else old loadlin-1.5 will fail) > .globl realmode_swtch > realmode_swtch: .word 0, 0 # default_switch, SETUPSEG >@@ -401,6 +401,8 @@ > #define INIT_SIZE VO_INIT_SIZE > #endif > init_size: .long INIT_SIZE # kernel initialization size >+handover_offset: .long 0x30 # offset to the handover >+ # protocol entry point > > # End of setup header ##################################################### > >--- arch/x86/include/asm/bootparam.h 2012-07-22 06:28:29.000000000 +0930 >+++ arch/x86/include/asm/bootparam.h 2012-07-30 08:31:43.000000000 +0930 >@@ -67,6 +68,7 @@ > __u64 setup_data; > __u64 pref_address; > __u32 init_size; >+ __u32 handover_offset; > } __attribute__((packed)); > > struct sys_desc_table { >--- Documentation/x86/boot.txt 2012-07-22 06:28:29.000000000 +0930 >+++ Documentation/x86/boot.txt 2012-07-30 08:31:43.000000000 +0930 >@@ -54,6 +54,9 @@ > beyond the kernel_alignment added, new init_size and > pref_address fields. Added extended boot loader IDs. > >+Protocol 2.11: (Kernel 3.6) Added a field for offset of EFI handover >+ protocol entry point. >+ > **** MEMORY LAYOUT > > The traditional memory map for the kernel loader, used for Image or >@@ -189,6 +192,7 @@ > of struct setup_data > 0258/8 2.10+ pref_address Preferred loading address > 0260/4 2.10+ init_size Linear memory required during initialization >+0264/4 2.11+ handover_offset Offset of handover entry point > > (1) For backwards compatibility, if the setup_sects field contains 0, the > real value is 4. >@@ -690,6 +694,16 @@ > else > runtime_start = pref_address > >+Field name: handover_offset >+Type: read >+Offset/size: 0x264/4 >+ >+ This field is the offset from the beginning of the kernel image to >+ the EFI handover protocol entry point. Boot loaders using the EFI >+ handover protocol to boot the kernel should jump to this offset. >+ >+ See EFI HANDOVER PROTOCOL below for more details. >+ > > **** THE IMAGE CHECKSUM > >@@ -1010,3 +1024,30 @@ > must have read/write permission; CS must be __BOOT_CS and DS, ES, SS > must be __BOOT_DS; interrupt must be disabled; %esi must hold the base > address of the struct boot_params; %ebp, %edi and %ebx must be zero. >+ >+**** EFI HANDOVER PROTOCOL >+ >+This protocol allows boot loaders to defer initialisation to the EFI >+boot stub. The boot loader is required to load the kernel/initrd(s) >+from the boot media and jump to the EFI handover protocol entry point >+which is hdr->handover_offset bytes from the beginning of >+startup_{32,64}. >+ >+The function prototype for the handover entry point looks like this, >+ >+ efi_main(void *handle, efi_system_table_t *table, struct boot_params *bp) >+ >+'handle' is the EFI image handle passed to the boot loader by the EFI >+firmware, 'table' is the EFI system table - these are the first two >+arguments of the "handoff state" as described in section 2.3 of the >+UEFI specification. 'bp' is the boot loader-allocated boot params. >+ >+The boot loader *must* fill out the following fields in bp, >+ >+ o hdr.code32_start >+ o hdr.cmd_line_ptr >+ o hdr.cmdline_size >+ o hdr.ramdisk_image (if applicable) >+ o hdr.ramdisk_size (if applicable) >+ >+All other fields should be zero. >--- drivers/pci/bus.c 2012-07-22 06:28:29.000000000 +0930 >+++ drivers/pci/bus.c 2012-07-30 08:31:43.000000000 +0930 >@@ -164,6 +164,11 @@ > int pci_bus_add_device(struct pci_dev *dev) > { > int retval; >+ >+ retval = pcibios_add_device(dev); >+ if (retval) >+ return retval; >+ > retval = device_add(&dev->dev); > if (retval) > return retval; >--- drivers/platform/x86/apple-gmux.c 2012-07-22 06:28:29.000000000 +0930 >+++ drivers/platform/x86/apple-gmux.c 2012-07-30 08:31:43.000000000 +0930 >@@ -2,6 +2,7 @@ > * Gmux driver for Apple laptops > * > * Copyright (C) Canonical Ltd. <seth.forshee@canonical.com> >+ * Copyright (C) 2010-2012 Andreas Heider <andreas@meetr.de> > * > * 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 >@@ -20,13 +21,22 @@ > #include <linux/slab.h> > #include <acpi/video.h> > #include <asm/io.h> >+#include <linux/pci.h> >+#include <linux/vga_switcheroo.h> >+#include <linux/delay.h> > >-struct apple_gmux_data { >+static struct apple_gmux_data { > unsigned long iostart; > unsigned long iolen; >+ acpi_handle dhandle; >+ enum vga_switcheroo_client_id resume_client_id; > > struct backlight_device *bdev; >-}; >+} gmux_data; >+ >+static struct pci_dev *discrete; >+ >+DECLARE_COMPLETION(powerchange_done); > > /* > * gmux port offsets. Many of these are not yet used, but may be in the >@@ -59,32 +69,29 @@ > #define GMUX_BRIGHTNESS_MASK 0x00ffffff > #define GMUX_MAX_BRIGHTNESS GMUX_BRIGHTNESS_MASK > >-static inline u8 gmux_read8(struct apple_gmux_data *gmux_data, int port) >+static inline u8 gmux_read8(int port) > { >- return inb(gmux_data->iostart + port); >+ return inb(gmux_data.iostart + port); > } > >-static inline void gmux_write8(struct apple_gmux_data *gmux_data, int port, >- u8 val) >+static inline void gmux_write8(int port, u8 val) > { >- outb(val, gmux_data->iostart + port); >+ outb(val, gmux_data.iostart + port); > } > >-static inline u32 gmux_read32(struct apple_gmux_data *gmux_data, int port) >+static inline u32 gmux_read32(int port) > { >- return inl(gmux_data->iostart + port); >+ return inl(gmux_data.iostart + port); > } > > static int gmux_get_brightness(struct backlight_device *bd) > { >- struct apple_gmux_data *gmux_data = bl_get_data(bd); >- return gmux_read32(gmux_data, GMUX_PORT_BRIGHTNESS) & >+ return gmux_read32(GMUX_PORT_BRIGHTNESS) & > GMUX_BRIGHTNESS_MASK; > } > > static int gmux_update_status(struct backlight_device *bd) > { >- struct apple_gmux_data *gmux_data = bl_get_data(bd); > u32 brightness = bd->props.brightness; > > if (bd->props.state & BL_CORE_SUSPENDED) >@@ -96,54 +103,227 @@ > * accept a single u32 write, but the old method also works, so we > * just use the old method for all gmux versions. > */ >- gmux_write8(gmux_data, GMUX_PORT_BRIGHTNESS, brightness); >- gmux_write8(gmux_data, GMUX_PORT_BRIGHTNESS + 1, brightness >> 8); >- gmux_write8(gmux_data, GMUX_PORT_BRIGHTNESS + 2, brightness >> 16); >- gmux_write8(gmux_data, GMUX_PORT_BRIGHTNESS + 3, 0); >+ gmux_write8(GMUX_PORT_BRIGHTNESS, brightness); >+ gmux_write8(GMUX_PORT_BRIGHTNESS + 1, brightness >> 8); >+ gmux_write8(GMUX_PORT_BRIGHTNESS + 2, brightness >> 16); >+ gmux_write8(GMUX_PORT_BRIGHTNESS + 3, 0); >+ >+ return 0; >+} >+ >+static int gmux_switchto(enum vga_switcheroo_client_id id) >+{ >+ if (id == VGA_SWITCHEROO_IGD) { >+ gmux_write8(GMUX_PORT_SWITCH_DDC, 1); >+ gmux_write8(GMUX_PORT_SWITCH_DISPLAY, 2); >+ gmux_write8(GMUX_PORT_SWITCH_EXTERNAL, 2); >+ } else { >+ gmux_write8(GMUX_PORT_SWITCH_DDC, 2); >+ gmux_write8(GMUX_PORT_SWITCH_DISPLAY, 3); >+ gmux_write8(GMUX_PORT_SWITCH_EXTERNAL, 3); >+ } >+ >+ return 0; >+} >+ >+static int gmux_call_acpi_pwrd(int arg) >+{ >+ acpi_handle gfx_handle = DEVICE_ACPI_HANDLE(&discrete->dev); >+ acpi_handle pwrd_handle = NULL; >+ acpi_status status = AE_OK; >+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; >+ union acpi_object arg0 = { ACPI_TYPE_INTEGER }; >+ struct acpi_object_list arg_list = { 1, &arg0 }; >+ >+ if (!gfx_handle) { >+ pr_err("Cannot find device ACPI handle\n"); >+ return -ENODEV; >+ } >+ >+ status = acpi_get_handle(gfx_handle, "PWRD", &pwrd_handle); >+ if (ACPI_FAILURE(status)) { >+ pr_err("Cannot get PWRD handle: %s\n", acpi_format_exception(status)); >+ return -ENODEV; >+ } >+ >+ arg0.integer.value = arg; >+ >+ status = acpi_evaluate_object(pwrd_handle, NULL, &arg_list, &buffer); >+ if (ACPI_FAILURE(status)) { >+ pr_err("PWRD call failed: %s\n", acpi_format_exception(status)); >+ return -ENODEV; >+ } >+ >+ //acpi_result_to_string(buffer.pointer); >+ kfree(buffer.pointer); >+ >+ pr_info("PWRD call successful\n"); >+ return 0; >+} >+ >+static int gmux_set_discrete_state(enum vga_switcheroo_state state) >+{ >+ /* TODO: locking for completions needed? */ >+ init_completion(&powerchange_done); >+ >+ if (state == VGA_SWITCHEROO_ON) { >+ gmux_call_acpi_pwrd(0); >+ gmux_write8(GMUX_PORT_DISCRETE_POWER, 1); >+ gmux_write8(GMUX_PORT_DISCRETE_POWER, 3); >+ pr_info("discrete card powered up\n"); >+ } else { >+ gmux_write8(GMUX_PORT_DISCRETE_POWER, 1); >+ gmux_write8(GMUX_PORT_DISCRETE_POWER, 0); >+ gmux_call_acpi_pwrd(1); >+ pr_info("discrete card powered down\n"); >+ } >+ >+ if (wait_for_completion_interruptible_timeout(&powerchange_done, msecs_to_jiffies(200))) >+ pr_info("completion timeout\n"); > > return 0; > } > >+static int gmux_set_power_state(enum vga_switcheroo_client_id id, >+ enum vga_switcheroo_state state) >+{ >+ if (id == VGA_SWITCHEROO_IGD) >+ return 0; >+ >+ return gmux_set_discrete_state(state); >+} >+ >+static int gmux_init(void) >+{ >+ return 0; >+} >+ >+static int gmux_get_client_id(struct pci_dev *pdev) >+{ >+ /* early mbps with switchable graphics use nvidia integrated graphics, >+ * hardcode that the 9400M is integrated */ >+ if (pdev->vendor == PCI_VENDOR_ID_INTEL) { >+ return VGA_SWITCHEROO_IGD; >+ } else if (pdev->vendor == PCI_VENDOR_ID_NVIDIA && pdev->device == 0x0863) { >+ return VGA_SWITCHEROO_IGD; >+ } else { >+ discrete = pdev; >+ return VGA_SWITCHEROO_DIS; >+ } >+} >+ >+static bool gmux_client_active(enum vga_switcheroo_client_id id) >+{ >+ u8 state = gmux_read8(GMUX_PORT_SWITCH_DISPLAY); >+ >+ if ((id == VGA_SWITCHEROO_IGD && state == 2) || >+ (id == VGA_SWITCHEROO_DIS && state == 3)) >+ return true; >+ >+ return false; >+} >+ >+static struct vga_switcheroo_handler gmux_handler = { >+ .switchto = gmux_switchto, >+ .power_state = gmux_set_power_state, >+ .init = gmux_init, >+ .get_client_id = gmux_get_client_id, >+ .client_active = gmux_client_active, >+}; >+ >+static void gmux_disable_interrupts(void) >+{ >+ gmux_write8(GMUX_PORT_INTERRUPT_ENABLE, GMUX_INTERRUPT_DISABLE); >+} >+ >+static void gmux_enable_interrupts(void) >+{ >+ gmux_write8(GMUX_PORT_INTERRUPT_ENABLE, GMUX_INTERRUPT_ENABLE); >+} >+ >+static int gmux_interrupt_get_status(void) >+{ >+ return gmux_read8(GMUX_PORT_INTERRUPT_STATUS); >+} >+ >+static void gmux_interrupt_activate_status(void) >+{ >+ int old_status; >+ int new_status; >+ >+ /* to reactivate interrupts write back current status */ >+ old_status = gmux_read8(GMUX_PORT_INTERRUPT_STATUS); >+ gmux_write8(GMUX_PORT_INTERRUPT_STATUS, old_status); >+ new_status = gmux_read8(GMUX_PORT_INTERRUPT_STATUS); >+ >+ /* status = 0 indicates active interrupts */ >+ if (new_status) >+ pr_info("gmux: error: activate_status, old_status %d new_status %d\n", old_status, new_status); >+} >+ >+static void gmux_notify_handler(acpi_handle device, u32 value, void *context) >+{ >+ int status; >+ >+ status = gmux_interrupt_get_status(); >+ gmux_disable_interrupts(); >+ pr_info("gmux: gpe handler called: status %d\n", status); >+ >+ gmux_interrupt_activate_status(); >+ gmux_enable_interrupts(); >+ >+ if (status & GMUX_INTERRUPT_STATUS_POWER) >+ complete(&powerchange_done); >+} >+ > static const struct backlight_ops gmux_bl_ops = { > .options = BL_CORE_SUSPENDRESUME, > .get_brightness = gmux_get_brightness, > .update_status = gmux_update_status, > }; > >+static int gmux_suspend(struct pnp_dev *dev, pm_message_t state) >+{ >+ gmux_data.resume_client_id = gmux_read8(GMUX_PORT_SWITCH_DISPLAY) == 2 ? >+ VGA_SWITCHEROO_IGD : VGA_SWITCHEROO_DIS; >+ return 0; >+} >+ >+static int gmux_resume(struct pnp_dev *dev) >+{ >+ gmux_switchto(gmux_data.resume_client_id); >+ return 0; >+} >+ > static int __devinit gmux_probe(struct pnp_dev *pnp, > const struct pnp_device_id *id) > { >- struct apple_gmux_data *gmux_data; > struct resource *res; > struct backlight_properties props; > struct backlight_device *bdev; > u8 ver_major, ver_minor, ver_release; >+ acpi_status status; > int ret = -ENXIO; > >- gmux_data = kzalloc(sizeof(*gmux_data), GFP_KERNEL); >- if (!gmux_data) >- return -ENOMEM; >- pnp_set_drvdata(pnp, gmux_data); >- > res = pnp_get_resource(pnp, IORESOURCE_IO, 0); > if (!res) { > pr_err("Failed to find gmux I/O resource\n"); >- goto err_free; >+ goto err_begin; > } > >- gmux_data->iostart = res->start; >- gmux_data->iolen = res->end - res->start; >+ gmux_data.iostart = res->start; >+ gmux_data.iolen = res->end - res->start; > >- if (gmux_data->iolen < GMUX_MIN_IO_LEN) { >+ if (gmux_data.iolen < GMUX_MIN_IO_LEN) { > pr_err("gmux I/O region too small (%lu < %u)\n", >- gmux_data->iolen, GMUX_MIN_IO_LEN); >- goto err_free; >+ gmux_data.iolen, GMUX_MIN_IO_LEN); >+ goto err_begin; > } > >- if (!request_region(gmux_data->iostart, gmux_data->iolen, >+ if (!request_region(gmux_data.iostart, gmux_data.iolen, > "Apple gmux")) { > pr_err("gmux I/O already in use\n"); >- goto err_free; >+ goto err_begin; > } > > /* >@@ -151,9 +331,9 @@ > * doesn't really have a gmux. Check for invalid version information > * to detect this. > */ >- ver_major = gmux_read8(gmux_data, GMUX_PORT_VERSION_MAJOR); >- ver_minor = gmux_read8(gmux_data, GMUX_PORT_VERSION_MINOR); >- ver_release = gmux_read8(gmux_data, GMUX_PORT_VERSION_RELEASE); >+ ver_major = gmux_read8(GMUX_PORT_VERSION_MAJOR); >+ ver_minor = gmux_read8(GMUX_PORT_VERSION_MINOR); >+ ver_release = gmux_read8(GMUX_PORT_VERSION_RELEASE); > if (ver_major == 0xff && ver_minor == 0xff && ver_release == 0xff) { > pr_info("gmux device not present\n"); > ret = -ENODEV; >@@ -165,7 +345,7 @@ > > memset(&props, 0, sizeof(props)); > props.type = BACKLIGHT_PLATFORM; >- props.max_brightness = gmux_read32(gmux_data, GMUX_PORT_MAX_BRIGHTNESS); >+ props.max_brightness = gmux_read32(GMUX_PORT_MAX_BRIGHTNESS); > > /* > * Currently it's assumed that the maximum brightness is less than >@@ -177,44 +357,72 @@ > props.max_brightness = GMUX_MAX_BRIGHTNESS; > > bdev = backlight_device_register("gmux_backlight", &pnp->dev, >- gmux_data, &gmux_bl_ops, &props); >+ NULL, &gmux_bl_ops, &props); > if (IS_ERR(bdev)) { > ret = PTR_ERR(bdev); > goto err_release; > } > >- gmux_data->bdev = bdev; >+ gmux_data.bdev = bdev; > bdev->props.brightness = gmux_get_brightness(bdev); > backlight_update_status(bdev); > >- /* >- * The backlight situation on Macs is complicated. If the gmux is >- * present it's the best choice, because it always works for >- * backlight control and supports more levels than other options. >- * Disable the other backlight choices. >- */ >- acpi_video_unregister(); >- apple_bl_unregister(); >+ gmux_data.dhandle = DEVICE_ACPI_HANDLE(&pnp->dev); >+ if (!gmux_data.dhandle) { >+ pr_err("Cannot find acpi device for pnp device %s\n", dev_name(&pnp->dev)); >+ goto err_release; >+ } else { >+ struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL }; >+ acpi_get_name(gmux_data.dhandle, ACPI_SINGLE_NAME, &buf); >+ pr_info("Found acpi handle for pnp device %s: %s\n", >+ dev_name(&pnp->dev), (char *)buf.pointer); >+ kfree(buf.pointer); >+ } >+ >+ status = acpi_install_notify_handler(gmux_data.dhandle, ACPI_DEVICE_NOTIFY, &gmux_notify_handler, pnp); >+ if (ACPI_FAILURE(status)) { >+ printk("Install notify handler failed: %s\n", acpi_format_exception(status)); >+ goto err_notify; >+ } >+ >+ if (vga_switcheroo_register_handler(&gmux_handler)) >+ goto err_register; >+ >+ init_completion(&powerchange_done); >+ gmux_enable_interrupts(); >+ >+ /* TODO: check this out */ >+ /*active_card = gmux_read8(GMUX_PORT_SWITCH_GET_DISPLAY);*/ >+ /*pr_info("active card: %x\n", active_card);*/ >+ /*pr_info("rom shadow: %x %d", pdev->vendor, pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW);*/ > > return 0; > >+err_register: >+ status = acpi_remove_notify_handler(gmux_data.dhandle, ACPI_DEVICE_NOTIFY, &gmux_notify_handler); >+ if (ACPI_FAILURE(status)) { >+ printk("Install notify handler failed: %s\n", acpi_format_exception(status)); >+ } >+err_notify: >+ backlight_device_unregister(bdev); > err_release: >- release_region(gmux_data->iostart, gmux_data->iolen); >-err_free: >- kfree(gmux_data); >+ release_region(gmux_data.iostart, gmux_data.iolen); >+err_begin: > return ret; > } > > static void __devexit gmux_remove(struct pnp_dev *pnp) > { >- struct apple_gmux_data *gmux_data = pnp_get_drvdata(pnp); >+ acpi_status status; > >- backlight_device_unregister(gmux_data->bdev); >- release_region(gmux_data->iostart, gmux_data->iolen); >- kfree(gmux_data); >- >- acpi_video_register(); >- apple_bl_register(); >+ vga_switcheroo_unregister_handler(); >+ backlight_device_unregister(gmux_data.bdev); >+ gmux_disable_interrupts(); >+ status = acpi_remove_notify_handler(gmux_data.dhandle, ACPI_DEVICE_NOTIFY, &gmux_notify_handler); >+ if (ACPI_FAILURE(status)) { >+ printk("Install notify handler failed: %s\n", acpi_format_exception(status)); >+ } >+ release_region(gmux_data.iostart, gmux_data.iolen); > } > > static const struct pnp_device_id gmux_device_ids[] = { >@@ -227,6 +435,8 @@ > .probe = gmux_probe, > .remove = __devexit_p(gmux_remove), > .id_table = gmux_device_ids, >+ .suspend = gmux_suspend, >+ .resume = gmux_resume > }; > > static int __init apple_gmux_init(void)
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 837461
:
601855
|
603359
| 627318 |
679517
|
692139