| @@ -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 | |||
| ; | |||
| @@ -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 <http://www.gnu.org/licenses/> | |||
| *******************************************************************/ | |||
| /* i2c.c */ | |||
| #ifdef HAVE_CONFIG_H | |||
| #include "../config.h" | |||
| #endif | |||
| #ifdef HAVE_LINUX_I2C_DEV_H | |||
| #include <linux/i2c-dev.h> | |||
| #ifdef I2C_FUNC_I2C | |||
| #define _WITH_I2C | |||
| #endif | |||
| #endif | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #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 <jdelvare@suse.de> | |||
| Copyright (C) 2001-2003 Frodo Looijaard <frodol@dds.nl>, and | |||
| Mark D. Studebaker <mdsxyz123@yahoo.com> | |||
| 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; | |||
| } | |||
| @@ -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 <http://www.gnu.org/licenses/> | |||
| *******************************************************************/ | |||
| /* 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 | |||
| @@ -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 <frodol@dds.nl> and | |||
| Mark D. Studebaker <mdsxyz123@yahoo.com> | |||
| Copyright (C) 2008-2012 Jean Delvare <jdelvare@suse.de> | |||
| 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 <sys/types.h> | |||
| #include <sys/stat.h> | |||
| #include <sys/param.h> /* for NAME_MAX */ | |||
| #include <sys/ioctl.h> | |||
| #include <string.h> | |||
| #include <strings.h> /* for strcasecmp() */ | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <unistd.h> | |||
| #include <limits.h> | |||
| #include <dirent.h> | |||
| #include <fcntl.h> | |||
| #include <errno.h> | |||
| #include "i2cbusses.h" | |||
| #include <linux/i2c-dev.h> | |||
| 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; | |||
| } | |||
| @@ -0,0 +1,44 @@ | |||
| /* | |||
| i2cbusses.h - Part of the i2c-tools package | |||
| Copyright (C) 2004-2010 Jean Delvare <jdelvare@suse.de> | |||
| 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 <unistd.h> | |||
| 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 | |||