sio(4) driver
Thomas Moestl
t.moestl at tu-bs.de
Fri Aug 1 10:03:54 PDT 2003
On Fri, 2003/08/01 at 16:22:40 +0300, Maxim Mazurok wrote:
> I need to add 2 async serial port to my sparc.
>
> 5.1-RELEASE
>
> I add to kernel
>
> device puc
> options PUC_FASTINTR
>
> but i forgot add
>
> device sio
>
> after reboot i have in dmesg:
>
> puc0: <NetMos NM9835 Dual UART and 1284 Printer port> port 0x1030-0x103f,0x1020-0x1027,0x1018-0x101f,0x1010-0x1017,0x1008-0x100f,0x1000-0x1007 irq 4 at device 3.0 on pci1
>
> card detected, but no have ports (no sio driver in kernel).
> I rebuild kernel width sio driver and after reboot have kernel trap.
> sio(4) diver are ported to sparc?
It works only for ISA sio(4)s currently, due to some ISA specific code
that happens to work with PCI on other platforms. I have attached a
quick hack to fix this which I use on one of my machines, which should
get you around the problems (it also cointains things like console
support).
The rework which marcel@ is doing in the perforce repository will
fix this the right way.
- Thomas
--
Thomas Moestl <t.moestl at tu-bs.de> http://www.tu-bs.de/~y0015675/
<tmm at FreeBSD.org> http://people.FreeBSD.org/~tmm/
PGP fingerprint: 1C97 A604 2BD0 E492 51D0 9C0F 1FE6 4F1D 419C 776C
-------------- next part --------------
Index: sio.c
===================================================================
RCS file: /vol/ncvs/src/sys/dev/sio/sio.c,v
retrieving revision 1.400
diff -u -r1.400 sio.c
--- sio.c 9 Jun 2003 21:25:14 -0000 1.400
+++ sio.c 12 Jun 2003 14:00:19 -0000
@@ -126,7 +126,7 @@
#define sio_getreg(com, off) \
(bus_space_read_1((com)->bst, (com)->bsh, (off)))
#define sio_setreg(com, off, value) \
- (bus_space_write_1((com)->bst, (com)->bsh, (off), (value)))
+ bus_space_write_1((com)->bst, (com)->bsh, (off), (value))
/*
* com state bits.
@@ -229,15 +229,9 @@
bus_space_tag_t bst;
bus_space_handle_t bsh;
- Port_t data_port; /* i/o ports */
#ifdef COM_ESP
Port_t esp_port;
#endif
- Port_t int_id_port;
- Port_t modem_ctl_port;
- Port_t line_status_port;
- Port_t modem_status_port;
- Port_t intr_ctl_port; /* Ports of IIR register */
struct tty *tp; /* cross reference */
@@ -337,9 +331,20 @@
&gdbdefaultrate, GDBSPEED, "");
static u_int com_events; /* input chars + weighted output completions */
static Port_t siocniobase;
-static int siocnunit = -1;
+#ifdef __sparc64__
+#define SIOP_CONS 0
+#define SIOP_LLCONS 1
+static struct bus_space_tag siocntag[2];
+static bus_space_handle_t siocnhandle[2];
+static bus_addr_t siocnports[2];
+#endif
+#if defined(__i386__) || defined(__ia64__) || defined(__sparc64__)
+static int siocnunit;
+#endif
static Port_t siogdbiobase;
+#ifndef __sparc64__
static int siogdbunit = -1;
+#endif
static void *sio_slow_ih;
static void *sio_fast_ih;
static int sio_timeout;
@@ -348,6 +353,18 @@
= CALLOUT_HANDLE_INITIALIZER(&sio_timeout_handle);
static int sio_numunits;
+#ifdef __sparc64__
+#define SIOCNIOBASE(b) siocnports[(b)]
+#define SIOCNOUTB(p, o, v) \
+ bus_space_write_1(&siocntag[p], siocnhandle[p], o, v)
+#define SIOCNINB(p, o) \
+ bus_space_read_1(&siocntag[p], siocnhandle[p], o)
+#else
+#define SIOCNIOBASE(b) (b)
+#define SIOCNOUTB(p, o, v) outb(p + o, v)
+#define SIOCNINB(p, o) inb(p + o)
+#endif
+
#ifdef COM_ESP
/* XXX configure this properly. */
/* XXX quite broken for new-bus. */
@@ -640,7 +657,7 @@
* XXX what about the UART bug avoided by waiting in comparam()?
* We don't want to to wait long enough to drain at 2 bps.
*/
- if (iobase == siocniobase)
+ if (iobase == SIOCNIOBASE(siocniobase))
DELAY((16 + 1) * 1000000 / (comdefaultrate / 10));
else {
sio_setreg(com, com_cfcr, CFCR_DLAB | CFCR_8BITS);
@@ -660,7 +677,8 @@
sio_setreg(com, com_mcr, mcr_image);
sio_setreg(com, com_ier, 0);
DELAY(1000); /* XXX */
- irqmap[0] = isa_irq_pending();
+ if (!noprobe)
+ irqmap[0] = isa_irq_pending();
/*
* Attempt to set loopback mode so that we can send a null byte
@@ -736,7 +754,7 @@
sio_setreg(com, com_cfcr, CFCR_8BITS);
mtx_unlock_spin(&sio_lock);
bus_release_resource(dev, SYS_RES_IOPORT, rid, port);
- if (iobase == siocniobase)
+ if (iobase == SIOCNIOBASE(siocniobase))
result = 0;
if (result != 0) {
device_set_softc(dev, NULL);
@@ -813,7 +831,7 @@
break;
}
bus_release_resource(dev, SYS_RES_IOPORT, rid, port);
- if (iobase == siocniobase)
+ if (iobase == SIOCNIOBASE(siocniobase))
result = 0;
if (result != 0) {
device_set_softc(dev, NULL);
@@ -944,13 +962,7 @@
com->obufs[0].l_head = com->obuf1;
com->obufs[1].l_head = com->obuf2;
- com->data_port = iobase + com_data;
- com->int_id_port = iobase + com_iir;
- com->modem_ctl_port = iobase + com_mcr;
- com->mcr_image = inb(com->modem_ctl_port);
- com->line_status_port = iobase + com_lsr;
- com->modem_status_port = iobase + com_msr;
- com->intr_ctl_port = iobase + com_ier;
+ com->mcr_image = sio_getreg(com, com_mcr);
if (rclk == 0)
rclk = DEFAULT_RCLK;
@@ -983,7 +995,7 @@
* Leave i/o resources allocated if this is a `cn'-level
* console, so that other devices can't snarf them.
*/
- if (iobase != siocniobase)
+ if (iobase != SIOCNIOBASE(siocniobase))
bus_release_resource(dev, SYS_RES_IOPORT, rid, port);
return (ENOMEM);
}
@@ -1015,7 +1027,7 @@
sio_setreg(com, com_fifo, FIFO_ENABLE | FIFO_RX_HIGH);
DELAY(100);
com->st16650a = 0;
- switch (inb(com->int_id_port) & IIR_FIFO_MASK) {
+ switch (sio_getreg(com, com_iir) & IIR_FIFO_MASK) {
case FIFO_RX_LOW:
printf(" 16450");
break;
@@ -1164,7 +1176,7 @@
* on the console.
*/
if (ret == 0 && unit == comconsole)
- outb(siocniobase + com_ier, IER_ERXRDY | IER_ERLS |
+ SIOCNOUTB(siocniobase, com_ier, IER_ERXRDY | IER_ERLS |
IER_EMSC);
#endif
}
@@ -1292,11 +1304,11 @@
* for about 85 usec instead of 100.
*/
DELAY(50);
- if (!(inb(com->line_status_port) & LSR_RXRDY))
+ if (!(sio_getreg(com, com_lsr) & LSR_RXRDY))
break;
sio_setreg(com, com_fifo, 0);
DELAY(50);
- (void) inb(com->data_port);
+ (void) sio_getreg(com, com_data);
}
if (i == 500) {
error = EIO;
@@ -1305,15 +1317,15 @@
}
mtx_lock_spin(&sio_lock);
- (void) inb(com->line_status_port);
- (void) inb(com->data_port);
+ (void) sio_getreg(com, com_lsr);
+ (void) sio_getreg(com, com_data);
com->prev_modem_status = com->last_modem_status
- = inb(com->modem_status_port);
+ = sio_getreg(com, com_msr);
if (COM_IIR_TXRDYBUG(com->flags)) {
- outb(com->intr_ctl_port, IER_ERXRDY | IER_ERLS
+ sio_setreg(com, com_ier, IER_ERXRDY | IER_ERLS
| IER_EMSC);
} else {
- outb(com->intr_ctl_port, IER_ERXRDY | IER_ETXRDY
+ sio_setreg(com, com_ier, IER_ERXRDY | IER_ETXRDY
| IER_ERLS | IER_EMSC);
}
mtx_unlock_spin(&sio_lock);
@@ -1524,7 +1536,7 @@
s = spltty();
if (com->state & CS_BUSY)
com->extra_state &= ~CSE_BUSYCHECK; /* False alarm. */
- else if ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY))
+ else if ((sio_getreg(com, com_lsr) & (LSR_TSRE | LSR_TXRDY))
== (LSR_TSRE | LSR_TXRDY)) {
com->tp->t_state &= ~TS_BUSY;
ttwwakeup(com->tp);
@@ -1668,7 +1680,7 @@
*/
if ((com->state & CS_RTS_IFLOW) && !(com->mcr_image & MCR_RTS) &&
!(tp->t_state & TS_TBLOCK))
- outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
+ sio_setreg(com, com_mcr, com->mcr_image |= MCR_RTS);
}
static void
@@ -1705,7 +1717,7 @@
*/
if (com != NULL
&& !com->gone
- && (inb(com->int_id_port) & IIR_IMASK)
+ && (sio_getreg(com, com_iir) & IIR_IMASK)
!= IIR_NOPEND) {
siointr1(com);
possibly_more_intrs = TRUE;
@@ -1761,12 +1773,12 @@
u_char int_ctl;
u_char int_ctl_new;
- int_ctl = inb(com->intr_ctl_port);
+ int_ctl = sio_getreg(com, com_ier);
int_ctl_new = int_ctl;
while (!com->gone) {
if (com->pps.ppsparam.mode & PPS_CAPTUREBOTH) {
- modem_status = inb(com->modem_status_port);
+ modem_status = sio_getreg(com, com_msr);
if ((modem_status ^ com->last_modem_status) &
com->pps_bit) {
pps_capture(&com->pps);
@@ -1775,7 +1787,7 @@
PPS_CAPTUREASSERT : PPS_CAPTURECLEAR);
}
}
- line_status = inb(com->line_status_port);
+ line_status = sio_getreg(com, com_lsr);
/* input event? (check first to help avoid overruns) */
while (line_status & LSR_RCV_MASK) {
@@ -1783,7 +1795,7 @@
if (!(line_status & LSR_RXRDY))
recv_data = 0;
else
- recv_data = inb(com->data_port);
+ recv_data = sio_getreg(com, com_data);
#if defined(DDB) && defined(ALT_BREAK_TO_DEBUGGER)
/*
* Solaris implements a new BREAK which is initiated
@@ -1870,7 +1882,7 @@
com->iptr = ++ioptr;
if (ioptr == com->ihighwater
&& com->state & CS_RTS_IFLOW)
- outb(com->modem_ctl_port,
+ sio_setreg(com, com_mcr,
com->mcr_image &= ~MCR_RTS);
if (line_status & LSR_OE)
CE_RECORD(com, CE_OVERRUN);
@@ -1880,11 +1892,11 @@
* "& 0x7F" is to avoid the gcc-1.40 generating a slow
* jump from the top of the loop to here
*/
- line_status = inb(com->line_status_port) & 0x7F;
+ line_status = sio_getreg(com, com_lsr) & 0x7F;
}
/* modem status change? (always check before doing output) */
- modem_status = inb(com->modem_status_port);
+ modem_status = sio_getreg(com, com_msr);
if (modem_status != com->last_modem_status) {
if (com->do_dcd_timestamp
&& !(com->last_modem_status & MSR_DCD)
@@ -1925,10 +1937,10 @@
ocount = com->tx_fifo_size;
com->bytes_out += ocount;
do
- outb(com->data_port, *ioptr++);
+ sio_setreg(com, com_data, *ioptr++);
while (--ocount != 0);
} else {
- outb(com->data_port, *ioptr++);
+ sio_setreg(com, com_data, *ioptr++);
++com->bytes_out;
if (com->unit == siotsunit) {
nanouptime(&siots[siotso]);
@@ -1965,13 +1977,13 @@
}
}
if (COM_IIR_TXRDYBUG(com->flags) && (int_ctl != int_ctl_new)) {
- outb(com->intr_ctl_port, int_ctl_new);
+ sio_setreg(com, com_ier, int_ctl_new);
}
}
/* finished? */
#ifndef COM_MULTIPORT
- if ((inb(com->int_id_port) & IIR_IMASK) == IIR_NOPEND)
+ if ((sio_getreg(com, com_iir) & IIR_IMASK) == IIR_NOPEND)
#endif /* COM_MULTIPORT */
return;
}
@@ -2345,7 +2357,7 @@
* CS_RTS_IFLOW just changed from on to off. Force MCR_RTS
* on here, since comstart() won't do it later.
*/
- outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
+ sio_setreg(com, com_mcr, com->mcr_image |= MCR_RTS);
if (com->st16650a) {
sio_setreg(com, com_cfcr, 0xbf);
sio_setreg(com, com_fifo,
@@ -2494,11 +2506,11 @@
com->state |= CS_TTGO;
if (tp->t_state & TS_TBLOCK) {
if (com->mcr_image & MCR_RTS && com->state & CS_RTS_IFLOW)
- outb(com->modem_ctl_port, com->mcr_image &= ~MCR_RTS);
+ sio_setreg(com, com_mcr, com->mcr_image &= ~MCR_RTS);
} else {
if (!(com->mcr_image & MCR_RTS) && com->iptr < com->ihighwater
&& com->state & CS_RTS_IFLOW)
- outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
+ sio_setreg(com, com_mcr, com->mcr_image |= MCR_RTS);
}
mtx_unlock_spin(&sio_lock);
if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) {
@@ -2643,14 +2655,14 @@
mtx_lock_spin(&sio_lock);
switch (how) {
case DMSET:
- outb(com->modem_ctl_port,
+ sio_setreg(com, com_mcr,
com->mcr_image = mcr | (com->mcr_image & MCR_IENABLE));
break;
case DMBIS:
- outb(com->modem_ctl_port, com->mcr_image |= mcr);
+ sio_setreg(com, com_mcr, com->mcr_image |= mcr);
break;
case DMBIC:
- outb(com->modem_ctl_port, com->mcr_image &= ~mcr);
+ sio_setreg(com, com_mcr, com->mcr_image &= ~mcr);
break;
}
mtx_unlock_spin(&sio_lock);
@@ -2785,6 +2797,7 @@
static speed_t siocngetspeed(Port_t, u_long rclk);
#endif
static void siocnclose(struct siocnstate *sp, Port_t iobase);
+static void siocninitdl(Port_t iobase, speed_t rate);
static void siocnopen(struct siocnstate *sp, Port_t iobase, int speed);
static void siocntxwait(Port_t iobase);
@@ -2810,7 +2823,9 @@
/* To get the GDB related variables */
#if DDB > 0
#include <ddb/ddb.h>
+#ifndef __sparc64__
static struct consdev gdbconsdev;
+#endif
#endif
@@ -2826,7 +2841,7 @@
* transmits.
*/
timo = 100000;
- while ((inb(iobase + com_lsr) & (LSR_TSRE | LSR_TXRDY))
+ while ((SIOCNINB(iobase, com_lsr) & (LSR_TSRE | LSR_TXRDY))
!= (LSR_TSRE | LSR_TXRDY) && --timo != 0)
;
}
@@ -2852,13 +2867,13 @@
u_char dlbl;
u_char cfcr;
- cfcr = inb(iobase + com_cfcr);
- outb(iobase + com_cfcr, CFCR_DLAB | cfcr);
+ cfcr = SIOCNINB(iobase, com_cfcr);
+ SIOCNOUTB(iobase, com_cfcr, CFCR_DLAB | cfcr);
- dlbl = inb(iobase + com_dlbl);
- dlbh = inb(iobase + com_dlbh);
+ dlbl = SIOCNINB(iobase, com_dlbl);
+ dlbh = SIOCNINB(iobase, com_dlbh);
- outb(iobase + com_cfcr, cfcr);
+ SIOCNOUTB(iobase, com_cfcr, cfcr);
divisor = dlbh << 8 | dlbl;
@@ -2885,13 +2900,13 @@
* and set our default ones (cs8 -parenb speed=comdefaultrate).
* We can't save the fifo register since it is read-only.
*/
- sp->ier = inb(iobase + com_ier);
- outb(iobase + com_ier, 0); /* spltty() doesn't stop siointr() */
+ sp->ier = SIOCNINB(iobase, com_ier);
+ SIOCNOUTB(iobase, com_ier, 0); /* spltty() doesn't stop siointr() */
siocntxwait(iobase);
- sp->cfcr = inb(iobase + com_cfcr);
- outb(iobase + com_cfcr, CFCR_DLAB | CFCR_8BITS);
- sp->dlbl = inb(iobase + com_dlbl);
- sp->dlbh = inb(iobase + com_dlbh);
+ sp->cfcr = SIOCNINB(iobase, com_cfcr);
+ SIOCNOUTB(iobase, com_cfcr, CFCR_DLAB | CFCR_8BITS);
+ sp->dlbl = SIOCNINB(iobase, com_dlbl);
+ sp->dlbh = SIOCNINB(iobase, com_dlbh);
/*
* Only set the divisor registers if they would change, since on
* some 16550 incompatibles (Startech), setting them clears the
@@ -2901,18 +2916,18 @@
divisor = siodivisor(comdefaultrclk, speed);
dlbl = divisor & 0xFF;
if (sp->dlbl != dlbl)
- outb(iobase + com_dlbl, dlbl);
+ SIOCNOUTB(iobase, com_dlbl, dlbl);
dlbh = divisor >> 8;
if (sp->dlbh != dlbh)
- outb(iobase + com_dlbh, dlbh);
- outb(iobase + com_cfcr, CFCR_8BITS);
- sp->mcr = inb(iobase + com_mcr);
+ SIOCNOUTB(iobase, com_dlbh, dlbh);
+ SIOCNOUTB(iobase, com_cfcr, CFCR_8BITS);
+ sp->mcr = SIOCNINB(iobase, com_mcr);
/*
* We don't want interrupts, but must be careful not to "disable"
* them by clearing the MCR_IENABLE bit, since that might cause
* an interrupt by floating the IRQ line.
*/
- outb(iobase + com_mcr, (sp->mcr & MCR_IENABLE) | MCR_DTR | MCR_RTS);
+ SIOCNOUTB(iobase, com_mcr, (sp->mcr & MCR_IENABLE) | MCR_DTR | MCR_RTS);
}
static void
@@ -2924,20 +2939,45 @@
* Restore the device control registers.
*/
siocntxwait(iobase);
- outb(iobase + com_cfcr, CFCR_DLAB | CFCR_8BITS);
- if (sp->dlbl != inb(iobase + com_dlbl))
- outb(iobase + com_dlbl, sp->dlbl);
- if (sp->dlbh != inb(iobase + com_dlbh))
- outb(iobase + com_dlbh, sp->dlbh);
- outb(iobase + com_cfcr, sp->cfcr);
+ SIOCNOUTB(iobase, com_cfcr, CFCR_DLAB | CFCR_8BITS);
+ if (sp->dlbl != SIOCNINB(iobase, com_dlbl))
+ SIOCNOUTB(iobase, com_dlbl, sp->dlbl);
+ if (sp->dlbh != SIOCNINB(iobase, com_dlbh))
+ SIOCNOUTB(iobase, com_dlbh, sp->dlbh);
+ SIOCNOUTB(iobase, com_cfcr, sp->cfcr);
/*
* XXX damp oscillations of MCR_DTR and MCR_RTS by not restoring them.
*/
- outb(iobase + com_mcr, sp->mcr | MCR_DTR | MCR_RTS);
- outb(iobase + com_ier, sp->ier);
+ SIOCNOUTB(iobase, com_mcr, sp->mcr | MCR_DTR | MCR_RTS);
+ SIOCNOUTB(iobase, com_ier, sp->ier);
}
-#ifndef __alpha__
+static void
+siocninitdl(iobase, rate)
+ Port_t iobase;
+ speed_t rate;
+{
+ u_int divisor;
+ u_char cfcr;
+
+ /*
+ * Initialize the divisor latch. We can't rely on
+ * siocnopen() to do this the first time, since it
+ * avoids writing to the latch if the latch appears
+ * to have the correct value. Also, if we didn't
+ * just read the speed from the hardware, then we
+ * need to set the speed in hardware so that
+ * switching it later is null.
+ */
+ cfcr = SIOCNINB(iobase, com_cfcr);
+ SIOCNOUTB(iobase, com_cfcr, CFCR_DLAB | cfcr);
+ divisor = siodivisor(comdefaultrclk, rate);
+ SIOCNOUTB(iobase, com_dlbl, divisor & 0xff);
+ SIOCNOUTB(iobase, com_dlbh, divisor >> 8);
+ SIOCNOUTB(iobase, com_cfcr, cfcr);
+}
+
+#if defined(__i386__) || defined(__ia64__)
static void
siocnprobe(cp)
@@ -2945,7 +2985,6 @@
{
speed_t boot_speed;
u_char cfcr;
- u_int divisor;
int s, unit;
struct siocnstate sp;
@@ -2989,22 +3028,7 @@
comdefaultrate = boot_speed;
}
- /*
- * Initialize the divisor latch. We can't rely on
- * siocnopen() to do this the first time, since it
- * avoids writing to the latch if the latch appears
- * to have the correct value. Also, if we didn't
- * just read the speed from the hardware, then we
- * need to set the speed in hardware so that
- * switching it later is null.
- */
- cfcr = inb(iobase + com_cfcr);
- outb(iobase + com_cfcr, CFCR_DLAB | cfcr);
- divisor = siodivisor(comdefaultrclk, comdefaultrate);
- outb(iobase + com_dlbl, divisor & 0xff);
- outb(iobase + com_dlbh, divisor >> 8);
- outb(iobase + com_cfcr, cfcr);
-
+ siocninitdl(iobase, comdefaultrate);
siocnopen(&sp, iobase, comdefaultrate);
splx(s);
@@ -3052,6 +3076,10 @@
#endif
}
+#endif
+
+#ifndef __alpha__
+
static void
siocninit(cp)
struct consdev *cp;
@@ -3079,34 +3107,16 @@
{
int s;
u_char cfcr;
- u_int divisor;
struct siocnstate sp;
- int unit = 0; /* XXX random value! */
siocniobase = port;
- siocnunit = unit;
comdefaultrate = speed;
sio_consdev.cn_pri = CN_NORMAL;
- sio_consdev.cn_dev = makedev(CDEV_MAJOR, unit);
+ sio_consdev.cn_dev = makedev(CDEV_MAJOR, 0);
s = spltty();
- /*
- * Initialize the divisor latch. We can't rely on
- * siocnopen() to do this the first time, since it
- * avoids writing to the latch if the latch appears
- * to have the correct value. Also, if we didn't
- * just read the speed from the hardware, then we
- * need to set the speed in hardware so that
- * switching it later is null.
- */
- cfcr = inb(siocniobase + com_cfcr);
- outb(siocniobase + com_cfcr, CFCR_DLAB | cfcr);
- divisor = siodivisor(comdefaultrclk, comdefaultrate);
- outb(siocniobase + com_dlbl, divisor & 0xff);
- outb(siocniobase + com_dlbh, divisor >> 8);
- outb(siocniobase + com_cfcr, cfcr);
-
+ siocninitdl(siocniobase, comdefaultrate);
siocnopen(&sp, siocniobase, comdefaultrate);
splx(s);
@@ -3121,9 +3131,8 @@
{
int s;
u_char cfcr;
- u_int divisor;
struct siocnstate sp;
- int unit = 1; /* XXX random value! */
+ int unit = 1; /* XXX !!! */
siogdbiobase = port;
gdbdefaultrate = speed;
@@ -3139,22 +3148,7 @@
s = spltty();
- /*
- * Initialize the divisor latch. We can't rely on
- * siocnopen() to do this the first time, since it
- * avoids writing to the latch if the latch appears
- * to have the correct value. Also, if we didn't
- * just read the speed from the hardware, then we
- * need to set the speed in hardware so that
- * switching it later is null.
- */
- cfcr = inb(siogdbiobase + com_cfcr);
- outb(siogdbiobase + com_cfcr, CFCR_DLAB | cfcr);
- divisor = siodivisor(comdefaultrclk, gdbdefaultrate);
- outb(siogdbiobase + com_dlbl, divisor & 0xff);
- outb(siogdbiobase + com_dlbh, divisor >> 8);
- outb(siogdbiobase + com_cfcr, cfcr);
-
+ siocninitdl(siogdbiobase, gdbdefaultrate);
siocnopen(&sp, siogdbiobase, gdbdefaultrate);
splx(s);
@@ -3183,8 +3177,8 @@
}
s = spltty();
siocnopen(&sp, iobase, speed);
- if (inb(iobase + com_lsr) & LSR_RXRDY)
- c = inb(iobase + com_data);
+ if (SIOCNINB(iobase, com_lsr) & LSR_RXRDY)
+ c = SIOCNINB(iobase, com_data);
else
c = -1;
siocnclose(&sp, iobase);
@@ -3213,9 +3207,9 @@
}
s = spltty();
siocnopen(&sp, iobase, speed);
- while (!(inb(iobase + com_lsr) & LSR_RXRDY))
+ while (!(SIOCNINB(iobase, com_lsr) & LSR_RXRDY))
;
- c = inb(iobase + com_data);
+ c = SIOCNINB(iobase, com_data);
siocnclose(&sp, iobase);
splx(s);
return (c);
@@ -3247,7 +3241,7 @@
}
siocnopen(&sp, iobase, speed);
siocntxwait(iobase);
- outb(iobase + com_data, c);
+ SIOCNOUTB(iobase, com_data, c);
siocnclose(&sp, iobase);
if (need_unlock)
mtx_unlock_spin(&sio_lock);
@@ -3304,6 +3298,208 @@
siocntxwait(siogdbiobase);
outb(siogdbiobase + com_data, c);
siocnclose(&sp, siogdbiobase);
+ splx(s);
+}
+#endif
+
+#ifdef __sparc64__
+
+#include <ofw/openfirm.h>
+#include <ofw/ofw_pci.h>
+#include <machine/ofw_upa.h>
+#include <sparc64/pci/ofw_pci.h>
+#include <sparc64/isa/ofw_isa.h>
+#include <sparc64/ebus/ebusvar.h>
+
+/* This requires EBus support for now. */
+extern char *sio_ofw_names[];
+extern char *sio_ofw_compat[];
+int sio_ofw_inlist(char *name, char *list[]);
+
+static phandle_t siocnfind(struct consdev *cp, phandle_t root,
+ int *unit, int *flags);
+
+static char sio_ofw_name[32];
+
+/*
+ * Sparc64 console support is a bit complicated; the console needs to
+ * initialize before any bus drivers are registered. Therefore the attach
+ * routine needs to walk the ofw device tree, extract nodes that look like
+ * sio's, look at the parent bus nodes, map the registers, and map the
+ * resulting PCI adresses to physical addresses using the PCI host bridge node.
+ */
+
+/* Find the first sio eligible for console use and return. */
+static phandle_t
+siocnfind(cp, root, unit, flags)
+ struct consdev *cp;
+ phandle_t root;
+ int *unit;
+ int *flags;
+{
+ int disabled;
+ int found;
+ phandle_t node;
+ phandle_t rv;
+
+ node = OF_child(root);
+ while (node != 0) {
+ found = 0;
+ if (OF_getprop(node, "name", sio_ofw_name,
+ sizeof(sio_ofw_name)) != -1) {
+ sio_ofw_name[sizeof(sio_ofw_name) - 1] = '\0';
+ if (sio_ofw_inlist(sio_ofw_name, sio_ofw_names))
+ found = 1;
+ }
+ if (OF_getprop(node, "compat", sio_ofw_name,
+ sizeof(sio_ofw_name)) != -1) {
+ sio_ofw_name[sizeof(sio_ofw_name) - 1] = '\0';
+ if (sio_ofw_inlist(sio_ofw_name, sio_ofw_compat))
+ found = 1;
+ }
+ if (found) {
+ if (resource_int_value("sio", *unit, "disabled",
+ &disabled) != 0)
+ disabled = 0;
+ if (resource_int_value("sio", *unit, "flags",
+ flags) == 0) {
+ if (!disabled && COM_CONSOLE(*flags))
+ return (node);
+ }
+ (*unit)++;
+ }
+ /*
+ * This recursion should be at most only about 5 levels deep,
+ * so this should not take up too much stack space.
+ * It is also done very early, before interrupts can kick in
+ * or the like.
+ */
+ if ((rv = siocnfind(cp, node, unit, flags)) != 0)
+ return (rv);
+ node = OF_peer(node);
+ }
+ return (0);
+}
+
+static int siocnmap(phandle_t node, phandle_t parent);
+
+/*
+ * ISA and EBus ranges and regs are identical, so we can use a single function
+ * here.
+ */
+static int
+siocnmap(node, parent)
+ phandle_t node;
+ phandle_t parent;
+{
+ int bs;
+ phandle_t bus;
+ u_long child;
+ int cs;
+ u_long dummy;
+ int error;
+ int i;
+ struct isa_ranges ir[4];
+ char name[32];
+ phandle_t pbus;
+ u_long phys;
+ struct isa_regs reg;
+ int rsz;
+ int type;
+ struct upa_ranges ur[4];
+
+ if (OF_getprop(node, "reg", ®, sizeof(reg)) == -1 ||
+ (rsz = OF_getprop(parent, "ranges", ir, sizeof(ir))) == -1)
+ return (ENXIO);
+ phys = ISA_REG_PHYS(®);
+ dummy = phys + 8;
+ type = ofw_isa_map_iorange(ir, rsz / sizeof(*ir), &phys, &dummy);
+ if (type == SYS_RES_MEMORY) {
+ cs = PCI_CS_MEM32;
+ bs = PCI_MEMORY_BUS_SPACE;
+ } else {
+ cs = PCI_CS_IO;
+ bs = PCI_IO_BUS_SPACE;
+ }
+ bus = OF_parent(parent);
+ if (OF_getprop(bus, "name", name, sizeof(name)) == -1)
+ return (ENXIO);
+ name[sizeof(name) - 1] = '\0';
+ if (strcmp(name, "pci") != 0)
+ return (ENXIO);
+ /* Find the topmost PCI node (the host bridge) */
+ while ((pbus = OF_parent(bus)) != 0) {
+ if (OF_getprop(pbus, "name", name, sizeof(name)) != -1) {
+ name[sizeof(name) - 1] = '\0';
+ if (strcmp(name, "pci") != 0)
+ break;
+ }
+ bus = pbus;
+ }
+ if (pbus == 0)
+ return (ENXIO);
+ if ((rsz = OF_getprop(bus, "ranges", ur, sizeof(ur))) == -1)
+ return (ENXIO);
+ error = ENXIO;
+ siocniobase = SIOP_CONS;
+ for (i = 0; i < (rsz / sizeof(ur[0])); i++) {
+ child = UPA_RANGE_CHILD(&ur[i]);
+ if (UPA_RANGE_CS(&ur[i]) == cs && phys >= child &&
+ phys - child < UPA_RANGE_SIZE(&ur[i])) {
+ siocnports[SIOP_CONS] = phys;
+ siocnhandle[SIOP_CONS] = sparc64_fake_bustag(bs,
+ UPA_RANGE_PHYS(&ur[i]) + phys,
+ &siocntag[SIOP_CONS]);
+ error = 0;
+ break;
+ }
+ }
+ return (error);
+}
+
+static void
+siocnprobe(cp)
+ struct consdev *cp;
+{
+ char bname[32];
+ speed_t boot_speed;
+ int error;
+ int flags;
+ phandle_t node;
+ phandle_t parent;
+ int s;
+ struct siocnstate sp;
+ int unit;
+
+ cp->cn_pri = CN_DEAD;
+ node = OF_peer(0);
+ if (node <= 0)
+ return;
+ unit = 0;
+ if ((node = siocnfind(cp, node, &unit, &flags)) == 0)
+ return;
+ if ((parent = OF_parent(node)) == 0)
+ return;
+ if ((OF_getprop(parent, "name", bname, sizeof(bname))) <= 0)
+ return;
+ bname[sizeof(bname) - 1] = '\0';
+ error = ENXIO;
+ if (strcmp(bname, "isa") == 0 ||
+ strcmp(bname, "ebus") == 0)
+ error = siocnmap(node, parent);
+ if (error != 0)
+ return;
+ s = spltty();
+ if (boothowto & RB_SERIAL) {
+ boot_speed = siocngetspeed(SIOP_CONS, comdefaultrclk);
+ if (boot_speed)
+ comdefaultrate = boot_speed;
+ }
+ cp->cn_dev = makedev(CDEV_MAJOR, unit);
+ cp->cn_pri = COM_FORCECONSOLE(flags) || boothowto & RB_SERIAL ?
+ CN_REMOTE : CN_NORMAL;
+ siocninitdl(SIOP_CONS, comdefaultrate);
+ siocnopen(&sp, SIOP_CONS, comdefaultrate);
splx(s);
}
#endif
More information about the freebsd-sparc64
mailing list