Super User's BSD Cross Reference: /FreeBSD/usr.sbin/spi/spi.c

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

AltStyle によって変換されたページ (->オリジナル) /