root/lm-sensors/trunk/prog/dump/i2cset.c @ 4432

Revision 4432, 7.3 KB (checked in by khali, 6 years ago)

Do not force the I2C slave address by default. It's only fair to let the
users know that they're doing something wrong. They can insist by using
the new -f option.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2    i2cset.c - A user-space program to write an I2C register.
3    Copyright (C) 2001-2003  Frodo Looijaard <frodol@dds.nl>, and
4                             Mark D. Studebaker <mdsxyz123@yahoo.com>
5    Copyright (C) 2004-2005  Jean Delvare <khali@linux-fr.org>
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20*/
21
22#include <errno.h>
23#include <string.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <unistd.h>
27#include "i2cbusses.h"
28#include "util.h"
29#include "i2c-dev.h"
30#include "version.h"
31
32void help(void) __attribute__ ((noreturn));
33
34void help(void)
35{
36        fprintf(stderr, "Syntax: i2cset [-f] [-y] I2CBUS CHIP-ADDRESS DATA-ADDRESS "
37                "VALUE [MODE] [MASK]\n"
38                "        i2cset -V\n"
39                "  MODE is 'b[yte]' or 'w[ord]' (default b)\n"
40                "  Append 'p' to MODE for PEC checking\n"
41                "  I2CBUS is an integer\n");
42        print_i2c_busses(0);
43        exit(1);
44}
45
46int main(int argc, char *argv[])
47{
48        char *end;
49        int res, i2cbus, address, size, file;
50        int value, daddress, vmask = 0;
51        int e1;
52        char filename[20];
53        unsigned long funcs;
54        int pec = 0;
55        int flags = 0;
56        int force = 0, yes = 0, version = 0;
57
58        /* handle (optional) flags first */
59        while (1+flags < argc && argv[1+flags][0] == '-') {
60                switch (argv[1+flags][1]) {
61                case 'V': version = 1; break;
62                case 'f': force = 1; break;
63                case 'y': yes = 1; break;
64                default:
65                        fprintf(stderr, "Warning: Unsupported flag "
66                                "\"-%c\"!\n", argv[1+flags][1]);
67                        help();
68                        exit(1);
69                }
70                flags++;
71        }
72
73        if (version) {
74                fprintf(stderr, "i2cset version %s\n", LM_VERSION);
75                exit(0);
76        }
77
78        if (argc < flags + 5)
79                help();
80
81        i2cbus = strtol(argv[flags+1], &end, 0);
82        if (*end || i2cbus < 0 || i2cbus > 0x3f) {
83                fprintf(stderr, "Error: I2CBUS argument invalid!\n");
84                help();
85        }
86
87        address = strtol(argv[flags+2], &end, 0);
88        if (*end || address < 0 || address > 0x7f) {
89                fprintf(stderr, "Error: Chip address invalid!\n");
90                help();
91        }
92
93        daddress = strtol(argv[flags+3], &end, 0);
94        if (*end || daddress < 0 || daddress > 0xff) {
95                fprintf(stderr, "Error: Data address invalid!\n");
96                help();
97        }
98
99        value = strtol(argv[flags+4], &end, 0);
100        if (*end) {
101                fprintf(stderr, "Error: Data value invalid!\n");
102                help();
103        }
104
105        if (argc < flags + 6) {
106                fprintf(stderr, "No size specified (using byte-data access)\n");
107                size = I2C_SMBUS_BYTE_DATA;
108        } else if (argv[flags+5][0] == 'b') {
109                size = I2C_SMBUS_BYTE_DATA;
110                pec = argv[flags+5][1] == 'p';
111        } else if (argv[flags+5][0] == 'w') {
112                size = I2C_SMBUS_WORD_DATA;
113                pec = argv[flags+5][1] == 'p';
114        } else {
115                fprintf(stderr, "Error: Invalid mode!\n");
116                help();
117        }
118
119        if (argc >= flags + 7) {
120                vmask = strtol(argv[flags+6], &end, 0);
121                if (*end || vmask == 0) {
122                        fprintf(stderr, "Error: Data value mask invalid!\n");
123                        help();
124                }
125        }
126
127        if (value < 0
128         || (size == I2C_SMBUS_BYTE_DATA && value > 0xff)
129         || (size == I2C_SMBUS_WORD_DATA && value > 0xffff)) {
130                fprintf(stderr, "Error: Data value out of range!\n");
131                help();
132        }
133
134        file = open_i2c_dev(i2cbus, filename, 0);
135        if (file < 0) {
136                exit(1);
137        }
138
139        /* check adapter functionality */
140        if (ioctl(file, I2C_FUNCS, &funcs) < 0) {
141                fprintf(stderr, "Error: Could not get the adapter "
142                        "functionality matrix: %s\n", strerror(errno));
143                exit(1);
144        }
145
146        switch (size) {
147        case I2C_SMBUS_BYTE_DATA:
148                if (!(funcs & I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) {
149                        fprintf(stderr, "Error: Adapter for i2c bus %d does "
150                                "not have byte write capability\n", i2cbus);
151                        exit(1);
152                }
153                break;
154
155        case I2C_SMBUS_WORD_DATA:
156                if (!(funcs & I2C_FUNC_SMBUS_WRITE_WORD_DATA)) {
157                        fprintf(stderr, "Error: Adapter for i2c bus %d does "
158                                "not have word write capability\n", i2cbus);
159                        exit(1);
160                }
161                break;
162        }
163
164        if (set_slave_addr(file, address, force) < 0)
165                exit(1);
166
167        if (!yes) {
168                int dont = 0;
169
170                fprintf(stderr, "WARNING! This program can confuse your I2C "
171                        "bus, cause data loss and worse!\n");
172
173                if (address >= 0x50 && address <= 0x57) {
174                        fprintf(stderr, "DANGEROUS! Writing to a serial "
175                                "EEPROM on a memory DIMM\nmay render your "
176                                "memory USELESS and make your system "
177                                "UNBOOTABLE!\n");
178                        dont = 1;
179                }
180
181                fprintf(stderr, "I will write to device file %s, chip address "
182                        "0x%02x, data address\n0x%02x, data 0x%02x%s, mode "
183                        "%s.\n", filename, address, daddress, value,
184                        vmask ? " (masked)" : "",
185                        size == I2C_SMBUS_BYTE_DATA ? "byte" : "word");
186                if (pec)
187                        fprintf(stderr, "PEC checking enabled.\n");
188
189                fprintf(stderr, "Continue? [%s] ", dont ? "y/N" : "Y/n");
190                fflush(stderr);
191                if (!user_ack(!dont)) {
192                        fprintf(stderr, "Aborting on user request.\n");
193                        exit(0);
194                }
195        }
196
197        if (vmask) {
198                int oldvalue;
199
200                if (size == I2C_SMBUS_WORD_DATA) {
201                        oldvalue = i2c_smbus_read_word_data(file, daddress);
202                } else {
203                        oldvalue = i2c_smbus_read_byte_data(file, daddress);
204                }
205
206                if (oldvalue < 0) {
207                        fprintf(stderr, "Error: Failed to read old value\n");
208                        exit(1);
209                }
210
211                value = (value & vmask) | (oldvalue & ~vmask);
212
213                if (!yes) {
214                        fprintf(stderr, "Old value 0x%0*x, write mask "
215                                "0x%0*x: Will write 0x%0*x to register "
216                                "0x%02x\n",
217                                size == I2C_SMBUS_WORD_DATA ? 4 : 2, oldvalue,
218                                size == I2C_SMBUS_WORD_DATA ? 4 : 2, vmask,
219                                size == I2C_SMBUS_WORD_DATA ? 4 : 2, value,
220                                daddress);
221
222                        fprintf(stderr, "Continue? [Y/n] ");
223                        fflush(stderr);
224                        if (!user_ack(1)) {
225                                fprintf(stderr, "Aborting on user request.\n");
226                                exit(0);
227                        }
228                }
229        }
230
231        if (pec) {
232                if (ioctl(file, I2C_PEC, 1) < 0) {
233                        fprintf(stderr, "Error: Could not set PEC: %s\n",
234                                strerror(errno));
235                        exit(1);
236                }
237                if (!(funcs & (I2C_FUNC_SMBUS_HWPEC_CALC | I2C_FUNC_I2C))) {
238                        fprintf(stderr, "Warning: Adapter for i2c bus %d does "
239                                "not seem to actually support PEC\n", i2cbus);
240                }
241        }
242
243        e1 = 0;
244        if (size == I2C_SMBUS_WORD_DATA) {
245                res = i2c_smbus_write_word_data(file, daddress, value);
246        } else {
247                res = i2c_smbus_write_byte_data(file, daddress, value);
248        }
249        if (res < 0) {
250                fprintf(stderr, "Warning - write failed\n");
251                e1++;
252        }
253
254        if (pec) {
255                if (ioctl(file, I2C_PEC, 0) < 0) {
256                        fprintf(stderr, "Error: Could not clear PEC: %s\n",
257                                strerror(errno));
258                        close(file);
259                        exit(e1);
260                }
261        }
262
263        if (size == I2C_SMBUS_WORD_DATA) {
264                res = i2c_smbus_read_word_data(file, daddress);
265        } else {
266                res = i2c_smbus_read_byte_data(file, daddress);
267        }
268        close(file);
269
270        if (res < 0) {
271                fprintf(stderr, "Warning - readback failed\n");
272                e1++;
273        } else
274        if (res != value) {
275                e1++;
276                fprintf(stderr, "Warning - data mismatch - wrote "
277                        "0x%0*x, read back 0x%0*x\n",
278                        size == I2C_SMBUS_WORD_DATA ? 4 : 2, value,
279                        size == I2C_SMBUS_WORD_DATA ? 4 : 2, res);
280        } else {
281                fprintf(stderr, "Value 0x%0*x written, readback matched\n",
282                        size == I2C_SMBUS_WORD_DATA ? 4 : 2, value);
283        }
284
285        exit(e1);
286}
Note: See TracBrowser for help on using the browser.