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