Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F177569679
D15029.1794764753.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
24 KB
Referenced Files
None
Subscribers
None
D15029.1794764753.diff
View Options
Index: usr.sbin/spi/Makefile
===================================================================
--- /dev/null
+++ usr.sbin/spi/Makefile
@@ -0,0 +1,10 @@
+# spi utility - author: Bob Frazier, S.F.T. Inc. (mrp3.com)
+# $FreeBSD:
+
+#.include <src.opts.mk>
+
+PROG= spi
+
+MAN8= spi.8
+
+.include <bsd.prog.mk>
Index: usr.sbin/spi/spi.8
===================================================================
--- /dev/null
+++ usr.sbin/spi/spi.8
@@ -0,0 +1,111 @@
+.Dd "14 March 2018"
+.Dt spi 8
+.Os
+.SH NAME
+.Nm spi
+.Nd communicate on SPI bus with slave devices
+
+.Sh SYNOPSIS
+.Nm
+.Op Fl f Ar device
+.Op Fl d Ar r|w|rw
+.Op Fl m Ar mode
+.Op Fl s Ar max-speed
+.Op Fl c Ar count
+.Op Fl A
+.Op Fl b
+.Op Fl L
+.Op Fl v
+.Nm
+.Op Fl i
+.Op Fl f Ar device
+.Op Fl v
+.Nm
+.Op Fl h
+
+.Sh DESCRIPTION
+The \f[B]spi\fP utility can be used to perform raw data transfers (read, write,
+or simultaneous read/write) with devices on the SPI bus, via the spigen device.
+
+An spigen device is associated with a specific \'chip select\' (cs) pin on the
+spibus, and therefore needs to be specified. If no spigen device name is
+specified on the command line, \f[B]spi\fP assumes spigen0.
+
+For more information on the spigen device, see spigen(4).
+
+The options are as follows:
+.Bl -tag -width ".Fl d Ar direction"
+.It Fl A
+ASCII mode - read and write data is input and output as 2-digit hexadecimal
+values, separaed by white space, such as 00 01 02 etc.. When combined with
+the '-b' flag, the data on stdin remains a sequence of ASCII hexadecimal
+byte values, but the output reverts to binary mode.
+.It Fl b
+Binary (output) mode. Only has an effect when '-A' has been specified. Reverts
+the output back to binary (rather than ASCII), while leaving the input format
+as-is. Use in combination with '-A' to allow using something like 'echo' to
+pass hexadecimal values to the SPI device, but output the received data on
+stdout as binary.
+.It Fl c Ar count
+The total number of bytes to transfer as a decimal integer. If a write or a
+read/write transaction is being performed, and fewer than this number of bytes
+are read in from stdin, the remaining bytes will be sent with a value of '0'.
+If the length can be determined from the input file size, you can use a 'count'
+value of '-1' to base the transfer on the input file's size.
+.It Fl d Ar r|w|rw
+Transfer direction: Use 'r' for read, 'w' for write, and 'rw' for simultaneous
+read and write.
+.It Fl f Ar device
+SPI device to use (default is /dev/spigen0).
+.It Fl h
+Print help text to stderr, explaining the command line options.
+.It Fl i
+Displays information about the SPI device to stderr. Whenever this flag is
+specified, no data is read or written, and the mode and speed are not changed.
+.It Fl L
+LSB bit order. The default is MSB, i.e. the highest order bit is transmitted
+first. Specifying -L caused the LSB to be transmitted and read first.
+.It Fl m Ar 0 - 3
+SPI mode, 0 through 3. This defines the clock phase and timing with respect to
+reading and writing data, as per the SPI specification.
+.It Fl s Ar speed
+Specify the maximum speed, in Hz, for the SPI clock. If the device has been
+configured for a lower speed, or cannot transmit at the specified speed, the lower
+value will be used.
+.It Fl v
+Verbose mode. Diagnostics and information are written to stderr. You can
+specify '-v' more than once to increase verbosity.
+.El
+.Sh EXAMPLES
+Here are a few examples of using the spi utility:
+.Bl -bullet
+.It
+Get information about the default SPI device
+.Pp
+spi -i
+.It
+Set the maximum clock to 200Khz and the mode to 3 on spigen1, but do not
+transmit nor receive any data
+.Pp
+spi -f spigen1 -s 200000 -m 3
+.It
+Transmit a byte value of 5, and receive 2 bytes, displaying their values as
+2-byte ASCII hexadecimal, with mode 2, and a maximum of a 500khz clock
+.Pp
+echo "5" | spi -A -d rw -m 2 -s 500000 -c 2
+.It
+Send a binary file, and output the SPI result through 'od' as hexadecimal bytes,
+using the current maximum clock and mode.
+.Pp
+spi -d rw -c -1 <input_file.bin | od -t x1
+.It
+Send 2 bytes of data, receive a total of 4 bytes, and output the SPI result as
+binary data, piped through 'od', displaying it as two hexadecimal short integers.
+.Pp
+echo "00 01" | spi -A -b -d rw -c 4 | od -t x2
+.El
+
+.Sh SEE ALSO
+spigen(4)
+
+
Index: usr.sbin/spi/spi.c
===================================================================
--- /dev/null
+++ usr.sbin/spi/spi.c
@@ -0,0 +1,895 @@
+/*-
+ *
+ * COPYRIGHT: Copyright (c) 2018 by S.F.T. Inc. - All rights reserved
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+/* use indent infile outfile -nce -di8 -i8 -lp */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <memory.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/ioccom.h>
+#include <sys/spigenio.h>
+#include <sys/sysctl.h>
+
+#define DEFAULT_DEVICE_NAME "spigen0"
+
+#define DIR_READ 0
+#define DIR_WRITE 1
+#define DIR_READWRITE 2
+#define DIR_NONE -1
+#define DEV_NAME_OFFSET 5
+
+struct spi_options {
+ int mode; /* mode (0,1,2,3, -1 == use default) */
+ int speed; /* speed (in Hz, -1 == use default) */
+ int count; /* count (0 through 'n' bytes, negative for
+ * stdin length) */
+ int binary; /* non-zero for binary output or zero for
+ * ASCII output when ASCII != 0 */
+ int ASCII; /* zero for binary input and output.
+ * non-zero for ASCII input, 'binary'
+ * determines output */
+ int lsb; /* non-zero for LSB order (default order is
+ * MSB) */
+ int verbose; /* non-zero for verbosity */
+ int max_cmd_len; /* max command length from driver sysctl */
+ int max_data_len; /* max data length from driver sysctl */
+};
+
+int get_sysctl_byname(const char *dev_name, const char *var_name, void *pbuf, int bufsize);
+int get_info(int hdev, const char *dev_name);
+int set_mode(int hdev, struct spi_options *popt);
+int set_speed(int hdev, struct spi_options *popt);
+int perform_read(int hdev, struct spi_options *popt);
+int perform_write(int hdev, struct spi_options *popt);
+int perform_readwrite(int hdev, struct spi_options *popt);
+void verbose_dump_buffer(void *pBuf, int icount, int lsb);
+
+/* LSB array - aLSB[n] is the LSB value of n as an MSB */
+static uint8_t aLSB[256] = {
+ 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
+ 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
+ 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
+ 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
+ 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
+ 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
+ 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
+ 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
+ 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
+ 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
+ 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
+ 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
+ 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
+ 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
+ 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
+ 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
+ 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
+ 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
+ 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
+ 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
+ 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
+ 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
+ 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
+ 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
+ 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
+ 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
+ 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
+ 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
+ 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
+ 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
+ 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
+ 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
+};
+
+
+void
+usage(void)
+{
+ fputs(getprogname(), stderr);
+ fputs(" - communicate on SPI bus with slave devices\n"
+ "Usage:\n"
+ " spi [-f device] [-d r|w|rw] [-m mode] [-s max-speed] [-c count]\n"
+ " [-A] [-b] [-L] [-v]\n"
+ " spi -i [-f device] [-v]\n"
+ " spi -h\n"
+ " where\n"
+ " -f specifies the device (default is spigen0)\n"
+ " -d specifies the operation (r, w, or rw; default is rw)\n"
+ " -m specifies the mode (0, 1, 2, or 3)\n"
+ " -s specifies the maximum speed (default is 0, device default)\n"
+ " -c specifies the number of bytes to transfer (default 0, i.e. none)\n"
+ " A negative value uses the length of the input data\n"
+ " -L specifies 'LSB' order on the SPI bus (default is MSB)\n"
+ " -i query information about the device\n"
+ " -A uses ASCII for input/output as 2-digit hex values\n"
+ " -b Override output format as binary (only valid with '-A')\n"
+ " -v verbose output\n"
+ " -h prints this message\n"
+ "\n"
+ "NOTE: setting the mode and/or speed is 'sticky'. Subsequent transactions\n"
+ " on that device will, by default, use the previously set values.\n"
+ "\n",
+ stderr);
+}
+
+int
+main(int argc, char *argv[], char *envp[])
+{
+ int err, ch, hdev, fInfo, fDir;
+ struct spi_options opt;
+ char dev_name[PATH_MAX * 2 + 5];
+ char temp_buf[PATH_MAX];
+
+
+ fInfo = 0;
+ fDir = DIR_NONE;
+
+ hdev = -1;
+ err = 0;
+
+ /* copy the well-known /dev/ path into 'dev_name' */
+
+ strcpy(dev_name, "/dev/"); /* dev_name[DEV_NAME_OFFSET] is where
+ * I write the dev name later */
+
+ opt.mode = -1;
+ opt.speed = -1;
+ opt.count = 0;
+ opt.ASCII = 0;
+ opt.binary = 0;
+ opt.lsb = 0;
+ opt.verbose = 0;
+
+ while (!err && (ch = getopt(argc, argv, "f:d:m:s:c:AbLvih")) != -1) {
+ switch (ch) {
+ case 'd':
+ if (optarg[0] == 'r') {
+ if (optarg[1] == 'w' && optarg[2] == 0) {
+ fDir = DIR_READWRITE;
+ }
+ else if (optarg[1] == 0) {
+ fDir = DIR_READ;
+ }
+ }
+ else if (optarg[0] == 'w' && optarg[1] == '0') {
+ fDir = DIR_WRITE;
+ }
+ else {
+ err = 1;
+ }
+ break;
+
+ case 'f':
+ if (!optarg[0]) { /* unlikely */
+ fputs("error - missing device name\n", stderr);
+ err = 1;
+ }
+ else {
+ strncat(&(dev_name[DEV_NAME_OFFSET]), optarg, sizeof(dev_name) - DEV_NAME_OFFSET - 1);
+ }
+ break;
+
+ case 'm':
+ opt.mode = atoi(optarg);
+
+ if (opt.mode < 0 || opt.mode > 3) {
+ fprintf(stderr, "Invalid mode specified: %d\n", opt.mode);
+ err = 1;
+ }
+ break;
+
+ case 's':
+ opt.speed = atoi(optarg);
+
+ if (opt.speed < 0) {
+ fprintf(stderr, "Invalid speed specified: %d\n", opt.speed);
+ err = 1;
+ }
+ break;
+
+ case 'c':
+ opt.count = atoi(optarg);
+ break;
+
+ case 'A':
+ opt.ASCII = 1;
+ break;
+
+ case 'b':
+ opt.binary = 1;
+ break;
+
+ case 'L':
+ opt.lsb = 1;
+ break;
+
+ case 'v':
+ opt.verbose++;
+ break;
+
+ case 'i':
+ fInfo = 1;
+ break;
+
+ default:
+ err = 1;
+ /* flows thruogh to next one */
+ case 'h':
+ usage();
+ goto the_end;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (err ||
+ (fDir == DIR_NONE && !fInfo && opt.mode == -1 && opt.speed == -1 && opt.count == 0)) {
+ /*
+ * if neither the direction, mode, speed, nor count not
+ * specified, print usage
+ */
+
+ usage();
+ goto the_end;
+ }
+
+ if (opt.count != 0 && fDir == DIR_NONE) {
+ /*
+ * count was specified, but direction was not. default is
+ * read/write
+ */
+ /*
+ * this includes a negative count, which implies write from
+ * stdin
+ */
+
+ fDir = DIR_READWRITE;
+ }
+
+ if (opt.count < 0 && fDir != DIR_READWRITE && fDir != DIR_WRITE) {
+ fprintf(stderr, "Invalid length %d when not writing data\n", opt.count);
+
+ err = 1;
+ usage();
+ goto the_end;
+ }
+
+
+ if (!dev_name[5]) /* no device name specified */
+ strncat(dev_name, DEFAULT_DEVICE_NAME, sizeof(dev_name) - 1);
+
+
+ hdev = open(dev_name, O_RDWR);
+
+ if (hdev == -1) {
+ fprintf(stderr, "Error - unable to open '%s', errno=%d\n", dev_name, errno);
+ err = 1;
+
+ goto the_end;
+ }
+
+ if (fInfo) {
+ err = get_info(hdev, dev_name);
+ goto the_end;
+ }
+
+
+ /* get max command,data length from sysctl */
+
+ err = get_sysctl_byname(dev_name, "command_length_max", &(opt.max_cmd_len), sizeof(opt.max_cmd_len));
+ if (err)
+ goto the_end;
+
+ err = get_sysctl_byname(dev_name, "data_length_max", &(opt.max_data_len), sizeof(opt.max_data_len));
+
+ if (err)
+ goto the_end;
+
+
+ /*
+ * if what I'm doing exceeds the sysctl max data/cmd length, it's an
+ * error [for now]
+ */
+
+ if (opt.count > opt.max_cmd_len || opt.count > opt.max_data_len) {
+ fprintf(stderr,
+ "Error, data count %d exceeds maximum command/data length %d\n",
+ opt.count,
+ (opt.max_cmd_len < opt.max_data_len ?
+ opt.max_cmd_len : opt.max_data_len));
+
+ err = 1;
+ goto the_end;
+ }
+
+ /* check and assign mode, speed */
+
+ opt.max_data_len = atoi(temp_buf);
+
+ if (opt.mode != -1) {
+ err = set_mode(hdev, &opt);
+
+ if (err)
+ goto the_end;
+ }
+
+ if (opt.speed != -1) {
+ err = set_speed(hdev, &opt);
+
+ if (err)
+ goto the_end;
+ }
+
+ /* do data transfer */
+
+ if (fDir == DIR_READ) {
+ err = perform_read(hdev, &opt);
+ }
+ else if (fDir == DIR_WRITE) {
+ err = perform_write(hdev, &opt);
+ }
+ else if (fDir == DIR_READWRITE) {
+ err = perform_readwrite(hdev, &opt);
+ }
+
+the_end:
+
+ if (hdev != -1) {
+ close(hdev);
+ }
+
+ return err;
+}
+
+int
+get_sysctl_byname(const char *dev_name, const char *var_name, void *pbuf, int bufsize)
+{
+ size_t cbbuf;
+ int err;
+ char the_var[PATH_MAX];
+
+
+ if (!pbuf || bufsize <= 0)
+ return -1; /* simple param check */
+
+ strncpy(the_var, "dev.spigen0.", sizeof(the_var) - 1); /* default */
+
+ cbbuf = bufsize;
+
+ if (!strncmp(&(dev_name[DEV_NAME_OFFSET]), "spigen", 6)) {
+ snprintf(the_var, sizeof(the_var) - 1, "dev.spigen.%d.", atoi(&(dev_name[DEV_NAME_OFFSET + 6])));
+
+ strncat(the_var, var_name, sizeof(the_var) - 1);
+
+ err = sysctlbyname(the_var, pbuf, &cbbuf, NULL, 0);
+
+ if (err)
+ fprintf(stderr, "Unable to get sysctl %s - err=%d, errno=%d\n",
+ the_var, err, errno);
+ else if (cbbuf < (bufsize - 1)) { /* assume it is a
+ * string? */
+ ((char *)pbuf)[cbbuf] = 0;
+ }
+ }
+ else {
+ fprintf(stderr, "Unrecognized device - '%s'\n", &(dev_name[DEV_NAME_OFFSET]));
+ err = 1;
+ }
+
+ return err;
+}
+
+int
+get_info(int hdev, const char *dev_name)
+{
+ uint32_t dwMode, dwSpeed, max_cmd, max_data;
+ int err;
+ char temp_buf[PATH_MAX];
+
+
+ err = ioctl(hdev, SPIGENIOC_GET_SPI_MODE, &dwMode);
+
+ if (err == 0)
+ err = ioctl(hdev, SPIGENIOC_GET_CLOCK_SPEED, &dwSpeed);
+
+ if (err == 0)
+ err = get_sysctl_byname(dev_name, "command_length_max", &max_cmd, sizeof(max_cmd));
+
+ if (err == 0)
+ err = get_sysctl_byname(dev_name, "data_length_max", &max_data, sizeof(&max_data));
+
+ if (err == 0)
+ err = get_sysctl_byname(dev_name, "%location", temp_buf, sizeof(temp_buf));
+
+ if (err == 0) {
+ fprintf(stderr,
+ "Device name: %s\n"
+ "Device mode: %d\n"
+ "Device speed: %d\n"
+ "Max cmd len: %d\n"
+ "Max data len: %d\n"
+ "Chip Select: %s\n",
+ dev_name, dwMode, dwSpeed, max_cmd, max_data, temp_buf);
+ }
+ else
+ fprintf(stderr, "Unable to query info (err=%d), errno=%d\n", err, errno);
+
+
+ return err;
+}
+
+int
+set_mode(int hdev, struct spi_options *popt)
+{
+ uint32_t dwMode = popt->mode;
+
+ if (popt->mode < 0) /* use default? */
+ return 0;
+
+ return ioctl(hdev, SPIGENIOC_SET_SPI_MODE, &dwMode);
+}
+
+int
+set_speed(int hdev, struct spi_options *popt)
+{
+ uint32_t dwClockSpeed = popt->speed;
+
+ if (popt->speed < 0)
+ return 0;
+
+ return ioctl(hdev, SPIGENIOC_SET_CLOCK_SPEED, &dwClockSpeed);
+}
+
+int
+hexval(char c)
+{
+ if (c >= '0' && c <= '9') {
+ return c - '0';
+ }
+ else if (c >= 'A' && c <= 'F') {
+ return c - 'A' + 10;
+ }
+ else if (c >= 'a' && c <= 'f') {
+ return c - 'a' + 10;
+ }
+ return -1;
+}
+
+void *
+prep_write_buffer(struct spi_options *popt)
+{
+ int ch , ch2, ch3, err;
+ uint8_t *pData;
+ size_t cbData, cbRead;
+
+
+ if (popt->count == 0)
+ return NULL; /* always since it's an error if it happens
+ * now */
+
+ if (popt->count < 0) {
+ /* read data until EOF - malloc maximum possible buffer size */
+
+ cbData = popt->max_cmd_len + popt->max_data_len;
+
+ if (!cbData) { /* we can't handle this */
+ fprintf(stderr, "Unable to alloc input buffer; max size not known\n");
+ return NULL;
+ }
+ }
+ else {
+ cbData = popt->count;
+ }
+
+ pData = malloc(cbData + 1);
+ cbRead = 0;
+
+ err = 0;
+
+ if (!pData)
+ return NULL;
+
+ /*
+ * read up to 'cbData' bytes. If I get an EOF, do one of two things:
+ * a) change the data count to match how many bytes I read in b) fill
+ * the rest of the input buffer with zeros
+ *
+ * If the specified length is negative, I do 'a', else 'b'
+ */
+
+ while (!err && cbRead < cbData && (ch = fgetc(stdin)) != EOF) {
+ if (popt->ASCII) {
+ /* skip consecutive white space */
+
+ while (ch <= ' ') {
+ if ((ch = fgetc(stdin)) == EOF)
+ break;
+ }
+
+ if (ch != EOF) {
+ ch2 = hexval(ch);
+
+ if (ch2 < 0) {
+ invalid_character:
+ fprintf(stderr, "Invalid input character '%c'\n", ch);
+ err = 1;
+ break;
+ }
+
+ ch = fgetc(stdin);
+
+ if (ch != EOF) {
+ ch3 = hexval(ch);
+
+ if (ch3 < 0)
+ goto invalid_character;
+
+ ch = ch2 * 16 + ch3;
+ }
+ }
+
+ if (err || ch == EOF)
+ break;
+ }
+
+ /* for LSB, flip the bits - otherwise, just copy the value */
+ if (popt->lsb)
+ pData[cbRead++] = aLSB[ch];
+ else
+ pData[cbRead++] = (uint8_t) ch;
+ }
+
+ /* if it was an error, not an EOF, that ended the I/O, return NULL */
+
+ if (err || ferror(stdin)) {
+ free(pData);
+ return NULL;
+ }
+
+ if (popt->verbose > 0) {
+ const char *szB;
+
+ if (cbRead != 1)
+ szB = "bytes"; /* correct plurality of 'byte|bytes' */
+ else
+ szB = "byte";
+
+ if (popt->ASCII)
+ fprintf(stderr, "ASCII input of %d %s\n", cbRead, szB);
+ else
+ fprintf(stderr, "Binary input of %d %s\n", cbRead, szB);
+ }
+
+ /* if opt.count is negative, copy actual byte count to opt.count */
+ if (popt->count < 0) {
+ popt->count = cbRead;
+ }
+ /*
+ * for everything else, fill the rest of the read buffer with '0'
+ * bytes
+ */
+ else {
+ while (cbRead < cbData)
+ pData[cbRead++] = 0;
+ }
+
+ /* popt->count bytes will be sent and read from the SPI */
+ /* must use 'popt->count at this point in the code */
+
+ if (popt->verbose > 0 && popt->count) {
+ fprintf(stderr, "Writing %d bytes to SPI device\n", popt->count);
+ verbose_dump_buffer(pData, popt->count, popt->lsb);
+ }
+
+ return pData;
+}
+
+int
+_read_write(int hdev, void *bufW, void *bufR, int cbRW, int lsb)
+{
+ int err, ctr;
+ struct spigen_transfer spi;
+
+ if (!cbRW)
+ return 0;
+
+ if (!bufR)
+ bufR = bufW;
+ else
+ memcpy(bufR, bufW, cbRW); /* transaction uses bufR for
+ * both R and W */
+
+ bzero(&spi, sizeof(spi)); /* zero structure first */
+
+ /* spigen code seems to suggest there must be at least 1 command byte */
+
+ spi.st_command.iov_base = bufR;
+ spi.st_command.iov_len = 1;
+
+ /* the rest of the bytes are data bytes */
+ if (cbRW > 1) {
+ spi.st_data.iov_base = bufR + 1;
+ spi.st_data.iov_len = cbRW - 1;
+ }
+
+ err = ioctl(hdev, SPIGENIOC_TRANSFER, &spi) < 0 ? -1 : 0;
+
+ if (!err && lsb) {
+ /* flip the bits for 'lsb' mode */
+ for (ctr = 0; ctr < cbRW; ctr++) {
+ ((uint8_t *) bufR)[ctr] = aLSB[((uint8_t *) bufR)[ctr]];
+ }
+ }
+
+ if (err)
+ fprintf(stderr, "Error performing SPI transaction, errno=%d\n", errno);
+
+ return err;
+}
+
+int
+_do_data_output(void *pR, struct spi_options *popt)
+{
+ int err, ictr, ictr2, index, icount;
+ const char *szB;
+
+ icount = popt->count;
+ err = 0;
+
+ if (icount <= 0) {
+ return -1; /* should not happen */
+ }
+
+ if (icount != 1)
+ szB = "bytes"; /* correct plurality of 'byte|bytes' for
+ * verbose message */
+ else
+ szB = "byte";
+
+ /* binary on stdout */
+ if (popt->binary || !popt->ASCII) {
+ if (popt->verbose > 0)
+ fprintf(stderr, "Binary output of %d %s\n", icount, szB);
+
+ err = fwrite(pR, 1, icount, stdout) != icount;
+ }
+ else if (icount > 0) {
+ if (popt->verbose > 0)
+ fprintf(stderr, "ASCII output of %d %s\n", icount, szB);
+
+ /* ASCII output */
+ for (index = 0; !err && index < icount; index++) {
+ if (index) {
+ /*
+ * not the first time, insert separating
+ * space
+ */
+ err = fputc(' ', stdout) == EOF;
+ }
+
+ if (!err)
+ err = fprintf(stdout, "%02hhx", ((uint8_t *) pR)[index]) < 0;
+ }
+
+ if (!err)
+ err = fputc('\n', stdout) == EOF;
+ }
+
+ /* verbose text out on stderr */
+
+ if (err)
+ fprintf(stderr, "Error writing to stdout, errno=%d\n", errno);
+ else if (popt->verbose > 0 && icount) {
+ const char *szB;
+
+ if (icount != 1)
+ szB = "bytes"; /* correct plurality of 'byte|bytes' */
+ else
+ szB = "byte";
+
+ fprintf(stderr, "%d %s read from SPI device\n", icount, szB);
+
+ verbose_dump_buffer(pR, icount, popt->lsb);
+ }
+
+ return err;
+}
+
+int
+perform_read(int hdev, struct spi_options *popt)
+{
+ int err;
+ void *pR, *pW;
+
+ pR = NULL;
+
+ /* prep write buffer filled with 0 bytes */
+ pW = malloc(popt->count);
+
+ if (!pW) {
+ err = -1;
+ goto the_end;
+ }
+
+ bzero(pW, popt->count);
+
+ pR = malloc(popt->count);
+
+ if (!pR) {
+ err = -2;
+ goto the_end;
+ }
+
+ bzero(pR, popt->count);
+
+ err = _read_write(hdev, pW, pR, popt->count, popt->lsb);
+
+ if (!err)
+ err = _do_data_output(pR, popt);
+
+the_end:
+
+ if (pR)
+ free(pR);
+ if (pW)
+ free(pW);
+
+ return err;
+}
+
+int
+perform_write(int hdev, struct spi_options *popt)
+{
+ int err;
+ void *pW;
+
+ /* read data from stdin and write to 'write' buffer */
+
+ pW = prep_write_buffer(popt);
+
+ if (!pW) {
+ err = -1;
+ goto the_end;
+ }
+
+ err = _read_write(hdev, pW, NULL, popt->count, popt->lsb);
+
+the_end:
+
+ if (pW)
+ free(pW);
+
+ return err;
+}
+
+int
+perform_readwrite(int hdev, struct spi_options *popt)
+{
+ int err;
+ void *pR, *pW;
+
+ pR = NULL;
+
+ pW = prep_write_buffer(popt);
+
+ if (!pW) {
+ err = -1;
+ goto the_end;
+ }
+
+ pR = malloc(popt->count);
+
+ if (!pR) {
+ err = -2;
+ goto the_end;
+ }
+
+ bzero(pR, popt->count);
+
+ err = _read_write(hdev, pW, pR, popt->count, popt->lsb);
+
+ if (!err)
+ err = _do_data_output(pR, popt);
+
+the_end:
+
+ if (pR)
+ free(pR);
+ if (pW)
+ free(pW);
+
+ return err;
+}
+
+
+void
+verbose_dump_buffer(void *pBuf, int icount, int lsb)
+{
+ uint8_t ch;
+ int ictr, ictr2, index;
+
+ fputs(" | 0 1 2 3 4 5 6 7 8 9 A B C D E F "
+ "| |\n", stderr);
+
+ for (ictr = 0; ictr < icount; ictr += 16) {
+ fprintf(stderr, " %6x | ", ictr & 0xfffff0);
+
+ for (ictr2 = 0; ictr2 < 16; ictr2++) {
+ index = ictr + ictr2;
+
+ if (index < icount) {
+ ch = ((uint8_t *) pBuf)[index];
+
+ if (lsb)
+ ch = aLSB[ch];
+
+ fprintf(stderr, "%02hhx ", ch);
+ }
+ else {
+ fputs(" ", stderr);
+ }
+ }
+
+ fputs("| ", stderr);
+
+ for (ictr2 = 0; ictr2 < 16; ictr2++) {
+ index = ictr + ictr2;
+
+ if (index < icount) {
+ ch = ((uint8_t *) pBuf)[index];
+
+ if (lsb)
+ ch = aLSB[ch];
+
+ if (ch < ' ' || ch > 127)
+ goto out_of_range;
+
+ fprintf(stderr, "%c", ch);
+ }
+ else if (index < icount) {
+ out_of_range:
+ fputc('.', stderr);
+ }
+ else {
+ fputc(' ', stderr);
+ }
+ }
+
+ fputs(" |", stderr);
+ }
+
+ fputc('\n', stderr);
+
+}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Nov 15, 5:45 PM (13 h, 47 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
41746348
Default Alt Text
D15029.1794764753.diff (24 KB)
Attached To
Mode
D15029: new utility usr.sbin/spi
Attached
Detach File
Event Timeline