xref: /freebsd/usr.sbin/spi/spi.c (revision 917d18462622a6b12bf7236d8ec6ef4432590dd9)
166660095SIan Lepore /*-
266660095SIan Lepore  * SPDX-License-Identifier: BSD-2-Clause
366660095SIan Lepore  *
466660095SIan Lepore  * Copyright (c) 2018 S.F.T. Inc.
566660095SIan Lepore  *
666660095SIan Lepore  * Redistribution and use in source and binary forms, with or without
766660095SIan Lepore  * modification, are permitted provided that the following conditions
866660095SIan Lepore  * are met:
966660095SIan Lepore  * 1. Redistributions of source code must retain the above copyright
1066660095SIan Lepore  *    notice, this list of conditions and the following disclaimer.
1166660095SIan Lepore  * 2. Redistributions in binary form must reproduce the above copyright
1266660095SIan Lepore  *    notice, this list of conditions and the following disclaimer in the
1366660095SIan Lepore  *    documentation and/or other materials provided with the distribution.
1466660095SIan Lepore  *
1566660095SIan Lepore  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1666660095SIan Lepore  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1766660095SIan Lepore  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1866660095SIan Lepore  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1966660095SIan Lepore  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2066660095SIan Lepore  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2166660095SIan Lepore  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2266660095SIan Lepore  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2366660095SIan Lepore  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2466660095SIan Lepore  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2566660095SIan Lepore  * SUCH DAMAGE.
2666660095SIan Lepore  */
2766660095SIan Lepore 
2866660095SIan Lepore #include <sys/cdefs.h>
2966660095SIan Lepore __FBSDID("$FreeBSD$");
3066660095SIan Lepore 
3166660095SIan Lepore #include <sys/types.h>
3266660095SIan Lepore #include <sys/ioccom.h>
3366660095SIan Lepore #include <sys/spigenio.h>
3466660095SIan Lepore #include <sys/sysctl.h>
3566660095SIan Lepore 
3666660095SIan Lepore #include <errno.h>
3766660095SIan Lepore #include <fcntl.h>
3866660095SIan Lepore #include <inttypes.h>
3966660095SIan Lepore #include <limits.h>
4066660095SIan Lepore #include <memory.h>
4166660095SIan Lepore #include <stdio.h>
4266660095SIan Lepore #include <stdlib.h>
4366660095SIan Lepore #include <string.h>
4466660095SIan Lepore #include <string.h>
4566660095SIan Lepore #include <unistd.h>
4666660095SIan Lepore 
4766660095SIan Lepore #define	DEFAULT_DEVICE_NAME	"/dev/spigen0.0"
4866660095SIan Lepore 
4966660095SIan Lepore #define	DEFAULT_BUFFER_SIZE	8192
5066660095SIan Lepore 
5166660095SIan Lepore #define	DIR_READ		0
5266660095SIan Lepore #define	DIR_WRITE		1
5366660095SIan Lepore #define	DIR_READWRITE		2
5466660095SIan Lepore #define	DIR_NONE		-1
5566660095SIan Lepore 
5666660095SIan Lepore struct spi_options {
5766660095SIan Lepore 	int	mode;		/* mode (0,1,2,3, -1 == use default) */
5866660095SIan Lepore 	int	speed;		/* speed (in Hz, -1 == use default) */
5966660095SIan Lepore 	int	count;		/* count (0 through 'n' bytes, negative for
6066660095SIan Lepore 				 * stdin length) */
6166660095SIan Lepore 	int	binary;		/* non-zero for binary output or zero for
6266660095SIan Lepore 				 * ASCII output when ASCII != 0 */
6366660095SIan Lepore 	int	ASCII;		/* zero for binary input and output.
6466660095SIan Lepore 				 * non-zero for ASCII input, 'binary'
6566660095SIan Lepore 				 * determines output */
6666660095SIan Lepore 	int	lsb;		/* non-zero for LSB order (default order is
6766660095SIan Lepore 				 * MSB) */
6866660095SIan Lepore 	int	verbose;	/* non-zero for verbosity */
6966660095SIan Lepore 	int	ncmd;		/* bytes to skip for incoming data */
7066660095SIan Lepore 	uint8_t	*pcmd;		/* command data (NULL if none) */
7166660095SIan Lepore };
7266660095SIan Lepore 
7366660095SIan Lepore static void	usage(void);
7466660095SIan Lepore static int	interpret_command_bytes(const char *parg, struct spi_options *popt);
7566660095SIan Lepore static void *	prep_write_buffer(struct spi_options *popt);
7666660095SIan Lepore static int	_read_write(int hdev, void *bufw, void *bufr, int cbrw, int lsb);
7766660095SIan Lepore static int	_do_data_output(void *pr, struct spi_options *popt);
7866660095SIan Lepore static int	get_info(int hdev, const char *dev_name);
7966660095SIan Lepore static int	set_mode(int hdev, struct spi_options *popt);
8066660095SIan Lepore static int	set_speed(int hdev, struct spi_options *popt);
8166660095SIan Lepore static int	hexval(char c);
8266660095SIan Lepore static int	perform_read(int hdev, struct spi_options *popt);
8366660095SIan Lepore static int	perform_write(int hdev, struct spi_options *popt);
8466660095SIan Lepore static int	perform_readwrite(int hdev, struct spi_options *popt);
8566660095SIan Lepore static void	verbose_dump_buffer(void *pbuf, int icount, int lsb);
8666660095SIan Lepore 
8766660095SIan Lepore /*
8866660095SIan Lepore  * LSB array - reversebits[n] is the LSB value of n as an MSB.  Use this array
8966660095SIan Lepore  * to obtain a reversed bit pattern of the index value when bits must
9066660095SIan Lepore  * be sent/received in an LSB order vs the default MSB
9166660095SIan Lepore  */
9266660095SIan Lepore static uint8_t reversebits[256] = {
9366660095SIan Lepore 	0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
9466660095SIan Lepore 	0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
9566660095SIan Lepore 	0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
9666660095SIan Lepore 	0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
9766660095SIan Lepore 	0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
9866660095SIan Lepore 	0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
9966660095SIan Lepore 	0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
10066660095SIan Lepore 	0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
10166660095SIan Lepore 	0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
10266660095SIan Lepore 	0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
10366660095SIan Lepore 	0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
10466660095SIan Lepore 	0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
10566660095SIan Lepore 	0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
10666660095SIan Lepore 	0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
10766660095SIan Lepore 	0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
10866660095SIan Lepore 	0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
10966660095SIan Lepore 	0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
11066660095SIan Lepore 	0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
11166660095SIan Lepore 	0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
11266660095SIan Lepore 	0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
11366660095SIan Lepore 	0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
11466660095SIan Lepore 	0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
11566660095SIan Lepore 	0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
11666660095SIan Lepore 	0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
11766660095SIan Lepore 	0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
11866660095SIan Lepore 	0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
11966660095SIan Lepore 	0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
12066660095SIan Lepore 	0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
12166660095SIan Lepore 	0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
12266660095SIan Lepore 	0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
12366660095SIan Lepore 	0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
12466660095SIan Lepore 	0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
12566660095SIan Lepore };
12666660095SIan Lepore 
12766660095SIan Lepore 
12866660095SIan Lepore static void
12966660095SIan Lepore usage(void)
13066660095SIan Lepore {
13166660095SIan Lepore 	fputs(getprogname(), stderr);
13266660095SIan Lepore 	fputs(" - communicate on SPI bus with slave devices\n"
13366660095SIan Lepore 	      "Usage:\n"
13466660095SIan Lepore 	      "        spi [-f device] [-d r|w|rw] [-m mode] [-s max-speed] [-c count]\n"
13566660095SIan Lepore 	      "            [-C \"command bytes\"] [-A] [-b] [-L] [-v]\n"
13666660095SIan Lepore 	      "        spi -i [-f device] [-v]\n"
13766660095SIan Lepore 	      "        spi -h\n"
13866660095SIan Lepore 	      " where\n"
13966660095SIan Lepore 	      "        -f specifies the device (default is spigen0.0)\n"
14066660095SIan Lepore 	      "        -d specifies the operation (r, w, or rw; default is rw)\n"
14166660095SIan Lepore 	      "        -m specifies the mode (0, 1, 2, or 3)\n"
14266660095SIan Lepore 	      "        -s specifies the maximum speed (default is 0, device default)\n"
14366660095SIan Lepore 	      "        -c specifies the number of data bytes to transfer (default 0, i.e. none)\n"
14466660095SIan Lepore 	      "           A negative value uses the length of the input data\n"
14566660095SIan Lepore 	      "        -C specifies 'command bytes' to be sent, as 2 byte hexadecimal values\n"
14666660095SIan Lepore 	      "           (these should be quoted, separated by optional white space)\n"
14766660095SIan Lepore 	      "        -L specifies 'LSB' order on the SPI bus (default is MSB)\n"
14866660095SIan Lepore 	      "        -i query information about the device\n"
14966660095SIan Lepore 	      "        -A uses ASCII for input/output as 2-digit hex values\n"
15066660095SIan Lepore 	      "        -b Override output format as binary (only valid with '-A')\n"
15166660095SIan Lepore 	      "        -v verbose output\n"
15266660095SIan Lepore 	      "        -h prints this message\n"
15366660095SIan Lepore 	      "\n"
15466660095SIan Lepore 	      "NOTE:  setting the mode and/or speed is 'sticky'.  Subsequent transactions\n"
15566660095SIan Lepore 	      "       on that device will, by default, use the previously set values.\n"
15666660095SIan Lepore 	      "\n",
15766660095SIan Lepore 	      stderr);
15866660095SIan Lepore }
15966660095SIan Lepore 
16066660095SIan Lepore int
16166660095SIan Lepore main(int argc, char *argv[], char *envp[] __unused)
16266660095SIan Lepore {
16366660095SIan Lepore 	struct spi_options opt;
16466660095SIan Lepore 	int err, ch, hdev, finfo, fdir;
16566660095SIan Lepore 	char *pstr;
16666660095SIan Lepore 	char dev_name[PATH_MAX * 2 + 5];
16766660095SIan Lepore 
16866660095SIan Lepore 	finfo = 0;
16966660095SIan Lepore 	fdir = DIR_NONE;
17066660095SIan Lepore 
17166660095SIan Lepore 	hdev = -1;
17266660095SIan Lepore 	err = 0;
17366660095SIan Lepore 
17466660095SIan Lepore 	dev_name[0] = 0;
17566660095SIan Lepore 
17666660095SIan Lepore 	opt.mode = -1;
17766660095SIan Lepore 	opt.speed = -1;
17866660095SIan Lepore 	opt.count = 0;
17966660095SIan Lepore 	opt.ASCII = 0;
18066660095SIan Lepore 	opt.binary = 0;
18166660095SIan Lepore 	opt.lsb = 0;
18266660095SIan Lepore 	opt.verbose = 0;
18366660095SIan Lepore 	opt.ncmd = 0;
18466660095SIan Lepore 	opt.pcmd = NULL;
18566660095SIan Lepore 
18666660095SIan Lepore 	while (!err && (ch = getopt(argc, argv, "f:d:m:s:c:C:AbLvih")) != -1) {
18766660095SIan Lepore 		switch (ch) {
18866660095SIan Lepore 		case 'd':
18966660095SIan Lepore 			if (optarg[0] == 'r') {
19066660095SIan Lepore 				if (optarg[1] == 'w' && optarg[2] == 0) {
19166660095SIan Lepore 					fdir = DIR_READWRITE;
19266660095SIan Lepore 				}
19366660095SIan Lepore 				else if (optarg[1] == 0) {
19466660095SIan Lepore 					fdir = DIR_READ;
19566660095SIan Lepore 				}
19666660095SIan Lepore 			}
19766660095SIan Lepore 			else if (optarg[0] == 'w' && optarg[1] == 0) {
19866660095SIan Lepore 				fdir = DIR_WRITE;
19966660095SIan Lepore 			}
20066660095SIan Lepore 			else {
20166660095SIan Lepore 				err = 1;
20266660095SIan Lepore 			}
20366660095SIan Lepore 			break;
20466660095SIan Lepore 
20566660095SIan Lepore 		case 'f':
20666660095SIan Lepore 			if (!optarg[0]) {	/* unlikely */
20766660095SIan Lepore 				fputs("error - missing device name\n", stderr);
20866660095SIan Lepore 				err = 1;
20966660095SIan Lepore 			}
21066660095SIan Lepore 			else {
21166660095SIan Lepore 				if (optarg[0] == '/')
21266660095SIan Lepore 					strlcpy(dev_name, optarg,
21366660095SIan Lepore 					    sizeof(dev_name));
21466660095SIan Lepore 				else
21566660095SIan Lepore 					snprintf(dev_name, sizeof(dev_name),
21666660095SIan Lepore 					    "/dev/%s", optarg);
21766660095SIan Lepore 			}
21866660095SIan Lepore 			break;
21966660095SIan Lepore 
22066660095SIan Lepore 		case 'm':
22166660095SIan Lepore 			opt.mode = (int)strtol(optarg, &pstr, 10);
22266660095SIan Lepore 
22366660095SIan Lepore 			if (!pstr || *pstr || opt.mode < 0 || opt.mode > 3) {
22466660095SIan Lepore 				fprintf(stderr, "Invalid mode specified: %s\n",
22566660095SIan Lepore 				    optarg);
22666660095SIan Lepore 				err = 1;
22766660095SIan Lepore 			}
22866660095SIan Lepore 			break;
22966660095SIan Lepore 
23066660095SIan Lepore 		case 's':
23166660095SIan Lepore 			opt.speed = (int)strtol(optarg, &pstr, 10);
23266660095SIan Lepore 
23366660095SIan Lepore 			if (!pstr || *pstr || opt.speed < 0) {
23466660095SIan Lepore 				fprintf(stderr, "Invalid speed specified: %s\n",
23566660095SIan Lepore 				    optarg);
23666660095SIan Lepore 				err = 1;
23766660095SIan Lepore 			}
23866660095SIan Lepore 			break;
23966660095SIan Lepore 
24066660095SIan Lepore 		case 'c':
24166660095SIan Lepore 			opt.count = (int)strtol(optarg, &pstr, 10);
24266660095SIan Lepore 
24366660095SIan Lepore 			if (!pstr || *pstr) {
24466660095SIan Lepore 				fprintf(stderr, "Invalid count specified: %s\n",
24566660095SIan Lepore 				    optarg);
24666660095SIan Lepore 				err = 1;
24766660095SIan Lepore 			}
24866660095SIan Lepore 			break;
24966660095SIan Lepore 
25066660095SIan Lepore 		case 'C':
25166660095SIan Lepore 			if(opt.pcmd) /* specified more than once */
25266660095SIan Lepore 				err = 1;
25366660095SIan Lepore 			else {
25466660095SIan Lepore 				/* get malloc'd buffer or error */
25566660095SIan Lepore 				if (interpret_command_bytes(optarg, &opt))
25666660095SIan Lepore 					err = 1;
25766660095SIan Lepore 			}
25866660095SIan Lepore 
25966660095SIan Lepore 			break;
26066660095SIan Lepore 
26166660095SIan Lepore 		case 'A':
26266660095SIan Lepore 			opt.ASCII = 1;
26366660095SIan Lepore 			break;
26466660095SIan Lepore 
26566660095SIan Lepore 		case 'b':
26666660095SIan Lepore 			opt.binary = 1;
26766660095SIan Lepore 			break;
26866660095SIan Lepore 
26966660095SIan Lepore 		case 'L':
27066660095SIan Lepore 			opt.lsb = 1;
27166660095SIan Lepore 			break;
27266660095SIan Lepore 
27366660095SIan Lepore 		case 'v':
27466660095SIan Lepore 			opt.verbose++;
27566660095SIan Lepore 			break;
27666660095SIan Lepore 
27766660095SIan Lepore 		case 'i':
27866660095SIan Lepore 			finfo = 1;
27966660095SIan Lepore 			break;
28066660095SIan Lepore 
28166660095SIan Lepore 		default:
28266660095SIan Lepore 			err = 1;
28366660095SIan Lepore 			/* FALLTHROUGH */
28466660095SIan Lepore 		case 'h':
28566660095SIan Lepore 			usage();
28666660095SIan Lepore 			goto the_end;
28766660095SIan Lepore 		}
28866660095SIan Lepore 	}
28966660095SIan Lepore 
29066660095SIan Lepore 	argc -= optind;
29166660095SIan Lepore 	argv += optind;
29266660095SIan Lepore 
29366660095SIan Lepore 	if (err ||
29466660095SIan Lepore 	    (fdir == DIR_NONE && !finfo && opt.mode == -1 && opt.speed == -1 && opt.count == 0)) {
29566660095SIan Lepore 		/*
29666660095SIan Lepore 		 * if any of the direction, mode, speed, or count not specified,
29766660095SIan Lepore 		 * print usage
29866660095SIan Lepore 		 */
29966660095SIan Lepore 
30066660095SIan Lepore 		usage();
30166660095SIan Lepore 		goto the_end;
30266660095SIan Lepore 	}
30366660095SIan Lepore 
30466660095SIan Lepore 	if ((opt.count != 0 || opt.ncmd != 0) && fdir == DIR_NONE) {
30566660095SIan Lepore 		/*
30666660095SIan Lepore 		 * count was specified, but direction was not.  default is
30766660095SIan Lepore 		 * read/write
30866660095SIan Lepore 		 */
30966660095SIan Lepore 		/*
31066660095SIan Lepore 		 * this includes a negative count, which implies write from
31166660095SIan Lepore 		 * stdin
31266660095SIan Lepore 		 */
31366660095SIan Lepore 		if (opt.count == 0)
31466660095SIan Lepore 			fdir = DIR_WRITE;
31566660095SIan Lepore 		else
31666660095SIan Lepore 			fdir = DIR_READWRITE;
31766660095SIan Lepore 	}
31866660095SIan Lepore 
31966660095SIan Lepore 	if (opt.count < 0 && fdir != DIR_READWRITE && fdir != DIR_WRITE) {
32066660095SIan Lepore 		fprintf(stderr, "Invalid length %d when not writing data\n",
32166660095SIan Lepore 		    opt.count);
32266660095SIan Lepore 
32366660095SIan Lepore 		err = 1;
32466660095SIan Lepore 		usage();
32566660095SIan Lepore 		goto the_end;
32666660095SIan Lepore 	}
32766660095SIan Lepore 
32866660095SIan Lepore 
32966660095SIan Lepore 	if (!dev_name[0])	/* no device name specified */
33066660095SIan Lepore 		strlcpy(dev_name, DEFAULT_DEVICE_NAME, sizeof(dev_name));
33166660095SIan Lepore 
33266660095SIan Lepore 	hdev = open(dev_name, O_RDWR);
33366660095SIan Lepore 
33466660095SIan Lepore 	if (hdev == -1) {
33566660095SIan Lepore 		fprintf(stderr, "Error - unable to open '%s', errno=%d\n",
33666660095SIan Lepore 		    dev_name, errno);
33766660095SIan Lepore 		err = 1;
33866660095SIan Lepore 		goto the_end;
33966660095SIan Lepore 	}
34066660095SIan Lepore 
34166660095SIan Lepore 	if (finfo) {
34266660095SIan Lepore 		err = get_info(hdev, dev_name);
34366660095SIan Lepore 		goto the_end;
34466660095SIan Lepore 	}
34566660095SIan Lepore 
34666660095SIan Lepore 	/* check and assign mode, speed */
34766660095SIan Lepore 
34866660095SIan Lepore 	if (opt.mode != -1) {
34966660095SIan Lepore 		err = set_mode(hdev, &opt);
35066660095SIan Lepore 
35166660095SIan Lepore 		if (err)
35266660095SIan Lepore 			goto the_end;
35366660095SIan Lepore 	}
35466660095SIan Lepore 
35566660095SIan Lepore 	if (opt.speed != -1) {
35666660095SIan Lepore 		err = set_speed(hdev, &opt);
35766660095SIan Lepore 
35866660095SIan Lepore 		if (err)
35966660095SIan Lepore 			goto the_end;
36066660095SIan Lepore 	}
36166660095SIan Lepore 
36266660095SIan Lepore 	/* do data transfer */
36366660095SIan Lepore 
36466660095SIan Lepore 	if (fdir == DIR_READ) {
36566660095SIan Lepore 		err = perform_read(hdev, &opt);
36666660095SIan Lepore 	}
36766660095SIan Lepore 	else if (fdir == DIR_WRITE) {
36866660095SIan Lepore 		err = perform_write(hdev, &opt);
36966660095SIan Lepore 	}
37066660095SIan Lepore 	else if (fdir == DIR_READWRITE) {
37166660095SIan Lepore 		err = perform_readwrite(hdev, &opt);
37266660095SIan Lepore 	}
37366660095SIan Lepore 
37466660095SIan Lepore the_end:
37566660095SIan Lepore 
37666660095SIan Lepore 	if (hdev != -1)
37766660095SIan Lepore 		close(hdev);
37866660095SIan Lepore 
37966660095SIan Lepore 	free(opt.pcmd);
38066660095SIan Lepore 
38166660095SIan Lepore 	return (err);
38266660095SIan Lepore }
38366660095SIan Lepore 
38466660095SIan Lepore static int
38566660095SIan Lepore interpret_command_bytes(const char *parg, struct spi_options *popt)
38666660095SIan Lepore {
38766660095SIan Lepore 	int ch, ch2, ctr, cbcmd, err;
38866660095SIan Lepore 	const char *ppos;
38966660095SIan Lepore 	void *ptemp;
39066660095SIan Lepore 	uint8_t *pcur;
39166660095SIan Lepore 
39266660095SIan Lepore 	err = 0;
39366660095SIan Lepore 	cbcmd = DEFAULT_BUFFER_SIZE; /* initial cmd buffer size */
39466660095SIan Lepore 	popt->pcmd = (uint8_t *)malloc(cbcmd);
39566660095SIan Lepore 
39666660095SIan Lepore 	if (!popt->pcmd)
39766660095SIan Lepore 		return 1;
39866660095SIan Lepore 
39966660095SIan Lepore 	pcur = popt->pcmd;
40066660095SIan Lepore 
40166660095SIan Lepore 	ctr = 0;
40266660095SIan Lepore 	ppos = parg;
40366660095SIan Lepore 
40466660095SIan Lepore 	while (*ppos) {
40566660095SIan Lepore 		while (*ppos && *ppos <= ' ') {
40666660095SIan Lepore 			ppos++; /* skip (optional) leading white space */
40766660095SIan Lepore 		}
40866660095SIan Lepore 
40966660095SIan Lepore 		if (!*ppos)
41066660095SIan Lepore 			break; /* I am done */
41166660095SIan Lepore 
41266660095SIan Lepore 		ch = hexval(*(ppos++));
41366660095SIan Lepore 		if (ch < 0 || !*ppos) { /* must be valid pair of hex characters */
41466660095SIan Lepore 			err = 1;
41566660095SIan Lepore 			goto the_end;
41666660095SIan Lepore 		}
41766660095SIan Lepore 
41866660095SIan Lepore 		ch2 = hexval(*(ppos++));
41966660095SIan Lepore 		if (ch2 < 0) {
42066660095SIan Lepore 			err = 1;
42166660095SIan Lepore 			goto the_end;
42266660095SIan Lepore 		}
42366660095SIan Lepore 
42466660095SIan Lepore 		ch = (ch * 16 + ch2) & 0xff; /* convert to byte */
42566660095SIan Lepore 
42666660095SIan Lepore 		if (ctr >= cbcmd) { /* need re-alloc buffer? (unlikely) */
42766660095SIan Lepore 			cbcmd += 8192; /* increase by additional 8k */
42866660095SIan Lepore 			ptemp = realloc(popt->pcmd, cbcmd);
42966660095SIan Lepore 
43066660095SIan Lepore 			if (!ptemp) {
43166660095SIan Lepore 				err = 1;
43266660095SIan Lepore 				fprintf(stderr,
43366660095SIan Lepore 					"Not enough memory to interpret command bytes, errno=%d\n",
43466660095SIan Lepore 					errno);
43566660095SIan Lepore 				goto the_end;
43666660095SIan Lepore 			}
43766660095SIan Lepore 
43866660095SIan Lepore 			popt->pcmd = (uint8_t *)ptemp;
43966660095SIan Lepore 			pcur = popt->pcmd + ctr;
44066660095SIan Lepore 		}
44166660095SIan Lepore 
44266660095SIan Lepore 		if (popt->lsb)
44366660095SIan Lepore 			*pcur = reversebits[ch];
44466660095SIan Lepore 		else
44566660095SIan Lepore 			*pcur = (uint8_t)ch;
44666660095SIan Lepore 
44766660095SIan Lepore 		pcur++;
44866660095SIan Lepore 		ctr++;
44966660095SIan Lepore 	}
45066660095SIan Lepore 
45166660095SIan Lepore 	popt->ncmd = ctr; /* record num bytes in '-C' argument */
45266660095SIan Lepore 
45366660095SIan Lepore the_end:
45466660095SIan Lepore 
45566660095SIan Lepore 	/* at this point popt->pcmd is NULL or a valid pointer */
45666660095SIan Lepore 
45766660095SIan Lepore 	return err;
45866660095SIan Lepore }
45966660095SIan Lepore 
46066660095SIan Lepore static int
46166660095SIan Lepore get_info(int hdev, const char *dev_name)
46266660095SIan Lepore {
46366660095SIan Lepore 	uint32_t fmode, fspeed;
46466660095SIan Lepore 	int err;
46566660095SIan Lepore 	char temp_buf[PATH_MAX], cpath[PATH_MAX];
46666660095SIan Lepore 
46766660095SIan Lepore 	if (!realpath(dev_name, cpath)) /* get canonical name for info purposes */
46866660095SIan Lepore 		strlcpy(cpath, temp_buf, sizeof(cpath));  /* this shouldn't happen */
46966660095SIan Lepore 
47066660095SIan Lepore 	err = ioctl(hdev, SPIGENIOC_GET_SPI_MODE, &fmode);
47166660095SIan Lepore 
47266660095SIan Lepore 	if (err == 0)
47366660095SIan Lepore 		err = ioctl(hdev, SPIGENIOC_GET_CLOCK_SPEED, &fspeed);
47466660095SIan Lepore 
47566660095SIan Lepore 	if (err == 0) {
47666660095SIan Lepore 		fprintf(stderr,
47766660095SIan Lepore 		        "Device name:   %s\n"
47866660095SIan Lepore 		        "Device mode:   %d\n"
47966660095SIan Lepore 		        "Device speed:  %d\n",
48066660095SIan Lepore 		        cpath, fmode, fspeed);//, max_cmd, max_data, temp_buf);
48166660095SIan Lepore 	}
48266660095SIan Lepore 	else
48366660095SIan Lepore 		fprintf(stderr, "Unable to query info (err=%d), errno=%d\n",
48466660095SIan Lepore 		    err, errno);
48566660095SIan Lepore 
48666660095SIan Lepore 	return err;
48766660095SIan Lepore }
48866660095SIan Lepore 
48966660095SIan Lepore static int
49066660095SIan Lepore set_mode(int hdev, struct spi_options *popt)
49166660095SIan Lepore {
49266660095SIan Lepore 	uint32_t fmode = popt->mode;
49366660095SIan Lepore 
49466660095SIan Lepore 	if (popt->mode < 0)	/* use default? */
49566660095SIan Lepore 		return 0;
49666660095SIan Lepore 
49766660095SIan Lepore 	return ioctl(hdev, SPIGENIOC_SET_SPI_MODE, &fmode);
49866660095SIan Lepore }
49966660095SIan Lepore 
50066660095SIan Lepore static int
50166660095SIan Lepore set_speed(int hdev, struct spi_options *popt)
50266660095SIan Lepore {
50366660095SIan Lepore 	uint32_t clock_speed = popt->speed;
50466660095SIan Lepore 
50566660095SIan Lepore 	if (popt->speed < 0)
50666660095SIan Lepore 		return 0;
50766660095SIan Lepore 
50866660095SIan Lepore 	return ioctl(hdev, SPIGENIOC_SET_CLOCK_SPEED, &clock_speed);
50966660095SIan Lepore }
51066660095SIan Lepore 
51166660095SIan Lepore static int
51266660095SIan Lepore hexval(char c)
51366660095SIan Lepore {
51466660095SIan Lepore 	if (c >= '0' && c <= '9') {
51566660095SIan Lepore 		return c - '0';
51666660095SIan Lepore 	} else if (c >= 'A' && c <= 'F') {
51766660095SIan Lepore 		return c - 'A' + 10;
51866660095SIan Lepore 	} else if (c >= 'a' && c <= 'f') {
51966660095SIan Lepore 		return c - 'a' + 10;
52066660095SIan Lepore 	}
52166660095SIan Lepore 	return -1;
52266660095SIan Lepore }
52366660095SIan Lepore 
52466660095SIan Lepore static void *
52566660095SIan Lepore prep_write_buffer(struct spi_options *popt)
52666660095SIan Lepore {
52766660095SIan Lepore 	int ch, ch2, ch3, ncmd, lsb, err;
52866660095SIan Lepore 	uint8_t *pdata, *pdat2;
52966660095SIan Lepore 	size_t cbdata, cbread;
53066660095SIan Lepore 	const char *szbytes;
53166660095SIan Lepore 
53266660095SIan Lepore 	ncmd = popt->ncmd; /* num command bytes (can be zero) */
53366660095SIan Lepore 
53466660095SIan Lepore 	if (ncmd == 0 && popt->count == 0)
53566660095SIan Lepore 		return NULL;	/* always since it's an error if it happens
53666660095SIan Lepore 				 * now */
53766660095SIan Lepore 
53866660095SIan Lepore 	if (popt->count < 0) {
53966660095SIan Lepore 		cbdata = DEFAULT_BUFFER_SIZE;
54066660095SIan Lepore 	}
54166660095SIan Lepore 	else {
54266660095SIan Lepore 		cbdata = popt->count;
54366660095SIan Lepore 	}
54466660095SIan Lepore 
54566660095SIan Lepore 	lsb = popt->lsb; /* non-zero if LSB order; else MSB */
54666660095SIan Lepore 
54766660095SIan Lepore 	pdata = malloc(cbdata + ncmd + 1);
54866660095SIan Lepore 	cbread = 0;
54966660095SIan Lepore 
55066660095SIan Lepore 	err = 0;
55166660095SIan Lepore 
55266660095SIan Lepore 	if (!pdata)
55366660095SIan Lepore 		return NULL;
55466660095SIan Lepore 
55566660095SIan Lepore 	if (popt->pcmd && ncmd > 0) {
55666660095SIan Lepore 		memcpy(pdata, popt->pcmd, ncmd); /* copy command bytes */
55766660095SIan Lepore 		pdat2 = pdata + ncmd;
55866660095SIan Lepore 	}
55966660095SIan Lepore 	else
56066660095SIan Lepore 		pdat2 = pdata; /* no prepended command data */
56166660095SIan Lepore 
56266660095SIan Lepore 	/*
56366660095SIan Lepore 	 * read up to 'cbdata' bytes.  If I get an EOF, do one of two things:
56466660095SIan Lepore 	 * a) change the data count to match how many bytes I read in b) fill
56566660095SIan Lepore 	 * the rest of the input buffer with zeros
56666660095SIan Lepore 	 *
56766660095SIan Lepore 	 * If the specified length is negative, I do 'a', else 'b'
56866660095SIan Lepore 	 */
56966660095SIan Lepore 
57066660095SIan Lepore 	while (!err && cbread < cbdata && (ch = fgetc(stdin)) != EOF) {
57166660095SIan Lepore 		if (popt->ASCII) {
57266660095SIan Lepore 			/* skip consecutive white space */
57366660095SIan Lepore 
57466660095SIan Lepore 			while (ch <= ' ') {
57566660095SIan Lepore 				if ((ch = fgetc(stdin)) == EOF)
57666660095SIan Lepore 					break;
57766660095SIan Lepore 			}
57866660095SIan Lepore 
57966660095SIan Lepore 			if (ch != EOF) {
58066660095SIan Lepore 				ch2 = hexval(ch);
58166660095SIan Lepore 
58266660095SIan Lepore 				if (ch2 < 0) {
58366660095SIan Lepore invalid_character:
58466660095SIan Lepore 					fprintf(stderr,
58566660095SIan Lepore 					    "Invalid input character '%c'\n", ch);
58666660095SIan Lepore 					err = 1;
58766660095SIan Lepore 					break;
58866660095SIan Lepore 				}
58966660095SIan Lepore 
59066660095SIan Lepore 				ch = fgetc(stdin);
59166660095SIan Lepore 
59266660095SIan Lepore 				if (ch != EOF) {
59366660095SIan Lepore 					ch3 = hexval(ch);
59466660095SIan Lepore 
59566660095SIan Lepore 					if (ch3 < 0)
59666660095SIan Lepore 						goto invalid_character;
59766660095SIan Lepore 
59866660095SIan Lepore 					ch = ch2 * 16 + ch3;
59966660095SIan Lepore 				}
60066660095SIan Lepore 			}
60166660095SIan Lepore 
60266660095SIan Lepore 			if (err || ch == EOF)
60366660095SIan Lepore 				break;
60466660095SIan Lepore 		}
60566660095SIan Lepore 
60666660095SIan Lepore 		/* for LSB, flip the bits - otherwise, just copy the value */
60766660095SIan Lepore 		if (lsb)
60866660095SIan Lepore 			pdat2[cbread] = reversebits[ch];
60966660095SIan Lepore 		else
61066660095SIan Lepore 			pdat2[cbread] = (uint8_t) ch;
61166660095SIan Lepore 
61266660095SIan Lepore 		cbread++; /* increment num bytes read so far */
61366660095SIan Lepore 	}
61466660095SIan Lepore 
61566660095SIan Lepore 	/* if it was an error, not an EOF, that ended the I/O, return NULL */
61666660095SIan Lepore 
61766660095SIan Lepore 	if (err || ferror(stdin)) {
61866660095SIan Lepore 		free(pdata);
61966660095SIan Lepore 		return NULL;
62066660095SIan Lepore 	}
62166660095SIan Lepore 
62266660095SIan Lepore 	if (popt->verbose > 0) {
62366660095SIan Lepore 		const char *sz_bytes;
62466660095SIan Lepore 
62566660095SIan Lepore 		if (cbread != 1)
62666660095SIan Lepore 			sz_bytes = "bytes";	/* correct plurality of 'byte|bytes' */
62766660095SIan Lepore 		else
62866660095SIan Lepore 			sz_bytes = "byte";
62966660095SIan Lepore 
63066660095SIan Lepore 		if (popt->ASCII)
63166660095SIan Lepore 			fprintf(stderr, "ASCII input of %zd %s\n", cbread,
63266660095SIan Lepore 			    sz_bytes);
63366660095SIan Lepore 		else
63466660095SIan Lepore 			fprintf(stderr, "Binary input of %zd %s\n", cbread,
63566660095SIan Lepore 			    sz_bytes);
63666660095SIan Lepore 	}
63766660095SIan Lepore 
63866660095SIan Lepore 	/*
63966660095SIan Lepore 	 * if opt.count is negative, copy actual byte count to opt.count which does
64066660095SIan Lepore 	 * not include any of the 'command' bytes that are being sent.  Can be zero.
64166660095SIan Lepore 	 */
64266660095SIan Lepore 	if (popt->count < 0) {
64366660095SIan Lepore 		popt->count = cbread;
64466660095SIan Lepore 	}
64566660095SIan Lepore 	/*
64666660095SIan Lepore 	 * for everything else, fill the rest of the read buffer with '0'
64766660095SIan Lepore 	 * bytes, as per the standard practice for SPI
64866660095SIan Lepore 	 */
64966660095SIan Lepore 	else {
65066660095SIan Lepore 		while (cbread < cbdata)
65166660095SIan Lepore 			pdat2[cbread++] = 0;
65266660095SIan Lepore 	}
65366660095SIan Lepore 
65466660095SIan Lepore 	/*
65566660095SIan Lepore 	 * popt->count bytes will be sent and read from the SPI, preceded by the
65666660095SIan Lepore 	 * 'popt->ncmd' command bytes (if any).
65766660095SIan Lepore 	 * So we must use 'popt->count' and 'popt->ncmd' from this point on in
65866660095SIan Lepore 	 * the code.
65966660095SIan Lepore 	 */
66066660095SIan Lepore 
66166660095SIan Lepore 	if (popt->verbose > 0 && popt->count + popt->ncmd) {
66266660095SIan Lepore 		if ((popt->count + popt->ncmd) == 1)
66366660095SIan Lepore 			szbytes = "byte";
66466660095SIan Lepore 		else
66566660095SIan Lepore 			szbytes = "bytes";
66666660095SIan Lepore 
66766660095SIan Lepore 		fprintf(stderr, "Writing %d %s to SPI device\n",
66866660095SIan Lepore 		        popt->count + popt->ncmd, szbytes);
66966660095SIan Lepore 
67066660095SIan Lepore 		verbose_dump_buffer(pdata, popt->count + popt->ncmd, lsb);
67166660095SIan Lepore 	}
67266660095SIan Lepore 
67366660095SIan Lepore 	return pdata;
67466660095SIan Lepore }
67566660095SIan Lepore 
67666660095SIan Lepore static int
67766660095SIan Lepore _read_write(int hdev, void *bufw, void *bufr, int cbrw, int lsb)
67866660095SIan Lepore {
67966660095SIan Lepore 	int	err, ctr;
68066660095SIan Lepore 	struct spigen_transfer spi;
68166660095SIan Lepore 
68266660095SIan Lepore 	if (!cbrw)
68366660095SIan Lepore 		return 0;
68466660095SIan Lepore 
68566660095SIan Lepore 	if (!bufr)
68666660095SIan Lepore 		bufr = bufw;
68766660095SIan Lepore 	else
68866660095SIan Lepore 		memcpy(bufr, bufw, cbrw);	/* transaction uses bufr for
68966660095SIan Lepore 						 * both R and W */
69066660095SIan Lepore 
69166660095SIan Lepore 	bzero(&spi, sizeof(spi));	/* zero structure first */
69266660095SIan Lepore 
69366660095SIan Lepore 	/* spigen code seems to suggest there must be at least 1 command byte */
69466660095SIan Lepore 
69566660095SIan Lepore 	spi.st_command.iov_base = bufr;
69666660095SIan Lepore 	spi.st_command.iov_len = cbrw;
69766660095SIan Lepore 
69866660095SIan Lepore 	/*
69966660095SIan Lepore 	 * The remaining members for spi.st_data are zero - all bytes are
70066660095SIan Lepore 	 * 'command' for this. The driver doesn't really do anything different
70166660095SIan Lepore 	 * for 'command' vs 'data' and at least one command byte must be sent in
70266660095SIan Lepore 	 * the transaction.
70366660095SIan Lepore 	 */
70466660095SIan Lepore 
70566660095SIan Lepore 	err = ioctl(hdev, SPIGENIOC_TRANSFER, &spi) < 0 ? -1 : 0;
70666660095SIan Lepore 
70766660095SIan Lepore 	if (!err && lsb) {
70866660095SIan Lepore 		/* flip the bits for 'lsb' mode */
70966660095SIan Lepore 		for (ctr = 0; ctr < cbrw; ctr++) {
71066660095SIan Lepore 			((uint8_t *) bufr)[ctr] =
71166660095SIan Lepore 			    reversebits[((uint8_t *)bufr)[ctr]];
71266660095SIan Lepore 		}
71366660095SIan Lepore 	}
71466660095SIan Lepore 
71566660095SIan Lepore 	if (err)
71666660095SIan Lepore 		fprintf(stderr, "Error performing SPI transaction, errno=%d\n",
71766660095SIan Lepore 		    errno);
71866660095SIan Lepore 
71966660095SIan Lepore 	return err;
72066660095SIan Lepore }
72166660095SIan Lepore 
72266660095SIan Lepore static int
72366660095SIan Lepore _do_data_output(void *pr, struct spi_options *popt)
72466660095SIan Lepore {
725*917d1846SIan Lepore 	int	err, idx, icount;
72666660095SIan Lepore 	const char *sz_bytes, *sz_byte2;
72766660095SIan Lepore 	const uint8_t *pbuf;
72866660095SIan Lepore 
72966660095SIan Lepore 	pbuf = (uint8_t *)pr + popt->ncmd; /* only the data we want */
73066660095SIan Lepore 	icount = popt->count;
73166660095SIan Lepore 	err = 0;
73266660095SIan Lepore 
73366660095SIan Lepore 	if (icount <= 0) {
73466660095SIan Lepore 		return -1; /* should not but could happen */
73566660095SIan Lepore 	}
73666660095SIan Lepore 
73766660095SIan Lepore 	if (icount != 1)
73866660095SIan Lepore 		sz_bytes = "bytes";	/* correct plurality of 'byte|bytes' */
73966660095SIan Lepore 	else
74066660095SIan Lepore 		sz_bytes = "byte";
74166660095SIan Lepore 
74266660095SIan Lepore 	if (popt->ncmd != 1)
74366660095SIan Lepore 		sz_byte2 = "bytes";
74466660095SIan Lepore 	else
74566660095SIan Lepore 		sz_byte2 = "byte";
74666660095SIan Lepore 
74766660095SIan Lepore 	/* binary on stdout */
74866660095SIan Lepore 	if (popt->binary || !popt->ASCII) {
74966660095SIan Lepore 		if (popt->verbose > 0)
75066660095SIan Lepore 			fprintf(stderr, "Binary output of %d %s\n", icount,
75166660095SIan Lepore 			    sz_bytes);
75266660095SIan Lepore 
75366660095SIan Lepore 		err = (int)fwrite(pbuf, 1, icount, stdout) != icount;
75466660095SIan Lepore 	}
75566660095SIan Lepore 	else if (icount > 0) {
75666660095SIan Lepore 		if (popt->verbose > 0)
75766660095SIan Lepore 			fprintf(stderr, "ASCII output of %d %s\n", icount,
75866660095SIan Lepore 			    sz_bytes);
75966660095SIan Lepore 
76066660095SIan Lepore 		/* ASCII output */
761*917d1846SIan Lepore 		for (idx = 0; !err && idx < icount; idx++) {
762*917d1846SIan Lepore 			if (idx) {
76366660095SIan Lepore 				/*
76466660095SIan Lepore 				 * not the first time, insert separating space
76566660095SIan Lepore 				 */
76666660095SIan Lepore 				err = fputc(' ', stdout) == EOF;
76766660095SIan Lepore 			}
76866660095SIan Lepore 
76966660095SIan Lepore 			if (!err)
770*917d1846SIan Lepore 				err = fprintf(stdout, "%02hhx", pbuf[idx]) < 0;
77166660095SIan Lepore 		}
77266660095SIan Lepore 
77366660095SIan Lepore 		if (!err)
77466660095SIan Lepore 			err = fputc('\n', stdout) == EOF;
77566660095SIan Lepore 	}
77666660095SIan Lepore 
77766660095SIan Lepore 	/* verbose text out on stderr */
77866660095SIan Lepore 
77966660095SIan Lepore 	if (err)
78066660095SIan Lepore 		fprintf(stderr, "Error writing to stdout, errno=%d\n", errno);
78166660095SIan Lepore 	else if (popt->verbose > 0 && icount) {
78266660095SIan Lepore 		fprintf(stderr,
78366660095SIan Lepore 		    "%d command %s and %d data %s read from SPI device\n",
78466660095SIan Lepore 		    popt->ncmd, sz_byte2, icount, sz_bytes);
78566660095SIan Lepore 
78666660095SIan Lepore 		/* verbose output will show the command bytes as well */
78766660095SIan Lepore 		verbose_dump_buffer(pr, icount + popt->ncmd, popt->lsb);
78866660095SIan Lepore 	}
78966660095SIan Lepore 
79066660095SIan Lepore 	return err;
79166660095SIan Lepore }
79266660095SIan Lepore 
79366660095SIan Lepore static int
79466660095SIan Lepore perform_read(int hdev, struct spi_options *popt)
79566660095SIan Lepore {
79666660095SIan Lepore 	int icount, err;
79766660095SIan Lepore 	void   *pr, *pw;
79866660095SIan Lepore 
79966660095SIan Lepore 	pr = NULL;
80066660095SIan Lepore 	icount = popt->count + popt->ncmd;
80166660095SIan Lepore 
80266660095SIan Lepore 	/* prep write buffer filled with 0 bytes */
80366660095SIan Lepore 	pw = malloc(icount);
80466660095SIan Lepore 
80566660095SIan Lepore 	if (!pw) {
80666660095SIan Lepore 		err = -1;
80766660095SIan Lepore 		goto the_end;
80866660095SIan Lepore 	}
80966660095SIan Lepore 
81066660095SIan Lepore 	bzero(pw, icount);
81166660095SIan Lepore 
81266660095SIan Lepore 	/* if I included a command sequence, copy bytes to the write buf */
81366660095SIan Lepore 	if (popt->pcmd && popt->ncmd > 0)
81466660095SIan Lepore 		memcpy(pw, popt->pcmd, popt->ncmd);
81566660095SIan Lepore 
81666660095SIan Lepore 	pr = malloc(icount + 1);
81766660095SIan Lepore 
81866660095SIan Lepore 	if (!pr) {
81966660095SIan Lepore 		err = -2;
82066660095SIan Lepore 		goto the_end;
82166660095SIan Lepore 	}
82266660095SIan Lepore 
82366660095SIan Lepore 	bzero(pr, icount);
82466660095SIan Lepore 
82566660095SIan Lepore 	err = _read_write(hdev, pw, pr, icount, popt->lsb);
82666660095SIan Lepore 
82766660095SIan Lepore 	if (!err && popt->count > 0)
82866660095SIan Lepore 		err = _do_data_output(pr, popt);
82966660095SIan Lepore 
83066660095SIan Lepore the_end:
83166660095SIan Lepore 
83266660095SIan Lepore 	free(pr);
83366660095SIan Lepore 	free(pw);
83466660095SIan Lepore 
83566660095SIan Lepore 	return err;
83666660095SIan Lepore }
83766660095SIan Lepore 
83866660095SIan Lepore static int
83966660095SIan Lepore perform_write(int hdev, struct spi_options *popt)
84066660095SIan Lepore {
84166660095SIan Lepore 	int err;
84266660095SIan Lepore 	void   *pw;
84366660095SIan Lepore 
84466660095SIan Lepore 	/* read data from cmd buf and stdin and write to 'write' buffer */
84566660095SIan Lepore 
84666660095SIan Lepore 	pw = prep_write_buffer(popt);
84766660095SIan Lepore 
84866660095SIan Lepore 	if (!pw) {
84966660095SIan Lepore 		err = -1;
85066660095SIan Lepore 		goto the_end;
85166660095SIan Lepore 	}
85266660095SIan Lepore 
85366660095SIan Lepore 	err = _read_write(hdev, pw, NULL, popt->count + popt->ncmd, popt->lsb);
85466660095SIan Lepore 
85566660095SIan Lepore the_end:
85666660095SIan Lepore 
85766660095SIan Lepore 	free(pw);
85866660095SIan Lepore 
85966660095SIan Lepore 	return err;
86066660095SIan Lepore }
86166660095SIan Lepore 
86266660095SIan Lepore static int
86366660095SIan Lepore perform_readwrite(int hdev, struct spi_options *popt)
86466660095SIan Lepore {
86566660095SIan Lepore 	int icount, err;
86666660095SIan Lepore 	void   *pr, *pw;
86766660095SIan Lepore 
86866660095SIan Lepore 	pr = NULL;
86966660095SIan Lepore 
87066660095SIan Lepore 	pw = prep_write_buffer(popt);
87166660095SIan Lepore 	icount = popt->count + popt->ncmd; /* assign after fn call */
87266660095SIan Lepore 
87366660095SIan Lepore 	if (!pw) {
87466660095SIan Lepore 		err = -1;
87566660095SIan Lepore 		goto the_end;
87666660095SIan Lepore 	}
87766660095SIan Lepore 
87866660095SIan Lepore 	pr = malloc(icount + 1);
87966660095SIan Lepore 
88066660095SIan Lepore 	if (!pr) {
88166660095SIan Lepore 		err = -2;
88266660095SIan Lepore 		goto the_end;
88366660095SIan Lepore 	}
88466660095SIan Lepore 
88566660095SIan Lepore 	bzero(pr, icount);
88666660095SIan Lepore 
88766660095SIan Lepore 	err = _read_write(hdev, pw, pr, icount, popt->lsb);
88866660095SIan Lepore 
88966660095SIan Lepore 	if (!err)
89066660095SIan Lepore 		err = _do_data_output(pr, popt);
89166660095SIan Lepore 
89266660095SIan Lepore the_end:
89366660095SIan Lepore 
89466660095SIan Lepore 	free(pr);
89566660095SIan Lepore 	free(pw);
89666660095SIan Lepore 
89766660095SIan Lepore 	return err;
89866660095SIan Lepore }
89966660095SIan Lepore 
90066660095SIan Lepore 
90166660095SIan Lepore static void
90266660095SIan Lepore verbose_dump_buffer(void *pbuf, int icount, int lsb)
90366660095SIan Lepore {
90466660095SIan Lepore 	uint8_t	ch;
905*917d1846SIan Lepore 	int	ictr, ictr2, idx;
90666660095SIan Lepore 
90766660095SIan Lepore 	fputs("        |  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F "
90866660095SIan Lepore 	      "|                  |\n", stderr);
90966660095SIan Lepore 
91066660095SIan Lepore 	for (ictr = 0; ictr < icount; ictr += 16) {
91166660095SIan Lepore 		fprintf(stderr, " %6x | ", ictr & 0xfffff0);
91266660095SIan Lepore 
91366660095SIan Lepore 		for (ictr2 = 0; ictr2 < 16; ictr2++) {
914*917d1846SIan Lepore 			idx = ictr + ictr2;
91566660095SIan Lepore 
916*917d1846SIan Lepore 			if (idx < icount) {
917*917d1846SIan Lepore 				ch = ((uint8_t *) pbuf)[idx];
91866660095SIan Lepore 
91966660095SIan Lepore 				if (lsb)
92066660095SIan Lepore 					ch = reversebits[ch];
92166660095SIan Lepore 
92266660095SIan Lepore 				fprintf(stderr, "%02hhx ", ch);
92366660095SIan Lepore 			}
92466660095SIan Lepore 			else {
92566660095SIan Lepore 				fputs("   ", stderr);
92666660095SIan Lepore 			}
92766660095SIan Lepore 		}
92866660095SIan Lepore 
92966660095SIan Lepore 		fputs("| ", stderr);
93066660095SIan Lepore 
93166660095SIan Lepore 		for (ictr2 = 0; ictr2 < 16; ictr2++) {
932*917d1846SIan Lepore 			idx = ictr + ictr2;
93366660095SIan Lepore 
934*917d1846SIan Lepore 			if (idx < icount) {
935*917d1846SIan Lepore 				ch = ((uint8_t *) pbuf)[idx];
93666660095SIan Lepore 
93766660095SIan Lepore 				if (lsb)
93866660095SIan Lepore 					ch = reversebits[ch];
93966660095SIan Lepore 
94066660095SIan Lepore 				if (ch < ' ' || ch > 127)
94166660095SIan Lepore 					goto out_of_range;
94266660095SIan Lepore 
94366660095SIan Lepore 				fprintf(stderr, "%c", ch);
94466660095SIan Lepore 			}
945*917d1846SIan Lepore 			else if (idx < icount) {
94666660095SIan Lepore 		out_of_range:
94766660095SIan Lepore 				fputc('.', stderr);
94866660095SIan Lepore 			}
94966660095SIan Lepore 			else {
95066660095SIan Lepore 				fputc(' ', stderr);
95166660095SIan Lepore 			}
95266660095SIan Lepore 		}
95366660095SIan Lepore 
95466660095SIan Lepore 		fputs(" |\n", stderr);
95566660095SIan Lepore 	}
95666660095SIan Lepore 
95766660095SIan Lepore 	fflush(stderr);
95866660095SIan Lepore }
959