2 * SPDX-License-Identifier: BSD-2-Clause
4 * Copyright (c) 2018 S.F.T. Inc.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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
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>
45 #define DEFAULT_DEVICE_NAME "/dev/spigen0.0"
47 #define DEFAULT_BUFFER_SIZE 8192
51 #define DIR_READWRITE 2
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
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
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) */
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);
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
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
129 fputs(getprogname(), stderr);
130 fputs(" - communicate on SPI bus with slave devices\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"
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"
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"
159 main(int argc, char *argv[], char *envp[] __unused)
161 struct spi_options opt;
162 int err, ch, hdev, finfo, fdir;
164 char dev_name[PATH_MAX * 2 + 5];
184 while (!err && (ch = getopt(argc, argv, "f:d:m:s:c:C:AbLvih")) != -1) {
187 if (optarg[0] == 'r') {
188 if (optarg[1] == 'w' && optarg[2] == 0) {
189 fdir = DIR_READWRITE;
191 else if (optarg[1] == 0) {
195 else if (optarg[0] == 'w' && optarg[1] == 0) {
204 if (!optarg[0]) { /* unlikely */
205 fputs("error - missing device name\n", stderr);
209 if (optarg[0] == '/')
210 strlcpy(dev_name, optarg,
213 snprintf(dev_name, sizeof(dev_name),
219 opt.mode = (int)strtol(optarg, &pstr, 10);
221 if (!pstr || *pstr || opt.mode < 0 || opt.mode > 3) {
222 fprintf(stderr, "Invalid mode specified: %s\n",
229 opt.speed = (int)strtol(optarg, &pstr, 10);
231 if (!pstr || *pstr || opt.speed < 0) {
232 fprintf(stderr, "Invalid speed specified: %s\n",
239 opt.count = (int)strtol(optarg, &pstr, 10);
241 if (!pstr || *pstr) {
242 fprintf(stderr, "Invalid count specified: %s\n",
249 if(opt.pcmd) /* specified more than once */
252 /* get malloc'd buffer or error */
253 if (interpret_command_bytes(optarg, &opt))
292 (fdir == DIR_NONE && !finfo && opt.mode == -1 && opt.speed == -1 && opt.count == 0)) {
294 * if any of the direction, mode, speed, or count not specified,
302 if ((opt.count != 0 || opt.ncmd != 0) && fdir == DIR_NONE) {
304 * count was specified, but direction was not. default is
308 * this includes a negative count, which implies write from
314 fdir = DIR_READWRITE;
317 if (opt.count < 0 && fdir != DIR_READWRITE && fdir != DIR_WRITE) {
318 fprintf(stderr, "Invalid length %d when not writing data\n",
327 if (!dev_name[0]) /* no device name specified */
328 strlcpy(dev_name, DEFAULT_DEVICE_NAME, sizeof(dev_name));
330 hdev = open(dev_name, O_RDWR);
333 fprintf(stderr, "Error - unable to open '%s', errno=%d\n",
340 err = get_info(hdev, dev_name);
344 /* check and assign mode, speed */
346 if (opt.mode != -1) {
347 err = set_mode(hdev, &opt);
353 if (opt.speed != -1) {
354 err = set_speed(hdev, &opt);
360 /* do data transfer */
362 if (fdir == DIR_READ) {
363 err = perform_read(hdev, &opt);
365 else if (fdir == DIR_WRITE) {
366 err = perform_write(hdev, &opt);
368 else if (fdir == DIR_READWRITE) {
369 err = perform_readwrite(hdev, &opt);
383 interpret_command_bytes(const char *parg, struct spi_options *popt)
385 int ch, ch2, ctr, cbcmd, err;
391 cbcmd = DEFAULT_BUFFER_SIZE; /* initial cmd buffer size */
392 popt->pcmd = (uint8_t *)malloc(cbcmd);
403 while (*ppos && *ppos <= ' ') {
404 ppos++; /* skip (optional) leading white space */
408 break; /* I am done */
410 ch = hexval(*(ppos++));
411 if (ch < 0 || !*ppos) { /* must be valid pair of hex characters */
416 ch2 = hexval(*(ppos++));
422 ch = (ch * 16 + ch2) & 0xff; /* convert to byte */
424 if (ctr >= cbcmd) { /* need re-alloc buffer? (unlikely) */
425 cbcmd += 8192; /* increase by additional 8k */
426 ptemp = realloc(popt->pcmd, cbcmd);
431 "Not enough memory to interpret command bytes, errno=%d\n",
436 popt->pcmd = (uint8_t *)ptemp;
437 pcur = popt->pcmd + ctr;
441 *pcur = reversebits[ch];
449 popt->ncmd = ctr; /* record num bytes in '-C' argument */
453 /* at this point popt->pcmd is NULL or a valid pointer */
459 get_info(int hdev, const char *dev_name)
461 uint32_t fmode, fspeed;
463 char temp_buf[PATH_MAX], cpath[PATH_MAX];
465 if (!realpath(dev_name, cpath)) /* get canonical name for info purposes */
466 strlcpy(cpath, temp_buf, sizeof(cpath)); /* this shouldn't happen */
468 err = ioctl(hdev, SPIGENIOC_GET_SPI_MODE, &fmode);
471 err = ioctl(hdev, SPIGENIOC_GET_CLOCK_SPEED, &fspeed);
477 "Device speed: %d\n",
478 cpath, fmode, fspeed);//, max_cmd, max_data, temp_buf);
481 fprintf(stderr, "Unable to query info (err=%d), errno=%d\n",
488 set_mode(int hdev, struct spi_options *popt)
490 uint32_t fmode = popt->mode;
492 if (popt->mode < 0) /* use default? */
495 return ioctl(hdev, SPIGENIOC_SET_SPI_MODE, &fmode);
499 set_speed(int hdev, struct spi_options *popt)
501 uint32_t clock_speed = popt->speed;
506 return ioctl(hdev, SPIGENIOC_SET_CLOCK_SPEED, &clock_speed);
512 if (c >= '0' && c <= '9') {
514 } else if (c >= 'A' && c <= 'F') {
516 } else if (c >= 'a' && c <= 'f') {
523 prep_write_buffer(struct spi_options *popt)
525 int ch, ch2, ch3, ncmd, lsb, err;
526 uint8_t *pdata, *pdat2;
527 size_t cbdata, cbread;
530 ncmd = popt->ncmd; /* num command bytes (can be zero) */
532 if (ncmd == 0 && popt->count == 0)
533 return NULL; /* always since it's an error if it happens
536 if (popt->count < 0) {
537 cbdata = DEFAULT_BUFFER_SIZE;
540 cbdata = popt->count;
543 lsb = popt->lsb; /* non-zero if LSB order; else MSB */
545 pdata = malloc(cbdata + ncmd + 1);
553 if (popt->pcmd && ncmd > 0) {
554 memcpy(pdata, popt->pcmd, ncmd); /* copy command bytes */
555 pdat2 = pdata + ncmd;
558 pdat2 = pdata; /* no prepended command data */
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
565 * If the specified length is negative, I do 'a', else 'b'
568 while (!err && cbread < cbdata && (ch = fgetc(stdin)) != EOF) {
570 /* skip consecutive white space */
573 if ((ch = fgetc(stdin)) == EOF)
583 "Invalid input character '%c'\n", ch);
594 goto invalid_character;
600 if (err || ch == EOF)
604 /* for LSB, flip the bits - otherwise, just copy the value */
606 pdat2[cbread] = reversebits[ch];
608 pdat2[cbread] = (uint8_t) ch;
610 cbread++; /* increment num bytes read so far */
613 /* if it was an error, not an EOF, that ended the I/O, return NULL */
615 if (err || ferror(stdin)) {
620 if (popt->verbose > 0) {
621 const char *sz_bytes;
624 sz_bytes = "bytes"; /* correct plurality of 'byte|bytes' */
629 fprintf(stderr, "ASCII input of %zd %s\n", cbread,
632 fprintf(stderr, "Binary input of %zd %s\n", cbread,
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.
640 if (popt->count < 0) {
641 popt->count = cbread;
644 * for everything else, fill the rest of the read buffer with '0'
645 * bytes, as per the standard practice for SPI
648 while (cbread < cbdata)
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
659 if (popt->verbose > 0 && popt->count + popt->ncmd) {
660 if ((popt->count + popt->ncmd) == 1)
665 fprintf(stderr, "Writing %d %s to SPI device\n",
666 popt->count + popt->ncmd, szbytes);
668 verbose_dump_buffer(pdata, popt->count + popt->ncmd, lsb);
675 _read_write(int hdev, void *bufw, void *bufr, int cbrw, int lsb)
678 struct spigen_transfer spi;
686 memcpy(bufr, bufw, cbrw); /* transaction uses bufr for
689 bzero(&spi, sizeof(spi)); /* zero structure first */
691 /* spigen code seems to suggest there must be at least 1 command byte */
693 spi.st_command.iov_base = bufr;
694 spi.st_command.iov_len = cbrw;
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
703 err = ioctl(hdev, SPIGENIOC_TRANSFER, &spi) < 0 ? -1 : 0;
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]];
714 fprintf(stderr, "Error performing SPI transaction, errno=%d\n",
721 _do_data_output(void *pr, struct spi_options *popt)
723 int err, idx, icount;
724 const char *sz_bytes, *sz_byte2;
727 pbuf = (uint8_t *)pr + popt->ncmd; /* only the data we want */
728 icount = popt->count;
732 return -1; /* should not but could happen */
736 sz_bytes = "bytes"; /* correct plurality of 'byte|bytes' */
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,
751 err = (int)fwrite(pbuf, 1, icount, stdout) != icount;
753 else if (icount > 0) {
754 if (popt->verbose > 0)
755 fprintf(stderr, "ASCII output of %d %s\n", icount,
759 for (idx = 0; !err && idx < icount; idx++) {
762 * not the first time, insert separating space
764 err = fputc(' ', stdout) == EOF;
768 err = fprintf(stdout, "%02hhx", pbuf[idx]) < 0;
772 err = fputc('\n', stdout) == EOF;
775 /* verbose text out on stderr */
778 fprintf(stderr, "Error writing to stdout, errno=%d\n", errno);
779 else if (popt->verbose > 0 && icount) {
781 "%d command %s and %d data %s read from SPI device\n",
782 popt->ncmd, sz_byte2, icount, sz_bytes);
784 /* verbose output will show the command bytes as well */
785 verbose_dump_buffer(pr, icount + popt->ncmd, popt->lsb);
792 perform_read(int hdev, struct spi_options *popt)
798 icount = popt->count + popt->ncmd;
800 /* prep write buffer filled with 0 bytes */
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);
814 pr = malloc(icount + 1);
823 err = _read_write(hdev, pw, pr, icount, popt->lsb);
825 if (!err && popt->count > 0)
826 err = _do_data_output(pr, popt);
837 perform_write(int hdev, struct spi_options *popt)
842 /* read data from cmd buf and stdin and write to 'write' buffer */
844 pw = prep_write_buffer(popt);
851 err = _read_write(hdev, pw, NULL, popt->count + popt->ncmd, popt->lsb);
861 perform_readwrite(int hdev, struct spi_options *popt)
868 pw = prep_write_buffer(popt);
869 icount = popt->count + popt->ncmd; /* assign after fn call */
876 pr = malloc(icount + 1);
885 err = _read_write(hdev, pw, pr, icount, popt->lsb);
888 err = _do_data_output(pr, popt);
900 verbose_dump_buffer(void *pbuf, int icount, int lsb)
903 int ictr, ictr2, idx;
905 fputs(" | 0 1 2 3 4 5 6 7 8 9 A B C D E F "
908 for (ictr = 0; ictr < icount; ictr += 16) {
909 fprintf(stderr, " %6x | ", ictr & 0xfffff0);
911 for (ictr2 = 0; ictr2 < 16; ictr2++) {
915 ch = ((uint8_t *) pbuf)[idx];
918 ch = reversebits[ch];
920 fprintf(stderr, "%02hhx ", ch);
929 for (ictr2 = 0; ictr2 < 16; ictr2++) {
933 ch = ((uint8_t *) pbuf)[idx];
936 ch = reversebits[ch];
938 if (ch < ' ' || ch > 127)
941 fprintf(stderr, "%c", ch);
943 else if (idx < icount) {
952 fputs(" |\n", stderr);