/* * Apple Macbook Pro LCD backlight control * * Copyright (C) 2006 Nicolas Boichat * * 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, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include #include #include #include #include #include #include #include #include #include char* memory; static inline unsigned int readl(const volatile void *addr) { return *(volatile unsigned int*) addr; } static inline void writel(unsigned int b, volatile void *addr) { *(volatile unsigned int*) addr = b; } #define INREG(addr) readl(memory+addr) #define OUTREG(addr,val) writel(val, memory+addr) unsigned char read_backlight() { return INREG(0x7af8) >> 8; } void write_backlight_value(unsigned char value) { OUTREG(0x7af8, 0x00000001 | ((unsigned int)value << 8)); } void write_backlight(unsigned char value) { unsigned int current = read_backlight(); if (current < value) { while (current < value) { current += 5; if (current > value) current = value; write_backlight_value((unsigned char)current); usleep(50000); } } else { while (current > value) { current -= 5; if (current < value) current = value; write_backlight_value((unsigned char)current); usleep(50000); } } } void usage(char* argv0) { printf("Apple Macbook (pro) backlight control " VERSION); printf("\n"); printf("Usage:\n"); printf("%s: read current value\n", argv0); printf("%s value: write value [0-255]\n", argv0); printf("%s +n: increase value by n\n", argv0); printf("%s -n: decrease value by n\n", argv0); } int main(int argc, char** argv) { if (argc > 2) { usage(argv[0]); return 1; } char* endptr; int ret = 0; long address = 0; long length = 0; int fd; int state; /* Search for the graphics card. */ /* Default values: */ /* address = 0x90300000; */ /* length = 0x20000; */ struct pci_access *pacc = pci_alloc(); pci_init(pacc); pci_scan_bus(pacc); struct pci_dev *dev; for(dev=pacc->devices; dev; dev=dev->next) { /* Iterate over all devices */ pci_fill_info(dev, PCI_FILL_IDENT | PCI_FILL_BASES); if ((dev->vendor_id == 0x1002) && (dev->device_id == 0x71c5)) { // ATI X1600 address = dev->base_addr[2]; length = dev->size[2]; } } pci_cleanup(pacc); if (!address) { printf("Failed to detect ATI X1600, aborting...\n"); return 1; } fd = open("/dev/mem", O_RDWR); if (fd < 0) { perror("cannot open /dev/mem"); return 1; } memory = mmap(NULL, length, PROT_READ|PROT_WRITE, MAP_SHARED, fd, address); if (memory == MAP_FAILED) { perror("mmap failed"); return 1; } /* Is it really necessary ? */ OUTREG(0x4dc, 0x00000005); state = INREG(0x7ae4); OUTREG(0x7ae4, state); if (argc == 2) { if (argv[1][0] == '+') { long value = strtol(&argv[1][1], &endptr, 10); if ((value < 0) || (value > 255) || (endptr[0])) { printf("Invalid value \"%s\" (should be an integer between 0 and 255).\n", &argv[1][1]); usage(argv[0]); ret = 1; } else { value = read_backlight()+value; if (value > 255) value = 255; write_backlight(value); } } else if (argv[1][0] == '-') { long value = strtol(&argv[1][1], &endptr, 10); if ((value < 0) || (value > 255) || (endptr[0])) { printf("Invalid value \"%s\" (should be an integer between 0 and 255).\n", &argv[1][1]); usage(argv[0]); ret = 1; } else { value = read_backlight()-value; if (value < 0) value = 0; write_backlight(value); } } else { long value = strtol(argv[1], &endptr, 10); if ((value < 0) || (value > 255) || (endptr[0])) { printf("Invalid value \"%s\" (should be an integer between 0 and 255).\n", argv[1]); usage(argv[0]); ret = 1; } else { write_backlight(value); } } } else { printf("%d\n", read_backlight()); } munmap(memory, length); close(fd); return ret; }