- Add an option to change escape character.
- Use CTRL macro. - Make target reset work on telnet port. - Add a key bind to invoke kgdb on the terminal. (experimental)
This commit is contained in:
parent
c00ecb1e06
commit
e5ece23f3a
@ -35,6 +35,7 @@
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl brvwRT1
|
||||
.Op Fl e Ar escape-char
|
||||
.Op Fl h Ar hz
|
||||
.Op Fl C Ar console_port
|
||||
.Op Fl G Ar gdb_port
|
||||
@ -107,13 +108,15 @@ acts as a master device with
|
||||
.Pp
|
||||
Typed characters are normally transmitted directly to
|
||||
.Xr dcons 4 .
|
||||
A tilde
|
||||
.Pq Ql ~
|
||||
appearing as the first character of a line is an escape signal; the
|
||||
A escape character (the default is
|
||||
.Ql ~
|
||||
) appearing as the first character of a line is an escape signal; the
|
||||
following are recognized:
|
||||
.Bl -tag -width ident
|
||||
.It Ic ~.
|
||||
Drop the connection and exit.
|
||||
.It Ic ~^G
|
||||
Invoke kgdb on the terminal on which dconschat is running.
|
||||
.It Ic ~^R
|
||||
Reset the target over FireWire if a reset address is registered in Configuration ROM.
|
||||
.It Ic ~^Z
|
||||
@ -156,6 +159,9 @@ Read available buffer, then exit.
|
||||
This implies the
|
||||
.Fl r
|
||||
option.
|
||||
.It Fl e Ar escape-char
|
||||
Specify escape character.
|
||||
The default is '~'.
|
||||
.It Fl h Ar hz
|
||||
Specify polling rate.
|
||||
The default value is 100.
|
||||
|
@ -78,9 +78,10 @@
|
||||
int verbose = 0;
|
||||
int tc_set = 0;
|
||||
int poll_hz = DCONS_POLL_HZ;
|
||||
static u_char abreak[3] = {13 /* CR */, 126 /* ~ */, 2 /* ^B */};
|
||||
|
||||
#define IS_CONSOLE(p) ((p)->port == 0)
|
||||
#define IS_GDB(p) ((p)->port == 1)
|
||||
#define IS_CONSOLE(p) ((p)->port == DCONS_CON)
|
||||
#define IS_GDB(p) ((p)->port == DCONS_GDB)
|
||||
|
||||
static struct dcons_state {
|
||||
int fd;
|
||||
@ -103,6 +104,7 @@ static struct dcons_state {
|
||||
int escape_state;
|
||||
struct dcons_port {
|
||||
int port;
|
||||
int sport;
|
||||
struct dcons_ch o;
|
||||
struct dcons_ch i;
|
||||
u_int32_t optr;
|
||||
@ -117,8 +119,11 @@ static struct dcons_state {
|
||||
struct timespec zero;
|
||||
struct termios tsave;
|
||||
struct termios traw;
|
||||
char escape;
|
||||
} sc;
|
||||
|
||||
static int dconschat_write_dcons(struct dcons_state *, int, char *, int);
|
||||
|
||||
static int
|
||||
dread(struct dcons_state *dc, void *buf, size_t n, off_t offset)
|
||||
{
|
||||
@ -147,21 +152,25 @@ dwrite(struct dcons_state *dc, void *buf, size_t n, off_t offset)
|
||||
}
|
||||
|
||||
static void
|
||||
dconschat_reset_target(struct dcons_state *dc)
|
||||
dconschat_reset_target(struct dcons_state *dc, struct dcons_port *p)
|
||||
{
|
||||
char zeros[PAGE_SIZE];
|
||||
char buf[PAGE_SIZE];
|
||||
if (dc->reset == 0)
|
||||
return;
|
||||
|
||||
bzero(&zeros[0], PAGE_SIZE);
|
||||
printf("\r\n[dconschat reset target(addr=0x%zx)...]\r\n", dc->reset);
|
||||
dwrite(dc, (void *)zeros, PAGE_SIZE, dc->reset);
|
||||
snprintf(buf, PAGE_SIZE, "\r\n[dconschat reset target(addr=0x%zx)...]\r\n", dc->reset);
|
||||
write(p->outfd, buf, strlen(buf));
|
||||
bzero(&buf[0], PAGE_SIZE);
|
||||
dwrite(dc, (void *)buf, PAGE_SIZE, dc->reset);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
dconschat_suspend(struct dcons_state *dc)
|
||||
dconschat_suspend(struct dcons_state *dc, struct dcons_port *p)
|
||||
{
|
||||
if (p->sport != 0)
|
||||
return;
|
||||
|
||||
if (tc_set)
|
||||
tcsetattr(STDIN_FILENO, TCSADRAIN, &dc->tsave);
|
||||
|
||||
@ -172,10 +181,71 @@ dconschat_suspend(struct dcons_state *dc)
|
||||
tcsetattr(STDIN_FILENO, TCSADRAIN, &dc->traw);
|
||||
}
|
||||
|
||||
static void
|
||||
dconschat_sigchld(int s)
|
||||
{
|
||||
struct kevent kev;
|
||||
struct dcons_port *p;
|
||||
char buf[256];
|
||||
|
||||
p = &sc.port[DCONS_CON];
|
||||
|
||||
snprintf(buf, 256, "\r\n[child exit]\r\n");
|
||||
write(p->outfd, buf, strlen(buf));
|
||||
|
||||
if (tc_set)
|
||||
tcsetattr(STDIN_FILENO, TCSADRAIN, &sc.traw);
|
||||
|
||||
EV_SET(&kev, p->infd, EVFILT_READ, EV_ADD, NOTE_LOWAT, 1, (void *)p);
|
||||
kevent(sc.kq, &kev, 1, NULL, 0, &sc.zero);
|
||||
}
|
||||
|
||||
static void
|
||||
dconschat_fork_gdb(struct dcons_state *dc, struct dcons_port *p)
|
||||
{
|
||||
pid_t pid;
|
||||
char buf[256], com[256];
|
||||
struct kevent kev;
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
snprintf(buf, 256, "\r\n[%s: fork failed]\r\n", __FUNCTION__);
|
||||
write(p->outfd, buf, strlen(buf));
|
||||
}
|
||||
|
||||
|
||||
if (pid == 0) {
|
||||
/* child */
|
||||
if (tc_set)
|
||||
tcsetattr(STDIN_FILENO, TCSADRAIN, &dc->tsave);
|
||||
|
||||
snprintf(com, sizeof(buf), "kgdb -r :%d kernel",
|
||||
dc->port[DCONS_GDB].sport);
|
||||
snprintf(buf, 256, "\n[fork %s]\n", com);
|
||||
write(p->outfd, buf, strlen(buf));
|
||||
|
||||
execl("/bin/sh", "/bin/sh", "-c", com, 0);
|
||||
|
||||
snprintf(buf, 256, "\n[fork failed]\n");
|
||||
write(p->outfd, buf, strlen(buf));
|
||||
|
||||
if (tc_set)
|
||||
tcsetattr(STDIN_FILENO, TCSADRAIN, &dc->traw);
|
||||
|
||||
exit(0);
|
||||
} else {
|
||||
signal(SIGCHLD, dconschat_sigchld);
|
||||
EV_SET(&kev, p->infd, EVFILT_READ, EV_DELETE, 0, 0, NULL);
|
||||
kevent(sc.kq, &kev, 1, NULL, 0, &sc.zero);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
dconschat_cleanup(int sig)
|
||||
{
|
||||
struct dcons_state *dc;
|
||||
int status;
|
||||
|
||||
dc = ≻
|
||||
if (tc_set != 0)
|
||||
@ -185,6 +255,7 @@ dconschat_cleanup(int sig)
|
||||
printf("\n[dconschat exiting with signal %d ...]\n", sig);
|
||||
else
|
||||
printf("\n[dconschat exiting...]\n");
|
||||
wait(&status);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
@ -451,7 +522,7 @@ ok:
|
||||
rlen = len;
|
||||
|
||||
#if 1
|
||||
if (verbose)
|
||||
if (verbose == 1)
|
||||
printf("[%d]", rlen); fflush(stdout);
|
||||
#endif
|
||||
|
||||
@ -532,13 +603,14 @@ again:
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
dconschat_write_socket(int fd, char *buf, int len)
|
||||
{
|
||||
write(fd, buf, len);
|
||||
if (verbose > 1) {
|
||||
buf[len] = 0;
|
||||
printf("[%s]", buf);
|
||||
printf("<- %s\n", buf);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
@ -554,6 +626,7 @@ dconschat_init_socket(struct dcons_state *dc, int port, char *host, int sport)
|
||||
|
||||
p = &dc->port[port];
|
||||
p->port = port;
|
||||
p->sport = sport;
|
||||
p->infd = p->outfd = -1;
|
||||
|
||||
if (sport < 0)
|
||||
@ -666,8 +739,8 @@ static int
|
||||
dconschat_read_filter(struct dcons_state *dc, struct dcons_port *p,
|
||||
u_char *sp, int slen, u_char *dp, int *dlen)
|
||||
{
|
||||
static u_char abreak[3] = {13 /* CR */, 126 /* ~ */, 2 /* ^B */};
|
||||
int skip;
|
||||
char *buf;
|
||||
|
||||
while (slen > 0) {
|
||||
skip = 0;
|
||||
@ -697,7 +770,7 @@ dconschat_read_filter(struct dcons_state *dc, struct dcons_port *p,
|
||||
}
|
||||
switch (dc->escape_state) {
|
||||
case STATE1:
|
||||
if (*sp == KEY_TILDE) {
|
||||
if (*sp == dc->escape) {
|
||||
skip = 1;
|
||||
dc->escape_state = STATE2;
|
||||
} else
|
||||
@ -705,20 +778,26 @@ dconschat_read_filter(struct dcons_state *dc, struct dcons_port *p,
|
||||
break;
|
||||
case STATE2:
|
||||
dc->escape_state = STATE0;
|
||||
skip = 1;
|
||||
if (*sp == '.')
|
||||
dconschat_cleanup(0);
|
||||
else if ((*sp == 0x12 /*'^R'*/)
|
||||
else if (*sp == CTRL('B')) {
|
||||
bcopy(abreak, dp, 3);
|
||||
dp += 3;
|
||||
*dlen += 3;
|
||||
}
|
||||
else if (*sp == CTRL('G'))
|
||||
dconschat_fork_gdb(dc, p);
|
||||
else if ((*sp == CTRL('R'))
|
||||
&& (dc->reset != 0)) {
|
||||
dc->escape_state = STATE3;
|
||||
skip = 1;
|
||||
printf("\r\n[Are you sure to "
|
||||
"reset target? (y/N)]");
|
||||
fflush(stdout);
|
||||
} else if (*sp == 0x1a /*'^Z'*/) {
|
||||
skip = 1;
|
||||
dconschat_suspend(dc);
|
||||
} else {
|
||||
*dp++ = '~';
|
||||
buf = "\r\n[Are you sure to reset target? (y/N)]";
|
||||
write(p->outfd, buf, strlen(buf));
|
||||
} else if (*sp == CTRL('Z'))
|
||||
dconschat_suspend(dc, p);
|
||||
else {
|
||||
skip = 0;
|
||||
*dp++ = dc->escape;
|
||||
(*dlen) ++;
|
||||
}
|
||||
break;
|
||||
@ -726,16 +805,18 @@ dconschat_read_filter(struct dcons_state *dc, struct dcons_port *p,
|
||||
dc->escape_state = STATE0;
|
||||
skip = 1;
|
||||
if (*sp == 'y')
|
||||
dconschat_reset_target(dc);
|
||||
else
|
||||
printf("\r\n");
|
||||
dconschat_reset_target(dc, p);
|
||||
else {
|
||||
write(p->outfd, sp, 1);
|
||||
write(p->outfd, "\r\n", 2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (*sp == KEY_CR)
|
||||
dc->escape_state = STATE1;
|
||||
} else if (IS_GDB(p)) {
|
||||
/* GDB: ^C -> CR+~+^B */
|
||||
if (*sp == 0x3 && (dc->flags & F_ALT_BREAK) != 0) {
|
||||
if (*sp == CTRL('C') && (dc->flags & F_ALT_BREAK) != 0) {
|
||||
bcopy(abreak, dp, 3);
|
||||
dp += 3;
|
||||
sp ++;
|
||||
@ -771,9 +852,8 @@ dconschat_read_socket(struct dcons_state *dc, struct dcons_port *p)
|
||||
dconschat_write_dcons(dc, p->port, wbuf, wlen);
|
||||
if (verbose > 1) {
|
||||
wbuf[wlen] = 0;
|
||||
printf("(%s)\n", wbuf);
|
||||
}
|
||||
if (verbose) {
|
||||
printf("-> %s\n", wbuf);
|
||||
} else if (verbose == 1) {
|
||||
printf("(%d)", wlen);
|
||||
fflush(stdout);
|
||||
}
|
||||
@ -926,7 +1006,7 @@ main(int argc, char **argv)
|
||||
port[0] = 0; /* stdin/out for console */
|
||||
port[1] = -1; /* disable gdb port */
|
||||
|
||||
while ((ch = getopt(argc, argv, "a:bh:rt:u:vwC:G:M:N:RT1")) != -1) {
|
||||
while ((ch = getopt(argc, argv, "a:be:h:rt:u:vwC:G:M:N:RT1")) != -1) {
|
||||
switch(ch) {
|
||||
case 'a':
|
||||
dc->paddr = strtoull(optarg, NULL, 0);
|
||||
@ -935,6 +1015,9 @@ main(int argc, char **argv)
|
||||
case 'b':
|
||||
dc->flags |= F_ALT_BREAK;
|
||||
break;
|
||||
case 'e':
|
||||
dc->escape |= optarg[0];
|
||||
break;
|
||||
case 'h':
|
||||
poll_hz = strtoul(optarg, NULL, 0);
|
||||
if (poll_hz == 0)
|
||||
|
Loading…
x
Reference in New Issue
Block a user