/ 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