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] [-S] [-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 " -S constantly stream from stdin to bus\n"
149 " -v verbose output\n"
150 " -h prints this message\n"
151 "\n"
152 "NOTE: setting the mode and/or speed is 'sticky'. Subsequent transactions\n"
153 " on that device will, by default, use the previously set values.\n"
154 "\n",
155 stderr);
156 }
157
158 int
main(int argc,char * argv[],char * envp[]__unused)159 main(int argc, char *argv[], char *envp[] __unused)
160 {
161 struct spi_options opt;
162 int err, ch, hdev, finfo, stream, fdir;
163 char *pstr;
164 char dev_name[PATH_MAX * 2 + 5];
165
166 finfo = 0;
167 stream = 0;
168 fdir = DIR_NONE;
169
170 hdev = -1;
171 err = 0;
172
173 dev_name[0] = 0;
174
175 opt.mode = -1;
176 opt.speed = -1;
177 opt.count = 0;
178 opt.ASCII = 0;
179 opt.binary = 0;
180 opt.lsb = 0;
181 opt.verbose = 0;
182 opt.ncmd = 0;
183 opt.pcmd = NULL;
184
185 while (!err && (ch = getopt(argc, argv, "f:d:m:s:c:C:AbLviSh")) != -1) {
186 switch (ch) {
187 case 'd':
188 if (optarg[0] == 'r') {
189 if (optarg[1] == 'w' && optarg[2] == 0) {
190 fdir = DIR_READWRITE;
191 }
192 else if (optarg[1] == 0) {
193 fdir = DIR_READ;
194 }
195 }
196 else if (optarg[0] == 'w' && optarg[1] == 0) {
197 fdir = DIR_WRITE;
198 }
199 else {
200 err = 1;
201 }
202 break;
203
204 case 'f':
205 if (!optarg[0]) { /* unlikely */
206 fputs("error - missing device name\n", stderr);
207 err = 1;
208 }
209 else {
210 if (optarg[0] == '/')
211 strlcpy(dev_name, optarg,
212 sizeof(dev_name));
213 else
214 snprintf(dev_name, sizeof(dev_name),
215 "/dev/%s", optarg);
216 }
217 break;
218
219 case 'm':
220 opt.mode = (int)strtol(optarg, &pstr, 10);
221
222 if (!pstr || *pstr || opt.mode < 0 || opt.mode > 3) {
223 fprintf(stderr, "Invalid mode specified: %s\n",
224 optarg);
225 err = 1;
226 }
227 break;
228
229 case 's':
230 opt.speed = (int)strtol(optarg, &pstr, 10);
231
232 if (!pstr || *pstr || opt.speed < 0) {
233 fprintf(stderr, "Invalid speed specified: %s\n",
234 optarg);
235 err = 1;
236 }
237 break;
238
239 case 'c':
240 opt.count = (int)strtol(optarg, &pstr, 10);
241
242 if (!pstr || *pstr) {
243 fprintf(stderr, "Invalid count specified: %s\n",
244 optarg);
245 err = 1;
246 }
247 break;
248
249 case 'C':
250 if(opt.pcmd) /* specified more than once */
251 err = 1;
252 else {
253 /* get malloc'd buffer or error */
254 if (interpret_command_bytes(optarg, &opt))
255 err = 1;
256 }
257
258 break;
259
260 case 'A':
261 opt.ASCII = 1;
262 break;
263
264 case 'b':
265 opt.binary = 1;
266 break;
267
268 case 'L':
269 opt.lsb = 1;
270 break;
271
272 case 'v':
273 opt.verbose++;
274 break;
275
276 case 'i':
277 finfo = 1;
278 break;
279
280 case 'S':
281 stream = 1;
282 break;
283
284 default:
285 err = 1;
286 /* FALLTHROUGH */
287 case 'h':
288 usage();
289 goto the_end;
290 }
291 }
292
293 argc -= optind;
294 argv += optind;
295
296 if (err ||
297 (fdir == DIR_NONE && !finfo && opt.mode == -1 && opt.speed == -1 && opt.count == 0)) {
298 /*
299 * if any of the direction, mode, speed, or count not specified,
300 * print usage
301 */
302
303 usage();
304 goto the_end;
305 }
306
307 if ((opt.count != 0 || opt.ncmd != 0) && fdir == DIR_NONE) {
308 /*
309 * count was specified, but direction was not. default is
310 * read/write
311 */
312 /*
313 * this includes a negative count, which implies write from
314 * stdin
315 */
316 if (opt.count == 0)
317 fdir = DIR_WRITE;
318 else
319 fdir = DIR_READWRITE;
320 }
321
322 if (opt.count < 0 && fdir != DIR_READWRITE && fdir != DIR_WRITE) {
323 fprintf(stderr, "Invalid length %d when not writing data\n",
324 opt.count);
325
326 err = 1;
327 usage();
328 goto the_end;
329 }
330
331
332 if (!dev_name[0]) /* no device name specified */
333 strlcpy(dev_name, DEFAULT_DEVICE_NAME, sizeof(dev_name));
334
335 hdev = open(dev_name, O_RDWR);
336
337 if (hdev == -1) {
338 fprintf(stderr, "Error - unable to open '%s', errno=%d\n",
339 dev_name, errno);
340 err = 1;
341 goto the_end;
342 }
343
344 if (finfo) {
345 err = get_info(hdev, dev_name);
346 goto the_end;
347 }
348
349 /* check and assign mode, speed */
350
351 if (opt.mode != -1) {
352 err = set_mode(hdev, &opt);
353
354 if (err)
355 goto the_end;
356 }
357
358 if (opt.speed != -1) {
359 err = set_speed(hdev, &opt);
360
361 if (err)
362 goto the_end;
363 }
364
365 /* do data transfer */
366
367 if (stream) {
368 while (!err && !feof(stdin)) {
369 if (fdir == DIR_READ) {
370 err = perform_read(hdev, &opt);
371 }
372 else if (fdir == DIR_WRITE) {
373 err = perform_write(hdev, &opt);
374 }
375 else if (fdir == DIR_READWRITE) {
376 err = perform_readwrite(hdev, &opt);
377 }
378 }
379 }
380 else {
381 if (fdir == DIR_READ) {
382 err = perform_read(hdev, &opt);
383 }
384 else if (fdir == DIR_WRITE) {
385 err = perform_write(hdev, &opt);
386 }
387 else if (fdir == DIR_READWRITE) {
388 err = perform_readwrite(hdev, &opt);
389 }
390 }
391
392 the_end:
393
394 if (hdev != -1)
395 close(hdev);
396
397 free(opt.pcmd);
398
399 return (err);
400 }
401
402 static int
interpret_command_bytes(const char * parg,struct spi_options * popt)403 interpret_command_bytes(const char *parg, struct spi_options *popt)
404 {
405 int ch, ch2, ctr, cbcmd, err;
406 const char *ppos;
407 void *ptemp;
408 uint8_t *pcur;
409
410 err = 0;
411 cbcmd = DEFAULT_BUFFER_SIZE; /* initial cmd buffer size */
412 popt->pcmd = (uint8_t *)malloc(cbcmd);
413
414 if (!popt->pcmd)
415 return 1;
416
417 pcur = popt->pcmd;
418
419 ctr = 0;
420 ppos = parg;
421
422 while (*ppos) {
423 while (*ppos && *ppos <= ' ') {
424 ppos++; /* skip (optional) leading white space */
425 }
426
427 if (!*ppos)
428 break; /* I am done */
429
430 ch = hexval(*(ppos++));
431 if (ch < 0 || !*ppos) { /* must be valid pair of hex characters */
432 err = 1;
433 goto the_end;
434 }
435
436 ch2 = hexval(*(ppos++));
437 if (ch2 < 0) {
438 err = 1;
439 goto the_end;
440 }
441
442 ch = (ch * 16 + ch2) & 0xff; /* convert to byte */
443
444 if (ctr >= cbcmd) { /* need re-alloc buffer? (unlikely) */
445 cbcmd += 8192; /* increase by additional 8k */
446 ptemp = realloc(popt->pcmd, cbcmd);
447
448 if (!ptemp) {
449 err = 1;
450 fprintf(stderr,
451 "Not enough memory to interpret command bytes, errno=%d\n",
452 errno);
453 goto the_end;
454 }
455
456 popt->pcmd = (uint8_t *)ptemp;
457 pcur = popt->pcmd + ctr;
458 }
459
460 if (popt->lsb)
461 *pcur = reversebits[ch];
462 else
463 *pcur = (uint8_t)ch;
464
465 pcur++;
466 ctr++;
467 }
468
469 popt->ncmd = ctr; /* record num bytes in '-C' argument */
470
471 the_end:
472
473 /* at this point popt->pcmd is NULL or a valid pointer */
474
475 return err;
476 }
477
478 static int
get_info(int hdev,const char * dev_name)479 get_info(int hdev, const char *dev_name)
480 {
481 uint32_t fmode, fspeed;
482 int err;
483 char temp_buf[PATH_MAX], cpath[PATH_MAX];
484
485 if (!realpath(dev_name, cpath)) /* get canonical name for info purposes */
486 strlcpy(cpath, temp_buf, sizeof(cpath)); /* this shouldn't happen */
487
488 err = ioctl(hdev, SPIGENIOC_GET_SPI_MODE, &fmode);
489
490 if (err == 0)
491 err = ioctl(hdev, SPIGENIOC_GET_CLOCK_SPEED, &fspeed);
492
493 if (err == 0) {
494 fprintf(stderr,
495 "Device name: %s\n"
496 "Device mode: %d\n"
497 "Device speed: %d\n",
498 cpath, fmode, fspeed);//, max_cmd, max_data, temp_buf);
499 }
500 else
501 fprintf(stderr, "Unable to query info (err=%d), errno=%d\n",
502 err, errno);
503
504 return err;
505 }
506
507 static int
set_mode(int hdev,struct spi_options * popt)508 set_mode(int hdev, struct spi_options *popt)
509 {
510 uint32_t fmode = popt->mode;
511
512 if (popt->mode < 0) /* use default? */
513 return 0;
514
515 return ioctl(hdev, SPIGENIOC_SET_SPI_MODE, &fmode);
516 }
517
518 static int
set_speed(int hdev,struct spi_options * popt)519 set_speed(int hdev, struct spi_options *popt)
520 {
521 uint32_t clock_speed = popt->speed;
522
523 if (popt->speed < 0)
524 return 0;
525
526 return ioctl(hdev, SPIGENIOC_SET_CLOCK_SPEED, &clock_speed);
527 }
528
529 static int
hexval(char c)530 hexval(char c)
531 {
532 if (c >= '0' && c <= '9') {
533 return c - '0';
534 } else if (c >= 'A' && c <= 'F') {
535 return c - 'A' + 10;
536 } else if (c >= 'a' && c <= 'f') {
537 return c - 'a' + 10;
538 }
539 return -1;
540 }
541
542 static void *
prep_write_buffer(struct spi_options * popt)543 prep_write_buffer(struct spi_options *popt)
544 {
545 int ch, ch2, ch3, ncmd, lsb, err;
546 uint8_t *pdata, *pdat2;
547 size_t cbdata, cbread;
548 const char *szbytes;
549
550 ncmd = popt->ncmd; /* num command bytes (can be zero) */
551
552 if (ncmd == 0 && popt->count == 0)
553 return NULL; /* always since it's an error if it happens
554 * now */
555
556 if (popt->count < 0) {
557 cbdata = DEFAULT_BUFFER_SIZE;
558 }
559 else {
560 cbdata = popt->count;
561 }
562
563 lsb = popt->lsb; /* non-zero if LSB order; else MSB */
564
565 pdata = malloc(cbdata + ncmd + 1);
566 cbread = 0;
567
568 err = 0;
569
570 if (!pdata)
571 return NULL;
572
573 if (popt->pcmd && ncmd > 0) {
574 memcpy(pdata, popt->pcmd, ncmd); /* copy command bytes */
575 pdat2 = pdata + ncmd;
576 }
577 else
578 pdat2 = pdata; /* no prepended command data */
579
580 /*
581 * read up to 'cbdata' bytes. If I get an EOF, do one of two things:
582 * a) change the data count to match how many bytes I read in b) fill
583 * the rest of the input buffer with zeros
584 *
585 * If the specified length is negative, I do 'a', else 'b'
586 */
587
588 while (!err && cbread < cbdata && (ch = fgetc(stdin)) != EOF) {
589 if (popt->ASCII) {
590 /* skip consecutive white space */
591
592 while (ch <= ' ') {
593 if ((ch = fgetc(stdin)) == EOF)
594 break;
595 }
596
597 if (ch != EOF) {
598 ch2 = hexval(ch);
599
600 if (ch2 < 0) {
601 invalid_character:
602 fprintf(stderr,
603 "Invalid input character '%c'\n", ch);
604 err = 1;
605 break;
606 }
607
608 ch = fgetc(stdin);
609
610 if (ch != EOF) {
611 ch3 = hexval(ch);
612
613 if (ch3 < 0)
614 goto invalid_character;
615
616 ch = ch2 * 16 + ch3;
617 }
618 }
619
620 if (err || ch == EOF)
621 break;
622 }
623
624 /* for LSB, flip the bits - otherwise, just copy the value */
625 if (lsb)
626 pdat2[cbread] = reversebits[ch];
627 else
628 pdat2[cbread] = (uint8_t) ch;
629
630 cbread++; /* increment num bytes read so far */
631 }
632
633 /* if it was an error, not an EOF, that ended the I/O, return NULL */
634
635 if (err || ferror(stdin)) {
636 free(pdata);
637 return NULL;
638 }
639
640 if (popt->verbose > 0) {
641 const char *sz_bytes;
642
643 if (cbread != 1)
644 sz_bytes = "bytes"; /* correct plurality of 'byte|bytes' */
645 else
646 sz_bytes = "byte";
647
648 if (popt->ASCII)
649 fprintf(stderr, "ASCII input of %zd %s\n", cbread,
650 sz_bytes);
651 else
652 fprintf(stderr, "Binary input of %zd %s\n", cbread,
653 sz_bytes);
654 }
655
656 /*
657 * if opt.count is negative, copy actual byte count to opt.count which does
658 * not include any of the 'command' bytes that are being sent. Can be zero.
659 */
660 if (popt->count < 0) {
661 popt->count = cbread;
662 }
663 /*
664 * for everything else, fill the rest of the read buffer with '0'
665 * bytes, as per the standard practice for SPI
666 */
667 else {
668 while (cbread < cbdata)
669 pdat2[cbread++] = 0;
670 }
671
672 /*
673 * popt->count bytes will be sent and read from the SPI, preceded by the
674 * 'popt->ncmd' command bytes (if any).
675 * So we must use 'popt->count' and 'popt->ncmd' from this point on in
676 * the code.
677 */
678
679 if (popt->verbose > 0 && popt->count + popt->ncmd) {
680 if ((popt->count + popt->ncmd) == 1)
681 szbytes = "byte";
682 else
683 szbytes = "bytes";
684
685 fprintf(stderr, "Writing %d %s to SPI device\n",
686 popt->count + popt->ncmd, szbytes);
687
688 verbose_dump_buffer(pdata, popt->count + popt->ncmd, lsb);
689 }
690
691 return pdata;
692 }
693
694 static int
_read_write(int hdev,void * bufw,void * bufr,int cbrw,int lsb)695 _read_write(int hdev, void *bufw, void *bufr, int cbrw, int lsb)
696 {
697 int err, ctr;
698 struct spigen_transfer spi;
699
700 if (!cbrw)
701 return 0;
702
703 if (!bufr)
704 bufr = bufw;
705 else
706 memcpy(bufr, bufw, cbrw); /* transaction uses bufr for
707 * both R and W */
708
709 bzero(&spi, sizeof(spi)); /* zero structure first */
710
711 /* spigen code seems to suggest there must be at least 1 command byte */
712
713 spi.st_command.iov_base = bufr;
714 spi.st_command.iov_len = cbrw;
715
716 /*
717 * The remaining members for spi.st_data are zero - all bytes are
718 * 'command' for this. The driver doesn't really do anything different
719 * for 'command' vs 'data' and at least one command byte must be sent in
720 * the transaction.
721 */
722
723 err = ioctl(hdev, SPIGENIOC_TRANSFER, &spi) < 0 ? -1 : 0;
724
725 if (!err && lsb) {
726 /* flip the bits for 'lsb' mode */
727 for (ctr = 0; ctr < cbrw; ctr++) {
728 ((uint8_t *) bufr)[ctr] =
729 reversebits[((uint8_t *)bufr)[ctr]];
730 }
731 }
732
733 if (err)
734 fprintf(stderr, "Error performing SPI transaction, errno=%d\n",
735 errno);
736
737 return err;
738 }
739
740 static int
_do_data_output(void * pr,struct spi_options * popt)741 _do_data_output(void *pr, struct spi_options *popt)
742 {
743 int err, idx, icount;
744 const char *sz_bytes, *sz_byte2;
745 const uint8_t *pbuf;
746
747 pbuf = (uint8_t *)pr + popt->ncmd; /* only the data we want */
748 icount = popt->count;
749 err = 0;
750
751 if (icount <= 0) {
752 return -1; /* should not but could happen */
753 }
754
755 if (icount != 1)
756 sz_bytes = "bytes"; /* correct plurality of 'byte|bytes' */
757 else
758 sz_bytes = "byte";
759
760 if (popt->ncmd != 1)
761 sz_byte2 = "bytes";
762 else
763 sz_byte2 = "byte";
764
765 /* binary on stdout */
766 if (popt->binary || !popt->ASCII) {
767 if (popt->verbose > 0)
768 fprintf(stderr, "Binary output of %d %s\n", icount,
769 sz_bytes);
770
771 err = (int)fwrite(pbuf, 1, icount, stdout) != icount;
772 }
773 else if (icount > 0) {
774 if (popt->verbose > 0)
775 fprintf(stderr, "ASCII output of %d %s\n", icount,
776 sz_bytes);
777
778 /* ASCII output */
779 for (idx = 0; !err && idx < icount; idx++) {
780 if (idx) {
781 /*
782 * not the first time, insert separating space
783 */
784 err = fputc(' ', stdout) == EOF;
785 }
786
787 if (!err)
788 err = fprintf(stdout, "%02hhx", pbuf[idx]) < 0;
789 }
790
791 if (!err)
792 err = fputc('\n', stdout) == EOF;
793 }
794
795 /* verbose text out on stderr */
796
797 if (err)
798 fprintf(stderr, "Error writing to stdout, errno=%d\n", errno);
799 else if (popt->verbose > 0 && icount) {
800 fprintf(stderr,
801 "%d command %s and %d data %s read from SPI device\n",
802 popt->ncmd, sz_byte2, icount, sz_bytes);
803
804 /* verbose output will show the command bytes as well */
805 verbose_dump_buffer(pr, icount + popt->ncmd, popt->lsb);
806 }
807
808 return err;
809 }
810
811 static int
perform_read(int hdev,struct spi_options * popt)812 perform_read(int hdev, struct spi_options *popt)
813 {
814 int icount, err;
815 void *pr, *pw;
816
817 pr = NULL;
818 icount = popt->count + popt->ncmd;
819
820 /* prep write buffer filled with 0 bytes */
821 pw = malloc(icount);
822
823 if (!pw) {
824 err = -1;
825 goto the_end;
826 }
827
828 bzero(pw, icount);
829
830 /* if I included a command sequence, copy bytes to the write buf */
831 if (popt->pcmd && popt->ncmd > 0)
832 memcpy(pw, popt->pcmd, popt->ncmd);
833
834 pr = malloc(icount + 1);
835
836 if (!pr) {
837 err = -2;
838 goto the_end;
839 }
840
841 bzero(pr, icount);
842
843 err = _read_write(hdev, pw, pr, icount, popt->lsb);
844
845 if (!err && popt->count > 0)
846 err = _do_data_output(pr, popt);
847
848 the_end:
849
850 free(pr);
851 free(pw);
852
853 return err;
854 }
855
856 static int
perform_write(int hdev,struct spi_options * popt)857 perform_write(int hdev, struct spi_options *popt)
858 {
859 int err;
860 void *pw;
861
862 /* read data from cmd buf and stdin and write to 'write' buffer */
863
864 pw = prep_write_buffer(popt);
865
866 if (!pw) {
867 err = -1;
868 goto the_end;
869 }
870
871 err = _read_write(hdev, pw, NULL, popt->count + popt->ncmd, popt->lsb);
872
873 the_end:
874
875 free(pw);
876
877 return err;
878 }
879
880 static int
perform_readwrite(int hdev,struct spi_options * popt)881 perform_readwrite(int hdev, struct spi_options *popt)
882 {
883 int icount, err;
884 void *pr, *pw;
885
886 pr = NULL;
887
888 pw = prep_write_buffer(popt);
889 icount = popt->count + popt->ncmd; /* assign after fn call */
890
891 if (!pw) {
892 err = -1;
893 goto the_end;
894 }
895
896 pr = malloc(icount + 1);
897
898 if (!pr) {
899 err = -2;
900 goto the_end;
901 }
902
903 bzero(pr, icount);
904
905 err = _read_write(hdev, pw, pr, icount, popt->lsb);
906
907 if (!err)
908 err = _do_data_output(pr, popt);
909
910 the_end:
911
912 free(pr);
913 free(pw);
914
915 return err;
916 }
917
918
919 static void
verbose_dump_buffer(void * pbuf,int icount,int lsb)920 verbose_dump_buffer(void *pbuf, int icount, int lsb)
921 {
922 uint8_t ch;
923 int ictr, ictr2, idx;
924
925 fputs(" | 0 1 2 3 4 5 6 7 8 9 A B C D E F "
926 "| |\n", stderr);
927
928 for (ictr = 0; ictr < icount; ictr += 16) {
929 fprintf(stderr, " %6x | ", ictr & 0xfffff0);
930
931 for (ictr2 = 0; ictr2 < 16; ictr2++) {
932 idx = ictr + ictr2;
933
934 if (idx < icount) {
935 ch = ((uint8_t *) pbuf)[idx];
936
937 if (lsb)
938 ch = reversebits[ch];
939
940 fprintf(stderr, "%02hhx ", ch);
941 }
942 else {
943 fputs(" ", stderr);
944 }
945 }
946
947 fputs("| ", stderr);
948
949 for (ictr2 = 0; ictr2 < 16; ictr2++) {
950 idx = ictr + ictr2;
951
952 if (idx < icount) {
953 ch = ((uint8_t *) pbuf)[idx];
954
955 if (lsb)
956 ch = reversebits[ch];
957
958 if (ch < ' ' || ch > 127)
959 goto out_of_range;
960
961 fprintf(stderr, "%c", ch);
962 }
963 else if (idx < icount) {
964 out_of_range:
965 fputc('.', stderr);
966 }
967 else {
968 fputc(' ', stderr);
969 }
970 }
971
972 fputs(" |\n", stderr);
973 }
974
975 fflush(stderr);
976 }
977