macbook-tools/backlight.c

195 lines
4.5 KiB
C
Raw Permalink Normal View History

2013-01-24 01:00:00 +01:00
/*
* 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;
}