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

Re: fnset utility on lombard, and fn/Ctrl swapping



Christian Jaeger <christian.jaeger@sl.ethz.ch> writes:

> Has anyone got the "fnset" utility from Jimi Xenidis got working on
> a lombard (and woody with 2.4.13-pre3-ben0)? It has defined a
> constant for Lombards but doesn't work nonetheless (it shows no
> effect).

Yes, I use the fnset utility on my lombard.  The source is
attached...

/*
 * fnset.c
 * Copyright 2001 Jimi Xenidis
 *
 * 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.
 *
 * Wouldn't have been able to figure out how to do this without trackpad.c
 * thanks to benh
*/


#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <linux/adb.h>
#include <linux/pmu.h>


#define PMU_GET_VERSION		0xea	/* get pmu firmware version # */
#define PMU_VERSION_LOMBARD	11
#define PMU_VERSION_KEYLARGO	12	/* another guess */
#define PMU_VERSION_IBOOK	PMU_VERSION_KEYLARGO

const char *prog;

int debug = 0;

void
usage()
{
    fprintf(stderr,
	    "Usage: %s [-hdfusb] [0|1]\n"
	    "  -h    Help, this message.\n"
	    "  -d    Turn debugging on.\n"
	    "  -f    Force search and setting of bits for an unknown PMU.\n"
	    "          WARNING: may damage hardware.\n"
	    "  -s    Set, function keys require <fn> modifier.\n"
	    "          Same as checking the box in MacOS.\n"
	    "  -u    Unset, hot keys require <fn> modifier.\n"
	    "          Same as unchecking the box in MacOS.\n"
	    "  -v    Verbose output.\n"
	    "  -b    Brief, output adb register bit value only.\n"
	    "  0     Set adb register bit to 0.\n"
	    "          May not be the same as the -u option.\n"
	    "  1     Set adb register bit to 1.\n"
	    "          May not be the same as the -s option.\n"
	    "No arguments displays the <fn> mode as if -v was used.\n",
	    prog);
}

int
put(int fd, unsigned char data[], size_t sz)
{
    int n;

    if (debug) {
	int i;
	fprintf(stderr, "writing %ld bytes: {", sz);
	for (i = 0; i < sz; i++) {
	    fprintf(stderr, " 0x%02x", data[i]);
	}
	fputs(" }\n", stderr);
    }

    n = write(fd, data, sz);
    if (n != sz) {
	if (n == -1) {
	    fprintf(stderr, "%s: write(): %s\n",
		    prog, strerror(errno));
	} else {
	    fprintf(stderr, "%s: write(): expected %ld got %ld\n",
		    prog, sz, n);
	}
	return -1;
    }
    return n;
}

int
get(int fd, unsigned char data[], size_t sz)
{
    int n;

    n = read(fd, data, sz);
    if (n == -1) {
	fprintf(stderr, "%s: read(): %s\n",
		prog, strerror(errno));
	return -1;
    }

    if (debug) {
	int i;
	fprintf(stderr, "read %ld bytes", n);
	if (n > 0) {
	    fputs(": {", stderr);
	    for (i = 0; i < n; i++) {
		fprintf(stderr, " 0x%02x", data[i]);
	    }
	    fputs(" }", stderr);
	}
	fputc('\n', stderr);
    }

    return n;
}

int
pmu_version(int fd)
{
    unsigned char data[32];
    int n;

    data[0] = PMU_PACKET;
    data[1] = PMU_GET_VERSION;

    n = put(fd, data, 2);
    if (n == -1) {
	return -1;
    }

    n = get(fd, data, sizeof (data));
    if (n == -1) {
	return -1;
    }
    if (n != 2) {
	fprintf(stderr, "%s: read(): expected 2 got %ld\n",
		prog, n);
	return -1;
    }
    return data[1];
}

int
show_regs(int fd, int id)
{
    unsigned char data[16];
    int i;

    fprintf(stderr, "=== reading all registers for device %d. ===\n", id);

    for (i = 0; i < 4; i++) {
	data[0] = ADB_PACKET;
	data[1] = ADB_READREG(id, i);
	put(fd, data, 2);
	get(fd, data, sizeof(data));
    }

    fprintf(stderr, "=== done reading all registers for device %d. ===\n", id);

    return 1;
}


int
find_device(int fd, int type, int bitpos, int *bit)
{
    int i;
    int n;
    int ret = -1;
    unsigned char data[16];

    for (i = 1; i < 16; i++) {
	if (debug) {
	    fprintf(stderr, "probe adb device %d.\n", i);
	}
	data[0] = ADB_PACKET;
	data[1] = ADB_READREG(i, 1);
	n = put(fd, data, 2);
	if (n == -1) {
	    return -1;
	}

	n = get(fd, data, sizeof (data));
	if (n == -1) {
	    return -1;
	}

	if ((n > 0) && (data[1] == type)) {
	    if (ret > 0) {
		fprintf(stderr, "Ignoring other keyboard at %d\n", i);
	    } else {
		if (debug) {
		    fprintf(stderr, "Found keyboard at ADB id %d.\n", i);
		}
		ret = i;
		*bit = (data[2] & (1<<bitpos)) >> bitpos;
		if (debug) {
		    show_regs(fd, ret);
		}
	    }
	}
    }
    return ret;
}

