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