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