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