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