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/types.h>
29 #include <sys/ioccom.h>
30 #include <sys/spigenio.h>
31 #include <sys/sysctl.h>
44 #define DEFAULT_DEVICE_NAME "/dev/spigen0.0"
46 #define DEFAULT_BUFFER_SIZE 8192
50 #define DIR_READWRITE 2
54 int mode; /* mode (0,1,2,3, -1 == use default) */
55 int speed; /* speed (in Hz, -1 == use default) */
56 int count; /* count (0 through 'n' bytes, negative for
58 int binary; /* non-zero for binary output or zero for
59 * ASCII output when ASCII != 0 */
60 int ASCII; /* zero for binary input and output.
61 * non-zero for ASCII input, 'binary'
62 * determines output */
63 int lsb; /* non-zero for LSB order (default order is
65 int verbose; /* non-zero for verbosity */
66 int ncmd; /* bytes to skip for incoming data */
67 uint8_t *pcmd; /* command data (NULL if none) */
70 static void usage(void);
71 static int interpret_command_bytes(const char *parg, struct spi_options *popt);
72 static void * prep_write_buffer(struct spi_options *popt);
73 static int _read_write(int hdev, void *bufw, void *bufr, int cbrw, int lsb);
74 static int _do_data_output(void *pr, struct spi_options *popt);
75 static int get_info(int hdev, const char *dev_name);
76 static int set_mode(int hdev, struct spi_options *popt);
77 static int set_speed(int hdev, struct spi_options *popt);
78 static int hexval(char c);
79 static int perform_read(int hdev, struct spi_options *popt);
80 static int perform_write(int hdev, struct spi_options *popt);
81 static int perform_readwrite(int hdev, struct spi_options *popt);
82 static void verbose_dump_buffer(void *pbuf, int icount, int lsb);
85 * LSB array - reversebits[n] is the LSB value of n as an MSB. Use this array
86 * to obtain a reversed bit pattern of the index value when bits must
87 * be sent/received in an LSB order vs the default MSB
89 static uint8_t reversebits[256] = {
90 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
91 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
92 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
93 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
94 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
95 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
96 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
97 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
98 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
99 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
100 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
101 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
102 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
103 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
104 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
105 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
106 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
107 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
108 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
109 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
110 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
111 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
112 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
113 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
114 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
115 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
116 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
117 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
118 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
119 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
120 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
121 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
128 fputs(getprogname(), stderr);
129 fputs(" - communicate on SPI bus with slave devices\n"
131 " spi [-f device] [-d r|w|rw] [-m mode] [-s max-speed] [-c count]\n"
132 " [-C \"command bytes\"] [-A] [-b] [-L] [-v]\n"
133 " spi -i [-f device] [-v]\n"
136 " -f specifies the device (default is spigen0.0)\n"
137 " -d specifies the operation (r, w, or rw; default is rw)\n"
138 " -m specifies the mode (0, 1, 2, or 3)\n"
139 " -s specifies the maximum speed (default is 0, device default)\n"
140 " -c specifies the number of data bytes to transfer (default 0, i.e. none)\n"
141 " A negative value uses the length of the input data\n"
142 " -C specifies 'command bytes' to be sent, as 2 byte hexadecimal values\n"
143 " (these should be quoted, separated by optional white space)\n"
144 " -L specifies 'LSB' order on the SPI bus (default is MSB)\n"
145 " -i query information about the device\n"
146 " -A uses ASCII for input/output as 2-digit hex values\n"
147 " -b Override output format as binary (only valid with '-A')\n"
148 " -v verbose output\n"
149 " -h prints this message\n"
151 "NOTE: setting the mode and/or speed is 'sticky'. Subsequent transactions\n"
152 " on that device will, by default, use the previously set values.\n"
158 main(int argc, char *argv[], char *envp[] __unused)
160 struct spi_options opt;
161 int err, ch, hdev, finfo, fdir;
163 char dev_name[PATH_MAX * 2 + 5];
183 while (!err && (ch = getopt(argc, argv, "f:d:m:s:c:C:AbLvih")) != -1) {
186 if (optarg[0] == 'r') {
187 if (optarg[1] == 'w' && optarg[2] == 0) {
188 fdir = DIR_READWRITE;
190 else if (optarg[1] == 0) {
194 else if (optarg[0] == 'w' && optarg[1] == 0) {
203 if (!optarg[0]) { /* unlikely */
204 fputs("error - missing device name\n", stderr);
208 if (optarg[0] == '/')
209 strlcpy(dev_name, optarg,
212 snprintf(dev_name, sizeof(dev_name),
218 opt.mode = (int)strtol(optarg, &pstr, 10);
220 if (!pstr || *pstr || opt.mode < 0 || opt.mode > 3) {
221 fprintf(stderr, "Invalid mode specified: %s\n",
228 opt.speed = (int)strtol(optarg, &pstr, 10);
230 if (!pstr || *pstr || opt.speed < 0) {
231 fprintf(stderr, "Invalid speed specified: %s\n",
238 opt.count = (int)strtol(optarg, &pstr, 10);
240 if (!pstr || *pstr) {
241 fprintf(stderr, "Invalid count specified: %s\n",
248 if(opt.pcmd) /* specified more than once */
251 /* get malloc'd buffer or error */
252 if (interpret_command_bytes(optarg, &opt))
291 (fdir == DIR_NONE && !finfo && opt.mode == -1 && opt.speed == -1 && opt.count == 0)) {
293 * if any of the direction, mode, speed, or count not specified,
301 if ((opt.count != 0 || opt.ncmd != 0) && fdir == DIR_NONE) {
303 * count was specified, but direction was not. default is
307 * this includes a negative count, which implies write from
313 fdir = DIR_READWRITE;
316 if (opt.count < 0 && fdir != DIR_READWRITE && fdir != DIR_WRITE) {
317 fprintf(stderr, "Invalid length %d when not writing data\n",
326 if (!dev_name[0]) /* no device name specified */
327 strlcpy(dev_name, DEFAULT_DEVICE_NAME, sizeof(dev_name));
329 hdev = open(dev_name, O_RDWR);
332 fprintf(stderr, "Error - unable to open '%s', errno=%d\n",
339 err = get_info(hdev, dev_name);
343 /* check and assign mode, speed */
345 if (opt.mode != -1) {
346 err = set_mode(hdev, &opt);
352 if (opt.speed != -1) {
353 err = set_speed(hdev, &opt);
359 /* do data transfer */
361 if (fdir == DIR_READ) {
362 err = perform_read(hdev, &opt);
364 else if (fdir == DIR_WRITE) {
365 err = perform_write(hdev, &opt);
367 else if (fdir == DIR_READWRITE) {
368 err = perform_readwrite(hdev, &opt);
382 interpret_command_bytes(const char *parg, struct spi_options *popt)
384 int ch, ch2, ctr, cbcmd, err;
390 cbcmd = DEFAULT_BUFFER_SIZE; /* initial cmd buffer size */
391 popt->pcmd = (uint8_t *)malloc(cbcmd);
402 while (*ppos && *ppos <= ' ') {
403 ppos++; /* skip (optional) leading white space */
407 break; /* I am done */
409 ch = hexval(*(ppos++));
410 if (ch < 0 || !*ppos) { /* must be valid pair of hex characters */
415 ch2 = hexval(*(ppos++));
421 ch = (ch * 16 + ch2) & 0xff; /* convert to byte */
423 if (ctr >= cbcmd) { /* need re-alloc buffer? (unlikely) */
424 cbcmd += 8192; /* increase by additional 8k */
425 ptemp = realloc(popt->pcmd, cbcmd);
430 "Not enough memory to interpret command bytes, errno=%d\n",
435 popt->pcmd = (uint8_t *)ptemp;
436 pcur = popt->pcmd + ctr;
440 *pcur = reversebits[ch];
448 popt->ncmd = ctr; /* record num bytes in '-C' argument */
452 /* at this point popt->pcmd is NULL or a valid pointer */
458 get_info(int hdev, const char *dev_name)
460 uint32_t fmode, fspeed;
462 char temp_buf[PATH_MAX], cpath[PATH_MAX];
464 if (!realpath(dev_name, cpath)) /* get canonical name for info purposes */
465 strlcpy(cpath, temp_buf, sizeof(cpath)); /* this shouldn't happen */
467 err = ioctl(hdev, SPIGENIOC_GET_SPI_MODE, &fmode);
470 err = ioctl(hdev, SPIGENIOC_GET_CLOCK_SPEED, &fspeed);
476 "Device speed: %d\n",
477 cpath, fmode, fspeed);//, max_cmd, max_data, temp_buf);
480 fprintf(stderr, "Unable to query info (err=%d), errno=%d\n",
487 set_mode(int hdev, struct spi_options *popt)
489 uint32_t fmode = popt->mode;
491 if (popt->mode < 0) /* use default? */
494 return ioctl(hdev, SPIGENIOC_SET_SPI_MODE, &fmode);
498 set_speed(int hdev, struct spi_options *popt)
500 uint32_t clock_speed = popt->speed;
505 return ioctl(hdev, SPIGENIOC_SET_CLOCK_SPEED, &clock_speed);
511 if (c >= '0' && c <= '9') {
513 } else if (c >= 'A' && c <= 'F') {
515 } else if (c >= 'a' && c <= 'f') {
522 prep_write_buffer(struct spi_options *popt)
524 int ch, ch2, ch3, ncmd, lsb, err;
525 uint8_t *pdata, *pdat2;
526 size_t cbdata, cbread;
529 ncmd = popt->ncmd; /* num command bytes (can be zero) */
531 if (ncmd == 0 && popt->count == 0)
532 return NULL; /* always since it's an error if it happens
535 if (popt->count < 0) {
536 cbdata = DEFAULT_BUFFER_SIZE;
539 cbdata = popt->count;
542 lsb = popt->lsb; /* non-zero if LSB order; else MSB */
544 pdata = malloc(cbdata + ncmd + 1);
552 if (popt->pcmd && ncmd > 0) {
553 memcpy(pdata, popt->pcmd, ncmd); /* copy command bytes */
554 pdat2 = pdata + ncmd;
557 pdat2 = pdata; /* no prepended command data */
560 * read up to 'cbdata' bytes. If I get an EOF, do one of two things:
561 * a) change the data count to match how many bytes I read in b) fill
562 * the rest of the input buffer with zeros
564 * If the specified length is negative, I do 'a', else 'b'
567 while (!err && cbread < cbdata && (ch = fgetc(stdin)) != EOF) {
569 /* skip consecutive white space */
572 if ((ch = fgetc(stdin)) == EOF)
582 "Invalid input character '%c'\n", ch);
593 goto invalid_character;
599 if (err || ch == EOF)
603 /* for LSB, flip the bits - otherwise, just copy the value */
605 pdat2[cbread] = reversebits[ch];
607 pdat2[cbread] = (uint8_t) ch;
609 cbread++; /* increment num bytes read so far */
612 /* if it was an error, not an EOF, that ended the I/O, return NULL */
614 if (err || ferror(stdin)) {
619 if (popt->verbose > 0) {
620 const char *sz_bytes;
623 sz_bytes = "bytes"; /* correct plurality of 'byte|bytes' */
628 fprintf(stderr, "ASCII input of %zd %s\n", cbread,
631 fprintf(stderr, "Binary input of %zd %s\n", cbread,
636 * if opt.count is negative, copy actual byte count to opt.count which does
637 * not include any of the 'command' bytes that are being sent. Can be zero.
639 if (popt->count < 0) {
640 popt->count = cbread;
643 * for everything else, fill the rest of the read buffer with '0'
644 * bytes, as per the standard practice for SPI
647 while (cbread < cbdata)
652 * popt->count bytes will be sent and read from the SPI, preceded by the
653 * 'popt->ncmd' command bytes (if any).
654 * So we must use 'popt->count' and 'popt->ncmd' from this point on in
658 if (popt->verbose > 0 && popt->count + popt->ncmd) {
659 if ((popt->count + popt->ncmd) == 1)
664 fprintf(stderr, "Writing %d %s to SPI device\n",
665 popt->count + popt->ncmd, szbytes);
667 verbose_dump_buffer(pdata, popt->count + popt->ncmd, lsb);
674 _read_write(int hdev, void *bufw, void *bufr, int cbrw, int lsb)
677 struct spigen_transfer spi;
685 memcpy(bufr, bufw, cbrw); /* transaction uses bufr for
688 bzero(&spi, sizeof(spi)); /* zero structure first */
690 /* spigen code seems to suggest there must be at least 1 command byte */
692 spi.st_command.iov_base = bufr;
693 spi.st_command.iov_len = cbrw;
696 * The remaining members for spi.st_data are zero - all bytes are
697 * 'command' for this. The driver doesn't really do anything different
698 * for 'command' vs 'data' and at least one command byte must be sent in
702 err = ioctl(hdev, SPIGENIOC_TRANSFER, &spi) < 0 ? -1 : 0;
705 /* flip the bits for 'lsb' mode */
706 for (ctr = 0; ctr < cbrw; ctr++) {
707 ((uint8_t *) bufr)[ctr] =
708 reversebits[((uint8_t *)bufr)[ctr]];
713 fprintf(stderr, "Error performing SPI transaction, errno=%d\n",
720 _do_data_output(void *pr, struct spi_options *popt)
722 int err, idx, icount;
723 const char *sz_bytes, *sz_byte2;
726 pbuf = (uint8_t *)pr + popt->ncmd; /* only the data we want */
727 icount = popt->count;
731 return -1; /* should not but could happen */
735 sz_bytes = "bytes"; /* correct plurality of 'byte|bytes' */
744 /* binary on stdout */
745 if (popt->binary || !popt->ASCII) {
746 if (popt->verbose > 0)
747 fprintf(stderr, "Binary output of %d %s\n", icount,
750 err = (int)fwrite(pbuf, 1, icount, stdout) != icount;
752 else if (icount > 0) {
753 if (popt->verbose > 0)
754 fprintf(stderr, "ASCII output of %d %s\n", icount,
758 for (idx = 0; !err && idx < icount; idx++) {
761 * not the first time, insert separating space
763 err = fputc(' ', stdout) == EOF;
767 err = fprintf(stdout, "%02hhx", pbuf[idx]) < 0;
771 err = fputc('\n', stdout) == EOF;
774 /* verbose text out on stderr */
777 fprintf(stderr, "Error writing to stdout, errno=%d\n", errno);
778 else if (popt->verbose > 0 && icount) {
780 "%d command %s and %d data %s read from SPI device\n",
781 popt->ncmd, sz_byte2, icount, sz_bytes);
783 /* verbose output will show the command bytes as well */
784 verbose_dump_buffer(pr, icount + popt->ncmd, popt->lsb);
791 perform_read(int hdev, struct spi_options *popt)
797 icount = popt->count + popt->ncmd;
799 /* prep write buffer filled with 0 bytes */
809 /* if I included a command sequence, copy bytes to the write buf */
810 if (popt->pcmd && popt->ncmd > 0)
811 memcpy(pw, popt->pcmd, popt->ncmd);
813 pr = malloc(icount + 1);
822 err = _read_write(hdev, pw, pr, icount, popt->lsb);
824 if (!err && popt->count > 0)
825 err = _do_data_output(pr, popt);
836 perform_write(int hdev, struct spi_options *popt)
841 /* read data from cmd buf and stdin and write to 'write' buffer */
843 pw = prep_write_buffer(popt);
850 err = _read_write(hdev, pw, NULL, popt->count + popt->ncmd, popt->lsb);
860 perform_readwrite(int hdev, struct spi_options *popt)
867 pw = prep_write_buffer(popt);
868 icount = popt->count + popt->ncmd; /* assign after fn call */
875 pr = malloc(icount + 1);
884 err = _read_write(hdev, pw, pr, icount, popt->lsb);
887 err = _do_data_output(pr, popt);
899 verbose_dump_buffer(void *pbuf, int icount, int lsb)
902 int ictr, ictr2, idx;
904 fputs(" | 0 1 2 3 4 5 6 7 8 9 A B C D E F "
907 for (ictr = 0; ictr < icount; ictr += 16) {
908 fprintf(stderr, " %6x | ", ictr & 0xfffff0);
910 for (ictr2 = 0; ictr2 < 16; ictr2++) {
914 ch = ((uint8_t *) pbuf)[idx];
917 ch = reversebits[ch];
919 fprintf(stderr, "%02hhx ", ch);
928 for (ictr2 = 0; ictr2 < 16; ictr2++) {
932 ch = ((uint8_t *) pbuf)[idx];
935 ch = reversebits[ch];
937 if (ch < ' ' || ch > 127)
940 fprintf(stderr, "%c", ch);
942 else if (idx < icount) {
951 fputs(" |\n", stderr);