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