* David S. Miller (davem@redhat.com), 2002-Jul-29
*/
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/circ_buf.h>
+#include <linux/serial.h>
+#include <linux/console.h>
+#include <linux/spinlock.h>
#ifdef CONFIG_SERIO
#include <linux/serio.h>
#endif
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/oplib.h>
+#include <asm/ebus.h>
+#ifdef CONFIG_SPARC64
+#include <asm/isa.h>
+#endif
+
+#include <linux/serial_core.h>
+#include <linux/serial_reg.h>
#include "suncore.h"
-#include "sunkbd.h"
-#include "sunmouse.h"
/* We are on a NS PC87303 clocked with 24.0 MHz, which results
* in a UART clock of 1.8462 MHz.
*/
-#define BAUD_BASE (1846200 / 16)
+#define SU_BASE_BAUD (1846200 / 16)
enum su_type { SU_PORT_NONE, SU_PORT_MS, SU_PORT_KBD, SU_PORT_PORT };
-static char *su_typev[] = { "???", "mouse", "kbd", "serial" };
+static char *su_typev[] = { "su(???)", "su(mouse)", "su(kbd)", "su(serial)" };
/*
* Here we define the default xmit fifo size used for each type of UART.
{ "RSA", 2048, UART_CLEAR_FIFO | UART_USE_FIFO }
};
+struct uart_sunsu_port {
+ struct uart_port port;
+ unsigned char acr;
+ unsigned char ier;
+ unsigned char rev;
+ unsigned char lcr;
+ unsigned int lsr_break_flag;
+ unsigned int cflag;
+
+ /* Probing information. */
+ enum su_type su_type;
+ int port_node;
+ unsigned int irq;
+
+ /* L1-A keyboard break state. */
+ int kbd_id;
+ int l1_down;
+#ifdef CONFIG_SERIO
+ struct serio serio;
+#endif
+};
+
#define _INLINE_
static _INLINE_ unsigned int serial_in(struct uart_sunsu_port *up, int offset)
serial_out(up, UART_ICR, value);
}
+#if 0 /* Unused currently */
static unsigned int serial_icr_read(struct uart_sunsu_port *up, int offset)
{
unsigned int value;
return value;
}
+#endif
#ifdef CONFIG_SERIAL_8250_RSA
/*
}
static _INLINE_ void
-receive_chars(struct uart_sunsu_port *up, int *status, struct pt_regs *regs)
+receive_chars(struct uart_sunsu_port *up, unsigned char *status, struct pt_regs *regs)
{
struct tty_struct *tty = up->port.info->tty;
unsigned char ch;
if (*status & UART_LSR_BI) {
*status &= ~(UART_LSR_FE | UART_LSR_PE);
up->port.icount.brk++;
- if (SU_IS_CONS(up))
+ if (up->port.line == up->port.cons->index)
saw_console_brk = 1;
/*
* We do the SysRQ and SAK checking
do {
status = serial_inp(up, UART_LSR);
if (status & UART_LSR_DR)
- receive_serial_chars(up, &status, regs);
+ receive_chars(up, &status, regs);
check_modem_status(up);
if (status & UART_LSR_THRE)
transmit_chars(up);
static void sunsu_change_mouse_baud(struct uart_sunsu_port *up)
{
- unsigned int cur_cflag = up->port.cflag;
+ unsigned int cur_cflag = up->cflag;
int quot, new_baud;
- up->port.cflag &= ~CBAUD;
- up->port.cflag |= suncore_mouse_baud_cflag_next(cur_cflag, &new_baud);
+ up->cflag &= ~CBAUD;
+ up->cflag |= suncore_mouse_baud_cflag_next(cur_cflag, &new_baud);
- quot = sunsu_calc_quot(new_baud);
+ quot = up->port.uartclk / (16 * new_baud);
spin_unlock(&up->port.lock);
- sunsu_change_speed(up, up->port.cflag, 0, quot);
+ sunsu_change_speed(&up->port, up->cflag, 0, quot);
spin_lock(&up->port.lock);
}
do {
unsigned char ch = serial_inp(up, UART_RX);
- if (up->port_type == SU_PORT_KBD) {
+ if (up->su_type == SU_PORT_KBD) {
if (ch == SUNKBD_RESET) {
up->kbd_id = 1;
up->l1_down = 0;
#ifdef CONFIG_SERIO
serio_interrupt(&up->serio, ch, 0);
#endif
- } else if (up->port_type == SU_PORT_MS) {
+ } else if (up->su_type == SU_PORT_MS) {
int ret = suncore_mouse_baud_detection(ch, is_break);
switch (ret) {
return -ENODEV;
}
+ if (up->su_type != SU_PORT_PORT) {
+ retval = request_irq(up->irq, sunsu_kbd_ms_interrupt,
+ SA_SHIRQ, su_typev[up->su_type], up);
+ } else {
+ retval = request_irq(up->irq, sunsu_serial_interrupt,
+ SA_SHIRQ, su_typev[up->su_type], up);
+ }
+ if (retval) {
+ printk("su: Cannot register IRQ\n");
+ return retval;
+ }
+
/*
* Now, initialize the UART
*/
}
serial_outp(up, UART_FCR, fcr); /* set fcr */
}
+
+ up->cflag = cflag;
+
spin_unlock_irqrestore(&up->port.lock, flags);
}
.startup = sunsu_startup,
.shutdown = sunsu_shutdown,
.change_speed = sunsu_change_speed,
- .pm = sunsu_pm,
.type = sunsu_type,
.release_port = sunsu_release_port,
.request_port = sunsu_request_port,
static spinlock_t sunsu_serio_lock = SPIN_LOCK_UNLOCKED;
-static void sunsu_serio_write(struct serio *serio, unsigned char ch)
+static int sunsu_serio_write(struct serio *serio, unsigned char ch)
{
struct uart_sunsu_port *up = serio->driver;
unsigned long flags;
} while (!(lsr & UART_LSR_THRE));
/* Send the character out. */
- sunsu_writeb(up, UART_TX, c);
+ serial_out(up, UART_TX, ch);
spin_unlock_irqrestore(&sunsu_serio_lock, flags);
+
+ return 0;
}
static int sunsu_serio_open(struct serio *serio)
#endif
unsigned long flags;
- if (!up->port_node || !up->port_type)
+ if (!up->port_node || !up->su_type)
return;
/*
}
serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
}
- serial_outp(up, UART_LCR, scratch2);
+ serial_outp(up, UART_LCR, save_lcr);
if (up->port.type == PORT_16450) {
scratch = serial_in(up, UART_SCR);
serial_outp(up, UART_SCR, 0xa5);
up->port.type = PORT_8250;
}
- up->port.xmit_fifo_size = uart_config[up->port.type].dfl_xmit_fifo_size;
+ up->port.fifosize = uart_config[up->port.type].dfl_xmit_fifo_size;
if (up->port.type == PORT_UNKNOWN)
goto out;
- sprintf(up->name, "su(%s)", su_typev[up->port_type]);
-
/*
* Reset the UART.
*/
.major = TTY_MAJOR,
};
-static int __init sunsu_serial_init(void)
-{
- int instance, ret;
-
- /* How many instances do we need? */
- instance = 0;
- for (i = 0; i < UART_NR; i++) {
- if (up->port_type == SU_PORT_MS ||
- up->port_type == SU_PORT_KBD)
- continue;
-
- up->port.type = PORT_UNKNOWN;
- up->port.baud_base = BAUD_BASE;
-
- sunsu_autoconfig(up);
- if (up->port.type == PORT_UNKNOWN)
- continue;
-
- up->port.line = instance++;
- up->port.ops = &sunsu_pops;
- }
-
- sunsu_reg.minor = sunserial_current_minor;
- sunserial_current_minor += instance;
-
- sunsu_reg.nr = instance;
- sunsu_reg.cons = &sunsu_console;
-
- ret = uart_register_driver(&sunsu_reg);
- if (ret < 0)
- return ret;
-
- instance = 0;
- for (i = 0; i < UART_NR; i++) {
- struct uart_sunsu_port *up = &sunsu_port[i];
-
- /* Do not register Keyboard/Mouse lines with UART
- * layer.
- */
- if (up->port_type == SU_PORT_MS ||
- up->port_type == SU_PORT_KBD)
- continue;
-
- if (up->port.type == PORT_UNKNOWN)
- continue;
-
- uart_add_one_port(&sunsu_reg, up);
- }
-
- return 0;
-}
-
-static int __init su_kbd_ms_init(void)
+static int __init sunsu_kbd_ms_init(void)
{
struct uart_sunsu_port *up;
int i;
for (i = 0, up = sunsu_ports; i < 2; i++, up++) {
up->port.line = i;
up->port.type = PORT_UNKNOWN;
- up->port.baud_base = BAUD_BASE;
+ up->port.uartclk = (SU_BASE_BAUD * 16);
- if (up->port_type == SU_PORT_KBD)
- up->port.cflag = B1200 | CS8 | CLOCAL | CREAD;
+ if (up->su_type == SU_PORT_KBD)
+ up->cflag = B1200 | CS8 | CLOCAL | CREAD;
else
- up->port.cflag = B4800 | CS8 | CLOCAL | CREAD;
+ up->cflag = B4800 | CS8 | CLOCAL | CREAD;
sunsu_autoconfig(up);
if (up->port.type == PORT_UNKNOWN)
up->serio.driver = up;
up->serio.type = SERIO_RS232;
- if (up->port_type == SU_PORT_KBD) {
+ if (up->su_type == SU_PORT_KBD) {
up->serio.type |= SERIO_SUNKBD;
up->serio.name = "sukbd";
} else {
up->serio.type |= SERIO_SUN;
up->serio.name = "sums";
}
- up->phys = (i == 0 ? "su/serio0" : "su/serio1");
+ up->serio.phys = (i == 0 ? "su/serio0" : "su/serio1");
up->serio.write = sunsu_serio_write;
up->serio.open = sunsu_serio_open;
serio_register_port(&up->serio);
#endif
- sunsu_startup(up);
+ sunsu_startup(&up->port);
}
return 0;
}
return 0;
index = serial_console - 1;
- if (su_table[index].port == 0 || su_table[index].port_node == 0)
+ if (sunsu_ports[index].port_node == 0)
return 0;
sunsu_cons.index = index;
register_console(&sunsu_cons);
return 0;
}
+static int __init sunsu_serial_init(void)
+{
+ 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];
+
+ if (up->su_type == SU_PORT_MS ||
+ up->su_type == SU_PORT_KBD)
+ continue;
+
+ up->port.type = PORT_UNKNOWN;
+ up->port.uartclk = (SU_BASE_BAUD * 16);
+
+ sunsu_autoconfig(up);
+ if (up->port.type == PORT_UNKNOWN)
+ continue;
+
+ up->port.line = instance++;
+ up->port.ops = &sunsu_pops;
+ }
+
+ sunsu_reg.minor = sunserial_current_minor;
+ sunserial_current_minor += instance;
+
+ sunsu_reg.nr = instance;
+ sunsu_reg.cons = &sunsu_cons;
+
+ ret = uart_register_driver(&sunsu_reg);
+ if (ret < 0)
+ return ret;
+
+ instance = 0;
+ for (i = 0; i < UART_NR; i++) {
+ struct uart_sunsu_port *up = &sunsu_ports[i];
+
+ /* Do not register Keyboard/Mouse lines with UART
+ * layer.
+ */
+ if (up->su_type == SU_PORT_MS ||
+ up->su_type == SU_PORT_KBD)
+ continue;
+
+ if (up->port.type == PORT_UNKNOWN)
+ continue;
+
+ uart_add_one_port(&sunsu_reg, &up->port);
+ }
+
+ return 0;
+}
+
static int su_node_ok(int node, char *name, int namelen)
{
if (strncmp(name, "su", namelen) == 0 ||
*/
static void __init su_probe_any(struct su_probe_scan *t, int sunode)
{
- struct su_struct *info;
+ struct uart_sunsu_port *up;
int len;
if (t->devices >= UART_NR)
continue; /* Broken PROM node */
if (su_node_ok(sunode, t->prop, len)) {
- info = &su_table[t->devices];
+ up = &sunsu_ports[t->devices];
if (t->kbnode != 0 && sunode == t->kbnode) {
t->kbx = t->devices;
- info->port_type = SU_PORT_KBD;
+ up->su_type = SU_PORT_KBD;
} else if (t->msnode != 0 && sunode == t->msnode) {
t->msx = t->devices;
- info->port_type = SU_PORT_MS;
+ up->su_type = SU_PORT_MS;
} else {
#ifdef CONFIG_SPARC64
/*
if (prom_getbool(sunode, "keyboard"))
continue;
#endif
- info->port_type = SU_PORT_PORT;
+ up->su_type = SU_PORT_PORT;
}
- info->is_console = 0;
- info->port_node = sunode;
+ up->port_node = sunode;
++t->devices;
} else {
su_probe_any(t, prom_getchild(sunode));
* Thus, we ignore values of .msx and .kbx, then compact ports.
*/
if (scan.msx != -1 && scan.kbx != -1) {
- sunsu_ports[0].port_type = SU_PORT_MS;
+ sunsu_ports[0].su_type = SU_PORT_MS;
sunsu_ports[0].port_node = scan.msnode;
- sunsu_ports[1].port_type = SU_PORT_KBD;
+ sunsu_ports[1].su_type = SU_PORT_KBD;
sunsu_ports[1].port_node = scan.kbnode;
sunsu_kbd_ms_init();
for (i = 0; i < UART_NR; i++) {
struct uart_sunsu_port *up = &sunsu_ports[i];
- if (up->port_type == SU_PORT_MS ||
- up->port_type == SU_PORT_KBD) {
+ 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);
+ uart_remove_one_port(&sunsu_reg, &up->port);
saw_uart++;
}
}