9 #include <sys/select.h>
15 int (*decode)(struct sball *sb, char *line);
18 static int stty_sball(int fd);
19 static int stty_mag(int fd);
21 static int decode_sball(struct sball *sb, char *line);
22 static int decode_mag(struct sball *sb, char *line);
24 static void make_printable(char *buf, int len);
25 static int read_timeout(int fd, char *buf, int bufsz, long tm_usec);
27 struct sball *sball_open(const char *dev)
33 if((fd = open(dev, O_RDWR | O_NOCTTY)) == -1) {
34 fprintf(stderr, "sball_open: failed to open device: %s: %s\n", dev, strerror(errno));
38 if(!(sb = malloc(sizeof *sb))) {
39 fprintf(stderr, "sball_open: failed to allocate sball object\n");
44 if(stty_sball(fd) == -1) {
48 if((sz = read_timeout(fd, buf, sizeof buf - 1, 2000000)) > 0) {
49 /* we got a response, so it's a spaceball */
50 make_printable(buf, sz);
51 printf("Spaceball detected: %s\n", buf);
53 sb->decode = decode_sball;
57 /* try as a magellan spacemouse */
58 if(stty_mag(fd) == -1) {
63 if((sz = read_timeout(fd, buf, sizeof buf - 1, 250000)) > 0) {
64 /* we got a response, it's a magellan spacemouse */
65 make_printable(buf, sz);
66 printf("Magellan SpaceMouse detected: %s\n", buf);
68 sb->decode = decode_mag;
78 void sball_close(struct sball *sb)
85 /* Labtec spaceball: 9600 8n1 XON/XOFF */
86 static int stty_sball(int fd)
90 if(tcgetattr(fd, &term) == -1) {
91 perror("sball_open: tcgetattr");
100 term.c_cflag = CLOCAL | CREAD | CS8 | HUPCL;
101 term.c_iflag = IGNBRK | IGNPAR | IXON | IXOFF;
103 cfsetispeed(&term, B9600);
104 cfsetospeed(&term, B9600);
106 if(tcsetattr(fd, TCSANOW, &term) == -1) {
107 perror("sball_open: tcsetattr");
114 /* Logicad magellan spacemouse: 9600 8n2 CTS/RTS */
115 static int stty_mag(int fd)
119 if(tcgetattr(fd, &term) == -1) {
120 perror("sball_open: tcgetattr");
127 term.c_cc[VTIME] = 1;
129 term.c_cflag = CLOCAL | CREAD | CS8 | CSTOPB | HUPCL | CRTSCTS;
130 term.c_iflag = IGNBRK | IGNPAR | ICRNL;
132 cfsetispeed(&term, B9600);
133 cfsetospeed(&term, B9600);
135 if(tcsetattr(fd, TCSANOW, &term) == -1) {
136 perror("sball_open: tcsetattr");
144 static int decode_sball(struct sball *sb, char *line)
149 static int decode_mag(struct sball *sb, char *line)
154 static void make_printable(char *buf, int len)
159 for(i=0; i<len; i++) {
163 if(*buf == '\n') buf++;
171 static int read_timeout(int fd, char *buf, int bufsz, long tm_usec)
175 struct timeval tv0, tv;
178 if(!buf || bufsz <= 0) return -1;
181 gettimeofday(&tv0, 0);
183 while(sz < bufsz && usec > 0) {
184 tv.tv_sec = usec / 1000000;
185 tv.tv_usec = usec % 1000000;
189 if((res = select(fd + 1, &rdset, 0, 0, &tv)) > 0 && FD_ISSET(fd, &rdset)) {
190 sz += read(fd, buf + sz, bufsz - sz);
192 tm_usec = usec = 128000; /* wait 128ms for the rest of the message to appear */
193 gettimeofday(&tv0, 0);
196 if(res == -1 && (errno == EWOULDBLOCK || errno == EAGAIN)) {
199 gettimeofday(&tv, 0);
200 usec = tm_usec - ((tv.tv_sec - tv0.tv_sec) * 1000000 + (tv.tv_usec - tv0.tv_usec));
203 return sz > 0 ? sz : -1;