xref: /illumos-gate/usr/src/test/i2c-tests/tests/libi2c/missing-field.c (revision 0cbe48189888d02563dba9c90132ac391ba233b6)
1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright 2025 Oxide Computer Company
14  */
15 
16 /*
17  * Verify that we fail when we're missing a field in a given request. This works
18  * from the empty device profile and targets smbussim1 where there will be no
19  * devices.
20  */
21 
22 #include <stdlib.h>
23 #include <err.h>
24 
25 #include "libi2c_test_util.h"
26 
27 static bool
test_add(i2c_hdl_t * hdl,i2c_dev_add_req_t * req,const char * desc)28 test_add(i2c_hdl_t *hdl, i2c_dev_add_req_t *req, const char *desc)
29 {
30 	if (i2c_device_add_req_exec(req)) {
31 		warnx("TEST FAILED: incomplete device add (%s) accidentally "
32 		    "succeeded", desc);
33 		return (false);
34 	} else if (i2c_err(hdl) != I2C_ERR_ADD_DEV_REQ_MISSING_FIELDS) {
35 		warnx("TEST FAILED: incomplete device add (%s) failed with "
36 		    "%s (0x%x), expected I2C_ERR_ADD_DEV_REQ_MISSING_FIELDS "
37 		    "(0x%x)", desc, i2c_errtostr(hdl, i2c_err(hdl)),
38 		    i2c_err(hdl), I2C_ERR_ADD_DEV_REQ_MISSING_FIELDS);
39 		return (false);
40 	} else {
41 		(void) printf("TEST PASSED: incomplete device add (%s) failed "
42 		    "with I2C_ERR_ADD_DEV_REQ_MISSING_FIELDS\n", desc);
43 		return (true);
44 	}
45 }
46 
47 /*
48  * Test that we error with missing fields. The compatible field is optional so
49  * this is basically just checking combinations of name and addr.
50  */
51 static bool
missing_adds(i2c_hdl_t * hdl,i2c_port_t * port)52 missing_adds(i2c_hdl_t *hdl, i2c_port_t *port)
53 {
54 	bool ret = true;
55 	i2c_dev_add_req_t *add;
56 
57 	if (!i2c_device_add_req_init(port, &add)) {
58 		libi2c_test_fatal(hdl, "INTERNAL TEST FAILURE: failed to "
59 		    "initialize device add requiest");
60 	}
61 
62 	if (!test_add(hdl, add, "all")) {
63 		ret = false;
64 	}
65 
66 	const i2c_addr_t addr = { I2C_ADDR_7BIT, 0x23 };
67 	if (!i2c_device_add_req_set_addr(add, &addr)) {
68 		libi2c_test_fatal(hdl, "INTERNAL TEST FAILURE: failed to set "
69 		    "device add address");
70 	}
71 
72 	if (!test_add(hdl, add, "name")) {
73 		ret = false;
74 	}
75 	i2c_device_add_req_fini(add);
76 
77 	if (!i2c_device_add_req_init(port, &add)) {
78 		libi2c_test_fatal(hdl, "INTERNAL TEST FAILURE: failed to "
79 		    "initialize device add requiest");
80 	}
81 
82 	if (!i2c_device_add_req_set_name(add, "foobar")) {
83 		libi2c_test_fatal(hdl, "INTERNAL TEST FAILURE: failed to set "
84 		    "device add address");
85 	}
86 
87 	if (!test_add(hdl, add, "addr")) {
88 		ret = false;
89 	}
90 
91 	i2c_device_add_req_fini(add);
92 
93 	return (ret);
94 }
95 
96 static bool
test_i2c_io(i2c_hdl_t * hdl,i2c_io_req_t * req,const char * desc)97 test_i2c_io(i2c_hdl_t *hdl, i2c_io_req_t *req, const char *desc)
98 {
99 	if (i2c_io_req_exec(req)) {
100 		warnx("TEST FAILED: incomplete I2C I/O (%s) accidentally "
101 		    "succeeded", desc);
102 		return (false);
103 	} else if (i2c_err(hdl) != I2C_ERR_IO_REQ_MISSING_FIELDS) {
104 		warnx("TEST FAILED: incomplete I2C I/O (%s) failed with "
105 		    "%s (0x%x), expected I2C_ERR_IO_REQ_MISSING_FIELDS (0x%x)",
106 		    desc, i2c_errtostr(hdl, i2c_err(hdl)), i2c_err(hdl),
107 		    I2C_ERR_IO_REQ_MISSING_FIELDS);
108 		return (false);
109 	} else {
110 		(void) printf("TEST PASSED: incomplete I2C I/O (%s) failed "
111 		    "with I2C_ERR_IO_REQ_MISSING_FIELDS\n", desc);
112 		return (true);
113 	}
114 }
115 
116 static bool
missing_i2c_io(i2c_hdl_t * hdl,i2c_port_t * port)117 missing_i2c_io(i2c_hdl_t *hdl, i2c_port_t *port)
118 {
119 	bool ret = true;
120 	i2c_io_req_t *req;
121 
122 	if (!i2c_io_req_init(port, &req)) {
123 		libi2c_test_fatal(hdl, "INTERNAL TEST FAILURE: failed to "
124 		    "initialize I2C I/O request");
125 	}
126 
127 	if (!test_i2c_io(hdl, req, "all")) {
128 		ret = false;
129 	}
130 
131 	uint8_t rbuf[4] = { 0 };
132 	uint8_t wbuf[4] = { 0 };
133 	if (!i2c_io_req_set_transmit_data(req, wbuf, sizeof (wbuf))) {
134 		libi2c_test_fatal(hdl, "INTERNAL TEST FAILURE: failed to "
135 		    "set I2C transmit buffer");
136 	}
137 
138 	if (!i2c_io_req_set_receive_buf(req, rbuf, sizeof (rbuf))) {
139 		libi2c_test_fatal(hdl, "INTERNAL TEST FAILURE: failed to "
140 		    "set I2C receive buffer");
141 	}
142 
143 	if (!test_i2c_io(hdl, req, "addr")) {
144 		ret = false;
145 	}
146 	i2c_io_req_fini(req);
147 	return (ret);
148 }
149 
150 static bool
test_smbus_io(i2c_hdl_t * hdl,smbus_io_req_t * req,const char * desc)151 test_smbus_io(i2c_hdl_t *hdl, smbus_io_req_t *req, const char *desc)
152 {
153 	if (smbus_io_req_exec(req)) {
154 		warnx("TEST FAILED: incomplete SMBus I/O (%s) accidentally "
155 		    "succeeded", desc);
156 		return (false);
157 	} else if (i2c_err(hdl) != I2C_ERR_IO_REQ_MISSING_FIELDS) {
158 		warnx("TEST FAILED: incomplete SMBus I/O (%s) failed with "
159 		    "%s (0x%x), expected I2C_ERR_IO_REQ_MISSING_FIELDS (0x%x)",
160 		    desc, i2c_errtostr(hdl, i2c_err(hdl)), i2c_err(hdl),
161 		    I2C_ERR_IO_REQ_MISSING_FIELDS);
162 		return (false);
163 	} else {
164 		(void) printf("TEST PASSED: incomplete SMBus I/O (%s) failed "
165 		    "with I2C_ERR_IO_REQ_MISSING_FIELDS\n", desc);
166 		return (true);
167 	}
168 }
169 
170 /*
171  * We only test a handful of the various SMBus operations here and hope that if
172  * it works for them it works for most.
173  */
174 static bool
missing_smbus_io(i2c_hdl_t * hdl,i2c_port_t * port)175 missing_smbus_io(i2c_hdl_t *hdl, i2c_port_t *port)
176 {
177 	bool ret = true;
178 	smbus_io_req_t *req;
179 
180 	if (!smbus_io_req_init(port, &req)) {
181 		libi2c_test_fatal(hdl, "INTERNAL TEST FAILURE: failed to "
182 		    "initialize SMBus I/O request");
183 	}
184 
185 	if (!test_smbus_io(hdl, req, "all")) {
186 		ret = false;
187 	}
188 	smbus_io_req_fini(req);
189 
190 	if (!smbus_io_req_init(port, &req)) {
191 		libi2c_test_fatal(hdl, "INTERNAL TEST FAILURE: failed to "
192 		    "initialize SMBus I/O request");
193 	}
194 
195 	const i2c_addr_t addr = { I2C_ADDR_7BIT, 0x42 };
196 	if (!smbus_io_req_set_addr(req, &addr)) {
197 		libi2c_test_fatal(hdl, "INTERNAL TEST FAILURE: failed to "
198 		    "set SMBus request address");
199 	}
200 
201 	if (!test_smbus_io(hdl, req, "command")) {
202 		ret = false;
203 	}
204 	smbus_io_req_fini(req);
205 
206 	if (!smbus_io_req_init(port, &req)) {
207 		libi2c_test_fatal(hdl, "INTERNAL TEST FAILURE: failed to "
208 		    "initialize SMBus I/O request");
209 	}
210 
211 	if (!smbus_io_req_set_write_u16(req, 0x23, 0x7777)) {
212 		libi2c_test_fatal(hdl, "INTERNAL TEST FAILURE: failed to "
213 		    "set write u16 command");
214 	}
215 
216 	if (!test_smbus_io(hdl, req, "addr: u16")) {
217 		ret = false;
218 	}
219 	smbus_io_req_fini(req);
220 
221 	if (!smbus_io_req_init(port, &req)) {
222 		libi2c_test_fatal(hdl, "INTERNAL TEST FAILURE: failed to "
223 		    "initialize SMBus I/O request");
224 	}
225 
226 	uint8_t buf[4];
227 	if (!smbus_io_req_set_read_block_i2c(req, 0x23, buf, sizeof (buf))) {
228 		libi2c_test_fatal(hdl, "INTERNAL TEST FAILURE: failed to "
229 		    "set read I2C block command");
230 	}
231 
232 	if (!test_smbus_io(hdl, req, "addr: read block i2c")) {
233 		ret = false;
234 	}
235 	smbus_io_req_fini(req);
236 
237 
238 	return (ret);
239 }
240 
241 int
main(void)242 main(void)
243 {
244 	i2c_port_t *port;
245 	int ret = EXIT_SUCCESS;
246 	i2c_hdl_t *hdl = i2c_init();
247 	if (hdl == NULL) {
248 		err(EXIT_FAILURE, "INTERNAL TEST FAILURE: failed to create "
249 		    "libi2c handle");
250 	}
251 
252 	if (!i2c_port_init_by_path(hdl, "smbussim1/0", &port)) {
253 		libi2c_test_fatal(hdl, "INTERNAL TEST FAILURE: failed to "
254 		    "initialize port smbussim1/0");
255 	}
256 
257 	if (!missing_adds(hdl, port)) {
258 		ret = EXIT_FAILURE;
259 	}
260 
261 	if (!missing_i2c_io(hdl, port)) {
262 		ret = EXIT_FAILURE;
263 	}
264 
265 	if (!missing_smbus_io(hdl, port)) {
266 		ret = EXIT_FAILURE;
267 	}
268 
269 	if (ret == EXIT_SUCCESS) {
270 		(void) printf("All tests passed successfully\n");
271 	}
272 	i2c_port_fini(port);
273 	i2c_fini(hdl);
274 	return (ret);
275 }
276