|
@@ -40,11 +40,8 @@
|
|
|
|
|
|
#include <asm/io.h>
|
|
#include <asm/io.h>
|
|
#include <asm/irq.h>
|
|
#include <asm/irq.h>
|
|
-#include <asm/oplib.h>
|
|
|
|
-#include <asm/ebus.h>
|
|
|
|
-#ifdef CONFIG_SPARC64
|
|
|
|
-#include <asm/isa.h>
|
|
|
|
-#endif
|
|
|
|
|
|
+#include <asm/prom.h>
|
|
|
|
+#include <asm/of_device.h>
|
|
|
|
|
|
#if defined(CONFIG_SERIAL_SUNSU_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
|
|
#if defined(CONFIG_SERIAL_SUNSU_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
|
|
#define SUPPORT_SYSRQ
|
|
#define SUPPORT_SYSRQ
|
|
@@ -94,10 +91,10 @@ struct uart_sunsu_port {
|
|
/* Probing information. */
|
|
/* Probing information. */
|
|
enum su_type su_type;
|
|
enum su_type su_type;
|
|
unsigned int type_probed; /* XXX Stupid */
|
|
unsigned int type_probed; /* XXX Stupid */
|
|
- int port_node;
|
|
|
|
|
|
+ unsigned long reg_size;
|
|
|
|
|
|
#ifdef CONFIG_SERIO
|
|
#ifdef CONFIG_SERIO
|
|
- struct serio *serio;
|
|
|
|
|
|
+ struct serio serio;
|
|
int serio_open;
|
|
int serio_open;
|
|
#endif
|
|
#endif
|
|
};
|
|
};
|
|
@@ -509,7 +506,7 @@ static void receive_kbd_ms_chars(struct uart_sunsu_port *up, struct pt_regs *reg
|
|
/* Stop-A is handled by drivers/char/keyboard.c now. */
|
|
/* Stop-A is handled by drivers/char/keyboard.c now. */
|
|
if (up->su_type == SU_PORT_KBD) {
|
|
if (up->su_type == SU_PORT_KBD) {
|
|
#ifdef CONFIG_SERIO
|
|
#ifdef CONFIG_SERIO
|
|
- serio_interrupt(up->serio, ch, 0, regs);
|
|
|
|
|
|
+ serio_interrupt(&up->serio, ch, 0, regs);
|
|
#endif
|
|
#endif
|
|
} else if (up->su_type == SU_PORT_MS) {
|
|
} else if (up->su_type == SU_PORT_MS) {
|
|
int ret = suncore_mouse_baud_detection(ch, is_break);
|
|
int ret = suncore_mouse_baud_detection(ch, is_break);
|
|
@@ -523,7 +520,7 @@ static void receive_kbd_ms_chars(struct uart_sunsu_port *up, struct pt_regs *reg
|
|
|
|
|
|
case 0:
|
|
case 0:
|
|
#ifdef CONFIG_SERIO
|
|
#ifdef CONFIG_SERIO
|
|
- serio_interrupt(up->serio, ch, 0, regs);
|
|
|
|
|
|
+ serio_interrupt(&up->serio, ch, 0, regs);
|
|
#endif
|
|
#endif
|
|
break;
|
|
break;
|
|
};
|
|
};
|
|
@@ -1031,99 +1028,14 @@ static void sunsu_autoconfig(struct uart_sunsu_port *up)
|
|
{
|
|
{
|
|
unsigned char status1, status2, scratch, scratch2, scratch3;
|
|
unsigned char status1, status2, scratch, scratch2, scratch3;
|
|
unsigned char save_lcr, save_mcr;
|
|
unsigned char save_lcr, save_mcr;
|
|
- struct linux_ebus_device *dev = NULL;
|
|
|
|
- struct linux_ebus *ebus;
|
|
|
|
-#ifdef CONFIG_SPARC64
|
|
|
|
- struct sparc_isa_bridge *isa_br;
|
|
|
|
- struct sparc_isa_device *isa_dev;
|
|
|
|
-#endif
|
|
|
|
-#ifndef CONFIG_SPARC64
|
|
|
|
- struct linux_prom_registers reg0;
|
|
|
|
-#endif
|
|
|
|
unsigned long flags;
|
|
unsigned long flags;
|
|
|
|
|
|
- if (!up->port_node || !up->su_type)
|
|
|
|
|
|
+ if (up->su_type == SU_PORT_NONE)
|
|
return;
|
|
return;
|
|
|
|
|
|
up->type_probed = PORT_UNKNOWN;
|
|
up->type_probed = PORT_UNKNOWN;
|
|
up->port.iotype = UPIO_MEM;
|
|
up->port.iotype = UPIO_MEM;
|
|
|
|
|
|
- /*
|
|
|
|
- * First we look for Ebus-bases su's
|
|
|
|
- */
|
|
|
|
- for_each_ebus(ebus) {
|
|
|
|
- for_each_ebusdev(dev, ebus) {
|
|
|
|
- if (dev->prom_node->node == up->port_node) {
|
|
|
|
- /*
|
|
|
|
- * The EBus is broken on sparc; it delivers
|
|
|
|
- * virtual addresses in resources. Oh well...
|
|
|
|
- * This is correct on sparc64, though.
|
|
|
|
- */
|
|
|
|
- up->port.membase = (char *) dev->resource[0].start;
|
|
|
|
- /*
|
|
|
|
- * This is correct on both architectures.
|
|
|
|
- */
|
|
|
|
- up->port.mapbase = dev->resource[0].start;
|
|
|
|
- up->port.irq = dev->irqs[0];
|
|
|
|
- goto ebus_done;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
-#ifdef CONFIG_SPARC64
|
|
|
|
- for_each_isa(isa_br) {
|
|
|
|
- for_each_isadev(isa_dev, isa_br) {
|
|
|
|
- if (isa_dev->prom_node->node == up->port_node) {
|
|
|
|
- /* Same on sparc64. Cool architecure... */
|
|
|
|
- up->port.membase = (char *) isa_dev->resource.start;
|
|
|
|
- up->port.mapbase = isa_dev->resource.start;
|
|
|
|
- up->port.irq = isa_dev->irq;
|
|
|
|
- goto ebus_done;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-#endif
|
|
|
|
-
|
|
|
|
-#ifdef CONFIG_SPARC64
|
|
|
|
- /*
|
|
|
|
- * Not on Ebus, bailing.
|
|
|
|
- */
|
|
|
|
- return;
|
|
|
|
-#else
|
|
|
|
- /*
|
|
|
|
- * Not on Ebus, must be OBIO.
|
|
|
|
- */
|
|
|
|
- if (prom_getproperty(up->port_node, "reg",
|
|
|
|
- (char *)®0, sizeof(reg0)) == -1) {
|
|
|
|
- prom_printf("sunsu: no \"reg\" property\n");
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
- prom_apply_obio_ranges(®0, 1);
|
|
|
|
- if (reg0.which_io != 0) { /* Just in case... */
|
|
|
|
- prom_printf("sunsu: bus number nonzero: 0x%x:%x\n",
|
|
|
|
- reg0.which_io, reg0.phys_addr);
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
- up->port.mapbase = reg0.phys_addr;
|
|
|
|
- if ((up->port.membase = ioremap(reg0.phys_addr, reg0.reg_size)) == 0) {
|
|
|
|
- prom_printf("sunsu: Cannot map registers.\n");
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /*
|
|
|
|
- * 0x20 is sun4m thing, Dave Redman heritage.
|
|
|
|
- * See arch/sparc/kernel/irq.c.
|
|
|
|
- */
|
|
|
|
-#define IRQ_4M(n) ((n)|0x20)
|
|
|
|
-
|
|
|
|
- /*
|
|
|
|
- * There is no intr property on MrCoffee, so hardwire it.
|
|
|
|
- */
|
|
|
|
- up->port.irq = IRQ_4M(13);
|
|
|
|
-#endif
|
|
|
|
-
|
|
|
|
-ebus_done:
|
|
|
|
-
|
|
|
|
spin_lock_irqsave(&up->port.lock, flags);
|
|
spin_lock_irqsave(&up->port.lock, flags);
|
|
|
|
|
|
if (!(up->port.flags & UPF_BUGGY_UART)) {
|
|
if (!(up->port.flags & UPF_BUGGY_UART)) {
|
|
@@ -1269,18 +1181,13 @@ static struct uart_driver sunsu_reg = {
|
|
.major = TTY_MAJOR,
|
|
.major = TTY_MAJOR,
|
|
};
|
|
};
|
|
|
|
|
|
-static int __init sunsu_kbd_ms_init(struct uart_sunsu_port *up, int channel)
|
|
|
|
|
|
+static int __init sunsu_kbd_ms_init(struct uart_sunsu_port *up)
|
|
{
|
|
{
|
|
int quot, baud;
|
|
int quot, baud;
|
|
#ifdef CONFIG_SERIO
|
|
#ifdef CONFIG_SERIO
|
|
struct serio *serio;
|
|
struct serio *serio;
|
|
#endif
|
|
#endif
|
|
|
|
|
|
- spin_lock_init(&up->port.lock);
|
|
|
|
- up->port.line = channel;
|
|
|
|
- up->port.type = PORT_UNKNOWN;
|
|
|
|
- up->port.uartclk = (SU_BASE_BAUD * 16);
|
|
|
|
-
|
|
|
|
if (up->su_type == SU_PORT_KBD) {
|
|
if (up->su_type == SU_PORT_KBD) {
|
|
up->cflag = B1200 | CS8 | CLOCAL | CREAD;
|
|
up->cflag = B1200 | CS8 | CLOCAL | CREAD;
|
|
baud = 1200;
|
|
baud = 1200;
|
|
@@ -1292,41 +1199,31 @@ static int __init sunsu_kbd_ms_init(struct uart_sunsu_port *up, int channel)
|
|
|
|
|
|
sunsu_autoconfig(up);
|
|
sunsu_autoconfig(up);
|
|
if (up->port.type == PORT_UNKNOWN)
|
|
if (up->port.type == PORT_UNKNOWN)
|
|
- return -1;
|
|
|
|
-
|
|
|
|
- printk(KERN_INFO "su%d at 0x%p (irq = %d) is a %s\n",
|
|
|
|
- channel,
|
|
|
|
- up->port.membase, up->port.irq,
|
|
|
|
- sunsu_type(&up->port));
|
|
|
|
|
|
+ return -ENODEV;
|
|
|
|
|
|
#ifdef CONFIG_SERIO
|
|
#ifdef CONFIG_SERIO
|
|
- up->serio = serio = kmalloc(sizeof(struct serio), GFP_KERNEL);
|
|
|
|
- if (serio) {
|
|
|
|
- memset(serio, 0, sizeof(*serio));
|
|
|
|
-
|
|
|
|
- serio->port_data = up;
|
|
|
|
-
|
|
|
|
- serio->id.type = SERIO_RS232;
|
|
|
|
- if (up->su_type == SU_PORT_KBD) {
|
|
|
|
- serio->id.proto = SERIO_SUNKBD;
|
|
|
|
- strlcpy(serio->name, "sukbd", sizeof(serio->name));
|
|
|
|
- } else {
|
|
|
|
- serio->id.proto = SERIO_SUN;
|
|
|
|
- serio->id.extra = 1;
|
|
|
|
- strlcpy(serio->name, "sums", sizeof(serio->name));
|
|
|
|
- }
|
|
|
|
- strlcpy(serio->phys, (channel == 0 ? "su/serio0" : "su/serio1"),
|
|
|
|
- sizeof(serio->phys));
|
|
|
|
|
|
+ serio = &up->serio;
|
|
|
|
+ serio->port_data = up;
|
|
|
|
|
|
- serio->write = sunsu_serio_write;
|
|
|
|
- serio->open = sunsu_serio_open;
|
|
|
|
- serio->close = sunsu_serio_close;
|
|
|
|
-
|
|
|
|
- serio_register_port(serio);
|
|
|
|
|
|
+ serio->id.type = SERIO_RS232;
|
|
|
|
+ if (up->su_type == SU_PORT_KBD) {
|
|
|
|
+ serio->id.proto = SERIO_SUNKBD;
|
|
|
|
+ strlcpy(serio->name, "sukbd", sizeof(serio->name));
|
|
} else {
|
|
} else {
|
|
- printk(KERN_WARNING "su%d: not enough memory for serio port\n",
|
|
|
|
- channel);
|
|
|
|
|
|
+ serio->id.proto = SERIO_SUN;
|
|
|
|
+ serio->id.extra = 1;
|
|
|
|
+ strlcpy(serio->name, "sums", sizeof(serio->name));
|
|
}
|
|
}
|
|
|
|
+ strlcpy(serio->phys,
|
|
|
|
+ (!(up->port.line & 1) ? "su/serio0" : "su/serio1"),
|
|
|
|
+ sizeof(serio->phys));
|
|
|
|
+
|
|
|
|
+ serio->write = sunsu_serio_write;
|
|
|
|
+ serio->open = sunsu_serio_open;
|
|
|
|
+ serio->close = sunsu_serio_close;
|
|
|
|
+ serio->dev.parent = up->port.dev;
|
|
|
|
+
|
|
|
|
+ serio_register_port(serio);
|
|
#endif
|
|
#endif
|
|
|
|
|
|
sunsu_change_speed(&up->port, up->cflag, 0, quot);
|
|
sunsu_change_speed(&up->port, up->cflag, 0, quot);
|
|
@@ -1458,22 +1355,20 @@ static struct console sunsu_cons = {
|
|
* Register console.
|
|
* Register console.
|
|
*/
|
|
*/
|
|
|
|
|
|
-static inline struct console *SUNSU_CONSOLE(void)
|
|
|
|
|
|
+static inline struct console *SUNSU_CONSOLE(int num_uart)
|
|
{
|
|
{
|
|
int i;
|
|
int i;
|
|
|
|
|
|
if (con_is_present())
|
|
if (con_is_present())
|
|
return NULL;
|
|
return NULL;
|
|
|
|
|
|
- for (i = 0; i < UART_NR; i++) {
|
|
|
|
|
|
+ for (i = 0; i < num_uart; i++) {
|
|
int this_minor = sunsu_reg.minor + i;
|
|
int this_minor = sunsu_reg.minor + i;
|
|
|
|
|
|
if ((this_minor - 64) == (serial_console - 1))
|
|
if ((this_minor - 64) == (serial_console - 1))
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
- if (i == UART_NR)
|
|
|
|
- return NULL;
|
|
|
|
- if (sunsu_ports[i].port_node == 0)
|
|
|
|
|
|
+ if (i == num_uart)
|
|
return NULL;
|
|
return NULL;
|
|
|
|
|
|
sunsu_cons.index = i;
|
|
sunsu_cons.index = i;
|
|
@@ -1481,252 +1376,180 @@ static inline struct console *SUNSU_CONSOLE(void)
|
|
return &sunsu_cons;
|
|
return &sunsu_cons;
|
|
}
|
|
}
|
|
#else
|
|
#else
|
|
-#define SUNSU_CONSOLE() (NULL)
|
|
|
|
|
|
+#define SUNSU_CONSOLE(num_uart) (NULL)
|
|
#define sunsu_serial_console_init() do { } while (0)
|
|
#define sunsu_serial_console_init() do { } while (0)
|
|
#endif
|
|
#endif
|
|
|
|
|
|
-static int __init sunsu_serial_init(void)
|
|
|
|
|
|
+static enum su_type __devinit su_get_type(struct device_node *dp)
|
|
{
|
|
{
|
|
- int instance, ret, i;
|
|
|
|
-
|
|
|
|
- /* How many instances do we need? */
|
|
|
|
- instance = 0;
|
|
|
|
- for (i = 0; i < UART_NR; i++) {
|
|
|
|
- struct uart_sunsu_port *up = &sunsu_ports[i];
|
|
|
|
|
|
+ struct device_node *ap = of_find_node_by_path("/aliases");
|
|
|
|
|
|
- if (up->su_type == SU_PORT_MS ||
|
|
|
|
- up->su_type == SU_PORT_KBD)
|
|
|
|
- continue;
|
|
|
|
|
|
+ if (ap) {
|
|
|
|
+ char *keyb = of_get_property(ap, "keyboard", NULL);
|
|
|
|
+ char *ms = of_get_property(ap, "mouse", NULL);
|
|
|
|
|
|
- spin_lock_init(&up->port.lock);
|
|
|
|
- up->port.flags |= UPF_BOOT_AUTOCONF;
|
|
|
|
- up->port.type = PORT_UNKNOWN;
|
|
|
|
- up->port.uartclk = (SU_BASE_BAUD * 16);
|
|
|
|
|
|
+ if (keyb) {
|
|
|
|
+ if (dp == of_find_node_by_path(keyb))
|
|
|
|
+ return SU_PORT_KBD;
|
|
|
|
+ }
|
|
|
|
+ if (ms) {
|
|
|
|
+ if (dp == of_find_node_by_path(ms))
|
|
|
|
+ return SU_PORT_MS;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
|
|
- sunsu_autoconfig(up);
|
|
|
|
- if (up->port.type == PORT_UNKNOWN)
|
|
|
|
- continue;
|
|
|
|
|
|
+ return SU_PORT_PORT;
|
|
|
|
+}
|
|
|
|
|
|
- up->port.line = instance++;
|
|
|
|
- up->port.ops = &sunsu_pops;
|
|
|
|
- }
|
|
|
|
|
|
+static int __devinit su_probe(struct of_device *op, const struct of_device_id *match)
|
|
|
|
+{
|
|
|
|
+ static int inst;
|
|
|
|
+ struct device_node *dp = op->node;
|
|
|
|
+ struct uart_sunsu_port *up;
|
|
|
|
+ struct resource *rp;
|
|
|
|
+ int err;
|
|
|
|
|
|
- sunsu_reg.minor = sunserial_current_minor;
|
|
|
|
|
|
+ if (inst >= UART_NR)
|
|
|
|
+ return -EINVAL;
|
|
|
|
|
|
- sunsu_reg.nr = instance;
|
|
|
|
|
|
+ up = &sunsu_ports[inst];
|
|
|
|
+ up->port.line = inst;
|
|
|
|
|
|
- ret = uart_register_driver(&sunsu_reg);
|
|
|
|
- if (ret < 0)
|
|
|
|
- return ret;
|
|
|
|
|
|
+ spin_lock_init(&up->port.lock);
|
|
|
|
|
|
- sunsu_reg.tty_driver->name_base = sunsu_reg.minor - 64;
|
|
|
|
|
|
+ up->su_type = su_get_type(dp);
|
|
|
|
|
|
- sunserial_current_minor += instance;
|
|
|
|
|
|
+ rp = &op->resource[0];
|
|
|
|
+ up->port.mapbase = op->resource[0].start;
|
|
|
|
|
|
- sunsu_reg.cons = SUNSU_CONSOLE();
|
|
|
|
|
|
+ up->reg_size = (rp->end - rp->start) + 1;
|
|
|
|
+ up->port.membase = of_ioremap(rp, 0, up->reg_size, "su");
|
|
|
|
+ if (!up->port.membase)
|
|
|
|
+ return -ENOMEM;
|
|
|
|
|
|
- for (i = 0; i < UART_NR; i++) {
|
|
|
|
- struct uart_sunsu_port *up = &sunsu_ports[i];
|
|
|
|
|
|
+ up->port.irq = op->irqs[0];
|
|
|
|
|
|
- /* Do not register Keyboard/Mouse lines with UART
|
|
|
|
- * layer.
|
|
|
|
- */
|
|
|
|
- if (up->su_type == SU_PORT_MS ||
|
|
|
|
- up->su_type == SU_PORT_KBD)
|
|
|
|
- continue;
|
|
|
|
|
|
+ up->port.dev = &op->dev;
|
|
|
|
|
|
- if (up->port.type == PORT_UNKNOWN)
|
|
|
|
- continue;
|
|
|
|
|
|
+ up->port.type = PORT_UNKNOWN;
|
|
|
|
+ up->port.uartclk = (SU_BASE_BAUD * 16);
|
|
|
|
|
|
- uart_add_one_port(&sunsu_reg, &up->port);
|
|
|
|
|
|
+ err = 0;
|
|
|
|
+ if (up->su_type == SU_PORT_KBD || up->su_type == SU_PORT_MS) {
|
|
|
|
+ err = sunsu_kbd_ms_init(up);
|
|
|
|
+ if (err)
|
|
|
|
+ goto out_unmap;
|
|
}
|
|
}
|
|
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
|
|
+ up->port.flags |= UPF_BOOT_AUTOCONF;
|
|
|
|
|
|
-static int su_node_ok(int node, char *name, int namelen)
|
|
|
|
-{
|
|
|
|
- if (strncmp(name, "su", namelen) == 0 ||
|
|
|
|
- strncmp(name, "su_pnp", namelen) == 0)
|
|
|
|
- return 1;
|
|
|
|
-
|
|
|
|
- if (strncmp(name, "serial", namelen) == 0) {
|
|
|
|
- char compat[32];
|
|
|
|
- int clen;
|
|
|
|
-
|
|
|
|
- /* Is it _really_ a 'su' device? */
|
|
|
|
- clen = prom_getproperty(node, "compatible", compat, sizeof(compat));
|
|
|
|
- if (clen > 0) {
|
|
|
|
- if (strncmp(compat, "sab82532", 8) == 0) {
|
|
|
|
- /* Nope, Siemens serial, not for us. */
|
|
|
|
- return 0;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- return 1;
|
|
|
|
- }
|
|
|
|
|
|
+ sunsu_autoconfig(up);
|
|
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
|
|
+ err = -ENODEV;
|
|
|
|
+ if (up->port.type == PORT_UNKNOWN)
|
|
|
|
+ goto out_unmap;
|
|
|
|
|
|
-#define SU_PROPSIZE 128
|
|
|
|
|
|
+ up->port.ops = &sunsu_pops;
|
|
|
|
|
|
-/*
|
|
|
|
- * Scan status structure.
|
|
|
|
- * "prop" is a local variable but it eats stack to keep it in each
|
|
|
|
- * stack frame of a recursive procedure.
|
|
|
|
- */
|
|
|
|
-struct su_probe_scan {
|
|
|
|
- int msnode, kbnode; /* PROM nodes for mouse and keyboard */
|
|
|
|
- int msx, kbx; /* minors for mouse and keyboard */
|
|
|
|
- int devices; /* scan index */
|
|
|
|
- char prop[SU_PROPSIZE];
|
|
|
|
-};
|
|
|
|
|
|
+ err = uart_add_one_port(&sunsu_reg, &up->port);
|
|
|
|
+ if (err)
|
|
|
|
+ goto out_unmap;
|
|
|
|
|
|
-/*
|
|
|
|
- * We have several platforms which present 'su' in different parts
|
|
|
|
- * of the device tree. 'su' may be found under obio, ebus, isa and pci.
|
|
|
|
- * We walk over the tree and find them wherever PROM hides them.
|
|
|
|
- */
|
|
|
|
-static void __init su_probe_any(struct su_probe_scan *t, int sunode)
|
|
|
|
-{
|
|
|
|
- struct uart_sunsu_port *up;
|
|
|
|
- int len;
|
|
|
|
|
|
+ dev_set_drvdata(&op->dev, up);
|
|
|
|
|
|
- if (t->devices >= UART_NR)
|
|
|
|
- return;
|
|
|
|
|
|
+ inst++;
|
|
|
|
|
|
- for (; sunode != 0; sunode = prom_getsibling(sunode)) {
|
|
|
|
- len = prom_getproperty(sunode, "name", t->prop, SU_PROPSIZE);
|
|
|
|
- if (len <= 1)
|
|
|
|
- continue; /* Broken PROM node */
|
|
|
|
-
|
|
|
|
- if (su_node_ok(sunode, t->prop, len)) {
|
|
|
|
- up = &sunsu_ports[t->devices];
|
|
|
|
- if (t->kbnode != 0 && sunode == t->kbnode) {
|
|
|
|
- t->kbx = t->devices;
|
|
|
|
- up->su_type = SU_PORT_KBD;
|
|
|
|
- } else if (t->msnode != 0 && sunode == t->msnode) {
|
|
|
|
- t->msx = t->devices;
|
|
|
|
- up->su_type = SU_PORT_MS;
|
|
|
|
- } else {
|
|
|
|
-#ifdef CONFIG_SPARC64
|
|
|
|
- /*
|
|
|
|
- * Do not attempt to use the truncated
|
|
|
|
- * keyboard/mouse ports as serial ports
|
|
|
|
- * on Ultras with PC keyboard attached.
|
|
|
|
- */
|
|
|
|
- if (prom_getbool(sunode, "mouse"))
|
|
|
|
- continue;
|
|
|
|
- if (prom_getbool(sunode, "keyboard"))
|
|
|
|
- continue;
|
|
|
|
-#endif
|
|
|
|
- up->su_type = SU_PORT_PORT;
|
|
|
|
- }
|
|
|
|
- up->port_node = sunode;
|
|
|
|
- ++t->devices;
|
|
|
|
- } else {
|
|
|
|
- su_probe_any(t, prom_getchild(sunode));
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
|
|
+out_unmap:
|
|
|
|
+ of_iounmap(up->port.membase, up->reg_size);
|
|
|
|
+ return err;
|
|
}
|
|
}
|
|
|
|
|
|
-static int __init sunsu_probe(void)
|
|
|
|
|
|
+static int __devexit su_remove(struct of_device *dev)
|
|
{
|
|
{
|
|
- int node;
|
|
|
|
- int len;
|
|
|
|
- struct su_probe_scan scan;
|
|
|
|
|
|
+ struct uart_sunsu_port *up = dev_get_drvdata(&dev->dev);;
|
|
|
|
|
|
- /*
|
|
|
|
- * First, we scan the tree.
|
|
|
|
- */
|
|
|
|
- scan.devices = 0;
|
|
|
|
- scan.msx = -1;
|
|
|
|
- scan.kbx = -1;
|
|
|
|
- scan.kbnode = 0;
|
|
|
|
- scan.msnode = 0;
|
|
|
|
|
|
+ if (up->su_type == SU_PORT_MS ||
|
|
|
|
+ up->su_type == SU_PORT_KBD) {
|
|
|
|
+#ifdef CONFIG_SERIO
|
|
|
|
+ serio_unregister_port(&up->serio);
|
|
|
|
+#endif
|
|
|
|
+ } else if (up->port.type != PORT_UNKNOWN)
|
|
|
|
+ uart_remove_one_port(&sunsu_reg, &up->port);
|
|
|
|
|
|
- /*
|
|
|
|
- * Get the nodes for keyboard and mouse from 'aliases'...
|
|
|
|
- */
|
|
|
|
- node = prom_getchild(prom_root_node);
|
|
|
|
- node = prom_searchsiblings(node, "aliases");
|
|
|
|
- if (node != 0) {
|
|
|
|
- len = prom_getproperty(node, "keyboard", scan.prop, SU_PROPSIZE);
|
|
|
|
- if (len > 0) {
|
|
|
|
- scan.prop[len] = 0;
|
|
|
|
- scan.kbnode = prom_finddevice(scan.prop);
|
|
|
|
- }
|
|
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
|
|
- len = prom_getproperty(node, "mouse", scan.prop, SU_PROPSIZE);
|
|
|
|
- if (len > 0) {
|
|
|
|
- scan.prop[len] = 0;
|
|
|
|
- scan.msnode = prom_finddevice(scan.prop);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+static struct of_device_id su_match[] = {
|
|
|
|
+ {
|
|
|
|
+ .name = "su",
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ .name = "su_pnp",
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ .name = "serial",
|
|
|
|
+ .compatible = "su",
|
|
|
|
+ },
|
|
|
|
+ {},
|
|
|
|
+};
|
|
|
|
+MODULE_DEVICE_TABLE(of, su_match);
|
|
|
|
|
|
- su_probe_any(&scan, prom_getchild(prom_root_node));
|
|
|
|
|
|
+static struct of_platform_driver su_driver = {
|
|
|
|
+ .name = "su",
|
|
|
|
+ .match_table = su_match,
|
|
|
|
+ .probe = su_probe,
|
|
|
|
+ .remove = __devexit_p(su_remove),
|
|
|
|
+};
|
|
|
|
|
|
- /*
|
|
|
|
- * Second, we process the special case of keyboard and mouse.
|
|
|
|
- *
|
|
|
|
- * Currently if we got keyboard and mouse hooked to "su" ports
|
|
|
|
- * we do not use any possible remaining "su" as a serial port.
|
|
|
|
- * Thus, we ignore values of .msx and .kbx, then compact ports.
|
|
|
|
- */
|
|
|
|
- if (scan.msx != -1 && scan.kbx != -1) {
|
|
|
|
- sunsu_ports[0].su_type = SU_PORT_MS;
|
|
|
|
- sunsu_ports[0].port_node = scan.msnode;
|
|
|
|
- sunsu_kbd_ms_init(&sunsu_ports[0], 0);
|
|
|
|
|
|
+static int num_uart;
|
|
|
|
|
|
- sunsu_ports[1].su_type = SU_PORT_KBD;
|
|
|
|
- sunsu_ports[1].port_node = scan.kbnode;
|
|
|
|
- sunsu_kbd_ms_init(&sunsu_ports[1], 1);
|
|
|
|
|
|
+static int __init sunsu_init(void)
|
|
|
|
+{
|
|
|
|
+ struct device_node *dp;
|
|
|
|
+ int err;
|
|
|
|
|
|
- return 0;
|
|
|
|
|
|
+ num_uart = 0;
|
|
|
|
+ for_each_node_by_name(dp, "su") {
|
|
|
|
+ if (su_get_type(dp) == SU_PORT_PORT)
|
|
|
|
+ num_uart++;
|
|
}
|
|
}
|
|
-
|
|
|
|
- if (scan.msx != -1 || scan.kbx != -1) {
|
|
|
|
- printk("sunsu_probe: cannot match keyboard and mouse, confused\n");
|
|
|
|
- return -ENODEV;
|
|
|
|
|
|
+ for_each_node_by_name(dp, "su_pnp") {
|
|
|
|
+ if (su_get_type(dp) == SU_PORT_PORT)
|
|
|
|
+ num_uart++;
|
|
|
|
+ }
|
|
|
|
+ for_each_node_by_name(dp, "serial") {
|
|
|
|
+ if (of_device_is_compatible(dp, "su")) {
|
|
|
|
+ if (su_get_type(dp) == SU_PORT_PORT)
|
|
|
|
+ num_uart++;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
- if (scan.devices == 0)
|
|
|
|
- return -ENODEV;
|
|
|
|
|
|
+ if (num_uart) {
|
|
|
|
+ sunsu_reg.minor = sunserial_current_minor;
|
|
|
|
+ sunsu_reg.nr = num_uart;
|
|
|
|
+ err = uart_register_driver(&sunsu_reg);
|
|
|
|
+ if (err)
|
|
|
|
+ return err;
|
|
|
|
+ sunsu_reg.tty_driver->name_base = sunsu_reg.minor - 64;
|
|
|
|
+ sunserial_current_minor += num_uart;
|
|
|
|
+ sunsu_reg.cons = SUNSU_CONSOLE(num_uart);
|
|
|
|
+ }
|
|
|
|
|
|
- /*
|
|
|
|
- * Console must be initiated after the generic initialization.
|
|
|
|
- */
|
|
|
|
- sunsu_serial_init();
|
|
|
|
|
|
+ err = of_register_driver(&su_driver, &of_bus_type);
|
|
|
|
+ if (err && num_uart)
|
|
|
|
+ uart_unregister_driver(&sunsu_reg);
|
|
|
|
|
|
- return 0;
|
|
|
|
|
|
+ return err;
|
|
}
|
|
}
|
|
|
|
|
|
static void __exit sunsu_exit(void)
|
|
static void __exit sunsu_exit(void)
|
|
{
|
|
{
|
|
- int i, saw_uart;
|
|
|
|
-
|
|
|
|
- saw_uart = 0;
|
|
|
|
- for (i = 0; i < UART_NR; i++) {
|
|
|
|
- struct uart_sunsu_port *up = &sunsu_ports[i];
|
|
|
|
-
|
|
|
|
- if (up->su_type == SU_PORT_MS ||
|
|
|
|
- up->su_type == SU_PORT_KBD) {
|
|
|
|
-#ifdef CONFIG_SERIO
|
|
|
|
- if (up->serio) {
|
|
|
|
- serio_unregister_port(up->serio);
|
|
|
|
- up->serio = NULL;
|
|
|
|
- }
|
|
|
|
-#endif
|
|
|
|
- } else if (up->port.type != PORT_UNKNOWN) {
|
|
|
|
- uart_remove_one_port(&sunsu_reg, &up->port);
|
|
|
|
- saw_uart++;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (saw_uart)
|
|
|
|
|
|
+ if (num_uart)
|
|
uart_unregister_driver(&sunsu_reg);
|
|
uart_unregister_driver(&sunsu_reg);
|
|
}
|
|
}
|
|
|
|
|
|
-module_init(sunsu_probe);
|
|
|
|
|
|
+module_init(sunsu_init);
|
|
module_exit(sunsu_exit);
|
|
module_exit(sunsu_exit);
|
|
MODULE_LICENSE("GPL");
|
|
MODULE_LICENSE("GPL");
|