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