#include <ctype.h>
#include <time.h>
#include <errno.h>
-#include <alloca.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <sys/time.h>
#include <sys/ioctl.h>
+#if defined(__i386__) || defined(__ia64__) || defined(WIN32) || \
+ (defined(__alpha__) || defined(__alpha)) || \
+ defined(__arm__) || \
+ (defined(__mips__) && defined(__MIPSEL__)) || \
+ defined(__SYMBIAN32__) || \
+ defined(__x86_64__) || \
+ defined(__LITTLE_ENDIAN__)
+#define SBALL_LITTLE_ENDIAN
+#else
+#define SBALL_BIG_ENDIAN
+#endif
+
#define INP_BUF_SZ 256
enum {
short mot[6];
unsigned int keystate;
+ struct termios saved_term;
+ int saved_mstat;
+
int (*parse)(struct sball*, int, char*, int);
};
-static int stty_sball(int fd);
-static int stty_mag(int fd);
+static int stty_sball(struct sball *sb);
+static int stty_mag(struct sball *sb);
+static void stty_save(struct sball *sb);
+static void stty_restore(struct sball *sb);
static int proc_input(struct sball *sb);
return 0;
}
- if(!(sb = malloc(sizeof *sb))) {
+ if(!(sb = calloc(1, sizeof *sb))) {
fprintf(stderr, "sball_open: failed to allocate sball object\n");
goto err;
}
sb->fd = fd;
- sb->flags = 0;
- sb->len = 0;
- if(stty_sball(fd) == -1) {
+ stty_save(sb);
+
+ if(stty_sball(sb) == -1) {
goto err;
}
write(fd, "\r@RESET\r", 8);
}
/* try as a magellan spacemouse */
- if(stty_mag(fd) == -1) {
+ if(stty_mag(sb) == -1) {
goto err;
}
write(fd, "vQ\r", 3);
}
err:
+ stty_restore(sb);
close(fd);
free(sb);
return 0;
void sball_close(struct sball *sb)
{
if(!sb) return;
+
+ stty_restore(sb);
close(sb->fd);
}
return sb->nbuttons;
}
-/* Labtec spaceball: 9600 8n1 XON/XOFF */
-static int stty_sball(int fd)
+/* Labtec spaceball: 9600 8n1 XON/XOFF
+ * Can't use canonical mode to assemble input into lines for the spaceball,
+ * because binary data received for motion events can include newlines which
+ * would be eaten up by the line discipline. Therefore we'll rely on VTIME=1 to
+ * hopefully get more than 1 byte at a time. Alternatively we could request
+ * printable reports, but I don't feel like implementing that.
+ */
+static int stty_sball(struct sball *sb)
{
- int status;
+ int mstat;
struct termios term;
- if(tcgetattr(fd, &term) == -1) {
- perror("sball_open: tcgetattr");
- return -1;
- }
-
+ term = sb->saved_term;
term.c_oflag = 0;
- term.c_lflag = ICANON;
+ term.c_lflag = 0;
term.c_cc[VMIN] = 0;
- term.c_cc[VTIME] = 0;
- term.c_cc[VEOF] = 0;
- term.c_cc[VEOL] = '\r';
- term.c_cc[VEOL2] = 0;
- term.c_cc[VERASE] = 0;
- term.c_cc[VKILL] = 0;
+ term.c_cc[VTIME] = 1;
term.c_cflag = CLOCAL | CREAD | CS8 | HUPCL;
- term.c_iflag = IGNBRK | IGNPAR;
+ term.c_iflag = IGNBRK | IGNPAR | IXON | IXOFF;
cfsetispeed(&term, B9600);
cfsetospeed(&term, B9600);
- if(tcsetattr(fd, TCSANOW, &term) == -1) {
+ if(tcsetattr(sb->fd, TCSAFLUSH, &term) == -1) {
perror("sball_open: tcsetattr");
return -1;
}
+ tcflush(sb->fd, TCIOFLUSH);
- if(ioctl(fd, TIOCMGET, &status) != -1) {
- status |= TIOCM_DTR | TIOCM_RTS;
- ioctl(fd, TIOCMSET, &status);
- }
+ mstat = sb->saved_mstat | TIOCM_DTR | TIOCM_RTS;
+ ioctl(sb->fd, TIOCMGET, &mstat);
return 0;
}
-/* Logicad magellan spacemouse: 9600 8n2 CTS/RTS */
-static int stty_mag(int fd)
+/* Logicad magellan spacemouse: 9600 8n2 CTS/RTS
+ * Since the magellan devices don't seem to send any newlines, we can rely on
+ * canonical mode to feed us nice whole lines at a time.
+ */
+static int stty_mag(struct sball *sb)
{
- int status;
+ int mstat;
struct termios term;
- if(tcgetattr(fd, &term) == -1) {
- perror("sball_open: tcgetattr");
- return -1;
- }
-
+ term = sb->saved_term;
term.c_oflag = 0;
term.c_lflag = ICANON;
term.c_cc[VMIN] = 0;
term.c_cc[VERASE] = 0;
term.c_cc[VKILL] = 0;
- term.c_cflag = CLOCAL | CREAD | CS8 | CSTOPB | HUPCL | CRTSCTS;
+ term.c_cflag = CLOCAL | CREAD | CS8 | CSTOPB | HUPCL;
+#ifdef CCTS_OFLOW
+ term.c_cflag |= CCTS_OFLOW;
+#elif defined(CRTSCTS)
+ term.c_cflag |= CRTSCTS;
+#endif
term.c_iflag = IGNBRK | IGNPAR;
cfsetispeed(&term, B9600);
cfsetospeed(&term, B9600);
- if(tcsetattr(fd, TCSAFLUSH, &term) == -1) {
+ if(tcsetattr(sb->fd, TCSAFLUSH, &term) == -1) {
perror("sball_open: tcsetattr");
return -1;
}
- tcflush(fd, TCIOFLUSH);
+ tcflush(sb->fd, TCIOFLUSH);
- if(ioctl(fd, TIOCMGET, &status) != -1) {
- status |= TIOCM_DTR | TIOCM_RTS;
- ioctl(fd, TIOCMGET, &status);
- }
+ mstat = sb->saved_mstat | TIOCM_DTR | TIOCM_RTS;
+ ioctl(sb->fd, TIOCMGET, &mstat);
return 0;
}
+static void stty_save(struct sball *sb)
+{
+ tcgetattr(sb->fd, &sb->saved_term);
+ ioctl(sb->fd, TIOCMGET, &sb->saved_mstat);
+}
+
+static void stty_restore(struct sball *sb)
+{
+ tcsetattr(sb->fd, TCSAFLUSH, &sb->saved_term);
+ tcflush(sb->fd, TCIOFLUSH);
+ ioctl(sb->fd, TIOCMSET, &sb->saved_mstat);
+}
+
static int proc_input(struct sball *sb)
{
}
#ifndef SBALL_BIG_ENDIAN
+ rd = data;
for(i=0; i<6; i++) {
- data += 2;
- c = data[0];
- data[0] = data[1];
- data[1] = c;
- sb->mot[i] = *(short*)data;
+ rd += 2;
+ c = rd[0];
+ rd[0] = rd[1];
+ rd[1] = c;
}
-#else
- memcpy(sb->mot, data + 2, 12);
#endif
+ memcpy(sb->mot, data + 2, 12);
print_state(sb);
break;
case 'E':
fprintf(stderr, "sball: error:");
for(i=0; i<len; i++) {
- if(isprint(data[i])) {
+ if(isprint((int)data[i])) {
fprintf(stderr, " %c", data[i]);
} else {
fprintf(stderr, " %02xh", (unsigned int)data[i]);