mirror of
https://github.com/dschmenk/apple2pi.git
synced 2024-11-24 12:31:30 +00:00
Properly support multiple clients
This commit is contained in:
parent
c35c2e78d8
commit
86e09f6aa7
185
src/a2pid.c
185
src/a2pid.c
@ -28,7 +28,7 @@
|
|||||||
#define MAX_XFER 32
|
#define MAX_XFER 32
|
||||||
|
|
||||||
struct a2request {
|
struct a2request {
|
||||||
int fd;
|
int idx;
|
||||||
int type;
|
int type;
|
||||||
int addr;
|
int addr;
|
||||||
int count;
|
int count;
|
||||||
@ -36,7 +36,18 @@ struct a2request {
|
|||||||
char *buffer;
|
char *buffer;
|
||||||
struct a2request *next;
|
struct a2request *next;
|
||||||
} *a2reqlist = NULL, *a2reqfree = NULL;
|
} *a2reqlist = NULL, *a2reqfree = NULL;
|
||||||
|
/*
|
||||||
|
* Client info
|
||||||
|
*/
|
||||||
|
#define CLIENT_OPEN 1
|
||||||
|
#define CLIENT_CLOSING 2
|
||||||
|
#define CLIENT_COUT 4
|
||||||
|
#define MAX_CLIENT 8
|
||||||
|
|
||||||
|
struct {
|
||||||
|
int fd;
|
||||||
|
int flags;
|
||||||
|
} a2client[MAX_CLIENT];
|
||||||
/*
|
/*
|
||||||
* ASCII to scancode conversion
|
* ASCII to scancode conversion
|
||||||
*/
|
*/
|
||||||
@ -451,7 +462,7 @@ void prlog(char *str)
|
|||||||
if (!isdaemon)
|
if (!isdaemon)
|
||||||
puts(str);
|
puts(str);
|
||||||
}
|
}
|
||||||
struct a2request *addreq(int a2fd, int reqfd, int type, int addr, int count, char *buffer)
|
struct a2request *addreq(int a2fd, int clidx, int type, int addr, int count, char *buffer)
|
||||||
{
|
{
|
||||||
char rwchar;
|
char rwchar;
|
||||||
struct a2request *a2req = a2reqfree;
|
struct a2request *a2req = a2reqfree;
|
||||||
@ -459,7 +470,7 @@ struct a2request *addreq(int a2fd, int reqfd, int type, int addr, int count, cha
|
|||||||
a2req = malloc(sizeof(struct a2request));
|
a2req = malloc(sizeof(struct a2request));
|
||||||
else
|
else
|
||||||
a2reqfree = a2reqfree->next;
|
a2reqfree = a2reqfree->next;
|
||||||
a2req->fd = reqfd;
|
a2req->idx = clidx;
|
||||||
a2req->type = type;
|
a2req->type = type;
|
||||||
a2req->addr = addr;
|
a2req->addr = addr;
|
||||||
a2req->count = count;
|
a2req->count = count;
|
||||||
@ -502,13 +513,13 @@ void finreq(int a2fd, int status, int result)
|
|||||||
/*
|
/*
|
||||||
* Send result to socket.
|
* Send result to socket.
|
||||||
*/
|
*/
|
||||||
if (a2req->fd)
|
if (a2client[a2req->idx].flags & CLIENT_OPEN)
|
||||||
{
|
{
|
||||||
if (a2req->type == 0x90) /* read bytes */
|
if (a2req->type == 0x90) /* read bytes */
|
||||||
write(a2req->fd, a2req->buffer, a2req->count);
|
write(a2client[a2req->idx].fd, a2req->buffer, a2req->count);
|
||||||
finbuf[0] = status;
|
finbuf[0] = status;
|
||||||
finbuf[1] = result;
|
finbuf[1] = result;
|
||||||
write(a2req->fd, finbuf, 2);
|
write(a2client[a2req->idx].fd, finbuf, 2);
|
||||||
}
|
}
|
||||||
if (a2req->buffer)
|
if (a2req->buffer)
|
||||||
{
|
{
|
||||||
@ -522,22 +533,24 @@ void finreq(int a2fd, int status, int result)
|
|||||||
a2req->next = a2reqfree;
|
a2req->next = a2reqfree;
|
||||||
a2reqfree = a2req;
|
a2reqfree = a2req;
|
||||||
}
|
}
|
||||||
void flushreqs(int a2fd, int status, int result)
|
void flushreqs(int a2fd, int clidx, int status, int result)
|
||||||
{
|
{
|
||||||
char finbuf[2];
|
char finbuf[2];
|
||||||
struct a2request *a2req;
|
struct a2request *a2req = a2reqlist, *a2reqprev = NULL;
|
||||||
while (a2req = a2reqlist)
|
while (a2req)
|
||||||
|
{
|
||||||
|
if (clidx < 0 || clidx == a2req->idx)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Send result to socket.
|
* Send result to socket.
|
||||||
*/
|
*/
|
||||||
if (a2req->fd)
|
if (a2client[a2req->idx].flags & CLIENT_OPEN)
|
||||||
{
|
{
|
||||||
if (a2req->type == 0x90) /* read bytes */
|
if (a2req->type == 0x90) /* read bytes */
|
||||||
write(a2req->fd, a2req->buffer, a2req->count);
|
write(a2client[a2req->idx].fd, a2req->buffer, a2req->count);
|
||||||
finbuf[0] = status;
|
finbuf[0] = status;
|
||||||
finbuf[1] = result;
|
finbuf[1] = result;
|
||||||
write(a2req->fd, finbuf, 2);
|
write(a2client[a2req->idx].fd, finbuf, 2);
|
||||||
}
|
}
|
||||||
if (a2req->buffer)
|
if (a2req->buffer)
|
||||||
{
|
{
|
||||||
@ -547,9 +560,26 @@ void flushreqs(int a2fd, int status, int result)
|
|||||||
/*
|
/*
|
||||||
* Update lists.
|
* Update lists.
|
||||||
*/
|
*/
|
||||||
|
if (a2req == a2reqlist)
|
||||||
|
{
|
||||||
a2reqlist = a2req->next;
|
a2reqlist = a2req->next;
|
||||||
a2req->next = a2reqfree;
|
a2req->next = a2reqfree;
|
||||||
a2reqfree = a2req;
|
a2reqfree = a2req;
|
||||||
|
a2req = a2reqlist;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
a2reqprev->next = a2req->next;
|
||||||
|
a2req->next = a2reqfree;
|
||||||
|
a2reqfree = a2req;
|
||||||
|
a2req = a2reqprev->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
a2reqprev = a2req;
|
||||||
|
a2req = a2req->next;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void main(int argc, char **argv)
|
void main(int argc, char **argv)
|
||||||
@ -557,8 +587,8 @@ void main(int argc, char **argv)
|
|||||||
struct uinput_user_dev uidev;
|
struct uinput_user_dev uidev;
|
||||||
struct termios oldtio,newtio;
|
struct termios oldtio,newtio;
|
||||||
unsigned char iopkt[16];
|
unsigned char iopkt[16];
|
||||||
int i, c, lastbtn, cout;
|
int i, c, rdycnt;
|
||||||
int a2fd, kbdfd, moufd, srvfd, reqfd, coutfd, maxfd;
|
int a2fd, kbdfd, moufd, srvfd, maxfd;
|
||||||
struct sockaddr_in servaddr;
|
struct sockaddr_in servaddr;
|
||||||
fd_set readset, openset;
|
fd_set readset, openset;
|
||||||
char *devtty = "/dev/ttyAMA0"; /* default for Raspberry Pi */
|
char *devtty = "/dev/ttyAMA0"; /* default for Raspberry Pi */
|
||||||
@ -730,33 +760,43 @@ void main(int argc, char **argv)
|
|||||||
die("error: socket create");
|
die("error: socket create");
|
||||||
if (bind(srvfd,(struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)
|
if (bind(srvfd,(struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)
|
||||||
die("error: bind socket");
|
die("error: bind socket");
|
||||||
if (listen(srvfd, 1) < 0)
|
if (listen(srvfd, MAX_CLIENT - 1) < 0)
|
||||||
die("error: listen socket");
|
die("error: listen socket");
|
||||||
/*
|
/*
|
||||||
* Come basck here on RESET.
|
* Come basck here on RESET.
|
||||||
*/
|
*/
|
||||||
reset:
|
reset:
|
||||||
state = RUN;
|
state = RUN;
|
||||||
cout = -1;
|
for (i = 0; i < MAX_CLIENT; i++)
|
||||||
reqfd = coutfd = 0;
|
{
|
||||||
|
a2client[i].fd = 0;
|
||||||
|
a2client[i].flags = 0;
|
||||||
|
}
|
||||||
|
maxfd = 0;
|
||||||
FD_ZERO(&openset);
|
FD_ZERO(&openset);
|
||||||
FD_SET(a2fd, &openset);
|
FD_SET(a2fd, &openset);
|
||||||
FD_SET(srvfd, &openset);
|
FD_SET(srvfd, &openset);
|
||||||
maxfd = a2fd > srvfd ? a2fd : srvfd;
|
|
||||||
/*
|
/*
|
||||||
* Event loop
|
* Event loop
|
||||||
*/
|
*/
|
||||||
prlog("a2pid: Enter event loop\n");
|
prlog("a2pid: Enter event loop\n");
|
||||||
while (state == RUN)
|
while (state == RUN)
|
||||||
{
|
{
|
||||||
|
if (maxfd == 0)
|
||||||
|
{
|
||||||
|
maxfd = a2fd > srvfd ? a2fd : srvfd;
|
||||||
|
for (i = 0; i < MAX_CLIENT; i++)
|
||||||
|
maxfd = a2client[i].fd > maxfd ? a2client[i].fd : maxfd;
|
||||||
|
}
|
||||||
memcpy(&readset, &openset, sizeof(openset));
|
memcpy(&readset, &openset, sizeof(openset));
|
||||||
if (select(maxfd + 1, &readset, NULL, NULL, NULL) > 0)
|
if ((rdycnt = select(maxfd + 1, &readset, NULL, NULL, NULL)) > 0)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Serial port to Apple II transaction.
|
* Serial port to Apple II transaction.
|
||||||
*/
|
*/
|
||||||
if (FD_ISSET(a2fd, &readset))
|
if (FD_ISSET(a2fd, &readset))
|
||||||
{
|
{
|
||||||
|
rdycnt--;
|
||||||
if (read(a2fd, iopkt, 3) == 3)
|
if (read(a2fd, iopkt, 3) == 3)
|
||||||
{
|
{
|
||||||
// printf("a2pi: A2 Event [0x%02X] [0x%02X] [0x%02X]\n", iopkt[0], iopkt[1], iopkt[2]);
|
// printf("a2pi: A2 Event [0x%02X] [0x%02X] [0x%02X]\n", iopkt[0], iopkt[1], iopkt[2]);
|
||||||
@ -767,7 +807,7 @@ reset:
|
|||||||
iopkt[0] = 0x81; /* acknowledge */
|
iopkt[0] = 0x81; /* acknowledge */
|
||||||
write(a2fd, iopkt, 1);
|
write(a2fd, iopkt, 1);
|
||||||
tcflush(a2fd, TCIFLUSH);
|
tcflush(a2fd, TCIFLUSH);
|
||||||
flushreqs(a2fd, -1, -1);
|
flushreqs(a2fd, 0, -1, -1);
|
||||||
break;
|
break;
|
||||||
case 0x82: /* keyboard event */
|
case 0x82: /* keyboard event */
|
||||||
// printf("Keyboard Event: 0x%02X:%c\n", iopkt[1], iopkt[2] & 0x7F);
|
// printf("Keyboard Event: 0x%02X:%c\n", iopkt[1], iopkt[2] & 0x7F);
|
||||||
@ -866,10 +906,9 @@ reset:
|
|||||||
state = RESET;
|
state = RESET;
|
||||||
break;
|
break;
|
||||||
case 0x98: /* get output char from Apple II */
|
case 0x98: /* get output char from Apple II */
|
||||||
if (coutfd)
|
for (i = 0; i < MAX_CLIENT; i++)
|
||||||
write(coutfd, iopkt, 2);
|
if (a2client[i].flags & CLIENT_COUT)
|
||||||
else
|
write(a2client[i].fd, iopkt, 2);
|
||||||
cout = iopkt[1];
|
|
||||||
break;
|
break;
|
||||||
case 0x9E: /* request complete ok */
|
case 0x9E: /* request complete ok */
|
||||||
case 0x9F: /* request complete error */
|
case 0x9F: /* request complete error */
|
||||||
@ -900,97 +939,107 @@ reset:
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
prlog("a2pid: error read serial port ????\n");
|
prlog("a2pid: error read serial port ????\n");
|
||||||
state = RESET;
|
state = STOP;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* Socket server connection.
|
* Open client connection.
|
||||||
*/
|
*/
|
||||||
if (FD_ISSET(srvfd, &readset))
|
if (FD_ISSET(srvfd, &readset))
|
||||||
{
|
{
|
||||||
reqfd = accept(srvfd, NULL, NULL);
|
rdycnt--;
|
||||||
if (reqfd > 0)
|
int clientfd = accept(srvfd, NULL, NULL);
|
||||||
FD_SET(reqfd, &openset);
|
if (clientfd >= 0)
|
||||||
|
{
|
||||||
|
for (i = 0; i < MAX_CLIENT; i++)
|
||||||
|
{
|
||||||
|
if (a2client[i].flags == 0)
|
||||||
|
{
|
||||||
|
a2client[i].fd = clientfd;
|
||||||
|
a2client[i].flags = CLIENT_OPEN;
|
||||||
|
FD_SET(a2client[i].fd, &openset);
|
||||||
|
maxfd = a2client[i].fd > maxfd ? a2client[i].fd : maxfd;
|
||||||
|
prlog("a2pi: Client Connect\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (i >= MAX_CLIENT)
|
||||||
|
/*
|
||||||
|
* Out of client structures.
|
||||||
|
*/
|
||||||
|
close(clientfd);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
prlog("a2pid: error accept");
|
prlog("a2pid: error accept");
|
||||||
maxfd = reqfd > maxfd ? reqfd : maxfd;
|
|
||||||
prlog("a2pi: Client Connect\n");
|
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* Socket client request.
|
* Socket client request.
|
||||||
*/
|
*/
|
||||||
if (reqfd > 0 && FD_ISSET(reqfd, &readset))
|
for (i = 0; rdycnt > 0 && i < MAX_CLIENT; i++)
|
||||||
|
{
|
||||||
|
if (a2client[i].flags && FD_ISSET(a2client[i].fd, &readset))
|
||||||
{
|
{
|
||||||
int addr, count;
|
int addr, count;
|
||||||
char *databuf;
|
char *databuf;
|
||||||
if (read(reqfd, iopkt, 1) == 1)
|
rdycnt--;
|
||||||
|
if (read(a2client[i].fd, iopkt, 1) == 1)
|
||||||
{
|
{
|
||||||
// printf("a2pi: Client Request [0x%02X]\n", iopkt[0]);
|
// printf("a2pi: Client Request [0x%02X]\n", iopkt[0]);
|
||||||
switch (iopkt[0])
|
switch (iopkt[0])
|
||||||
{
|
{
|
||||||
case 0x90: /* read bytes */
|
case 0x90: /* read bytes */
|
||||||
if (read(reqfd, iopkt, 4) == 4)
|
if (read(a2client[i].fd, iopkt, 4) == 4)
|
||||||
{
|
{
|
||||||
addr = (unsigned char)iopkt[0] | ((unsigned char)iopkt[1] << 8);
|
addr = (unsigned char)iopkt[0] | ((unsigned char)iopkt[1] << 8);
|
||||||
count = (unsigned char)iopkt[2] | ((unsigned char)iopkt[3] << 8);
|
count = (unsigned char)iopkt[2] | ((unsigned char)iopkt[3] << 8);
|
||||||
if (count)
|
if (count)
|
||||||
{
|
{
|
||||||
databuf = malloc(count);
|
databuf = malloc(count);
|
||||||
addreq(a2fd, reqfd, 0x90, addr, count, databuf);
|
addreq(a2fd, i, 0x90, addr, count, databuf);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
iopkt[0] = 0x9E;
|
iopkt[0] = 0x9E;
|
||||||
iopkt[1] = 0x00;
|
iopkt[1] = 0x00;
|
||||||
write(reqfd, iopkt, 2);
|
write(a2client[i].fd, iopkt, 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x92: /* write bytes */
|
case 0x92: /* write bytes */
|
||||||
if (read(reqfd, iopkt, 4) == 4)
|
if (read(a2client[i].fd, iopkt, 4) == 4)
|
||||||
{
|
{
|
||||||
addr = (unsigned char)iopkt[0] | ((unsigned char)iopkt[1] << 8);
|
addr = (unsigned char)iopkt[0] | ((unsigned char)iopkt[1] << 8);
|
||||||
count = (unsigned char)iopkt[2] | ((unsigned char)iopkt[3] << 8);
|
count = (unsigned char)iopkt[2] | ((unsigned char)iopkt[3] << 8);
|
||||||
if (count)
|
if (count)
|
||||||
{
|
{
|
||||||
databuf = malloc(count);
|
databuf = malloc(count);
|
||||||
if (read(reqfd, databuf, count) == count)
|
if (read(a2client[i].fd, databuf, count) == count)
|
||||||
addreq(a2fd, reqfd, 0x92, addr, count, databuf);
|
addreq(a2fd, i, 0x92, addr, count, databuf);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
iopkt[0] = 0x9E;
|
iopkt[0] = 0x9E;
|
||||||
iopkt[1] = 0x00;
|
iopkt[1] = 0x00;
|
||||||
write(reqfd, iopkt, 2);
|
write(a2client[i].fd, iopkt, 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x94: /* call */
|
case 0x94: /* call */
|
||||||
if (read(reqfd, iopkt, 2) == 2)
|
if (read(a2client[i].fd, iopkt, 2) == 2)
|
||||||
{
|
{
|
||||||
addr = (unsigned char)iopkt[0] | ((unsigned char)iopkt[1] << 8);
|
addr = (unsigned char)iopkt[0] | ((unsigned char)iopkt[1] << 8);
|
||||||
addreq(a2fd, reqfd, 0x94, addr, 0, NULL);
|
addreq(a2fd, i, 0x94, addr, 0, NULL);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x96: /* send input char to Apple II */
|
case 0x96: /* send input char to Apple II */
|
||||||
if (read(reqfd, iopkt, 1) == 1)
|
if (read(a2client[i].fd, iopkt, 1) == 1)
|
||||||
addreq(a2fd, reqfd, 0x96, iopkt[0], 0, NULL);
|
addreq(a2fd, i, 0x96, iopkt[0], 0, NULL);
|
||||||
break;
|
break;
|
||||||
case 0x98: /* get output chars from Apple II */
|
case 0x98: /* get output chars from Apple II */
|
||||||
if (cout >= 0)
|
a2client[i].flags |= CLIENT_COUT;
|
||||||
{
|
|
||||||
iopkt[1] = cout;
|
|
||||||
write(reqfd, iopkt, 2);
|
|
||||||
cout = -1;
|
|
||||||
}
|
|
||||||
coutfd = reqfd;
|
|
||||||
break;
|
break;
|
||||||
case 0xFF: /* close */
|
case 0xFF: /* close */
|
||||||
FD_CLR(reqfd, &openset);
|
a2client[i].flags = CLIENT_CLOSING;
|
||||||
close(reqfd);
|
|
||||||
reqfd = 0;
|
|
||||||
coutfd = 0;
|
|
||||||
maxfd = a2fd > srvfd ? a2fd : srvfd;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
prlog("a2pid: Unknown Request\n");
|
prlog("a2pid: Unknown Request\n");
|
||||||
@ -998,19 +1047,25 @@ reset:
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
FD_CLR(reqfd, &openset);
|
/*
|
||||||
close(reqfd);
|
* Close client socket connection.
|
||||||
reqfd = 0;
|
*/
|
||||||
coutfd = 0;
|
FD_CLR(a2client[i].fd, &openset);
|
||||||
maxfd = a2fd > srvfd ? a2fd : srvfd;
|
close(a2client[i].fd);
|
||||||
prlog("a2pid: error read socket ????");
|
if (a2client[i].fd >= maxfd)
|
||||||
|
maxfd = 0;
|
||||||
|
a2client[i].fd = 0;
|
||||||
|
a2client[i].flags = 0;
|
||||||
|
flushreqs(a2fd, i, -1, -1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
flushreqs(a2fd, -1, -1);
|
}
|
||||||
if (reqfd > 0)
|
flushreqs(a2fd, -1, -1, -1);
|
||||||
close(reqfd);
|
for (i = 0; i < MAX_CLIENT; i++)
|
||||||
|
if (a2client[i].flags)
|
||||||
|
close(a2client[i].fd);
|
||||||
if (state == RESET)
|
if (state == RESET)
|
||||||
goto reset;
|
goto reset;
|
||||||
shutdown(srvfd, SHUT_RDWR);
|
shutdown(srvfd, SHUT_RDWR);
|
||||||
|
Loading…
Reference in New Issue
Block a user