1*32002227SRobert Mustacchi /*
2*32002227SRobert Mustacchi * This file and its contents are supplied under the terms of the
3*32002227SRobert Mustacchi * Common Development and Distribution License ("CDDL"), version 1.0.
4*32002227SRobert Mustacchi * You may only use this file in accordance with the terms of version
5*32002227SRobert Mustacchi * 1.0 of the CDDL.
6*32002227SRobert Mustacchi *
7*32002227SRobert Mustacchi * A full copy of the text of the CDDL should have accompanied this
8*32002227SRobert Mustacchi * source. A copy of the CDDL is also available via the Internet at
9*32002227SRobert Mustacchi * http://www.illumos.org/license/CDDL.
10*32002227SRobert Mustacchi */
11*32002227SRobert Mustacchi
12*32002227SRobert Mustacchi /*
13*32002227SRobert Mustacchi * Copyright 2025 Oxide Computer Company
14*32002227SRobert Mustacchi */
15*32002227SRobert Mustacchi
16*32002227SRobert Mustacchi /*
17*32002227SRobert Mustacchi * i2c, SMBus, and i3c administration
18*32002227SRobert Mustacchi */
19*32002227SRobert Mustacchi
20*32002227SRobert Mustacchi #include <stdlib.h>
21*32002227SRobert Mustacchi #include <strings.h>
22*32002227SRobert Mustacchi #include <stdio.h>
23*32002227SRobert Mustacchi #include <stdarg.h>
24*32002227SRobert Mustacchi #include <err.h>
25*32002227SRobert Mustacchi #include <libgen.h>
26*32002227SRobert Mustacchi #include <sys/sysmacros.h>
27*32002227SRobert Mustacchi
28*32002227SRobert Mustacchi #include "i2cadm.h"
29*32002227SRobert Mustacchi
30*32002227SRobert Mustacchi i2cadm_t i2cadm;
31*32002227SRobert Mustacchi
32*32002227SRobert Mustacchi /*
33*32002227SRobert Mustacchi * The number of devices per line for the pretty printed address table.
34*32002227SRobert Mustacchi */
35*32002227SRobert Mustacchi #define DEVS_PER_LINE 16
36*32002227SRobert Mustacchi
37*32002227SRobert Mustacchi void
i2cadm_print_table(const i2cadm_table_t * table,void * arg)38*32002227SRobert Mustacchi i2cadm_print_table(const i2cadm_table_t *table, void *arg)
39*32002227SRobert Mustacchi {
40*32002227SRobert Mustacchi bool post = false;
41*32002227SRobert Mustacchi
42*32002227SRobert Mustacchi (void) printf("%s %s:\n\n%s\n", table->table_msg, table->table_port,
43*32002227SRobert Mustacchi table->table_key);
44*32002227SRobert Mustacchi
45*32002227SRobert Mustacchi (void) printf("ADDR");
46*32002227SRobert Mustacchi for (uint32_t i = 0; i < DEVS_PER_LINE; i++) {
47*32002227SRobert Mustacchi (void) printf("%s0x%x", i != 0 ? " " : "\t", i);
48*32002227SRobert Mustacchi }
49*32002227SRobert Mustacchi (void) printf("\n");
50*32002227SRobert Mustacchi for (uint16_t i = 0; i < table->table_max; i++) {
51*32002227SRobert Mustacchi bool line_start = (i % DEVS_PER_LINE) == 0;
52*32002227SRobert Mustacchi
53*32002227SRobert Mustacchi if (line_start) {
54*32002227SRobert Mustacchi if (table->table_max > UINT8_MAX) {
55*32002227SRobert Mustacchi (void) printf("0x%03x\t", i);
56*32002227SRobert Mustacchi } else {
57*32002227SRobert Mustacchi (void) printf("0x%02x\t", i);
58*32002227SRobert Mustacchi }
59*32002227SRobert Mustacchi }
60*32002227SRobert Mustacchi
61*32002227SRobert Mustacchi if (!line_start) {
62*32002227SRobert Mustacchi (void) printf(" ");
63*32002227SRobert Mustacchi }
64*32002227SRobert Mustacchi
65*32002227SRobert Mustacchi if (table->table_cb(arg, i))
66*32002227SRobert Mustacchi post = true;
67*32002227SRobert Mustacchi
68*32002227SRobert Mustacchi if ((i % DEVS_PER_LINE) == DEVS_PER_LINE - 1) {
69*32002227SRobert Mustacchi (void) printf("\n");
70*32002227SRobert Mustacchi }
71*32002227SRobert Mustacchi }
72*32002227SRobert Mustacchi
73*32002227SRobert Mustacchi if (post) {
74*32002227SRobert Mustacchi table->table_post(arg, table->table_max);
75*32002227SRobert Mustacchi }
76*32002227SRobert Mustacchi }
77*32002227SRobert Mustacchi
78*32002227SRobert Mustacchi static void
i2cadm_vwarn(const char * fmt,va_list ap)79*32002227SRobert Mustacchi i2cadm_vwarn(const char *fmt, va_list ap)
80*32002227SRobert Mustacchi {
81*32002227SRobert Mustacchi i2c_hdl_t *hdl = i2cadm.i2c_hdl;
82*32002227SRobert Mustacchi
83*32002227SRobert Mustacchi (void) fprintf(stderr, "i2cadm: ");
84*32002227SRobert Mustacchi (void) vfprintf(stderr, fmt, ap);
85*32002227SRobert Mustacchi (void) fprintf(stderr, ": %s: %s (libi2c: 0x%x, sys: %d)\n",
86*32002227SRobert Mustacchi i2c_errmsg(hdl), i2c_errtostr(hdl, i2c_err(hdl)),
87*32002227SRobert Mustacchi i2c_err(hdl), i2c_syserr(hdl));
88*32002227SRobert Mustacchi }
89*32002227SRobert Mustacchi
90*32002227SRobert Mustacchi void
i2cadm_warn(const char * fmt,...)91*32002227SRobert Mustacchi i2cadm_warn(const char *fmt, ...)
92*32002227SRobert Mustacchi {
93*32002227SRobert Mustacchi va_list ap;
94*32002227SRobert Mustacchi
95*32002227SRobert Mustacchi va_start(ap, fmt);
96*32002227SRobert Mustacchi i2cadm_vwarn(fmt, ap);
97*32002227SRobert Mustacchi va_end(ap);
98*32002227SRobert Mustacchi }
99*32002227SRobert Mustacchi
100*32002227SRobert Mustacchi void __NORETURN
i2cadm_fatal(const char * fmt,...)101*32002227SRobert Mustacchi i2cadm_fatal(const char *fmt, ...)
102*32002227SRobert Mustacchi {
103*32002227SRobert Mustacchi va_list ap;
104*32002227SRobert Mustacchi
105*32002227SRobert Mustacchi va_start(ap, fmt);
106*32002227SRobert Mustacchi i2cadm_vwarn(fmt, ap);
107*32002227SRobert Mustacchi va_end(ap);
108*32002227SRobert Mustacchi
109*32002227SRobert Mustacchi exit(EXIT_FAILURE);
110*32002227SRobert Mustacchi }
111*32002227SRobert Mustacchi
112*32002227SRobert Mustacchi void
i2cadm_ofmt_errx(const char * fmt,...)113*32002227SRobert Mustacchi i2cadm_ofmt_errx(const char *fmt, ...)
114*32002227SRobert Mustacchi {
115*32002227SRobert Mustacchi va_list ap;
116*32002227SRobert Mustacchi
117*32002227SRobert Mustacchi va_start(ap, fmt);
118*32002227SRobert Mustacchi verrx(EXIT_FAILURE, fmt, ap);
119*32002227SRobert Mustacchi }
120*32002227SRobert Mustacchi
121*32002227SRobert Mustacchi void
i2cadm_walk_usage(const i2cadm_cmdtab_t * tab,size_t len,FILE * f)122*32002227SRobert Mustacchi i2cadm_walk_usage(const i2cadm_cmdtab_t *tab, size_t len, FILE *f)
123*32002227SRobert Mustacchi {
124*32002227SRobert Mustacchi for (size_t i = 0; i < len; i++) {
125*32002227SRobert Mustacchi tab[i].icmd_use(f);
126*32002227SRobert Mustacchi }
127*32002227SRobert Mustacchi }
128*32002227SRobert Mustacchi
129*32002227SRobert Mustacchi static void
i2cadm_usage(const i2cadm_cmdtab_t * tab,size_t len,const char * format,...)130*32002227SRobert Mustacchi i2cadm_usage(const i2cadm_cmdtab_t *tab, size_t len, const char *format, ...)
131*32002227SRobert Mustacchi {
132*32002227SRobert Mustacchi if (format != NULL) {
133*32002227SRobert Mustacchi va_list ap;
134*32002227SRobert Mustacchi
135*32002227SRobert Mustacchi va_start(ap, format);
136*32002227SRobert Mustacchi vwarnx(format, ap);
137*32002227SRobert Mustacchi va_end(ap);
138*32002227SRobert Mustacchi }
139*32002227SRobert Mustacchi
140*32002227SRobert Mustacchi if (tab == NULL)
141*32002227SRobert Mustacchi return;
142*32002227SRobert Mustacchi
143*32002227SRobert Mustacchi fprintf(stderr, "Usage: i2cadm <subcommand> <args> ... \n\n");
144*32002227SRobert Mustacchi i2cadm_walk_usage(tab, len, stderr);
145*32002227SRobert Mustacchi }
146*32002227SRobert Mustacchi
147*32002227SRobert Mustacchi int
i2cadm_walk_tab(const i2cadm_cmdtab_t * tab,size_t len,int argc,char * argv[])148*32002227SRobert Mustacchi i2cadm_walk_tab(const i2cadm_cmdtab_t *tab, size_t len, int argc, char *argv[])
149*32002227SRobert Mustacchi {
150*32002227SRobert Mustacchi if (argc == 0) {
151*32002227SRobert Mustacchi i2cadm_usage(tab, len, "missing required sub-command");
152*32002227SRobert Mustacchi return (EXIT_FAILURE);
153*32002227SRobert Mustacchi }
154*32002227SRobert Mustacchi
155*32002227SRobert Mustacchi for (size_t i = 0; i < len; i++) {
156*32002227SRobert Mustacchi if (strcmp(argv[0], tab[i].icmd_name) != 0)
157*32002227SRobert Mustacchi continue;
158*32002227SRobert Mustacchi
159*32002227SRobert Mustacchi argc--;
160*32002227SRobert Mustacchi argv++;
161*32002227SRobert Mustacchi optind = 0;
162*32002227SRobert Mustacchi return (tab[i].icmd_func(argc, argv));
163*32002227SRobert Mustacchi }
164*32002227SRobert Mustacchi
165*32002227SRobert Mustacchi i2cadm_usage(tab, len, "unknown subcommand %s", argv[0]);
166*32002227SRobert Mustacchi return (EXIT_USAGE);
167*32002227SRobert Mustacchi }
168*32002227SRobert Mustacchi
169*32002227SRobert Mustacchi /*
170*32002227SRobert Mustacchi * The order commands are listed below impacts the order in usage and help
171*32002227SRobert Mustacchi * statements. We order these roughly based upon the general operations that one
172*32002227SRobert Mustacchi * needs to take starting with all operations that list different entities,
173*32002227SRobert Mustacchi * roughly ordered by importance, followed by operations which operate on the
174*32002227SRobert Mustacchi * device.
175*32002227SRobert Mustacchi */
176*32002227SRobert Mustacchi static const i2cadm_cmdtab_t i2cadm_cmds[] = {
177*32002227SRobert Mustacchi { "controller", i2cadm_controller, i2cadm_controller_usage },
178*32002227SRobert Mustacchi { "device", i2cadm_device, i2cadm_device_usage },
179*32002227SRobert Mustacchi { "mux", i2cadm_mux, i2cadm_mux_usage },
180*32002227SRobert Mustacchi { "port", i2cadm_port, i2cadm_port_usage },
181*32002227SRobert Mustacchi { "io", i2cadm_io, i2cadm_io_usage },
182*32002227SRobert Mustacchi { "scan", i2cadm_scan, i2cadm_scan_usage }
183*32002227SRobert Mustacchi };
184*32002227SRobert Mustacchi
185*32002227SRobert Mustacchi int
main(int argc,char * argv[])186*32002227SRobert Mustacchi main(int argc, char *argv[])
187*32002227SRobert Mustacchi {
188*32002227SRobert Mustacchi i2cadm.i2c_progname = basename(argv[0]);
189*32002227SRobert Mustacchi
190*32002227SRobert Mustacchi if (argc < 2) {
191*32002227SRobert Mustacchi i2cadm_usage(i2cadm_cmds, ARRAY_SIZE(i2cadm_cmds),
192*32002227SRobert Mustacchi "missing required sub-command");
193*32002227SRobert Mustacchi exit(EXIT_USAGE);
194*32002227SRobert Mustacchi }
195*32002227SRobert Mustacchi
196*32002227SRobert Mustacchi i2cadm.i2c_hdl = i2c_init();
197*32002227SRobert Mustacchi if (i2cadm.i2c_hdl == NULL) {
198*32002227SRobert Mustacchi err(EXIT_FAILURE, "failed to initialize libi2c");
199*32002227SRobert Mustacchi }
200*32002227SRobert Mustacchi
201*32002227SRobert Mustacchi argc--;
202*32002227SRobert Mustacchi argv++;
203*32002227SRobert Mustacchi
204*32002227SRobert Mustacchi return (i2cadm_walk_tab(i2cadm_cmds, ARRAY_SIZE(i2cadm_cmds), argc,
205*32002227SRobert Mustacchi argv));
206*32002227SRobert Mustacchi }
207