]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/spi/spi.c
bhyvectl(8): Normalize the man page date
[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 __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 }