/ fpgautils.c
fpgautils.c
1 /* 2 * Copyright 2013 Con Kolivas <kernel@kolivas.org> 3 * Copyright 2012 Luke Dashjr 4 * Copyright 2012 Andrew Smith 5 * 6 * This program is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License as published by the Free 8 * Software Foundation; either version 3 of the License, or (at your option) 9 * any later version. See COPYING for more details. 10 */ 11 12 #include "config.h" 13 14 #include <sys/types.h> 15 #include <dirent.h> 16 #include <string.h> 17 18 #include "miner.h" 19 20 #ifndef WIN32 21 #include <errno.h> 22 #include <termios.h> 23 #include <sys/ioctl.h> 24 #include <sys/stat.h> 25 #include <unistd.h> 26 #include <fcntl.h> 27 #ifndef O_CLOEXEC 28 #define O_CLOEXEC 0 29 #endif 30 #else 31 #include <windows.h> 32 #include <io.h> 33 #endif 34 35 #ifdef HAVE_LIBUDEV 36 #include <libudev.h> 37 #include <sys/ioctl.h> 38 #endif 39 40 #include "elist.h" 41 #include "logging.h" 42 #include "miner.h" 43 #include "fpgautils.h" 44 45 #ifdef HAVE_LIBUDEV 46 int serial_autodetect_udev(detectone_func_t detectone, const char*prodname) 47 { 48 struct udev *udev = udev_new(); 49 struct udev_enumerate *enumerate = udev_enumerate_new(udev); 50 struct udev_list_entry *list_entry; 51 char found = 0; 52 53 udev_enumerate_add_match_subsystem(enumerate, "tty"); 54 udev_enumerate_add_match_property(enumerate, "ID_MODEL", prodname); 55 udev_enumerate_scan_devices(enumerate); 56 udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(enumerate)) { 57 struct udev_device *device = udev_device_new_from_syspath( 58 udev_enumerate_get_udev(enumerate), 59 udev_list_entry_get_name(list_entry) 60 ); 61 if (!device) 62 continue; 63 64 const char *devpath = udev_device_get_devnode(device); 65 if (devpath && detectone(devpath)) 66 ++found; 67 68 udev_device_unref(device); 69 } 70 udev_enumerate_unref(enumerate); 71 udev_unref(udev); 72 73 return found; 74 } 75 #else 76 int serial_autodetect_udev(__maybe_unused detectone_func_t detectone, __maybe_unused const char*prodname) 77 { 78 return 0; 79 } 80 #endif 81 82 int serial_autodetect_devserial(__maybe_unused detectone_func_t detectone, __maybe_unused const char*prodname) 83 { 84 #ifndef WIN32 85 DIR *D; 86 struct dirent *de; 87 const char udevdir[] = "/dev/serial/by-id"; 88 char devpath[sizeof(udevdir) + 1 + NAME_MAX]; 89 char *devfile = devpath + sizeof(udevdir); 90 char found = 0; 91 92 D = opendir(udevdir); 93 if (!D) 94 return 0; 95 memcpy(devpath, udevdir, sizeof(udevdir) - 1); 96 devpath[sizeof(udevdir) - 1] = '/'; 97 while ( (de = readdir(D)) ) { 98 if (!strstr(de->d_name, prodname)) 99 continue; 100 strcpy(devfile, de->d_name); 101 if (detectone(devpath)) 102 ++found; 103 } 104 closedir(D); 105 106 return found; 107 #else 108 return 0; 109 #endif 110 } 111 112 int _serial_detect(struct device_drv *drv, detectone_func_t detectone, autoscan_func_t autoscan, bool forceauto) 113 { 114 struct string_elist *iter, *tmp; 115 const char *dev, *colon; 116 bool inhibitauto = false; 117 char found = 0; 118 size_t namel = strlen(drv->name); 119 size_t dnamel = strlen(drv->dname); 120 121 list_for_each_entry_safe(iter, tmp, &scan_devices, list) { 122 dev = iter->string; 123 if ((colon = strchr(dev, ':')) && colon[1] != '\0') { 124 size_t idlen = colon - dev; 125 126 // allow either name:device or dname:device 127 if ((idlen != namel || strncasecmp(dev, drv->name, idlen)) 128 && (idlen != dnamel || strncasecmp(dev, drv->dname, idlen))) 129 continue; 130 131 dev = colon + 1; 132 } 133 if (!strcmp(dev, "auto")) 134 forceauto = true; 135 else if (!strcmp(dev, "noauto")) 136 inhibitauto = true; 137 else if (detectone(dev)) { 138 string_elist_del(iter); 139 inhibitauto = true; 140 ++found; 141 } 142 } 143 144 if ((forceauto || !inhibitauto) && autoscan) 145 found += autoscan(); 146 147 return found; 148 } 149 150 // This code is purely for debugging but is very useful for that 151 // It also took quite a bit of effort so I left it in 152 // #define TERMIOS_DEBUG 1 153 // Here to include it at compile time 154 // It's off by default 155 #ifndef WIN32 156 #ifdef TERMIOS_DEBUG 157 158 #define BITSSET "Y" 159 #define BITSNOTSET "N" 160 161 int tiospeed(speed_t speed) 162 { 163 switch (speed) { 164 case B0: 165 return 0; 166 case B50: 167 return 50; 168 case B75: 169 return 75; 170 case B110: 171 return 110; 172 case B134: 173 return 134; 174 case B150: 175 return 150; 176 case B200: 177 return 200; 178 case B300: 179 return 300; 180 case B600: 181 return 600; 182 case B1200: 183 return 1200; 184 case B1800: 185 return 1800; 186 case B2400: 187 return 2400; 188 case B4800: 189 return 4800; 190 case B9600: 191 return 9600; 192 case B19200: 193 return 19200; 194 case B38400: 195 return 38400; 196 case B57600: 197 return 57600; 198 case B115200: 199 return 115200; 200 case B230400: 201 return 230400; 202 case B460800: 203 return 460800; 204 case B500000: 205 return 500000; 206 case B576000: 207 return 576000; 208 case B921600: 209 return 921600; 210 case B1000000: 211 return 1000000; 212 case B1152000: 213 return 1152000; 214 case B1500000: 215 return 1500000; 216 case B2000000: 217 return 2000000; 218 case B2500000: 219 return 2500000; 220 case B3000000: 221 return 3000000; 222 case B3500000: 223 return 3500000; 224 case B4000000: 225 return 4000000; 226 default: 227 return -1; 228 } 229 } 230 231 void termios_debug(const char *devpath, struct termios *my_termios, const char *msg) 232 { 233 applog(LOG_DEBUG, "TIOS: Open %s attributes %s: ispeed=%d ospeed=%d", 234 devpath, msg, tiospeed(cfgetispeed(my_termios)), tiospeed(cfgetispeed(my_termios))); 235 236 #define ISSETI(b) ((my_termios->c_iflag | (b)) ? BITSSET : BITSNOTSET) 237 238 applog(LOG_DEBUG, "TIOS: c_iflag: IGNBRK=%s BRKINT=%s IGNPAR=%s PARMRK=%s INPCK=%s ISTRIP=%s INLCR=%s IGNCR=%s ICRNL=%s IUCLC=%s IXON=%s IXANY=%s IOFF=%s IMAXBEL=%s IUTF8=%s", 239 ISSETI(IGNBRK), ISSETI(BRKINT), ISSETI(IGNPAR), ISSETI(PARMRK), 240 ISSETI(INPCK), ISSETI(ISTRIP), ISSETI(INLCR), ISSETI(IGNCR), 241 ISSETI(ICRNL), ISSETI(IUCLC), ISSETI(IXON), ISSETI(IXANY), 242 ISSETI(IXOFF), ISSETI(IMAXBEL), ISSETI(IUTF8)); 243 244 #define ISSETO(b) ((my_termios->c_oflag | (b)) ? BITSSET : BITSNOTSET) 245 #define VALO(b) (my_termios->c_oflag | (b)) 246 247 applog(LOG_DEBUG, "TIOS: c_oflag: OPOST=%s OLCUC=%s ONLCR=%s OCRNL=%s ONOCR=%s ONLRET=%s OFILL=%s OFDEL=%s NLDLY=%d CRDLY=%d TABDLY=%d BSDLY=%d VTDLY=%d FFDLY=%d", 248 ISSETO(OPOST), ISSETO(OLCUC), ISSETO(ONLCR), ISSETO(OCRNL), 249 ISSETO(ONOCR), ISSETO(ONLRET), ISSETO(OFILL), ISSETO(OFDEL), 250 VALO(NLDLY), VALO(CRDLY), VALO(TABDLY), VALO(BSDLY), 251 VALO(VTDLY), VALO(FFDLY)); 252 253 #define ISSETC(b) ((my_termios->c_cflag | (b)) ? BITSSET : BITSNOTSET) 254 #define VALC(b) (my_termios->c_cflag | (b)) 255 256 applog(LOG_DEBUG, "TIOS: c_cflag: CBAUDEX=%s CSIZE=%d CSTOPB=%s CREAD=%s PARENB=%s PARODD=%s HUPCL=%s CLOCAL=%s" 257 #ifdef LOBLK 258 " LOBLK=%s" 259 #endif 260 " CMSPAR=%s CRTSCTS=%s", 261 ISSETC(CBAUDEX), VALC(CSIZE), ISSETC(CSTOPB), ISSETC(CREAD), 262 ISSETC(PARENB), ISSETC(PARODD), ISSETC(HUPCL), ISSETC(CLOCAL), 263 #ifdef LOBLK 264 ISSETC(LOBLK), 265 #endif 266 ISSETC(CMSPAR), ISSETC(CRTSCTS)); 267 268 #define ISSETL(b) ((my_termios->c_lflag | (b)) ? BITSSET : BITSNOTSET) 269 270 applog(LOG_DEBUG, "TIOS: c_lflag: ISIG=%s ICANON=%s XCASE=%s ECHO=%s ECHOE=%s ECHOK=%s ECHONL=%s ECHOCTL=%s ECHOPRT=%s ECHOKE=%s" 271 #ifdef DEFECHO 272 " DEFECHO=%s" 273 #endif 274 " FLUSHO=%s NOFLSH=%s TOSTOP=%s PENDIN=%s IEXTEN=%s", 275 ISSETL(ISIG), ISSETL(ICANON), ISSETL(XCASE), ISSETL(ECHO), 276 ISSETL(ECHOE), ISSETL(ECHOK), ISSETL(ECHONL), ISSETL(ECHOCTL), 277 ISSETL(ECHOPRT), ISSETL(ECHOKE), 278 #ifdef DEFECHO 279 ISSETL(DEFECHO), 280 #endif 281 ISSETL(FLUSHO), ISSETL(NOFLSH), ISSETL(TOSTOP), ISSETL(PENDIN), 282 ISSETL(IEXTEN)); 283 284 #define VALCC(b) (my_termios->c_cc[b]) 285 applog(LOG_DEBUG, "TIOS: c_cc: VINTR=0x%02x VQUIT=0x%02x VERASE=0x%02x VKILL=0x%02x VEOF=0x%02x VMIN=%u VEOL=0x%02x VTIME=%u VEOL2=0x%02x" 286 #ifdef VSWTCH 287 " VSWTCH=0x%02x" 288 #endif 289 " VSTART=0x%02x VSTOP=0x%02x VSUSP=0x%02x" 290 #ifdef VDSUSP 291 " VDSUSP=0x%02x" 292 #endif 293 " VLNEXT=0x%02x VWERASE=0x%02x VREPRINT=0x%02x VDISCARD=0x%02x" 294 #ifdef VSTATUS 295 " VSTATUS=0x%02x" 296 #endif 297 , 298 VALCC(VINTR), VALCC(VQUIT), VALCC(VERASE), VALCC(VKILL), 299 VALCC(VEOF), VALCC(VMIN), VALCC(VEOL), VALCC(VTIME), 300 VALCC(VEOL2), 301 #ifdef VSWTCH 302 VALCC(VSWTCH), 303 #endif 304 VALCC(VSTART), VALCC(VSTOP), VALCC(VSUSP), 305 #ifdef VDSUSP 306 VALCC(VDSUSP), 307 #endif 308 VALCC(VLNEXT), VALCC(VWERASE), 309 VALCC(VREPRINT), VALCC(VDISCARD) 310 #ifdef VSTATUS 311 ,VALCC(VSTATUS) 312 #endif 313 ); 314 } 315 #endif 316 #endif 317 318 int serial_open(const char *devpath, unsigned long baud, signed short timeout, bool purge) 319 { 320 #ifdef WIN32 321 HANDLE hSerial = CreateFile(devpath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); 322 if (unlikely(hSerial == INVALID_HANDLE_VALUE)) 323 { 324 DWORD e = GetLastError(); 325 switch (e) { 326 case ERROR_ACCESS_DENIED: 327 applog(LOG_ERR, "Do not have user privileges required to open %s", devpath); 328 break; 329 case ERROR_SHARING_VIOLATION: 330 applog(LOG_ERR, "%s is already in use by another process", devpath); 331 break; 332 default: 333 applog(LOG_DEBUG, "Open %s failed, GetLastError:%d", devpath, (int)e); 334 break; 335 } 336 return -1; 337 } 338 339 // thanks to af_newbie for pointers about this 340 COMMCONFIG comCfg = {0}; 341 comCfg.dwSize = sizeof(COMMCONFIG); 342 comCfg.wVersion = 1; 343 comCfg.dcb.DCBlength = sizeof(DCB); 344 comCfg.dcb.BaudRate = baud; 345 comCfg.dcb.fBinary = 1; 346 comCfg.dcb.fDtrControl = DTR_CONTROL_ENABLE; 347 comCfg.dcb.fRtsControl = RTS_CONTROL_ENABLE; 348 comCfg.dcb.ByteSize = 8; 349 350 SetCommConfig(hSerial, &comCfg, sizeof(comCfg)); 351 352 // Code must specify a valid timeout value (0 means don't timeout) 353 const DWORD ctoms = (timeout * 100); 354 COMMTIMEOUTS cto = {ctoms, 0, ctoms, 0, ctoms}; 355 SetCommTimeouts(hSerial, &cto); 356 357 if (purge) { 358 PurgeComm(hSerial, PURGE_RXABORT); 359 PurgeComm(hSerial, PURGE_TXABORT); 360 PurgeComm(hSerial, PURGE_RXCLEAR); 361 PurgeComm(hSerial, PURGE_TXCLEAR); 362 } 363 364 return _open_osfhandle((intptr_t)hSerial, 0); 365 #else 366 int fdDev = open(devpath, O_RDWR | O_CLOEXEC | O_NOCTTY); 367 368 if (unlikely(fdDev == -1)) 369 { 370 if (errno == EACCES) 371 applog(LOG_ERR, "Do not have user privileges required to open %s", devpath); 372 else 373 applog(LOG_DEBUG, "Open %s failed, errno:%d", devpath, errno); 374 375 return -1; 376 } 377 378 struct termios my_termios; 379 380 tcgetattr(fdDev, &my_termios); 381 382 #ifdef TERMIOS_DEBUG 383 termios_debug(devpath, &my_termios, "before"); 384 #endif 385 386 switch (baud) { 387 case 0: 388 break; 389 case 19200: 390 cfsetispeed(&my_termios, B19200); 391 cfsetospeed(&my_termios, B19200); 392 break; 393 case 38400: 394 cfsetispeed(&my_termios, B38400); 395 cfsetospeed(&my_termios, B38400); 396 break; 397 case 57600: 398 cfsetispeed(&my_termios, B57600); 399 cfsetospeed(&my_termios, B57600); 400 break; 401 case 115200: 402 cfsetispeed(&my_termios, B115200); 403 cfsetospeed(&my_termios, B115200); 404 break; 405 // TODO: try some higher speeds with the Icarus and BFL to see 406 // if they support them and if setting them makes any difference 407 // N.B. B3000000 doesn't work on Icarus 408 default: 409 applog(LOG_WARNING, "Unrecognized baud rate: %lu", baud); 410 } 411 412 my_termios.c_cflag &= ~(CSIZE | PARENB); 413 my_termios.c_cflag |= CS8; 414 my_termios.c_cflag |= CREAD; 415 my_termios.c_cflag |= CLOCAL; 416 417 my_termios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | 418 ISTRIP | INLCR | IGNCR | ICRNL | IXON); 419 my_termios.c_oflag &= ~OPOST; 420 my_termios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); 421 422 // Code must specify a valid timeout value (0 means don't timeout) 423 my_termios.c_cc[VTIME] = (cc_t)timeout; 424 my_termios.c_cc[VMIN] = 0; 425 426 #ifdef TERMIOS_DEBUG 427 termios_debug(devpath, &my_termios, "settings"); 428 #endif 429 430 tcsetattr(fdDev, TCSANOW, &my_termios); 431 432 #ifdef TERMIOS_DEBUG 433 tcgetattr(fdDev, &my_termios); 434 termios_debug(devpath, &my_termios, "after"); 435 #endif 436 437 if (purge) 438 tcflush(fdDev, TCIOFLUSH); 439 return fdDev; 440 #endif 441 } 442 443 ssize_t _serial_read(int fd, char *buf, size_t bufsiz, char *eol) 444 { 445 ssize_t len, tlen = 0; 446 while (bufsiz) { 447 len = read(fd, buf, eol ? 1 : bufsiz); 448 if (unlikely(len == -1)) 449 break; 450 tlen += len; 451 if (eol && *eol == buf[0]) 452 break; 453 buf += len; 454 bufsiz -= len; 455 } 456 return tlen; 457 } 458 459 static FILE *_open_bitstream(const char *path, const char *subdir, const char *filename) 460 { 461 char fullpath[PATH_MAX]; 462 strcpy(fullpath, path); 463 strcat(fullpath, "/"); 464 if (subdir) { 465 strcat(fullpath, subdir); 466 strcat(fullpath, "/"); 467 } 468 strcat(fullpath, filename); 469 return fopen(fullpath, "rb"); 470 } 471 #define _open_bitstream(path, subdir) do { \ 472 f = _open_bitstream(path, subdir, filename); \ 473 if (f) \ 474 return f; \ 475 } while(0) 476 477 #define _open_bitstream3(path) do { \ 478 _open_bitstream(path, dname); \ 479 _open_bitstream(path, "bitstreams"); \ 480 _open_bitstream(path, NULL); \ 481 } while(0) 482 483 FILE *open_bitstream(const char *dname, const char *filename) 484 { 485 FILE *f; 486 487 _open_bitstream3(opt_kernel_path); 488 _open_bitstream3(cgminer_path); 489 _open_bitstream3("."); 490 491 return NULL; 492 } 493 494 #ifndef WIN32 495 496 static bool _select_wait_read(int fd, struct timeval *timeout) 497 { 498 fd_set rfds; 499 500 FD_ZERO(&rfds); 501 FD_SET(fd, &rfds); 502 503 if (select(fd+1, &rfds, NULL, NULL, timeout) > 0) 504 return true; 505 else 506 return false; 507 } 508 509 // Default timeout 100ms - only for device initialisation 510 const struct timeval tv_timeout_default = { 0, 100000 }; 511 // Default inter character timeout = 1ms - only for device initialisation 512 const struct timeval tv_inter_char_default = { 0, 1000 }; 513 514 // Device initialisation function - NOT for work processing 515 size_t _select_read(int fd, char *buf, size_t bufsiz, struct timeval *timeout, struct timeval *char_timeout, int finished) 516 { 517 struct timeval tv_time, tv_char; 518 ssize_t siz, red = 0; 519 char got; 520 521 // timeout is the maximum time to wait for the first character 522 tv_time.tv_sec = timeout->tv_sec; 523 tv_time.tv_usec = timeout->tv_usec; 524 525 if (!_select_wait_read(fd, &tv_time)) 526 return 0; 527 528 while (4242) { 529 if ((siz = read(fd, buf, 1)) < 0) 530 return red; 531 532 got = *buf; 533 buf += siz; 534 red += siz; 535 bufsiz -= siz; 536 537 if (bufsiz < 1 || (finished >= 0 && got == finished)) 538 return red; 539 540 // char_timeout is the maximum time to wait for each subsequent character 541 // this is OK for initialisation, but bad for work processing 542 // work processing MUST have a fixed size so this doesn't come into play 543 tv_char.tv_sec = char_timeout->tv_sec; 544 tv_char.tv_usec = char_timeout->tv_usec; 545 546 if (!_select_wait_read(fd, &tv_char)) 547 return red; 548 } 549 550 return red; 551 } 552 553 // Device initialisation function - NOT for work processing 554 size_t _select_write(int fd, char *buf, size_t siz, struct timeval *timeout) 555 { 556 struct timeval tv_time, tv_now, tv_finish; 557 fd_set rfds; 558 ssize_t wrote = 0, ret; 559 560 cgtime(&tv_now); 561 timeradd(&tv_now, timeout, &tv_finish); 562 563 // timeout is the maximum time to spend trying to write 564 tv_time.tv_sec = timeout->tv_sec; 565 tv_time.tv_usec = timeout->tv_usec; 566 567 FD_ZERO(&rfds); 568 FD_SET(fd, &rfds); 569 570 while (siz > 0 && (tv_now.tv_sec < tv_finish.tv_sec || (tv_now.tv_sec == tv_finish.tv_sec && tv_now.tv_usec < tv_finish.tv_usec)) && select(fd+1, NULL, &rfds, NULL, &tv_time) > 0) { 571 if ((ret = write(fd, buf, 1)) > 0) { 572 buf++; 573 wrote++; 574 siz--; 575 } 576 else if (ret < 0) 577 return wrote; 578 579 cgtime(&tv_now); 580 } 581 582 return wrote; 583 } 584 585 int get_serial_cts(int fd) 586 { 587 int flags; 588 589 if (!fd) 590 return -1; 591 592 ioctl(fd, TIOCMGET, &flags); 593 return (flags & TIOCM_CTS) ? 1 : 0; 594 } 595 #else 596 int get_serial_cts(const int fd) 597 { 598 if (!fd) 599 return -1; 600 const HANDLE fh = (HANDLE)_get_osfhandle(fd); 601 if (!fh) 602 return -1; 603 604 DWORD flags; 605 if (!GetCommModemStatus(fh, &flags)) 606 return -1; 607 608 return (flags & MS_CTS_ON) ? 1 : 0; 609 } 610 #endif // ! WIN32