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 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 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 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 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 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 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 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