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