1*66660095SIan Lepore /*- 2*66660095SIan Lepore * SPDX-License-Identifier: BSD-2-Clause 3*66660095SIan Lepore * 4*66660095SIan Lepore * Copyright (c) 2018 S.F.T. Inc. 5*66660095SIan Lepore * 6*66660095SIan Lepore * Redistribution and use in source and binary forms, with or without 7*66660095SIan Lepore * modification, are permitted provided that the following conditions 8*66660095SIan Lepore * are met: 9*66660095SIan Lepore * 1. Redistributions of source code must retain the above copyright 10*66660095SIan Lepore * notice, this list of conditions and the following disclaimer. 11*66660095SIan Lepore * 2. Redistributions in binary form must reproduce the above copyright 12*66660095SIan Lepore * notice, this list of conditions and the following disclaimer in the 13*66660095SIan Lepore * documentation and/or other materials provided with the distribution. 14*66660095SIan Lepore * 15*66660095SIan Lepore * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16*66660095SIan Lepore * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17*66660095SIan Lepore * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18*66660095SIan Lepore * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19*66660095SIan Lepore * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20*66660095SIan Lepore * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21*66660095SIan Lepore * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22*66660095SIan Lepore * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23*66660095SIan Lepore * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24*66660095SIan Lepore * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25*66660095SIan Lepore * SUCH DAMAGE. 26*66660095SIan Lepore */ 27*66660095SIan Lepore 28*66660095SIan Lepore #include <sys/cdefs.h> 29*66660095SIan Lepore __FBSDID("$FreeBSD$"); 30*66660095SIan Lepore 31*66660095SIan Lepore #include <sys/types.h> 32*66660095SIan Lepore #include <sys/ioccom.h> 33*66660095SIan Lepore #include <sys/spigenio.h> 34*66660095SIan Lepore #include <sys/sysctl.h> 35*66660095SIan Lepore 36*66660095SIan Lepore #include <errno.h> 37*66660095SIan Lepore #include <fcntl.h> 38*66660095SIan Lepore #include <inttypes.h> 39*66660095SIan Lepore #include <limits.h> 40*66660095SIan Lepore #include <memory.h> 41*66660095SIan Lepore #include <stdio.h> 42*66660095SIan Lepore #include <stdlib.h> 43*66660095SIan Lepore #include <string.h> 44*66660095SIan Lepore #include <string.h> 45*66660095SIan Lepore #include <unistd.h> 46*66660095SIan Lepore 47*66660095SIan Lepore #define DEFAULT_DEVICE_NAME "/dev/spigen0.0" 48*66660095SIan Lepore 49*66660095SIan Lepore #define DEFAULT_BUFFER_SIZE 8192 50*66660095SIan Lepore 51*66660095SIan Lepore #define DIR_READ 0 52*66660095SIan Lepore #define DIR_WRITE 1 53*66660095SIan Lepore #define DIR_READWRITE 2 54*66660095SIan Lepore #define DIR_NONE -1 55*66660095SIan Lepore 56*66660095SIan Lepore struct spi_options { 57*66660095SIan Lepore int mode; /* mode (0,1,2,3, -1 == use default) */ 58*66660095SIan Lepore int speed; /* speed (in Hz, -1 == use default) */ 59*66660095SIan Lepore int count; /* count (0 through 'n' bytes, negative for 60*66660095SIan Lepore * stdin length) */ 61*66660095SIan Lepore int binary; /* non-zero for binary output or zero for 62*66660095SIan Lepore * ASCII output when ASCII != 0 */ 63*66660095SIan Lepore int ASCII; /* zero for binary input and output. 64*66660095SIan Lepore * non-zero for ASCII input, 'binary' 65*66660095SIan Lepore * determines output */ 66*66660095SIan Lepore int lsb; /* non-zero for LSB order (default order is 67*66660095SIan Lepore * MSB) */ 68*66660095SIan Lepore int verbose; /* non-zero for verbosity */ 69*66660095SIan Lepore int ncmd; /* bytes to skip for incoming data */ 70*66660095SIan Lepore uint8_t *pcmd; /* command data (NULL if none) */ 71*66660095SIan Lepore }; 72*66660095SIan Lepore 73*66660095SIan Lepore static void usage(void); 74*66660095SIan Lepore static int interpret_command_bytes(const char *parg, struct spi_options *popt); 75*66660095SIan Lepore static void * prep_write_buffer(struct spi_options *popt); 76*66660095SIan Lepore static int _read_write(int hdev, void *bufw, void *bufr, int cbrw, int lsb); 77*66660095SIan Lepore static int _do_data_output(void *pr, struct spi_options *popt); 78*66660095SIan Lepore static int get_info(int hdev, const char *dev_name); 79*66660095SIan Lepore static int set_mode(int hdev, struct spi_options *popt); 80*66660095SIan Lepore static int set_speed(int hdev, struct spi_options *popt); 81*66660095SIan Lepore static int hexval(char c); 82*66660095SIan Lepore static int perform_read(int hdev, struct spi_options *popt); 83*66660095SIan Lepore static int perform_write(int hdev, struct spi_options *popt); 84*66660095SIan Lepore static int perform_readwrite(int hdev, struct spi_options *popt); 85*66660095SIan Lepore static void verbose_dump_buffer(void *pbuf, int icount, int lsb); 86*66660095SIan Lepore 87*66660095SIan Lepore /* 88*66660095SIan Lepore * LSB array - reversebits[n] is the LSB value of n as an MSB. Use this array 89*66660095SIan Lepore * to obtain a reversed bit pattern of the index value when bits must 90*66660095SIan Lepore * be sent/received in an LSB order vs the default MSB 91*66660095SIan Lepore */ 92*66660095SIan Lepore static uint8_t reversebits[256] = { 93*66660095SIan Lepore 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 94*66660095SIan Lepore 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, 95*66660095SIan Lepore 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, 96*66660095SIan Lepore 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, 97*66660095SIan Lepore 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, 98*66660095SIan Lepore 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, 99*66660095SIan Lepore 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 100*66660095SIan Lepore 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, 101*66660095SIan Lepore 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 102*66660095SIan Lepore 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, 103*66660095SIan Lepore 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, 104*66660095SIan Lepore 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, 105*66660095SIan Lepore 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 106*66660095SIan Lepore 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, 107*66660095SIan Lepore 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, 108*66660095SIan Lepore 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, 109*66660095SIan Lepore 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, 110*66660095SIan Lepore 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, 111*66660095SIan Lepore 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 112*66660095SIan Lepore 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, 113*66660095SIan Lepore 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, 114*66660095SIan Lepore 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, 115*66660095SIan Lepore 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, 116*66660095SIan Lepore 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, 117*66660095SIan Lepore 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 118*66660095SIan Lepore 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, 119*66660095SIan Lepore 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 120*66660095SIan Lepore 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, 121*66660095SIan Lepore 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, 122*66660095SIan Lepore 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, 123*66660095SIan Lepore 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 124*66660095SIan Lepore 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff 125*66660095SIan Lepore }; 126*66660095SIan Lepore 127*66660095SIan Lepore 128*66660095SIan Lepore static void 129*66660095SIan Lepore usage(void) 130*66660095SIan Lepore { 131*66660095SIan Lepore fputs(getprogname(), stderr); 132*66660095SIan Lepore fputs(" - communicate on SPI bus with slave devices\n" 133*66660095SIan Lepore "Usage:\n" 134*66660095SIan Lepore " spi [-f device] [-d r|w|rw] [-m mode] [-s max-speed] [-c count]\n" 135*66660095SIan Lepore " [-C \"command bytes\"] [-A] [-b] [-L] [-v]\n" 136*66660095SIan Lepore " spi -i [-f device] [-v]\n" 137*66660095SIan Lepore " spi -h\n" 138*66660095SIan Lepore " where\n" 139*66660095SIan Lepore " -f specifies the device (default is spigen0.0)\n" 140*66660095SIan Lepore " -d specifies the operation (r, w, or rw; default is rw)\n" 141*66660095SIan Lepore " -m specifies the mode (0, 1, 2, or 3)\n" 142*66660095SIan Lepore " -s specifies the maximum speed (default is 0, device default)\n" 143*66660095SIan Lepore " -c specifies the number of data bytes to transfer (default 0, i.e. none)\n" 144*66660095SIan Lepore " A negative value uses the length of the input data\n" 145*66660095SIan Lepore " -C specifies 'command bytes' to be sent, as 2 byte hexadecimal values\n" 146*66660095SIan Lepore " (these should be quoted, separated by optional white space)\n" 147*66660095SIan Lepore " -L specifies 'LSB' order on the SPI bus (default is MSB)\n" 148*66660095SIan Lepore " -i query information about the device\n" 149*66660095SIan Lepore " -A uses ASCII for input/output as 2-digit hex values\n" 150*66660095SIan Lepore " -b Override output format as binary (only valid with '-A')\n" 151*66660095SIan Lepore " -v verbose output\n" 152*66660095SIan Lepore " -h prints this message\n" 153*66660095SIan Lepore "\n" 154*66660095SIan Lepore "NOTE: setting the mode and/or speed is 'sticky'. Subsequent transactions\n" 155*66660095SIan Lepore " on that device will, by default, use the previously set values.\n" 156*66660095SIan Lepore "\n", 157*66660095SIan Lepore stderr); 158*66660095SIan Lepore } 159*66660095SIan Lepore 160*66660095SIan Lepore int 161*66660095SIan Lepore main(int argc, char *argv[], char *envp[] __unused) 162*66660095SIan Lepore { 163*66660095SIan Lepore struct spi_options opt; 164*66660095SIan Lepore int err, ch, hdev, finfo, fdir; 165*66660095SIan Lepore char *pstr; 166*66660095SIan Lepore char dev_name[PATH_MAX * 2 + 5]; 167*66660095SIan Lepore 168*66660095SIan Lepore finfo = 0; 169*66660095SIan Lepore fdir = DIR_NONE; 170*66660095SIan Lepore 171*66660095SIan Lepore hdev = -1; 172*66660095SIan Lepore err = 0; 173*66660095SIan Lepore 174*66660095SIan Lepore dev_name[0] = 0; 175*66660095SIan Lepore 176*66660095SIan Lepore opt.mode = -1; 177*66660095SIan Lepore opt.speed = -1; 178*66660095SIan Lepore opt.count = 0; 179*66660095SIan Lepore opt.ASCII = 0; 180*66660095SIan Lepore opt.binary = 0; 181*66660095SIan Lepore opt.lsb = 0; 182*66660095SIan Lepore opt.verbose = 0; 183*66660095SIan Lepore opt.ncmd = 0; 184*66660095SIan Lepore opt.pcmd = NULL; 185*66660095SIan Lepore 186*66660095SIan Lepore while (!err && (ch = getopt(argc, argv, "f:d:m:s:c:C:AbLvih")) != -1) { 187*66660095SIan Lepore switch (ch) { 188*66660095SIan Lepore case 'd': 189*66660095SIan Lepore if (optarg[0] == 'r') { 190*66660095SIan Lepore if (optarg[1] == 'w' && optarg[2] == 0) { 191*66660095SIan Lepore fdir = DIR_READWRITE; 192*66660095SIan Lepore } 193*66660095SIan Lepore else if (optarg[1] == 0) { 194*66660095SIan Lepore fdir = DIR_READ; 195*66660095SIan Lepore } 196*66660095SIan Lepore } 197*66660095SIan Lepore else if (optarg[0] == 'w' && optarg[1] == 0) { 198*66660095SIan Lepore fdir = DIR_WRITE; 199*66660095SIan Lepore } 200*66660095SIan Lepore else { 201*66660095SIan Lepore err = 1; 202*66660095SIan Lepore } 203*66660095SIan Lepore break; 204*66660095SIan Lepore 205*66660095SIan Lepore case 'f': 206*66660095SIan Lepore if (!optarg[0]) { /* unlikely */ 207*66660095SIan Lepore fputs("error - missing device name\n", stderr); 208*66660095SIan Lepore err = 1; 209*66660095SIan Lepore } 210*66660095SIan Lepore else { 211*66660095SIan Lepore if (optarg[0] == '/') 212*66660095SIan Lepore strlcpy(dev_name, optarg, 213*66660095SIan Lepore sizeof(dev_name)); 214*66660095SIan Lepore else 215*66660095SIan Lepore snprintf(dev_name, sizeof(dev_name), 216*66660095SIan Lepore "/dev/%s", optarg); 217*66660095SIan Lepore } 218*66660095SIan Lepore break; 219*66660095SIan Lepore 220*66660095SIan Lepore case 'm': 221*66660095SIan Lepore opt.mode = (int)strtol(optarg, &pstr, 10); 222*66660095SIan Lepore 223*66660095SIan Lepore if (!pstr || *pstr || opt.mode < 0 || opt.mode > 3) { 224*66660095SIan Lepore fprintf(stderr, "Invalid mode specified: %s\n", 225*66660095SIan Lepore optarg); 226*66660095SIan Lepore err = 1; 227*66660095SIan Lepore } 228*66660095SIan Lepore break; 229*66660095SIan Lepore 230*66660095SIan Lepore case 's': 231*66660095SIan Lepore opt.speed = (int)strtol(optarg, &pstr, 10); 232*66660095SIan Lepore 233*66660095SIan Lepore if (!pstr || *pstr || opt.speed < 0) { 234*66660095SIan Lepore fprintf(stderr, "Invalid speed specified: %s\n", 235*66660095SIan Lepore optarg); 236*66660095SIan Lepore err = 1; 237*66660095SIan Lepore } 238*66660095SIan Lepore break; 239*66660095SIan Lepore 240*66660095SIan Lepore case 'c': 241*66660095SIan Lepore opt.count = (int)strtol(optarg, &pstr, 10); 242*66660095SIan Lepore 243*66660095SIan Lepore if (!pstr || *pstr) { 244*66660095SIan Lepore fprintf(stderr, "Invalid count specified: %s\n", 245*66660095SIan Lepore optarg); 246*66660095SIan Lepore err = 1; 247*66660095SIan Lepore } 248*66660095SIan Lepore break; 249*66660095SIan Lepore 250*66660095SIan Lepore case 'C': 251*66660095SIan Lepore if(opt.pcmd) /* specified more than once */ 252*66660095SIan Lepore err = 1; 253*66660095SIan Lepore else { 254*66660095SIan Lepore /* get malloc'd buffer or error */ 255*66660095SIan Lepore if (interpret_command_bytes(optarg, &opt)) 256*66660095SIan Lepore err = 1; 257*66660095SIan Lepore } 258*66660095SIan Lepore 259*66660095SIan Lepore break; 260*66660095SIan Lepore 261*66660095SIan Lepore case 'A': 262*66660095SIan Lepore opt.ASCII = 1; 263*66660095SIan Lepore break; 264*66660095SIan Lepore 265*66660095SIan Lepore case 'b': 266*66660095SIan Lepore opt.binary = 1; 267*66660095SIan Lepore break; 268*66660095SIan Lepore 269*66660095SIan Lepore case 'L': 270*66660095SIan Lepore opt.lsb = 1; 271*66660095SIan Lepore break; 272*66660095SIan Lepore 273*66660095SIan Lepore case 'v': 274*66660095SIan Lepore opt.verbose++; 275*66660095SIan Lepore break; 276*66660095SIan Lepore 277*66660095SIan Lepore case 'i': 278*66660095SIan Lepore finfo = 1; 279*66660095SIan Lepore break; 280*66660095SIan Lepore 281*66660095SIan Lepore default: 282*66660095SIan Lepore err = 1; 283*66660095SIan Lepore /* FALLTHROUGH */ 284*66660095SIan Lepore case 'h': 285*66660095SIan Lepore usage(); 286*66660095SIan Lepore goto the_end; 287*66660095SIan Lepore } 288*66660095SIan Lepore } 289*66660095SIan Lepore 290*66660095SIan Lepore argc -= optind; 291*66660095SIan Lepore argv += optind; 292*66660095SIan Lepore 293*66660095SIan Lepore if (err || 294*66660095SIan Lepore (fdir == DIR_NONE && !finfo && opt.mode == -1 && opt.speed == -1 && opt.count == 0)) { 295*66660095SIan Lepore /* 296*66660095SIan Lepore * if any of the direction, mode, speed, or count not specified, 297*66660095SIan Lepore * print usage 298*66660095SIan Lepore */ 299*66660095SIan Lepore 300*66660095SIan Lepore usage(); 301*66660095SIan Lepore goto the_end; 302*66660095SIan Lepore } 303*66660095SIan Lepore 304*66660095SIan Lepore if ((opt.count != 0 || opt.ncmd != 0) && fdir == DIR_NONE) { 305*66660095SIan Lepore /* 306*66660095SIan Lepore * count was specified, but direction was not. default is 307*66660095SIan Lepore * read/write 308*66660095SIan Lepore */ 309*66660095SIan Lepore /* 310*66660095SIan Lepore * this includes a negative count, which implies write from 311*66660095SIan Lepore * stdin 312*66660095SIan Lepore */ 313*66660095SIan Lepore if (opt.count == 0) 314*66660095SIan Lepore fdir = DIR_WRITE; 315*66660095SIan Lepore else 316*66660095SIan Lepore fdir = DIR_READWRITE; 317*66660095SIan Lepore } 318*66660095SIan Lepore 319*66660095SIan Lepore if (opt.count < 0 && fdir != DIR_READWRITE && fdir != DIR_WRITE) { 320*66660095SIan Lepore fprintf(stderr, "Invalid length %d when not writing data\n", 321*66660095SIan Lepore opt.count); 322*66660095SIan Lepore 323*66660095SIan Lepore err = 1; 324*66660095SIan Lepore usage(); 325*66660095SIan Lepore goto the_end; 326*66660095SIan Lepore } 327*66660095SIan Lepore 328*66660095SIan Lepore 329*66660095SIan Lepore if (!dev_name[0]) /* no device name specified */ 330*66660095SIan Lepore strlcpy(dev_name, DEFAULT_DEVICE_NAME, sizeof(dev_name)); 331*66660095SIan Lepore 332*66660095SIan Lepore hdev = open(dev_name, O_RDWR); 333*66660095SIan Lepore 334*66660095SIan Lepore if (hdev == -1) { 335*66660095SIan Lepore fprintf(stderr, "Error - unable to open '%s', errno=%d\n", 336*66660095SIan Lepore dev_name, errno); 337*66660095SIan Lepore err = 1; 338*66660095SIan Lepore goto the_end; 339*66660095SIan Lepore } 340*66660095SIan Lepore 341*66660095SIan Lepore if (finfo) { 342*66660095SIan Lepore err = get_info(hdev, dev_name); 343*66660095SIan Lepore goto the_end; 344*66660095SIan Lepore } 345*66660095SIan Lepore 346*66660095SIan Lepore /* check and assign mode, speed */ 347*66660095SIan Lepore 348*66660095SIan Lepore if (opt.mode != -1) { 349*66660095SIan Lepore err = set_mode(hdev, &opt); 350*66660095SIan Lepore 351*66660095SIan Lepore if (err) 352*66660095SIan Lepore goto the_end; 353*66660095SIan Lepore } 354*66660095SIan Lepore 355*66660095SIan Lepore if (opt.speed != -1) { 356*66660095SIan Lepore err = set_speed(hdev, &opt); 357*66660095SIan Lepore 358*66660095SIan Lepore if (err) 359*66660095SIan Lepore goto the_end; 360*66660095SIan Lepore } 361*66660095SIan Lepore 362*66660095SIan Lepore /* do data transfer */ 363*66660095SIan Lepore 364*66660095SIan Lepore if (fdir == DIR_READ) { 365*66660095SIan Lepore err = perform_read(hdev, &opt); 366*66660095SIan Lepore } 367*66660095SIan Lepore else if (fdir == DIR_WRITE) { 368*66660095SIan Lepore err = perform_write(hdev, &opt); 369*66660095SIan Lepore } 370*66660095SIan Lepore else if (fdir == DIR_READWRITE) { 371*66660095SIan Lepore err = perform_readwrite(hdev, &opt); 372*66660095SIan Lepore } 373*66660095SIan Lepore 374*66660095SIan Lepore the_end: 375*66660095SIan Lepore 376*66660095SIan Lepore if (hdev != -1) 377*66660095SIan Lepore close(hdev); 378*66660095SIan Lepore 379*66660095SIan Lepore free(opt.pcmd); 380*66660095SIan Lepore 381*66660095SIan Lepore return (err); 382*66660095SIan Lepore } 383*66660095SIan Lepore 384*66660095SIan Lepore static int 385*66660095SIan Lepore interpret_command_bytes(const char *parg, struct spi_options *popt) 386*66660095SIan Lepore { 387*66660095SIan Lepore int ch, ch2, ctr, cbcmd, err; 388*66660095SIan Lepore const char *ppos; 389*66660095SIan Lepore void *ptemp; 390*66660095SIan Lepore uint8_t *pcur; 391*66660095SIan Lepore 392*66660095SIan Lepore err = 0; 393*66660095SIan Lepore cbcmd = DEFAULT_BUFFER_SIZE; /* initial cmd buffer size */ 394*66660095SIan Lepore popt->pcmd = (uint8_t *)malloc(cbcmd); 395*66660095SIan Lepore 396*66660095SIan Lepore if (!popt->pcmd) 397*66660095SIan Lepore return 1; 398*66660095SIan Lepore 399*66660095SIan Lepore pcur = popt->pcmd; 400*66660095SIan Lepore 401*66660095SIan Lepore ctr = 0; 402*66660095SIan Lepore ppos = parg; 403*66660095SIan Lepore 404*66660095SIan Lepore while (*ppos) { 405*66660095SIan Lepore while (*ppos && *ppos <= ' ') { 406*66660095SIan Lepore ppos++; /* skip (optional) leading white space */ 407*66660095SIan Lepore } 408*66660095SIan Lepore 409*66660095SIan Lepore if (!*ppos) 410*66660095SIan Lepore break; /* I am done */ 411*66660095SIan Lepore 412*66660095SIan Lepore ch = hexval(*(ppos++)); 413*66660095SIan Lepore if (ch < 0 || !*ppos) { /* must be valid pair of hex characters */ 414*66660095SIan Lepore err = 1; 415*66660095SIan Lepore goto the_end; 416*66660095SIan Lepore } 417*66660095SIan Lepore 418*66660095SIan Lepore ch2 = hexval(*(ppos++)); 419*66660095SIan Lepore if (ch2 < 0) { 420*66660095SIan Lepore err = 1; 421*66660095SIan Lepore goto the_end; 422*66660095SIan Lepore } 423*66660095SIan Lepore 424*66660095SIan Lepore ch = (ch * 16 + ch2) & 0xff; /* convert to byte */ 425*66660095SIan Lepore 426*66660095SIan Lepore if (ctr >= cbcmd) { /* need re-alloc buffer? (unlikely) */ 427*66660095SIan Lepore cbcmd += 8192; /* increase by additional 8k */ 428*66660095SIan Lepore ptemp = realloc(popt->pcmd, cbcmd); 429*66660095SIan Lepore 430*66660095SIan Lepore if (!ptemp) { 431*66660095SIan Lepore err = 1; 432*66660095SIan Lepore fprintf(stderr, 433*66660095SIan Lepore "Not enough memory to interpret command bytes, errno=%d\n", 434*66660095SIan Lepore errno); 435*66660095SIan Lepore goto the_end; 436*66660095SIan Lepore } 437*66660095SIan Lepore 438*66660095SIan Lepore popt->pcmd = (uint8_t *)ptemp; 439*66660095SIan Lepore pcur = popt->pcmd + ctr; 440*66660095SIan Lepore } 441*66660095SIan Lepore 442*66660095SIan Lepore if (popt->lsb) 443*66660095SIan Lepore *pcur = reversebits[ch]; 444*66660095SIan Lepore else 445*66660095SIan Lepore *pcur = (uint8_t)ch; 446*66660095SIan Lepore 447*66660095SIan Lepore pcur++; 448*66660095SIan Lepore ctr++; 449*66660095SIan Lepore } 450*66660095SIan Lepore 451*66660095SIan Lepore popt->ncmd = ctr; /* record num bytes in '-C' argument */ 452*66660095SIan Lepore 453*66660095SIan Lepore the_end: 454*66660095SIan Lepore 455*66660095SIan Lepore /* at this point popt->pcmd is NULL or a valid pointer */ 456*66660095SIan Lepore 457*66660095SIan Lepore return err; 458*66660095SIan Lepore } 459*66660095SIan Lepore 460*66660095SIan Lepore static int 461*66660095SIan Lepore get_info(int hdev, const char *dev_name) 462*66660095SIan Lepore { 463*66660095SIan Lepore uint32_t fmode, fspeed; 464*66660095SIan Lepore int err; 465*66660095SIan Lepore char temp_buf[PATH_MAX], cpath[PATH_MAX]; 466*66660095SIan Lepore 467*66660095SIan Lepore if (!realpath(dev_name, cpath)) /* get canonical name for info purposes */ 468*66660095SIan Lepore strlcpy(cpath, temp_buf, sizeof(cpath)); /* this shouldn't happen */ 469*66660095SIan Lepore 470*66660095SIan Lepore err = ioctl(hdev, SPIGENIOC_GET_SPI_MODE, &fmode); 471*66660095SIan Lepore 472*66660095SIan Lepore if (err == 0) 473*66660095SIan Lepore err = ioctl(hdev, SPIGENIOC_GET_CLOCK_SPEED, &fspeed); 474*66660095SIan Lepore 475*66660095SIan Lepore if (err == 0) { 476*66660095SIan Lepore fprintf(stderr, 477*66660095SIan Lepore "Device name: %s\n" 478*66660095SIan Lepore "Device mode: %d\n" 479*66660095SIan Lepore "Device speed: %d\n", 480*66660095SIan Lepore cpath, fmode, fspeed);//, max_cmd, max_data, temp_buf); 481*66660095SIan Lepore } 482*66660095SIan Lepore else 483*66660095SIan Lepore fprintf(stderr, "Unable to query info (err=%d), errno=%d\n", 484*66660095SIan Lepore err, errno); 485*66660095SIan Lepore 486*66660095SIan Lepore return err; 487*66660095SIan Lepore } 488*66660095SIan Lepore 489*66660095SIan Lepore static int 490*66660095SIan Lepore set_mode(int hdev, struct spi_options *popt) 491*66660095SIan Lepore { 492*66660095SIan Lepore uint32_t fmode = popt->mode; 493*66660095SIan Lepore 494*66660095SIan Lepore if (popt->mode < 0) /* use default? */ 495*66660095SIan Lepore return 0; 496*66660095SIan Lepore 497*66660095SIan Lepore return ioctl(hdev, SPIGENIOC_SET_SPI_MODE, &fmode); 498*66660095SIan Lepore } 499*66660095SIan Lepore 500*66660095SIan Lepore static int 501*66660095SIan Lepore set_speed(int hdev, struct spi_options *popt) 502*66660095SIan Lepore { 503*66660095SIan Lepore uint32_t clock_speed = popt->speed; 504*66660095SIan Lepore 505*66660095SIan Lepore if (popt->speed < 0) 506*66660095SIan Lepore return 0; 507*66660095SIan Lepore 508*66660095SIan Lepore return ioctl(hdev, SPIGENIOC_SET_CLOCK_SPEED, &clock_speed); 509*66660095SIan Lepore } 510*66660095SIan Lepore 511*66660095SIan Lepore static int 512*66660095SIan Lepore hexval(char c) 513*66660095SIan Lepore { 514*66660095SIan Lepore if (c >= '0' && c <= '9') { 515*66660095SIan Lepore return c - '0'; 516*66660095SIan Lepore } else if (c >= 'A' && c <= 'F') { 517*66660095SIan Lepore return c - 'A' + 10; 518*66660095SIan Lepore } else if (c >= 'a' && c <= 'f') { 519*66660095SIan Lepore return c - 'a' + 10; 520*66660095SIan Lepore } 521*66660095SIan Lepore return -1; 522*66660095SIan Lepore } 523*66660095SIan Lepore 524*66660095SIan Lepore static void * 525*66660095SIan Lepore prep_write_buffer(struct spi_options *popt) 526*66660095SIan Lepore { 527*66660095SIan Lepore int ch, ch2, ch3, ncmd, lsb, err; 528*66660095SIan Lepore uint8_t *pdata, *pdat2; 529*66660095SIan Lepore size_t cbdata, cbread; 530*66660095SIan Lepore const char *szbytes; 531*66660095SIan Lepore 532*66660095SIan Lepore ncmd = popt->ncmd; /* num command bytes (can be zero) */ 533*66660095SIan Lepore 534*66660095SIan Lepore if (ncmd == 0 && popt->count == 0) 535*66660095SIan Lepore return NULL; /* always since it's an error if it happens 536*66660095SIan Lepore * now */ 537*66660095SIan Lepore 538*66660095SIan Lepore if (popt->count < 0) { 539*66660095SIan Lepore cbdata = DEFAULT_BUFFER_SIZE; 540*66660095SIan Lepore } 541*66660095SIan Lepore else { 542*66660095SIan Lepore cbdata = popt->count; 543*66660095SIan Lepore } 544*66660095SIan Lepore 545*66660095SIan Lepore lsb = popt->lsb; /* non-zero if LSB order; else MSB */ 546*66660095SIan Lepore 547*66660095SIan Lepore pdata = malloc(cbdata + ncmd + 1); 548*66660095SIan Lepore cbread = 0; 549*66660095SIan Lepore 550*66660095SIan Lepore err = 0; 551*66660095SIan Lepore 552*66660095SIan Lepore if (!pdata) 553*66660095SIan Lepore return NULL; 554*66660095SIan Lepore 555*66660095SIan Lepore if (popt->pcmd && ncmd > 0) { 556*66660095SIan Lepore memcpy(pdata, popt->pcmd, ncmd); /* copy command bytes */ 557*66660095SIan Lepore pdat2 = pdata + ncmd; 558*66660095SIan Lepore } 559*66660095SIan Lepore else 560*66660095SIan Lepore pdat2 = pdata; /* no prepended command data */ 561*66660095SIan Lepore 562*66660095SIan Lepore /* 563*66660095SIan Lepore * read up to 'cbdata' bytes. If I get an EOF, do one of two things: 564*66660095SIan Lepore * a) change the data count to match how many bytes I read in b) fill 565*66660095SIan Lepore * the rest of the input buffer with zeros 566*66660095SIan Lepore * 567*66660095SIan Lepore * If the specified length is negative, I do 'a', else 'b' 568*66660095SIan Lepore */ 569*66660095SIan Lepore 570*66660095SIan Lepore while (!err && cbread < cbdata && (ch = fgetc(stdin)) != EOF) { 571*66660095SIan Lepore if (popt->ASCII) { 572*66660095SIan Lepore /* skip consecutive white space */ 573*66660095SIan Lepore 574*66660095SIan Lepore while (ch <= ' ') { 575*66660095SIan Lepore if ((ch = fgetc(stdin)) == EOF) 576*66660095SIan Lepore break; 577*66660095SIan Lepore } 578*66660095SIan Lepore 579*66660095SIan Lepore if (ch != EOF) { 580*66660095SIan Lepore ch2 = hexval(ch); 581*66660095SIan Lepore 582*66660095SIan Lepore if (ch2 < 0) { 583*66660095SIan Lepore invalid_character: 584*66660095SIan Lepore fprintf(stderr, 585*66660095SIan Lepore "Invalid input character '%c'\n", ch); 586*66660095SIan Lepore err = 1; 587*66660095SIan Lepore break; 588*66660095SIan Lepore } 589*66660095SIan Lepore 590*66660095SIan Lepore ch = fgetc(stdin); 591*66660095SIan Lepore 592*66660095SIan Lepore if (ch != EOF) { 593*66660095SIan Lepore ch3 = hexval(ch); 594*66660095SIan Lepore 595*66660095SIan Lepore if (ch3 < 0) 596*66660095SIan Lepore goto invalid_character; 597*66660095SIan Lepore 598*66660095SIan Lepore ch = ch2 * 16 + ch3; 599*66660095SIan Lepore } 600*66660095SIan Lepore } 601*66660095SIan Lepore 602*66660095SIan Lepore if (err || ch == EOF) 603*66660095SIan Lepore break; 604*66660095SIan Lepore } 605*66660095SIan Lepore 606*66660095SIan Lepore /* for LSB, flip the bits - otherwise, just copy the value */ 607*66660095SIan Lepore if (lsb) 608*66660095SIan Lepore pdat2[cbread] = reversebits[ch]; 609*66660095SIan Lepore else 610*66660095SIan Lepore pdat2[cbread] = (uint8_t) ch; 611*66660095SIan Lepore 612*66660095SIan Lepore cbread++; /* increment num bytes read so far */ 613*66660095SIan Lepore } 614*66660095SIan Lepore 615*66660095SIan Lepore /* if it was an error, not an EOF, that ended the I/O, return NULL */ 616*66660095SIan Lepore 617*66660095SIan Lepore if (err || ferror(stdin)) { 618*66660095SIan Lepore free(pdata); 619*66660095SIan Lepore return NULL; 620*66660095SIan Lepore } 621*66660095SIan Lepore 622*66660095SIan Lepore if (popt->verbose > 0) { 623*66660095SIan Lepore const char *sz_bytes; 624*66660095SIan Lepore 625*66660095SIan Lepore if (cbread != 1) 626*66660095SIan Lepore sz_bytes = "bytes"; /* correct plurality of 'byte|bytes' */ 627*66660095SIan Lepore else 628*66660095SIan Lepore sz_bytes = "byte"; 629*66660095SIan Lepore 630*66660095SIan Lepore if (popt->ASCII) 631*66660095SIan Lepore fprintf(stderr, "ASCII input of %zd %s\n", cbread, 632*66660095SIan Lepore sz_bytes); 633*66660095SIan Lepore else 634*66660095SIan Lepore fprintf(stderr, "Binary input of %zd %s\n", cbread, 635*66660095SIan Lepore sz_bytes); 636*66660095SIan Lepore } 637*66660095SIan Lepore 638*66660095SIan Lepore /* 639*66660095SIan Lepore * if opt.count is negative, copy actual byte count to opt.count which does 640*66660095SIan Lepore * not include any of the 'command' bytes that are being sent. Can be zero. 641*66660095SIan Lepore */ 642*66660095SIan Lepore if (popt->count < 0) { 643*66660095SIan Lepore popt->count = cbread; 644*66660095SIan Lepore } 645*66660095SIan Lepore /* 646*66660095SIan Lepore * for everything else, fill the rest of the read buffer with '0' 647*66660095SIan Lepore * bytes, as per the standard practice for SPI 648*66660095SIan Lepore */ 649*66660095SIan Lepore else { 650*66660095SIan Lepore while (cbread < cbdata) 651*66660095SIan Lepore pdat2[cbread++] = 0; 652*66660095SIan Lepore } 653*66660095SIan Lepore 654*66660095SIan Lepore /* 655*66660095SIan Lepore * popt->count bytes will be sent and read from the SPI, preceded by the 656*66660095SIan Lepore * 'popt->ncmd' command bytes (if any). 657*66660095SIan Lepore * So we must use 'popt->count' and 'popt->ncmd' from this point on in 658*66660095SIan Lepore * the code. 659*66660095SIan Lepore */ 660*66660095SIan Lepore 661*66660095SIan Lepore if (popt->verbose > 0 && popt->count + popt->ncmd) { 662*66660095SIan Lepore if ((popt->count + popt->ncmd) == 1) 663*66660095SIan Lepore szbytes = "byte"; 664*66660095SIan Lepore else 665*66660095SIan Lepore szbytes = "bytes"; 666*66660095SIan Lepore 667*66660095SIan Lepore fprintf(stderr, "Writing %d %s to SPI device\n", 668*66660095SIan Lepore popt->count + popt->ncmd, szbytes); 669*66660095SIan Lepore 670*66660095SIan Lepore verbose_dump_buffer(pdata, popt->count + popt->ncmd, lsb); 671*66660095SIan Lepore } 672*66660095SIan Lepore 673*66660095SIan Lepore return pdata; 674*66660095SIan Lepore } 675*66660095SIan Lepore 676*66660095SIan Lepore static int 677*66660095SIan Lepore _read_write(int hdev, void *bufw, void *bufr, int cbrw, int lsb) 678*66660095SIan Lepore { 679*66660095SIan Lepore int err, ctr; 680*66660095SIan Lepore struct spigen_transfer spi; 681*66660095SIan Lepore 682*66660095SIan Lepore if (!cbrw) 683*66660095SIan Lepore return 0; 684*66660095SIan Lepore 685*66660095SIan Lepore if (!bufr) 686*66660095SIan Lepore bufr = bufw; 687*66660095SIan Lepore else 688*66660095SIan Lepore memcpy(bufr, bufw, cbrw); /* transaction uses bufr for 689*66660095SIan Lepore * both R and W */ 690*66660095SIan Lepore 691*66660095SIan Lepore bzero(&spi, sizeof(spi)); /* zero structure first */ 692*66660095SIan Lepore 693*66660095SIan Lepore /* spigen code seems to suggest there must be at least 1 command byte */ 694*66660095SIan Lepore 695*66660095SIan Lepore spi.st_command.iov_base = bufr; 696*66660095SIan Lepore spi.st_command.iov_len = cbrw; 697*66660095SIan Lepore 698*66660095SIan Lepore /* 699*66660095SIan Lepore * The remaining members for spi.st_data are zero - all bytes are 700*66660095SIan Lepore * 'command' for this. The driver doesn't really do anything different 701*66660095SIan Lepore * for 'command' vs 'data' and at least one command byte must be sent in 702*66660095SIan Lepore * the transaction. 703*66660095SIan Lepore */ 704*66660095SIan Lepore 705*66660095SIan Lepore err = ioctl(hdev, SPIGENIOC_TRANSFER, &spi) < 0 ? -1 : 0; 706*66660095SIan Lepore 707*66660095SIan Lepore if (!err && lsb) { 708*66660095SIan Lepore /* flip the bits for 'lsb' mode */ 709*66660095SIan Lepore for (ctr = 0; ctr < cbrw; ctr++) { 710*66660095SIan Lepore ((uint8_t *) bufr)[ctr] = 711*66660095SIan Lepore reversebits[((uint8_t *)bufr)[ctr]]; 712*66660095SIan Lepore } 713*66660095SIan Lepore } 714*66660095SIan Lepore 715*66660095SIan Lepore if (err) 716*66660095SIan Lepore fprintf(stderr, "Error performing SPI transaction, errno=%d\n", 717*66660095SIan Lepore errno); 718*66660095SIan Lepore 719*66660095SIan Lepore return err; 720*66660095SIan Lepore } 721*66660095SIan Lepore 722*66660095SIan Lepore static int 723*66660095SIan Lepore _do_data_output(void *pr, struct spi_options *popt) 724*66660095SIan Lepore { 725*66660095SIan Lepore int err, index, icount; 726*66660095SIan Lepore const char *sz_bytes, *sz_byte2; 727*66660095SIan Lepore const uint8_t *pbuf; 728*66660095SIan Lepore 729*66660095SIan Lepore pbuf = (uint8_t *)pr + popt->ncmd; /* only the data we want */ 730*66660095SIan Lepore icount = popt->count; 731*66660095SIan Lepore err = 0; 732*66660095SIan Lepore 733*66660095SIan Lepore if (icount <= 0) { 734*66660095SIan Lepore return -1; /* should not but could happen */ 735*66660095SIan Lepore } 736*66660095SIan Lepore 737*66660095SIan Lepore if (icount != 1) 738*66660095SIan Lepore sz_bytes = "bytes"; /* correct plurality of 'byte|bytes' */ 739*66660095SIan Lepore else 740*66660095SIan Lepore sz_bytes = "byte"; 741*66660095SIan Lepore 742*66660095SIan Lepore if (popt->ncmd != 1) 743*66660095SIan Lepore sz_byte2 = "bytes"; 744*66660095SIan Lepore else 745*66660095SIan Lepore sz_byte2 = "byte"; 746*66660095SIan Lepore 747*66660095SIan Lepore /* binary on stdout */ 748*66660095SIan Lepore if (popt->binary || !popt->ASCII) { 749*66660095SIan Lepore if (popt->verbose > 0) 750*66660095SIan Lepore fprintf(stderr, "Binary output of %d %s\n", icount, 751*66660095SIan Lepore sz_bytes); 752*66660095SIan Lepore 753*66660095SIan Lepore err = (int)fwrite(pbuf, 1, icount, stdout) != icount; 754*66660095SIan Lepore } 755*66660095SIan Lepore else if (icount > 0) { 756*66660095SIan Lepore if (popt->verbose > 0) 757*66660095SIan Lepore fprintf(stderr, "ASCII output of %d %s\n", icount, 758*66660095SIan Lepore sz_bytes); 759*66660095SIan Lepore 760*66660095SIan Lepore /* ASCII output */ 761*66660095SIan Lepore for (index = 0; !err && index < icount; index++) { 762*66660095SIan Lepore if (index) { 763*66660095SIan Lepore /* 764*66660095SIan Lepore * not the first time, insert separating space 765*66660095SIan Lepore */ 766*66660095SIan Lepore err = fputc(' ', stdout) == EOF; 767*66660095SIan Lepore } 768*66660095SIan Lepore 769*66660095SIan Lepore if (!err) 770*66660095SIan Lepore err = fprintf(stdout, "%02hhx", pbuf[index]) < 0; 771*66660095SIan Lepore } 772*66660095SIan Lepore 773*66660095SIan Lepore if (!err) 774*66660095SIan Lepore err = fputc('\n', stdout) == EOF; 775*66660095SIan Lepore } 776*66660095SIan Lepore 777*66660095SIan Lepore /* verbose text out on stderr */ 778*66660095SIan Lepore 779*66660095SIan Lepore if (err) 780*66660095SIan Lepore fprintf(stderr, "Error writing to stdout, errno=%d\n", errno); 781*66660095SIan Lepore else if (popt->verbose > 0 && icount) { 782*66660095SIan Lepore fprintf(stderr, 783*66660095SIan Lepore "%d command %s and %d data %s read from SPI device\n", 784*66660095SIan Lepore popt->ncmd, sz_byte2, icount, sz_bytes); 785*66660095SIan Lepore 786*66660095SIan Lepore /* verbose output will show the command bytes as well */ 787*66660095SIan Lepore verbose_dump_buffer(pr, icount + popt->ncmd, popt->lsb); 788*66660095SIan Lepore } 789*66660095SIan Lepore 790*66660095SIan Lepore return err; 791*66660095SIan Lepore } 792*66660095SIan Lepore 793*66660095SIan Lepore static int 794*66660095SIan Lepore perform_read(int hdev, struct spi_options *popt) 795*66660095SIan Lepore { 796*66660095SIan Lepore int icount, err; 797*66660095SIan Lepore void *pr, *pw; 798*66660095SIan Lepore 799*66660095SIan Lepore pr = NULL; 800*66660095SIan Lepore icount = popt->count + popt->ncmd; 801*66660095SIan Lepore 802*66660095SIan Lepore /* prep write buffer filled with 0 bytes */ 803*66660095SIan Lepore pw = malloc(icount); 804*66660095SIan Lepore 805*66660095SIan Lepore if (!pw) { 806*66660095SIan Lepore err = -1; 807*66660095SIan Lepore goto the_end; 808*66660095SIan Lepore } 809*66660095SIan Lepore 810*66660095SIan Lepore bzero(pw, icount); 811*66660095SIan Lepore 812*66660095SIan Lepore /* if I included a command sequence, copy bytes to the write buf */ 813*66660095SIan Lepore if (popt->pcmd && popt->ncmd > 0) 814*66660095SIan Lepore memcpy(pw, popt->pcmd, popt->ncmd); 815*66660095SIan Lepore 816*66660095SIan Lepore pr = malloc(icount + 1); 817*66660095SIan Lepore 818*66660095SIan Lepore if (!pr) { 819*66660095SIan Lepore err = -2; 820*66660095SIan Lepore goto the_end; 821*66660095SIan Lepore } 822*66660095SIan Lepore 823*66660095SIan Lepore bzero(pr, icount); 824*66660095SIan Lepore 825*66660095SIan Lepore err = _read_write(hdev, pw, pr, icount, popt->lsb); 826*66660095SIan Lepore 827*66660095SIan Lepore if (!err && popt->count > 0) 828*66660095SIan Lepore err = _do_data_output(pr, popt); 829*66660095SIan Lepore 830*66660095SIan Lepore the_end: 831*66660095SIan Lepore 832*66660095SIan Lepore free(pr); 833*66660095SIan Lepore free(pw); 834*66660095SIan Lepore 835*66660095SIan Lepore return err; 836*66660095SIan Lepore } 837*66660095SIan Lepore 838*66660095SIan Lepore static int 839*66660095SIan Lepore perform_write(int hdev, struct spi_options *popt) 840*66660095SIan Lepore { 841*66660095SIan Lepore int err; 842*66660095SIan Lepore void *pw; 843*66660095SIan Lepore 844*66660095SIan Lepore /* read data from cmd buf and stdin and write to 'write' buffer */ 845*66660095SIan Lepore 846*66660095SIan Lepore pw = prep_write_buffer(popt); 847*66660095SIan Lepore 848*66660095SIan Lepore if (!pw) { 849*66660095SIan Lepore err = -1; 850*66660095SIan Lepore goto the_end; 851*66660095SIan Lepore } 852*66660095SIan Lepore 853*66660095SIan Lepore err = _read_write(hdev, pw, NULL, popt->count + popt->ncmd, popt->lsb); 854*66660095SIan Lepore 855*66660095SIan Lepore the_end: 856*66660095SIan Lepore 857*66660095SIan Lepore free(pw); 858*66660095SIan Lepore 859*66660095SIan Lepore return err; 860*66660095SIan Lepore } 861*66660095SIan Lepore 862*66660095SIan Lepore static int 863*66660095SIan Lepore perform_readwrite(int hdev, struct spi_options *popt) 864*66660095SIan Lepore { 865*66660095SIan Lepore int icount, err; 866*66660095SIan Lepore void *pr, *pw; 867*66660095SIan Lepore 868*66660095SIan Lepore pr = NULL; 869*66660095SIan Lepore 870*66660095SIan Lepore pw = prep_write_buffer(popt); 871*66660095SIan Lepore icount = popt->count + popt->ncmd; /* assign after fn call */ 872*66660095SIan Lepore 873*66660095SIan Lepore if (!pw) { 874*66660095SIan Lepore err = -1; 875*66660095SIan Lepore goto the_end; 876*66660095SIan Lepore } 877*66660095SIan Lepore 878*66660095SIan Lepore pr = malloc(icount + 1); 879*66660095SIan Lepore 880*66660095SIan Lepore if (!pr) { 881*66660095SIan Lepore err = -2; 882*66660095SIan Lepore goto the_end; 883*66660095SIan Lepore } 884*66660095SIan Lepore 885*66660095SIan Lepore bzero(pr, icount); 886*66660095SIan Lepore 887*66660095SIan Lepore err = _read_write(hdev, pw, pr, icount, popt->lsb); 888*66660095SIan Lepore 889*66660095SIan Lepore if (!err) 890*66660095SIan Lepore err = _do_data_output(pr, popt); 891*66660095SIan Lepore 892*66660095SIan Lepore the_end: 893*66660095SIan Lepore 894*66660095SIan Lepore free(pr); 895*66660095SIan Lepore free(pw); 896*66660095SIan Lepore 897*66660095SIan Lepore return err; 898*66660095SIan Lepore } 899*66660095SIan Lepore 900*66660095SIan Lepore 901*66660095SIan Lepore static void 902*66660095SIan Lepore verbose_dump_buffer(void *pbuf, int icount, int lsb) 903*66660095SIan Lepore { 904*66660095SIan Lepore uint8_t ch; 905*66660095SIan Lepore int ictr, ictr2, index; 906*66660095SIan Lepore 907*66660095SIan Lepore fputs(" | 0 1 2 3 4 5 6 7 8 9 A B C D E F " 908*66660095SIan Lepore "| |\n", stderr); 909*66660095SIan Lepore 910*66660095SIan Lepore for (ictr = 0; ictr < icount; ictr += 16) { 911*66660095SIan Lepore fprintf(stderr, " %6x | ", ictr & 0xfffff0); 912*66660095SIan Lepore 913*66660095SIan Lepore for (ictr2 = 0; ictr2 < 16; ictr2++) { 914*66660095SIan Lepore index = ictr + ictr2; 915*66660095SIan Lepore 916*66660095SIan Lepore if (index < icount) { 917*66660095SIan Lepore ch = ((uint8_t *) pbuf)[index]; 918*66660095SIan Lepore 919*66660095SIan Lepore if (lsb) 920*66660095SIan Lepore ch = reversebits[ch]; 921*66660095SIan Lepore 922*66660095SIan Lepore fprintf(stderr, "%02hhx ", ch); 923*66660095SIan Lepore } 924*66660095SIan Lepore else { 925*66660095SIan Lepore fputs(" ", stderr); 926*66660095SIan Lepore } 927*66660095SIan Lepore } 928*66660095SIan Lepore 929*66660095SIan Lepore fputs("| ", stderr); 930*66660095SIan Lepore 931*66660095SIan Lepore for (ictr2 = 0; ictr2 < 16; ictr2++) { 932*66660095SIan Lepore index = ictr + ictr2; 933*66660095SIan Lepore 934*66660095SIan Lepore if (index < icount) { 935*66660095SIan Lepore ch = ((uint8_t *) pbuf)[index]; 936*66660095SIan Lepore 937*66660095SIan Lepore if (lsb) 938*66660095SIan Lepore ch = reversebits[ch]; 939*66660095SIan Lepore 940*66660095SIan Lepore if (ch < ' ' || ch > 127) 941*66660095SIan Lepore goto out_of_range; 942*66660095SIan Lepore 943*66660095SIan Lepore fprintf(stderr, "%c", ch); 944*66660095SIan Lepore } 945*66660095SIan Lepore else if (index < icount) { 946*66660095SIan Lepore out_of_range: 947*66660095SIan Lepore fputc('.', stderr); 948*66660095SIan Lepore } 949*66660095SIan Lepore else { 950*66660095SIan Lepore fputc(' ', stderr); 951*66660095SIan Lepore } 952*66660095SIan Lepore } 953*66660095SIan Lepore 954*66660095SIan Lepore fputs(" |\n", stderr); 955*66660095SIan Lepore } 956*66660095SIan Lepore 957*66660095SIan Lepore fflush(stderr); 958*66660095SIan Lepore } 959