xref: /freebsd/usr.sbin/spi/spi.c (revision 66660095309c7515df3a0e97783d208c37051ee6)
1*66660095SIan Lepore /*-
2*66660095SIan Lepore  * SPDX-License-Identifier: BSD-2-Clause
3*66660095SIan Lepore  *
4*66660095SIan Lepore  * Copyright (c) 2018 S.F.T. Inc.
5*66660095SIan Lepore  *
6*66660095SIan Lepore  * Redistribution and use in source and binary forms, with or without
7*66660095SIan Lepore  * modification, are permitted provided that the following conditions
8*66660095SIan Lepore  * are met:
9*66660095SIan Lepore  * 1. Redistributions of source code must retain the above copyright
10*66660095SIan Lepore  *    notice, this list of conditions and the following disclaimer.
11*66660095SIan Lepore  * 2. Redistributions in binary form must reproduce the above copyright
12*66660095SIan Lepore  *    notice, this list of conditions and the following disclaimer in the
13*66660095SIan Lepore  *    documentation and/or other materials provided with the distribution.
14*66660095SIan Lepore  *
15*66660095SIan Lepore  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16*66660095SIan Lepore  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17*66660095SIan Lepore  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18*66660095SIan Lepore  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19*66660095SIan Lepore  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20*66660095SIan Lepore  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21*66660095SIan Lepore  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22*66660095SIan Lepore  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23*66660095SIan Lepore  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24*66660095SIan Lepore  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25*66660095SIan Lepore  * SUCH DAMAGE.
26*66660095SIan Lepore  */
27*66660095SIan Lepore 
28*66660095SIan Lepore #include <sys/cdefs.h>
29*66660095SIan Lepore __FBSDID("$FreeBSD$");
30*66660095SIan Lepore 
31*66660095SIan Lepore #include <sys/types.h>
32*66660095SIan Lepore #include <sys/ioccom.h>
33*66660095SIan Lepore #include <sys/spigenio.h>
34*66660095SIan Lepore #include <sys/sysctl.h>
35*66660095SIan Lepore 
36*66660095SIan Lepore #include <errno.h>
37*66660095SIan Lepore #include <fcntl.h>
38*66660095SIan Lepore #include <inttypes.h>
39*66660095SIan Lepore #include <limits.h>
40*66660095SIan Lepore #include <memory.h>
41*66660095SIan Lepore #include <stdio.h>
42*66660095SIan Lepore #include <stdlib.h>
43*66660095SIan Lepore #include <string.h>
44*66660095SIan Lepore #include <string.h>
45*66660095SIan Lepore #include <unistd.h>
46*66660095SIan Lepore 
47*66660095SIan Lepore #define	DEFAULT_DEVICE_NAME	"/dev/spigen0.0"
48*66660095SIan Lepore 
49*66660095SIan Lepore #define	DEFAULT_BUFFER_SIZE	8192
50*66660095SIan Lepore 
51*66660095SIan Lepore #define	DIR_READ		0
52*66660095SIan Lepore #define	DIR_WRITE		1
53*66660095SIan Lepore #define	DIR_READWRITE		2
54*66660095SIan Lepore #define	DIR_NONE		-1
55*66660095SIan Lepore 
56*66660095SIan Lepore struct spi_options {
57*66660095SIan Lepore 	int	mode;		/* mode (0,1,2,3, -1 == use default) */
58*66660095SIan Lepore 	int	speed;		/* speed (in Hz, -1 == use default) */
59*66660095SIan Lepore 	int	count;		/* count (0 through 'n' bytes, negative for
60*66660095SIan Lepore 				 * stdin length) */
61*66660095SIan Lepore 	int	binary;		/* non-zero for binary output or zero for
62*66660095SIan Lepore 				 * ASCII output when ASCII != 0 */
63*66660095SIan Lepore 	int	ASCII;		/* zero for binary input and output.
64*66660095SIan Lepore 				 * non-zero for ASCII input, 'binary'
65*66660095SIan Lepore 				 * determines output */
66*66660095SIan Lepore 	int	lsb;		/* non-zero for LSB order (default order is
67*66660095SIan Lepore 				 * MSB) */
68*66660095SIan Lepore 	int	verbose;	/* non-zero for verbosity */
69*66660095SIan Lepore 	int	ncmd;		/* bytes to skip for incoming data */
70*66660095SIan Lepore 	uint8_t	*pcmd;		/* command data (NULL if none) */
71*66660095SIan Lepore };
72*66660095SIan Lepore 
73*66660095SIan Lepore static void	usage(void);
74*66660095SIan Lepore static int	interpret_command_bytes(const char *parg, struct spi_options *popt);
75*66660095SIan Lepore static void *	prep_write_buffer(struct spi_options *popt);
76*66660095SIan Lepore static int	_read_write(int hdev, void *bufw, void *bufr, int cbrw, int lsb);
77*66660095SIan Lepore static int	_do_data_output(void *pr, struct spi_options *popt);
78*66660095SIan Lepore static int	get_info(int hdev, const char *dev_name);
79*66660095SIan Lepore static int	set_mode(int hdev, struct spi_options *popt);
80*66660095SIan Lepore static int	set_speed(int hdev, struct spi_options *popt);
81*66660095SIan Lepore static int	hexval(char c);
82*66660095SIan Lepore static int	perform_read(int hdev, struct spi_options *popt);
83*66660095SIan Lepore static int	perform_write(int hdev, struct spi_options *popt);
84*66660095SIan Lepore static int	perform_readwrite(int hdev, struct spi_options *popt);
85*66660095SIan Lepore static void	verbose_dump_buffer(void *pbuf, int icount, int lsb);
86*66660095SIan Lepore 
87*66660095SIan Lepore /*
88*66660095SIan Lepore  * LSB array - reversebits[n] is the LSB value of n as an MSB.  Use this array
89*66660095SIan Lepore  * to obtain a reversed bit pattern of the index value when bits must
90*66660095SIan Lepore  * be sent/received in an LSB order vs the default MSB
91*66660095SIan Lepore  */
92*66660095SIan Lepore static uint8_t reversebits[256] = {
93*66660095SIan Lepore 	0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
94*66660095SIan Lepore 	0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
95*66660095SIan Lepore 	0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
96*66660095SIan Lepore 	0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
97*66660095SIan Lepore 	0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
98*66660095SIan Lepore 	0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
99*66660095SIan Lepore 	0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
100*66660095SIan Lepore 	0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
101*66660095SIan Lepore 	0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
102*66660095SIan Lepore 	0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
103*66660095SIan Lepore 	0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
104*66660095SIan Lepore 	0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
105*66660095SIan Lepore 	0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
106*66660095SIan Lepore 	0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
107*66660095SIan Lepore 	0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
108*66660095SIan Lepore 	0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
109*66660095SIan Lepore 	0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
110*66660095SIan Lepore 	0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
111*66660095SIan Lepore 	0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
112*66660095SIan Lepore 	0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
113*66660095SIan Lepore 	0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
114*66660095SIan Lepore 	0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
115*66660095SIan Lepore 	0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
116*66660095SIan Lepore 	0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
117*66660095SIan Lepore 	0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
118*66660095SIan Lepore 	0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
119*66660095SIan Lepore 	0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
120*66660095SIan Lepore 	0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
121*66660095SIan Lepore 	0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
122*66660095SIan Lepore 	0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
123*66660095SIan Lepore 	0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
124*66660095SIan Lepore 	0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
125*66660095SIan Lepore };
126*66660095SIan Lepore 
127*66660095SIan Lepore 
128*66660095SIan Lepore static void
129*66660095SIan Lepore usage(void)
130*66660095SIan Lepore {
131*66660095SIan Lepore 	fputs(getprogname(), stderr);
132*66660095SIan Lepore 	fputs(" - communicate on SPI bus with slave devices\n"
133*66660095SIan Lepore 	      "Usage:\n"
134*66660095SIan Lepore 	      "        spi [-f device] [-d r|w|rw] [-m mode] [-s max-speed] [-c count]\n"
135*66660095SIan Lepore 	      "            [-C \"command bytes\"] [-A] [-b] [-L] [-v]\n"
136*66660095SIan Lepore 	      "        spi -i [-f device] [-v]\n"
137*66660095SIan Lepore 	      "        spi -h\n"
138*66660095SIan Lepore 	      " where\n"
139*66660095SIan Lepore 	      "        -f specifies the device (default is spigen0.0)\n"
140*66660095SIan Lepore 	      "        -d specifies the operation (r, w, or rw; default is rw)\n"
141*66660095SIan Lepore 	      "        -m specifies the mode (0, 1, 2, or 3)\n"
142*66660095SIan Lepore 	      "        -s specifies the maximum speed (default is 0, device default)\n"
143*66660095SIan Lepore 	      "        -c specifies the number of data bytes to transfer (default 0, i.e. none)\n"
144*66660095SIan Lepore 	      "           A negative value uses the length of the input data\n"
145*66660095SIan Lepore 	      "        -C specifies 'command bytes' to be sent, as 2 byte hexadecimal values\n"
146*66660095SIan Lepore 	      "           (these should be quoted, separated by optional white space)\n"
147*66660095SIan Lepore 	      "        -L specifies 'LSB' order on the SPI bus (default is MSB)\n"
148*66660095SIan Lepore 	      "        -i query information about the device\n"
149*66660095SIan Lepore 	      "        -A uses ASCII for input/output as 2-digit hex values\n"
150*66660095SIan Lepore 	      "        -b Override output format as binary (only valid with '-A')\n"
151*66660095SIan Lepore 	      "        -v verbose output\n"
152*66660095SIan Lepore 	      "        -h prints this message\n"
153*66660095SIan Lepore 	      "\n"
154*66660095SIan Lepore 	      "NOTE:  setting the mode and/or speed is 'sticky'.  Subsequent transactions\n"
155*66660095SIan Lepore 	      "       on that device will, by default, use the previously set values.\n"
156*66660095SIan Lepore 	      "\n",
157*66660095SIan Lepore 	      stderr);
158*66660095SIan Lepore }
159*66660095SIan Lepore 
160*66660095SIan Lepore int
161*66660095SIan Lepore main(int argc, char *argv[], char *envp[] __unused)
162*66660095SIan Lepore {
163*66660095SIan Lepore 	struct spi_options opt;
164*66660095SIan Lepore 	int err, ch, hdev, finfo, fdir;
165*66660095SIan Lepore 	char *pstr;
166*66660095SIan Lepore 	char dev_name[PATH_MAX * 2 + 5];
167*66660095SIan Lepore 
168*66660095SIan Lepore 	finfo = 0;
169*66660095SIan Lepore 	fdir = DIR_NONE;
170*66660095SIan Lepore 
171*66660095SIan Lepore 	hdev = -1;
172*66660095SIan Lepore 	err = 0;
173*66660095SIan Lepore 
174*66660095SIan Lepore 	dev_name[0] = 0;
175*66660095SIan Lepore 
176*66660095SIan Lepore 	opt.mode = -1;
177*66660095SIan Lepore 	opt.speed = -1;
178*66660095SIan Lepore 	opt.count = 0;
179*66660095SIan Lepore 	opt.ASCII = 0;
180*66660095SIan Lepore 	opt.binary = 0;
181*66660095SIan Lepore 	opt.lsb = 0;
182*66660095SIan Lepore 	opt.verbose = 0;
183*66660095SIan Lepore 	opt.ncmd = 0;
184*66660095SIan Lepore 	opt.pcmd = NULL;
185*66660095SIan Lepore 
186*66660095SIan Lepore 	while (!err && (ch = getopt(argc, argv, "f:d:m:s:c:C:AbLvih")) != -1) {
187*66660095SIan Lepore 		switch (ch) {
188*66660095SIan Lepore 		case 'd':
189*66660095SIan Lepore 			if (optarg[0] == 'r') {
190*66660095SIan Lepore 				if (optarg[1] == 'w' && optarg[2] == 0) {
191*66660095SIan Lepore 					fdir = DIR_READWRITE;
192*66660095SIan Lepore 				}
193*66660095SIan Lepore 				else if (optarg[1] == 0) {
194*66660095SIan Lepore 					fdir = DIR_READ;
195*66660095SIan Lepore 				}
196*66660095SIan Lepore 			}
197*66660095SIan Lepore 			else if (optarg[0] == 'w' && optarg[1] == 0) {
198*66660095SIan Lepore 				fdir = DIR_WRITE;
199*66660095SIan Lepore 			}
200*66660095SIan Lepore 			else {
201*66660095SIan Lepore 				err = 1;
202*66660095SIan Lepore 			}
203*66660095SIan Lepore 			break;
204*66660095SIan Lepore 
205*66660095SIan Lepore 		case 'f':
206*66660095SIan Lepore 			if (!optarg[0]) {	/* unlikely */
207*66660095SIan Lepore 				fputs("error - missing device name\n", stderr);
208*66660095SIan Lepore 				err = 1;
209*66660095SIan Lepore 			}
210*66660095SIan Lepore 			else {
211*66660095SIan Lepore 				if (optarg[0] == '/')
212*66660095SIan Lepore 					strlcpy(dev_name, optarg,
213*66660095SIan Lepore 					    sizeof(dev_name));
214*66660095SIan Lepore 				else
215*66660095SIan Lepore 					snprintf(dev_name, sizeof(dev_name),
216*66660095SIan Lepore 					    "/dev/%s", optarg);
217*66660095SIan Lepore 			}
218*66660095SIan Lepore 			break;
219*66660095SIan Lepore 
220*66660095SIan Lepore 		case 'm':
221*66660095SIan Lepore 			opt.mode = (int)strtol(optarg, &pstr, 10);
222*66660095SIan Lepore 
223*66660095SIan Lepore 			if (!pstr || *pstr || opt.mode < 0 || opt.mode > 3) {
224*66660095SIan Lepore 				fprintf(stderr, "Invalid mode specified: %s\n",
225*66660095SIan Lepore 				    optarg);
226*66660095SIan Lepore 				err = 1;
227*66660095SIan Lepore 			}
228*66660095SIan Lepore 			break;
229*66660095SIan Lepore 
230*66660095SIan Lepore 		case 's':
231*66660095SIan Lepore 			opt.speed = (int)strtol(optarg, &pstr, 10);
232*66660095SIan Lepore 
233*66660095SIan Lepore 			if (!pstr || *pstr || opt.speed < 0) {
234*66660095SIan Lepore 				fprintf(stderr, "Invalid speed specified: %s\n",
235*66660095SIan Lepore 				    optarg);
236*66660095SIan Lepore 				err = 1;
237*66660095SIan Lepore 			}
238*66660095SIan Lepore 			break;
239*66660095SIan Lepore 
240*66660095SIan Lepore 		case 'c':
241*66660095SIan Lepore 			opt.count = (int)strtol(optarg, &pstr, 10);
242*66660095SIan Lepore 
243*66660095SIan Lepore 			if (!pstr || *pstr) {
244*66660095SIan Lepore 				fprintf(stderr, "Invalid count specified: %s\n",
245*66660095SIan Lepore 				    optarg);
246*66660095SIan Lepore 				err = 1;
247*66660095SIan Lepore 			}
248*66660095SIan Lepore 			break;
249*66660095SIan Lepore 
250*66660095SIan Lepore 		case 'C':
251*66660095SIan Lepore 			if(opt.pcmd) /* specified more than once */
252*66660095SIan Lepore 				err = 1;
253*66660095SIan Lepore 			else {
254*66660095SIan Lepore 				/* get malloc'd buffer or error */
255*66660095SIan Lepore 				if (interpret_command_bytes(optarg, &opt))
256*66660095SIan Lepore 					err = 1;
257*66660095SIan Lepore 			}
258*66660095SIan Lepore 
259*66660095SIan Lepore 			break;
260*66660095SIan Lepore 
261*66660095SIan Lepore 		case 'A':
262*66660095SIan Lepore 			opt.ASCII = 1;
263*66660095SIan Lepore 			break;
264*66660095SIan Lepore 
265*66660095SIan Lepore 		case 'b':
266*66660095SIan Lepore 			opt.binary = 1;
267*66660095SIan Lepore 			break;
268*66660095SIan Lepore 
269*66660095SIan Lepore 		case 'L':
270*66660095SIan Lepore 			opt.lsb = 1;
271*66660095SIan Lepore 			break;
272*66660095SIan Lepore 
273*66660095SIan Lepore 		case 'v':
274*66660095SIan Lepore 			opt.verbose++;
275*66660095SIan Lepore 			break;
276*66660095SIan Lepore 
277*66660095SIan Lepore 		case 'i':
278*66660095SIan Lepore 			finfo = 1;
279*66660095SIan Lepore 			break;
280*66660095SIan Lepore 
281*66660095SIan Lepore 		default:
282*66660095SIan Lepore 			err = 1;
283*66660095SIan Lepore 			/* FALLTHROUGH */
284*66660095SIan Lepore 		case 'h':
285*66660095SIan Lepore 			usage();
286*66660095SIan Lepore 			goto the_end;
287*66660095SIan Lepore 		}
288*66660095SIan Lepore 	}
289*66660095SIan Lepore 
290*66660095SIan Lepore 	argc -= optind;
291*66660095SIan Lepore 	argv += optind;
292*66660095SIan Lepore 
293*66660095SIan Lepore 	if (err ||
294*66660095SIan Lepore 	    (fdir == DIR_NONE && !finfo && opt.mode == -1 && opt.speed == -1 && opt.count == 0)) {
295*66660095SIan Lepore 		/*
296*66660095SIan Lepore 		 * if any of the direction, mode, speed, or count not specified,
297*66660095SIan Lepore 		 * print usage
298*66660095SIan Lepore 		 */
299*66660095SIan Lepore 
300*66660095SIan Lepore 		usage();
301*66660095SIan Lepore 		goto the_end;
302*66660095SIan Lepore 	}
303*66660095SIan Lepore 
304*66660095SIan Lepore 	if ((opt.count != 0 || opt.ncmd != 0) && fdir == DIR_NONE) {
305*66660095SIan Lepore 		/*
306*66660095SIan Lepore 		 * count was specified, but direction was not.  default is
307*66660095SIan Lepore 		 * read/write
308*66660095SIan Lepore 		 */
309*66660095SIan Lepore 		/*
310*66660095SIan Lepore 		 * this includes a negative count, which implies write from
311*66660095SIan Lepore 		 * stdin
312*66660095SIan Lepore 		 */
313*66660095SIan Lepore 		if (opt.count == 0)
314*66660095SIan Lepore 			fdir = DIR_WRITE;
315*66660095SIan Lepore 		else
316*66660095SIan Lepore 			fdir = DIR_READWRITE;
317*66660095SIan Lepore 	}
318*66660095SIan Lepore 
319*66660095SIan Lepore 	if (opt.count < 0 && fdir != DIR_READWRITE && fdir != DIR_WRITE) {
320*66660095SIan Lepore 		fprintf(stderr, "Invalid length %d when not writing data\n",
321*66660095SIan Lepore 		    opt.count);
322*66660095SIan Lepore 
323*66660095SIan Lepore 		err = 1;
324*66660095SIan Lepore 		usage();
325*66660095SIan Lepore 		goto the_end;
326*66660095SIan Lepore 	}
327*66660095SIan Lepore 
328*66660095SIan Lepore 
329*66660095SIan Lepore 	if (!dev_name[0])	/* no device name specified */
330*66660095SIan Lepore 		strlcpy(dev_name, DEFAULT_DEVICE_NAME, sizeof(dev_name));
331*66660095SIan Lepore 
332*66660095SIan Lepore 	hdev = open(dev_name, O_RDWR);
333*66660095SIan Lepore 
334*66660095SIan Lepore 	if (hdev == -1) {
335*66660095SIan Lepore 		fprintf(stderr, "Error - unable to open '%s', errno=%d\n",
336*66660095SIan Lepore 		    dev_name, errno);
337*66660095SIan Lepore 		err = 1;
338*66660095SIan Lepore 		goto the_end;
339*66660095SIan Lepore 	}
340*66660095SIan Lepore 
341*66660095SIan Lepore 	if (finfo) {
342*66660095SIan Lepore 		err = get_info(hdev, dev_name);
343*66660095SIan Lepore 		goto the_end;
344*66660095SIan Lepore 	}
345*66660095SIan Lepore 
346*66660095SIan Lepore 	/* check and assign mode, speed */
347*66660095SIan Lepore 
348*66660095SIan Lepore 	if (opt.mode != -1) {
349*66660095SIan Lepore 		err = set_mode(hdev, &opt);
350*66660095SIan Lepore 
351*66660095SIan Lepore 		if (err)
352*66660095SIan Lepore 			goto the_end;
353*66660095SIan Lepore 	}
354*66660095SIan Lepore 
355*66660095SIan Lepore 	if (opt.speed != -1) {
356*66660095SIan Lepore 		err = set_speed(hdev, &opt);
357*66660095SIan Lepore 
358*66660095SIan Lepore 		if (err)
359*66660095SIan Lepore 			goto the_end;
360*66660095SIan Lepore 	}
361*66660095SIan Lepore 
362*66660095SIan Lepore 	/* do data transfer */
363*66660095SIan Lepore 
364*66660095SIan Lepore 	if (fdir == DIR_READ) {
365*66660095SIan Lepore 		err = perform_read(hdev, &opt);
366*66660095SIan Lepore 	}
367*66660095SIan Lepore 	else if (fdir == DIR_WRITE) {
368*66660095SIan Lepore 		err = perform_write(hdev, &opt);
369*66660095SIan Lepore 	}
370*66660095SIan Lepore 	else if (fdir == DIR_READWRITE) {
371*66660095SIan Lepore 		err = perform_readwrite(hdev, &opt);
372*66660095SIan Lepore 	}
373*66660095SIan Lepore 
374*66660095SIan Lepore the_end:
375*66660095SIan Lepore 
376*66660095SIan Lepore 	if (hdev != -1)
377*66660095SIan Lepore 		close(hdev);
378*66660095SIan Lepore 
379*66660095SIan Lepore 	free(opt.pcmd);
380*66660095SIan Lepore 
381*66660095SIan Lepore 	return (err);
382*66660095SIan Lepore }
383*66660095SIan Lepore 
384*66660095SIan Lepore static int
385*66660095SIan Lepore interpret_command_bytes(const char *parg, struct spi_options *popt)
386*66660095SIan Lepore {
387*66660095SIan Lepore 	int ch, ch2, ctr, cbcmd, err;
388*66660095SIan Lepore 	const char *ppos;
389*66660095SIan Lepore 	void *ptemp;
390*66660095SIan Lepore 	uint8_t *pcur;
391*66660095SIan Lepore 
392*66660095SIan Lepore 	err = 0;
393*66660095SIan Lepore 	cbcmd = DEFAULT_BUFFER_SIZE; /* initial cmd buffer size */
394*66660095SIan Lepore 	popt->pcmd = (uint8_t *)malloc(cbcmd);
395*66660095SIan Lepore 
396*66660095SIan Lepore 	if (!popt->pcmd)
397*66660095SIan Lepore 		return 1;
398*66660095SIan Lepore 
399*66660095SIan Lepore 	pcur = popt->pcmd;
400*66660095SIan Lepore 
401*66660095SIan Lepore 	ctr = 0;
402*66660095SIan Lepore 	ppos = parg;
403*66660095SIan Lepore 
404*66660095SIan Lepore 	while (*ppos) {
405*66660095SIan Lepore 		while (*ppos && *ppos <= ' ') {
406*66660095SIan Lepore 			ppos++; /* skip (optional) leading white space */
407*66660095SIan Lepore 		}
408*66660095SIan Lepore 
409*66660095SIan Lepore 		if (!*ppos)
410*66660095SIan Lepore 			break; /* I am done */
411*66660095SIan Lepore 
412*66660095SIan Lepore 		ch = hexval(*(ppos++));
413*66660095SIan Lepore 		if (ch < 0 || !*ppos) { /* must be valid pair of hex characters */
414*66660095SIan Lepore 			err = 1;
415*66660095SIan Lepore 			goto the_end;
416*66660095SIan Lepore 		}
417*66660095SIan Lepore 
418*66660095SIan Lepore 		ch2 = hexval(*(ppos++));
419*66660095SIan Lepore 		if (ch2 < 0) {
420*66660095SIan Lepore 			err = 1;
421*66660095SIan Lepore 			goto the_end;
422*66660095SIan Lepore 		}
423*66660095SIan Lepore 
424*66660095SIan Lepore 		ch = (ch * 16 + ch2) & 0xff; /* convert to byte */
425*66660095SIan Lepore 
426*66660095SIan Lepore 		if (ctr >= cbcmd) { /* need re-alloc buffer? (unlikely) */
427*66660095SIan Lepore 			cbcmd += 8192; /* increase by additional 8k */
428*66660095SIan Lepore 			ptemp = realloc(popt->pcmd, cbcmd);
429*66660095SIan Lepore 
430*66660095SIan Lepore 			if (!ptemp) {
431*66660095SIan Lepore 				err = 1;
432*66660095SIan Lepore 				fprintf(stderr,
433*66660095SIan Lepore 					"Not enough memory to interpret command bytes, errno=%d\n",
434*66660095SIan Lepore 					errno);
435*66660095SIan Lepore 				goto the_end;
436*66660095SIan Lepore 			}
437*66660095SIan Lepore 
438*66660095SIan Lepore 			popt->pcmd = (uint8_t *)ptemp;
439*66660095SIan Lepore 			pcur = popt->pcmd + ctr;
440*66660095SIan Lepore 		}
441*66660095SIan Lepore 
442*66660095SIan Lepore 		if (popt->lsb)
443*66660095SIan Lepore 			*pcur = reversebits[ch];
444*66660095SIan Lepore 		else
445*66660095SIan Lepore 			*pcur = (uint8_t)ch;
446*66660095SIan Lepore 
447*66660095SIan Lepore 		pcur++;
448*66660095SIan Lepore 		ctr++;
449*66660095SIan Lepore 	}
450*66660095SIan Lepore 
451*66660095SIan Lepore 	popt->ncmd = ctr; /* record num bytes in '-C' argument */
452*66660095SIan Lepore 
453*66660095SIan Lepore the_end:
454*66660095SIan Lepore 
455*66660095SIan Lepore 	/* at this point popt->pcmd is NULL or a valid pointer */
456*66660095SIan Lepore 
457*66660095SIan Lepore 	return err;
458*66660095SIan Lepore }
459*66660095SIan Lepore 
460*66660095SIan Lepore static int
461*66660095SIan Lepore get_info(int hdev, const char *dev_name)
462*66660095SIan Lepore {
463*66660095SIan Lepore 	uint32_t fmode, fspeed;
464*66660095SIan Lepore 	int err;
465*66660095SIan Lepore 	char temp_buf[PATH_MAX], cpath[PATH_MAX];
466*66660095SIan Lepore 
467*66660095SIan Lepore 	if (!realpath(dev_name, cpath)) /* get canonical name for info purposes */
468*66660095SIan Lepore 		strlcpy(cpath, temp_buf, sizeof(cpath));  /* this shouldn't happen */
469*66660095SIan Lepore 
470*66660095SIan Lepore 	err = ioctl(hdev, SPIGENIOC_GET_SPI_MODE, &fmode);
471*66660095SIan Lepore 
472*66660095SIan Lepore 	if (err == 0)
473*66660095SIan Lepore 		err = ioctl(hdev, SPIGENIOC_GET_CLOCK_SPEED, &fspeed);
474*66660095SIan Lepore 
475*66660095SIan Lepore 	if (err == 0) {
476*66660095SIan Lepore 		fprintf(stderr,
477*66660095SIan Lepore 		        "Device name:   %s\n"
478*66660095SIan Lepore 		        "Device mode:   %d\n"
479*66660095SIan Lepore 		        "Device speed:  %d\n",
480*66660095SIan Lepore 		        cpath, fmode, fspeed);//, max_cmd, max_data, temp_buf);
481*66660095SIan Lepore 	}
482*66660095SIan Lepore 	else
483*66660095SIan Lepore 		fprintf(stderr, "Unable to query info (err=%d), errno=%d\n",
484*66660095SIan Lepore 		    err, errno);
485*66660095SIan Lepore 
486*66660095SIan Lepore 	return err;
487*66660095SIan Lepore }
488*66660095SIan Lepore 
489*66660095SIan Lepore static int
490*66660095SIan Lepore set_mode(int hdev, struct spi_options *popt)
491*66660095SIan Lepore {
492*66660095SIan Lepore 	uint32_t fmode = popt->mode;
493*66660095SIan Lepore 
494*66660095SIan Lepore 	if (popt->mode < 0)	/* use default? */
495*66660095SIan Lepore 		return 0;
496*66660095SIan Lepore 
497*66660095SIan Lepore 	return ioctl(hdev, SPIGENIOC_SET_SPI_MODE, &fmode);
498*66660095SIan Lepore }
499*66660095SIan Lepore 
500*66660095SIan Lepore static int
501*66660095SIan Lepore set_speed(int hdev, struct spi_options *popt)
502*66660095SIan Lepore {
503*66660095SIan Lepore 	uint32_t clock_speed = popt->speed;
504*66660095SIan Lepore 
505*66660095SIan Lepore 	if (popt->speed < 0)
506*66660095SIan Lepore 		return 0;
507*66660095SIan Lepore 
508*66660095SIan Lepore 	return ioctl(hdev, SPIGENIOC_SET_CLOCK_SPEED, &clock_speed);
509*66660095SIan Lepore }
510*66660095SIan Lepore 
511*66660095SIan Lepore static int
512*66660095SIan Lepore hexval(char c)
513*66660095SIan Lepore {
514*66660095SIan Lepore 	if (c >= '0' && c <= '9') {
515*66660095SIan Lepore 		return c - '0';
516*66660095SIan Lepore 	} else if (c >= 'A' && c <= 'F') {
517*66660095SIan Lepore 		return c - 'A' + 10;
518*66660095SIan Lepore 	} else if (c >= 'a' && c <= 'f') {
519*66660095SIan Lepore 		return c - 'a' + 10;
520*66660095SIan Lepore 	}
521*66660095SIan Lepore 	return -1;
522*66660095SIan Lepore }
523*66660095SIan Lepore 
524*66660095SIan Lepore static void *
525*66660095SIan Lepore prep_write_buffer(struct spi_options *popt)
526*66660095SIan Lepore {
527*66660095SIan Lepore 	int ch, ch2, ch3, ncmd, lsb, err;
528*66660095SIan Lepore 	uint8_t *pdata, *pdat2;
529*66660095SIan Lepore 	size_t cbdata, cbread;
530*66660095SIan Lepore 	const char *szbytes;
531*66660095SIan Lepore 
532*66660095SIan Lepore 	ncmd = popt->ncmd; /* num command bytes (can be zero) */
533*66660095SIan Lepore 
534*66660095SIan Lepore 	if (ncmd == 0 && popt->count == 0)
535*66660095SIan Lepore 		return NULL;	/* always since it's an error if it happens
536*66660095SIan Lepore 				 * now */
537*66660095SIan Lepore 
538*66660095SIan Lepore 	if (popt->count < 0) {
539*66660095SIan Lepore 		cbdata = DEFAULT_BUFFER_SIZE;
540*66660095SIan Lepore 	}
541*66660095SIan Lepore 	else {
542*66660095SIan Lepore 		cbdata = popt->count;
543*66660095SIan Lepore 	}
544*66660095SIan Lepore 
545*66660095SIan Lepore 	lsb = popt->lsb; /* non-zero if LSB order; else MSB */
546*66660095SIan Lepore 
547*66660095SIan Lepore 	pdata = malloc(cbdata + ncmd + 1);
548*66660095SIan Lepore 	cbread = 0;
549*66660095SIan Lepore 
550*66660095SIan Lepore 	err = 0;
551*66660095SIan Lepore 
552*66660095SIan Lepore 	if (!pdata)
553*66660095SIan Lepore 		return NULL;
554*66660095SIan Lepore 
555*66660095SIan Lepore 	if (popt->pcmd && ncmd > 0) {
556*66660095SIan Lepore 		memcpy(pdata, popt->pcmd, ncmd); /* copy command bytes */
557*66660095SIan Lepore 		pdat2 = pdata + ncmd;
558*66660095SIan Lepore 	}
559*66660095SIan Lepore 	else
560*66660095SIan Lepore 		pdat2 = pdata; /* no prepended command data */
561*66660095SIan Lepore 
562*66660095SIan Lepore 	/*
563*66660095SIan Lepore 	 * read up to 'cbdata' bytes.  If I get an EOF, do one of two things:
564*66660095SIan Lepore 	 * a) change the data count to match how many bytes I read in b) fill
565*66660095SIan Lepore 	 * the rest of the input buffer with zeros
566*66660095SIan Lepore 	 *
567*66660095SIan Lepore 	 * If the specified length is negative, I do 'a', else 'b'
568*66660095SIan Lepore 	 */
569*66660095SIan Lepore 
570*66660095SIan Lepore 	while (!err && cbread < cbdata && (ch = fgetc(stdin)) != EOF) {
571*66660095SIan Lepore 		if (popt->ASCII) {
572*66660095SIan Lepore 			/* skip consecutive white space */
573*66660095SIan Lepore 
574*66660095SIan Lepore 			while (ch <= ' ') {
575*66660095SIan Lepore 				if ((ch = fgetc(stdin)) == EOF)
576*66660095SIan Lepore 					break;
577*66660095SIan Lepore 			}
578*66660095SIan Lepore 
579*66660095SIan Lepore 			if (ch != EOF) {
580*66660095SIan Lepore 				ch2 = hexval(ch);
581*66660095SIan Lepore 
582*66660095SIan Lepore 				if (ch2 < 0) {
583*66660095SIan Lepore invalid_character:
584*66660095SIan Lepore 					fprintf(stderr,
585*66660095SIan Lepore 					    "Invalid input character '%c'\n", ch);
586*66660095SIan Lepore 					err = 1;
587*66660095SIan Lepore 					break;
588*66660095SIan Lepore 				}
589*66660095SIan Lepore 
590*66660095SIan Lepore 				ch = fgetc(stdin);
591*66660095SIan Lepore 
592*66660095SIan Lepore 				if (ch != EOF) {
593*66660095SIan Lepore 					ch3 = hexval(ch);
594*66660095SIan Lepore 
595*66660095SIan Lepore 					if (ch3 < 0)
596*66660095SIan Lepore 						goto invalid_character;
597*66660095SIan Lepore 
598*66660095SIan Lepore 					ch = ch2 * 16 + ch3;
599*66660095SIan Lepore 				}
600*66660095SIan Lepore 			}
601*66660095SIan Lepore 
602*66660095SIan Lepore 			if (err || ch == EOF)
603*66660095SIan Lepore 				break;
604*66660095SIan Lepore 		}
605*66660095SIan Lepore 
606*66660095SIan Lepore 		/* for LSB, flip the bits - otherwise, just copy the value */
607*66660095SIan Lepore 		if (lsb)
608*66660095SIan Lepore 			pdat2[cbread] = reversebits[ch];
609*66660095SIan Lepore 		else
610*66660095SIan Lepore 			pdat2[cbread] = (uint8_t) ch;
611*66660095SIan Lepore 
612*66660095SIan Lepore 		cbread++; /* increment num bytes read so far */
613*66660095SIan Lepore 	}
614*66660095SIan Lepore 
615*66660095SIan Lepore 	/* if it was an error, not an EOF, that ended the I/O, return NULL */
616*66660095SIan Lepore 
617*66660095SIan Lepore 	if (err || ferror(stdin)) {
618*66660095SIan Lepore 		free(pdata);
619*66660095SIan Lepore 		return NULL;
620*66660095SIan Lepore 	}
621*66660095SIan Lepore 
622*66660095SIan Lepore 	if (popt->verbose > 0) {
623*66660095SIan Lepore 		const char *sz_bytes;
624*66660095SIan Lepore 
625*66660095SIan Lepore 		if (cbread != 1)
626*66660095SIan Lepore 			sz_bytes = "bytes";	/* correct plurality of 'byte|bytes' */
627*66660095SIan Lepore 		else
628*66660095SIan Lepore 			sz_bytes = "byte";
629*66660095SIan Lepore 
630*66660095SIan Lepore 		if (popt->ASCII)
631*66660095SIan Lepore 			fprintf(stderr, "ASCII input of %zd %s\n", cbread,
632*66660095SIan Lepore 			    sz_bytes);
633*66660095SIan Lepore 		else
634*66660095SIan Lepore 			fprintf(stderr, "Binary input of %zd %s\n", cbread,
635*66660095SIan Lepore 			    sz_bytes);
636*66660095SIan Lepore 	}
637*66660095SIan Lepore 
638*66660095SIan Lepore 	/*
639*66660095SIan Lepore 	 * if opt.count is negative, copy actual byte count to opt.count which does
640*66660095SIan Lepore 	 * not include any of the 'command' bytes that are being sent.  Can be zero.
641*66660095SIan Lepore 	 */
642*66660095SIan Lepore 	if (popt->count < 0) {
643*66660095SIan Lepore 		popt->count = cbread;
644*66660095SIan Lepore 	}
645*66660095SIan Lepore 	/*
646*66660095SIan Lepore 	 * for everything else, fill the rest of the read buffer with '0'
647*66660095SIan Lepore 	 * bytes, as per the standard practice for SPI
648*66660095SIan Lepore 	 */
649*66660095SIan Lepore 	else {
650*66660095SIan Lepore 		while (cbread < cbdata)
651*66660095SIan Lepore 			pdat2[cbread++] = 0;
652*66660095SIan Lepore 	}
653*66660095SIan Lepore 
654*66660095SIan Lepore 	/*
655*66660095SIan Lepore 	 * popt->count bytes will be sent and read from the SPI, preceded by the
656*66660095SIan Lepore 	 * 'popt->ncmd' command bytes (if any).
657*66660095SIan Lepore 	 * So we must use 'popt->count' and 'popt->ncmd' from this point on in
658*66660095SIan Lepore 	 * the code.
659*66660095SIan Lepore 	 */
660*66660095SIan Lepore 
661*66660095SIan Lepore 	if (popt->verbose > 0 && popt->count + popt->ncmd) {
662*66660095SIan Lepore 		if ((popt->count + popt->ncmd) == 1)
663*66660095SIan Lepore 			szbytes = "byte";
664*66660095SIan Lepore 		else
665*66660095SIan Lepore 			szbytes = "bytes";
666*66660095SIan Lepore 
667*66660095SIan Lepore 		fprintf(stderr, "Writing %d %s to SPI device\n",
668*66660095SIan Lepore 		        popt->count + popt->ncmd, szbytes);
669*66660095SIan Lepore 
670*66660095SIan Lepore 		verbose_dump_buffer(pdata, popt->count + popt->ncmd, lsb);
671*66660095SIan Lepore 	}
672*66660095SIan Lepore 
673*66660095SIan Lepore 	return pdata;
674*66660095SIan Lepore }
675*66660095SIan Lepore 
676*66660095SIan Lepore static int
677*66660095SIan Lepore _read_write(int hdev, void *bufw, void *bufr, int cbrw, int lsb)
678*66660095SIan Lepore {
679*66660095SIan Lepore 	int	err, ctr;
680*66660095SIan Lepore 	struct spigen_transfer spi;
681*66660095SIan Lepore 
682*66660095SIan Lepore 	if (!cbrw)
683*66660095SIan Lepore 		return 0;
684*66660095SIan Lepore 
685*66660095SIan Lepore 	if (!bufr)
686*66660095SIan Lepore 		bufr = bufw;
687*66660095SIan Lepore 	else
688*66660095SIan Lepore 		memcpy(bufr, bufw, cbrw);	/* transaction uses bufr for
689*66660095SIan Lepore 						 * both R and W */
690*66660095SIan Lepore 
691*66660095SIan Lepore 	bzero(&spi, sizeof(spi));	/* zero structure first */
692*66660095SIan Lepore 
693*66660095SIan Lepore 	/* spigen code seems to suggest there must be at least 1 command byte */
694*66660095SIan Lepore 
695*66660095SIan Lepore 	spi.st_command.iov_base = bufr;
696*66660095SIan Lepore 	spi.st_command.iov_len = cbrw;
697*66660095SIan Lepore 
698*66660095SIan Lepore 	/*
699*66660095SIan Lepore 	 * The remaining members for spi.st_data are zero - all bytes are
700*66660095SIan Lepore 	 * 'command' for this. The driver doesn't really do anything different
701*66660095SIan Lepore 	 * for 'command' vs 'data' and at least one command byte must be sent in
702*66660095SIan Lepore 	 * the transaction.
703*66660095SIan Lepore 	 */
704*66660095SIan Lepore 
705*66660095SIan Lepore 	err = ioctl(hdev, SPIGENIOC_TRANSFER, &spi) < 0 ? -1 : 0;
706*66660095SIan Lepore 
707*66660095SIan Lepore 	if (!err && lsb) {
708*66660095SIan Lepore 		/* flip the bits for 'lsb' mode */
709*66660095SIan Lepore 		for (ctr = 0; ctr < cbrw; ctr++) {
710*66660095SIan Lepore 			((uint8_t *) bufr)[ctr] =
711*66660095SIan Lepore 			    reversebits[((uint8_t *)bufr)[ctr]];
712*66660095SIan Lepore 		}
713*66660095SIan Lepore 	}
714*66660095SIan Lepore 
715*66660095SIan Lepore 	if (err)
716*66660095SIan Lepore 		fprintf(stderr, "Error performing SPI transaction, errno=%d\n",
717*66660095SIan Lepore 		    errno);
718*66660095SIan Lepore 
719*66660095SIan Lepore 	return err;
720*66660095SIan Lepore }
721*66660095SIan Lepore 
722*66660095SIan Lepore static int
723*66660095SIan Lepore _do_data_output(void *pr, struct spi_options *popt)
724*66660095SIan Lepore {
725*66660095SIan Lepore 	int	err, index, icount;
726*66660095SIan Lepore 	const char *sz_bytes, *sz_byte2;
727*66660095SIan Lepore 	const uint8_t *pbuf;
728*66660095SIan Lepore 
729*66660095SIan Lepore 	pbuf = (uint8_t *)pr + popt->ncmd; /* only the data we want */
730*66660095SIan Lepore 	icount = popt->count;
731*66660095SIan Lepore 	err = 0;
732*66660095SIan Lepore 
733*66660095SIan Lepore 	if (icount <= 0) {
734*66660095SIan Lepore 		return -1; /* should not but could happen */
735*66660095SIan Lepore 	}
736*66660095SIan Lepore 
737*66660095SIan Lepore 	if (icount != 1)
738*66660095SIan Lepore 		sz_bytes = "bytes";	/* correct plurality of 'byte|bytes' */
739*66660095SIan Lepore 	else
740*66660095SIan Lepore 		sz_bytes = "byte";
741*66660095SIan Lepore 
742*66660095SIan Lepore 	if (popt->ncmd != 1)
743*66660095SIan Lepore 		sz_byte2 = "bytes";
744*66660095SIan Lepore 	else
745*66660095SIan Lepore 		sz_byte2 = "byte";
746*66660095SIan Lepore 
747*66660095SIan Lepore 	/* binary on stdout */
748*66660095SIan Lepore 	if (popt->binary || !popt->ASCII) {
749*66660095SIan Lepore 		if (popt->verbose > 0)
750*66660095SIan Lepore 			fprintf(stderr, "Binary output of %d %s\n", icount,
751*66660095SIan Lepore 			    sz_bytes);
752*66660095SIan Lepore 
753*66660095SIan Lepore 		err = (int)fwrite(pbuf, 1, icount, stdout) != icount;
754*66660095SIan Lepore 	}
755*66660095SIan Lepore 	else if (icount > 0) {
756*66660095SIan Lepore 		if (popt->verbose > 0)
757*66660095SIan Lepore 			fprintf(stderr, "ASCII output of %d %s\n", icount,
758*66660095SIan Lepore 			    sz_bytes);
759*66660095SIan Lepore 
760*66660095SIan Lepore 		/* ASCII output */
761*66660095SIan Lepore 		for (index = 0; !err && index < icount; index++) {
762*66660095SIan Lepore 			if (index) {
763*66660095SIan Lepore 				/*
764*66660095SIan Lepore 				 * not the first time, insert separating space
765*66660095SIan Lepore 				 */
766*66660095SIan Lepore 				err = fputc(' ', stdout) == EOF;
767*66660095SIan Lepore 			}
768*66660095SIan Lepore 
769*66660095SIan Lepore 			if (!err)
770*66660095SIan Lepore 				err = fprintf(stdout, "%02hhx", pbuf[index]) < 0;
771*66660095SIan Lepore 		}
772*66660095SIan Lepore 
773*66660095SIan Lepore 		if (!err)
774*66660095SIan Lepore 			err = fputc('\n', stdout) == EOF;
775*66660095SIan Lepore 	}
776*66660095SIan Lepore 
777*66660095SIan Lepore 	/* verbose text out on stderr */
778*66660095SIan Lepore 
779*66660095SIan Lepore 	if (err)
780*66660095SIan Lepore 		fprintf(stderr, "Error writing to stdout, errno=%d\n", errno);
781*66660095SIan Lepore 	else if (popt->verbose > 0 && icount) {
782*66660095SIan Lepore 		fprintf(stderr,
783*66660095SIan Lepore 		    "%d command %s and %d data %s read from SPI device\n",
784*66660095SIan Lepore 		    popt->ncmd, sz_byte2, icount, sz_bytes);
785*66660095SIan Lepore 
786*66660095SIan Lepore 		/* verbose output will show the command bytes as well */
787*66660095SIan Lepore 		verbose_dump_buffer(pr, icount + popt->ncmd, popt->lsb);
788*66660095SIan Lepore 	}
789*66660095SIan Lepore 
790*66660095SIan Lepore 	return err;
791*66660095SIan Lepore }
792*66660095SIan Lepore 
793*66660095SIan Lepore static int
794*66660095SIan Lepore perform_read(int hdev, struct spi_options *popt)
795*66660095SIan Lepore {
796*66660095SIan Lepore 	int icount, err;
797*66660095SIan Lepore 	void   *pr, *pw;
798*66660095SIan Lepore 
799*66660095SIan Lepore 	pr = NULL;
800*66660095SIan Lepore 	icount = popt->count + popt->ncmd;
801*66660095SIan Lepore 
802*66660095SIan Lepore 	/* prep write buffer filled with 0 bytes */
803*66660095SIan Lepore 	pw = malloc(icount);
804*66660095SIan Lepore 
805*66660095SIan Lepore 	if (!pw) {
806*66660095SIan Lepore 		err = -1;
807*66660095SIan Lepore 		goto the_end;
808*66660095SIan Lepore 	}
809*66660095SIan Lepore 
810*66660095SIan Lepore 	bzero(pw, icount);
811*66660095SIan Lepore 
812*66660095SIan Lepore 	/* if I included a command sequence, copy bytes to the write buf */
813*66660095SIan Lepore 	if (popt->pcmd && popt->ncmd > 0)
814*66660095SIan Lepore 		memcpy(pw, popt->pcmd, popt->ncmd);
815*66660095SIan Lepore 
816*66660095SIan Lepore 	pr = malloc(icount + 1);
817*66660095SIan Lepore 
818*66660095SIan Lepore 	if (!pr) {
819*66660095SIan Lepore 		err = -2;
820*66660095SIan Lepore 		goto the_end;
821*66660095SIan Lepore 	}
822*66660095SIan Lepore 
823*66660095SIan Lepore 	bzero(pr, icount);
824*66660095SIan Lepore 
825*66660095SIan Lepore 	err = _read_write(hdev, pw, pr, icount, popt->lsb);
826*66660095SIan Lepore 
827*66660095SIan Lepore 	if (!err && popt->count > 0)
828*66660095SIan Lepore 		err = _do_data_output(pr, popt);
829*66660095SIan Lepore 
830*66660095SIan Lepore the_end:
831*66660095SIan Lepore 
832*66660095SIan Lepore 	free(pr);
833*66660095SIan Lepore 	free(pw);
834*66660095SIan Lepore 
835*66660095SIan Lepore 	return err;
836*66660095SIan Lepore }
837*66660095SIan Lepore 
838*66660095SIan Lepore static int
839*66660095SIan Lepore perform_write(int hdev, struct spi_options *popt)
840*66660095SIan Lepore {
841*66660095SIan Lepore 	int err;
842*66660095SIan Lepore 	void   *pw;
843*66660095SIan Lepore 
844*66660095SIan Lepore 	/* read data from cmd buf and stdin and write to 'write' buffer */
845*66660095SIan Lepore 
846*66660095SIan Lepore 	pw = prep_write_buffer(popt);
847*66660095SIan Lepore 
848*66660095SIan Lepore 	if (!pw) {
849*66660095SIan Lepore 		err = -1;
850*66660095SIan Lepore 		goto the_end;
851*66660095SIan Lepore 	}
852*66660095SIan Lepore 
853*66660095SIan Lepore 	err = _read_write(hdev, pw, NULL, popt->count + popt->ncmd, popt->lsb);
854*66660095SIan Lepore 
855*66660095SIan Lepore the_end:
856*66660095SIan Lepore 
857*66660095SIan Lepore 	free(pw);
858*66660095SIan Lepore 
859*66660095SIan Lepore 	return err;
860*66660095SIan Lepore }
861*66660095SIan Lepore 
862*66660095SIan Lepore static int
863*66660095SIan Lepore perform_readwrite(int hdev, struct spi_options *popt)
864*66660095SIan Lepore {
865*66660095SIan Lepore 	int icount, err;
866*66660095SIan Lepore 	void   *pr, *pw;
867*66660095SIan Lepore 
868*66660095SIan Lepore 	pr = NULL;
869*66660095SIan Lepore 
870*66660095SIan Lepore 	pw = prep_write_buffer(popt);
871*66660095SIan Lepore 	icount = popt->count + popt->ncmd; /* assign after fn call */
872*66660095SIan Lepore 
873*66660095SIan Lepore 	if (!pw) {
874*66660095SIan Lepore 		err = -1;
875*66660095SIan Lepore 		goto the_end;
876*66660095SIan Lepore 	}
877*66660095SIan Lepore 
878*66660095SIan Lepore 	pr = malloc(icount + 1);
879*66660095SIan Lepore 
880*66660095SIan Lepore 	if (!pr) {
881*66660095SIan Lepore 		err = -2;
882*66660095SIan Lepore 		goto the_end;
883*66660095SIan Lepore 	}
884*66660095SIan Lepore 
885*66660095SIan Lepore 	bzero(pr, icount);
886*66660095SIan Lepore 
887*66660095SIan Lepore 	err = _read_write(hdev, pw, pr, icount, popt->lsb);
888*66660095SIan Lepore 
889*66660095SIan Lepore 	if (!err)
890*66660095SIan Lepore 		err = _do_data_output(pr, popt);
891*66660095SIan Lepore 
892*66660095SIan Lepore the_end:
893*66660095SIan Lepore 
894*66660095SIan Lepore 	free(pr);
895*66660095SIan Lepore 	free(pw);
896*66660095SIan Lepore 
897*66660095SIan Lepore 	return err;
898*66660095SIan Lepore }
899*66660095SIan Lepore 
900*66660095SIan Lepore 
901*66660095SIan Lepore static void
902*66660095SIan Lepore verbose_dump_buffer(void *pbuf, int icount, int lsb)
903*66660095SIan Lepore {
904*66660095SIan Lepore 	uint8_t	ch;
905*66660095SIan Lepore 	int	ictr, ictr2, index;
906*66660095SIan Lepore 
907*66660095SIan Lepore 	fputs("        |  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F "
908*66660095SIan Lepore 	      "|                  |\n", stderr);
909*66660095SIan Lepore 
910*66660095SIan Lepore 	for (ictr = 0; ictr < icount; ictr += 16) {
911*66660095SIan Lepore 		fprintf(stderr, " %6x | ", ictr & 0xfffff0);
912*66660095SIan Lepore 
913*66660095SIan Lepore 		for (ictr2 = 0; ictr2 < 16; ictr2++) {
914*66660095SIan Lepore 			index = ictr + ictr2;
915*66660095SIan Lepore 
916*66660095SIan Lepore 			if (index < icount) {
917*66660095SIan Lepore 				ch = ((uint8_t *) pbuf)[index];
918*66660095SIan Lepore 
919*66660095SIan Lepore 				if (lsb)
920*66660095SIan Lepore 					ch = reversebits[ch];
921*66660095SIan Lepore 
922*66660095SIan Lepore 				fprintf(stderr, "%02hhx ", ch);
923*66660095SIan Lepore 			}
924*66660095SIan Lepore 			else {
925*66660095SIan Lepore 				fputs("   ", stderr);
926*66660095SIan Lepore 			}
927*66660095SIan Lepore 		}
928*66660095SIan Lepore 
929*66660095SIan Lepore 		fputs("| ", stderr);
930*66660095SIan Lepore 
931*66660095SIan Lepore 		for (ictr2 = 0; ictr2 < 16; ictr2++) {
932*66660095SIan Lepore 			index = ictr + ictr2;
933*66660095SIan Lepore 
934*66660095SIan Lepore 			if (index < icount) {
935*66660095SIan Lepore 				ch = ((uint8_t *) pbuf)[index];
936*66660095SIan Lepore 
937*66660095SIan Lepore 				if (lsb)
938*66660095SIan Lepore 					ch = reversebits[ch];
939*66660095SIan Lepore 
940*66660095SIan Lepore 				if (ch < ' ' || ch > 127)
941*66660095SIan Lepore 					goto out_of_range;
942*66660095SIan Lepore 
943*66660095SIan Lepore 				fprintf(stderr, "%c", ch);
944*66660095SIan Lepore 			}
945*66660095SIan Lepore 			else if (index < icount) {
946*66660095SIan Lepore 		out_of_range:
947*66660095SIan Lepore 				fputc('.', stderr);
948*66660095SIan Lepore 			}
949*66660095SIan Lepore 			else {
950*66660095SIan Lepore 				fputc(' ', stderr);
951*66660095SIan Lepore 			}
952*66660095SIan Lepore 		}
953*66660095SIan Lepore 
954*66660095SIan Lepore 		fputs(" |\n", stderr);
955*66660095SIan Lepore 	}
956*66660095SIan Lepore 
957*66660095SIan Lepore 	fflush(stderr);
958*66660095SIan Lepore }
959