xref: /minix/minix/usr.bin/eepromread/eepromread.c (revision 7f5f010b)
1 #include <minix/i2c.h>
2 #include <minix/com.h>
3 
4 #include <sys/types.h>
5 #include <sys/stat.h>
6 
7 #include <ctype.h>
8 #include <errno.h>
9 #include <fcntl.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <unistd.h>
14 
15 #include "eepromread.h"
16 
17 static int __eeprom_read128(int fd, i2c_addr_t addr, uint16_t memaddr,
18     void *buf, size_t buflen, int flags, enum device_types device_type);
19 static int eeprom_dump(int fd, i2c_addr_t addr, int flags,
20     enum device_types device_type);
21 
22 #define DEFAULT_I2C_DEVICE "/dev/i2c-1"
23 #define DEFAULT_I2C_ADDRESS 0x50
24 
25 /*
26  * The /dev interface only supports 128 byte reads/writes and the EEPROM is
27  * larger, so to read the whole EEPROM, the task is broken down into 128 byte
28  * chunks in eeprom_read(). __eeprom_read128() does the actual ioctl() to do
29  * the read.
30  */
31 
32 static int
33 __eeprom_read128(int fd, i2c_addr_t addr, uint16_t memaddr, void *buf,
34     size_t buflen, int flags, enum device_types device_type)
35 {
36 	int r;
37 	minix_i2c_ioctl_exec_t ioctl_exec;
38 
39 	if (buflen > I2C_EXEC_MAX_BUFLEN || buf == NULL
40 	    || ((memaddr + buflen) < memaddr)) {
41 		errno = EINVAL;
42 		return -1;
43 	}
44 
45 	/* if /dev/eeprom, then use read() */
46 	if (device_type == EEPROM_DEVICE) {
47 
48 		off_t offset;
49 
50 		offset = lseek(fd, memaddr, SEEK_SET);
51 		if (offset != memaddr) {
52 			return -1;
53 		}
54 
55 		return read(fd, buf, buflen);
56 
57 	}
58 	/* else /dev/i2c, use i2c_ioctl_exec_t interface */
59 	memset(&ioctl_exec, '\0', sizeof(minix_i2c_ioctl_exec_t));
60 
61 	ioctl_exec.iie_op = I2C_OP_READ_WITH_STOP;
62 	ioctl_exec.iie_addr = addr;
63 
64 	/* set the address to read from */
65 	if ((BDEV_NOPAGE & flags) == BDEV_NOPAGE) {
66 		/* reading within the current page */
67 		ioctl_exec.iie_cmd[0] = (memaddr & 0xff);
68 		ioctl_exec.iie_cmdlen = 1;
69 	} else {
70 		/* reading from device with multiple pages */
71 		ioctl_exec.iie_cmd[0] = ((memaddr >> 8) & 0xff);
72 		ioctl_exec.iie_cmd[1] = (memaddr & 0xff);
73 		ioctl_exec.iie_cmdlen = 2;
74 	}
75 	ioctl_exec.iie_buflen = buflen;
76 
77 	r = ioctl(fd, MINIX_I2C_IOCTL_EXEC, &ioctl_exec);
78 	if (r == -1) {
79 		return -1;
80 	}
81 
82 	/* call was good, copy results to caller's buffer */
83 	memcpy(buf, ioctl_exec.iie_buf, buflen);
84 
85 	return 0;
86 }
87 
88 int
89 eeprom_read(int fd, i2c_addr_t addr, uint16_t memaddr, void *buf,
90     size_t buflen, int flags, enum device_types device_type)
91 {
92 	int r;
93 	uint16_t i;
94 
95 	if (buf == NULL || ((memaddr + buflen) < memaddr)) {
96 		errno = EINVAL;
97 		return -1;
98 	}
99 
100 	for (i = 0; i < buflen; i += 128) {
101 
102 		r = __eeprom_read128(fd, addr, memaddr + i, buf + i,
103 		    ((buflen - i) < 128) ? (buflen - i) : 128, flags,
104 		    device_type);
105 		if (r == -1) {
106 			return -1;
107 		}
108 	}
109 
110 	return 0;
111 }
112 
113 /*
114  * Read 256 bytes and print it to the screen in HEX and ASCII.
115  */
116 static int
117 eeprom_dump(int fd, i2c_addr_t addr, int flags, enum device_types device_type)
118 {
119 	int i, j, r;
120 	uint8_t buf[256];
121 
122 	memset(buf, '\0', 256);
123 
124 	r = eeprom_read(fd, addr, 0x0000, buf, 256, flags, device_type);
125 	if (r == -1) {
126 		return r;
127 	}
128 
129 	/* print table header */
130 	for (i = 0; i < 2; i++) {
131 		printf("   ");
132 		for (j = 0x0; j <= 0xf; j++) {
133 			if (i == 0) {
134 				printf("  ");
135 			}
136 			printf("%x", j);
137 		}
138 	}
139 	printf("\n");
140 
141 	/* print table data */
142 	for (i = 0x00; i < 0xff; i += 0x10) {
143 
144 		/* row label */
145 		printf("%02x:", i);
146 
147 		/* row data (in hex) */
148 		for (j = 0x0; j <= 0xf; j++) {
149 			printf(" %02x", buf[i + j]);
150 		}
151 
152 		printf("   ");
153 
154 		/* row data (in ASCII) */
155 		for (j = 0x0; j <= 0xf; j++) {
156 			if (isprint(buf[i + j])) {
157 				printf("%c", buf[i + j]);
158 			} else {
159 				printf(".");
160 			}
161 		}
162 
163 		printf("\n");
164 	}
165 
166 	return 0;
167 }
168 
169 int
170 main(int argc, char *argv[])
171 {
172 	int r, fd;
173 	int ch, iflag = 0, read_flags = 0;
174 	char *device = DEFAULT_I2C_DEVICE;
175 	i2c_addr_t address = DEFAULT_I2C_ADDRESS;
176 	enum device_types device_type = DEFAULT_DEVICE;
177 
178 	setprogname(*argv);
179 
180 	while ((ch = getopt(argc, argv, "a:f:in")) != -1) {
181 		switch (ch) {
182 		case 'a':
183 			address = strtol(optarg, NULL, 0x10);
184 			break;
185 		case 'f':
186 			device = optarg;
187 			break;
188 		case 'i':
189 			iflag = 1;
190 			break;
191 		case 'n':
192 			read_flags |= BDEV_NOPAGE;
193 			break;
194 		default:
195 			break;
196 		}
197 	}
198 
199 	/* determine whether to use /dev/i2c or /dev/eeprom interface */
200 	device_type =
201 	    strstr(device, "i2c") == NULL ? EEPROM_DEVICE : I2C_DEVICE;
202 
203 	fd = open(device, O_RDWR);
204 	if (fd == -1) {
205 		fprintf(stderr, "open(): %s\n", strerror(errno));
206 		return 1;
207 	}
208 
209 	if (iflag == 1) {
210 		r = board_info(fd, address, read_flags, device_type);
211 		if (r == -1) {
212 			fprintf(stderr, "board_info(): %s\n", strerror(errno));
213 			return 1;
214 		}
215 	} else {
216 		r = eeprom_dump(fd, address, read_flags, device_type);
217 		if (r == -1) {
218 			fprintf(stderr, "eeprom_dump(): %s\n",
219 			    strerror(errno));
220 			return 1;
221 		}
222 	}
223 
224 	r = close(fd);
225 	if (r == -1) {
226 		fprintf(stderr, "close(): %s\n", strerror(errno));
227 		return 1;
228 	}
229 
230 	return 0;
231 }
232