* Russell King <rmk@arm.linux.org.uk> [2006-03-25 17:34]:
> > - if ((status & DCD) ^ up->prev_status)
> > + if ((status ^ up->prev_status) ^ DCD)
> Shouldn't this be (status ^ up->prev_status) & DCD ?
>
> > - if ((status & CTS) ^ up->prev_status)
> > + if ((status ^ up->prev_status) ^ CTS)
> Shouldn't this be (status ^ up->prev_status) & CTS ?
Thanks for catching this! I obviously copied too much from sunzilog.c
without thinking. Below is a new version which has this fix and which
has been updated so it apples to 2.6.17-rc1.
[PATCH] Sync ip22zilog with latest sunzilog driver
ip22zilog is based on the sunzilog driver, but there hasn't been a sync
since 2.6.0-test7. Sync the relevant changes that have been made since
then.
Signed-off-by: Martin Michlmayr <tbm@cyrius.com>
--- a/drivers/serial/ip22zilog.c
+++ b/drivers/serial/ip22zilog.c
@@ -2,7 +2,7 @@
* Driver for Zilog serial chips found on SGI workstations and
* servers. This driver could actually be made more generic.
*
- * This is based on the drivers/serial/sunzilog.c code as of 2.6.0-test7 and
the
+ * This is based on the drivers/serial/sunzilog.c code as of 2.6.17-rc1 and the
* old drivers/sgi/char/sgiserial.c code which itself is based of the original
* drivers/sbus/char/zs.c code. A lot of code has been simply moved over
* directly from there but much has been rewritten. Credits therefore go out
@@ -86,15 +86,11 @@ struct uart_ip22zilog_port {
unsigned int cflag;
- /* L1-A keyboard break state. */
- int kbd_id;
- int l1_down;
-
unsigned char parity_mask;
unsigned char prev_status;
};
-#define ZILOG_CHANNEL_FROM_PORT(PORT) ((struct zilog_channel
*)((PORT)->membase))
+#define ZILOG_CHANNEL_FROM_PORT(PORT) ((struct zilog_channel __iomem
*)((PORT)->membase))
#define UART_ZILOG(PORT) ((struct uart_ip22zilog_port *)(PORT))
#define IP22ZILOG_GET_CURR_REG(PORT, REGNUM) \
(UART_ZILOG(PORT)->curregs[REGNUM])
@@ -116,7 +112,7 @@ struct uart_ip22zilog_port {
* The port lock must be held and local IRQs must be disabled
* when {read,write}_zsreg is invoked.
*/
-static unsigned char read_zsreg(struct zilog_channel *channel,
+static unsigned char read_zsreg(struct zilog_channel __iomem *channel,
unsigned char reg)
{
unsigned char retval;
@@ -129,7 +125,7 @@ static unsigned char read_zsreg(struct z
return retval;
}
-static void write_zsreg(struct zilog_channel *channel,
+static void write_zsreg(struct zilog_channel __iomem *channel,
unsigned char reg, unsigned char value)
{
writeb(reg, &channel->control);
@@ -138,7 +134,7 @@ static void write_zsreg(struct zilog_cha
ZSDELAY();
}
-static void ip22zilog_clear_fifo(struct zilog_channel *channel)
+static void ip22zilog_clear_fifo(struct zilog_channel __iomem *channel)
{
int i;
@@ -165,7 +161,7 @@ static void ip22zilog_clear_fifo(struct
/* This function must only be called when the TX is not busy. The UART
* port lock must be held and local interrupts disabled.
*/
-static void __load_zsregs(struct zilog_channel *channel, unsigned char *regs)
+static void __load_zsregs(struct zilog_channel __iomem *channel, unsigned char
*regs)
{
int i;
@@ -241,7 +237,7 @@ static void __load_zsregs(struct zilog_c
* The UART port lock must be held and local interrupts disabled.
*/
static void ip22zilog_maybe_update_regs(struct uart_ip22zilog_port *up,
- struct zilog_channel *channel)
+ struct zilog_channel __iomem *channel)
{
if (!ZS_REGS_HELD(up)) {
if (ZS_TX_ACTIVE(up)) {
@@ -252,14 +248,20 @@ static void ip22zilog_maybe_update_regs(
}
}
-static void ip22zilog_receive_chars(struct uart_ip22zilog_port *up,
- struct zilog_channel *channel,
- struct pt_regs *regs)
-{
- struct tty_struct *tty = up->port.info->tty; /* XXX info==NULL? */
+static struct tty_struct *
+ip22zilog_receive_chars(struct uart_ip22zilog_port *up,
+ struct zilog_channel __iomem *channel,
+ struct pt_regs *regs)
+{
+ struct tty_struct *tty;
+ unsigned char ch, r1, flag;
+
+ tty = NULL;
+ if (up->port.info != NULL && /* Unopened serial console */
+ up->port.info->tty != NULL) /* Keyboard || mouse */
+ tty = up->port.info->tty;
while (1) {
- unsigned char ch, r1, flag;
r1 = read_zsreg(channel, R1);
if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR)) {
@@ -277,23 +279,17 @@ static void ip22zilog_receive_chars(stru
if (ch & BRK_ABRT)
r1 |= BRK_ABRT;
+ if (!(ch & Rx_CH_AV))
+ break;
+
ch = readb(&channel->data);
ZSDELAY();
ch &= up->parity_mask;
- if (ZS_IS_CONS(up) && (r1 & BRK_ABRT)) {
- /* Wait for BREAK to deassert to avoid potentially
- * confusing the PROM.
- */
- while (1) {
- ch = readb(&channel->control);
- ZSDELAY();
- if (!(ch & BRK_ABRT))
- break;
- }
- ip22_do_break();
- return;
+ if (tty == NULL) {
+ uart_handle_sysrq_char(&up->port, ch, regs);
+ continue;
}
/* A real serial line, record the character and status. */
@@ -304,7 +300,7 @@ static void ip22zilog_receive_chars(stru
r1 &= ~(PAR_ERR | CRC_ERR);
up->port.icount.brk++;
if (uart_handle_break(&up->port))
- goto next_char;
+ continue;
}
else if (r1 & PAR_ERR)
up->port.icount.parity++;
@@ -321,7 +317,7 @@ static void ip22zilog_receive_chars(stru
flag = TTY_FRAME;
}
if (uart_handle_sysrq_char(&up->port, ch, regs))
- goto next_char;
+ continue;
if (up->port.ignore_status_mask == 0xff ||
(r1 & up->port.ignore_status_mask) == 0)
@@ -329,18 +325,13 @@ static void ip22zilog_receive_chars(stru
if (r1 & Rx_OVR)
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
- next_char:
- ch = readb(&channel->control);
- ZSDELAY();
- if (!(ch & Rx_CH_AV))
- break;
}
- tty_flip_buffer_push(tty);
+ return tty;
}
static void ip22zilog_status_handle(struct uart_ip22zilog_port *up,
- struct zilog_channel *channel,
+ struct zilog_channel __iomem *channel,
struct pt_regs *regs)
{
unsigned char status;
@@ -352,6 +343,22 @@ static void ip22zilog_status_handle(stru
ZSDELAY();
ZS_WSYNC(channel);
+ if (status & BRK_ABRT) {
+ if (ZS_IS_CONS(up)) {
+ /* Wait for BREAK to deassert to avoid potentially
+ * confusing the PROM.
+ */
+ while (1) {
+ status = readb(&channel->control);
+ ZSDELAY();
+ if (!(status & BRK_ABRT))
+ break;
+ }
+ ip22_do_break();
+ return;
+ }
+ }
+
if (ZS_WANTS_MODEM_STATUS(up)) {
if (status & SYNC)
up->port.icount.dsr++;
@@ -360,10 +367,10 @@ static void ip22zilog_status_handle(stru
* But it does not tell us which bit has changed, we have to
keep
* track of this ourselves.
*/
- if ((status & DCD) ^ up->prev_status)
+ if ((status ^ up->prev_status) & DCD)
uart_handle_dcd_change(&up->port,
(status & DCD));
- if ((status & CTS) ^ up->prev_status)
+ if ((status ^ up->prev_status) & CTS)
uart_handle_cts_change(&up->port,
(status & CTS));
@@ -374,7 +381,7 @@ static void ip22zilog_status_handle(stru
}
static void ip22zilog_transmit_chars(struct uart_ip22zilog_port *up,
- struct zilog_channel *channel)
+ struct zilog_channel __iomem *channel)
{
struct circ_buf *xmit;
@@ -449,21 +456,23 @@ static irqreturn_t ip22zilog_interrupt(i
struct uart_ip22zilog_port *up = dev_id;
while (up) {
- struct zilog_channel *channel
+ struct zilog_channel __iomem *channel
= ZILOG_CHANNEL_FROM_PORT(&up->port);
+ struct tty_struct *tty;
unsigned char r3;
spin_lock(&up->port.lock);
r3 = read_zsreg(channel, R3);
/* Channel A */
+ tty = NULL;
if (r3 & (CHAEXT | CHATxIP | CHARxIP)) {
writeb(RES_H_IUS, &channel->control);
ZSDELAY();
ZS_WSYNC(channel);
if (r3 & CHARxIP)
- ip22zilog_receive_chars(up, channel, regs);
+ tty = ip22zilog_receive_chars(up, channel,
regs);
if (r3 & CHAEXT)
ip22zilog_status_handle(up, channel, regs);
if (r3 & CHATxIP)
@@ -471,18 +480,22 @@ static irqreturn_t ip22zilog_interrupt(i
}
spin_unlock(&up->port.lock);
+ if (tty)
+ tty_flip_buffer_push(tty);
+
/* Channel B */
up = up->next;
channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
spin_lock(&up->port.lock);
+ tty = NULL;
if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) {
writeb(RES_H_IUS, &channel->control);
ZSDELAY();
ZS_WSYNC(channel);
if (r3 & CHBRxIP)
- ip22zilog_receive_chars(up, channel, regs);
+ tty = ip22zilog_receive_chars(up, channel,
regs);
if (r3 & CHBEXT)
ip22zilog_status_handle(up, channel, regs);
if (r3 & CHBTxIP)
@@ -490,6 +503,9 @@ static irqreturn_t ip22zilog_interrupt(i
}
spin_unlock(&up->port.lock);
+ if (tty)
+ tty_flip_buffer_push(tty);
+
up = up->next;
}
@@ -501,7 +517,7 @@ static irqreturn_t ip22zilog_interrupt(i
*/
static __inline__ unsigned char ip22zilog_read_channel_status(struct uart_port
*port)
{
- struct zilog_channel *channel;
+ struct zilog_channel __iomem *channel;
unsigned char status;
channel = ZILOG_CHANNEL_FROM_PORT(port);
@@ -555,7 +571,7 @@ static unsigned int ip22zilog_get_mctrl(
static void ip22zilog_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port;
- struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port);
+ struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(port);
unsigned char set_bits, clear_bits;
set_bits = clear_bits = 0;
@@ -587,7 +603,7 @@ static void ip22zilog_stop_tx(struct uar
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);
+ struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(port);
unsigned char status;
up->flags |= IP22ZILOG_FLAG_TX_ACTIVE;
@@ -629,7 +645,7 @@ static void ip22zilog_start_tx(struct ua
static void ip22zilog_stop_rx(struct uart_port *port)
{
struct uart_ip22zilog_port *up = UART_ZILOG(port);
- struct zilog_channel *channel;
+ struct zilog_channel __iomem *channel;
if (ZS_IS_CONS(up))
return;
@@ -645,7 +661,7 @@ static void ip22zilog_stop_rx(struct uar
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);
+ struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(port);
unsigned char new_reg;
new_reg = up->curregs[R15] | (DCDIE | SYNCIE | CTSIE);
@@ -661,7 +677,7 @@ static void ip22zilog_enable_ms(struct u
static void ip22zilog_break_ctl(struct uart_port *port, int break_state)
{
struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port;
- struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port);
+ struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(port);
unsigned char set_bits, clear_bits, new_reg;
unsigned long flags;
@@ -687,7 +703,7 @@ static void ip22zilog_break_ctl(struct u
static void __ip22zilog_startup(struct uart_ip22zilog_port *up)
{
- struct zilog_channel *channel;
+ struct zilog_channel __iomem *channel;
channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
up->prev_status = readb(&channel->control);
@@ -742,7 +758,7 @@ static int ip22zilog_startup(struct uart
static void ip22zilog_shutdown(struct uart_port *port)
{
struct uart_ip22zilog_port *up = UART_ZILOG(port);
- struct zilog_channel *channel;
+ struct zilog_channel __iomem *channel;
unsigned long flags;
if (ZS_IS_CONS(up))
@@ -918,7 +934,7 @@ static struct uart_ops ip22zilog_pops =
};
static struct uart_ip22zilog_port *ip22zilog_port_table;
-static struct zilog_layout **ip22zilog_chip_regs;
+static struct zilog_layout __iomem **ip22zilog_chip_regs;
static struct uart_ip22zilog_port *ip22zilog_irq_chain;
static int zilog_irq = -1;
@@ -936,10 +952,10 @@ static void * __init alloc_one_table(uns
static void __init ip22zilog_alloc_tables(void)
{
- ip22zilog_port_table = (struct uart_ip22zilog_port *)
+ ip22zilog_port_table =
alloc_one_table(NUM_CHANNELS * sizeof(struct
uart_ip22zilog_port));
- ip22zilog_chip_regs = (struct zilog_layout **)
- alloc_one_table(NUM_IP22ZILOG * sizeof(struct zilog_layout *));
+ ip22zilog_chip_regs =
+ alloc_one_table(NUM_IP22ZILOG * sizeof(struct zilog_layout
__iomem *));
if (ip22zilog_port_table == NULL || ip22zilog_chip_regs == NULL) {
panic("IP22-Zilog: Cannot allocate IP22-Zilog tables.");
@@ -947,7 +963,7 @@ static void __init ip22zilog_alloc_table
}
/* Get the address of the registers for IP22-Zilog instance CHIP. */
-static struct zilog_layout * __init get_zs(int chip)
+static struct zilog_layout __iomem * __init get_zs(int chip)
{
unsigned long base;
@@ -961,13 +977,13 @@ static struct zilog_layout * __init get_
zilog_irq = SGI_SERIAL_IRQ;
request_mem_region(base, 8, "IP22-Zilog");
- return (struct zilog_layout *) base;
+ return (struct zilog_layout __iomem *) base;
}
#define ZS_PUT_CHAR_MAX_DELAY 2000 /* 10 ms */
#ifdef CONFIG_SERIAL_IP22_ZILOG_CONSOLE
-static void ip22zilog_put_char(struct uart_port *port, int ch)
+static void ip22zilog_putchar(struct uart_port *port, int ch)
{
struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port);
int loops = ZS_PUT_CHAR_MAX_DELAY;
@@ -996,7 +1012,7 @@ ip22zilog_console_write(struct console *
unsigned long flags;
spin_lock_irqsave(&up->port.lock, flags);
- uart_console_write(&up->port, s, count, ip22zilog_put_char);
+ uart_console_write(&up->port, s, count, ip22zilog_putchar);
udelay(2);
spin_unlock_irqrestore(&up->port.lock, flags);
}
@@ -1098,7 +1114,7 @@ static struct uart_driver ip22zilog_reg
static void __init ip22zilog_prepare(void)
{
struct uart_ip22zilog_port *up;
- struct zilog_layout *rp;
+ struct zilog_layout __iomem *rp;
int channel, chip;
/*
@@ -1117,8 +1133,8 @@ static void __init ip22zilog_prepare(voi
if (!ip22zilog_chip_regs[chip]) {
ip22zilog_chip_regs[chip] = rp = get_zs(chip);
- up[(chip * 2) + 0].port.membase = (char *)
&rp->channelB;
- up[(chip * 2) + 1].port.membase = (char *)
&rp->channelA;
+ up[(chip * 2) + 0].port.membase = (void __iomem *)
&rp->channelB;
+ up[(chip * 2) + 1].port.membase = (void __iomem *)
&rp->channelA;
/* In theory mapbase is the physical address ... */
up[(chip * 2) + 0].port.mapbase =
@@ -1157,7 +1173,7 @@ static void __init ip22zilog_init_hw(voi
for (i = 0; i < NUM_CHANNELS; i++) {
struct uart_ip22zilog_port *up = &ip22zilog_port_table[i];
- struct zilog_channel *channel =
ZILOG_CHANNEL_FROM_PORT(&up->port);
+ struct zilog_channel __iomem *channel =
ZILOG_CHANNEL_FROM_PORT(&up->port);
unsigned long flags;
int baud, brg;
--
Martin Michlmayr
http://www.cyrius.com/
|