i2c_tools.c 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * Minimal i2c-tools implementation for busybox.
  4. * Parts of code ported from i2c-tools:
  5. * http://www.lm-sensors.org/wiki/I2CTools.
  6. *
  7. * Copyright (C) 2014 by Bartosz Golaszewski <bartekgola@gmail.com>
  8. *
  9. * Licensed under GPLv2 or later, see file LICENSE in this source tree.
  10. */
  11. //config:config I2CGET
  12. //config: bool "i2cget (5.6 kb)"
  13. //config: default y
  14. //config: select PLATFORM_LINUX
  15. //config: help
  16. //config: Read from I2C/SMBus chip registers.
  17. //config:
  18. //config:config I2CSET
  19. //config: bool "i2cset (6.9 kb)"
  20. //config: default y
  21. //config: select PLATFORM_LINUX
  22. //config: help
  23. //config: Set I2C registers.
  24. //config:
  25. //config:config I2CDUMP
  26. //config: bool "i2cdump (7.2 kb)"
  27. //config: default y
  28. //config: select PLATFORM_LINUX
  29. //config: help
  30. //config: Examine I2C registers.
  31. //config:
  32. //config:config I2CDETECT
  33. //config: bool "i2cdetect (7.2 kb)"
  34. //config: default y
  35. //config: select PLATFORM_LINUX
  36. //config: help
  37. //config: Detect I2C chips.
  38. //config:
  39. //applet:IF_I2CGET(APPLET(i2cget, BB_DIR_USR_SBIN, BB_SUID_DROP))
  40. //applet:IF_I2CSET(APPLET(i2cset, BB_DIR_USR_SBIN, BB_SUID_DROP))
  41. //applet:IF_I2CDUMP(APPLET(i2cdump, BB_DIR_USR_SBIN, BB_SUID_DROP))
  42. //applet:IF_I2CDETECT(APPLET(i2cdetect, BB_DIR_USR_SBIN, BB_SUID_DROP))
  43. /* not NOEXEC: if hw operation stalls, use less memory in "hung" process */
  44. //kbuild:lib-$(CONFIG_I2CGET) += i2c_tools.o
  45. //kbuild:lib-$(CONFIG_I2CSET) += i2c_tools.o
  46. //kbuild:lib-$(CONFIG_I2CDUMP) += i2c_tools.o
  47. //kbuild:lib-$(CONFIG_I2CDETECT) += i2c_tools.o
  48. /*
  49. * Unsupported stuff:
  50. *
  51. * - upstream i2c-tools can also look-up i2c busses by name, we only accept
  52. * numbers,
  53. * - bank and bankreg parameters for i2cdump are not supported because of
  54. * their limited usefulness (see i2cdump manual entry for more info),
  55. * - i2cdetect doesn't look for bus info in /proc as it does in upstream, but
  56. * it shouldn't be a problem in modern kernels.
  57. */
  58. #include "libbb.h"
  59. #include <linux/i2c.h>
  60. #define I2CDUMP_NUM_REGS 256
  61. #define I2CDETECT_MODE_AUTO 0
  62. #define I2CDETECT_MODE_QUICK 1
  63. #define I2CDETECT_MODE_READ 2
  64. /* linux/i2c-dev.h from i2c-tools overwrites the one from linux uapi
  65. * and defines symbols already defined by linux/i2c.h.
  66. * Also, it defines a bunch of static inlines which we would rather NOT
  67. * inline. What a mess.
  68. * We need only these definitions from linux/i2c-dev.h:
  69. */
  70. #define I2C_SLAVE 0x0703
  71. #define I2C_SLAVE_FORCE 0x0706
  72. #define I2C_FUNCS 0x0705
  73. #define I2C_PEC 0x0708
  74. #define I2C_SMBUS 0x0720
  75. struct i2c_smbus_ioctl_data {
  76. __u8 read_write;
  77. __u8 command;
  78. __u32 size;
  79. union i2c_smbus_data *data;
  80. };
  81. /* end linux/i2c-dev.h */
  82. /*
  83. * This is needed for ioctl_or_perror_and_die() since it only accepts pointers.
  84. */
  85. static ALWAYS_INLINE void *itoptr(int i)
  86. {
  87. return (void*)(intptr_t)i;
  88. }
  89. static int32_t i2c_smbus_access(int fd, char read_write, uint8_t cmd,
  90. int size, union i2c_smbus_data *data)
  91. {
  92. struct i2c_smbus_ioctl_data args;
  93. args.read_write = read_write;
  94. args.command = cmd;
  95. args.size = size;
  96. args.data = data;
  97. return ioctl(fd, I2C_SMBUS, &args);
  98. }
  99. static int32_t i2c_smbus_read_byte(int fd)
  100. {
  101. union i2c_smbus_data data;
  102. int err;
  103. err = i2c_smbus_access(fd, I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, &data);
  104. if (err < 0)
  105. return err;
  106. return data.byte;
  107. }
  108. #if ENABLE_I2CGET || ENABLE_I2CSET || ENABLE_I2CDUMP
  109. static int32_t i2c_smbus_write_byte(int fd, uint8_t val)
  110. {
  111. return i2c_smbus_access(fd, I2C_SMBUS_WRITE,
  112. val, I2C_SMBUS_BYTE, NULL);
  113. }
  114. static int32_t i2c_smbus_read_byte_data(int fd, uint8_t cmd)
  115. {
  116. union i2c_smbus_data data;
  117. int err;
  118. err = i2c_smbus_access(fd, I2C_SMBUS_READ, cmd,
  119. I2C_SMBUS_BYTE_DATA, &data);
  120. if (err < 0)
  121. return err;
  122. return data.byte;
  123. }
  124. static int32_t i2c_smbus_read_word_data(int fd, uint8_t cmd)
  125. {
  126. union i2c_smbus_data data;
  127. int err;
  128. err = i2c_smbus_access(fd, I2C_SMBUS_READ, cmd,
  129. I2C_SMBUS_WORD_DATA, &data);
  130. if (err < 0)
  131. return err;
  132. return data.word;
  133. }
  134. #endif /* ENABLE_I2CGET || ENABLE_I2CSET || ENABLE_I2CDUMP */
  135. #if ENABLE_I2CSET
  136. static int32_t i2c_smbus_write_byte_data(int file,
  137. uint8_t cmd, uint8_t value)
  138. {
  139. union i2c_smbus_data data;
  140. data.byte = value;
  141. return i2c_smbus_access(file, I2C_SMBUS_WRITE, cmd,
  142. I2C_SMBUS_BYTE_DATA, &data);
  143. }
  144. static int32_t i2c_smbus_write_word_data(int file, uint8_t cmd, uint16_t value)
  145. {
  146. union i2c_smbus_data data;
  147. data.word = value;
  148. return i2c_smbus_access(file, I2C_SMBUS_WRITE, cmd,
  149. I2C_SMBUS_WORD_DATA, &data);
  150. }
  151. static int32_t i2c_smbus_write_block_data(int file, uint8_t cmd,
  152. uint8_t length, const uint8_t *values)
  153. {
  154. union i2c_smbus_data data;
  155. if (length > I2C_SMBUS_BLOCK_MAX)
  156. length = I2C_SMBUS_BLOCK_MAX;
  157. memcpy(data.block+1, values, length);
  158. data.block[0] = length;
  159. return i2c_smbus_access(file, I2C_SMBUS_WRITE, cmd,
  160. I2C_SMBUS_BLOCK_DATA, &data);
  161. }
  162. static int32_t i2c_smbus_write_i2c_block_data(int file, uint8_t cmd,
  163. uint8_t length, const uint8_t *values)
  164. {
  165. union i2c_smbus_data data;
  166. if (length > I2C_SMBUS_BLOCK_MAX)
  167. length = I2C_SMBUS_BLOCK_MAX;
  168. memcpy(data.block+1, values, length);
  169. data.block[0] = length;
  170. return i2c_smbus_access(file, I2C_SMBUS_WRITE, cmd,
  171. I2C_SMBUS_I2C_BLOCK_BROKEN, &data);
  172. }
  173. #endif /* ENABLE_I2CSET */
  174. #if ENABLE_I2CDUMP
  175. /*
  176. * Returns the number of bytes read, vals must hold at
  177. * least I2C_SMBUS_BLOCK_MAX bytes.
  178. */
  179. static int32_t i2c_smbus_read_block_data(int fd, uint8_t cmd, uint8_t *vals)
  180. {
  181. union i2c_smbus_data data;
  182. int i, err;
  183. err = i2c_smbus_access(fd, I2C_SMBUS_READ, cmd,
  184. I2C_SMBUS_BLOCK_DATA, &data);
  185. if (err < 0)
  186. return err;
  187. for (i = 1; i <= data.block[0]; i++)
  188. *vals++ = data.block[i];
  189. return data.block[0];
  190. }
  191. static int32_t i2c_smbus_read_i2c_block_data(int fd, uint8_t cmd,
  192. uint8_t len, uint8_t *vals)
  193. {
  194. union i2c_smbus_data data;
  195. int i, err;
  196. if (len > I2C_SMBUS_BLOCK_MAX)
  197. len = I2C_SMBUS_BLOCK_MAX;
  198. data.block[0] = len;
  199. err = i2c_smbus_access(fd, I2C_SMBUS_READ, cmd,
  200. len == 32 ? I2C_SMBUS_I2C_BLOCK_BROKEN :
  201. I2C_SMBUS_I2C_BLOCK_DATA, &data);
  202. if (err < 0)
  203. return err;
  204. for (i = 1; i <= data.block[0]; i++)
  205. *vals++ = data.block[i];
  206. return data.block[0];
  207. }
  208. #endif /* ENABLE_I2CDUMP */
  209. #if ENABLE_I2CDETECT
  210. static int32_t i2c_smbus_write_quick(int fd, uint8_t val)
  211. {
  212. return i2c_smbus_access(fd, val, 0, I2C_SMBUS_QUICK, NULL);
  213. }
  214. #endif /* ENABLE_I2CDETECT */
  215. static int i2c_bus_lookup(const char *bus_str)
  216. {
  217. return xstrtou_range(bus_str, 10, 0, 0xfffff);
  218. }
  219. #if ENABLE_I2CGET || ENABLE_I2CSET || ENABLE_I2CDUMP
  220. static int i2c_parse_bus_addr(const char *addr_str)
  221. {
  222. /* Slave address must be in range 0x03 - 0x77. */
  223. return xstrtou_range(addr_str, 16, 0x03, 0x77);
  224. }
  225. static void i2c_set_pec(int fd, int pec)
  226. {
  227. ioctl_or_perror_and_die(fd, I2C_PEC,
  228. itoptr(pec ? 1 : 0),
  229. "can't set PEC");
  230. }
  231. static void i2c_set_slave_addr(int fd, int addr, int force)
  232. {
  233. ioctl_or_perror_and_die(fd, force ? I2C_SLAVE_FORCE : I2C_SLAVE,
  234. itoptr(addr),
  235. "can't set address to 0x%02x", addr);
  236. }
  237. #endif /* ENABLE_I2CGET || ENABLE_I2CSET || ENABLE_I2CDUMP */
  238. #if ENABLE_I2CGET || ENABLE_I2CSET
  239. static int i2c_parse_data_addr(const char *data_addr)
  240. {
  241. /* Data address must be an 8 bit integer. */
  242. return xstrtou_range(data_addr, 16, 0, 0xff);
  243. }
  244. #endif /* ENABLE_I2CGET || ENABLE_I2CSET */
  245. /*
  246. * Opens the device file associated with given i2c bus.
  247. *
  248. * Upstream i2c-tools also support opening devices by i2c bus name
  249. * but we drop it here for size reduction.
  250. */
  251. static int i2c_dev_open(int i2cbus)
  252. {
  253. char filename[sizeof("/dev/i2c-%d") + sizeof(int)*3];
  254. int fd;
  255. sprintf(filename, "/dev/i2c-%d", i2cbus);
  256. fd = open(filename, O_RDWR);
  257. if (fd < 0) {
  258. if (errno == ENOENT) {
  259. filename[8] = '/'; /* change to "/dev/i2c/%d" */
  260. fd = xopen(filename, O_RDWR);
  261. } else {
  262. bb_perror_msg_and_die("can't open '%s'", filename);
  263. }
  264. }
  265. return fd;
  266. }
  267. /* Size reducing helpers for xxx_check_funcs(). */
  268. static void get_funcs_matrix(int fd, unsigned long *funcs)
  269. {
  270. ioctl_or_perror_and_die(fd, I2C_FUNCS, funcs,
  271. "can't get adapter functionality matrix");
  272. }
  273. #if ENABLE_I2CGET || ENABLE_I2CSET || ENABLE_I2CDUMP
  274. static void check_funcs_test_end(int funcs, int pec, const char *err)
  275. {
  276. if (pec && !(funcs & (I2C_FUNC_SMBUS_PEC | I2C_FUNC_I2C)))
  277. bb_error_msg("warning: adapter does not support PEC");
  278. if (err)
  279. bb_error_msg_and_die(
  280. "adapter has no %s capability", err);
  281. }
  282. #endif /* ENABLE_I2CGET || ENABLE_I2CSET || ENABLE_I2CDUMP */
  283. /*
  284. * The below functions emit an error message and exit if the adapter doesn't
  285. * support desired functionalities.
  286. */
  287. #if ENABLE_I2CGET || ENABLE_I2CDUMP
  288. static void check_read_funcs(int fd, int mode, int data_addr, int pec)
  289. {
  290. unsigned long funcs;
  291. const char *err = NULL;
  292. get_funcs_matrix(fd, &funcs);
  293. switch (mode) {
  294. case I2C_SMBUS_BYTE:
  295. if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE)) {
  296. err = "SMBus receive byte";
  297. break;
  298. }
  299. if (data_addr >= 0 && !(funcs & I2C_FUNC_SMBUS_WRITE_BYTE))
  300. err = "SMBus send byte";
  301. break;
  302. case I2C_SMBUS_BYTE_DATA:
  303. if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE_DATA))
  304. err = "SMBus read byte";
  305. break;
  306. case I2C_SMBUS_WORD_DATA:
  307. if (!(funcs & I2C_FUNC_SMBUS_READ_WORD_DATA))
  308. err = "SMBus read word";
  309. break;
  310. #if ENABLE_I2CDUMP
  311. case I2C_SMBUS_BLOCK_DATA:
  312. if (!(funcs & I2C_FUNC_SMBUS_READ_BLOCK_DATA))
  313. err = "SMBus block read";
  314. break;
  315. case I2C_SMBUS_I2C_BLOCK_DATA:
  316. if (!(funcs & I2C_FUNC_SMBUS_READ_I2C_BLOCK))
  317. err = "I2C block read";
  318. break;
  319. #endif /* ENABLE_I2CDUMP */
  320. default:
  321. bb_error_msg_and_die("internal error");
  322. }
  323. check_funcs_test_end(funcs, pec, err);
  324. }
  325. #endif /* ENABLE_I2CGET || ENABLE_I2CDUMP */
  326. #if ENABLE_I2CSET
  327. static void check_write_funcs(int fd, int mode, int pec)
  328. {
  329. unsigned long funcs;
  330. const char *err = NULL;
  331. get_funcs_matrix(fd, &funcs);
  332. switch (mode) {
  333. case I2C_SMBUS_BYTE:
  334. if (!(funcs & I2C_FUNC_SMBUS_WRITE_BYTE))
  335. err = "SMBus send byte";
  336. break;
  337. case I2C_SMBUS_BYTE_DATA:
  338. if (!(funcs & I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
  339. err = "SMBus write byte";
  340. break;
  341. case I2C_SMBUS_WORD_DATA:
  342. if (!(funcs & I2C_FUNC_SMBUS_WRITE_WORD_DATA))
  343. err = "SMBus write word";
  344. break;
  345. case I2C_SMBUS_BLOCK_DATA:
  346. if (!(funcs & I2C_FUNC_SMBUS_WRITE_BLOCK_DATA))
  347. err = "SMBus block write";
  348. break;
  349. case I2C_SMBUS_I2C_BLOCK_DATA:
  350. if (!(funcs & I2C_FUNC_SMBUS_WRITE_I2C_BLOCK))
  351. err = "I2C block write";
  352. break;
  353. }
  354. check_funcs_test_end(funcs, pec, err);
  355. }
  356. #endif /* ENABLE_I2CSET */
  357. static void confirm_or_abort(void)
  358. {
  359. fprintf(stderr, "Continue? [y/N] ");
  360. fflush_all();
  361. if (!bb_ask_confirmation())
  362. bb_error_msg_and_die("aborting");
  363. }
  364. /*
  365. * Return only if user confirms the action, abort otherwise.
  366. *
  367. * The messages displayed here are much less elaborate than their i2c-tools
  368. * counterparts - this is done for size reduction.
  369. */
  370. static void confirm_action(int bus_addr, int mode, int data_addr, int pec)
  371. {
  372. bb_error_msg("WARNING! This program can confuse your I2C bus");
  373. /* Don't let the user break his/her EEPROMs */
  374. if (bus_addr >= 0x50 && bus_addr <= 0x57 && pec) {
  375. bb_error_msg_and_die("this is I2C not smbus - using PEC on I2C "
  376. "devices may result in data loss, aborting");
  377. }
  378. if (mode == I2C_SMBUS_BYTE && data_addr >= 0 && pec)
  379. bb_error_msg("WARNING! May interpret a write byte command "
  380. "with PEC as a write byte data command");
  381. if (pec)
  382. bb_error_msg("PEC checking enabled");
  383. confirm_or_abort();
  384. }
  385. #if ENABLE_I2CGET
  386. //usage:#define i2cget_trivial_usage
  387. //usage: "[-fy] BUS CHIP-ADDRESS [DATA-ADDRESS [MODE]]"
  388. //usage:#define i2cget_full_usage "\n\n"
  389. //usage: "Read from I2C/SMBus chip registers"
  390. //usage: "\n"
  391. //usage: "\n I2CBUS I2C bus number"
  392. //usage: "\n ADDRESS 0x03-0x77"
  393. //usage: "\nMODE is:"
  394. //usage: "\n b Read byte data (default)"
  395. //usage: "\n w Read word data"
  396. //usage: "\n c Write byte/read byte"
  397. //usage: "\n Append p for SMBus PEC"
  398. //usage: "\n"
  399. //usage: "\n -f Force access"
  400. //usage: "\n -y Disable interactive mode"
  401. int i2cget_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  402. int i2cget_main(int argc UNUSED_PARAM, char **argv)
  403. {
  404. const unsigned opt_f = (1 << 0), opt_y = (1 << 1);
  405. int bus_num, bus_addr, data_addr = -1, status;
  406. int mode = I2C_SMBUS_BYTE, pec = 0, fd;
  407. unsigned opts;
  408. opts = getopt32(argv, "^" "fy" "\0" "-2:?4"/*from 2 to 4 args*/);
  409. argv += optind;
  410. bus_num = i2c_bus_lookup(argv[0]);
  411. bus_addr = i2c_parse_bus_addr(argv[1]);
  412. if (argv[2]) {
  413. data_addr = i2c_parse_data_addr(argv[2]);
  414. mode = I2C_SMBUS_BYTE_DATA;
  415. if (argv[3]) {
  416. switch (argv[3][0]) {
  417. case 'b': /* Already set */ break;
  418. case 'w': mode = I2C_SMBUS_WORD_DATA; break;
  419. case 'c': mode = I2C_SMBUS_BYTE; break;
  420. default:
  421. bb_error_msg("invalid mode");
  422. bb_show_usage();
  423. }
  424. pec = argv[3][1] == 'p';
  425. }
  426. }
  427. fd = i2c_dev_open(bus_num);
  428. check_read_funcs(fd, mode, data_addr, pec);
  429. i2c_set_slave_addr(fd, bus_addr, opts & opt_f);
  430. if (!(opts & opt_y))
  431. confirm_action(bus_addr, mode, data_addr, pec);
  432. if (pec)
  433. i2c_set_pec(fd, 1);
  434. switch (mode) {
  435. case I2C_SMBUS_BYTE:
  436. if (data_addr >= 0) {
  437. status = i2c_smbus_write_byte(fd, data_addr);
  438. if (status < 0)
  439. bb_error_msg("warning - write failed");
  440. }
  441. status = i2c_smbus_read_byte(fd);
  442. break;
  443. case I2C_SMBUS_WORD_DATA:
  444. status = i2c_smbus_read_word_data(fd, data_addr);
  445. break;
  446. default: /* I2C_SMBUS_BYTE_DATA */
  447. status = i2c_smbus_read_byte_data(fd, data_addr);
  448. }
  449. close(fd);
  450. if (status < 0)
  451. bb_perror_msg_and_die("read failed");
  452. printf("0x%0*x\n", mode == I2C_SMBUS_WORD_DATA ? 4 : 2, status);
  453. return 0;
  454. }
  455. #endif /* ENABLE_I2CGET */
  456. #if ENABLE_I2CSET
  457. //usage:#define i2cset_trivial_usage
  458. //usage: "[-fy] [-m MASK] BUS CHIP-ADDRESS DATA-ADDRESS [VALUE] ... [MODE]"
  459. //usage:#define i2cset_full_usage "\n\n"
  460. //usage: "Set I2C registers"
  461. //usage: "\n"
  462. //usage: "\n I2CBUS I2C bus number"
  463. //usage: "\n ADDRESS 0x03-0x77"
  464. //usage: "\nMODE is:"
  465. //usage: "\n c Byte, no value"
  466. //usage: "\n b Byte data (default)"
  467. //usage: "\n w Word data"
  468. //usage: "\n i I2C block data"
  469. //usage: "\n s SMBus block data"
  470. //usage: "\n Append p for SMBus PEC"
  471. //usage: "\n"
  472. //usage: "\n -f Force access"
  473. //usage: "\n -y Disable interactive mode"
  474. //usage: "\n -r Read back and compare the result"
  475. //usage: "\n -m MASK Mask specifying which bits to write"
  476. int i2cset_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  477. int i2cset_main(int argc, char **argv)
  478. {
  479. const unsigned opt_f = (1 << 0), opt_y = (1 << 1),
  480. opt_m = (1 << 2), opt_r = (1 << 3);
  481. int bus_num, bus_addr, data_addr, mode = I2C_SMBUS_BYTE, pec = 0;
  482. int val, blen, mask, fd, status;
  483. unsigned char block[I2C_SMBUS_BLOCK_MAX];
  484. char *opt_m_arg = NULL;
  485. unsigned opts;
  486. opts = getopt32(argv, "^"
  487. "fym:r"
  488. "\0" "-3", /* minimum 3 args */
  489. &opt_m_arg
  490. );
  491. argv += optind;
  492. argc -= optind;
  493. argc--; /* now argv[argc] is last arg */
  494. bus_num = i2c_bus_lookup(argv[0]);
  495. bus_addr = i2c_parse_bus_addr(argv[1]);
  496. data_addr = i2c_parse_data_addr(argv[2]);
  497. if (argv[3]) {
  498. if (!argv[4] && argv[3][0] != 'c') {
  499. mode = I2C_SMBUS_BYTE_DATA; /* Implicit b */
  500. } else {
  501. switch (argv[argc][0]) {
  502. case 'c': /* Already set */
  503. break;
  504. case 'b': mode = I2C_SMBUS_BYTE_DATA;
  505. break;
  506. case 'w': mode = I2C_SMBUS_WORD_DATA;
  507. break;
  508. case 's': mode = I2C_SMBUS_BLOCK_DATA;
  509. break;
  510. case 'i': mode = I2C_SMBUS_I2C_BLOCK_DATA;
  511. break;
  512. default:
  513. bb_error_msg("invalid mode");
  514. bb_show_usage();
  515. }
  516. pec = (argv[argc][1] == 'p');
  517. if (mode == I2C_SMBUS_BLOCK_DATA
  518. || mode == I2C_SMBUS_I2C_BLOCK_DATA
  519. ) {
  520. if (pec && mode == I2C_SMBUS_I2C_BLOCK_DATA)
  521. bb_error_msg_and_die(
  522. "PEC not supported for I2C "
  523. "block writes");
  524. if (opts & opt_m)
  525. bb_error_msg_and_die(
  526. "mask not supported for block "
  527. "writes");
  528. }
  529. }
  530. }
  531. /* Prepare the value(s) to be written according to current mode. */
  532. mask = 0;
  533. blen = 0;
  534. switch (mode) {
  535. case I2C_SMBUS_BYTE_DATA:
  536. val = xstrtou_range(argv[3], 0, 0, 0xff);
  537. break;
  538. case I2C_SMBUS_WORD_DATA:
  539. val = xstrtou_range(argv[3], 0, 0, 0xffff);
  540. break;
  541. case I2C_SMBUS_BLOCK_DATA:
  542. case I2C_SMBUS_I2C_BLOCK_DATA:
  543. for (blen = 3; blen < argc; blen++)
  544. block[blen - 3] = xstrtou_range(argv[blen], 0, 0, 0xff);
  545. blen -= 3;
  546. val = -1;
  547. break;
  548. default:
  549. val = -1;
  550. break;
  551. }
  552. if (opts & opt_m) {
  553. mask = xstrtou_range(opt_m_arg, 0, 0,
  554. (mode == I2C_SMBUS_BYTE ||
  555. mode == I2C_SMBUS_BYTE_DATA) ? 0xff : 0xffff);
  556. }
  557. fd = i2c_dev_open(bus_num);
  558. check_write_funcs(fd, mode, pec);
  559. i2c_set_slave_addr(fd, bus_addr, opts & opt_f);
  560. if (!(opts & opt_y))
  561. confirm_action(bus_addr, mode, data_addr, pec);
  562. /*
  563. * If we're using mask - read the current value here and adjust the
  564. * value to be written.
  565. */
  566. if (opts & opt_m) {
  567. int tmpval;
  568. switch (mode) {
  569. case I2C_SMBUS_BYTE:
  570. tmpval = i2c_smbus_read_byte(fd);
  571. break;
  572. case I2C_SMBUS_WORD_DATA:
  573. tmpval = i2c_smbus_read_word_data(fd, data_addr);
  574. break;
  575. default:
  576. tmpval = i2c_smbus_read_byte_data(fd, data_addr);
  577. }
  578. if (tmpval < 0)
  579. bb_perror_msg_and_die("can't read old value");
  580. val = (val & mask) | (tmpval & ~mask);
  581. if (!(opts & opt_y)) {
  582. bb_error_msg("old value 0x%0*x, write mask "
  583. "0x%0*x, will write 0x%0*x to register "
  584. "0x%02x",
  585. mode == I2C_SMBUS_WORD_DATA ? 4 : 2, tmpval,
  586. mode == I2C_SMBUS_WORD_DATA ? 4 : 2, mask,
  587. mode == I2C_SMBUS_WORD_DATA ? 4 : 2, val,
  588. data_addr);
  589. confirm_or_abort();
  590. }
  591. }
  592. if (pec)
  593. i2c_set_pec(fd, 1);
  594. switch (mode) {
  595. case I2C_SMBUS_BYTE:
  596. status = i2c_smbus_write_byte(fd, data_addr);
  597. break;
  598. case I2C_SMBUS_WORD_DATA:
  599. status = i2c_smbus_write_word_data(fd, data_addr, val);
  600. break;
  601. case I2C_SMBUS_BLOCK_DATA:
  602. status = i2c_smbus_write_block_data(fd, data_addr,
  603. blen, block);
  604. break;
  605. case I2C_SMBUS_I2C_BLOCK_DATA:
  606. status = i2c_smbus_write_i2c_block_data(fd, data_addr,
  607. blen, block);
  608. break;
  609. default: /* I2C_SMBUS_BYTE_DATA */
  610. status = i2c_smbus_write_byte_data(fd, data_addr, val);
  611. break;
  612. }
  613. if (status < 0)
  614. bb_perror_msg_and_die("write failed");
  615. if (pec)
  616. i2c_set_pec(fd, 0); /* Clear PEC. */
  617. /* No readback required - we're done. */
  618. if (!(opts & opt_r))
  619. return 0;
  620. switch (mode) {
  621. case I2C_SMBUS_BYTE:
  622. status = i2c_smbus_read_byte(fd);
  623. val = data_addr;
  624. break;
  625. case I2C_SMBUS_WORD_DATA:
  626. status = i2c_smbus_read_word_data(fd, data_addr);
  627. break;
  628. default: /* I2C_SMBUS_BYTE_DATA */
  629. status = i2c_smbus_read_byte_data(fd, data_addr);
  630. }
  631. if (status < 0) {
  632. puts("Warning - readback failed");
  633. } else
  634. if (status != val) {
  635. printf("Warning - data mismatch - wrote "
  636. "0x%0*x, read back 0x%0*x\n",
  637. mode == I2C_SMBUS_WORD_DATA ? 4 : 2, val,
  638. mode == I2C_SMBUS_WORD_DATA ? 4 : 2, status);
  639. } else {
  640. printf("Value 0x%0*x written, readback matched\n",
  641. mode == I2C_SMBUS_WORD_DATA ? 4 : 2, val);
  642. }
  643. return 0;
  644. }
  645. #endif /* ENABLE_I2CSET */
  646. #if ENABLE_I2CDUMP
  647. static int read_block_data(int buf_fd, int mode, int *block)
  648. {
  649. uint8_t cblock[I2C_SMBUS_BLOCK_MAX + I2CDUMP_NUM_REGS];
  650. int res, blen = 0, tmp, i;
  651. if (mode == I2C_SMBUS_BLOCK_DATA) {
  652. blen = i2c_smbus_read_block_data(buf_fd, 0, cblock);
  653. if (blen <= 0)
  654. goto fail;
  655. } else {
  656. for (res = 0; res < I2CDUMP_NUM_REGS; res += tmp) {
  657. tmp = i2c_smbus_read_i2c_block_data(
  658. buf_fd, res, I2C_SMBUS_BLOCK_MAX,
  659. cblock + res);
  660. if (tmp <= 0) {
  661. blen = tmp;
  662. goto fail;
  663. }
  664. }
  665. if (res >= I2CDUMP_NUM_REGS)
  666. res = I2CDUMP_NUM_REGS;
  667. for (i = 0; i < res; i++)
  668. block[i] = cblock[i];
  669. if (mode != I2C_SMBUS_BLOCK_DATA)
  670. for (i = res; i < I2CDUMP_NUM_REGS; i++)
  671. block[i] = -1;
  672. }
  673. return blen;
  674. fail:
  675. bb_error_msg_and_die("block read failed: %d", blen);
  676. }
  677. /* Dump all but word data. */
  678. static void dump_data(int bus_fd, int mode, unsigned first,
  679. unsigned last, int *block, int blen)
  680. {
  681. int i, j, res;
  682. puts(" 0 1 2 3 4 5 6 7 8 9 a b c d e f"
  683. " 0123456789abcdef");
  684. for (i = 0; i < I2CDUMP_NUM_REGS; i += 0x10) {
  685. if (mode == I2C_SMBUS_BLOCK_DATA && i >= blen)
  686. break;
  687. if (i/16 < first/16)
  688. continue;
  689. if (i/16 > last/16)
  690. break;
  691. printf("%02x: ", i);
  692. for (j = 0; j < 16; j++) {
  693. fflush_all();
  694. /* Skip unwanted registers */
  695. if (i+j < first || i+j > last) {
  696. printf(" ");
  697. if (mode == I2C_SMBUS_WORD_DATA) {
  698. printf(" ");
  699. j++;
  700. }
  701. continue;
  702. }
  703. switch (mode) {
  704. case I2C_SMBUS_BYTE_DATA:
  705. res = i2c_smbus_read_byte_data(bus_fd, i+j);
  706. block[i+j] = res;
  707. break;
  708. case I2C_SMBUS_WORD_DATA:
  709. res = i2c_smbus_read_word_data(bus_fd, i+j);
  710. if (res < 0) {
  711. block[i+j] = res;
  712. block[i+j+1] = res;
  713. } else {
  714. block[i+j] = res & 0xff;
  715. block[i+j+1] = res >> 8;
  716. }
  717. break;
  718. case I2C_SMBUS_BYTE:
  719. res = i2c_smbus_read_byte(bus_fd);
  720. block[i+j] = res;
  721. break;
  722. default:
  723. res = block[i+j];
  724. }
  725. if (mode == I2C_SMBUS_BLOCK_DATA &&
  726. i+j >= blen) {
  727. printf(" ");
  728. } else if (res < 0) {
  729. printf("XX ");
  730. if (mode == I2C_SMBUS_WORD_DATA)
  731. printf("XX ");
  732. } else {
  733. printf("%02x ", block[i+j]);
  734. if (mode == I2C_SMBUS_WORD_DATA)
  735. printf("%02x ", block[i+j+1]);
  736. }
  737. if (mode == I2C_SMBUS_WORD_DATA)
  738. j++;
  739. }
  740. printf(" ");
  741. for (j = 0; j < 16; j++) {
  742. if (mode == I2C_SMBUS_BLOCK_DATA && i+j >= blen)
  743. break;
  744. /* Skip unwanted registers */
  745. if (i+j < first || i+j > last) {
  746. bb_putchar(' ');
  747. continue;
  748. }
  749. res = block[i+j];
  750. if (res < 0) {
  751. bb_putchar('X');
  752. } else if (res == 0x00 || res == 0xff) {
  753. bb_putchar('.');
  754. } else if (res < 32 || res >= 127) {
  755. bb_putchar('?');
  756. } else {
  757. bb_putchar(res);
  758. }
  759. }
  760. bb_putchar('\n');
  761. }
  762. }
  763. static void dump_word_data(int bus_fd, unsigned first, unsigned last)
  764. {
  765. int i, j, rv;
  766. /* Word data. */
  767. puts(" 0,8 1,9 2,a 3,b 4,c 5,d 6,e 7,f");
  768. for (i = 0; i < 256; i += 8) {
  769. if (i/8 < first/8)
  770. continue;
  771. if (i/8 > last/8)
  772. break;
  773. printf("%02x: ", i);
  774. for (j = 0; j < 8; j++) {
  775. /* Skip unwanted registers. */
  776. if (i+j < first || i+j > last) {
  777. printf(" ");
  778. continue;
  779. }
  780. rv = i2c_smbus_read_word_data(bus_fd, i+j);
  781. if (rv < 0)
  782. printf("XXXX ");
  783. else
  784. printf("%04x ", rv & 0xffff);
  785. }
  786. bb_putchar('\n');
  787. }
  788. }
  789. //usage:#define i2cdump_trivial_usage
  790. //usage: "[-fy] [-r FIRST-LAST] BUS ADDR [MODE]"
  791. //usage:#define i2cdump_full_usage "\n\n"
  792. //usage: "Examine I2C registers"
  793. //usage: "\n"
  794. //usage: "\n I2CBUS I2C bus number"
  795. //usage: "\n ADDRESS 0x03-0x77"
  796. //usage: "\nMODE is:"
  797. //usage: "\n b Byte (default)"
  798. //usage: "\n w Word"
  799. //usage: "\n W Word on even register addresses"
  800. //usage: "\n i I2C block"
  801. //usage: "\n s SMBus block"
  802. //usage: "\n c Consecutive byte"
  803. //usage: "\n Append p for SMBus PEC"
  804. //usage: "\n"
  805. //usage: "\n -f Force access"
  806. //usage: "\n -y Disable interactive mode"
  807. //usage: "\n -r Limit the number of registers being accessed"
  808. int i2cdump_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  809. int i2cdump_main(int argc UNUSED_PARAM, char **argv)
  810. {
  811. const unsigned opt_f = (1 << 0), opt_y = (1 << 1),
  812. opt_r = (1 << 2);
  813. int bus_num, bus_addr, mode = I2C_SMBUS_BYTE_DATA, even = 0, pec = 0;
  814. unsigned first = 0x00, last = 0xff, opts;
  815. int block[I2CDUMP_NUM_REGS];
  816. char *opt_r_str, *dash;
  817. int fd, res;
  818. opts = getopt32(argv, "^"
  819. "fyr:"
  820. "\0" "-2:?3" /* from 2 to 3 args */,
  821. &opt_r_str
  822. );
  823. argv += optind;
  824. bus_num = i2c_bus_lookup(argv[0]);
  825. bus_addr = i2c_parse_bus_addr(argv[1]);
  826. if (argv[2]) {
  827. switch (argv[2][0]) {
  828. case 'b': /* Already set. */ break;
  829. case 'c': mode = I2C_SMBUS_BYTE; break;
  830. case 'w': mode = I2C_SMBUS_WORD_DATA; break;
  831. case 'W':
  832. mode = I2C_SMBUS_WORD_DATA;
  833. even = 1;
  834. break;
  835. case 's': mode = I2C_SMBUS_BLOCK_DATA; break;
  836. case 'i': mode = I2C_SMBUS_I2C_BLOCK_DATA; break;
  837. default:
  838. bb_error_msg_and_die("invalid mode");
  839. }
  840. if (argv[2][1] == 'p') {
  841. if (argv[2][0] == 'W' || argv[2][0] == 'i') {
  842. bb_error_msg_and_die(
  843. "pec not supported for -W and -i");
  844. } else {
  845. pec = 1;
  846. }
  847. }
  848. }
  849. if (opts & opt_r) {
  850. first = strtol(opt_r_str, &dash, 0);
  851. if (dash == opt_r_str || *dash != '-' || first > 0xff)
  852. bb_error_msg_and_die("invalid range");
  853. last = xstrtou_range(++dash, 0, first, 0xff);
  854. /* Range is not available for every mode. */
  855. switch (mode) {
  856. case I2C_SMBUS_BYTE:
  857. case I2C_SMBUS_BYTE_DATA:
  858. break;
  859. case I2C_SMBUS_WORD_DATA:
  860. if (!even || (!(first % 2) && last % 2))
  861. break;
  862. /* Fall through */
  863. default:
  864. bb_error_msg_and_die(
  865. "range not compatible with selected mode");
  866. }
  867. }
  868. fd = i2c_dev_open(bus_num);
  869. check_read_funcs(fd, mode, -1 /* data_addr */, pec);
  870. i2c_set_slave_addr(fd, bus_addr, opts & opt_f);
  871. if (pec)
  872. i2c_set_pec(fd, 1);
  873. if (!(opts & opt_y))
  874. confirm_action(bus_addr, mode, -1 /* data_addr */, pec);
  875. /* All but word data. */
  876. if (mode != I2C_SMBUS_WORD_DATA || even) {
  877. int blen = 0;
  878. if (mode == I2C_SMBUS_BLOCK_DATA || mode == I2C_SMBUS_I2C_BLOCK_DATA)
  879. blen = read_block_data(fd, mode, block);
  880. if (mode == I2C_SMBUS_BYTE) {
  881. res = i2c_smbus_write_byte(fd, first);
  882. if (res < 0)
  883. bb_perror_msg_and_die("write start address");
  884. }
  885. dump_data(fd, mode, first, last, block, blen);
  886. } else {
  887. dump_word_data(fd, first, last);
  888. }
  889. return 0;
  890. }
  891. #endif /* ENABLE_I2CDUMP */
  892. #if ENABLE_I2CDETECT
  893. enum adapter_type {
  894. ADT_DUMMY = 0,
  895. ADT_ISA,
  896. ADT_I2C,
  897. ADT_SMBUS,
  898. };
  899. struct adap_desc {
  900. const char *funcs;
  901. const char *algo;
  902. };
  903. static const struct adap_desc adap_descs[] = {
  904. { .funcs = "dummy",
  905. .algo = "Dummy bus", },
  906. { .funcs = "isa",
  907. .algo = "ISA bus", },
  908. { .funcs = "i2c",
  909. .algo = "I2C adapter", },
  910. { .funcs = "smbus",
  911. .algo = "SMBus adapter", },
  912. };
  913. struct i2c_func
  914. {
  915. long value;
  916. const char* name;
  917. };
  918. static const struct i2c_func i2c_funcs_tab[] = {
  919. { .value = I2C_FUNC_I2C,
  920. .name = "I2C" },
  921. { .value = I2C_FUNC_SMBUS_QUICK,
  922. .name = "SMBus quick command" },
  923. { .value = I2C_FUNC_SMBUS_WRITE_BYTE,
  924. .name = "SMBus send byte" },
  925. { .value = I2C_FUNC_SMBUS_READ_BYTE,
  926. .name = "SMBus receive byte" },
  927. { .value = I2C_FUNC_SMBUS_WRITE_BYTE_DATA,
  928. .name = "SMBus write byte" },
  929. { .value = I2C_FUNC_SMBUS_READ_BYTE_DATA,
  930. .name = "SMBus read byte" },
  931. { .value = I2C_FUNC_SMBUS_WRITE_WORD_DATA,
  932. .name = "SMBus write word" },
  933. { .value = I2C_FUNC_SMBUS_READ_WORD_DATA,
  934. .name = "SMBus read word" },
  935. { .value = I2C_FUNC_SMBUS_PROC_CALL,
  936. .name = "SMBus process call" },
  937. { .value = I2C_FUNC_SMBUS_WRITE_BLOCK_DATA,
  938. .name = "SMBus block write" },
  939. { .value = I2C_FUNC_SMBUS_READ_BLOCK_DATA,
  940. .name = "SMBus block read" },
  941. { .value = I2C_FUNC_SMBUS_BLOCK_PROC_CALL,
  942. .name = "SMBus block process call" },
  943. { .value = I2C_FUNC_SMBUS_PEC,
  944. .name = "SMBus PEC" },
  945. { .value = I2C_FUNC_SMBUS_WRITE_I2C_BLOCK,
  946. .name = "I2C block write" },
  947. { .value = I2C_FUNC_SMBUS_READ_I2C_BLOCK,
  948. .name = "I2C block read" },
  949. { .value = 0, .name = NULL }
  950. };
  951. static enum adapter_type i2cdetect_get_funcs(int bus)
  952. {
  953. enum adapter_type ret;
  954. unsigned long funcs;
  955. int fd;
  956. fd = i2c_dev_open(bus);
  957. get_funcs_matrix(fd, &funcs);
  958. if (funcs & I2C_FUNC_I2C)
  959. ret = ADT_I2C;
  960. else if (funcs & (I2C_FUNC_SMBUS_BYTE |
  961. I2C_FUNC_SMBUS_BYTE_DATA |
  962. I2C_FUNC_SMBUS_WORD_DATA))
  963. ret = ADT_SMBUS;
  964. else
  965. ret = ADT_DUMMY;
  966. close(fd);
  967. return ret;
  968. }
  969. static void NORETURN list_i2c_busses_and_exit(void)
  970. {
  971. const char *const i2cdev_path = "/sys/class/i2c-dev";
  972. char path[NAME_MAX], name[128];
  973. struct dirent *de, *subde;
  974. enum adapter_type adt;
  975. DIR *dir, *subdir;
  976. int rv, bus;
  977. char *pos;
  978. FILE *fp;
  979. /*
  980. * XXX Upstream i2cdetect also looks for i2c bus info in /proc/bus/i2c,
  981. * but we won't bother since it's only useful on older kernels (before
  982. * 2.6.5). We expect sysfs to be present and mounted at /sys/.
  983. */
  984. dir = xopendir(i2cdev_path);
  985. while ((de = readdir(dir))) {
  986. if (de->d_name[0] == '.')
  987. continue;
  988. /* Simple version for ISA chips. */
  989. snprintf(path, NAME_MAX, "%s/%s/name",
  990. i2cdev_path, de->d_name);
  991. fp = fopen(path, "r");
  992. if (fp == NULL) {
  993. snprintf(path, NAME_MAX,
  994. "%s/%s/device/name",
  995. i2cdev_path, de->d_name);
  996. fp = fopen(path, "r");
  997. }
  998. /* Non-ISA chips require the hard-way. */
  999. if (fp == NULL) {
  1000. snprintf(path, NAME_MAX,
  1001. "%s/%s/device/name",
  1002. i2cdev_path, de->d_name);
  1003. subdir = opendir(path);
  1004. if (subdir == NULL)
  1005. continue;
  1006. while ((subde = readdir(subdir))) {
  1007. if (subde->d_name[0] == '.')
  1008. continue;
  1009. if (is_prefixed_with(subde->d_name, "i2c-")) {
  1010. snprintf(path, NAME_MAX,
  1011. "%s/%s/device/%s/name",
  1012. i2cdev_path, de->d_name,
  1013. subde->d_name);
  1014. fp = fopen(path, "r");
  1015. break;
  1016. }
  1017. }
  1018. }
  1019. if (fp != NULL) {
  1020. /*
  1021. * Get the rest of the info and display a line
  1022. * for a single bus.
  1023. */
  1024. memset(name, 0, sizeof(name));
  1025. pos = fgets(name, sizeof(name), fp);
  1026. fclose(fp);
  1027. if (pos == NULL)
  1028. continue;
  1029. pos = strchr(name, '\n');
  1030. if (pos != NULL)
  1031. *pos = '\0';
  1032. rv = sscanf(de->d_name, "i2c-%d", &bus);
  1033. if (rv != 1)
  1034. continue;
  1035. if (is_prefixed_with(name, "ISA"))
  1036. adt = ADT_ISA;
  1037. else
  1038. adt = i2cdetect_get_funcs(bus);
  1039. printf(
  1040. "i2c-%d\t%-10s\t%-32s\t%s\n",
  1041. bus, adap_descs[adt].funcs,
  1042. name, adap_descs[adt].algo);
  1043. }
  1044. }
  1045. exit(EXIT_SUCCESS);
  1046. }
  1047. static void NORETURN no_support(const char *cmd)
  1048. {
  1049. bb_error_msg_and_die("bus doesn't support %s", cmd);
  1050. }
  1051. static void will_skip(const char *cmd)
  1052. {
  1053. bb_error_msg(
  1054. "warning: can't use %s command, "
  1055. "will skip some addresses", cmd);
  1056. }
  1057. //usage:#define i2cdetect_trivial_usage
  1058. //usage: "-l | -F I2CBUS | [-ya] [-q|-r] I2CBUS [FIRST LAST]"
  1059. //usage:#define i2cdetect_full_usage "\n\n"
  1060. //usage: "Detect I2C chips"
  1061. //usage: "\n"
  1062. //usage: "\n -l List installed buses"
  1063. //usage: "\n -F BUS# List functionalities on this bus"
  1064. //usage: "\n -y Disable interactive mode"
  1065. //usage: "\n -a Force scanning of non-regular addresses"
  1066. //usage: "\n -q Use smbus quick write commands for probing (default)"
  1067. //usage: "\n -r Use smbus read byte commands for probing"
  1068. //usage: "\n FIRST and LAST limit probing range"
  1069. int i2cdetect_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  1070. int i2cdetect_main(int argc UNUSED_PARAM, char **argv)
  1071. {
  1072. const unsigned opt_y = (1 << 0), opt_a = (1 << 1),
  1073. opt_q = (1 << 2), opt_r = (1 << 3),
  1074. opt_F = (1 << 4), opt_l = (1 << 5);
  1075. int fd, bus_num, i, j, mode = I2CDETECT_MODE_AUTO, status, cmd;
  1076. unsigned first = 0x03, last = 0x77, opts;
  1077. unsigned long funcs;
  1078. opts = getopt32(argv, "^"
  1079. "yaqrFl"
  1080. "\0"
  1081. "q--r:r--q:"/*mutually exclusive*/
  1082. "?3"/*up to 3 args*/
  1083. );
  1084. argv += optind;
  1085. if (opts & opt_l)
  1086. list_i2c_busses_and_exit();
  1087. if (!argv[0])
  1088. bb_show_usage();
  1089. bus_num = i2c_bus_lookup(argv[0]);
  1090. fd = i2c_dev_open(bus_num);
  1091. get_funcs_matrix(fd, &funcs);
  1092. if (opts & opt_F) {
  1093. /* Only list the functionalities. */
  1094. printf("Functionalities implemented by bus #%d\n", bus_num);
  1095. for (i = 0; i2c_funcs_tab[i].value; i++) {
  1096. printf("%-32s %s\n", i2c_funcs_tab[i].name,
  1097. funcs & i2c_funcs_tab[i].value ? "yes" : "no");
  1098. }
  1099. return EXIT_SUCCESS;
  1100. }
  1101. if (opts & opt_r)
  1102. mode = I2CDETECT_MODE_READ;
  1103. else if (opts & opt_q)
  1104. mode = I2CDETECT_MODE_QUICK;
  1105. if (opts & opt_a) {
  1106. first = 0x00;
  1107. last = 0x7f;
  1108. }
  1109. /* Read address range. */
  1110. if (argv[1]) {
  1111. first = xstrtou_range(argv[1], 16, first, last);
  1112. if (argv[2])
  1113. last = xstrtou_range(argv[2], 16, first, last);
  1114. }
  1115. if (!(funcs & (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_READ_BYTE))) {
  1116. no_support("detection commands");
  1117. } else
  1118. if (mode == I2CDETECT_MODE_QUICK && !(funcs & I2C_FUNC_SMBUS_QUICK)) {
  1119. no_support("SMBus quick write");
  1120. } else
  1121. if (mode == I2CDETECT_MODE_READ && !(funcs & I2C_FUNC_SMBUS_READ_BYTE)) {
  1122. no_support("SMBus receive byte");
  1123. }
  1124. if (mode == I2CDETECT_MODE_AUTO) {
  1125. if (!(funcs & I2C_FUNC_SMBUS_QUICK))
  1126. will_skip("SMBus quick write");
  1127. if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE))
  1128. will_skip("SMBus receive byte");
  1129. }
  1130. if (!(opts & opt_y))
  1131. confirm_action(-1, -1, -1, 0);
  1132. puts(" 0 1 2 3 4 5 6 7 8 9 a b c d e f");
  1133. for (i = 0; i < 128; i += 16) {
  1134. printf("%02x: ", i);
  1135. for (j = 0; j < 16; j++) {
  1136. fflush_all();
  1137. cmd = mode;
  1138. if (mode == I2CDETECT_MODE_AUTO) {
  1139. if ((i+j >= 0x30 && i+j <= 0x37) ||
  1140. (i+j >= 0x50 && i+j <= 0x5F))
  1141. cmd = I2CDETECT_MODE_READ;
  1142. else
  1143. cmd = I2CDETECT_MODE_QUICK;
  1144. }
  1145. /* Skip unwanted addresses. */
  1146. if (i+j < first
  1147. || i+j > last
  1148. || (cmd == I2CDETECT_MODE_READ && !(funcs & I2C_FUNC_SMBUS_READ_BYTE))
  1149. || (cmd == I2CDETECT_MODE_QUICK && !(funcs & I2C_FUNC_SMBUS_QUICK)))
  1150. {
  1151. printf(" ");
  1152. continue;
  1153. }
  1154. status = ioctl(fd, I2C_SLAVE, itoptr(i + j));
  1155. if (status < 0) {
  1156. if (errno == EBUSY) {
  1157. printf("UU ");
  1158. continue;
  1159. }
  1160. bb_perror_msg_and_die(
  1161. "can't set address to 0x%02x", i + j);
  1162. }
  1163. switch (cmd) {
  1164. case I2CDETECT_MODE_READ:
  1165. /*
  1166. * This is known to lock SMBus on various
  1167. * write-only chips (mainly clock chips).
  1168. */
  1169. status = i2c_smbus_read_byte(fd);
  1170. break;
  1171. default: /* I2CDETECT_MODE_QUICK: */
  1172. /*
  1173. * This is known to corrupt the Atmel
  1174. * AT24RF08 EEPROM.
  1175. */
  1176. status = i2c_smbus_write_quick(fd,
  1177. I2C_SMBUS_WRITE);
  1178. break;
  1179. }
  1180. if (status < 0)
  1181. printf("-- ");
  1182. else
  1183. printf("%02x ", i+j);
  1184. }
  1185. bb_putchar('\n');
  1186. }
  1187. return 0;
  1188. }
  1189. #endif /* ENABLE_I2CDETECT */