summaryrefslogtreecommitdiffstats
path: root/usr.sbin/dconschat
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/dconschat')
-rw-r--r--usr.sbin/dconschat/dconschat.830
-rw-r--r--usr.sbin/dconschat/dconschat.c97
2 files changed, 103 insertions, 24 deletions
diff --git a/usr.sbin/dconschat/dconschat.8 b/usr.sbin/dconschat/dconschat.8
index 1feebd8..d24ae80 100644
--- a/usr.sbin/dconschat/dconschat.8
+++ b/usr.sbin/dconschat/dconschat.8
@@ -69,7 +69,8 @@ using
.Xr firewire 4 ,
you have to specify target EUI64 address using the
.Fl t
-option.
+option. Physical DMA should be enabled on the target machine for access
+via FireWire.
.Pp
The
.Nm
@@ -95,15 +96,6 @@ options respectively.
The port number 0 has special meaning that
current TTY (stdin/stdout) is used instead of TCP/IP.
A negative port number will disable the port.
-To quit
-.Nm ,
-send a CR +
-.Ql ~
-+
-.Ql \&.
-sequence to the console port,
-or send signal to the process.
-.Pp
By analogy with
.Xr pty 4
device, the
@@ -112,6 +104,24 @@ acts as a slave device and
.Nm
acts as a master device with
.Xr telnetd 8 .
+.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
+following are recognized:
+.Bl -tag -width ident
+.It Ic ~.
+Drop the connection and exit.
+.It Ic ~^R
+Reset the target over FireWire if a reset address is registered in Configuration ROM.
+.It Ic ~^Z
+Suspend the dconschat process.
+.El
+.Pp
+The following options are supported.
+.Pp
.Bl -tag -width indent
.It Fl b
Translate Ctrl-C to ALT_BREAK (CR +
diff --git a/usr.sbin/dconschat/dconschat.c b/usr.sbin/dconschat/dconschat.c
index 719b21f..58a16df 100644
--- a/usr.sbin/dconschat/dconschat.c
+++ b/usr.sbin/dconschat/dconschat.c
@@ -87,6 +87,7 @@ static struct dcons_state {
kvm_t *kd;
int kq;
off_t paddr;
+ off_t reset;
#define F_READY (1 << 1)
#define F_RD_ONLY (1 << 2)
#define F_ALT_BREAK (1 << 3)
@@ -115,6 +116,7 @@ static struct dcons_state {
struct timespec to;
struct timespec zero;
struct termios tsave;
+ struct termios traw;
} sc;
static int
@@ -145,6 +147,32 @@ dwrite(struct dcons_state *dc, void *buf, size_t n, off_t offset)
}
static void
+dconschat_reset_target(struct dcons_state *dc)
+{
+ char zeros[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);
+}
+
+
+static void
+dconschat_suspend(struct dcons_state *dc)
+{
+ if (tc_set)
+ tcsetattr(STDIN_FILENO, TCSADRAIN, &dc->tsave);
+
+ printf("\n[dconschat suspend]\n");
+ kill(getpid(), SIGTSTP);
+
+ if (tc_set)
+ tcsetattr(STDIN_FILENO, TCSADRAIN, &dc->traw);
+}
+
+static void
dconschat_cleanup(int sig)
{
struct dcons_state *dc;
@@ -166,7 +194,7 @@ dconschat_get_crom(struct dcons_state *dc)
{
off_t addr;
int i, state = 0;
- u_int32_t buf, hi = 0, lo = 0;
+ u_int32_t buf, hi = 0, lo = 0, reset_hi = 0, reset_lo = 0;
struct csrreg *reg;
reg = (struct csrreg *)&buf;
@@ -193,21 +221,35 @@ dconschat_get_crom(struct dcons_state *dc)
state = 2;
break;
case 2:
- if (reg->key == DCONS_CSR_KEY_HI)
+ switch (reg->key) {
+ case DCONS_CSR_KEY_HI:
hi = reg->val;
- else if (reg->key == DCONS_CSR_KEY_LO) {
+ break;
+ case DCONS_CSR_KEY_LO:
lo = reg->val;
+ break;
+ case DCONS_CSR_KEY_RESET_HI:
+ reset_hi = reg->val;
+ break;
+ case DCONS_CSR_KEY_RESET_LO:
+ reset_lo = reg->val;
goto out;
+ break;
+ case 0x81:
+ break;
+ default:
+ state = 0;
}
break;
}
}
- /* not found */
- return (-1);
out:
if (verbose)
printf("addr: %06x %06x\n", hi, lo);
dc->paddr = ((off_t)hi << 24) | lo;
+ dc->reset = ((off_t)reset_hi << 24) | reset_lo;
+ if (dc->paddr == 0)
+ return (-1);
return (0);
}
#endif
@@ -525,11 +567,9 @@ dconschat_init_socket(struct dcons_state *dc, int port, char *host, int sport)
p->s = -1;
if (tc_set == 0 &&
tcgetattr(STDIN_FILENO, &dc->tsave) == 0) {
- struct termios traw;
-
- traw = dc->tsave;
- cfmakeraw(&traw);
- tcsetattr(STDIN_FILENO, TCSADRAIN, &traw);
+ dc->traw = dc->tsave;
+ cfmakeraw(&dc->traw);
+ tcsetattr(STDIN_FILENO, TCSADRAIN, &dc->traw);
tc_set = 1;
}
EV_SET(&kev, p->infd, EVFILT_READ, EV_ADD, NOTE_LOWAT, 1,
@@ -627,8 +667,10 @@ 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;
while (slen > 0) {
+ skip = 0;
if (IS_CONSOLE(p)) {
if ((dc->flags & F_TELNET) != 0) {
/* XXX Telnet workarounds */
@@ -655,15 +697,39 @@ dconschat_read_filter(struct dcons_state *dc, struct dcons_port *p,
}
switch (dc->escape_state) {
case STATE1:
- if (*sp == KEY_TILDE)
+ if (*sp == KEY_TILDE) {
+ skip = 1;
dc->escape_state = STATE2;
- else
+ } else
dc->escape_state = STATE0;
break;
case STATE2:
dc->escape_state = STATE0;
if (*sp == '.')
dconschat_cleanup(0);
+ else if ((*sp == 0x12 /*'^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++ = '~';
+ (*dlen) ++;
+ }
+ break;
+ case STATE3:
+ dc->escape_state = STATE0;
+ skip = 1;
+ if (*sp == 'y')
+ dconschat_reset_target(dc);
+ else
+ printf("\r\n");
+ break;
}
if (*sp == KEY_CR)
dc->escape_state = STATE1;
@@ -679,8 +745,11 @@ dconschat_read_filter(struct dcons_state *dc, struct dcons_port *p,
break;
}
}
- *dp++ = *sp++;
- (*dlen) ++;
+ if (!skip) {
+ *dp++ = *sp;
+ (*dlen) ++;
+ }
+ sp ++;
slen --;
}
return (*dlen);
OpenPOWER on IntegriCloud