Skip to content

Commit

Permalink
Serial port enumeration working for Linux, but needs more work - see …
Browse files Browse the repository at this point in the history
…senum_primary
  • Loading branch information
stg committed Mar 13, 2013
1 parent b8649d5 commit 6df0dd5
Show file tree
Hide file tree
Showing 4 changed files with 162 additions and 1 deletion.
Binary file modified bin-linux/gui
Binary file not shown.
Binary file removed bin-linux/gui_sdl12
Binary file not shown.
19 changes: 19 additions & 0 deletions bin-linux/ports.rc
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Custom ports for display when clicking EMULATE
#
# DevicePath-1
# DeviceName-1
# DevicePath-2
# DeviceName-2
# ...
# DevicePath-n
# DeviceName-n
#
# Comments and empty lines are only allowed when expecting a device
# path and such a line MUST be immediately followed by a name
#
# Example:
#
# /dev/ttyMyDevice
# My custom serial adapter
# /dev/ttyAnotherDev
# Another serial device
144 changes: 143 additions & 1 deletion lib/src/serial.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,16 @@
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>
#include <dirent.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <libgen.h>
#include <sys/ioctl.h>
#include <linux/serial.h>
#endif

#ifdef _WIN32
Expand Down Expand Up @@ -187,9 +197,141 @@ bool sclose() {
static int h_serial;
static struct termios restore;

static bool senum_primary(void (*fp_enum)(char *name, char *device)) {
// This should probe udev /dev/serial
return false;
}

static bool senum_fallback(void (*fp_enum)(char *name, char *device)) {
const char* sysdir = "/sys/class/tty/";
const char *devprefix = "/dev/";
const char *devsuffix = "/device";
const char *drvsuffix = "/driver";
int n;
struct dirent **namelist;
char* path;
char *device;
struct stat st;
char *devpath;
int ret;
ssize_t link_size;
char *driver;
char *buffer;
size_t buffer_size;
struct serial_struct serinfo;
int fd;
bool add_device;

n = scandir(sysdir, &namelist, NULL, NULL);
if(n >= 0) {
while(n--) {
if(strcmp(namelist[n]->d_name, "..") && strcmp(namelist[n]->d_name, ".")) {
path = malloc(strlen(sysdir) + strlen(namelist[n]->d_name) + 1);
strcpy(path, sysdir);
strcat(path, namelist[n]->d_name);

// Get driver
driver = NULL;
buffer = NULL;
buffer_size = 32;
devpath = malloc(strlen(path) + strlen(devsuffix) + strlen(drvsuffix) + 1);
strcpy(devpath, path);
strcat(devpath, devsuffix);
ret = lstat(devpath, &st);
if(ret == 0 && S_ISLNK(st.st_mode)) {
strcat(devpath, drvsuffix);
do {
if(buffer) free(buffer);
buffer_size <<= 1;
buffer = malloc(buffer_size + 1);
link_size = readlink(devpath, buffer, buffer_size);
} while(link_size > 0 && link_size >= buffer_size);
if(link_size > 0) {
buffer[link_size] = 0;
driver = malloc(strlen(basename(buffer)) + 1);
strcpy(driver, basename(buffer));
}
free(buffer);
}
free(devpath);

// Check if driver exists
if(driver) {
add_device = false;
device = malloc(strlen(devprefix) + strlen(basename(path)) + 1);
strcpy(device, devprefix);
strcat(device, basename(path));
// Check driver type
if(!strcmp(driver, "serial8250")) {
// Probe all serial8250
fd = open(device, O_RDWR | O_NONBLOCK | O_NOCTTY);
if(fd >= 0) {
if (ioctl(fd, TIOCGSERIAL, &serinfo)==0) {
if(serinfo.type != PORT_UNKNOWN) {
add_device = true;
}
}
close(fd);
}
} else {
add_device = true;
}
// Should we add this device?
if(add_device) {
buffer = malloc(strlen(device) + strlen(driver) + 2);
strcpy(buffer, device);
strcat(buffer, " ");
strcat(buffer, driver);
fp_enum(buffer, device);
free(buffer);
}
free(device);
free(driver);
}

free(path);
}
free(namelist[n]);
}
free(namelist);
} else {
return false;
}
return true;
}

// posix - enumerate serial ports
void senum(void (*fp_enum)(char *name, char *device)) {
// TODO:
FILE *f;
char name[1024];
char device[1024];
if(!senum_primary(fp_enum)) {
senum_fallback(fp_enum);
}
// Final fallback, allow users to add ports manually via ports.rc
// This is quick and dirty, does not allow special characters like
// '\n' in filenames and filenames cannot start with '#'
// Comments and empty lines are only allowed when expecting a
// device path and such a line MUST be immediately followed by a name
f = fopen("ports.rc", "r");
if(f) {
while(!feof(f)) {
if(fgets(device, 1024, f)) {
if(strlen(device)) {
if(device[strlen(device) - 1] == '\n') device[strlen(device) - 1] = 0;
}
if(strlen(device)) {
if(device[0] != '#') {
if(fgets(name, 1024, f)) {
if( name[strlen( name) - 1] == '\n') name[strlen( name) - 1] = 0;
fp_enum(name, device);
}
}
}
}
}
fclose(f);
}
}

// posix - open serial port
Expand Down

0 comments on commit 6df0dd5

Please sign in to comment.