1/*
2 * Copyright 2020, J��r��me Duval, jerome.duval@gmail.com.
3 * Distributed under the terms of the MIT license.
4 */
5
6
7#include <errno.h>
8#include <fcntl.h>
9#include <getopt.h>
10#include <stdint.h>
11#include <stdio.h>
12#include <stdlib.h>
13#include <string.h>
14
15#include <Drivers.h>
16
17#include <AutoDeleter.h>
18
19#include "i2c.h"
20
21
22static struct option const kLongOptions[] = {
23	{"help", no_argument, 0, 'h'},
24	{NULL}
25};
26
27
28extern const char *__progname;
29static const char *kProgramName = __progname;
30
31
32void
33usage(int returnValue)
34{
35	fprintf(stderr, "Usage: %s <path-to-i2c-bus-device>\n", kProgramName);
36	exit(returnValue);
37}
38
39
40static int
41scan_bus(const char *path)
42{
43	int err = EXIT_SUCCESS;
44	FileDescriptorCloser fd(open(path, O_RDONLY));
45	if (!fd.IsSet()) {
46		fprintf(stderr, "%s: Could not access path: %s\n", kProgramName,
47			strerror(errno));
48		return EXIT_FAILURE;
49	}
50
51	setbuf(stdout, NULL);
52	printf("Scanning I2C bus: %s\n", path);
53
54	printf("     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f\n");
55	for (int i = 0; i < 128; i+=16) {
56		printf("%02x: ", i);
57		for (int j = 0; j < 16; j++) {
58			uint16 addr = i + j;
59			uint8 cmd = 0;
60			uint8 data = 0;
61			i2c_ioctl_exec exec;
62			exec.addr = addr;
63			exec.op = I2C_OP_READ_STOP;
64			exec.cmdBuffer = &cmd;
65			exec.cmdLength = sizeof(cmd);
66			exec.buffer = &data;
67			exec.bufferLength = sizeof(data);
68			if (ioctl(fd.Get(), I2CEXEC, &exec, sizeof(exec)) == 0)
69				printf("%02x ", addr);
70			else
71				printf("-- ");
72		}
73		printf("\n");
74	}
75
76	return err;
77}
78
79
80int
81main(int argc, char** argv)
82{
83	int c;
84	while ((c = getopt_long(argc, argv, "h", kLongOptions, NULL)) != -1) {
85		switch (c) {
86			case 0:
87				break;
88			case 'h':
89				usage(0);
90				break;
91			default:
92				usage(1);
93				break;
94		}
95	}
96
97	if (argc - optind < 1)
98		usage(1);
99	const char* path = argv[optind++];
100
101	exit(scan_bus(path));
102}
103