int
fnset(int fd, int id, int bitpos, int bit)
{
    unsigned char data[4];
    int n;

    /* get current state */
    data[0] = ADB_PACKET;
    data[1] = ADB_READREG(id, 1);

    n = put(fd, data, 2);
    if (n == -1) {
	return 0;
    }

    n = get(fd, &data[1], sizeof (data) - 1);
    if (n == -1) {
	return 0;
    }

    /* write new state */
    data[0] = ADB_PACKET;
    data[1] = ADB_WRITEREG(id, 1);
    /* keep data[2] the same */
    data[3] = (data[3] & (~(1<<bitpos))) | (bit<<bitpos);

    n = put(fd, data, 1 + n);
    if (n == -1) {
	return 0;
    }
    n = get(fd, data, sizeof (data));
    if (n == -1) {
	return 0;
    }

    /* read in new state */
    data[0] = ADB_PACKET;
    data[1] = ADB_READREG(id, 1);
    n = put(fd, data, 2);
    if (n == -1) {
	return 0;
    }

    n = get(fd, data, sizeof (data));
    if (n == -1) {
	return 0;
    }

    if ((data[2] & (1<<bitpos)) != (bit<<bitpos)) {
	fprintf(stderr, "bit 0x%x did not get written.\n", (bit<<bitpos));
	return 0;
    }
    return 1;
}

int
main(int argc, char *argv[], char *envp[])
{
    const char *adb = "/dev/adb";
    unsigned char data[32];
    const char *optlet = "dvhsubvP:";

    extern char *optarg;
    extern int optind;
    int c;
    unsigned int bitpos = 0;
    int bit = -1;
    int force = 0;
    int val;
    int pmu;
    int fd;
    int id;
    int type;
    int brief = 0;
    int verbose = 0;

    prog = argv[0];

    if (argc == 1) {
	/* if no arguments theb be verbose */
	verbose = 1;
    } else {
	while((c = getopt(argc, argv, optlet)) != EOF) {
	    switch (c) {
	    case 'P':
		bitpos = strtol(optarg, (char **)NULL, 0);
		if (bitpos > 7) {
		    fprintf(stderr, "%s: bit position must be 0-8.\n", prog);
		    return 1;
		}
		break;
	    case 'd':
		debug = 1;
		break;
	    case 'f':
		force = 1;
		break;
	    case 'h':
		usage();
		return 0;
		break;
	    case 's':
		if (bit != -1) {
		    fprintf(stderr, "%s: conflicting arguments\n", prog);
		    usage();
		    return 1;
		}
		bit = 0;
		break;
	    case 'u':
		if (bit != -1) {
		    fprintf(stderr, "%s: conflicting arguments\n", prog);
		    usage();
		    return 1;
		}
		bit = 1;
		break;
	    case 'b':
		if (verbose) {
		    fprintf(stderr, "%s: conflicting arguments\n", prog);
		    usage();
		    return 1;
		}
		brief = 1 ;
		break;
	    case 'v':
		if (brief) {
		    fprintf(stderr, "%s: conflicting arguments\n", prog);
		    usage();
		    return 1;
		}
		verbose = 1 ;
		break;
	    case '?':
	    default:
		usage();
		return 1;
		break;
	    }
	}

	if (optind < argc) {
	    if (bit != -1) {
		fprintf(stderr, "%s: conflicting arguments\n", prog);
		usage();
		return 1;
	    }
	    if (argv[optind][0] == '1' && argv[optind][1] == '\0') {
		bit = 1;
	    } else if (argv[optind][0] == '0' && argv[optind][1] == '\0') {
		bit = 0;
	    }
	    if (debug) {
		fprintf(stderr, "set bit to: optarg: %u\n", bit);
	    }
	    ++optind;
	}

	if (optind != argc) {
	    fprintf(stderr,"%s: too many arguements\n", prog);
	    return 1;
	}
    }

    if (bitpos && !force) {
	fprintf(stderr,
		"%: WARNING: use of bit offset other than 0 (-P option)"
		"requires force (-f option) since it may damage hardware!\n",
		prog);
    }

    fd = open(adb, O_RDWR);
    if (fd < 0) {
	fprintf(stderr, "%s: open(%s): %s\n",
		prog, adb, strerror(errno));
	return 1;
    }

    pmu = pmu_version(fd);
    switch (pmu) {
    case PMU_VERSION_IBOOK:
    case PMU_VERSION_LOMBARD:
	type = 0x04;
	break;
    default:
	fprintf(stderr, "unknown PMU version %d\n", pmu);
	if (force) {
	    type = 0x04;
	    fprintf(stderr, "forcing look up of type 0x%02x.\n", type);
	} else {
	    close(fd);
	    return 1;
	}
	break;
    case -1:
	close(fd);
	return 1;
	break;
    }

    id = find_device(fd, type, bitpos, &val);
    if (id == -1) {
	close(fd);
	return 1;
    }

    if (bit != -1) {
	if (bit != val) {
	    if (debug) {
		fprintf(stderr, "Changing value from %d to %d.\n", val, bit);
	    }
	    if (!fnset(fd, id, bitpos, bit)) {
		if (debug) {
		    fprintf(stderr, "Failed to set value to %d.\n", bit);
		}
		close(fd);
		return 1;
	    }
	    val = bit;
	} else {
	    if (debug) {
		fputs("Value already correct, nothing to do.\n", stderr);
	    }
	}
    }
    if (brief) {
	printf("%u\n", val);
    } else if (verbose) {
	if (val == 0) {
	    printf("Set: Function keys require <fn> modifier.\n");
	} else {
	    printf("Unset: Hot keys require <fn> modifier.\n");
	}
    }
    close(fd);
    return 0;
}

-- 
Josh Huber                                   | huber@debian.org |

Reply to: