diff --git a/src/ex/testi2c.nif b/src/ex/testi2c.nif
new file mode 100644
index 0000000..25d3a45
--- /dev/null
+++ b/src/ex/testi2c.nif
@@ -0,0 +1,30 @@
+
+: test1
+ 200 0 do
+ " i vaut : " "type I .
+ I 0x12 1 i2c_read
+ " et on lit : " "type . cr
+ 1 sleep
+ loop
+;
+
+: test2
+ 200 0 do
+ " i vaut : " "type I .
+ I I 0x12 1 i2c_write
+ " on ecrit cette valeur a cette adresse " "type
+ I 0x12 1 i2c_read
+ " et on lit : " "type . cr
+ 1 sleep
+ loop
+;
+
+# fonction qui envoie une valeur a l'Arduino et qui recupere le resultat du calcul
+# on suppose ici que le I2C-ID est egal a 1 car Model B
+: arduino # [ val chip-address - resultat ]
+ dup unrot dup 1 i2c_write
+ 1 sleep # a voir si c'est bien necessaire
+ -1 swap 1 i2c_read
+;
+
+
diff --git a/src/i2c.c b/src/i2c.c
new file mode 100644
index 0000000..bae5175
--- /dev/null
+++ b/src/i2c.c
@@ -0,0 +1,374 @@
+/* Copyright (C) 2011-2014 Patrick H. E. Foubet - S.E.R.I.A.N.E.
+
+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 3 of the License, or 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, see
+*******************************************************************/
+/* i2c.c */
+
+#ifdef HAVE_CONFIG_H
+#include "../config.h"
+#endif
+
+#ifdef HAVE_LINUX_I2C_DEV_H
+#include
+#ifdef I2C_FUNC_I2C
+#define _WITH_I2C
+#endif
+#endif
+
+#include
+#include
+#include
+
+#ifdef _WITH_I2C
+/*
+ This part is a merge of Linux i2c-tools code and Nife code.
+ i2c-tools are user-space programs to detect, scan I2C devices,
+ and read and/or write an I2C register.
+ Copyright (C) 2005-2012 Jean Delvare
+
+ Copyright (C) 2001-2003 Frodo Looijaard , and
+ Mark D. Studebaker
+ Copyright (C) 2004-2005 Jean Delvare
+
+ 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.
+*/
+#include "i2cbusses.c" /* add code for I2C on Linux */
+
+#define MODE_AUTO 0
+#define MODE_QUICK 1
+#define MODE_READ 2
+#define MODE_FUNC 3
+
+/*
+ * Print the installed i2c busses. The format is those of Linux 2.4's
+ * /proc/bus/i2c for historical compatibility reasons.
+ */
+static void print_i2c_busses(void)
+{
+ struct i2c_adap *adapters;
+ int count;
+
+ adapters = gather_i2c_busses();
+ if (adapters == NULL) {
+ fprintf(stderr, "Error: Out of memory!\n");
+ return;
+ }
+ printf("i2c-id\tfunction \tadapter name\t\t\t\talgorithm\n");
+ for (count = 0; adapters[count].name; count++) {
+ printf("%d\t%-10s\t%-32s\t%s\n",
+ adapters[count].nr, adapters[count].funcs,
+ adapters[count].name, adapters[count].algo);
+ }
+ free_adapters(adapters);
+}
+
+static int scan_i2c_bus(int file, int mode, int first, int last)
+{
+int i, j;
+int res;
+ printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f\n");
+ for (i = 0; i < 128; i += 16) {
+ printf("%02x: ", i);
+ for(j = 0; j < 16; j++) {
+ fflush(stdout);
+
+ /* Skip unwanted addresses */
+ if (i+j < first || i+j > last) {
+ printf(" ");
+ continue;
+ }
+
+ /* Set slave address */
+ if (ioctl(file, I2C_SLAVE, i+j) < 0) {
+ if (errno == EBUSY) {
+ printf("UU ");
+ continue;
+ } else {
+ fprintf(stderr, "Error: Could not set "
+ "address to 0x%02x: %s\n", i+j,
+ strerror(errno));
+ return -1;
+ }
+ }
+
+ /* Probe this address */
+ switch (mode) {
+ case MODE_QUICK:
+ /* This is known to corrupt the Atmel AT24RF08
+ EEPROM */
+ res = i2c_smbus_write_quick(file,
+ I2C_SMBUS_WRITE);
+ break;
+ case MODE_READ:
+ /* This is known to lock SMBus on various
+ write-only chips (mainly clock chips) */
+ res = i2c_smbus_read_byte(file);
+ break;
+ default:
+ if ((i+j >= 0x30 && i+j <= 0x37)
+ || (i+j >= 0x50 && i+j <= 0x5F))
+ res = i2c_smbus_read_byte(file);
+ else
+ res = i2c_smbus_write_quick(file,
+ I2C_SMBUS_WRITE);
+ }
+ if (res < 0)
+ printf("-- ");
+ else
+ printf("%02x ", i+j);
+ }
+ printf("\n");
+ }
+ return 0;
+}
+
+static int check_write_funcs(int file, int size, int pec)
+{
+unsigned long funcs;
+ /* check adapter functionality */
+ if (ioctl(file, I2C_FUNCS, &funcs) < 0) {
+ fprintf(stderr, "Error: Could not get the adapter "
+ "functionality matrix: %s\n", strerror(errno));
+ return -1;
+ }
+ switch (size) {
+ case I2C_SMBUS_BYTE:
+ if (!(funcs & I2C_FUNC_SMBUS_WRITE_BYTE)) {
+ fprintf(stderr, MISSING_FUNC_FMT, "SMBus send byte");
+ return -1;
+ }
+ break;
+ case I2C_SMBUS_BYTE_DATA:
+ if (!(funcs & I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) {
+ fprintf(stderr, MISSING_FUNC_FMT, "SMBus write byte");
+ return -1;
+ }
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ if (!(funcs & I2C_FUNC_SMBUS_WRITE_WORD_DATA)) {
+ fprintf(stderr, MISSING_FUNC_FMT, "SMBus write word");
+ return -1;
+ }
+ break;
+ case I2C_SMBUS_BLOCK_DATA:
+ if (!(funcs & I2C_FUNC_SMBUS_WRITE_BLOCK_DATA)) {
+ fprintf(stderr, MISSING_FUNC_FMT, "SMBus block write");
+ return -1;
+ }
+ break;
+ case I2C_SMBUS_I2C_BLOCK_DATA:
+ if (!(funcs & I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)) {
+ fprintf(stderr, MISSING_FUNC_FMT, "I2C block write");
+ return -1;
+ }
+ break;
+ }
+ if (pec && !(funcs & (I2C_FUNC_SMBUS_PEC | I2C_FUNC_I2C))) {
+ fprintf(stderr, "Warning: Adapter does "
+ "not seem to support PEC\n");
+ }
+ return 0;
+}
+
+static int check_read_funcs(int file, int size, int daddress, int pec)
+{
+unsigned long funcs;
+ /* check adapter functionality */
+ if (ioctl(file, I2C_FUNCS, &funcs) < 0) {
+ fprintf(stderr, "Error: Could not get the adapter "
+ "functionality matrix: %s\n", strerror(errno));
+ return -1;
+ }
+ switch (size) {
+ case I2C_SMBUS_BYTE:
+ if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE)) {
+ fprintf(stderr, MISSING_FUNC_FMT, "SMBus receive byte");
+ return -1;
+ }
+ if (daddress >= 0
+ && !(funcs & I2C_FUNC_SMBUS_WRITE_BYTE)) {
+ fprintf(stderr, MISSING_FUNC_FMT, "SMBus send byte");
+ return -1;
+ }
+ break;
+ case I2C_SMBUS_BYTE_DATA:
+ if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE_DATA)) {
+ fprintf(stderr, MISSING_FUNC_FMT, "SMBus read byte");
+ return -1;
+ }
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ if (!(funcs & I2C_FUNC_SMBUS_READ_WORD_DATA)) {
+ fprintf(stderr, MISSING_FUNC_FMT, "SMBus read word");
+ return -1;
+ }
+ break;
+ }
+ if (pec
+ && !(funcs & (I2C_FUNC_SMBUS_PEC | I2C_FUNC_I2C))) {
+ fprintf(stderr, "Warning: Adapter does "
+ "not seem to support PEC\n");
+ }
+ return 0;
+}
+
+#endif /* for _WITH_I2C */
+/* *********************************************************************/
+
+#include "stackN.h"
+#include "i2c.h"
+#include "err.h"
+
+void IF_listI2C (void)
+{
+#ifdef _WITH_I2C
+ print_i2c_busses();
+#else
+ messErr(49);
+#endif
+}
+
+void IF_showI2C (void)
+{
+long n;
+ if (!getParLong(&n)) return;
+
+#ifdef _WITH_I2C
+int i2cbus, file;
+int mode=MODE_AUTO;
+int first = 0x03, last = 0x77;
+unsigned long funcs;
+char Bus[10], filename[20];
+ sprintf(Bus, "%ld",n);
+ i2cbus = lookup_i2c_bus(Bus);
+ if (i2cbus < 0) messErr(50);
+ else {
+ file = open_i2c_dev(i2cbus, filename, sizeof(filename), 0);
+ if (file < 0) messErr(51);
+ else {
+ if (ioctl(file, I2C_FUNCS, &funcs) < 0) messErr(52);
+ else scan_i2c_bus(file, mode, first, last);
+ close(file);
+ }
+ }
+#else
+ messErr(49);
+#endif
+}
+
+static void i2c_read(int id, int add, int off)
+{
+#ifdef _WITH_I2C
+int i2cbus, file, address, res;
+int size = I2C_SMBUS_BYTE_DATA;
+int pec = 0,force = 0;
+char Buf[10], filename[20];
+ sprintf(Buf, "%ld",id);
+ i2cbus = lookup_i2c_bus(Buf);
+ if (i2cbus < 0) messErr(50);
+ else {
+ sprintf(Buf, "%ld",add);
+ address = parse_i2c_address(Buf);
+ if (address < 0) messErr(53);
+ else {
+ if (off == -1) size = I2C_SMBUS_BYTE;
+ if (off < -1 || off > 0xff) messErr(54);
+ else {
+ file = open_i2c_dev(i2cbus, filename, sizeof(filename), 0);
+ if (file < 0
+ || check_read_funcs(file, size, off, pec)
+ || set_slave_addr(file, address, force)) messErr(51);
+ else {
+ if (size == I2C_SMBUS_BYTE)
+ res = i2c_smbus_read_byte(file);
+ else
+ res = i2c_smbus_read_byte_data(file, off);
+ close(file);
+ if (res < 0) messErr(57);
+ else putLong((long long)res);
+ }
+ }
+ }
+ }
+#else
+ messErr(49);
+#endif
+}
+
+void IF_I2CRead (void)
+{
+long id, add, off;
+ if (!getParLong(&id)) return; /* I2C ID */
+ if (!getParLong(&add)) return; /* CHIP ADDRESS */
+ if (!getParLong(&off)) return; /* DATA ADDRESS (OFFSET) */
+ i2c_read(id, add, off);
+}
+
+static void i2c_write(int id, int add, int off, int val)
+{
+#ifdef _WITH_I2C
+int i2cbus, file, address, res;
+int size = I2C_SMBUS_BYTE_DATA;
+int pec = 0,force = 0;
+char Buf[10], filename[20];
+ sprintf(Buf, "%ld",id);
+ i2cbus = lookup_i2c_bus(Buf);
+ if (i2cbus < 0) messErr(50);
+ else {
+ sprintf(Buf, "%ld",add);
+ address = parse_i2c_address(Buf);
+ if (address < 0) messErr(53);
+ else {
+ if (off < 0 || off > 0xff) messErr(54);
+ else {
+ if (val > 0xff) messErr(55);
+ else {
+ file = open_i2c_dev(i2cbus, filename, sizeof(filename), 0);
+ if (file < 0
+ || check_write_funcs(file, size, pec)
+ || set_slave_addr(file, address, force)) messErr(51);
+ else {
+ res = i2c_smbus_write_byte_data(file, off, val);
+ close(file);
+ if (res < 0) messErr(56);
+ }
+ }
+ }
+ }
+ }
+#else
+ messErr(49);
+#endif
+}
+
+void IF_I2CWrite (void)
+{
+long id, add, off, val;
+ if (!getParLong(&id)) return; /* I2C ID */
+ if (!getParLong(&add)) return; /* CHIP ADDRESS */
+ if (!getParLong(&off)) return; /* DATA ADDRESS (OFFSET) */
+ if (!getParLong(&val)) return; /* DATA BYTE */
+ i2c_write(id, add, off, val);
+ return;
+}
+
+
diff --git a/src/i2c.h b/src/i2c.h
new file mode 100644
index 0000000..b77cd4d
--- /dev/null
+++ b/src/i2c.h
@@ -0,0 +1,26 @@
+/* Copyright (C) 2011-2014 Patrick H. E. Foubet - S.E.R.I.A.N.E.
+
+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 3 of the License, or 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, see
+*******************************************************************/
+/* i2c.h */
+
+#ifndef __NIFE_I2C_H__
+#define __NIFE_I2C_H__
+
+extern void IF_listI2C (void);
+extern void IF_showI2C (void);
+extern void IF_I2CRead (void);
+extern void IF_I2CWrite (void);
+
+#endif
diff --git a/src/i2cbusses.c b/src/i2cbusses.c
new file mode 100644
index 0000000..7a1b7cb
--- /dev/null
+++ b/src/i2cbusses.c
@@ -0,0 +1,416 @@
+/*
+ i2cbusses: Print the installed i2c busses for both 2.4 and 2.6 kernels.
+ Part of user-space programs to access for I2C
+ devices.
+ Copyright (c) 1999-2003 Frodo Looijaard and
+ Mark D. Studebaker
+ Copyright (C) 2008-2012 Jean Delvare
+
+ 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., 51 Franklin Street, Fifth Floor, Boston,
+ MA 02110-1301 USA.
+*/
+
+/* For strdup and snprintf */
+#define _BSD_SOURCE 1
+
+#include
+#include
+#include /* for NAME_MAX */
+#include
+#include
+#include /* for strcasecmp() */
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "i2cbusses.h"
+#include
+
+enum adt { adt_dummy, adt_isa, adt_i2c, adt_smbus, adt_unknown };
+
+struct adap_type {
+ const char *funcs;
+ const char* algo;
+};
+
+static struct adap_type adap_types[5] = {
+ { .funcs = "dummy",
+ .algo = "Dummy bus", },
+ { .funcs = "isa",
+ .algo = "ISA bus", },
+ { .funcs = "i2c",
+ .algo = "I2C adapter", },
+ { .funcs = "smbus",
+ .algo = "SMBus adapter", },
+ { .funcs = "unknown",
+ .algo = "N/A", },
+};
+
+static enum adt i2c_get_funcs(int i2cbus)
+{
+ unsigned long funcs;
+ int file;
+ char filename[20];
+ enum adt ret;
+
+ file = open_i2c_dev(i2cbus, filename, sizeof(filename), 1);
+ if (file < 0)
+ return adt_unknown;
+
+ if (ioctl(file, I2C_FUNCS, &funcs) < 0)
+ ret = adt_unknown;
+ else if (funcs & I2C_FUNC_I2C)
+ ret = adt_i2c;
+ else if (funcs & (I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA |
+ I2C_FUNC_SMBUS_WORD_DATA))
+ ret = adt_smbus;
+ else
+ ret = adt_dummy;
+
+ close(file);
+ return ret;
+}
+
+/* Remove trailing spaces from a string
+ Return the new string length including the trailing NUL */
+static int rtrim(char *s)
+{
+ int i;
+
+ for (i = strlen(s) - 1; i >= 0 && (s[i] == ' ' || s[i] == '\n'); i--)
+ s[i] = '\0';
+ return i + 2;
+}
+
+void free_adapters(struct i2c_adap *adapters)
+{
+ int i;
+
+ for (i = 0; adapters[i].name; i++)
+ free(adapters[i].name);
+ free(adapters);
+}
+
+/* We allocate space for the adapters in bunches. The last item is a
+ terminator, so here we start with room for 7 adapters, which should
+ be enough in most cases. If not, we allocate more later as needed. */
+#define BUNCH 8
+
+/* n must match the size of adapters at calling time */
+static struct i2c_adap *more_adapters(struct i2c_adap *adapters, int n)
+{
+ struct i2c_adap *new_adapters;
+
+ new_adapters = realloc(adapters, (n + BUNCH) * sizeof(struct i2c_adap));
+ if (!new_adapters) {
+ free_adapters(adapters);
+ return NULL;
+ }
+ memset(new_adapters + n, 0, BUNCH * sizeof(struct i2c_adap));
+
+ return new_adapters;
+}
+
+struct i2c_adap *gather_i2c_busses(void)
+{
+ char s[120];
+ struct dirent *de, *dde;
+ DIR *dir, *ddir;
+ FILE *f;
+ char fstype[NAME_MAX], sysfs[NAME_MAX], n[NAME_MAX];
+ int foundsysfs = 0;
+ int count=0;
+ struct i2c_adap *adapters;
+
+ adapters = calloc(BUNCH, sizeof(struct i2c_adap));
+ if (!adapters)
+ return NULL;
+
+ /* look in /proc/bus/i2c */
+ if ((f = fopen("/proc/bus/i2c", "r"))) {
+ while (fgets(s, 120, f)) {
+ char *algo, *name, *type, *all;
+ int len_algo, len_name, len_type;
+ int i2cbus;
+
+ algo = strrchr(s, '\t');
+ *(algo++) = '\0';
+ len_algo = rtrim(algo);
+
+ name = strrchr(s, '\t');
+ *(name++) = '\0';
+ len_name = rtrim(name);
+
+ type = strrchr(s, '\t');
+ *(type++) = '\0';
+ len_type = rtrim(type);
+
+ sscanf(s, "i2c-%d", &i2cbus);
+
+ if ((count + 1) % BUNCH == 0) {
+ /* We need more space */
+ adapters = more_adapters(adapters, count + 1);
+ if (!adapters)
+ return NULL;
+ }
+
+ all = malloc(len_name + len_type + len_algo);
+ if (all == NULL) {
+ free_adapters(adapters);
+ return NULL;
+ }
+ adapters[count].nr = i2cbus;
+ adapters[count].name = strcpy(all, name);
+ adapters[count].funcs = strcpy(all + len_name, type);
+ adapters[count].algo = strcpy(all + len_name + len_type,
+ algo);
+ count++;
+ }
+ fclose(f);
+ goto done;
+ }
+
+ /* look in sysfs */
+ /* First figure out where sysfs was mounted */
+ if ((f = fopen("/proc/mounts", "r")) == NULL) {
+ goto done;
+ }
+ while (fgets(n, NAME_MAX, f)) {
+ sscanf(n, "%*[^ ] %[^ ] %[^ ] %*s\n", sysfs, fstype);
+ if (strcasecmp(fstype, "sysfs") == 0) {
+ foundsysfs++;
+ break;
+ }
+ }
+ fclose(f);
+ if (! foundsysfs) {
+ goto done;
+ }
+
+ /* Bus numbers in i2c-adapter don't necessarily match those in
+ i2c-dev and what we really care about are the i2c-dev numbers.
+ Unfortunately the names are harder to get in i2c-dev */
+ strcat(sysfs, "/class/i2c-dev");
+ if(!(dir = opendir(sysfs)))
+ goto done;
+ /* go through the busses */
+ while ((de = readdir(dir)) != NULL) {
+ if (!strcmp(de->d_name, "."))
+ continue;
+ if (!strcmp(de->d_name, ".."))
+ continue;
+
+ /* this should work for kernels 2.6.5 or higher and */
+ /* is preferred because is unambiguous */
+ sprintf(n, "%s/%s/name", sysfs, de->d_name);
+ f = fopen(n, "r");
+ /* this seems to work for ISA */
+ if(f == NULL) {
+ sprintf(n, "%s/%s/device/name", sysfs, de->d_name);
+ f = fopen(n, "r");
+ }
+ /* non-ISA is much harder */
+ /* and this won't find the correct bus name if a driver
+ has more than one bus */
+ if(f == NULL) {
+ sprintf(n, "%s/%s/device", sysfs, de->d_name);
+ if(!(ddir = opendir(n)))
+ continue;
+ while ((dde = readdir(ddir)) != NULL) {
+ if (!strcmp(dde->d_name, "."))
+ continue;
+ if (!strcmp(dde->d_name, ".."))
+ continue;
+ if ((!strncmp(dde->d_name, "i2c-", 4))) {
+ sprintf(n, "%s/%s/device/%s/name",
+ sysfs, de->d_name, dde->d_name);
+ if((f = fopen(n, "r")))
+ goto found;
+ }
+ }
+ }
+
+found:
+ if (f != NULL) {
+ int i2cbus;
+ enum adt type;
+ char *px;
+
+ px = fgets(s, 120, f);
+ fclose(f);
+ if (!px) {
+ fprintf(stderr, "%s: read error\n", n);
+ continue;
+ }
+ if ((px = strchr(s, '\n')) != NULL)
+ *px = 0;
+ if (!sscanf(de->d_name, "i2c-%d", &i2cbus))
+ continue;
+ if (!strncmp(s, "ISA ", 4)) {
+ type = adt_isa;
+ } else {
+ /* Attempt to probe for adapter capabilities */
+ type = i2c_get_funcs(i2cbus);
+ }
+
+ if ((count + 1) % BUNCH == 0) {
+ /* We need more space */
+ adapters = more_adapters(adapters, count + 1);
+ if (!adapters)
+ return NULL;
+ }
+
+ adapters[count].nr = i2cbus;
+ adapters[count].name = strdup(s);
+ if (adapters[count].name == NULL) {
+ free_adapters(adapters);
+ return NULL;
+ }
+ adapters[count].funcs = adap_types[type].funcs;
+ adapters[count].algo = adap_types[type].algo;
+ count++;
+ }
+ }
+ closedir(dir);
+
+done:
+ return adapters;
+}
+
+static int lookup_i2c_bus_by_name(const char *bus_name)
+{
+ struct i2c_adap *adapters;
+ int i, i2cbus = -1;
+
+ adapters = gather_i2c_busses();
+ if (adapters == NULL) {
+ fprintf(stderr, "Error: Out of memory!\n");
+ return -3;
+ }
+
+ /* Walk the list of i2c busses, looking for the one with the
+ right name */
+ for (i = 0; adapters[i].name; i++) {
+ if (strcmp(adapters[i].name, bus_name) == 0) {
+ if (i2cbus >= 0) {
+ fprintf(stderr,
+ "Error: I2C bus name is not unique!\n");
+ i2cbus = -4;
+ goto done;
+ }
+ i2cbus = adapters[i].nr;
+ }
+ }
+
+ if (i2cbus == -1)
+ fprintf(stderr, "Error: I2C bus name doesn't match any "
+ "bus present!\n");
+
+done:
+ free_adapters(adapters);
+ return i2cbus;
+}
+
+/*
+ * Parse an I2CBUS command line argument and return the corresponding
+ * bus number, or a negative value if the bus is invalid.
+ */
+int lookup_i2c_bus(const char *i2cbus_arg)
+{
+ unsigned long i2cbus;
+ char *end;
+
+ i2cbus = strtoul(i2cbus_arg, &end, 0);
+ if (*end || !*i2cbus_arg) {
+ /* Not a number, maybe a name? */
+ return lookup_i2c_bus_by_name(i2cbus_arg);
+ }
+ if (i2cbus > 0xFFFFF) {
+ fprintf(stderr, "Error: I2C bus out of range!\n");
+ return -2;
+ }
+
+ return i2cbus;
+}
+
+/*
+ * Parse a CHIP-ADDRESS command line argument and return the corresponding
+ * chip address, or a negative value if the address is invalid.
+ */
+int parse_i2c_address(const char *address_arg)
+{
+ long address;
+ char *end;
+
+ address = strtol(address_arg, &end, 0);
+ if (*end || !*address_arg) {
+ fprintf(stderr, "Error: Chip address is not a number!\n");
+ return -1;
+ }
+ if (address < 0x03 || address > 0x77) {
+ fprintf(stderr, "Error: Chip address out of range "
+ "(0x03-0x77)!\n");
+ return -2;
+ }
+
+ return address;
+}
+
+int open_i2c_dev(int i2cbus, char *filename, size_t size, int quiet)
+{
+ int file;
+
+ snprintf(filename, size, "/dev/i2c/%d", i2cbus);
+ filename[size - 1] = '\0';
+ file = open(filename, O_RDWR);
+
+ if (file < 0 && (errno == ENOENT || errno == ENOTDIR)) {
+ sprintf(filename, "/dev/i2c-%d", i2cbus);
+ file = open(filename, O_RDWR);
+ }
+
+ if (file < 0 && !quiet) {
+ if (errno == ENOENT) {
+ fprintf(stderr, "Error: Could not open file "
+ "`/dev/i2c-%d' or `/dev/i2c/%d': %s\n",
+ i2cbus, i2cbus, strerror(ENOENT));
+ } else {
+ fprintf(stderr, "Error: Could not open file "
+ "`%s': %s\n", filename, strerror(errno));
+ if (errno == EACCES)
+ fprintf(stderr, "Run as root?\n");
+ }
+ }
+
+ return file;
+}
+
+int set_slave_addr(int file, int address, int force)
+{
+ /* With force, let the user read from/write to the registers
+ even when a driver is also running */
+ if (ioctl(file, force ? I2C_SLAVE_FORCE : I2C_SLAVE, address) < 0) {
+ fprintf(stderr,
+ "Error: Could not set address to 0x%02x: %s\n",
+ address, strerror(errno));
+ return -errno;
+ }
+
+ return 0;
+}
diff --git a/src/i2cbusses.h b/src/i2cbusses.h
new file mode 100644
index 0000000..26143a5
--- /dev/null
+++ b/src/i2cbusses.h
@@ -0,0 +1,44 @@
+/*
+ i2cbusses.h - Part of the i2c-tools package
+
+ Copyright (C) 2004-2010 Jean Delvare
+
+ 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., 51 Franklin Street, Fifth Floor, Boston,
+ MA 02110-1301 USA.
+*/
+
+#ifndef _I2CBUSSES_H
+#define _I2CBUSSES_H
+
+#include
+
+struct i2c_adap {
+ int nr;
+ char *name;
+ const char *funcs;
+ const char *algo;
+};
+
+struct i2c_adap *gather_i2c_busses(void);
+void free_adapters(struct i2c_adap *adapters);
+
+int lookup_i2c_bus(const char *i2cbus_arg);
+int parse_i2c_address(const char *address_arg);
+int open_i2c_dev(int i2cbus, char *filename, size_t size, int quiet);
+int set_slave_addr(int file, int address, int force);
+
+#define MISSING_FUNC_FMT "Error: Adapter does not have %s capability\n"
+
+#endif