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 __FBSDID("$FreeBSD$");
31 #include <sys/types.h>
32 #include <sys/ioccom.h>
33 #include <sys/spigenio.h>
34 #include <sys/sysctl.h>
47 #define DEFAULT_DEVICE_NAME "/dev/spigen0.0"
49 #define DEFAULT_BUFFER_SIZE 8192
53 #define DIR_READWRITE 2
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
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
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) */
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);
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
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
131 fputs(getprogname(), stderr);
132 fputs(" - communicate on SPI bus with slave devices\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"
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"
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"
161 main(int argc, char *argv[], char *envp[] __unused)
163 struct spi_options opt;
164 int err, ch, hdev, finfo, fdir;
166 char dev_name[PATH_MAX * 2 + 5];
186 while (!err && (ch = getopt(argc, argv, "f:d:m:s:c:C:AbLvih")) != -1) {
189 if (optarg[0] == 'r') {
190 if (optarg[1] == 'w' && optarg[2] == 0) {
191 fdir = DIR_READWRITE;
193 else if (optarg[1] == 0) {
197 else if (optarg[0] == 'w' && optarg[1] == 0) {
206 if (!optarg[0]) { /* unlikely */
207 fputs("error - missing device name\n", stderr);
211 if (optarg[0] == '/')
212 strlcpy(dev_name, optarg,
215 snprintf(dev_name, sizeof(dev_name),
221 opt.mode = (int)strtol(optarg, &pstr, 10);
223 if (!pstr || *pstr || opt.mode < 0 || opt.mode > 3) {
224 fprintf(stderr, "Invalid mode specified: %s\n",
231 opt.speed = (int)strtol(optarg, &pstr, 10);
233 if (!pstr || *pstr || opt.speed < 0) {
234 fprintf(stderr, "Invalid speed specified: %s\n",
241 opt.count = (int)strtol(optarg, &pstr, 10);
243 if (!pstr || *pstr) {
244 fprintf(stderr, "Invalid count specified: %s\n",
251 if(opt.pcmd) /* specified more than once */
254 /* get malloc'd buffer or error */
255 if (interpret_command_bytes(optarg, &opt))
294 (fdir == DIR_NONE && !finfo && opt.mode == -1 && opt.speed == -1 && opt.count == 0)) {
296 * if any of the direction, mode, speed, or count not specified,
304 if ((opt.count != 0 || opt.ncmd != 0) && fdir == DIR_NONE) {
306 * count was specified, but direction was not. default is
310 * this includes a negative count, which implies write from
316 fdir = DIR_READWRITE;
319 if (opt.count < 0 && fdir != DIR_READWRITE && fdir != DIR_WRITE) {
320 fprintf(stderr, "Invalid length %d when not writing data\n",
329 if (!dev_name[0]) /* no device name specified */
330 strlcpy(dev_name, DEFAULT_DEVICE_NAME, sizeof(dev_name));
332 hdev = open(dev_name, O_RDWR);
335 fprintf(stderr, "Error - unable to open '%s', errno=%d\n",
342 err = get_info(hdev, dev_name);
346 /* check and assign mode, speed */
348 if (opt.mode != -1) {
349 err = set_mode(hdev, &opt);
355 if (opt.speed != -1) {
356 err = set_speed(hdev, &opt);
362 /* do data transfer */
364 if (fdir == DIR_READ) {
365 err = perform_read(hdev, &opt);
367 else if (fdir == DIR_WRITE) {
368 err = perform_write(hdev, &opt);
370 else if (fdir == DIR_READWRITE) {
371 err = perform_readwrite(hdev, &opt);
385 interpret_command_bytes(const char *parg, struct spi_options *popt)
387 int ch, ch2, ctr, cbcmd, err;
393 cbcmd = DEFAULT_BUFFER_SIZE; /* initial cmd buffer size */
394 popt->pcmd = (uint8_t *)malloc(cbcmd);
405 while (*ppos && *ppos <= ' ') {
406 ppos++; /* skip (optional) leading white space */
410 break; /* I am done */
412 ch = hexval(*(ppos++));
413 if (ch < 0 || !*ppos) { /* must be valid pair of hex characters */
418 ch2 = hexval(*(ppos++));
424 ch = (ch * 16 + ch2) & 0xff; /* convert to byte */
426 if (ctr >= cbcmd) { /* need re-alloc buffer? (unlikely) */
427 cbcmd += 8192; /* increase by additional 8k */
428 ptemp = realloc(popt->pcmd, cbcmd);
433 "Not enough memory to interpret command bytes, errno=%d\n",
438 popt->pcmd = (uint8_t *)ptemp;
439 pcur = popt->pcmd + ctr;
443 *pcur = reversebits[ch];
451 popt->ncmd = ctr; /* record num bytes in '-C' argument */
455 /* at this point popt->pcmd is NULL or a valid pointer */
461 get_info(int hdev, const char *dev_name)
463 uint32_t fmode, fspeed;
465 char temp_buf[PATH_MAX], cpath[PATH_MAX];
467 if (!realpath(dev_name, cpath)) /* get canonical name for info purposes */
468 strlcpy(cpath, temp_buf, sizeof(cpath)); /* this shouldn't happen */
470 err = ioctl(hdev, SPIGENIOC_GET_SPI_MODE, &fmode);
473 err = ioctl(hdev, SPIGENIOC_GET_CLOCK_SPEED, &fspeed);
479 "Device speed: %d\n",
480 cpath, fmode, fspeed);//, max_cmd, max_data, temp_buf);
483 fprintf(stderr, "Unable to query info (err=%d), errno=%d\n",
490 set_mode(int hdev, struct spi_options *popt)
492 uint32_t fmode = popt->mode;
494 if (popt->mode < 0) /* use default? */
497 return ioctl(hdev, SPIGENIOC_SET_SPI_MODE, &fmode);
501 set_speed(int hdev, struct spi_options *popt)
503 uint32_t clock_speed = popt->speed;
508 return ioctl(hdev, SPIGENIOC_SET_CLOCK_SPEED, &clock_speed);
514 if (c >= '0' && c <= '9') {
516 } else if (c >= 'A' && c <= 'F') {
518 } else if (c >= 'a' && c <= 'f') {
525 prep_write_buffer(struct spi_options *popt)
527 int ch, ch2, ch3, ncmd, lsb, err;
528 uint8_t *pdata, *pdat2;
529 size_t cbdata, cbread;
532 ncmd = popt->ncmd; /* num command bytes (can be zero) */
534 if (ncmd == 0 && popt->count == 0)
535 return NULL; /* always since it's an error if it happens
538 if (popt->count < 0) {
539 cbdata = DEFAULT_BUFFER_SIZE;
542 cbdata = popt->count;
545 lsb = popt->lsb; /* non-zero if LSB order; else MSB */
547 pdata = malloc(cbdata + ncmd + 1);
555 if (popt->pcmd && ncmd > 0) {
556 memcpy(pdata, popt->pcmd, ncmd); /* copy command bytes */
557 pdat2 = pdata + ncmd;
560 pdat2 = pdata; /* no prepended command data */
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
567 * If the specified length is negative, I do 'a', else 'b'
570 while (!err && cbread < cbdata && (ch = fgetc(stdin)) != EOF) {
572 /* skip consecutive white space */
575 if ((ch = fgetc(stdin)) == EOF)
585 "Invalid input character '%c'\n", ch);
596 goto invalid_character;
602 if (err || ch == EOF)
606 /* for LSB, flip the bits - otherwise, just copy the value */
608 pdat2[cbread] = reversebits[ch];
610 pdat2[cbread] = (uint8_t) ch;
612 cbread++; /* increment num bytes read so far */
615 /* if it was an error, not an EOF, that ended the I/O, return NULL */
617 if (err || ferror(stdin)) {
622 if (popt->verbose > 0) {
623 const char *sz_bytes;
626 sz_bytes = "bytes"; /* correct plurality of 'byte|bytes' */
631 fprintf(stderr, "ASCII input of %zd %s\n", cbread,
634 fprintf(stderr, "Binary input of %zd %s\n", cbread,
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.
642 if (popt->count < 0) {
643 popt->count = cbread;
646 * for everything else, fill the rest of the read buffer with '0'
647 * bytes, as per the standard practice for SPI
650 while (cbread < cbdata)
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
661 if (popt->verbose > 0 && popt->count + popt->ncmd) {
662 if ((popt->count + popt->ncmd) == 1)
667 fprintf(stderr, "Writing %d %s to SPI device\n",
668 popt->count + popt->ncmd, szbytes);
670 verbose_dump_buffer(pdata, popt->count + popt->ncmd, lsb);
677 _read_write(int hdev, void *bufw, void *bufr, int cbrw, int lsb)
680 struct spigen_transfer spi;
688 memcpy(bufr, bufw, cbrw); /* transaction uses bufr for
691 bzero(&spi, sizeof(spi)); /* zero structure first */
693 /* spigen code seems to suggest there must be at least 1 command byte */
695 spi.st_command.iov_base = bufr;
696 spi.st_command.iov_len = cbrw;
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
705 err = ioctl(hdev, SPIGENIOC_TRANSFER, &spi) < 0 ? -1 : 0;
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]];
716 fprintf(stderr, "Error performing SPI transaction, errno=%d\n",
723 _do_data_output(void *pr, struct spi_options *popt)
725 int err, idx, icount;
726 const char *sz_bytes, *sz_byte2;
729 pbuf = (uint8_t *)pr + popt->ncmd; /* only the data we want */
730 icount = popt->count;
734 return -1; /* should not but could happen */
738 sz_bytes = "bytes"; /* correct plurality of 'byte|bytes' */
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,
753 err = (int)fwrite(pbuf, 1, icount, stdout) != icount;
755 else if (icount > 0) {
756 if (popt->verbose > 0)
757 fprintf(stderr, "ASCII output of %d %s\n", icount,
761 for (idx = 0; !err && idx < icount; idx++) {
764 * not the first time, insert separating space
766 err = fputc(' ', stdout) == EOF;
770 err = fprintf(stdout, "%02hhx", pbuf[idx]) < 0;
774 err = fputc('\n', stdout) == EOF;
777 /* verbose text out on stderr */
780 fprintf(stderr, "Error writing to stdout, errno=%d\n", errno);
781 else if (popt->verbose > 0 && icount) {
783 "%d command %s and %d data %s read from SPI device\n",
784 popt->ncmd, sz_byte2, icount, sz_bytes);
786 /* verbose output will show the command bytes as well */
787 verbose_dump_buffer(pr, icount + popt->ncmd, popt->lsb);
794 perform_read(int hdev, struct spi_options *popt)
800 icount = popt->count + popt->ncmd;
802 /* prep write buffer filled with 0 bytes */
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);
816 pr = malloc(icount + 1);
825 err = _read_write(hdev, pw, pr, icount, popt->lsb);
827 if (!err && popt->count > 0)
828 err = _do_data_output(pr, popt);
839 perform_write(int hdev, struct spi_options *popt)
844 /* read data from cmd buf and stdin and write to 'write' buffer */
846 pw = prep_write_buffer(popt);
853 err = _read_write(hdev, pw, NULL, popt->count + popt->ncmd, popt->lsb);
863 perform_readwrite(int hdev, struct spi_options *popt)
870 pw = prep_write_buffer(popt);
871 icount = popt->count + popt->ncmd; /* assign after fn call */
878 pr = malloc(icount + 1);
887 err = _read_write(hdev, pw, pr, icount, popt->lsb);
890 err = _do_data_output(pr, popt);
902 verbose_dump_buffer(void *pbuf, int icount, int lsb)
905 int ictr, ictr2, idx;
907 fputs(" | 0 1 2 3 4 5 6 7 8 9 A B C D E F "
910 for (ictr = 0; ictr < icount; ictr += 16) {
911 fprintf(stderr, " %6x | ", ictr & 0xfffff0);
913 for (ictr2 = 0; ictr2 < 16; ictr2++) {
917 ch = ((uint8_t *) pbuf)[idx];
920 ch = reversebits[ch];
922 fprintf(stderr, "%02hhx ", ch);
931 for (ictr2 = 0; ictr2 < 16; ictr2++) {
935 ch = ((uint8_t *) pbuf)[idx];
938 ch = reversebits[ch];
940 if (ch < ' ' || ch > 127)
943 fprintf(stderr, "%c", ch);
945 else if (idx < icount) {
954 fputs(" |\n", stderr);