xref: /freebsd-src/usr.sbin/smbmsg/smbmsg.c (revision b3e7694832e81d7a904a10f525f8797b753bf0d3)
1325bf22bSJoerg Wunsch /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
31de7b4b8SPedro F. Giffuni  *
4325bf22bSJoerg Wunsch  * Copyright (C) 2004 Joerg Wunsch
5325bf22bSJoerg Wunsch  * All Rights Reserved.
6325bf22bSJoerg Wunsch  *
7325bf22bSJoerg Wunsch  * Redistribution and use in source and binary forms, with or without
8325bf22bSJoerg Wunsch  * modification, are permitted provided that the following conditions
9325bf22bSJoerg Wunsch  * are met:
10325bf22bSJoerg Wunsch  * 1. Redistributions of source code must retain the above copyright
11325bf22bSJoerg Wunsch  *    notice, this list of conditions and the following disclaimer.
12325bf22bSJoerg Wunsch  * 2. Redistributions in binary form must reproduce the above copyright
13325bf22bSJoerg Wunsch  *    notice, this list of conditions and the following disclaimer in the
14325bf22bSJoerg Wunsch  *    documentation and/or other materials provided with the distribution.
15325bf22bSJoerg Wunsch  *
16325bf22bSJoerg Wunsch  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17325bf22bSJoerg Wunsch  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18325bf22bSJoerg Wunsch  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19325bf22bSJoerg Wunsch  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
20325bf22bSJoerg Wunsch  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21325bf22bSJoerg Wunsch  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22325bf22bSJoerg Wunsch  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23325bf22bSJoerg Wunsch  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24325bf22bSJoerg Wunsch  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25325bf22bSJoerg Wunsch  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26325bf22bSJoerg Wunsch  * SUCH DAMAGE.
27325bf22bSJoerg Wunsch  */
28325bf22bSJoerg Wunsch 
29325bf22bSJoerg Wunsch /*
30325bf22bSJoerg Wunsch  * Send or receive messages over an SMBus.
31325bf22bSJoerg Wunsch  */
32325bf22bSJoerg Wunsch 
33325bf22bSJoerg Wunsch #include <err.h>
34325bf22bSJoerg Wunsch #include <errno.h>
35325bf22bSJoerg Wunsch #include <fcntl.h>
36325bf22bSJoerg Wunsch #include <stdio.h>
37325bf22bSJoerg Wunsch #include <stdlib.h>
38325bf22bSJoerg Wunsch #include <string.h>
39325bf22bSJoerg Wunsch #include <sysexits.h>
40325bf22bSJoerg Wunsch #include <unistd.h>
41325bf22bSJoerg Wunsch 
42325bf22bSJoerg Wunsch #include <sys/types.h>
43325bf22bSJoerg Wunsch #include <sys/ioctl.h>
44325bf22bSJoerg Wunsch 
45325bf22bSJoerg Wunsch #include <dev/smbus/smb.h>
46325bf22bSJoerg Wunsch 
47325bf22bSJoerg Wunsch #include "pathnames.h"
48325bf22bSJoerg Wunsch 
49325bf22bSJoerg Wunsch static const char *dev = PATH_DEFAULTSMBDEV;
50325bf22bSJoerg Wunsch static const char *bytefmt = "0x%02x";
51325bf22bSJoerg Wunsch static const char *wordfmt = "0x%04x";
52325bf22bSJoerg Wunsch static const char *fmt;
53325bf22bSJoerg Wunsch 
54325bf22bSJoerg Wunsch static int fd;			/* file descriptor for /dev/smbX */
55325bf22bSJoerg Wunsch static int cflag = -1;		/* SMBus cmd */
56325bf22bSJoerg Wunsch static int iflag = -1;		/* input data */
57325bf22bSJoerg Wunsch static int oflag = -1;		/* output data */
58325bf22bSJoerg Wunsch static int pflag;		/* probe bus */
59325bf22bSJoerg Wunsch static int slave = -1;		/* slave address */
60325bf22bSJoerg Wunsch static int wflag;		/* word IO */
61325bf22bSJoerg Wunsch 
62325bf22bSJoerg Wunsch static unsigned char ibuf[SMB_MAXBLOCKSIZE];
63325bf22bSJoerg Wunsch static unsigned char obuf[SMB_MAXBLOCKSIZE];
64cf3a35a7SAndriy Gapon static unsigned short oword;
65325bf22bSJoerg Wunsch 
66325bf22bSJoerg Wunsch /*
67325bf22bSJoerg Wunsch  * The I2C specs say that all addresses below 16 and above or equal
68325bf22bSJoerg Wunsch  * 240 are reserved.  Address 0 is the global address, but we do not
69325bf22bSJoerg Wunsch  * care for this detail.
70325bf22bSJoerg Wunsch  */
71325bf22bSJoerg Wunsch #define MIN_I2C_ADDR	16
72325bf22bSJoerg Wunsch #define MAX_I2C_ADDR	240
73325bf22bSJoerg Wunsch 
742c2d8591SJoerg Wunsch static int	do_io(void);
752c2d8591SJoerg Wunsch static int	getnum(const char *s);
762c2d8591SJoerg Wunsch static void	probe_i2c(void);
772c2d8591SJoerg Wunsch static void	usage(void);
782c2d8591SJoerg Wunsch 
79325bf22bSJoerg Wunsch static void
usage(void)80325bf22bSJoerg Wunsch usage(void)
81325bf22bSJoerg Wunsch {
82325bf22bSJoerg Wunsch 	fprintf(stderr,
83325bf22bSJoerg Wunsch 		"usage: smbmsg [-f dev] -p\n"
84325bf22bSJoerg Wunsch 		"       smbmsg [-f dev] -s slave [-F fmt] [-c cmd] [-w] "
85325bf22bSJoerg Wunsch 		"[-i incnt] [-o outcnt] [outdata ...]\n");
86325bf22bSJoerg Wunsch 	exit(EX_USAGE);
87325bf22bSJoerg Wunsch }
88325bf22bSJoerg Wunsch 
89325bf22bSJoerg Wunsch static int
getnum(const char * s)90325bf22bSJoerg Wunsch getnum(const char *s)
91325bf22bSJoerg Wunsch {
92325bf22bSJoerg Wunsch 	char *endp;
93325bf22bSJoerg Wunsch 	unsigned long l;
94325bf22bSJoerg Wunsch 
95325bf22bSJoerg Wunsch 	l = strtoul(s, &endp, 0);
96325bf22bSJoerg Wunsch 	if (*s != '\0' && *endp == '\0')
97325bf22bSJoerg Wunsch 		return (int)l;
982c2d8591SJoerg Wunsch 	return (-1);
99325bf22bSJoerg Wunsch }
100325bf22bSJoerg Wunsch 
101325bf22bSJoerg Wunsch static void
probe_i2c(void)102325bf22bSJoerg Wunsch probe_i2c(void)
103325bf22bSJoerg Wunsch {
104325bf22bSJoerg Wunsch 	unsigned char addr;
105325bf22bSJoerg Wunsch 	int flags;
106325bf22bSJoerg Wunsch #define IS_READABLE	1
107325bf22bSJoerg Wunsch #define IS_WRITEABLE	2
108325bf22bSJoerg Wunsch 	struct smbcmd c;
109325bf22bSJoerg Wunsch 
110325bf22bSJoerg Wunsch 	printf("Probing for devices on %s:\n", dev);
111325bf22bSJoerg Wunsch 
112325bf22bSJoerg Wunsch 	for (addr = MIN_I2C_ADDR; addr < MAX_I2C_ADDR; addr += 2) {
113325bf22bSJoerg Wunsch 		c.slave = addr;
114325bf22bSJoerg Wunsch 		flags = 0;
115325bf22bSJoerg Wunsch 		if (ioctl(fd, SMB_RECVB, &c) != -1)
116325bf22bSJoerg Wunsch 			flags = IS_READABLE;
117325bf22bSJoerg Wunsch 		if (ioctl(fd, SMB_QUICK_WRITE, &c) != -1)
118325bf22bSJoerg Wunsch 			flags |= IS_WRITEABLE;
119325bf22bSJoerg Wunsch 		if (flags != 0) {
120325bf22bSJoerg Wunsch 			printf("Device @0x%02x: ", addr);
121325bf22bSJoerg Wunsch 			if (flags & IS_READABLE)
122325bf22bSJoerg Wunsch 				putchar('r');
123325bf22bSJoerg Wunsch 			if (flags & IS_WRITEABLE)
124325bf22bSJoerg Wunsch 				putchar('w');
125325bf22bSJoerg Wunsch 			putchar('\n');
126325bf22bSJoerg Wunsch 		}
127325bf22bSJoerg Wunsch 	}
128325bf22bSJoerg Wunsch }
129325bf22bSJoerg Wunsch 
130325bf22bSJoerg Wunsch static int
do_io(void)131325bf22bSJoerg Wunsch do_io(void)
132325bf22bSJoerg Wunsch {
133325bf22bSJoerg Wunsch 	struct smbcmd c;
134325bf22bSJoerg Wunsch 	int i;
135325bf22bSJoerg Wunsch 
136325bf22bSJoerg Wunsch 	c.slave = slave;
137325bf22bSJoerg Wunsch 	c.cmd = cflag;
138cf3a35a7SAndriy Gapon 	c.rcount = 0;
139cf3a35a7SAndriy Gapon 	c.wcount = 0;
140325bf22bSJoerg Wunsch 
141325bf22bSJoerg Wunsch 	if (fmt == NULL && iflag > 0)
142325bf22bSJoerg Wunsch 		fmt = wflag? wordfmt: bytefmt;
143325bf22bSJoerg Wunsch 
144325bf22bSJoerg Wunsch 	if (cflag == -1) {
145325bf22bSJoerg Wunsch 		/* operations that do not require a command byte */
146325bf22bSJoerg Wunsch 		if (iflag == -1 && oflag == 0)
147325bf22bSJoerg Wunsch 			/* 0 bytes output: quick write operation */
148325bf22bSJoerg Wunsch 			return (ioctl(fd, SMB_QUICK_WRITE, &c));
149325bf22bSJoerg Wunsch 		else if (iflag == 0 && oflag == -1)
150325bf22bSJoerg Wunsch 			/* 0 bytes input: quick read operation */
151325bf22bSJoerg Wunsch 			return (ioctl(fd, SMB_QUICK_READ, &c));
152325bf22bSJoerg Wunsch 		else if (iflag == 1 && oflag == -1) {
153325bf22bSJoerg Wunsch 			/* no command, 1 byte input: receive byte op. */
154325bf22bSJoerg Wunsch 			if (ioctl(fd, SMB_RECVB, &c) == -1)
155325bf22bSJoerg Wunsch 				return (-1);
156325bf22bSJoerg Wunsch 			printf(fmt, (unsigned char)c.cmd);
157325bf22bSJoerg Wunsch 			putchar('\n');
158325bf22bSJoerg Wunsch 			return (0);
159325bf22bSJoerg Wunsch 		} else if (iflag == -1 && oflag == 1) {
160325bf22bSJoerg Wunsch 			/* no command, 1 byte output: send byte op. */
161325bf22bSJoerg Wunsch 			c.cmd = obuf[0];
162325bf22bSJoerg Wunsch 			return (ioctl(fd, SMB_SENDB, &c));
163325bf22bSJoerg Wunsch 		} else
164325bf22bSJoerg Wunsch 			return (-2);
165325bf22bSJoerg Wunsch 	}
166325bf22bSJoerg Wunsch 	if (iflag == 1 && oflag == -1) {
167325bf22bSJoerg Wunsch 		/* command + 1 byte input: read byte op. */
168325bf22bSJoerg Wunsch 		if (ioctl(fd, SMB_READB, &c) == -1)
169325bf22bSJoerg Wunsch 			return (-1);
170cf3a35a7SAndriy Gapon 		printf(fmt, (unsigned char)c.rdata.byte);
171325bf22bSJoerg Wunsch 		putchar('\n');
172325bf22bSJoerg Wunsch 		return (0);
173325bf22bSJoerg Wunsch 	} else if (iflag == -1 && oflag == 1) {
174325bf22bSJoerg Wunsch 		/* command + 1 byte output: write byte op. */
175202379afSMichael Gmelin 		c.wdata.byte = obuf[0];
176325bf22bSJoerg Wunsch 		return (ioctl(fd, SMB_WRITEB, &c));
177325bf22bSJoerg Wunsch 	} else if (wflag && iflag == 2 && oflag == -1) {
178325bf22bSJoerg Wunsch 		/* command + 2 bytes input: read word op. */
179325bf22bSJoerg Wunsch 		if (ioctl(fd, SMB_READW, &c) == -1)
180325bf22bSJoerg Wunsch 			return (-1);
181cf3a35a7SAndriy Gapon 		printf(fmt, (unsigned short)c.rdata.word);
182325bf22bSJoerg Wunsch 		putchar('\n');
183325bf22bSJoerg Wunsch 		return (0);
184325bf22bSJoerg Wunsch 	} else if (wflag && iflag == -1 && oflag == 2) {
185325bf22bSJoerg Wunsch 		/* command + 2 bytes output: write word op. */
186202379afSMichael Gmelin 		c.wdata.word = oword;
187325bf22bSJoerg Wunsch 		return (ioctl(fd, SMB_WRITEW, &c));
188325bf22bSJoerg Wunsch 	} else if (wflag && iflag == 2 && oflag == 2) {
189325bf22bSJoerg Wunsch 		/*
190325bf22bSJoerg Wunsch 		 * command + 2 bytes output + 2 bytes input:
191325bf22bSJoerg Wunsch 		 * "process call" op.
192325bf22bSJoerg Wunsch 		 */
193202379afSMichael Gmelin 		c.wdata.word = oword;
194325bf22bSJoerg Wunsch 		if (ioctl(fd, SMB_PCALL, &c) == -1)
195325bf22bSJoerg Wunsch 			return (-1);
196cf3a35a7SAndriy Gapon 		printf(fmt, (unsigned short)c.rdata.word);
197325bf22bSJoerg Wunsch 		putchar('\n');
198325bf22bSJoerg Wunsch 		return (0);
199325bf22bSJoerg Wunsch 	} else if (iflag > 1 && oflag == -1) {
200325bf22bSJoerg Wunsch 		/* command + > 1 bytes of input: block read */
201202379afSMichael Gmelin 		c.rbuf = ibuf;
202202379afSMichael Gmelin 		c.rcount = iflag;
203325bf22bSJoerg Wunsch 		if (ioctl(fd, SMB_BREAD, &c) == -1)
204325bf22bSJoerg Wunsch 			return (-1);
205cf3a35a7SAndriy Gapon 		for (i = 0; i < c.rcount; i++) {
206325bf22bSJoerg Wunsch 			if (i != 0)
207325bf22bSJoerg Wunsch 				putchar(' ');
208325bf22bSJoerg Wunsch 			printf(fmt, ibuf[i]);
209325bf22bSJoerg Wunsch 		}
210325bf22bSJoerg Wunsch 		putchar('\n');
211325bf22bSJoerg Wunsch 		return (0);
212325bf22bSJoerg Wunsch 	} else if (iflag == -1 && oflag > 1) {
213325bf22bSJoerg Wunsch 		/* command + > 1 bytes of output: block write */
214202379afSMichael Gmelin 		c.wbuf = obuf;
215202379afSMichael Gmelin 		c.wcount = oflag;
216325bf22bSJoerg Wunsch 		return (ioctl(fd, SMB_BWRITE, &c));
217325bf22bSJoerg Wunsch 	}
218325bf22bSJoerg Wunsch 
219325bf22bSJoerg Wunsch 	return (-2);
220325bf22bSJoerg Wunsch }
221325bf22bSJoerg Wunsch 
222325bf22bSJoerg Wunsch 
223325bf22bSJoerg Wunsch int
main(int argc,char ** argv)224325bf22bSJoerg Wunsch main(int argc, char **argv)
225325bf22bSJoerg Wunsch {
226325bf22bSJoerg Wunsch 	int i, n, errs = 0;
227325bf22bSJoerg Wunsch 	int savederrno;
228325bf22bSJoerg Wunsch 
229325bf22bSJoerg Wunsch 	while ((i = getopt(argc, argv, "F:c:f:i:o:ps:w")) != -1)
230325bf22bSJoerg Wunsch 		switch (i) {
231325bf22bSJoerg Wunsch 		case 'F':
232325bf22bSJoerg Wunsch 			fmt = optarg;
233325bf22bSJoerg Wunsch 			break;
234325bf22bSJoerg Wunsch 
235325bf22bSJoerg Wunsch 		case 'c':
236325bf22bSJoerg Wunsch 			if ((cflag = getnum(optarg)) == -1)
237325bf22bSJoerg Wunsch 				errx(EX_USAGE, "Invalid number: %s", optarg);
238325bf22bSJoerg Wunsch 			if (cflag < 0 || cflag >= 256)
239325bf22bSJoerg Wunsch 				errx(EX_USAGE,
240325bf22bSJoerg Wunsch 				     "CMD out of range: %d",
241325bf22bSJoerg Wunsch 				     cflag);
242325bf22bSJoerg Wunsch 			break;
243325bf22bSJoerg Wunsch 
244325bf22bSJoerg Wunsch 		case 'f':
245325bf22bSJoerg Wunsch 			dev = optarg;
246325bf22bSJoerg Wunsch 			break;
247325bf22bSJoerg Wunsch 
248325bf22bSJoerg Wunsch 		case 'i':
249325bf22bSJoerg Wunsch 			if ((iflag = getnum(optarg)) == -1)
250325bf22bSJoerg Wunsch 				errx(EX_USAGE, "Invalid number: %s", optarg);
251cc09a897SJoerg Wunsch 			if (iflag < 0 || iflag > SMB_MAXBLOCKSIZE)
252325bf22bSJoerg Wunsch 				errx(EX_USAGE,
253325bf22bSJoerg Wunsch 				     "# input bytes out of range: %d",
254325bf22bSJoerg Wunsch 				     iflag);
255325bf22bSJoerg Wunsch 			break;
256325bf22bSJoerg Wunsch 
257325bf22bSJoerg Wunsch 		case 'o':
258325bf22bSJoerg Wunsch 			if ((oflag = getnum(optarg)) == -1)
259325bf22bSJoerg Wunsch 				errx(EX_USAGE, "Invalid number: %s", optarg);
260cc09a897SJoerg Wunsch 			if (oflag < 0 || oflag > SMB_MAXBLOCKSIZE)
261325bf22bSJoerg Wunsch 				errx(EX_USAGE,
262325bf22bSJoerg Wunsch 				     "# output bytes out of range: %d",
263325bf22bSJoerg Wunsch 				     oflag);
264325bf22bSJoerg Wunsch 			break;
265325bf22bSJoerg Wunsch 
266325bf22bSJoerg Wunsch 		case 'p':
267325bf22bSJoerg Wunsch 			pflag = 1;
268325bf22bSJoerg Wunsch 			break;
269325bf22bSJoerg Wunsch 
270325bf22bSJoerg Wunsch 		case 's':
271325bf22bSJoerg Wunsch 			if ((slave = getnum(optarg)) == -1)
272325bf22bSJoerg Wunsch 				errx(EX_USAGE, "Invalid number: %s", optarg);
273325bf22bSJoerg Wunsch 
274325bf22bSJoerg Wunsch 			if (slave < MIN_I2C_ADDR || slave >= MAX_I2C_ADDR)
275325bf22bSJoerg Wunsch 				errx(EX_USAGE,
276325bf22bSJoerg Wunsch 				     "Slave address out of range: %d",
277325bf22bSJoerg Wunsch 				     slave);
278325bf22bSJoerg Wunsch 			break;
279325bf22bSJoerg Wunsch 
280325bf22bSJoerg Wunsch 		case 'w':
281325bf22bSJoerg Wunsch 			wflag = 1;
282325bf22bSJoerg Wunsch 			break;
283325bf22bSJoerg Wunsch 
284325bf22bSJoerg Wunsch 		default:
285325bf22bSJoerg Wunsch 			errs++;
286325bf22bSJoerg Wunsch 		}
287325bf22bSJoerg Wunsch 	argc -= optind;
288325bf22bSJoerg Wunsch 	argv += optind;
289325bf22bSJoerg Wunsch 	if (errs || (slave != -1 && pflag) || (slave == -1 && !pflag))
290325bf22bSJoerg Wunsch 		usage();
291325bf22bSJoerg Wunsch 	if (wflag &&
292325bf22bSJoerg Wunsch 	    !((iflag == 2 && oflag == -1) ||
293325bf22bSJoerg Wunsch 	      (iflag == -1 && oflag == 2) ||
294325bf22bSJoerg Wunsch 	      (iflag == 2 && oflag == 2)))
295325bf22bSJoerg Wunsch 		errx(EX_USAGE, "Illegal # IO bytes for word IO");
296325bf22bSJoerg Wunsch 	if (!pflag && iflag == -1 && oflag == -1)
297325bf22bSJoerg Wunsch 		errx(EX_USAGE, "Nothing to do");
298325bf22bSJoerg Wunsch 	if (pflag && (cflag != -1 || iflag != -1 || oflag != -1 || wflag != 0))
299325bf22bSJoerg Wunsch 		usage();
300325bf22bSJoerg Wunsch 	if (oflag > 0) {
301325bf22bSJoerg Wunsch 		if (oflag == 2 && wflag) {
302325bf22bSJoerg Wunsch 			if (argc == 0)
303325bf22bSJoerg Wunsch 				errx(EX_USAGE, "Too few arguments for -o count");
304325bf22bSJoerg Wunsch 			if ((n = getnum(*argv)) == -1)
305325bf22bSJoerg Wunsch 				errx(EX_USAGE, "Invalid number: %s", *argv);
306325bf22bSJoerg Wunsch 			if (n < 0 || n >= 65535)
307325bf22bSJoerg Wunsch 				errx(EX_USAGE, "Value out of range: %d", n);
308325bf22bSJoerg Wunsch 			oword = n;
309325bf22bSJoerg Wunsch 			argc--;
310325bf22bSJoerg Wunsch 			argv++;
311325bf22bSJoerg Wunsch 		} else for (i = 0; i < oflag; i++, argv++, argc--) {
312325bf22bSJoerg Wunsch 			if (argc == 0)
313325bf22bSJoerg Wunsch 				errx(EX_USAGE, "Too few arguments for -o count");
314325bf22bSJoerg Wunsch 			if ((n = getnum(*argv)) == -1)
315325bf22bSJoerg Wunsch 				errx(EX_USAGE, "Invalid number: %s", *argv);
316325bf22bSJoerg Wunsch 			if (n < 0 || n >= 256)
317325bf22bSJoerg Wunsch 				errx(EX_USAGE, "Value out of range: %d", n);
318325bf22bSJoerg Wunsch 			obuf[i] = n;
319325bf22bSJoerg Wunsch 		}
320325bf22bSJoerg Wunsch 	}
321325bf22bSJoerg Wunsch 	if (argc != 0)
322325bf22bSJoerg Wunsch 		usage();
323325bf22bSJoerg Wunsch 
324325bf22bSJoerg Wunsch 	if ((fd = open(dev, O_RDWR)) == -1)
325325bf22bSJoerg Wunsch 		err(EX_UNAVAILABLE, "Cannot open %s", dev);
326325bf22bSJoerg Wunsch 
327325bf22bSJoerg Wunsch 	i = 0;
328325bf22bSJoerg Wunsch 	if (pflag)
329325bf22bSJoerg Wunsch 		probe_i2c();
330325bf22bSJoerg Wunsch 	else
331325bf22bSJoerg Wunsch 		i = do_io();
332325bf22bSJoerg Wunsch 
333325bf22bSJoerg Wunsch 	savederrno = errno;
334325bf22bSJoerg Wunsch 	close(fd);
335325bf22bSJoerg Wunsch 	errno = savederrno;
336325bf22bSJoerg Wunsch 
337325bf22bSJoerg Wunsch 	if (i == -1)
338325bf22bSJoerg Wunsch 		err(EX_UNAVAILABLE, "Error performing SMBus IO");
339325bf22bSJoerg Wunsch 	else if (i == -2)
340325bf22bSJoerg Wunsch 		errx(EX_USAGE, "Invalid option combination");
341325bf22bSJoerg Wunsch 
3422c2d8591SJoerg Wunsch 	return (0);
343325bf22bSJoerg Wunsch }
344