[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

New I2C and machine probing method



Hi,
I want to use some OF and kernel 2.6 features to improve device probing
in pbbuttonsd. Unfortunately I have only an ancient PowerBook so I need
your help to test the new routines on as many different machines as
possible.

I attached the source code of a short program. You could compile it as
follows:
 $> gcc -o of_probing of_probing.c

This program does three things:
1. detecting the machine ID.
   Any PowerBook user can test this feature. Launch the program and
   check if the machine ID is correctly detected on your machine. If
   you don't know which ID your machine have see in
     $> cat /proc/device-tree/model or
     $> cat /proc/cpuinfo
   Tell me if your machine is not correctly identified. PowerBooks
   before the G3 Pismo will get the dummy ID "1", because Apple started
   his numbering system just with the Pismo.

2. detecting the LMU I2C address
   The program looked for the "lmu-controller" in the device tree and
   read the attached data to find out the I2C address.
   This test will only have a result, if you have a PowerBook with an
   ambient light sensor. Otherwise the program won't find an LMU.
   If your machine definitely has an ambient light sensor and the program 
   won't find it, the device tree path might be wrong. In this case please
   send me the correct path or an tar archive of /proc/device-tree.

3. detecting of the /dev/i2c device to communicate with the LMU
   This test reads /sys to find out which i2c devices are available and
   which one is connected to the "uni-n" controller the LMU is attached
   to. Each found i2c device will then be checked for the LMU.
   The program lists all found i2c devices to the console and mark the
   device with the LMU connected.
   This test needs the kernel module i2c-dev to be loaded. If not
   already done, you could load the module with
     $> modprobe i2c-dev

I would appreciate any feedback.

 Thank you and Best Regards
   Matthias






#include <stdio.h>
#include <dirent.h>
#include <string.h>
#include <fcntl.h>
#include <sys/ioctl.h>

#define OFBASE     "/proc/device-tree"
#define SYSI2CDEV  "/sys/class/i2c-dev"
#define I2CCHIP    "uni-n"
#define I2C_SLAVE  0x0703

int
probeLMU(char *device, int addr)
{
	char buffer[4];
	int fd, rc = 0;

	if ((fd = open(device, O_RDWR)) >= 0) {
		if (ioctl(fd, I2C_SLAVE, addr) >= 0) {
			if (read (fd, buffer, 4) == 4) 
				rc = 1;
		}
		close(fd);
	}
	return rc;
}

int
addPath(char *path, int maxlen, char *pattern)
{
	DIR *dh;
	struct dirent *dir;
	int rc = 1;
	
	if ((dh = opendir(path))) {
		while (dir = readdir(dh)) {
			if ((strncmp(dir->d_name, pattern, strlen(pattern)) == 0)) {
				strncat(path, "/", maxlen-1);
				strncat(path, dir->d_name, maxlen-1);
				rc = 0;
				break;
			}			
		}
		closedir(dh);
	}
	return rc;
}

int
getLMUAddress()
{
	char path[200];
	FILE *fd;
	long reg;
	int n, rc = 0, err = 0;

	path[0] = 0; /* terminate path buffer */
	strncat(path, OFBASE, sizeof(path)-1);
	err += addPath(path, sizeof(path), "uni-n");
	err += addPath(path, sizeof(path), "i2c");
	err += addPath(path, sizeof(path), "lmu-controller");
	strncat(path, "/reg", sizeof(path)-1);
	
	printf("  OF: '%s'\n", path); 
	if (err > 0)
		printf("    Path incomplete! One or more elements not found.\n");
	else if ((fd = fopen(path, "r")) >= 0) {
		n = fread(&reg, sizeof(long), 1, fd);
		if (n == 1)
			rc = (int) (reg >> 1);
		fclose(fd);
	}
	return rc;
}

int
findI2CDevice(int addr)
{
	char buffer[40];
	DIR *dh;
	FILE *fd;
	struct dirent *dir;
	int n;

	if ((dh = opendir(SYSI2CDEV))) {
		while (dir = readdir(dh)) {
			if (dir->d_name[0] == '.') continue;
			snprintf(buffer, sizeof(buffer), SYSI2CDEV"/%s/name", dir->d_name);
			if ((fd = fopen(buffer, "r")) >= 0) {
				n = fread(buffer, 1, sizeof(buffer), fd);
				if (n > 0 && n < sizeof(buffer)) {
					buffer[n-1] = 0;
					printf("  I2C: '%s', '%s'", dir->d_name, buffer); 
					if ((strncmp(I2CCHIP" ", buffer, 6) == 0)) {
						snprintf(buffer, sizeof(buffer), "/dev/%s", dir->d_name);
						if ((probeLMU(buffer, addr)))
							printf("  <- this is the LMU device");
					}
					printf("\n");
				}
				fclose(fd);
			}
		}
		closedir(dh);
	}
}

int
getMachineID()
{
	char buffer[32];
	int fd, n, machine = 0;

	if ((fd = open(OFBASE"/model", O_RDONLY))) {
		if ((n = read(fd, buffer, sizeof(buffer) - 1)) != -1) {
			buffer[n] = 0;   /* terminate buffer, only to be sure */
			if (strncmp("PowerBook", buffer, 9) == 0) {
				if (buffer[9] == 0)
					machine = 1;  /* Dummy code for pre-Pismo PowerBooks */
				else {
					machine = (atoi(&buffer[9]) & 0xf) << 4;
					for (n = 9; buffer[n] != ',' && buffer[n] != '\0'; ++n);
					if (buffer[n] == ',')
						machine |= atoi(&buffer[n+1]) & 0xf;
				}
			}
		}
		close(fd);
	}
	return machine;
}


int
main (int argc, char *argv[])
{
	int addr, machine;

	printf("\nProbing machine...\n");
	
	machine = getMachineID();
	if (machine != 0) {
		printf ("  Machine: ID = %x\n", machine);

		addr = getLMUAddress();
		if (addr) {
			printf("  LMU: I2C address = %x \n", addr);
			findI2CDevice(addr);
		} else
			printf("  LMU: No LMU found!\n");
		
	} else
		printf ("  Machine: This is not a PowerBook\n");
				
	return 0;
}


Reply to: