* Copyright (C) 2002 Ralf Baechle (ralf@linux-mips.org)
* Copyright (C) 2002 David S. Miller (davem@redhat.com)
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include "ip22zilog.h"
-int ip22serial_current_minor = 64;
-
void ip22_do_break(void);
/*
#define ZSDELAY_LONG() udelay(20)
#define ZS_WSYNC(channel) do { } while (0)
-#define NUM_IP22ZILOG 1
-#define NUM_CHANNELS (NUM_IP22ZILOG * 2)
+#define NUM_IP22ZILOG 1
+#define NUM_CHANNELS (NUM_IP22ZILOG * 2)
-#define ZS_CLOCK 4915200 /* Zilog input clock rate. */
+#define ZS_CLOCK 3672000 /* Zilog input clock rate. */
#define ZS_CLOCK_DIVISOR 16 /* Divisor this driver uses. */
/*
#define IP22ZILOG_FLAG_TX_STOPPED 0x00000080
#define IP22ZILOG_FLAG_TX_ACTIVE 0x00000100
- unsigned int cflag;
+ unsigned int cflag;
/* L1-A keyboard break state. */
int kbd_id;
/* Lower and upper byte of baud rate generator divisor. */
write_zsreg(channel, R12, regs[R12]);
write_zsreg(channel, R13, regs[R13]);
-
+
/* Now rewrite R14, with BRENAB (if set). */
write_zsreg(channel, R14, regs[R14]);
}
static void ip22zilog_receive_chars(struct uart_ip22zilog_port *up,
- struct zilog_channel *channel,
- struct pt_regs *regs)
+ struct zilog_channel *channel)
{
struct tty_struct *tty = up->port.info->tty; /* XXX info==NULL? */
while (1) {
- unsigned char ch, r1;
-
- if (unlikely(tty->flip.count >= TTY_FLIPBUF_SIZE)) {
- tty->flip.work.func((void *)tty);
- if (tty->flip.count >= TTY_FLIPBUF_SIZE)
- return; /* XXX Ignores SysRq when we need it most. Fix. */
- }
+ unsigned char ch, r1, flag;
r1 = read_zsreg(channel, R1);
if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR)) {
}
/* A real serial line, record the character and status. */
- *tty->flip.char_buf_ptr = ch;
- *tty->flip.flag_buf_ptr = TTY_NORMAL;
+ flag = TTY_NORMAL;
up->port.icount.rx++;
if (r1 & (BRK_ABRT | PAR_ERR | Rx_OVR | CRC_ERR)) {
if (r1 & BRK_ABRT) {
up->port.icount.overrun++;
r1 &= up->port.read_status_mask;
if (r1 & BRK_ABRT)
- *tty->flip.flag_buf_ptr = TTY_BREAK;
+ flag = TTY_BREAK;
else if (r1 & PAR_ERR)
- *tty->flip.flag_buf_ptr = TTY_PARITY;
+ flag = TTY_PARITY;
else if (r1 & CRC_ERR)
- *tty->flip.flag_buf_ptr = TTY_FRAME;
+ flag = TTY_FRAME;
}
- if (uart_handle_sysrq_char(&up->port, ch, regs))
+ if (uart_handle_sysrq_char(&up->port, ch))
goto next_char;
if (up->port.ignore_status_mask == 0xff ||
- (r1 & up->port.ignore_status_mask) == 0) {
- tty->flip.flag_buf_ptr++;
- tty->flip.char_buf_ptr++;
- tty->flip.count++;
- }
- if ((r1 & Rx_OVR) &&
- tty->flip.count < TTY_FLIPBUF_SIZE) {
- *tty->flip.flag_buf_ptr = TTY_OVERRUN;
- tty->flip.flag_buf_ptr++;
- tty->flip.char_buf_ptr++;
- tty->flip.count++;
- }
+ (r1 & up->port.ignore_status_mask) == 0)
+ tty_insert_flip_char(tty, ch, flag);
+
+ if (r1 & Rx_OVR)
+ tty_insert_flip_char(tty, 0, TTY_OVERRUN);
next_char:
ch = readb(&channel->control);
ZSDELAY();
}
static void ip22zilog_status_handle(struct uart_ip22zilog_port *up,
- struct zilog_channel *channel,
- struct pt_regs *regs)
+ struct zilog_channel *channel)
{
unsigned char status;
if (up->port.info == NULL)
goto ack_tx_int;
xmit = &up->port.info->xmit;
- if (uart_circ_empty(xmit)) {
- uart_write_wakeup(&up->port);
+ if (uart_circ_empty(xmit))
goto ack_tx_int;
- }
if (uart_tx_stopped(&up->port))
goto ack_tx_int;
ZS_WSYNC(channel);
}
-static irqreturn_t ip22zilog_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t ip22zilog_interrupt(int irq, void *dev_id)
{
struct uart_ip22zilog_port *up = dev_id;
ZS_WSYNC(channel);
if (r3 & CHARxIP)
- ip22zilog_receive_chars(up, channel, regs);
+ ip22zilog_receive_chars(up, channel);
if (r3 & CHAEXT)
- ip22zilog_status_handle(up, channel, regs);
+ ip22zilog_status_handle(up, channel);
if (r3 & CHATxIP)
ip22zilog_transmit_chars(up, channel);
}
ZS_WSYNC(channel);
if (r3 & CHBRxIP)
- ip22zilog_receive_chars(up, channel, regs);
+ ip22zilog_receive_chars(up, channel);
if (r3 & CHBEXT)
- ip22zilog_status_handle(up, channel, regs);
+ ip22zilog_status_handle(up, channel);
if (r3 & CHBTxIP)
ip22zilog_transmit_chars(up, channel);
}
static __inline__ unsigned char ip22zilog_read_channel_status(struct uart_port *port)
{
struct zilog_channel *channel;
- unsigned long flags;
unsigned char status;
- spin_lock_irqsave(&port->lock, flags);
-
channel = ZILOG_CHANNEL_FROM_PORT(port);
status = readb(&channel->control);
ZSDELAY();
- spin_unlock_irqrestore(&port->lock, flags);
-
return status;
}
/* The port lock is not held. */
static unsigned int ip22zilog_tx_empty(struct uart_port *port)
{
+ unsigned long flags;
unsigned char status;
unsigned int ret;
+ spin_lock_irqsave(&port->lock, flags);
+
status = ip22zilog_read_channel_status(port);
+
+ spin_unlock_irqrestore(&port->lock, flags);
+
if (status & Tx_BUF_EMP)
ret = TIOCSER_TEMT;
else
return ret;
}
-/* The port lock is not held. */
+/* The port lock is held and interrupts are disabled. */
static unsigned int ip22zilog_get_mctrl(struct uart_port *port)
{
unsigned char status;
else
clear_bits |= DTR;
- /* NOTE: Not subject to 'transmitter active' rule. */
+ /* NOTE: Not subject to 'transmitter active' rule. */
up->curregs[R5] |= set_bits;
up->curregs[R5] &= ~clear_bits;
write_zsreg(channel, R5, up->curregs[R5]);
}
/* The port lock is held and interrupts are disabled. */
-static void ip22zilog_stop_tx(struct uart_port *port, unsigned int tty_stop)
+static void ip22zilog_stop_tx(struct uart_port *port)
{
struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port;
}
/* The port lock is held and interrupts are disabled. */
-static void ip22zilog_start_tx(struct uart_port *port, unsigned int tty_start)
+static void ip22zilog_start_tx(struct uart_port *port)
{
struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port;
struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port);
}
}
-/* The port lock is not held. */
+/* The port lock is held and interrupts are disabled. */
static void ip22zilog_stop_rx(struct uart_port *port)
{
struct uart_ip22zilog_port *up = UART_ZILOG(port);
struct zilog_channel *channel;
- unsigned long flags;
if (ZS_IS_CONS(up))
return;
- spin_lock_irqsave(&port->lock, flags);
-
channel = ZILOG_CHANNEL_FROM_PORT(port);
/* Disable all RX interrupts. */
up->curregs[R1] &= ~RxINT_MASK;
ip22zilog_maybe_update_regs(up, channel);
-
- spin_unlock_irqrestore(&port->lock, flags);
}
-/* The port lock is not held. */
+/* The port lock is held. */
static void ip22zilog_enable_ms(struct uart_port *port)
{
struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port;
struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port);
unsigned char new_reg;
- unsigned long flags;
-
- spin_lock_irqsave(&port->lock, flags);
new_reg = up->curregs[R15] | (DCDIE | SYNCIE | CTSIE);
if (new_reg != up->curregs[R15]) {
up->curregs[R15] = new_reg;
- /* NOTE: Not subject to 'transmitter active' rule. */
+ /* NOTE: Not subject to 'transmitter active' rule. */
write_zsreg(channel, R15, up->curregs[R15]);
}
-
- spin_unlock_irqrestore(&port->lock, flags);
}
/* The port lock is not held. */
if (new_reg != up->curregs[R5]) {
up->curregs[R5] = new_reg;
- /* NOTE: Not subject to 'transmitter active' rule. */
+ /* NOTE: Not subject to 'transmitter active' rule. */
write_zsreg(channel, R5, up->curregs[R5]);
}
up->curregs[R4] |= X16CLK;
up->curregs[R12] = brg & 0xff;
up->curregs[R13] = (brg >> 8) & 0xff;
- up->curregs[R14] = BRSRC | BRENAB;
+ up->curregs[R14] = BRENAB;
/* Character size, stop bits, and parity. */
up->curregs[3] &= ~RxN_MASK;
/* The port lock is not held. */
static void
-ip22zilog_set_termios(struct uart_port *port, struct termios *termios,
- struct termios *old)
+ip22zilog_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
{
struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port;
unsigned long flags;
static struct uart_ip22zilog_port *ip22zilog_irq_chain;
static int zilog_irq = -1;
-static struct uart_driver ip22zilog_reg = {
- .owner = THIS_MODULE,
- .driver_name = "ttyS",
- .devfs_name = "tty/",
- .major = TTY_MAJOR,
-};
-
static void * __init alloc_one_table(unsigned long size)
{
void *ret;
}
/* Not probe-able, hard code it. */
- base = (unsigned long) &sgioc->serport;
+ base = (unsigned long) &sgioc->uart;
zilog_irq = SGI_SERIAL_IRQ;
request_mem_region(base, 8, "IP22-Zilog");
#define ZS_PUT_CHAR_MAX_DELAY 2000 /* 10 ms */
#ifdef CONFIG_SERIAL_IP22_ZILOG_CONSOLE
-static void ip22zilog_put_char(struct zilog_channel *channel, unsigned char ch)
+static void ip22zilog_put_char(struct uart_port *port, int ch)
{
+ struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port);
int loops = ZS_PUT_CHAR_MAX_DELAY;
/* This is a timed polling loop so do not switch the explicit
ip22zilog_console_write(struct console *con, const char *s, unsigned int count)
{
struct uart_ip22zilog_port *up = &ip22zilog_port_table[con->index];
- struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
unsigned long flags;
- int i;
spin_lock_irqsave(&up->port.lock, flags);
- for (i = 0; i < count; i++, s++) {
- ip22zilog_put_char(channel, *s);
- if (*s == 10)
- ip22zilog_put_char(channel, 13);
- }
+ uart_console_write(&up->port, s, count, ip22zilog_put_char);
udelay(2);
spin_unlock_irqrestore(&up->port.lock, flags);
}
int parity = 'n';
int flow = 'n';
- if (!serial_console)
- return;
-
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
unsigned long flags;
int baud, brg;
- printk("Console: ttyS%d (IP22-Zilog)\n",
- (ip22zilog_reg.minor - 64) + con->index);
+ printk("Console: ttyS%d (IP22-Zilog)\n", con->index);
/* Get firmware console settings. */
ip22serial_console_termios(con, options);
return 0;
}
+static struct uart_driver ip22zilog_reg;
+
static struct console ip22zilog_console = {
.name = "ttyS",
.write = ip22zilog_console_write,
.index = -1,
.data = &ip22zilog_reg,
};
-#define IP22ZILOG_CONSOLE (&ip22zilog_console)
-
-static int __init ip22zilog_console_init(void)
-{
- int i;
-
- if (con_is_present())
- return 0;
-
- for (i = 0; i < NUM_CHANNELS; i++) {
- int this_minor = ip22zilog_reg.minor + i;
-
- if ((this_minor - 64) == (serial_console - 1))
- break;
- }
- if (i == NUM_CHANNELS)
- return 0;
+#endif /* CONFIG_SERIAL_IP22_ZILOG_CONSOLE */
- ip22zilog_console.index = i;
- register_console(&ip22zilog_console);
- return 0;
-}
-#else /* CONFIG_SERIAL_IP22_ZILOG_CONSOLE */
-#define IP22ZILOG_CONSOLE (NULL)
-#define ip22zilog_console_init() do { } while (0)
+static struct uart_driver ip22zilog_reg = {
+ .owner = THIS_MODULE,
+ .driver_name = "serial",
+ .dev_name = "ttyS",
+ .major = TTY_MAJOR,
+ .minor = 64,
+ .nr = NUM_CHANNELS,
+#ifdef CONFIG_SERIAL_IP22_ZILOG_CONSOLE
+ .cons = &ip22zilog_console,
#endif
+};
static void __init ip22zilog_prepare(void)
{
for (channel = 0; channel < NUM_CHANNELS; channel++)
spin_lock_init(&ip22zilog_port_table[channel].port.lock);
- ip22zilog_irq_chain = up = &ip22zilog_port_table[0];
- for (channel = 0; channel < NUM_CHANNELS - 1; channel++)
- up[channel].next = &up[channel + 1];
+ ip22zilog_irq_chain = &ip22zilog_port_table[NUM_CHANNELS - 1];
+ up = &ip22zilog_port_table[0];
+ for (channel = NUM_CHANNELS - 1 ; channel > 0; channel--)
+ up[channel].next = &up[channel - 1];
up[channel].next = NULL;
for (chip = 0; chip < NUM_IP22ZILOG; chip++) {
if (!ip22zilog_chip_regs[chip]) {
ip22zilog_chip_regs[chip] = rp = get_zs(chip);
- up[(chip * 2) + 0].port.membase = (char *) &rp->channelA;
- up[(chip * 2) + 1].port.membase = (char *) &rp->channelB;
+ up[(chip * 2) + 0].port.membase = (char *) &rp->channelB;
+ up[(chip * 2) + 1].port.membase = (char *) &rp->channelA;
+
+ /* In theory mapbase is the physical address ... */
+ up[(chip * 2) + 0].port.mapbase =
+ (unsigned long) ioremap((unsigned long) &rp->channelB, 8);
+ up[(chip * 2) + 1].port.mapbase =
+ (unsigned long) ioremap((unsigned long) &rp->channelA, 8);
}
/* Channel A */
up[(chip * 2) + 0].port.type = PORT_IP22ZILOG;
up[(chip * 2) + 0].port.flags = 0;
up[(chip * 2) + 0].port.line = (chip * 2) + 0;
- up[(chip * 2) + 0].flags |= IP22ZILOG_FLAG_IS_CHANNEL_A;
+ up[(chip * 2) + 0].flags = 0;
/* Channel B */
up[(chip * 2) + 1].port.iotype = UPIO_MEM;
up[(chip * 2) + 1].port.fifosize = 1;
up[(chip * 2) + 1].port.ops = &ip22zilog_pops;
up[(chip * 2) + 1].port.type = PORT_IP22ZILOG;
- up[(chip * 2) + 1].port.flags = 0;
up[(chip * 2) + 1].port.line = (chip * 2) + 1;
- up[(chip * 2) + 1].flags |= 0;
+ up[(chip * 2) + 1].flags |= IP22ZILOG_FLAG_IS_CHANNEL_A;
}
}
brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR);
up->curregs[R12] = (brg & 0xff);
up->curregs[R13] = (brg >> 8) & 0xff;
- up->curregs[R14] = BRSRC | BRENAB;
+ up->curregs[R14] = BRENAB;
__load_zsregs(channel, up->curregs);
+ /* set master interrupt enable */
+ write_zsreg(channel, R9, up->curregs[R9]);
spin_unlock_irqrestore(&up->port.lock, flags);
}
ip22zilog_init_hw();
- /* We can only init this once we have probed the Zilogs
- * in the system.
- */
- ip22zilog_reg.nr = NUM_CHANNELS;
- ip22zilog_reg.cons = IP22ZILOG_CONSOLE;
-
- ip22zilog_reg.minor = ip22serial_current_minor;
- ip22serial_current_minor += NUM_CHANNELS;
-
ret = uart_register_driver(&ip22zilog_reg);
if (ret == 0) {
int i;
static int __init ip22zilog_init(void)
{
/* IP22 Zilog setup is hard coded, no probing to do. */
-
ip22zilog_alloc_tables();
-
ip22zilog_ports_init();
- ip22zilog_console_init();
return 0;
}
static void __exit ip22zilog_exit(void)
{
int i;
+ struct uart_ip22zilog_port *up;
for (i = 0; i < NUM_CHANNELS; i++) {
- struct uart_ip22zilog_port *up = &ip22zilog_port_table[i];
+ up = &ip22zilog_port_table[i];
uart_remove_one_port(&ip22zilog_reg, &up->port);
}
+ /* Free IO mem */
+ up = &ip22zilog_port_table[0];
+ for (i = 0; i < NUM_IP22ZILOG; i++) {
+ if (up[(i * 2) + 0].port.mapbase) {
+ iounmap((void*)up[(i * 2) + 0].port.mapbase);
+ up[(i * 2) + 0].port.mapbase = 0;
+ }
+ if (up[(i * 2) + 1].port.mapbase) {
+ iounmap((void*)up[(i * 2) + 1].port.mapbase);
+ up[(i * 2) + 1].port.mapbase = 0;
+ }
+ }
+
uart_unregister_driver(&ip22zilog_reg);
}