#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/tty.h>
#include <sys/conf.h>
#include <machine/bus.h>
#include <machine/autoconf.h>
#include <machine/openfirm.h>
#include <sparc64/dev/ebusreg.h>
#include <sparc64/dev/ebusvar.h>
#include <dev/cons.h>
#include <dev/ic/comvar.h>
cdev_decl(com);
int com_ebus_match(struct device *, void *, void *);
void com_ebus_attach(struct device *, struct device *, void *);
int com_ebus_speed(struct ebus_attach_args *);
const struct cfattach com_ebus_ca = {
sizeof(struct com_softc), com_ebus_match, com_ebus_attach
};
static char *com_names[] = {
"su",
"su_pnp",
"rsc-console",
"lom-console",
NULL
};
static inline int
com_match_ikkaku(void)
{
char model[80];
int i;
i = OF_getproplen(findroot(), "model");
if (i == 0)
return (0);
if (OF_getprop(findroot(), "model", model, sizeof(model)) != i)
return (0);
return (strcmp(model, "IKKAKU") == 0);
}
int
com_ebus_match(struct device *parent, void *match, void *aux)
{
struct ebus_attach_args *ea = aux;
int i;
for (i=0; com_names[i]; i++)
if (strcmp(ea->ea_name, com_names[i]) == 0)
return (1);
if (strcmp(ea->ea_name, "serial") == 0) {
char compat[80];
if (com_match_ikkaku())
return (0);
if ((i = OF_getproplen(ea->ea_node, "compatible")) &&
OF_getprop(ea->ea_node, "compatible", compat,
sizeof(compat)) == i) {
if (strcmp(compat, "su16552") == 0 ||
strcmp(compat, "su16550") == 0 ||
strcmp(compat, "FJSV,su") == 0 ||
strcmp(compat, "su") == 0) {
return (1);
}
}
}
return (0);
}
#define BAUD_BASE (1843200)
void
com_ebus_attach(struct device *parent, struct device *self, void *aux)
{
struct com_softc *sc = (void *)self;
struct ebus_attach_args *ea = aux;
int i, com_is_input, com_is_output;
int node, port;
char buf[32];
sc->sc_iobase = EBUS_PADDR_FROM_REG(&ea->ea_regs[0]);
if (ea->ea_nvaddrs) {
if (bus_space_map(ea->ea_memtag, ea->ea_vaddrs[0], 0,
BUS_SPACE_MAP_PROMADDRESS, &sc->sc_ioh) != 0) {
printf(": can't map register space\n");
return;
}
sc->sc_iot = ea->ea_memtag;
} else if (ebus_bus_map(ea->ea_memtag, 0,
EBUS_PADDR_FROM_REG(&ea->ea_regs[0]),
ea->ea_regs[0].size, 0, 0, &sc->sc_ioh) == 0) {
sc->sc_iot = ea->ea_memtag;
} else if (ebus_bus_map(ea->ea_iotag, 0,
EBUS_PADDR_FROM_REG(&ea->ea_regs[0]),
ea->ea_regs[0].size, 0, 0, &sc->sc_ioh) == 0) {
sc->sc_iot = ea->ea_iotag;
} else {
printf(": can't map register space\n");
return;
}
sc->sc_hwflags = 0;
sc->sc_swflags = 0;
sc->sc_frequency = BAUD_BASE;
for (i = 0; i < ea->ea_nintrs; i++)
bus_intr_establish(sc->sc_iot, ea->ea_intrs[i],
IPL_TTY, 0, comintr, sc, self->dv_xname);
node = OF_instance_to_package(OF_stdin());
com_is_input = (ea->ea_node == node);
if (OF_getprop(node, "name", buf, sizeof(buf)) > 0 &&
strcmp(buf, "pseudo-console") == 0) {
port = getpropint(node, "tty-port#", -1);
node = OF_parent(OF_parent(ea->ea_node));
com_is_input = (getpropint(node, "board#", -2) == port);
}
node = OF_instance_to_package(OF_stdout());
com_is_output = (ea->ea_node == node);
if (OF_getprop(node, "name", buf, sizeof(buf)) > 0 &&
strcmp(buf, "pseudo-console") == 0) {
port = getpropint(node, "tty-port#", -1);
node = OF_parent(OF_parent(ea->ea_node));
com_is_output = (getpropint(node, "board#", -2) == port);
}
if (com_is_input || com_is_output) {
struct consdev *cn_orig;
int speed;
speed = com_ebus_speed(ea);
comconsioh = sc->sc_ioh;
cn_orig = cn_tab;
if (comcnattach(sc->sc_iot, sc->sc_iobase, speed,
sc->sc_frequency,
((TTYDEF_CFLAG & ~(CSIZE | PARENB))|CREAD | CS8 | HUPCL))) {
printf("Error: comcnattach failed\n");
}
cn_tab = cn_orig;
if (com_is_input) {
cn_tab->cn_dev = makedev(36, sc->sc_dev.dv_unit);
cn_tab->cn_probe = comcnprobe;
cn_tab->cn_init = comcninit;
cn_tab->cn_getc = comcngetc;
cn_tab->cn_pollc = comcnpollc;
}
if (com_is_output)
cn_tab->cn_putc = comcnputc;
}
if (OF_getprop(ea->ea_node, "compatible", buf, sizeof(buf)) > 0 &&
strcmp(buf, "FJSV,su") == 0)
sc->sc_uarttype = COM_UART_16550;
if (OF_getproplen(ea->ea_node, "keyboard") == 0)
printf(": keyboard");
else if (OF_getproplen(ea->ea_node, "mouse") == 0)
printf(": mouse");
com_attach_subr(sc);
}
int
com_ebus_speed(struct ebus_attach_args *ea)
{
char buf[128];
char *name = NULL;
int aliases, options;
if (strcmp(ea->ea_name, "rsc-console") == 0)
return 115200;
aliases = OF_finddevice("/aliases");
if (OF_getprop(aliases, "ttya", buf, sizeof(buf)) != -1 &&
OF_finddevice(buf) == ea->ea_node)
name = "ttya-mode";
if (OF_getprop(aliases, "ttyb", buf, sizeof(buf)) != -1 &&
OF_finddevice(buf) == ea->ea_node)
name = "ttyb-mode";
if (name == NULL)
return TTYDEF_SPEED;
options = OF_finddevice("/options");
return (getpropspeed(options, name));
}