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.
 
 
 
 

390 lines
12 KiB

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