195 lines
4.5 KiB
C
195 lines
4.5 KiB
C
/*
|
|
* Apple Macbook Pro LCD backlight control
|
|
*
|
|
* Copyright (C) 2006 Nicolas Boichat <nicolas@boichat.ch>
|
|
*
|
|
* 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 <stdio.h>
|
|
#include <sys/io.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/mman.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
|
|
#include <pci/pci.h>
|
|
|
|
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;
|
|
}
|