From 3d29217ef37449898cc59b08c50119936a9c8e69 Mon Sep 17 00:00:00 2001 From: "Patrick H. E. Foubet" Date: Sun, 11 May 2014 00:03:07 +0200 Subject: [PATCH] Version 0.47 --- src/ex/testi2c.nif | 30 ++++ src/i2c.c | 374 ++++++++++++++++++++++++++++++++++++++++ src/i2c.h | 26 +++ src/i2cbusses.c | 416 +++++++++++++++++++++++++++++++++++++++++++++ src/i2cbusses.h | 44 +++++ 5 files changed, 890 insertions(+) create mode 100644 src/ex/testi2c.nif create mode 100644 src/i2c.c create mode 100644 src/i2c.h create mode 100644 src/i2cbusses.c create mode 100644 src/i2cbusses.h 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