serial.c 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823
  1. /*
  2. * This file is Copyright 2010 by the GPSD project
  3. * SPDX-License-Identifier: BSD-2-clause
  4. */
  5. #include "gpsd_config.h" /* must be before all includes */
  6. #include <ctype.h> /* for isdigit() */
  7. #include <dirent.h> /* for DIR */
  8. #include <errno.h>
  9. #include <fcntl.h>
  10. #include <stdbool.h>
  11. #include <stdio.h>
  12. #include <string.h>
  13. #include <sys/ioctl.h>
  14. #include <sys/param.h> /* defines BSD */
  15. #include <sys/socket.h>
  16. #include <sys/stat.h>
  17. #include <sys/types.h>
  18. #include <unistd.h>
  19. #ifdef HAVE_SYS_SYSMACROS_H
  20. #include <sys/sysmacros.h> /* defines major() */
  21. #endif /* HAVE_SYS_SYSMACROS_H */
  22. #ifdef ENABLE_BLUEZ
  23. #include <bluetooth/bluetooth.h>
  24. #include <bluetooth/hci.h>
  25. #include <bluetooth/hci_lib.h>
  26. #include <bluetooth/rfcomm.h>
  27. #endif /* ENABLE_BLUEZ */
  28. #include "compiler.h" // for FALLTHROUGH
  29. #include "gpsd.h"
  30. /* Workaround for HP-UX 11.23, which is missing CRTSCTS */
  31. #ifndef CRTSCTS
  32. # ifdef CNEW_RTSCTS
  33. # define CRTSCTS CNEW_RTSCTS
  34. # else
  35. # define CRTSCTS 0
  36. # endif /* CNEW_RTSCTS */
  37. #endif /* !CRTSCTS */
  38. static sourcetype_t gpsd_classify(const char *path)
  39. /* figure out what kind of device we're looking at */
  40. {
  41. struct stat sb;
  42. if (stat(path, &sb) == -1)
  43. return source_unknown;
  44. else if (S_ISREG(sb.st_mode))
  45. return source_blockdev;
  46. /* this assumes we won't get UDP from a filesystem socket */
  47. else if (S_ISSOCK(sb.st_mode))
  48. return source_tcp;
  49. /* OS-independent check for ptys using Unix98 naming convention */
  50. else if (strncmp(path, "/dev/pts/", 9) == 0)
  51. return source_pty;
  52. else if (strncmp(path, "/dev/pps", 8) == 0)
  53. return source_pps;
  54. else if (S_ISFIFO(sb.st_mode))
  55. return source_pipe;
  56. else if (S_ISCHR(sb.st_mode)) {
  57. sourcetype_t devtype = source_rs232;
  58. #ifdef __linux__
  59. /* Linux major device numbers live here
  60. *
  61. * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/admin-guide/devices.txt
  62. *
  63. * Note: This code works because Linux major device numbers are
  64. * stable and architecture-independent. It is *not* a good model
  65. * for other Unixes where either or both assumptions may break.
  66. */
  67. int devmajor = major(sb.st_rdev);
  68. /* 207 are Freescale i.MX UARTs (ttymxc*) */
  69. if (devmajor == 4 || devmajor == 204 || devmajor == 207)
  70. devtype = source_rs232;
  71. else if (devmajor == 188 || devmajor == 166)
  72. devtype = source_usb;
  73. else if (devmajor == 216 || devmajor == 217)
  74. devtype = source_bluetooth;
  75. else if (devmajor == 3 || (devmajor >= 136 && devmajor <= 143))
  76. devtype = source_pty;
  77. #endif /* __linux__ */
  78. /*
  79. * See http://nadeausoftware.com/articles/2012/01/c_c_tip_how_use_compiler_predefined_macros_detect_operating_system
  80. * for discussion how this works. Key graphs:
  81. *
  82. * Compilers for the old BSD base for these distributions
  83. * defined the __bsdi__ macro, but none of these distributions
  84. * define it now. This leaves no generic "BSD" macro defined
  85. * by the compiler itself, but all UNIX-style OSes provide a
  86. * <sys/param.h> file. On BSD distributions, and only on BSD
  87. * distributions, this file defines a BSD macro that's set to
  88. * the OS version. Checking for this generic macro is more
  89. * robust than looking for known BSD distributions with
  90. * __DragonFly__, __FreeBSD__, __NetBSD__, and __OpenBSD__
  91. * macros.
  92. *
  93. * Apple's OSX for the Mac and iOS for iPhones and iPads are
  94. * based in part on a fork of FreeBSD distributed as
  95. * Darwin. As such, OSX and iOS also define the BSD macro
  96. * within <sys/param.h>. However, compilers for OSX, iOS, and
  97. * Darwin do not define __unix__. To detect all BSD OSes,
  98. * including OSX, iOS, and Darwin, use an #if/#endif that
  99. * checks for __unix__ along with __APPLE__ and __MACH__ (see
  100. * the later section on OSX and iOS).
  101. */
  102. #ifdef BSD
  103. /*
  104. * Hacky check for pty, which is what really matters for avoiding
  105. * adaptive delay.
  106. */
  107. if (strncmp(path, "/dev/ttyp", 9) == 0 ||
  108. strncmp(path, "/dev/ttyq", 9) == 0)
  109. devtype = source_pty;
  110. else if (strncmp(path, "/dev/ttyU", 9) == 0 ||
  111. strncmp(path, "/dev/dtyU", 9) == 0)
  112. devtype = source_usb;
  113. /* XXX bluetooth */
  114. #endif /* BSD */
  115. return devtype;
  116. } else
  117. return source_unknown;
  118. }
  119. #ifdef __linux__
  120. /* return true if any process has the specified path open */
  121. static int fusercount(const char *path)
  122. {
  123. DIR *procd, *fdd;
  124. struct dirent *procentry, *fdentry;
  125. char procpath[GPS_PATH_MAX], fdpath[GPS_PATH_MAX], linkpath[GPS_PATH_MAX];
  126. int cnt = 0;
  127. if (NULL == (procd = opendir("/proc")))
  128. return -1;
  129. while (NULL != (procentry = readdir(procd))) {
  130. if (0 == isdigit(procentry->d_name[0]))
  131. continue;
  132. /* longest procentry->d_name I could find was 12 */
  133. (void)snprintf(procpath, sizeof(procpath),
  134. "/proc/%.20s/fd/", procentry->d_name);
  135. if (NULL == (fdd = opendir(procpath)))
  136. continue;
  137. while (NULL != (fdentry = readdir(fdd))) {
  138. ssize_t rd;
  139. (void)strlcpy(fdpath, procpath, sizeof(fdpath));
  140. (void)strlcat(fdpath, fdentry->d_name, sizeof(fdpath));
  141. // readlink does not NUL terminate.
  142. rd = readlink(fdpath, linkpath, sizeof(linkpath) - 1);
  143. if (0 > rd)
  144. continue;
  145. // pacify coverity by setting NUL
  146. linkpath[rd] = '\0';
  147. if (0 == strcmp(linkpath, path)) {
  148. ++cnt;
  149. }
  150. }
  151. (void)closedir(fdd);
  152. }
  153. (void)closedir(procd);
  154. return cnt;
  155. }
  156. #endif /* __linux__ */
  157. void gpsd_tty_init(struct gps_device_t *session)
  158. /* to be called on allocating a device */
  159. {
  160. /* mark GPS fd closed and its baud rate unknown */
  161. session->gpsdata.gps_fd = -1;
  162. session->saved_baud = -1;
  163. session->zerokill = false;
  164. session->reawake = (time_t)0;
  165. }
  166. #if !defined(HAVE_CFMAKERAW)
  167. /*
  168. * Local implementation of cfmakeraw (which is not specified by
  169. * POSIX; see matching declaration in gpsd.h).
  170. */
  171. /* Pasted from man page; added in serial.c arbitrarily */
  172. void cfmakeraw(struct termios *termios_p)
  173. {
  174. termios_p->c_iflag &=
  175. ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
  176. termios_p->c_oflag &= ~OPOST;
  177. termios_p->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
  178. termios_p->c_cflag &= ~(CSIZE | PARENB);
  179. termios_p->c_cflag |= CS8;
  180. }
  181. #endif /* !defined(HAVE_CFMAKERAW) */
  182. static speed_t gpsd_get_speed_termios(const struct termios *ttyctl)
  183. {
  184. speed_t code = cfgetospeed(ttyctl);
  185. switch (code) {
  186. case B300:
  187. return (300);
  188. case B1200:
  189. return (1200);
  190. case B2400:
  191. return (2400);
  192. case B4800:
  193. return (4800);
  194. case B9600:
  195. return (9600);
  196. case B19200:
  197. return (19200);
  198. case B38400:
  199. return (38400);
  200. case B57600:
  201. return (57600);
  202. case B115200:
  203. return (115200);
  204. case B230400:
  205. return (230400);
  206. default: /* B0 */
  207. return 0;
  208. }
  209. }
  210. speed_t gpsd_get_speed(const struct gps_device_t *dev)
  211. {
  212. return gpsd_get_speed_termios(&dev->ttyset);
  213. }
  214. speed_t gpsd_get_speed_old(const struct gps_device_t *dev)
  215. {
  216. return gpsd_get_speed_termios(&dev->ttyset_old);
  217. }
  218. char gpsd_get_parity(const struct gps_device_t *dev)
  219. {
  220. char parity = 'N';
  221. if ((dev->ttyset.c_cflag & (PARENB | PARODD)) == (PARENB | PARODD))
  222. parity = 'O';
  223. else if ((dev->ttyset.c_cflag & PARENB) == PARENB)
  224. parity = 'E';
  225. return parity;
  226. }
  227. int gpsd_get_stopbits(const struct gps_device_t *dev)
  228. {
  229. int stopbits = 0;
  230. if ((dev->ttyset.c_cflag & CS8) == CS8)
  231. stopbits = 1;
  232. else if ((dev->ttyset.c_cflag & (CS7 | CSTOPB)) == (CS7 | CSTOPB))
  233. stopbits = 2;
  234. return stopbits;
  235. }
  236. bool gpsd_set_raw(struct gps_device_t * session)
  237. {
  238. (void)cfmakeraw(&session->ttyset);
  239. if (-1 == tcsetattr(session->gpsdata.gps_fd, TCIOFLUSH, &session->ttyset)) {
  240. GPSD_LOG(LOG_ERROR, &session->context->errout,
  241. "SER: error changing port attributes: %s\n", strerror(errno));
  242. return false;
  243. }
  244. return true;
  245. }
  246. void gpsd_set_speed(struct gps_device_t *session,
  247. speed_t speed, char parity, unsigned int stopbits)
  248. {
  249. speed_t rate;
  250. struct timespec delay;
  251. if (0 < session->context->fixed_port_speed) {
  252. speed = session->context->fixed_port_speed;
  253. }
  254. if ('\0' != session->context->fixed_port_framing[0]) {
  255. // ignore length, stopbits=2 forces length 7.
  256. parity = session->context->fixed_port_framing[1];
  257. stopbits = session->context->fixed_port_framing[2] - '0';
  258. }
  259. /*
  260. * Yes, you can set speeds that aren't in the hunt loop. If you
  261. * do this, and you aren't on Linux where baud rate is preserved
  262. * across port closings, you've screwed yourself. Don't do that!
  263. */
  264. if (speed < 300)
  265. rate = B0;
  266. else if (speed < 1200)
  267. rate = B300;
  268. else if (speed < 2400)
  269. rate = B1200;
  270. else if (speed < 4800)
  271. rate = B2400;
  272. else if (speed < 9600)
  273. rate = B4800;
  274. else if (speed < 19200)
  275. rate = B9600;
  276. else if (speed < 38400)
  277. rate = B19200;
  278. else if (speed < 57600)
  279. rate = B38400;
  280. else if (speed < 115200)
  281. rate = B57600;
  282. else if (speed < 230400)
  283. rate = B115200;
  284. else
  285. rate = B230400;
  286. /* backward-compatibility hack */
  287. switch (parity) {
  288. case 'E':
  289. FALLTHROUGH
  290. case (char)2:
  291. parity = 'E';
  292. break;
  293. case 'O':
  294. FALLTHROUGH
  295. case (char)1:
  296. parity = 'O';
  297. break;
  298. case 'N':
  299. FALLTHROUGH
  300. case (char)0:
  301. FALLTHROUGH
  302. default:
  303. parity = 'N'; /* without this we might emit malformed JSON */
  304. break;
  305. }
  306. if (rate != cfgetispeed(&session->ttyset)
  307. || parity != session->gpsdata.dev.parity
  308. || stopbits != session->gpsdata.dev.stopbits) {
  309. /*
  310. * Don't mess with this conditional! Speed zero is supposed to mean
  311. * to leave the port speed at whatever it currently is. This leads
  312. * to excellent behavior on Linux, which preserves baudrate across
  313. * serial device closes - it means that if you've opened this
  314. * device before you typically don't have to hunt at all because
  315. * it's still at the same speed you left it - you'll typically
  316. * get packet lock within 1.5 seconds. Alas, the BSDs and OS X
  317. * aren't so nice.
  318. */
  319. if (rate != B0) {
  320. (void)cfsetispeed(&session->ttyset, rate);
  321. (void)cfsetospeed(&session->ttyset, rate);
  322. }
  323. session->ttyset.c_iflag &= ~(PARMRK | INPCK);
  324. session->ttyset.c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD);
  325. session->ttyset.c_cflag |= (stopbits == 2 ? CS7 | CSTOPB : CS8);
  326. switch (parity) {
  327. case 'E':
  328. session->ttyset.c_iflag |= INPCK;
  329. session->ttyset.c_cflag |= PARENB;
  330. break;
  331. case 'O':
  332. session->ttyset.c_iflag |= INPCK;
  333. session->ttyset.c_cflag |= PARENB | PARODD;
  334. break;
  335. }
  336. if (0 != tcsetattr(session->gpsdata.gps_fd, TCSANOW,
  337. &session->ttyset)) {
  338. /* strangely this fails on non-serial ports, but if
  339. * we do not try, we get other failures.
  340. * so ignore for now, as we always have, until it can
  341. * be nailed down.
  342. *
  343. * GPSD_LOG(&session->context->errout, LOG_ERROR,
  344. * "SER: error setting port attributes: %s, sourcetype: %d\n",
  345. * strerror(errno), session->sourcetype);
  346. * return;
  347. */
  348. }
  349. /*
  350. * Serious black magic begins here. Getting this code wrong can cause
  351. * failures to lock to a correct speed, and not clean reproducible
  352. * failures but flukey hardware- and timing-dependent ones. So
  353. * be very sure you know what you're doing before hacking it, and
  354. * test thoroughly.
  355. *
  356. * The fundamental problem here is that serial devices take time
  357. * to settle into a new baud rate after tcsetattr() is issued. Until
  358. * they do so, input will be arbitrarily garbled. Normally this
  359. * is not a big problem, but in our hunt loop the garbling can trash
  360. * a long enough prefix of each sample to prevent detection of a
  361. * packet header. We could address the symptom by making the sample
  362. * size enough larger that subtracting the maximum length of garble
  363. * would still leave a sample longer than the maximum packet size.
  364. * But it's better (and more efficient) to address the disease.
  365. *
  366. * In theory, one might think that not even a tcflush() call would
  367. * be needed, with tcsetattr() delaying its return until the device
  368. * is in a good state. For simple devices like a 14550 UART that
  369. * have fixed response timings this may even work, if the driver
  370. * writer was smart enough to delay the return by the right number
  371. * of milliseconds after poking the device port(s).
  372. *
  373. * Problems may arise if the driver's timings are off. Or we may
  374. * be talking to a USB device like the pl2303 commonly used in GPS
  375. * mice; on these, the change will not happen immediately because
  376. * it has to be sent as a message to the external processor that
  377. * has to act upon it, and that processor may still have buffered
  378. * data in its own FIFO. In this case the expected delay may be
  379. * too large and too variable (depending on the details of how the
  380. * USB device is integrated with its symbiont hardware) to be put
  381. * in the driver.
  382. *
  383. * So, somehow, we have to introduce a delay after tcsatattr()
  384. * returns sufficient to allow *any* device to settle. On the other
  385. * hand, a really long delay will make gpsd device registration
  386. * unpleasantly laggy.
  387. *
  388. * The classic way to address this is with a tcflush(), counting
  389. * on it to clear the device FIFO. But that call may clear only the
  390. * kernel buffers, not the device's hardware FIFO, so it may not
  391. * be sufficient by itself.
  392. *
  393. * flush followed by a 200-millisecond delay followed by flush has
  394. * been found to work reliably on the pl2303. It is also known
  395. * from testing that a 100-millisec delay is too short, allowing
  396. * occasional failure to lock.
  397. */
  398. (void)tcflush(session->gpsdata.gps_fd, TCIOFLUSH);
  399. /* wait 200,000 uSec */
  400. delay.tv_sec = 0;
  401. delay.tv_nsec = 200000000L;
  402. nanosleep(&delay, NULL);
  403. (void)tcflush(session->gpsdata.gps_fd, TCIOFLUSH);
  404. }
  405. GPSD_LOG(LOG_INF, &session->context->errout,
  406. "SER: speed %lu, %d%c%d\n",
  407. (unsigned long)gpsd_get_speed(session), 9 - stopbits, parity,
  408. stopbits);
  409. session->gpsdata.dev.baudrate = (unsigned int)speed;
  410. session->gpsdata.dev.parity = parity;
  411. session->gpsdata.dev.stopbits = stopbits;
  412. /*
  413. * The device might need a wakeup string before it will send data.
  414. * If we don't know the device type, ship it every driver's wakeup
  415. * in hopes it will respond. But not to USB or Bluetooth, because
  416. * shipping probe strings to unknown USB serial adaptors or
  417. * Bluetooth devices may spam devices that aren't GPSes at all and
  418. * could become confused.
  419. */
  420. if (!session->context->readonly
  421. && session->sourcetype != source_usb
  422. && session->sourcetype != source_bluetooth) {
  423. if (isatty(session->gpsdata.gps_fd) != 0
  424. && !session->context->readonly) {
  425. if (session->device_type == NULL) {
  426. const struct gps_type_t **dp;
  427. for (dp = gpsd_drivers; *dp; dp++)
  428. if ((*dp)->event_hook != NULL)
  429. (*dp)->event_hook(session, event_wakeup);
  430. } else if (session->device_type->event_hook != NULL)
  431. session->device_type->event_hook(session, event_wakeup);
  432. }
  433. }
  434. packet_reset(&session->lexer);
  435. }
  436. /* open a device for access to its data
  437. * return: the opened file descriptor
  438. * PLACEHOLDING_FD - for /dev/ppsX
  439. * UNALLOCATED_FD - for open failure
  440. */
  441. int gpsd_serial_open(struct gps_device_t *session)
  442. {
  443. mode_t mode = (mode_t) O_RDWR;
  444. session->sourcetype = gpsd_classify(session->gpsdata.dev.path);
  445. session->servicetype = service_sensor;
  446. /* we may need to hold on to this slot without opening the device */
  447. if (source_pps == session->sourcetype) {
  448. (void)gpsd_switch_driver(session, "PPS");
  449. return PLACEHOLDING_FD;
  450. }
  451. if (session->context->readonly
  452. || (session->sourcetype <= source_blockdev)) {
  453. mode = (mode_t) O_RDONLY;
  454. GPSD_LOG(LOG_INF, &session->context->errout,
  455. "SER: opening read-only GPS data source type %d and at '%s'\n",
  456. (int)session->sourcetype, session->gpsdata.dev.path);
  457. } else {
  458. GPSD_LOG(LOG_INF, &session->context->errout,
  459. "SER: opening GPS data source type %d at '%s'\n",
  460. (int)session->sourcetype, session->gpsdata.dev.path);
  461. }
  462. #ifdef ENABLE_BLUEZ
  463. if (bachk(session->gpsdata.dev.path) == 0) {
  464. struct sockaddr_rc addr = { 0, *BDADDR_ANY, 0};
  465. session->gpsdata.gps_fd = socket(AF_BLUETOOTH,
  466. SOCK_STREAM,
  467. BTPROTO_RFCOMM);
  468. if (0 > session->gpsdata.gps_fd) {
  469. GPSD_LOG(LOG_ERROR, &session->context->errout,
  470. "SER: bluetooth socket() failed: %s\n",
  471. strerror(errno));
  472. return UNALLOCATED_FD;
  473. }
  474. addr.rc_family = AF_BLUETOOTH;
  475. addr.rc_channel = (uint8_t) 1;
  476. (void) str2ba(session->gpsdata.dev.path, &addr.rc_bdaddr);
  477. if (-1 == connect(session->gpsdata.gps_fd,
  478. (struct sockaddr *) &addr,
  479. sizeof (addr))) {
  480. if (errno != EINPROGRESS && errno != EAGAIN) {
  481. (void)close(session->gpsdata.gps_fd);
  482. GPSD_LOG(LOG_ERROR, &session->context->errout,
  483. "SER: bluetooth socket connect failed: %s\n",
  484. strerror(errno));
  485. return UNALLOCATED_FD;
  486. }
  487. GPSD_LOG(LOG_ERROR, &session->context->errout,
  488. "SER: bluetooth socket connect in progress or "
  489. "EAGAIN: %s\n",
  490. strerror(errno));
  491. }
  492. (void)fcntl(session->gpsdata.gps_fd, F_SETFL, (int)mode);
  493. GPSD_LOG(LOG_PROG, &session->context->errout,
  494. "SER: bluez device open success: %s %s\n",
  495. session->gpsdata.dev.path, strerror(errno));
  496. } else
  497. #endif /* BLUEZ */
  498. {
  499. /*
  500. * We open with O_NONBLOCK because we want to not get hung if
  501. * the CLOCAL flag is off. Need to keep O_NONBLOCK so the main
  502. * loop does not clock on an unresponsive read() from a receiver.
  503. */
  504. errno = 0;
  505. if ((session->gpsdata.gps_fd =
  506. open(session->gpsdata.dev.path,
  507. (int)(mode | O_NONBLOCK | O_NOCTTY))) == -1) {
  508. GPSD_LOG(LOG_ERROR, &session->context->errout,
  509. "SER: device open of %s failed: %s - "
  510. "retrying read-only\n",
  511. session->gpsdata.dev.path,
  512. strerror(errno));
  513. if ((session->gpsdata.gps_fd =
  514. open(session->gpsdata.dev.path,
  515. O_RDONLY | O_NONBLOCK | O_NOCTTY)) == -1) {
  516. GPSD_LOG(LOG_ERROR, &session->context->errout,
  517. "SER: read-only device open of %s failed: %s\n",
  518. session->gpsdata.dev.path,
  519. strerror(errno));
  520. return UNALLOCATED_FD;
  521. }
  522. GPSD_LOG(LOG_PROG, &session->context->errout,
  523. "SER: file device open of %s succeeded\n",
  524. session->gpsdata.dev.path);
  525. }
  526. }
  527. /*
  528. * Ideally we want to exclusion-lock the device before doing any reads.
  529. * It would have been best to do this at open(2) time, but O_EXCL
  530. * doesn't work without O_CREAT.
  531. *
  532. * We have to make an exception for ptys, which are intentionally
  533. * opened by another process on the master side, otherwise we'll
  534. * break all our regression tests.
  535. *
  536. * We also exclude bluetooth device because the bluetooth daemon opens them.
  537. */
  538. if (!(session->sourcetype == source_pty ||
  539. session->sourcetype == source_bluetooth)) {
  540. #ifdef TIOCEXCL
  541. /*
  542. * Try to block other processes from using this device while we
  543. * have it open (later opens should return EBUSY). Won't work
  544. * against anything with root privileges, alas.
  545. */
  546. (void)ioctl(session->gpsdata.gps_fd, (unsigned long)TIOCEXCL);
  547. #endif /* TIOCEXCL */
  548. #ifdef __linux__
  549. /*
  550. * Don't touch devices already opened by another process.
  551. */
  552. if (fusercount(session->gpsdata.dev.path) > 1) {
  553. GPSD_LOG(LOG_ERROR, &session->context->errout,
  554. "SER: %s already opened by another process\n",
  555. session->gpsdata.dev.path);
  556. (void)close(session->gpsdata.gps_fd);
  557. session->gpsdata.gps_fd = UNALLOCATED_FD;
  558. return UNALLOCATED_FD;
  559. }
  560. #endif /* __linux__ */
  561. }
  562. if (0 < session->context->fixed_port_speed) {
  563. session->saved_baud = session->context->fixed_port_speed;
  564. }
  565. if (session->saved_baud != -1) {
  566. (void)cfsetispeed(&session->ttyset, (speed_t)session->saved_baud);
  567. (void)cfsetospeed(&session->ttyset, (speed_t)session->saved_baud);
  568. if (0 != tcsetattr(session->gpsdata.gps_fd, TCSANOW,
  569. &session->ttyset)) {
  570. GPSD_LOG(LOG_ERROR, &session->context->errout,
  571. "SER: Error setting port attributes: %s\n",
  572. strerror(errno));
  573. }
  574. (void)tcflush(session->gpsdata.gps_fd, TCIOFLUSH);
  575. }
  576. session->lexer.type = BAD_PACKET;
  577. if ( 0 != isatty(session->gpsdata.gps_fd) ) {
  578. speed_t new_speed;
  579. char new_parity; // E, N, O
  580. unsigned int new_stop;
  581. /* Save original terminal parameters */
  582. if (tcgetattr(session->gpsdata.gps_fd, &session->ttyset_old) != 0)
  583. return UNALLOCATED_FD;
  584. session->ttyset = session->ttyset_old;
  585. /* twiddle the speed, parity, etc. but only on real serial ports */
  586. memset(session->ttyset.c_cc, 0, sizeof(session->ttyset.c_cc));
  587. //session->ttyset.c_cc[VTIME] = 1;
  588. /*
  589. * Tip from Chris Kuethe: the FIDI chip used in the Trip-Nav
  590. * 200 (and possibly other USB GPSes) gets completely hosed
  591. * in the presence of flow control. Thus, turn off CRTSCTS.
  592. *
  593. * This is not ideal. Setting no parity here will mean extra
  594. * initialization time for some devices, like certain Trimble
  595. * boards, that want 7O2 or other non-8N1 settings. But starting
  596. * the hunt loop at 8N1 will minimize the average sync time
  597. * over all devices.
  598. */
  599. session->ttyset.c_cflag &= ~(PARENB | PARODD | CRTSCTS | CSTOPB);
  600. session->ttyset.c_cflag |= CREAD | CLOCAL;
  601. session->ttyset.c_iflag = session->ttyset.c_oflag =
  602. session->ttyset.c_lflag = (tcflag_t) 0;
  603. session->baudindex = 0;
  604. if (0 < session->context->fixed_port_speed) {
  605. new_speed = session->context->fixed_port_speed;
  606. } else {
  607. new_speed = gpsd_get_speed_old(session);
  608. }
  609. if ('\0' == session->context->fixed_port_framing[0]) {
  610. new_parity = 'N';
  611. new_stop = 1;
  612. } else {
  613. // ignore length, stopbits=2 forces length 7.
  614. new_parity = session->context->fixed_port_framing[1];
  615. new_stop = session->context->fixed_port_framing[2] - '0';
  616. }
  617. gpsd_set_speed(session, new_speed, new_parity, new_stop);
  618. }
  619. /* Used to turn off O_NONBLOCK here, but best not to block trying
  620. * to read from an unresponsive receiver. */
  621. /* required so parity field won't be '\0' if saved speed matches */
  622. if (session->sourcetype <= source_blockdev) {
  623. session->gpsdata.dev.parity = 'N';
  624. session->gpsdata.dev.stopbits = 1;
  625. }
  626. GPSD_LOG(LOG_SPIN, &session->context->errout,
  627. "SER: open(%s) -> %d in gpsd_serial_open()\n",
  628. session->gpsdata.dev.path, session->gpsdata.gps_fd);
  629. return session->gpsdata.gps_fd;
  630. }
  631. ssize_t gpsd_serial_write(struct gps_device_t * session,
  632. const char *buf, const size_t len)
  633. {
  634. ssize_t status;
  635. bool ok;
  636. if (session == NULL ||
  637. session->context == NULL || session->context->readonly)
  638. return 0;
  639. status = write(session->gpsdata.gps_fd, buf, len);
  640. ok = (status == (ssize_t) len);
  641. (void)tcdrain(session->gpsdata.gps_fd);
  642. /* extra guard prevents expensive hexdump calls */
  643. if (session->context->errout.debug >= LOG_IO) {
  644. char scratchbuf[MAX_PACKET_LENGTH*2+1];
  645. GPSD_LOG(LOG_IO, &session->context->errout,
  646. "SER: => GPS: %s%s\n",
  647. gpsd_packetdump(scratchbuf, sizeof(scratchbuf),
  648. (char *)buf, len), ok ? "" : " FAILED");
  649. }
  650. return status;
  651. }
  652. /*
  653. * This constant controls how long the packet sniffer will spend looking
  654. * for a packet leader before it gives up. It *must* be larger than
  655. * MAX_PACKET_LENGTH or we risk never syncing up at all. Large values
  656. * will produce annoying startup lag.
  657. */
  658. #define SNIFF_RETRIES (MAX_PACKET_LENGTH + 128)
  659. /* advance to the next hunt setting */
  660. bool gpsd_next_hunt_setting(struct gps_device_t * session)
  661. {
  662. /* every rate we're likely to see on an old GPS */
  663. // FIXME add new rates
  664. static unsigned int rates[] =
  665. {0, 4800, 9600, 19200, 38400, 57600, 115200, 230400};
  666. char new_parity; // E, N, O
  667. unsigned int new_stop;
  668. /* don't waste time in the hunt loop if this is not actually a tty */
  669. if (0 == isatty(session->gpsdata.gps_fd))
  670. return false;
  671. /* ...or if it's nominally a tty but delivers only PPS and no data */
  672. if (session->sourcetype == source_pps)
  673. return false;
  674. if (session->lexer.retry_counter++ >= SNIFF_RETRIES) {
  675. if (0 < session->context->fixed_port_speed) {
  676. // fixed speed, don't hunt
  677. // this prevents framing hunt?
  678. return false;
  679. }
  680. if (session->baudindex++ >=
  681. (unsigned int)(sizeof(rates) / sizeof(rates[0])) - 1) {
  682. session->baudindex = 0;
  683. if ('\0' != session->context->fixed_port_framing[0]) {
  684. return false; /* hunt is over, no sync */
  685. }
  686. // More stop bits to try?
  687. if (session->gpsdata.dev.stopbits++ >= 2) {
  688. return false; /* hunt is over, no sync */
  689. }
  690. }
  691. if ('\0' == session->context->fixed_port_framing[0]) {
  692. new_parity = session->gpsdata.dev.parity;
  693. new_stop = session->gpsdata.dev.stopbits;
  694. } else {
  695. // ignore length, stopbits=2 forces length 7.
  696. new_parity = session->context->fixed_port_framing[1];
  697. new_stop = session->context->fixed_port_framing[2] - '0';
  698. }
  699. gpsd_set_speed(session, rates[session->baudindex], new_parity,
  700. new_stop);
  701. session->lexer.retry_counter = 0;
  702. }
  703. return true; /* keep hunting */
  704. }
  705. /* to be called when we want to register that we've synced with a device */
  706. void gpsd_assert_sync(struct gps_device_t *session)
  707. {
  708. /*
  709. * We've achieved first sync with the device. Remember the
  710. * baudrate so we can try it first next time this device
  711. * is opened.
  712. */
  713. if (session->saved_baud == -1)
  714. session->saved_baud = (int)cfgetispeed(&session->ttyset);
  715. }
  716. void gpsd_close(struct gps_device_t *session)
  717. {
  718. if (!BAD_SOCKET(session->gpsdata.gps_fd)) {
  719. #ifdef TIOCNXCL
  720. (void)ioctl(session->gpsdata.gps_fd, (unsigned long)TIOCNXCL);
  721. #endif /* TIOCNXCL */
  722. if (!session->context->readonly)
  723. (void)tcdrain(session->gpsdata.gps_fd);
  724. if (isatty(session->gpsdata.gps_fd) != 0) {
  725. /* force hangup on close on systems that don't do HUPCL properly */
  726. (void)cfsetispeed(&session->ttyset, (speed_t) B0);
  727. (void)cfsetospeed(&session->ttyset, (speed_t) B0);
  728. (void)tcsetattr(session->gpsdata.gps_fd, TCSANOW,
  729. &session->ttyset);
  730. }
  731. /* this is the clean way to do it */
  732. session->ttyset_old.c_cflag |= HUPCL;
  733. /*
  734. * Don't revert the serial parameters if we didn't have to mess with
  735. * them the first time. Economical, and avoids tripping over an
  736. * obscure Linux 2.6 kernel bug that disables threaded
  737. * ioctl(TIOCMIWAIT) on a device after tcsetattr() is called.
  738. */
  739. if ((cfgetispeed(&session->ttyset_old) !=
  740. cfgetispeed(&session->ttyset)) ||
  741. ((session->ttyset_old.c_cflag & CSTOPB) !=
  742. (session->ttyset.c_cflag & CSTOPB))) {
  743. /*
  744. * If we revert, keep the most recent baud rate.
  745. * Cuts down on autobaud overhead the next time.
  746. */
  747. (void)cfsetispeed(&session->ttyset_old,
  748. (speed_t) session->gpsdata.dev.baudrate);
  749. (void)cfsetospeed(&session->ttyset_old,
  750. (speed_t) session->gpsdata.dev.baudrate);
  751. (void)tcsetattr(session->gpsdata.gps_fd, TCSANOW,
  752. &session->ttyset_old);
  753. }
  754. GPSD_LOG(LOG_SPIN, &session->context->errout,
  755. "SER: close(%d) in gpsd_close(%s)\n",
  756. session->gpsdata.gps_fd, session->gpsdata.dev.path);
  757. (void)close(session->gpsdata.gps_fd);
  758. session->gpsdata.gps_fd = -1;
  759. }
  760. }
  761. // vim: set expandtab shiftwidth=4