166660095SIan Lepore /*-
266660095SIan Lepore * SPDX-License-Identifier: BSD-2-Clause
366660095SIan Lepore *
466660095SIan Lepore * Copyright (c) 2018 S.F.T. Inc.
566660095SIan Lepore *
666660095SIan Lepore * Redistribution and use in source and binary forms, with or without
766660095SIan Lepore * modification, are permitted provided that the following conditions
866660095SIan Lepore * are met:
966660095SIan Lepore * 1. Redistributions of source code must retain the above copyright
1066660095SIan Lepore * notice, this list of conditions and the following disclaimer.
1166660095SIan Lepore * 2. Redistributions in binary form must reproduce the above copyright
1266660095SIan Lepore * notice, this list of conditions and the following disclaimer in the
1366660095SIan Lepore * documentation and/or other materials provided with the distribution.
1466660095SIan Lepore *
1566660095SIan Lepore * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1666660095SIan Lepore * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1766660095SIan Lepore * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1866660095SIan Lepore * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1966660095SIan Lepore * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2066660095SIan Lepore * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2166660095SIan Lepore * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2266660095SIan Lepore * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2366660095SIan Lepore * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2466660095SIan Lepore * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2566660095SIan Lepore * SUCH DAMAGE.
2666660095SIan Lepore */
2766660095SIan Lepore
2866660095SIan Lepore #include <sys/types.h>
2966660095SIan Lepore #include <sys/ioccom.h>
3066660095SIan Lepore #include <sys/spigenio.h>
3166660095SIan Lepore #include <sys/sysctl.h>
3266660095SIan Lepore
3366660095SIan Lepore #include <errno.h>
3466660095SIan Lepore #include <fcntl.h>
3566660095SIan Lepore #include <inttypes.h>
3666660095SIan Lepore #include <limits.h>
3766660095SIan Lepore #include <memory.h>
3866660095SIan Lepore #include <stdio.h>
3966660095SIan Lepore #include <stdlib.h>
4066660095SIan Lepore #include <string.h>
4166660095SIan Lepore #include <string.h>
4266660095SIan Lepore #include <unistd.h>
4366660095SIan Lepore
4466660095SIan Lepore #define DEFAULT_DEVICE_NAME "/dev/spigen0.0"
4566660095SIan Lepore
4666660095SIan Lepore #define DEFAULT_BUFFER_SIZE 8192
4766660095SIan Lepore
4866660095SIan Lepore #define DIR_READ 0
4966660095SIan Lepore #define DIR_WRITE 1
5066660095SIan Lepore #define DIR_READWRITE 2
5166660095SIan Lepore #define DIR_NONE -1
5266660095SIan Lepore
5366660095SIan Lepore struct spi_options {
5466660095SIan Lepore int mode; /* mode (0,1,2,3, -1 == use default) */
5566660095SIan Lepore int speed; /* speed (in Hz, -1 == use default) */
5666660095SIan Lepore int count; /* count (0 through 'n' bytes, negative for
5766660095SIan Lepore * stdin length) */
5866660095SIan Lepore int binary; /* non-zero for binary output or zero for
5966660095SIan Lepore * ASCII output when ASCII != 0 */
6066660095SIan Lepore int ASCII; /* zero for binary input and output.
6166660095SIan Lepore * non-zero for ASCII input, 'binary'
6266660095SIan Lepore * determines output */
6366660095SIan Lepore int lsb; /* non-zero for LSB order (default order is
6466660095SIan Lepore * MSB) */
6566660095SIan Lepore int verbose; /* non-zero for verbosity */
6666660095SIan Lepore int ncmd; /* bytes to skip for incoming data */
6766660095SIan Lepore uint8_t *pcmd; /* command data (NULL if none) */
6866660095SIan Lepore };
6966660095SIan Lepore
7066660095SIan Lepore static void usage(void);
7166660095SIan Lepore static int interpret_command_bytes(const char *parg, struct spi_options *popt);
7266660095SIan Lepore static void * prep_write_buffer(struct spi_options *popt);
7366660095SIan Lepore static int _read_write(int hdev, void *bufw, void *bufr, int cbrw, int lsb);
7466660095SIan Lepore static int _do_data_output(void *pr, struct spi_options *popt);
7566660095SIan Lepore static int get_info(int hdev, const char *dev_name);
7666660095SIan Lepore static int set_mode(int hdev, struct spi_options *popt);
7766660095SIan Lepore static int set_speed(int hdev, struct spi_options *popt);
7866660095SIan Lepore static int hexval(char c);
7966660095SIan Lepore static int perform_read(int hdev, struct spi_options *popt);
8066660095SIan Lepore static int perform_write(int hdev, struct spi_options *popt);
8166660095SIan Lepore static int perform_readwrite(int hdev, struct spi_options *popt);
8266660095SIan Lepore static void verbose_dump_buffer(void *pbuf, int icount, int lsb);
8366660095SIan Lepore
8466660095SIan Lepore /*
8566660095SIan Lepore * LSB array - reversebits[n] is the LSB value of n as an MSB. Use this array
8666660095SIan Lepore * to obtain a reversed bit pattern of the index value when bits must
8766660095SIan Lepore * be sent/received in an LSB order vs the default MSB
8866660095SIan Lepore */
8966660095SIan Lepore static uint8_t reversebits[256] = {
9066660095SIan Lepore 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
9166660095SIan Lepore 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
9266660095SIan Lepore 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
9366660095SIan Lepore 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
9466660095SIan Lepore 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
9566660095SIan Lepore 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
9666660095SIan Lepore 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
9766660095SIan Lepore 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
9866660095SIan Lepore 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
9966660095SIan Lepore 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
10066660095SIan Lepore 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
10166660095SIan Lepore 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
10266660095SIan Lepore 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
10366660095SIan Lepore 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
10466660095SIan Lepore 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
10566660095SIan Lepore 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
10666660095SIan Lepore 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
10766660095SIan Lepore 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
10866660095SIan Lepore 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
10966660095SIan Lepore 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
11066660095SIan Lepore 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
11166660095SIan Lepore 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
11266660095SIan Lepore 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
11366660095SIan Lepore 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
11466660095SIan Lepore 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
11566660095SIan Lepore 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
11666660095SIan Lepore 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
11766660095SIan Lepore 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
11866660095SIan Lepore 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
11966660095SIan Lepore 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
12066660095SIan Lepore 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
12166660095SIan Lepore 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
12266660095SIan Lepore };
12366660095SIan Lepore
12466660095SIan Lepore
12566660095SIan Lepore static void
usage(void)12666660095SIan Lepore usage(void)
12766660095SIan Lepore {
12866660095SIan Lepore fputs(getprogname(), stderr);
12966660095SIan Lepore fputs(" - communicate on SPI bus with slave devices\n"
13066660095SIan Lepore "Usage:\n"
13166660095SIan Lepore " spi [-f device] [-d r|w|rw] [-m mode] [-s max-speed] [-c count]\n"
13266660095SIan Lepore " [-C \"command bytes\"] [-A] [-b] [-L] [-v]\n"
13366660095SIan Lepore " spi -i [-f device] [-v]\n"
13466660095SIan Lepore " spi -h\n"
13566660095SIan Lepore " where\n"
13666660095SIan Lepore " -f specifies the device (default is spigen0.0)\n"
13766660095SIan Lepore " -d specifies the operation (r, w, or rw; default is rw)\n"
13866660095SIan Lepore " -m specifies the mode (0, 1, 2, or 3)\n"
13966660095SIan Lepore " -s specifies the maximum speed (default is 0, device default)\n"
14066660095SIan Lepore " -c specifies the number of data bytes to transfer (default 0, i.e. none)\n"
14166660095SIan Lepore " A negative value uses the length of the input data\n"
14266660095SIan Lepore " -C specifies 'command bytes' to be sent, as 2 byte hexadecimal values\n"
14366660095SIan Lepore " (these should be quoted, separated by optional white space)\n"
14466660095SIan Lepore " -L specifies 'LSB' order on the SPI bus (default is MSB)\n"
14566660095SIan Lepore " -i query information about the device\n"
14666660095SIan Lepore " -A uses ASCII for input/output as 2-digit hex values\n"
14766660095SIan Lepore " -b Override output format as binary (only valid with '-A')\n"
14866660095SIan Lepore " -v verbose output\n"
14966660095SIan Lepore " -h prints this message\n"
15066660095SIan Lepore "\n"
15166660095SIan Lepore "NOTE: setting the mode and/or speed is 'sticky'. Subsequent transactions\n"
15266660095SIan Lepore " on that device will, by default, use the previously set values.\n"
15366660095SIan Lepore "\n",
15466660095SIan Lepore stderr);
15566660095SIan Lepore }
15666660095SIan Lepore
15766660095SIan Lepore int
main(int argc,char * argv[],char * envp[]__unused)15866660095SIan Lepore main(int argc, char *argv[], char *envp[] __unused)
15966660095SIan Lepore {
16066660095SIan Lepore struct spi_options opt;
16166660095SIan Lepore int err, ch, hdev, finfo, fdir;
16266660095SIan Lepore char *pstr;
16366660095SIan Lepore char dev_name[PATH_MAX * 2 + 5];
16466660095SIan Lepore
16566660095SIan Lepore finfo = 0;
16666660095SIan Lepore fdir = DIR_NONE;
16766660095SIan Lepore
16866660095SIan Lepore hdev = -1;
16966660095SIan Lepore err = 0;
17066660095SIan Lepore
17166660095SIan Lepore dev_name[0] = 0;
17266660095SIan Lepore
17366660095SIan Lepore opt.mode = -1;
17466660095SIan Lepore opt.speed = -1;
17566660095SIan Lepore opt.count = 0;
17666660095SIan Lepore opt.ASCII = 0;
17766660095SIan Lepore opt.binary = 0;
17866660095SIan Lepore opt.lsb = 0;
17966660095SIan Lepore opt.verbose = 0;
18066660095SIan Lepore opt.ncmd = 0;
18166660095SIan Lepore opt.pcmd = NULL;
18266660095SIan Lepore
18366660095SIan Lepore while (!err && (ch = getopt(argc, argv, "f:d:m:s:c:C:AbLvih")) != -1) {
18466660095SIan Lepore switch (ch) {
18566660095SIan Lepore case 'd':
18666660095SIan Lepore if (optarg[0] == 'r') {
18766660095SIan Lepore if (optarg[1] == 'w' && optarg[2] == 0) {
18866660095SIan Lepore fdir = DIR_READWRITE;
18966660095SIan Lepore }
19066660095SIan Lepore else if (optarg[1] == 0) {
19166660095SIan Lepore fdir = DIR_READ;
19266660095SIan Lepore }
19366660095SIan Lepore }
19466660095SIan Lepore else if (optarg[0] == 'w' && optarg[1] == 0) {
19566660095SIan Lepore fdir = DIR_WRITE;
19666660095SIan Lepore }
19766660095SIan Lepore else {
19866660095SIan Lepore err = 1;
19966660095SIan Lepore }
20066660095SIan Lepore break;
20166660095SIan Lepore
20266660095SIan Lepore case 'f':
20366660095SIan Lepore if (!optarg[0]) { /* unlikely */
20466660095SIan Lepore fputs("error - missing device name\n", stderr);
20566660095SIan Lepore err = 1;
20666660095SIan Lepore }
20766660095SIan Lepore else {
20866660095SIan Lepore if (optarg[0] == '/')
20966660095SIan Lepore strlcpy(dev_name, optarg,
21066660095SIan Lepore sizeof(dev_name));
21166660095SIan Lepore else
21266660095SIan Lepore snprintf(dev_name, sizeof(dev_name),
21366660095SIan Lepore "/dev/%s", optarg);
21466660095SIan Lepore }
21566660095SIan Lepore break;
21666660095SIan Lepore
21766660095SIan Lepore case 'm':
21866660095SIan Lepore opt.mode = (int)strtol(optarg, &pstr, 10);
21966660095SIan Lepore
22066660095SIan Lepore if (!pstr || *pstr || opt.mode < 0 || opt.mode > 3) {
22166660095SIan Lepore fprintf(stderr, "Invalid mode specified: %s\n",
22266660095SIan Lepore optarg);
22366660095SIan Lepore err = 1;
22466660095SIan Lepore }
22566660095SIan Lepore break;
22666660095SIan Lepore
22766660095SIan Lepore case 's':
22866660095SIan Lepore opt.speed = (int)strtol(optarg, &pstr, 10);
22966660095SIan Lepore
23066660095SIan Lepore if (!pstr || *pstr || opt.speed < 0) {
23166660095SIan Lepore fprintf(stderr, "Invalid speed specified: %s\n",
23266660095SIan Lepore optarg);
23366660095SIan Lepore err = 1;
23466660095SIan Lepore }
23566660095SIan Lepore break;
23666660095SIan Lepore
23766660095SIan Lepore case 'c':
23866660095SIan Lepore opt.count = (int)strtol(optarg, &pstr, 10);
23966660095SIan Lepore
24066660095SIan Lepore if (!pstr || *pstr) {
24166660095SIan Lepore fprintf(stderr, "Invalid count specified: %s\n",
24266660095SIan Lepore optarg);
24366660095SIan Lepore err = 1;
24466660095SIan Lepore }
24566660095SIan Lepore break;
24666660095SIan Lepore
24766660095SIan Lepore case 'C':
24866660095SIan Lepore if(opt.pcmd) /* specified more than once */
24966660095SIan Lepore err = 1;
25066660095SIan Lepore else {
25166660095SIan Lepore /* get malloc'd buffer or error */
25266660095SIan Lepore if (interpret_command_bytes(optarg, &opt))
25366660095SIan Lepore err = 1;
25466660095SIan Lepore }
25566660095SIan Lepore
25666660095SIan Lepore break;
25766660095SIan Lepore
25866660095SIan Lepore case 'A':
25966660095SIan Lepore opt.ASCII = 1;
26066660095SIan Lepore break;
26166660095SIan Lepore
26266660095SIan Lepore case 'b':
26366660095SIan Lepore opt.binary = 1;
26466660095SIan Lepore break;
26566660095SIan Lepore
26666660095SIan Lepore case 'L':
26766660095SIan Lepore opt.lsb = 1;
26866660095SIan Lepore break;
26966660095SIan Lepore
27066660095SIan Lepore case 'v':
27166660095SIan Lepore opt.verbose++;
27266660095SIan Lepore break;
27366660095SIan Lepore
27466660095SIan Lepore case 'i':
27566660095SIan Lepore finfo = 1;
27666660095SIan Lepore break;
27766660095SIan Lepore
27866660095SIan Lepore default:
27966660095SIan Lepore err = 1;
28066660095SIan Lepore /* FALLTHROUGH */
28166660095SIan Lepore case 'h':
28266660095SIan Lepore usage();
28366660095SIan Lepore goto the_end;
28466660095SIan Lepore }
28566660095SIan Lepore }
28666660095SIan Lepore
28766660095SIan Lepore argc -= optind;
28866660095SIan Lepore argv += optind;
28966660095SIan Lepore
29066660095SIan Lepore if (err ||
29166660095SIan Lepore (fdir == DIR_NONE && !finfo && opt.mode == -1 && opt.speed == -1 && opt.count == 0)) {
29266660095SIan Lepore /*
29366660095SIan Lepore * if any of the direction, mode, speed, or count not specified,
29466660095SIan Lepore * print usage
29566660095SIan Lepore */
29666660095SIan Lepore
29766660095SIan Lepore usage();
29866660095SIan Lepore goto the_end;
29966660095SIan Lepore }
30066660095SIan Lepore
30166660095SIan Lepore if ((opt.count != 0 || opt.ncmd != 0) && fdir == DIR_NONE) {
30266660095SIan Lepore /*
30366660095SIan Lepore * count was specified, but direction was not. default is
30466660095SIan Lepore * read/write
30566660095SIan Lepore */
30666660095SIan Lepore /*
30766660095SIan Lepore * this includes a negative count, which implies write from
30866660095SIan Lepore * stdin
30966660095SIan Lepore */
31066660095SIan Lepore if (opt.count == 0)
31166660095SIan Lepore fdir = DIR_WRITE;
31266660095SIan Lepore else
31366660095SIan Lepore fdir = DIR_READWRITE;
31466660095SIan Lepore }
31566660095SIan Lepore
31666660095SIan Lepore if (opt.count < 0 && fdir != DIR_READWRITE && fdir != DIR_WRITE) {
31766660095SIan Lepore fprintf(stderr, "Invalid length %d when not writing data\n",
31866660095SIan Lepore opt.count);
31966660095SIan Lepore
32066660095SIan Lepore err = 1;
32166660095SIan Lepore usage();
32266660095SIan Lepore goto the_end;
32366660095SIan Lepore }
32466660095SIan Lepore
32566660095SIan Lepore
32666660095SIan Lepore if (!dev_name[0]) /* no device name specified */
32766660095SIan Lepore strlcpy(dev_name, DEFAULT_DEVICE_NAME, sizeof(dev_name));
32866660095SIan Lepore
32966660095SIan Lepore hdev = open(dev_name, O_RDWR);
33066660095SIan Lepore
33166660095SIan Lepore if (hdev == -1) {
33266660095SIan Lepore fprintf(stderr, "Error - unable to open '%s', errno=%d\n",
33366660095SIan Lepore dev_name, errno);
33466660095SIan Lepore err = 1;
33566660095SIan Lepore goto the_end;
33666660095SIan Lepore }
33766660095SIan Lepore
33866660095SIan Lepore if (finfo) {
33966660095SIan Lepore err = get_info(hdev, dev_name);
34066660095SIan Lepore goto the_end;
34166660095SIan Lepore }
34266660095SIan Lepore
34366660095SIan Lepore /* check and assign mode, speed */
34466660095SIan Lepore
34566660095SIan Lepore if (opt.mode != -1) {
34666660095SIan Lepore err = set_mode(hdev, &opt);
34766660095SIan Lepore
34866660095SIan Lepore if (err)
34966660095SIan Lepore goto the_end;
35066660095SIan Lepore }
35166660095SIan Lepore
35266660095SIan Lepore if (opt.speed != -1) {
35366660095SIan Lepore err = set_speed(hdev, &opt);
35466660095SIan Lepore
35566660095SIan Lepore if (err)
35666660095SIan Lepore goto the_end;
35766660095SIan Lepore }
35866660095SIan Lepore
35966660095SIan Lepore /* do data transfer */
36066660095SIan Lepore
36166660095SIan Lepore if (fdir == DIR_READ) {
36266660095SIan Lepore err = perform_read(hdev, &opt);
36366660095SIan Lepore }
36466660095SIan Lepore else if (fdir == DIR_WRITE) {
36566660095SIan Lepore err = perform_write(hdev, &opt);
36666660095SIan Lepore }
36766660095SIan Lepore else if (fdir == DIR_READWRITE) {
36866660095SIan Lepore err = perform_readwrite(hdev, &opt);
36966660095SIan Lepore }
37066660095SIan Lepore
37166660095SIan Lepore the_end:
37266660095SIan Lepore
37366660095SIan Lepore if (hdev != -1)
37466660095SIan Lepore close(hdev);
37566660095SIan Lepore
37666660095SIan Lepore free(opt.pcmd);
37766660095SIan Lepore
37866660095SIan Lepore return (err);
37966660095SIan Lepore }
38066660095SIan Lepore
38166660095SIan Lepore static int
interpret_command_bytes(const char * parg,struct spi_options * popt)38266660095SIan Lepore interpret_command_bytes(const char *parg, struct spi_options *popt)
38366660095SIan Lepore {
38466660095SIan Lepore int ch, ch2, ctr, cbcmd, err;
38566660095SIan Lepore const char *ppos;
38666660095SIan Lepore void *ptemp;
38766660095SIan Lepore uint8_t *pcur;
38866660095SIan Lepore
38966660095SIan Lepore err = 0;
39066660095SIan Lepore cbcmd = DEFAULT_BUFFER_SIZE; /* initial cmd buffer size */
39166660095SIan Lepore popt->pcmd = (uint8_t *)malloc(cbcmd);
39266660095SIan Lepore
39366660095SIan Lepore if (!popt->pcmd)
39466660095SIan Lepore return 1;
39566660095SIan Lepore
39666660095SIan Lepore pcur = popt->pcmd;
39766660095SIan Lepore
39866660095SIan Lepore ctr = 0;
39966660095SIan Lepore ppos = parg;
40066660095SIan Lepore
40166660095SIan Lepore while (*ppos) {
40266660095SIan Lepore while (*ppos && *ppos <= ' ') {
40366660095SIan Lepore ppos++; /* skip (optional) leading white space */
40466660095SIan Lepore }
40566660095SIan Lepore
40666660095SIan Lepore if (!*ppos)
40766660095SIan Lepore break; /* I am done */
40866660095SIan Lepore
40966660095SIan Lepore ch = hexval(*(ppos++));
41066660095SIan Lepore if (ch < 0 || !*ppos) { /* must be valid pair of hex characters */
41166660095SIan Lepore err = 1;
41266660095SIan Lepore goto the_end;
41366660095SIan Lepore }
41466660095SIan Lepore
41566660095SIan Lepore ch2 = hexval(*(ppos++));
41666660095SIan Lepore if (ch2 < 0) {
41766660095SIan Lepore err = 1;
41866660095SIan Lepore goto the_end;
41966660095SIan Lepore }
42066660095SIan Lepore
42166660095SIan Lepore ch = (ch * 16 + ch2) & 0xff; /* convert to byte */
42266660095SIan Lepore
42366660095SIan Lepore if (ctr >= cbcmd) { /* need re-alloc buffer? (unlikely) */
42466660095SIan Lepore cbcmd += 8192; /* increase by additional 8k */
42566660095SIan Lepore ptemp = realloc(popt->pcmd, cbcmd);
42666660095SIan Lepore
42766660095SIan Lepore if (!ptemp) {
42866660095SIan Lepore err = 1;
42966660095SIan Lepore fprintf(stderr,
43066660095SIan Lepore "Not enough memory to interpret command bytes, errno=%d\n",
43166660095SIan Lepore errno);
43266660095SIan Lepore goto the_end;
43366660095SIan Lepore }
43466660095SIan Lepore
43566660095SIan Lepore popt->pcmd = (uint8_t *)ptemp;
43666660095SIan Lepore pcur = popt->pcmd + ctr;
43766660095SIan Lepore }
43866660095SIan Lepore
43966660095SIan Lepore if (popt->lsb)
44066660095SIan Lepore *pcur = reversebits[ch];
44166660095SIan Lepore else
44266660095SIan Lepore *pcur = (uint8_t)ch;
44366660095SIan Lepore
44466660095SIan Lepore pcur++;
44566660095SIan Lepore ctr++;
44666660095SIan Lepore }
44766660095SIan Lepore
44866660095SIan Lepore popt->ncmd = ctr; /* record num bytes in '-C' argument */
44966660095SIan Lepore
45066660095SIan Lepore the_end:
45166660095SIan Lepore
45266660095SIan Lepore /* at this point popt->pcmd is NULL or a valid pointer */
45366660095SIan Lepore
45466660095SIan Lepore return err;
45566660095SIan Lepore }
45666660095SIan Lepore
45766660095SIan Lepore static int
get_info(int hdev,const char * dev_name)45866660095SIan Lepore get_info(int hdev, const char *dev_name)
45966660095SIan Lepore {
46066660095SIan Lepore uint32_t fmode, fspeed;
46166660095SIan Lepore int err;
46266660095SIan Lepore char temp_buf[PATH_MAX], cpath[PATH_MAX];
46366660095SIan Lepore
46466660095SIan Lepore if (!realpath(dev_name, cpath)) /* get canonical name for info purposes */
46566660095SIan Lepore strlcpy(cpath, temp_buf, sizeof(cpath)); /* this shouldn't happen */
46666660095SIan Lepore
46766660095SIan Lepore err = ioctl(hdev, SPIGENIOC_GET_SPI_MODE, &fmode);
46866660095SIan Lepore
46966660095SIan Lepore if (err == 0)
47066660095SIan Lepore err = ioctl(hdev, SPIGENIOC_GET_CLOCK_SPEED, &fspeed);
47166660095SIan Lepore
47266660095SIan Lepore if (err == 0) {
47366660095SIan Lepore fprintf(stderr,
47466660095SIan Lepore "Device name: %s\n"
47566660095SIan Lepore "Device mode: %d\n"
47666660095SIan Lepore "Device speed: %d\n",
47766660095SIan Lepore cpath, fmode, fspeed);//, max_cmd, max_data, temp_buf);
47866660095SIan Lepore }
47966660095SIan Lepore else
48066660095SIan Lepore fprintf(stderr, "Unable to query info (err=%d), errno=%d\n",
48166660095SIan Lepore err, errno);
48266660095SIan Lepore
48366660095SIan Lepore return err;
48466660095SIan Lepore }
48566660095SIan Lepore
48666660095SIan Lepore static int
set_mode(int hdev,struct spi_options * popt)48766660095SIan Lepore set_mode(int hdev, struct spi_options *popt)
48866660095SIan Lepore {
48966660095SIan Lepore uint32_t fmode = popt->mode;
49066660095SIan Lepore
49166660095SIan Lepore if (popt->mode < 0) /* use default? */
49266660095SIan Lepore return 0;
49366660095SIan Lepore
49466660095SIan Lepore return ioctl(hdev, SPIGENIOC_SET_SPI_MODE, &fmode);
49566660095SIan Lepore }
49666660095SIan Lepore
49766660095SIan Lepore static int
set_speed(int hdev,struct spi_options * popt)49866660095SIan Lepore set_speed(int hdev, struct spi_options *popt)
49966660095SIan Lepore {
50066660095SIan Lepore uint32_t clock_speed = popt->speed;
50166660095SIan Lepore
50266660095SIan Lepore if (popt->speed < 0)
50366660095SIan Lepore return 0;
50466660095SIan Lepore
50566660095SIan Lepore return ioctl(hdev, SPIGENIOC_SET_CLOCK_SPEED, &clock_speed);
50666660095SIan Lepore }
50766660095SIan Lepore
50866660095SIan Lepore static int
hexval(char c)50966660095SIan Lepore hexval(char c)
51066660095SIan Lepore {
51166660095SIan Lepore if (c >= '0' && c <= '9') {
51266660095SIan Lepore return c - '0';
51366660095SIan Lepore } else if (c >= 'A' && c <= 'F') {
51466660095SIan Lepore return c - 'A' + 10;
51566660095SIan Lepore } else if (c >= 'a' && c <= 'f') {
51666660095SIan Lepore return c - 'a' + 10;
51766660095SIan Lepore }
51866660095SIan Lepore return -1;
51966660095SIan Lepore }
52066660095SIan Lepore
52166660095SIan Lepore static void *
prep_write_buffer(struct spi_options * popt)52266660095SIan Lepore prep_write_buffer(struct spi_options *popt)
52366660095SIan Lepore {
52466660095SIan Lepore int ch, ch2, ch3, ncmd, lsb, err;
52566660095SIan Lepore uint8_t *pdata, *pdat2;
52666660095SIan Lepore size_t cbdata, cbread;
52766660095SIan Lepore const char *szbytes;
52866660095SIan Lepore
52966660095SIan Lepore ncmd = popt->ncmd; /* num command bytes (can be zero) */
53066660095SIan Lepore
53166660095SIan Lepore if (ncmd == 0 && popt->count == 0)
53266660095SIan Lepore return NULL; /* always since it's an error if it happens
53366660095SIan Lepore * now */
53466660095SIan Lepore
53566660095SIan Lepore if (popt->count < 0) {
53666660095SIan Lepore cbdata = DEFAULT_BUFFER_SIZE;
53766660095SIan Lepore }
53866660095SIan Lepore else {
53966660095SIan Lepore cbdata = popt->count;
54066660095SIan Lepore }
54166660095SIan Lepore
54266660095SIan Lepore lsb = popt->lsb; /* non-zero if LSB order; else MSB */
54366660095SIan Lepore
54466660095SIan Lepore pdata = malloc(cbdata + ncmd + 1);
54566660095SIan Lepore cbread = 0;
54666660095SIan Lepore
54766660095SIan Lepore err = 0;
54866660095SIan Lepore
54966660095SIan Lepore if (!pdata)
55066660095SIan Lepore return NULL;
55166660095SIan Lepore
55266660095SIan Lepore if (popt->pcmd && ncmd > 0) {
55366660095SIan Lepore memcpy(pdata, popt->pcmd, ncmd); /* copy command bytes */
55466660095SIan Lepore pdat2 = pdata + ncmd;
55566660095SIan Lepore }
55666660095SIan Lepore else
55766660095SIan Lepore pdat2 = pdata; /* no prepended command data */
55866660095SIan Lepore
55966660095SIan Lepore /*
56066660095SIan Lepore * read up to 'cbdata' bytes. If I get an EOF, do one of two things:
56166660095SIan Lepore * a) change the data count to match how many bytes I read in b) fill
56266660095SIan Lepore * the rest of the input buffer with zeros
56366660095SIan Lepore *
56466660095SIan Lepore * If the specified length is negative, I do 'a', else 'b'
56566660095SIan Lepore */
56666660095SIan Lepore
56766660095SIan Lepore while (!err && cbread < cbdata && (ch = fgetc(stdin)) != EOF) {
56866660095SIan Lepore if (popt->ASCII) {
56966660095SIan Lepore /* skip consecutive white space */
57066660095SIan Lepore
57166660095SIan Lepore while (ch <= ' ') {
57266660095SIan Lepore if ((ch = fgetc(stdin)) == EOF)
57366660095SIan Lepore break;
57466660095SIan Lepore }
57566660095SIan Lepore
57666660095SIan Lepore if (ch != EOF) {
57766660095SIan Lepore ch2 = hexval(ch);
57866660095SIan Lepore
57966660095SIan Lepore if (ch2 < 0) {
58066660095SIan Lepore invalid_character:
58166660095SIan Lepore fprintf(stderr,
58266660095SIan Lepore "Invalid input character '%c'\n", ch);
58366660095SIan Lepore err = 1;
58466660095SIan Lepore break;
58566660095SIan Lepore }
58666660095SIan Lepore
58766660095SIan Lepore ch = fgetc(stdin);
58866660095SIan Lepore
58966660095SIan Lepore if (ch != EOF) {
59066660095SIan Lepore ch3 = hexval(ch);
59166660095SIan Lepore
59266660095SIan Lepore if (ch3 < 0)
59366660095SIan Lepore goto invalid_character;
59466660095SIan Lepore
59566660095SIan Lepore ch = ch2 * 16 + ch3;
59666660095SIan Lepore }
59766660095SIan Lepore }
59866660095SIan Lepore
59966660095SIan Lepore if (err || ch == EOF)
60066660095SIan Lepore break;
60166660095SIan Lepore }
60266660095SIan Lepore
60366660095SIan Lepore /* for LSB, flip the bits - otherwise, just copy the value */
60466660095SIan Lepore if (lsb)
60566660095SIan Lepore pdat2[cbread] = reversebits[ch];
60666660095SIan Lepore else
60766660095SIan Lepore pdat2[cbread] = (uint8_t) ch;
60866660095SIan Lepore
60966660095SIan Lepore cbread++; /* increment num bytes read so far */
61066660095SIan Lepore }
61166660095SIan Lepore
61266660095SIan Lepore /* if it was an error, not an EOF, that ended the I/O, return NULL */
61366660095SIan Lepore
61466660095SIan Lepore if (err || ferror(stdin)) {
61566660095SIan Lepore free(pdata);
61666660095SIan Lepore return NULL;
61766660095SIan Lepore }
61866660095SIan Lepore
61966660095SIan Lepore if (popt->verbose > 0) {
62066660095SIan Lepore const char *sz_bytes;
62166660095SIan Lepore
62266660095SIan Lepore if (cbread != 1)
62366660095SIan Lepore sz_bytes = "bytes"; /* correct plurality of 'byte|bytes' */
62466660095SIan Lepore else
62566660095SIan Lepore sz_bytes = "byte";
62666660095SIan Lepore
62766660095SIan Lepore if (popt->ASCII)
62866660095SIan Lepore fprintf(stderr, "ASCII input of %zd %s\n", cbread,
62966660095SIan Lepore sz_bytes);
63066660095SIan Lepore else
63166660095SIan Lepore fprintf(stderr, "Binary input of %zd %s\n", cbread,
63266660095SIan Lepore sz_bytes);
63366660095SIan Lepore }
63466660095SIan Lepore
63566660095SIan Lepore /*
63666660095SIan Lepore * if opt.count is negative, copy actual byte count to opt.count which does
63766660095SIan Lepore * not include any of the 'command' bytes that are being sent. Can be zero.
63866660095SIan Lepore */
63966660095SIan Lepore if (popt->count < 0) {
64066660095SIan Lepore popt->count = cbread;
64166660095SIan Lepore }
64266660095SIan Lepore /*
64366660095SIan Lepore * for everything else, fill the rest of the read buffer with '0'
64466660095SIan Lepore * bytes, as per the standard practice for SPI
64566660095SIan Lepore */
64666660095SIan Lepore else {
64766660095SIan Lepore while (cbread < cbdata)
64866660095SIan Lepore pdat2[cbread++] = 0;
64966660095SIan Lepore }
65066660095SIan Lepore
65166660095SIan Lepore /*
65266660095SIan Lepore * popt->count bytes will be sent and read from the SPI, preceded by the
65366660095SIan Lepore * 'popt->ncmd' command bytes (if any).
65466660095SIan Lepore * So we must use 'popt->count' and 'popt->ncmd' from this point on in
65566660095SIan Lepore * the code.
65666660095SIan Lepore */
65766660095SIan Lepore
65866660095SIan Lepore if (popt->verbose > 0 && popt->count + popt->ncmd) {
65966660095SIan Lepore if ((popt->count + popt->ncmd) == 1)
66066660095SIan Lepore szbytes = "byte";
66166660095SIan Lepore else
66266660095SIan Lepore szbytes = "bytes";
66366660095SIan Lepore
66466660095SIan Lepore fprintf(stderr, "Writing %d %s to SPI device\n",
66566660095SIan Lepore popt->count + popt->ncmd, szbytes);
66666660095SIan Lepore
66766660095SIan Lepore verbose_dump_buffer(pdata, popt->count + popt->ncmd, lsb);
66866660095SIan Lepore }
66966660095SIan Lepore
67066660095SIan Lepore return pdata;
67166660095SIan Lepore }
67266660095SIan Lepore
67366660095SIan Lepore static int
_read_write(int hdev,void * bufw,void * bufr,int cbrw,int lsb)67466660095SIan Lepore _read_write(int hdev, void *bufw, void *bufr, int cbrw, int lsb)
67566660095SIan Lepore {
67666660095SIan Lepore int err, ctr;
67766660095SIan Lepore struct spigen_transfer spi;
67866660095SIan Lepore
67966660095SIan Lepore if (!cbrw)
68066660095SIan Lepore return 0;
68166660095SIan Lepore
68266660095SIan Lepore if (!bufr)
68366660095SIan Lepore bufr = bufw;
68466660095SIan Lepore else
68566660095SIan Lepore memcpy(bufr, bufw, cbrw); /* transaction uses bufr for
68666660095SIan Lepore * both R and W */
68766660095SIan Lepore
68866660095SIan Lepore bzero(&spi, sizeof(spi)); /* zero structure first */
68966660095SIan Lepore
69066660095SIan Lepore /* spigen code seems to suggest there must be at least 1 command byte */
69166660095SIan Lepore
69266660095SIan Lepore spi.st_command.iov_base = bufr;
69366660095SIan Lepore spi.st_command.iov_len = cbrw;
69466660095SIan Lepore
69566660095SIan Lepore /*
69666660095SIan Lepore * The remaining members for spi.st_data are zero - all bytes are
69766660095SIan Lepore * 'command' for this. The driver doesn't really do anything different
69866660095SIan Lepore * for 'command' vs 'data' and at least one command byte must be sent in
69966660095SIan Lepore * the transaction.
70066660095SIan Lepore */
70166660095SIan Lepore
70266660095SIan Lepore err = ioctl(hdev, SPIGENIOC_TRANSFER, &spi) < 0 ? -1 : 0;
70366660095SIan Lepore
70466660095SIan Lepore if (!err && lsb) {
70566660095SIan Lepore /* flip the bits for 'lsb' mode */
70666660095SIan Lepore for (ctr = 0; ctr < cbrw; ctr++) {
70766660095SIan Lepore ((uint8_t *) bufr)[ctr] =
70866660095SIan Lepore reversebits[((uint8_t *)bufr)[ctr]];
70966660095SIan Lepore }
71066660095SIan Lepore }
71166660095SIan Lepore
71266660095SIan Lepore if (err)
71366660095SIan Lepore fprintf(stderr, "Error performing SPI transaction, errno=%d\n",
71466660095SIan Lepore errno);
71566660095SIan Lepore
71666660095SIan Lepore return err;
71766660095SIan Lepore }
71866660095SIan Lepore
71966660095SIan Lepore static int
_do_data_output(void * pr,struct spi_options * popt)72066660095SIan Lepore _do_data_output(void *pr, struct spi_options *popt)
72166660095SIan Lepore {
722917d1846SIan Lepore int err, idx, icount;
72366660095SIan Lepore const char *sz_bytes, *sz_byte2;
72466660095SIan Lepore const uint8_t *pbuf;
72566660095SIan Lepore
72666660095SIan Lepore pbuf = (uint8_t *)pr + popt->ncmd; /* only the data we want */
72766660095SIan Lepore icount = popt->count;
72866660095SIan Lepore err = 0;
72966660095SIan Lepore
73066660095SIan Lepore if (icount <= 0) {
73166660095SIan Lepore return -1; /* should not but could happen */
73266660095SIan Lepore }
73366660095SIan Lepore
73466660095SIan Lepore if (icount != 1)
73566660095SIan Lepore sz_bytes = "bytes"; /* correct plurality of 'byte|bytes' */
73666660095SIan Lepore else
73766660095SIan Lepore sz_bytes = "byte";
73866660095SIan Lepore
73966660095SIan Lepore if (popt->ncmd != 1)
74066660095SIan Lepore sz_byte2 = "bytes";
74166660095SIan Lepore else
74266660095SIan Lepore sz_byte2 = "byte";
74366660095SIan Lepore
74466660095SIan Lepore /* binary on stdout */
74566660095SIan Lepore if (popt->binary || !popt->ASCII) {
74666660095SIan Lepore if (popt->verbose > 0)
74766660095SIan Lepore fprintf(stderr, "Binary output of %d %s\n", icount,
74866660095SIan Lepore sz_bytes);
74966660095SIan Lepore
75066660095SIan Lepore err = (int)fwrite(pbuf, 1, icount, stdout) != icount;
75166660095SIan Lepore }
75266660095SIan Lepore else if (icount > 0) {
75366660095SIan Lepore if (popt->verbose > 0)
75466660095SIan Lepore fprintf(stderr, "ASCII output of %d %s\n", icount,
75566660095SIan Lepore sz_bytes);
75666660095SIan Lepore
75766660095SIan Lepore /* ASCII output */
758917d1846SIan Lepore for (idx = 0; !err && idx < icount; idx++) {
759917d1846SIan Lepore if (idx) {
76066660095SIan Lepore /*
76166660095SIan Lepore * not the first time, insert separating space
76266660095SIan Lepore */
76366660095SIan Lepore err = fputc(' ', stdout) == EOF;
76466660095SIan Lepore }
76566660095SIan Lepore
76666660095SIan Lepore if (!err)
767917d1846SIan Lepore err = fprintf(stdout, "%02hhx", pbuf[idx]) < 0;
76866660095SIan Lepore }
76966660095SIan Lepore
77066660095SIan Lepore if (!err)
77166660095SIan Lepore err = fputc('\n', stdout) == EOF;
77266660095SIan Lepore }
77366660095SIan Lepore
77466660095SIan Lepore /* verbose text out on stderr */
77566660095SIan Lepore
77666660095SIan Lepore if (err)
77766660095SIan Lepore fprintf(stderr, "Error writing to stdout, errno=%d\n", errno);
77866660095SIan Lepore else if (popt->verbose > 0 && icount) {
77966660095SIan Lepore fprintf(stderr,
78066660095SIan Lepore "%d command %s and %d data %s read from SPI device\n",
78166660095SIan Lepore popt->ncmd, sz_byte2, icount, sz_bytes);
78266660095SIan Lepore
78366660095SIan Lepore /* verbose output will show the command bytes as well */
78466660095SIan Lepore verbose_dump_buffer(pr, icount + popt->ncmd, popt->lsb);
78566660095SIan Lepore }
78666660095SIan Lepore
78766660095SIan Lepore return err;
78866660095SIan Lepore }
78966660095SIan Lepore
79066660095SIan Lepore static int
perform_read(int hdev,struct spi_options * popt)79166660095SIan Lepore perform_read(int hdev, struct spi_options *popt)
79266660095SIan Lepore {
79366660095SIan Lepore int icount, err;
79466660095SIan Lepore void *pr, *pw;
79566660095SIan Lepore
79666660095SIan Lepore pr = NULL;
79766660095SIan Lepore icount = popt->count + popt->ncmd;
79866660095SIan Lepore
79966660095SIan Lepore /* prep write buffer filled with 0 bytes */
80066660095SIan Lepore pw = malloc(icount);
80166660095SIan Lepore
80266660095SIan Lepore if (!pw) {
80366660095SIan Lepore err = -1;
80466660095SIan Lepore goto the_end;
80566660095SIan Lepore }
80666660095SIan Lepore
80766660095SIan Lepore bzero(pw, icount);
80866660095SIan Lepore
80966660095SIan Lepore /* if I included a command sequence, copy bytes to the write buf */
81066660095SIan Lepore if (popt->pcmd && popt->ncmd > 0)
81166660095SIan Lepore memcpy(pw, popt->pcmd, popt->ncmd);
81266660095SIan Lepore
81366660095SIan Lepore pr = malloc(icount + 1);
81466660095SIan Lepore
81566660095SIan Lepore if (!pr) {
81666660095SIan Lepore err = -2;
81766660095SIan Lepore goto the_end;
81866660095SIan Lepore }
81966660095SIan Lepore
82066660095SIan Lepore bzero(pr, icount);
82166660095SIan Lepore
82266660095SIan Lepore err = _read_write(hdev, pw, pr, icount, popt->lsb);
82366660095SIan Lepore
82466660095SIan Lepore if (!err && popt->count > 0)
82566660095SIan Lepore err = _do_data_output(pr, popt);
82666660095SIan Lepore
82766660095SIan Lepore the_end:
82866660095SIan Lepore
82966660095SIan Lepore free(pr);
83066660095SIan Lepore free(pw);
83166660095SIan Lepore
83266660095SIan Lepore return err;
83366660095SIan Lepore }
83466660095SIan Lepore
83566660095SIan Lepore static int
perform_write(int hdev,struct spi_options * popt)83666660095SIan Lepore perform_write(int hdev, struct spi_options *popt)
83766660095SIan Lepore {
83866660095SIan Lepore int err;
83966660095SIan Lepore void *pw;
84066660095SIan Lepore
84166660095SIan Lepore /* read data from cmd buf and stdin and write to 'write' buffer */
84266660095SIan Lepore
84366660095SIan Lepore pw = prep_write_buffer(popt);
84466660095SIan Lepore
84566660095SIan Lepore if (!pw) {
84666660095SIan Lepore err = -1;
84766660095SIan Lepore goto the_end;
84866660095SIan Lepore }
84966660095SIan Lepore
85066660095SIan Lepore err = _read_write(hdev, pw, NULL, popt->count + popt->ncmd, popt->lsb);
85166660095SIan Lepore
85266660095SIan Lepore the_end:
85366660095SIan Lepore
85466660095SIan Lepore free(pw);
85566660095SIan Lepore
85666660095SIan Lepore return err;
85766660095SIan Lepore }
85866660095SIan Lepore
85966660095SIan Lepore static int
perform_readwrite(int hdev,struct spi_options * popt)86066660095SIan Lepore perform_readwrite(int hdev, struct spi_options *popt)
86166660095SIan Lepore {
86266660095SIan Lepore int icount, err;
86366660095SIan Lepore void *pr, *pw;
86466660095SIan Lepore
86566660095SIan Lepore pr = NULL;
86666660095SIan Lepore
86766660095SIan Lepore pw = prep_write_buffer(popt);
86866660095SIan Lepore icount = popt->count + popt->ncmd; /* assign after fn call */
86966660095SIan Lepore
87066660095SIan Lepore if (!pw) {
87166660095SIan Lepore err = -1;
87266660095SIan Lepore goto the_end;
87366660095SIan Lepore }
87466660095SIan Lepore
87566660095SIan Lepore pr = malloc(icount + 1);
87666660095SIan Lepore
87766660095SIan Lepore if (!pr) {
87866660095SIan Lepore err = -2;
87966660095SIan Lepore goto the_end;
88066660095SIan Lepore }
88166660095SIan Lepore
88266660095SIan Lepore bzero(pr, icount);
88366660095SIan Lepore
88466660095SIan Lepore err = _read_write(hdev, pw, pr, icount, popt->lsb);
88566660095SIan Lepore
88666660095SIan Lepore if (!err)
88766660095SIan Lepore err = _do_data_output(pr, popt);
88866660095SIan Lepore
88966660095SIan Lepore the_end:
89066660095SIan Lepore
89166660095SIan Lepore free(pr);
89266660095SIan Lepore free(pw);
89366660095SIan Lepore
89466660095SIan Lepore return err;
89566660095SIan Lepore }
89666660095SIan Lepore
89766660095SIan Lepore
89866660095SIan Lepore static void
verbose_dump_buffer(void * pbuf,int icount,int lsb)89966660095SIan Lepore verbose_dump_buffer(void *pbuf, int icount, int lsb)
90066660095SIan Lepore {
90166660095SIan Lepore uint8_t ch;
902917d1846SIan Lepore int ictr, ictr2, idx;
90366660095SIan Lepore
90466660095SIan Lepore fputs(" | 0 1 2 3 4 5 6 7 8 9 A B C D E F "
90566660095SIan Lepore "| |\n", stderr);
90666660095SIan Lepore
90766660095SIan Lepore for (ictr = 0; ictr < icount; ictr += 16) {
90866660095SIan Lepore fprintf(stderr, " %6x | ", ictr & 0xfffff0);
90966660095SIan Lepore
91066660095SIan Lepore for (ictr2 = 0; ictr2 < 16; ictr2++) {
911917d1846SIan Lepore idx = ictr + ictr2;
91266660095SIan Lepore
913917d1846SIan Lepore if (idx < icount) {
914917d1846SIan Lepore ch = ((uint8_t *) pbuf)[idx];
91566660095SIan Lepore
91666660095SIan Lepore if (lsb)
91766660095SIan Lepore ch = reversebits[ch];
91866660095SIan Lepore
91966660095SIan Lepore fprintf(stderr, "%02hhx ", ch);
92066660095SIan Lepore }
92166660095SIan Lepore else {
92266660095SIan Lepore fputs(" ", stderr);
92366660095SIan Lepore }
92466660095SIan Lepore }
92566660095SIan Lepore
92666660095SIan Lepore fputs("| ", stderr);
92766660095SIan Lepore
92866660095SIan Lepore for (ictr2 = 0; ictr2 < 16; ictr2++) {
929917d1846SIan Lepore idx = ictr + ictr2;
93066660095SIan Lepore
931917d1846SIan Lepore if (idx < icount) {
932917d1846SIan Lepore ch = ((uint8_t *) pbuf)[idx];
93366660095SIan Lepore
93466660095SIan Lepore if (lsb)
93566660095SIan Lepore ch = reversebits[ch];
93666660095SIan Lepore
93766660095SIan Lepore if (ch < ' ' || ch > 127)
93866660095SIan Lepore goto out_of_range;
93966660095SIan Lepore
94066660095SIan Lepore fprintf(stderr, "%c", ch);
94166660095SIan Lepore }
942917d1846SIan Lepore else if (idx < icount) {
94366660095SIan Lepore out_of_range:
94466660095SIan Lepore fputc('.', stderr);
94566660095SIan Lepore }
94666660095SIan Lepore else {
94766660095SIan Lepore fputc(' ', stderr);
94866660095SIan Lepore }
94966660095SIan Lepore }
95066660095SIan Lepore
95166660095SIan Lepore fputs(" |\n", stderr);
95266660095SIan Lepore }
95366660095SIan Lepore
95466660095SIan Lepore fflush(stderr);
95566660095SIan Lepore }
956