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