Nife version Beta
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

391 lines
12 KiB

  1. /* Copyright (C) 2011-2022 Patrick H. E. Foubet - S.E.R.I.A.N.E.
  2. This program is free software: you can redistribute it and/or modify
  3. it under the terms of the GNU General Public License as published by
  4. the Free Software Foundation, either version 3 of the License, or any
  5. later version.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  9. GNU General Public License for more details.
  10. You should have received a copy of the GNU General Public License
  11. along with this program. If not, see <http://www.gnu.org/licenses/>
  12. *******************************************************************/
  13. /* i2c.c */
  14. #ifdef HAVE_CONFIG_H
  15. #include "../config.h"
  16. #endif
  17. #ifdef HAVE_LINUX_I2C_DEV_H
  18. #include <linux/i2c-dev.h>
  19. #ifdef I2C_FUNC_I2C
  20. #define _WITH_I2C
  21. #endif
  22. #endif
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26. #include <unistd.h>
  27. #ifdef _WITH_I2C
  28. /*
  29. This part is a merge of Linux i2c-tools code and Nife code.
  30. i2c-tools are user-space programs to detect, scan I2C devices,
  31. and read and/or write an I2C register.
  32. Copyright (C) 2005-2012 Jean Delvare <jdelvare@suse.de>
  33. Copyright (C) 2001-2003 Frodo Looijaard <frodol@dds.nl>, and
  34. Mark D. Studebaker <mdsxyz123@yahoo.com>
  35. Copyright (C) 2004-2005 Jean Delvare
  36. This program is free software; you can redistribute it and/or modify
  37. it under the terms of the GNU General Public License as published by
  38. the Free Software Foundation; either version 2 of the License, or
  39. (at your option) any later version.
  40. This program is distributed in the hope that it will be useful,
  41. but WITHOUT ANY WARRANTY; without even the implied warranty of
  42. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  43. GNU General Public License for more details.
  44. */
  45. #include "i2cbusses.c" /* add code for I2C on Linux */
  46. #define MODE_AUTO 0
  47. #define MODE_QUICK 1
  48. #define MODE_READ 2
  49. #define MODE_FUNC 3
  50. /*
  51. * Print the installed i2c busses. The format is those of Linux 2.4's
  52. * /proc/bus/i2c for historical compatibility reasons.
  53. */
  54. static void print_i2c_busses(void)
  55. {
  56. struct i2c_adap *adapters;
  57. int count;
  58. adapters = gather_i2c_busses();
  59. if (adapters == NULL) {
  60. fprintf(stderr, "Error: Out of memory!\n");
  61. return;
  62. }
  63. printf("i2c-id\tfunction \tadapter name\t\t\t\talgorithm\n");
  64. for (count = 0; adapters[count].name; count++) {
  65. printf("%d\t%-10s\t%-32s\t%s\n",
  66. adapters[count].nr, adapters[count].funcs,
  67. adapters[count].name, adapters[count].algo);
  68. }
  69. free_adapters(adapters);
  70. }
  71. static int scan_i2c_bus(int file, int mode, int first, int last)
  72. {
  73. int i, j;
  74. int res;
  75. printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f\n");
  76. for (i = 0; i < 128; i += 16) {
  77. printf("%02x: ", i);
  78. for(j = 0; j < 16; j++) {
  79. fflush(stdout);
  80. /* Skip unwanted addresses */
  81. if (i+j < first || i+j > last) {
  82. printf(" ");
  83. continue;
  84. }
  85. /* Set slave address */
  86. if (ioctl(file, I2C_SLAVE, i+j) < 0) {
  87. if (errno == EBUSY) {
  88. printf("UU ");
  89. continue;
  90. } else {
  91. fprintf(stderr, "Error: Could not set "
  92. "address to 0x%02x: %s\n", i+j,
  93. strerror(errno));
  94. return -1;
  95. }
  96. }
  97. /* Probe this address */
  98. switch (mode) {
  99. case MODE_QUICK:
  100. /* This is known to corrupt the Atmel AT24RF08
  101. EEPROM */
  102. res = i2c_smbus_write_quick(file,
  103. I2C_SMBUS_WRITE);
  104. break;
  105. case MODE_READ:
  106. /* This is known to lock SMBus on various
  107. write-only chips (mainly clock chips) */
  108. res = i2c_smbus_read_byte(file);
  109. break;
  110. default:
  111. if ((i+j >= 0x30 && i+j <= 0x37)
  112. || (i+j >= 0x50 && i+j <= 0x5F))
  113. res = i2c_smbus_read_byte(file);
  114. else
  115. res = i2c_smbus_write_quick(file,
  116. I2C_SMBUS_WRITE);
  117. }
  118. if (res < 0)
  119. printf("-- ");
  120. else
  121. printf("%02x ", i+j);
  122. }
  123. printf("\n");
  124. }
  125. return 0;
  126. }
  127. static int check_write_funcs(int file, int size, int pec)
  128. {
  129. unsigned long funcs;
  130. /* check adapter functionality */
  131. if (ioctl(file, I2C_FUNCS, &funcs) < 0) {
  132. fprintf(stderr, "Error: Could not get the adapter "
  133. "functionality matrix: %s\n", strerror(errno));
  134. return -1;
  135. }
  136. switch (size) {
  137. case I2C_SMBUS_BYTE:
  138. if (!(funcs & I2C_FUNC_SMBUS_WRITE_BYTE)) {
  139. fprintf(stderr, MISSING_FUNC_FMT, "SMBus send byte");
  140. return -1;
  141. }
  142. break;
  143. case I2C_SMBUS_BYTE_DATA:
  144. if (!(funcs & I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) {
  145. fprintf(stderr, MISSING_FUNC_FMT, "SMBus write byte");
  146. return -1;
  147. }
  148. break;
  149. case I2C_SMBUS_WORD_DATA:
  150. if (!(funcs & I2C_FUNC_SMBUS_WRITE_WORD_DATA)) {
  151. fprintf(stderr, MISSING_FUNC_FMT, "SMBus write word");
  152. return -1;
  153. }
  154. break;
  155. case I2C_SMBUS_BLOCK_DATA:
  156. if (!(funcs & I2C_FUNC_SMBUS_WRITE_BLOCK_DATA)) {
  157. fprintf(stderr, MISSING_FUNC_FMT, "SMBus block write");
  158. return -1;
  159. }
  160. break;
  161. case I2C_SMBUS_I2C_BLOCK_DATA:
  162. if (!(funcs & I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)) {
  163. fprintf(stderr, MISSING_FUNC_FMT, "I2C block write");
  164. return -1;
  165. }
  166. break;
  167. }
  168. if (pec && !(funcs & (I2C_FUNC_SMBUS_PEC | I2C_FUNC_I2C))) {
  169. fprintf(stderr, "Warning: Adapter does "
  170. "not seem to support PEC\n");
  171. }
  172. return 0;
  173. }
  174. static int check_read_funcs(int file, int size, int daddress, int pec)
  175. {
  176. unsigned long funcs;
  177. /* check adapter functionality */
  178. if (ioctl(file, I2C_FUNCS, &funcs) < 0) {
  179. fprintf(stderr, "Error: Could not get the adapter "
  180. "functionality matrix: %s\n", strerror(errno));
  181. return -1;
  182. }
  183. switch (size) {
  184. case I2C_SMBUS_BYTE:
  185. if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE)) {
  186. fprintf(stderr, MISSING_FUNC_FMT, "SMBus receive byte");
  187. return -1;
  188. }
  189. if (daddress >= 0
  190. && !(funcs & I2C_FUNC_SMBUS_WRITE_BYTE)) {
  191. fprintf(stderr, MISSING_FUNC_FMT, "SMBus send byte");
  192. return -1;
  193. }
  194. break;
  195. case I2C_SMBUS_BYTE_DATA:
  196. if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE_DATA)) {
  197. fprintf(stderr, MISSING_FUNC_FMT, "SMBus read byte");
  198. return -1;
  199. }
  200. break;
  201. case I2C_SMBUS_WORD_DATA:
  202. if (!(funcs & I2C_FUNC_SMBUS_READ_WORD_DATA)) {
  203. fprintf(stderr, MISSING_FUNC_FMT, "SMBus read word");
  204. return -1;
  205. }
  206. break;
  207. }
  208. if (pec
  209. && !(funcs & (I2C_FUNC_SMBUS_PEC | I2C_FUNC_I2C))) {
  210. fprintf(stderr, "Warning: Adapter does "
  211. "not seem to support PEC\n");
  212. }
  213. return 0;
  214. }
  215. #endif /* for _WITH_I2C */
  216. /* *********************************************************************/
  217. #include "stackN.h"
  218. #include "i2c.h"
  219. #include "err.h"
  220. #include "debug.h"
  221. void IF_listI2C (void)
  222. {
  223. #ifdef _WITH_I2C
  224. print_i2c_busses();
  225. #else
  226. messErr(49);
  227. #endif
  228. }
  229. void IFD_listI2C (void)
  230. {
  231. _IFD_BEGIN_
  232. IF_listI2C();
  233. _IFD_END_
  234. }
  235. void IF_showI2C (void)
  236. {
  237. long n;
  238. if (!getParLong(&n)) return;
  239. #ifdef _WITH_I2C
  240. int i2cbus, file;
  241. int mode=MODE_AUTO;
  242. int first = 0x03, last = 0x77;
  243. unsigned long funcs;
  244. char Bus[10], filename[20];
  245. sprintf(Bus, "%ld",n);
  246. i2cbus = lookup_i2c_bus(Bus);
  247. if (i2cbus < 0) messErr(50);
  248. else {
  249. file = open_i2c_dev(i2cbus, filename, sizeof(filename), 0);
  250. if (file < 0) messErr(51);
  251. else {
  252. if (ioctl(file, I2C_FUNCS, &funcs) < 0) messErr(52);
  253. else scan_i2c_bus(file, mode, first, last);
  254. close(file);
  255. }
  256. }
  257. #else
  258. messErr(49);
  259. #endif
  260. }
  261. void IFD_showI2C (void)
  262. {
  263. _IFD_BEGIN_
  264. IF_showI2C();
  265. _IFD_END_
  266. }
  267. static void i2c_read(int id, int add, int off)
  268. {
  269. #ifdef _WITH_I2C
  270. int i2cbus, file, address, res;
  271. int size = I2C_SMBUS_BYTE_DATA;
  272. int pec = 0,force = 0;
  273. char Buf[10], filename[20];
  274. sprintf(Buf, "%ld",id);
  275. i2cbus = lookup_i2c_bus(Buf);
  276. if (i2cbus < 0) messErr(50);
  277. else {
  278. sprintf(Buf, "%ld",add);
  279. address = parse_i2c_address(Buf);
  280. if (address < 0) messErr(53);
  281. else {
  282. if (off == -1) size = I2C_SMBUS_BYTE;
  283. if (off < -1 || off > 0xff) messErr(54);
  284. else {
  285. file = open_i2c_dev(i2cbus, filename, sizeof(filename), 0);
  286. if (file < 0
  287. || check_read_funcs(file, size, off, pec)
  288. || set_slave_addr(file, address, force)) messErr(51);
  289. else {
  290. if (size == I2C_SMBUS_BYTE)
  291. res = i2c_smbus_read_byte(file);
  292. else
  293. res = i2c_smbus_read_byte_data(file, off);
  294. close(file);
  295. if (res < 0) messErr(57);
  296. else putLong((long long)res);
  297. }
  298. }
  299. }
  300. }
  301. #else
  302. messErr(49);
  303. #endif
  304. }
  305. void IF_I2CRead (void)
  306. {
  307. long id, add, off;
  308. if (!getParLong(&id)) return; /* I2C ID */
  309. if (!getParLong(&add)) return; /* CHIP ADDRESS */
  310. if (!getParLong(&off)) return; /* DATA ADDRESS (OFFSET) */
  311. i2c_read(id, add, off);
  312. }
  313. static void i2c_write(int id, int add, int off, int val)
  314. {
  315. #ifdef _WITH_I2C
  316. int i2cbus, file, address, res;
  317. int size = I2C_SMBUS_BYTE_DATA;
  318. int pec = 0,force = 0;
  319. char Buf[10], filename[20];
  320. sprintf(Buf, "%ld",id);
  321. i2cbus = lookup_i2c_bus(Buf);
  322. if (i2cbus < 0) messErr(50);
  323. else {
  324. sprintf(Buf, "%ld",add);
  325. address = parse_i2c_address(Buf);
  326. if (address < 0) messErr(53);
  327. else {
  328. if (off < 0 || off > 0xff) messErr(54);
  329. else {
  330. if (val > 0xff) messErr(55);
  331. else {
  332. file = open_i2c_dev(i2cbus, filename, sizeof(filename), 0);
  333. if (file < 0
  334. || check_write_funcs(file, size, pec)
  335. || set_slave_addr(file, address, force)) messErr(51);
  336. else {
  337. res = i2c_smbus_write_byte_data(file, off, val);
  338. close(file);
  339. if (res < 0) messErr(56);
  340. }
  341. }
  342. }
  343. }
  344. }
  345. #else
  346. messErr(49);
  347. #endif
  348. }
  349. void IF_I2CWrite (void)
  350. {
  351. long id, add, off, val;
  352. if (!getParLong(&id)) return; /* I2C ID */
  353. if (!getParLong(&add)) return; /* CHIP ADDRESS */
  354. if (!getParLong(&off)) return; /* DATA ADDRESS (OFFSET) */
  355. if (!getParLong(&val)) return; /* DATA BYTE */
  356. i2c_write(id, add, off, val);
  357. return;
  358. }