int gpsd_serial_open(struct gps_device_t *session) /* open a device for access to its data */ { mode_t mode = (mode_t) O_RDWR; session->sourcetype = gpsd_classify(session->gpsdata.dev.path); session->servicetype = service_sensor; /*@ -boolops -type @*/ if (session->context->readonly || (session->sourcetype <= source_blockdev)) { mode = (mode_t) O_RDONLY; gpsd_report(LOG_INF, "opening read-only GPS data source type %d and at '%s'\n", (int)session->sourcetype, session->gpsdata.dev.path); } else { gpsd_report(LOG_INF, "opening GPS data source type %d at '%s'\n", (int)session->sourcetype, session->gpsdata.dev.path); } /*@ +boolops +type @*/ #ifdef HAVE_BLUEZ if (bachk(session->gpsdata.dev.path) == 0) { session->gpsdata.gps_fd = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); struct sockaddr_rc addr = { 0 }; addr.rc_family = AF_BLUETOOTH; addr.rc_channel = (uint8_t) 1; str2ba(session->gpsdata.dev.path, &addr.rc_bdaddr); if (connect(session->gpsdata.gps_fd, (struct sockaddr *) &addr, sizeof (addr)) == -1) { if (errno != EINPROGRESS && errno != EAGAIN) { gpsd_report(LOG_ERROR, "bluetooth socket connect failed: %s\n", strerror(errno)); return -1; } gpsd_report(LOG_ERROR, "bluetooth socket connect in progress or again : %s\n", strerror(errno)); } (void)fcntl(session->gpsdata.gps_fd, F_SETFL, (int)mode | O_NONBLOCK); gpsd_report(LOG_PROG, "bluez device open success: %s %s\n", session->gpsdata.dev.path, strerror(errno)); } else #endif /* BLUEZ */ { if ((session->gpsdata.gps_fd = open(session->gpsdata.dev.path, (int)(mode | O_NONBLOCK | O_NOCTTY))) == -1) { gpsd_report(LOG_ERROR, "device open failed: %s - retrying read-only\n", strerror(errno)); if ((session->gpsdata.gps_fd = open(session->gpsdata.dev.path, O_RDONLY | O_NONBLOCK | O_NOCTTY)) == -1) { gpsd_report(LOG_ERROR, "read-only device open failed: %s\n", strerror(errno)); return -1; } gpsd_report(LOG_PROG, "file device open success: %s\n", strerror(errno)); } } /* * Ideally we want to exclusion-lock the device before doing any reads. * It would have been best to do this at open(2) time, but O_EXCL * doesn't work wuthout O_CREAT. * * We have to make an exception for ptys, which are intentionally * opened by another process on the master side, otherwise we'll * break all our regression tests. */ if (session->sourcetype != source_pty) { /* * Try to block other processes from using this device while we * have it open (later opens should return EBUSY). Won't work * against anything with root privileges, alas. */ (void)ioctl(session->gpsdata.gps_fd, (unsigned long)TIOCEXCL); #ifdef __linux__ /* * Don't touch devices already opened by another process. */ if (fusercount(session->gpsdata.dev.path) > 1) { gpsd_report(LOG_ERROR, "%s already opened by another process\n", session->gpsdata.dev.path); (void)close(session->gpsdata.gps_fd); session->gpsdata.gps_fd = -1; return -1; } #endif /* __linux__ */ } #ifdef FIXED_PORT_SPEED session->saved_baud = FIXED_PORT_SPEED; #endif if (session->saved_baud != -1) { /*@i@*/ (void) cfsetispeed(&session->ttyset, (speed_t) session->saved_baud); /*@i@*/ (void) cfsetospeed(&session->ttyset, (speed_t) session->saved_baud); (void)tcsetattr(session->gpsdata.gps_fd, TCSANOW, &session->ttyset); (void)tcflush(session->gpsdata.gps_fd, TCIOFLUSH); } session->packet.type = BAD_PACKET; if (isatty(session->gpsdata.gps_fd) != 0) { /* Save original terminal parameters */ if (tcgetattr(session->gpsdata.gps_fd, &session->ttyset_old) != 0) return -1; (void)memcpy(&session->ttyset, &session->ttyset_old, sizeof(session->ttyset)); /* * Only block until we get at least one character, whatever the * third arg of read(2) says. */ /*@ ignore @*/ memset(session->ttyset.c_cc, 0, sizeof(session->ttyset.c_cc)); session->ttyset.c_cc[VMIN] = 1; /*@ end @*/ /* * Tip from Chris Kuethe: the FIDI chip used in the Trip-Nav * 200 (and possibly other USB GPSes) gets completely hosed * in the presence of flow control. Thus, turn off CRTSCTS. */ session->ttyset.c_cflag &= ~(PARENB | PARODD | CRTSCTS); session->ttyset.c_cflag |= CREAD | CLOCAL; session->ttyset.c_iflag = session->ttyset.c_oflag = session->ttyset.c_lflag = (tcflag_t) 0; #ifndef FIXED_PORT_SPEED session->baudindex = 0; #endif /* FIXED_PORT_SPEED */ gpsd_set_speed(session, gpsd_get_speed(&session->ttyset_old), 'N', 1); } gpsd_report(LOG_SPIN, "open(%s) -> %d in gpsd_serial_open()\n", session->gpsdata.dev.path, session->gpsdata.gps_fd); return session->gpsdata.gps_fd; }
int gpsd_serial_open(struct gps_device_t *session) /* open a device for access to its data * return: the opened file descriptor * PLACEHOLDING_FD - for /dev/ppsX * UNALLOCATED_FD - for open failure */ { mode_t mode = (mode_t) O_RDWR; session->sourcetype = gpsd_classify(session->gpsdata.dev.path); session->servicetype = service_sensor; /* we may need to hold on to this slot without opening the device */ if (source_pps == session->sourcetype) { (void)gpsd_switch_driver(session, "PPS"); return PLACEHOLDING_FD; } if (session->context->readonly || (session->sourcetype <= source_blockdev)) { mode = (mode_t) O_RDONLY; gpsd_log(&session->context->errout, LOG_INF, "opening read-only GPS data source type %d and at '%s'\n", (int)session->sourcetype, session->gpsdata.dev.path); } else { gpsd_log(&session->context->errout, LOG_INF, "opening GPS data source type %d at '%s'\n", (int)session->sourcetype, session->gpsdata.dev.path); } #ifdef ENABLE_BLUEZ if (bachk(session->gpsdata.dev.path) == 0) { struct sockaddr_rc addr = { 0, *BDADDR_ANY, 0}; session->gpsdata.gps_fd = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); addr.rc_family = AF_BLUETOOTH; addr.rc_channel = (uint8_t) 1; (void) str2ba(session->gpsdata.dev.path, &addr.rc_bdaddr); if (connect(session->gpsdata.gps_fd, (struct sockaddr *) &addr, sizeof (addr)) == -1) { if (errno != EINPROGRESS && errno != EAGAIN) { (void)close(session->gpsdata.gps_fd); gpsd_log(&session->context->errout, LOG_ERROR, "bluetooth socket connect failed: %s\n", strerror(errno)); return UNALLOCATED_FD; } gpsd_log(&session->context->errout, LOG_ERROR, "bluetooth socket connect in progress or again : %s\n", strerror(errno)); } (void)fcntl(session->gpsdata.gps_fd, F_SETFL, (int)mode); gpsd_log(&session->context->errout, LOG_PROG, "bluez device open success: %s %s\n", session->gpsdata.dev.path, strerror(errno)); } else #endif /* BLUEZ */ { /* * We open with O_NONBLOCK because we want to now get hung if * the clocal flag is off, but we don't want to stay in that mode. */ if ((session->gpsdata.gps_fd = open(session->gpsdata.dev.path, (int)(mode | O_NONBLOCK | O_NOCTTY))) == -1) { gpsd_log(&session->context->errout, LOG_ERROR, "device open of %s failed: %s - retrying read-only\n", session->gpsdata.dev.path, strerror(errno)); if ((session->gpsdata.gps_fd = open(session->gpsdata.dev.path, O_RDONLY | O_NONBLOCK | O_NOCTTY)) == -1) { gpsd_log(&session->context->errout, LOG_ERROR, "read-only device open of %s failed: %s\n", session->gpsdata.dev.path, strerror(errno)); return UNALLOCATED_FD; } gpsd_log(&session->context->errout, LOG_PROG, "file device open of %s succeeded: %s\n", session->gpsdata.dev.path, strerror(errno)); } } /* * Ideally we want to exclusion-lock the device before doing any reads. * It would have been best to do this at open(2) time, but O_EXCL * doesn't work without O_CREAT. * * We have to make an exception for ptys, which are intentionally * opened by another process on the master side, otherwise we'll * break all our regression tests. * * We also exclude bluetooth device because the bluetooth daemon opens them. */ if (!(session->sourcetype == source_pty || session->sourcetype == source_bluetooth)) { #ifdef TIOCEXCL /* * Try to block other processes from using this device while we * have it open (later opens should return EBUSY). Won't work * against anything with root privileges, alas. */ (void)ioctl(session->gpsdata.gps_fd, (unsigned long)TIOCEXCL); #endif /* TIOCEXCL */ #ifdef __linux__ /* * Don't touch devices already opened by another process. */ if (fusercount(session->gpsdata.dev.path) > 1) { gpsd_log(&session->context->errout, LOG_ERROR, "%s already opened by another process\n", session->gpsdata.dev.path); (void)close(session->gpsdata.gps_fd); session->gpsdata.gps_fd = UNALLOCATED_FD; return UNALLOCATED_FD; } #endif /* __linux__ */ } #ifdef FIXED_PORT_SPEED session->saved_baud = FIXED_PORT_SPEED; #endif if (session->saved_baud != -1) { (void)cfsetispeed(&session->ttyset, (speed_t)session->saved_baud); (void)cfsetospeed(&session->ttyset, (speed_t)session->saved_baud); (void)tcsetattr(session->gpsdata.gps_fd, TCSANOW, &session->ttyset); (void)tcflush(session->gpsdata.gps_fd, TCIOFLUSH); } session->lexer.type = BAD_PACKET; if (isatty(session->gpsdata.gps_fd) != 0) { /* Save original terminal parameters */ if (tcgetattr(session->gpsdata.gps_fd, &session->ttyset_old) != 0) return UNALLOCATED_FD; session->ttyset = session->ttyset_old; memset(session->ttyset.c_cc, 0, sizeof(session->ttyset.c_cc)); //session->ttyset.c_cc[VTIME] = 1; /* * Tip from Chris Kuethe: the FIDI chip used in the Trip-Nav * 200 (and possibly other USB GPSes) gets completely hosed * in the presence of flow control. Thus, turn off CRTSCTS. * * This is not ideal. Setting no parity here will mean extra * initialization time for some devices, like certain Trimble * boards, that want 7O2 or other non-8N1 settings. But starting * the hunt loop at 8N1 will minimize the average sync time * over all devices. */ session->ttyset.c_cflag &= ~(PARENB | PARODD | CRTSCTS | CSTOPB); session->ttyset.c_cflag |= CREAD | CLOCAL; session->ttyset.c_iflag = session->ttyset.c_oflag = session->ttyset.c_lflag = (tcflag_t) 0; #ifndef FIXED_PORT_SPEED session->baudindex = 0; #endif /* FIXED_PORT_SPEED */ gpsd_set_speed(session, #ifdef FIXED_PORT_SPEED FIXED_PORT_SPEED, #else gpsd_get_speed_old(session), #endif /* FIXED_PORT_SPEED */ 'N', #ifdef FIXED_STOP_BITS FIXED_STOP_BITS #else 1 #endif /* FIXED_STOP_BITS */ ); } /* Switch back to blocking I/O now that CLOCAL is set. */ { int oldfl = fcntl(session->gpsdata.gps_fd, F_GETFL); if (oldfl != -1) (void)fcntl(session->gpsdata.gps_fd, F_SETFL, oldfl & ~O_NONBLOCK); } /* required so parity field won't be '\0' if saved speed matches */ if (session->sourcetype <= source_blockdev) { session->gpsdata.dev.parity = 'N'; session->gpsdata.dev.stopbits = 1; } gpsd_log(&session->context->errout, LOG_SPIN, "open(%s) -> %d in gpsd_serial_open()\n", session->gpsdata.dev.path, session->gpsdata.gps_fd); return session->gpsdata.gps_fd; }