Nife version Beta
Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.
 
 
 
 

375 wiersze
12 KiB

  1. /* Copyright (C) 2011-2014 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. void IF_listI2C (void)
  220. {
  221. #ifdef _WITH_I2C
  222. print_i2c_busses();
  223. #else
  224. messErr(49);
  225. #endif
  226. }
  227. void IF_showI2C (void)
  228. {
  229. long n;
  230. if (!getParLong(&n)) return;
  231. #ifdef _WITH_I2C
  232. int i2cbus, file;
  233. int mode=MODE_AUTO;
  234. int first = 0x03, last = 0x77;
  235. unsigned long funcs;
  236. char Bus[10], filename[20];
  237. sprintf(Bus, "%ld",n);
  238. i2cbus = lookup_i2c_bus(Bus);
  239. if (i2cbus < 0) messErr(50);
  240. else {
  241. file = open_i2c_dev(i2cbus, filename, sizeof(filename), 0);
  242. if (file < 0) messErr(51);
  243. else {
  244. if (ioctl(file, I2C_FUNCS, &funcs) < 0) messErr(52);
  245. else scan_i2c_bus(file, mode, first, last);
  246. close(file);
  247. }
  248. }
  249. #else
  250. messErr(49);
  251. #endif
  252. }
  253. static void i2c_read(int id, int add, int off)
  254. {
  255. #ifdef _WITH_I2C
  256. int i2cbus, file, address, res;
  257. int size = I2C_SMBUS_BYTE_DATA;
  258. int pec = 0,force = 0;
  259. char Buf[10], filename[20];
  260. sprintf(Buf, "%ld",id);
  261. i2cbus = lookup_i2c_bus(Buf);
  262. if (i2cbus < 0) messErr(50);
  263. else {
  264. sprintf(Buf, "%ld",add);
  265. address = parse_i2c_address(Buf);
  266. if (address < 0) messErr(53);
  267. else {
  268. if (off == -1) size = I2C_SMBUS_BYTE;
  269. if (off < -1 || off > 0xff) messErr(54);
  270. else {
  271. file = open_i2c_dev(i2cbus, filename, sizeof(filename), 0);
  272. if (file < 0
  273. || check_read_funcs(file, size, off, pec)
  274. || set_slave_addr(file, address, force)) messErr(51);
  275. else {
  276. if (size == I2C_SMBUS_BYTE)
  277. res = i2c_smbus_read_byte(file);
  278. else
  279. res = i2c_smbus_read_byte_data(file, off);
  280. close(file);
  281. if (res < 0) messErr(57);
  282. else putLong((long long)res);
  283. }
  284. }
  285. }
  286. }
  287. #else
  288. messErr(49);
  289. #endif
  290. }
  291. void IF_I2CRead (void)
  292. {
  293. long id, add, off;
  294. if (!getParLong(&id)) return; /* I2C ID */
  295. if (!getParLong(&add)) return; /* CHIP ADDRESS */
  296. if (!getParLong(&off)) return; /* DATA ADDRESS (OFFSET) */
  297. i2c_read(id, add, off);
  298. }
  299. static void i2c_write(int id, int add, int off, int val)
  300. {
  301. #ifdef _WITH_I2C
  302. int i2cbus, file, address, res;
  303. int size = I2C_SMBUS_BYTE_DATA;
  304. int pec = 0,force = 0;
  305. char Buf[10], filename[20];
  306. sprintf(Buf, "%ld",id);
  307. i2cbus = lookup_i2c_bus(Buf);
  308. if (i2cbus < 0) messErr(50);
  309. else {
  310. sprintf(Buf, "%ld",add);
  311. address = parse_i2c_address(Buf);
  312. if (address < 0) messErr(53);
  313. else {
  314. if (off < 0 || off > 0xff) messErr(54);
  315. else {
  316. if (val > 0xff) messErr(55);
  317. else {
  318. file = open_i2c_dev(i2cbus, filename, sizeof(filename), 0);
  319. if (file < 0
  320. || check_write_funcs(file, size, pec)
  321. || set_slave_addr(file, address, force)) messErr(51);
  322. else {
  323. res = i2c_smbus_write_byte_data(file, off, val);
  324. close(file);
  325. if (res < 0) messErr(56);
  326. }
  327. }
  328. }
  329. }
  330. }
  331. #else
  332. messErr(49);
  333. #endif
  334. }
  335. void IF_I2CWrite (void)
  336. {
  337. long id, add, off, val;
  338. if (!getParLong(&id)) return; /* I2C ID */
  339. if (!getParLong(&add)) return; /* CHIP ADDRESS */
  340. if (!getParLong(&off)) return; /* DATA ADDRESS (OFFSET) */
  341. if (!getParLong(&val)) return; /* DATA BYTE */
  342. i2c_write(id, add, off, val);
  343. return;
  344. }