*
* DECstation changes
* Copyright (C) 1998-2000 Harald Koerfgen
- * Copyright (C) 2000,2001 Maciej W. Rozycki <macro@ds2.pg.gda.pl>
+ * Copyright (C) 2000, 2001, 2002, 2003, 2004 Maciej W. Rozycki
*
* For the rest of the code the original Copyright applies:
* Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/ioport.h>
-#ifdef CONFIG_SERIAL_CONSOLE
+#ifdef CONFIG_SERIAL_DEC_CONSOLE
#include <linux/console.h>
#endif
#include <asm/pgtable.h>
#include <asm/irq.h>
#include <asm/system.h>
-#include <asm/bitops.h>
#include <asm/uaccess.h>
-#include <asm/wbflush.h>
#include <asm/bootinfo.h>
+#include <asm/dec/serial.h>
+
#ifdef CONFIG_MACH_DECSTATION
#include <asm/dec/interrupts.h>
#include <asm/dec/machtype.h>
#include <asm/dec/tc.h>
#include <asm/dec/ioasic_addrs.h>
#endif
-#ifdef CONFIG_BAGET_MIPS
-#include <asm/baget/baget.h>
-unsigned long system_base;
-#endif
#ifdef CONFIG_KGDB
#include <asm/kgdb.h>
#endif
#define NUM_SERIAL 2 /* Max number of ZS chips supported */
#define NUM_CHANNELS (NUM_SERIAL * 2) /* 2 channels per chip */
#define CHANNEL_A_NR (zs_parms->channel_a_offset > zs_parms->channel_b_offset)
- /* Number of channel A in the chip */
+ /* Number of channel A in the chip */
#define ZS_CHAN_IO_SIZE 8
#define ZS_CLOCK 7372800 /* Z8530 RTxC input clock rate */
unsigned long scc1;
int channel_a_offset;
int channel_b_offset;
- int irq;
+ int irq0;
+ int irq1;
int clock;
};
#ifdef CONFIG_MACH_DECSTATION
static struct zs_parms ds_parms = {
- scc0 : SCC0,
- scc1 : SCC1,
+ scc0 : IOASIC_SCC0,
+ scc1 : IOASIC_SCC1,
channel_a_offset : 1,
channel_b_offset : 9,
- irq : SERIAL,
+ irq0 : -1,
+ irq1 : -1,
clock : ZS_CLOCK
};
#endif
-#ifdef CONFIG_BAGET_MIPS
-static struct zs_parms baget_parms = {
- scc0 : UNI_SCC0,
- scc1 : UNI_SCC1,
- channel_a_offset : 9,
- channel_b_offset : 1,
- irq : BAGET_SCC_IRQ,
- clock : 14745000
-};
-#endif
#ifdef CONFIG_MACH_DECSTATION
#define DS_BUS_PRESENT (IOASIC)
#define DS_BUS_PRESENT 0
#endif
-#ifdef CONFIG_BAGET_MIPS
-#define BAGET_BUS_PRESENT (mips_machtype == MACH_BAGET202)
-#else
-#define BAGET_BUS_PRESENT 0
-#endif
-
-#define BUS_PRESENT (DS_BUS_PRESENT || BAGET_BUS_PRESENT)
+#define BUS_PRESENT (DS_BUS_PRESENT)
struct dec_zschannel zs_channels[NUM_CHANNELS];
struct dec_serial zs_soft[NUM_CHANNELS];
struct tty_struct zs_ttys[NUM_CHANNELS];
-#ifdef CONFIG_SERIAL_CONSOLE
+#ifdef CONFIG_SERIAL_DEC_CONSOLE
static struct console sercons;
#endif
-#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) \
- && !defined(MODULE)
+#if defined(CONFIG_SERIAL_DEC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && \
+ !defined(MODULE)
static unsigned long break_pressed; /* break, really ... */
#endif
static unsigned char zs_init_regs[16] __initdata = {
- 0, /* write 0 */
- 0, /* write 1 */
- 0xf0, /* write 2 */
- (Rx8), /* write 3 */
- (X16CLK | SB1), /* write 4 */
- (Tx8), /* write 5 */
- 0, 0, 0, /* write 6, 7, 8 */
- (VIS), /* write 9 */
- (NRZ), /* write 10 */
- (TCBR | RCBR), /* write 11 */
- 0, 0, /* BRG time constant, write 12 + 13 */
- (BRSRC | BRENABL), /* write 14 */
- 0 /* write 15 */
+ 0, /* write 0 */
+ 0, /* write 1 */
+ 0, /* write 2 */
+ 0, /* write 3 */
+ (X16CLK), /* write 4 */
+ 0, /* write 5 */
+ 0, 0, 0, /* write 6, 7, 8 */
+ (MIE | DLC | NV), /* write 9 */
+ (NRZ), /* write 10 */
+ (TCBR | RCBR), /* write 11 */
+ 0, 0, /* BRG time constant, write 12 + 13 */
+ (BRSRC | BRENABL), /* write 14 */
+ 0 /* write 15 */
};
DECLARE_TASK_QUEUE(tq_zs_serial);
/*
* Debugging.
*/
-#undef SERIAL_DEBUG_INTR
#undef SERIAL_DEBUG_OPEN
#undef SERIAL_DEBUG_FLOW
#undef SERIAL_DEBUG_THROTTLE
0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
9600, 19200, 38400, 57600, 115200, 0 };
-/*
+/*
* Reading and writing Z8530 registers.
*/
static inline unsigned char read_zsreg(struct dec_zschannel *channel,
if (reg != 0) {
*channel->control = reg & 0xf;
- wbflush(); RECOVERY_DELAY;
+ fast_iob(); RECOVERY_DELAY;
}
retval = *channel->control;
RECOVERY_DELAY;
{
if (reg != 0) {
*channel->control = reg & 0xf;
- wbflush(); RECOVERY_DELAY;
+ fast_iob(); RECOVERY_DELAY;
}
*channel->control = value;
- wbflush(); RECOVERY_DELAY;
+ fast_iob(); RECOVERY_DELAY;
return;
}
unsigned char value)
{
*channel->data = value;
- wbflush(); RECOVERY_DELAY;
+ fast_iob(); RECOVERY_DELAY;
return;
}
/* ZS_CLEARERR(channel);
ZS_CLEARFIFO(channel); */
/* Load 'em up */
- write_zsreg(channel, R4, regs[R4]);
write_zsreg(channel, R3, regs[R3] & ~RxENABLE);
write_zsreg(channel, R5, regs[R5] & ~TxENAB);
+ write_zsreg(channel, R4, regs[R4]);
write_zsreg(channel, R9, regs[R9]);
write_zsreg(channel, R1, regs[R1]);
write_zsreg(channel, R2, regs[R2]);
* -----------------------------------------------------------------------
*/
-static int tty_break; /* Set whenever BREAK condition is detected. */
-
/*
* This routine is used by the interrupt handler to schedule
* processing in the software interrupt portion of the driver.
stat = read_zsreg(info->zs_channel, R1);
ch = read_zsdata(info->zs_channel);
- if (!tty && !info->hook && !info->hook->rx_char)
+ if (!tty && (!info->hook || !info->hook->rx_char))
continue;
- if (tty_break) {
- tty_break = 0;
-#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && !defined(MODULE)
- if (info->line == sercons.index) {
- if (!break_pressed) {
- break_pressed = jiffies;
- goto ignore_char;
- }
- break_pressed = 0;
- }
-#endif
+ flag = TTY_NORMAL;
+ if (info->tty_break) {
+ info->tty_break = 0;
flag = TTY_BREAK;
if (info->flags & ZILOG_SAK)
do_SAK(tty);
+ /* Ignore the null char got when BREAK is removed. */
+ if (ch == 0)
+ continue;
} else {
if (stat & Rx_OVR) {
flag = TTY_OVERRUN;
flag = TTY_FRAME;
} else if (stat & PAR_ERR) {
flag = TTY_PARITY;
- } else
- flag = 0;
- if (flag)
+ }
+ if (flag != TTY_NORMAL)
/* reset the error indication */
write_zsreg(info->zs_channel, R0, ERR_RES);
}
-#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && !defined(MODULE)
+#if defined(CONFIG_SERIAL_DEC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && \
+ !defined(MODULE)
if (break_pressed && info->line == sercons.index) {
- if (ch != 0 &&
- time_before(jiffies, break_pressed + HZ*5)) {
+ /* Ignore the null char got when BREAK is removed. */
+ if (ch == 0)
+ continue;
+ if (time_before(jiffies, break_pressed + HZ * 5)) {
handle_sysrq(ch, regs, NULL);
break_pressed = 0;
- goto ignore_char;
+ continue;
}
break_pressed = 0;
}
(*info->hook->rx_char)(ch, flag);
return;
}
-
- if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
- static int flip_buf_ovf;
- ++flip_buf_ovf;
- continue;
- }
- tty->flip.count++;
- {
- static int flip_max_cnt;
- if (flip_max_cnt < tty->flip.count)
- flip_max_cnt = tty->flip.count;
- }
- *tty->flip.flag_buf_ptr++ = flag;
- *tty->flip.char_buf_ptr++ = ch;
- ignore_char:
+ tty_insert_flip_char(tty, ch, flag);
}
if (tty)
tty_flip_buffer_push(tty);
/* Get status from Read Register 0 */
stat = read_zsreg(info->zs_channel, R0);
- if (stat & BRK_ABRT) {
-#ifdef SERIAL_DEBUG_INTR
- printk("handling break....");
+ if ((stat & BRK_ABRT) && !(info->read_reg_zero & BRK_ABRT)) {
+#if defined(CONFIG_SERIAL_DEC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && \
+ !defined(MODULE)
+ if (info->line == sercons.index) {
+ if (!break_pressed)
+ break_pressed = jiffies;
+ } else
#endif
- tty_break = 1;
+ info->tty_break = 1;
}
if (info->zs_channel != info->zs_chan_a) {
- /* FIXEM: Check for DCD transitions */
- if (((stat ^ info->read_reg_zero) & DCD) != 0
- && info->tty && !C_CLOCAL(info->tty)) {
+ /* Check for DCD transitions */
+ if (info->tty && !C_CLOCAL(info->tty) &&
+ ((stat ^ info->read_reg_zero) & DCD) != 0 ) {
if (stat & DCD) {
wake_up_interruptible(&info->open_wait);
} else {
shift = 0; /* Channel B */
for (;;) {
- zs_intreg = read_zsreg(info->zs_chan_a, R3) >> shift;
+ zs_intreg = read_zsreg(info->zs_chan_a, R3) >> shift;
if ((zs_intreg & CHAN_IRQMASK) == 0)
break;
status_handle(info);
}
}
-
+
/* Why do we need this ? */
write_zsreg(info->zs_channel, 0, RES_H_IUS);
}
void zs_dump (void) {
int i, j;
for (i = 0; i < zs_channels_found; i++) {
- struct dec_zschannel *ch = &zs_channels[i];
+ struct dec_zschannel *ch = &zs_channels[i];
if ((long)ch->control == UNI_IO_BASE+UNI_SCC1A_CTRL) {
for (j = 0; j < 15; j++) {
- printk("W%d = 0x%x\t",
+ printk("W%d = 0x%x\t",
j, (int)ch->curregs[j]);
}
for (j = 0; j < 15; j++) {
- printk("R%d = 0x%x\t",
+ printk("R%d = 0x%x\t",
j, (int)read_zsreg(ch,j));
}
printk("\n\n");
if (serial_paranoia_check(info, tty->name, "rs_stop"))
return;
-
+
#if 1
save_flags(flags); cli();
if (info->zs_channel->curregs[5] & TxENAB) {
{
struct dec_serial *info = (struct dec_serial *)tty->driver_data;
unsigned long flags;
-
+
if (serial_paranoia_check(info, tty->name, "rs_start"))
return;
-
+
save_flags(flags); cli();
#if 1
if (info->xmit_cnt && info->xmit_buf && !(info->zs_channel->curregs[5] & TxENAB)) {
{
struct dec_serial *info = (struct dec_serial *) private_;
struct tty_struct *tty;
-
+
tty = info->tty;
if (!tty)
return;
/*
* Clear the interrupt registers.
*/
- write_zsreg(info->zs_channel, 0, ERR_RES);
- write_zsreg(info->zs_channel, 0, RES_H_IUS);
+ write_zsreg(info->zs_channel, R0, ERR_RES);
+ write_zsreg(info->zs_channel, R0, RES_H_IUS);
+
+ /*
+ * Set the speed of the serial port
+ */
+ change_speed(info);
/*
* Turn on RTS and DTR.
/*
* Finally, enable sequencing and interrupts
*/
- info->zs_channel->curregs[1] = (info->zs_channel->curregs[1] & ~0x18) | (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB);
- info->zs_channel->curregs[3] |= (RxENABLE | Rx8);
- info->zs_channel->curregs[5] |= (TxENAB | Tx8);
- info->zs_channel->curregs[15] |= (DCDIE | CTSIE | TxUIE | BRKIE);
- info->zs_channel->curregs[9] |= (VIS | MIE);
- write_zsreg(info->zs_channel, 1, info->zs_channel->curregs[1]);
- write_zsreg(info->zs_channel, 3, info->zs_channel->curregs[3]);
- write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]);
- write_zsreg(info->zs_channel, 15, info->zs_channel->curregs[15]);
- write_zsreg(info->zs_channel, 9, info->zs_channel->curregs[9]);
+ info->zs_channel->curregs[R1] &= ~RxINT_MASK;
+ info->zs_channel->curregs[R1] |= (RxINT_ALL | TxINT_ENAB |
+ EXT_INT_ENAB);
+ info->zs_channel->curregs[R3] |= RxENABLE;
+ info->zs_channel->curregs[R5] |= TxENAB;
+ info->zs_channel->curregs[R15] |= (DCDIE | CTSIE | TxUIE | BRKIE);
+ write_zsreg(info->zs_channel, R1, info->zs_channel->curregs[R1]);
+ write_zsreg(info->zs_channel, R3, info->zs_channel->curregs[R3]);
+ write_zsreg(info->zs_channel, R5, info->zs_channel->curregs[R5]);
+ write_zsreg(info->zs_channel, R15, info->zs_channel->curregs[R15]);
/*
* And clear the interrupt registers again for luck.
*/
- write_zsreg(info->zs_channel, 0, ERR_RES);
- write_zsreg(info->zs_channel, 0, RES_H_IUS);
+ write_zsreg(info->zs_channel, R0, ERR_RES);
+ write_zsreg(info->zs_channel, R0, RES_H_IUS);
+
+ /* Save the current value of RR0 */
+ info->read_reg_zero = read_zsreg(info->zs_channel, R0);
if (info->tty)
clear_bit(TTY_IO_ERROR, &info->tty->flags);
info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
- /*
- * Set the speed of the serial port
- */
- change_speed(info);
-
- /* Save the current value of RR0 */
- info->read_reg_zero = read_zsreg(info->zs_channel, 0);
-
info->flags |= ZILOG_INITIALIZED;
restore_flags(flags);
return 0;
printk("Shutting down serial port %d (irq %d)....", info->line,
info->irq);
#endif
-
+
save_flags(flags); cli(); /* Disable interrupts */
-
+
if (info->xmit_buf) {
free_page((unsigned long) info->xmit_buf);
info->xmit_buf = 0;
save_flags(flags); cli();
info->zs_baud = baud_table[i];
- info->clk_divisor = 16;
if (info->zs_baud) {
- info->zs_channel->curregs[4] = X16CLK;
brg = BPS_TO_BRG(info->zs_baud, zs_parms->clock/info->clk_divisor);
info->zs_channel->curregs[12] = (brg & 255);
info->zs_channel->curregs[13] = ((brg >> 8) & 255);
- zs_rtsdtr(info, DTR, 1);
+ zs_rtsdtr(info, DTR, 1);
} else {
zs_rtsdtr(info, RTS | DTR, 0);
return;
restore_flags(flags);
}
-static int rs_write(struct tty_struct * tty, int from_user,
+static int rs_write(struct tty_struct * tty,
const unsigned char *buf, int count)
{
int c, total = 0;
save_flags(flags);
while (1) {
- cli();
- c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
- SERIAL_XMIT_SIZE - info->xmit_head));
+ cli();
+ c = min(count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+ SERIAL_XMIT_SIZE - info->xmit_head));
if (c <= 0)
break;
if (from_user) {
down(&tmp_buf_sem);
copy_from_user(tmp_buf, buf, c);
- c = min_t(int, c, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
- SERIAL_XMIT_SIZE - info->xmit_head));
+ c = min(c, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+ SERIAL_XMIT_SIZE - info->xmit_head));
memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
up(&tmp_buf_sem);
} else
{
struct dec_serial *info = (struct dec_serial *)tty->driver_data;
int ret;
-
+
if (serial_paranoia_check(info, tty->name, "rs_write_room"))
return 0;
ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
static int rs_chars_in_buffer(struct tty_struct *tty)
{
struct dec_serial *info = (struct dec_serial *)tty->driver_data;
-
+
if (serial_paranoia_check(info, tty->name, "rs_chars_in_buffer"))
return 0;
return info->xmit_cnt;
static void rs_flush_buffer(struct tty_struct *tty)
{
struct dec_serial *info = (struct dec_serial *)tty->driver_data;
-
+
if (serial_paranoia_check(info, tty->name, "rs_flush_buffer"))
return;
cli();
/*
* ------------------------------------------------------------
* rs_throttle()
- *
+ *
* This routine is called by the upper-layer tty layer to signal that
* incoming characters should be throttled.
* ------------------------------------------------------------
#ifdef SERIAL_DEBUG_THROTTLE
char buf[64];
-
+
printk("throttle %s: %d....\n", _tty_name(tty, buf),
tty->ldisc.chars_in_buffer(tty));
#endif
if (serial_paranoia_check(info, tty->name, "rs_throttle"))
return;
-
+
if (I_IXOFF(tty)) {
save_flags(flags); cli();
info->x_char = STOP_CHAR(tty);
#ifdef SERIAL_DEBUG_THROTTLE
char buf[64];
-
+
printk("unthrottle %s: %d....\n", _tty_name(tty, buf),
tty->ldisc.chars_in_buffer(tty));
#endif
if (serial_paranoia_check(info, tty->name, "rs_unthrottle"))
return;
-
+
if (I_IXOFF(tty)) {
save_flags(flags); cli();
if (info->x_char)
* release the bus after transmitting. This must be done when
* the transmit shift register is empty, not be done when the
* transmit holding register is empty. This functionality
- * allows an RS485 driver to be written in user space.
+ * allows an RS485 driver to be written in user space.
*/
static int get_lsr_info(struct dec_serial * info, unsigned int *value)
{
}
static int rs_tiocmset(struct tty_struct *tty, struct file *file,
- unsigned int set, unsigned int clear)
+ unsigned int set, unsigned int clear)
{
struct dec_serial * info = (struct dec_serial *)tty->driver_data;
int error;
if (info->zs_channel == info->zs_chan_a)
return 0;
+ get_user(arg, value);
cli();
if (set & TIOCM_RTS)
info->zs_chan_a->curregs[5] |= RTS;
if (tty->flags & (1 << TTY_IO_ERROR))
return -EIO;
}
-
+
switch (cmd) {
- case TIOCGSERIAL:
- error = verify_area(VERIFY_WRITE, (void *) arg,
- sizeof(struct serial_struct));
- if (error)
- return error;
- return get_serial_info(info,
- (struct serial_struct *) arg);
- case TIOCSSERIAL:
- return set_serial_info(info,
- (struct serial_struct *) arg);
- case TIOCSERGETLSR: /* Get line status register */
- error = verify_area(VERIFY_WRITE, (void *) arg,
- sizeof(unsigned int));
- if (error)
- return error;
- else
- return get_lsr_info(info, (unsigned int *) arg);
-
- case TIOCSERGSTRUCT:
- error = verify_area(VERIFY_WRITE, (void *) arg,
- sizeof(struct dec_serial));
- if (error)
- return error;
- copy_from_user((struct dec_serial *) arg,
- info, sizeof(struct dec_serial));
- return 0;
-
- default:
- return -ENOIOCTLCMD;
- }
+ case TIOCGSERIAL:
+ error = verify_area(VERIFY_WRITE, (void *)arg,
+ sizeof(struct serial_struct));
+ if (error)
+ return error;
+ return get_serial_info(info, (struct serial_struct *)arg);
+
+ case TIOCSSERIAL:
+ return set_serial_info(info, (struct serial_struct *)arg);
+
+ case TIOCSERGETLSR: /* Get line status register */
+ error = verify_area(VERIFY_WRITE, (void *)arg,
+ sizeof(unsigned int));
+ if (error)
+ return error;
+ else
+ return get_lsr_info(info, (unsigned int *)arg);
+
+ case TIOCSERGSTRUCT:
+ error = verify_area(VERIFY_WRITE, (void *)arg,
+ sizeof(struct dec_serial));
+ if (error)
+ return error;
+ copy_from_user((struct dec_serial *)arg, info,
+ sizeof(struct dec_serial));
+ return 0;
+
+ default:
+ return -ENOIOCTLCMD;
+ }
return 0;
}
/*
* ------------------------------------------------------------
* rs_close()
- *
+ *
* This routine is called when the serial port gets closed.
* Wait for the last remaining data to be sent.
* ------------------------------------------------------------
if (!info || serial_paranoia_check(info, tty->name, "rs_close"))
return;
-
+
save_flags(flags); cli();
-
+
if (tty_hung_up_p(filp)) {
restore_flags(flags);
return;
}
-
+
#ifdef SERIAL_DEBUG_OPEN
printk("rs_close ttyS%d, count = %d\n", info->line, info->count);
#endif
}
info->flags |= ZILOG_CLOSING;
/*
- * Now we wait for the transmit buffer to clear; and we notify
+ * Now we wait for the transmit buffer to clear; and we notify
* the line discipline to only process XON/XOFF characters.
*/
tty->closing = 1;
static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
{
struct dec_serial *info = (struct dec_serial *) tty->driver_data;
- unsigned long orig_jiffies, char_time;
+ unsigned long orig_jiffies;
+ int char_time;
if (serial_paranoia_check(info, tty->name, "rs_wait_until_sent"))
return;
if (char_time == 0)
char_time = 1;
if (timeout)
- char_time = min_t(unsigned long, char_time, timeout);
+ char_time = min(char_time, timeout);
while ((read_zsreg(info->zs_channel, 1) & Tx_BUF_EMP) == 0) {
current->state = TASK_INTERRUPTIBLE;
schedule_timeout(char_time);
#endif
}
- /*
- * If this is a callout device, then just make sure the normal
- * device isn't being used.
- */
-
/*
* If non-blocking mode is set, or the port is not enabled,
* then make the check up front and then exit.
info->line, info->count);
#endif
cli();
- if (!tty_hung_up_p(filp))
+ if (!tty_hung_up_p(filp))
info->count--;
sti();
info->blocked_open++;
if (info->flags & ZILOG_HUP_NOTIFY)
retval = -EAGAIN;
else
- retval = -ERESTARTSYS;
+ retval = -ERESTARTSYS;
#else
retval = -EAGAIN;
#endif
return retval;
info->flags |= ZILOG_NORMAL_ACTIVE;
return 0;
-}
+}
/*
* This routine is called whenever a serial port is opened. It
return retval;
}
-#ifdef CONFIG_SERIAL_CONSOLE
+#ifdef CONFIG_SERIAL_DEC_CONSOLE
if (sercons.cflag && sercons.index == line) {
tty->termios->c_cflag = sercons.cflag;
sercons.cflag = 0;
static void __init show_serial_version(void)
{
- printk("DECstation Z8530 serial driver version 0.05\n");
+ printk("DECstation Z8530 serial driver version 0.09\n");
}
/* Initialize Z8530s zs_channels
{
struct dec_serial **pp;
int i, n, n_chips = 0, n_channels, chip, channel;
+ unsigned long flags;
/*
* did we get here by accident?
printk("Not on JUNKIO machine, skipping probe_sccs\n");
return;
}
-
+
/*
* When serial console is activated, tc_init has not been called yet
* and system_base is undefined. Unfortunately we have to hardcode
switch(mips_machtype) {
#ifdef CONFIG_MACH_DECSTATION
case MACH_DS5000_2X0:
- system_base = 0xbf800000;
+ case MACH_DS5900:
+ system_base = KSEG1ADDR(0x1f800000);
n_chips = 2;
zs_parms = &ds_parms;
+ zs_parms->irq0 = dec_interrupt[DEC_IRQ_SCC0];
+ zs_parms->irq1 = dec_interrupt[DEC_IRQ_SCC1];
break;
case MACH_DS5000_1XX:
- system_base = 0xbc000000;
+ system_base = KSEG1ADDR(0x1c000000);
n_chips = 2;
zs_parms = &ds_parms;
+ zs_parms->irq0 = dec_interrupt[DEC_IRQ_SCC0];
+ zs_parms->irq1 = dec_interrupt[DEC_IRQ_SCC1];
break;
case MACH_DS5000_XX:
- system_base = 0xbc000000;
+ system_base = KSEG1ADDR(0x1c000000);
n_chips = 1;
zs_parms = &ds_parms;
- break;
-#endif
-#ifdef CONFIG_BAGET_MIPS
- case MACH_BAGET202:
- system_base = UNI_IO_BASE;
- n_chips = 2;
- zs_parms = &baget_parms;
- zs_init_regs[2] = 0x8;
+ zs_parms->irq0 = dec_interrupt[DEC_IRQ_SCC0];
break;
#endif
default:
/*
* The sccs reside on the high byte of the 16 bit IOBUS
*/
- zs_channels[n_channels].control =
- (volatile unsigned char *)system_base +
- (0 == chip ? zs_parms->scc0 : zs_parms->scc1) +
- (0 == channel ? zs_parms->channel_a_offset :
+ zs_channels[n_channels].control =
+ (volatile unsigned char *)system_base +
+ (0 == chip ? zs_parms->scc0 : zs_parms->scc1) +
+ (0 == channel ? zs_parms->channel_a_offset :
zs_parms->channel_b_offset);
- zs_channels[n_channels].data =
+ zs_channels[n_channels].data =
zs_channels[n_channels].control + 4;
-#ifndef CONFIG_SERIAL_CONSOLE
+#ifndef CONFIG_SERIAL_DEC_CONSOLE
/*
* We're called early and memory managment isn't up, yet.
* Thus check_region would fail.
panic("SCC I/O region is not free");
#endif
zs_soft[n_channels].zs_channel = &zs_channels[n_channels];
- zs_soft[n_channels].irq = zs_parms->irq;
+ /* HACK alert! */
+ if (!(chip & 1))
+ zs_soft[n_channels].irq = zs_parms->irq0;
+ else
+ zs_soft[n_channels].irq = zs_parms->irq1;
- /*
+ /*
* Identification of channel A. Location of channel A
* inside chip depends on mapping of internal address
* the chip decodes channels by.
- * CHANNEL_A_NR returns either 0 (in case of
+ * CHANNEL_A_NR returns either 0 (in case of
* DECstations) or 1 (in case of Baget).
*/
if (CHANNEL_A_NR == channel)
- zs_soft[n_channels].zs_chan_a =
+ zs_soft[n_channels].zs_chan_a =
&zs_channels[n_channels+1-2*CHANNEL_A_NR];
else
- zs_soft[n_channels].zs_chan_a =
+ zs_soft[n_channels].zs_chan_a =
&zs_channels[n_channels];
*pp = &zs_soft[n_channels];
}
}
-/* save_and_cli(flags);
+ save_and_cli(flags);
for (n = 0; n < zs_channels_found; n++) {
- if (((int)zs_channels[n].control & 0xf) == 1) {
+ if (n % 2 == 0) {
write_zsreg(zs_soft[n].zs_chan_a, R9, FHWRES);
- mdelay(10);
+ udelay(10);
write_zsreg(zs_soft[n].zs_chan_a, R9, 0);
}
- load_zsregs(zs_soft[n].zs_channel, zs_soft[n].zs_channel->curregs);
- }
- restore_flags(flags); */
+ load_zsregs(zs_soft[n].zs_channel,
+ zs_soft[n].zs_channel->curregs);
+ }
+ restore_flags(flags);
}
static struct tty_operations serial_ops = {
int __init zs_init(void)
{
int channel, i;
- unsigned long flags;
struct dec_serial *info;
if(!BUS_PRESENT)
/* Find out how many Z8530 SCCs we have */
if (zs_chain == 0)
probe_sccs();
-
serial_driver = alloc_tty_driver(zs_channels_found);
if (!serial_driver)
return -ENOMEM;
tty_set_operations(serial_driver, &serial_ops);
if (tty_register_driver(serial_driver))
- panic("Couldn't register serial driver\n");
-
- save_flags(flags); cli();
-
- for (channel = 0; channel < zs_channels_found; ++channel) {
- if (zs_soft[channel].hook &&
- zs_soft[channel].hook->init_channel)
- (*zs_soft[channel].hook->init_channel)
- (&zs_soft[channel]);
+ panic("Couldn't register serial driver");
- zs_soft[channel].clk_divisor = 16;
- zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]);
+ for (info = zs_chain, i = 0; info; info = info->zs_next, i++) {
- if (request_irq(zs_parms->irq, rs_interrupt, SA_SHIRQ,
- "SCC", &zs_soft[channel]))
- printk(KERN_ERR "decserial: can't get irq %d\n",
- zs_parms->irq);
- }
+ /* Needed before interrupts are enabled. */
+ info->tty = 0;
+ info->x_char = 0;
- for (info = zs_chain, i = 0; info; info = info->zs_next, i++)
- {
if (info->hook && info->hook->init_info) {
(*info->hook->init_info)(info);
continue;
}
+
info->magic = SERIAL_MAGIC;
info->port = (int) info->zs_channel->control;
info->line = i;
- info->tty = 0;
info->custom_divisor = 16;
info->close_delay = 50;
info->closing_wait = 3000;
- info->x_char = 0;
info->event = 0;
info->count = 0;
info->blocked_open = 0;
info->tqueue.data = info;
init_waitqueue_head(&info->open_wait);
init_waitqueue_head(&info->close_wait);
- printk("ttyS%d at 0x%08x (irq = %d)", info->line,
- info->port, info->irq);
- printk(" is a Z85C30 SCC\n");
+ printk("ttyS%02d at 0x%08x (irq = %d) is a Z85C30 SCC\n",
+ info->line, info->port, info->irq);
tty_register_device(serial_driver, info->line, NULL);
+
}
- restore_flags(flags);
+ for (channel = 0; channel < zs_channels_found; ++channel) {
+ zs_soft[channel].clk_divisor = 16;
+ zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]);
- return 0;
-}
+ if (request_irq(zs_soft[channel].irq, rs_interrupt, SA_SHIRQ,
+ "scc", &zs_soft[channel]))
+ printk(KERN_ERR "decserial: can't get irq %d\n",
+ zs_soft[channel].irq);
-/*
- * register_serial and unregister_serial allows for serial ports to be
- * configured at run-time, to support PCMCIA modems.
- */
-/* PowerMac: Unused at this time, just here to make things link. */
-int register_serial(struct serial_struct *req)
-{
- return -1;
-}
+ if (zs_soft[channel].hook) {
+ zs_startup(&zs_soft[channel]);
+ if (zs_soft[channel].hook->init_channel)
+ (*zs_soft[channel].hook->init_channel)
+ (&zs_soft[channel]);
+ }
+ }
-void unregister_serial(int line)
-{
- return;
+ return 0;
}
/*
* polling I/O routines
*/
static int
-zs_poll_tx_char(struct dec_serial *info, unsigned char ch)
+zs_poll_tx_char(void *handle, unsigned char ch)
{
+ struct dec_serial *info = handle;
struct dec_zschannel *chan = info->zs_channel;
int ret;
if(chan) {
int loops = 10000;
-// int nine = read_zsreg(chan, R9);
-
- RECOVERY_DELAY;
-// write_zsreg(chan, R9, nine & ~MIE);
- wbflush();
- RECOVERY_DELAY;
-
- while (!(*(chan->control) & Tx_BUF_EMP) && --loops)
- RECOVERY_DELAY;
-
- if (loops) {
- ret = 0;
- *(chan->data) = ch;
- wbflush();
- RECOVERY_DELAY;
- } else
- ret = -EAGAIN;
-// write_zsreg(chan, R9, nine);
- wbflush();
- RECOVERY_DELAY;
+ while (loops && !(read_zsreg(chan, 0) & Tx_BUF_EMP))
+ loops--;
- return ret;
- }
+ if (loops) {
+ write_zsdata(chan, ch);
+ ret = 0;
+ } else
+ ret = -EAGAIN;
- return -ENODEV;
+ return ret;
+ } else
+ return -ENODEV;
}
static int
-zs_poll_rx_char(struct dec_serial *info)
+zs_poll_rx_char(void *handle)
{
+ struct dec_serial *info = handle;
struct dec_zschannel *chan = info->zs_channel;
int ret;
if(chan) {
int loops = 10000;
- while((read_zsreg(chan, 0) & Rx_CH_AV) == 0)
- loops--;
+ while (loops && !(read_zsreg(chan, 0) & Rx_CH_AV))
+ loops--;
if (loops)
ret = read_zsdata(chan);
else
ret = -EAGAIN;
- return ret;
- } else
- return -ENODEV;
+ return ret;
+ } else
+ return -ENODEV;
}
-unsigned int register_zs_hook(unsigned int channel, struct zs_hook *hook)
+int register_zs_hook(unsigned int channel, struct dec_serial_hook *hook)
{
struct dec_serial *info = &zs_soft[channel];
return 0;
} else {
- info->hook = hook;
-
- if (zs_chain == 0)
- probe_sccs();
-
- if (!(info->flags & ZILOG_INITIALIZED))
- zs_startup(info);
-
hook->poll_rx_char = zs_poll_rx_char;
hook->poll_tx_char = zs_poll_tx_char;
+ info->hook = hook;
return 1;
}
}
-unsigned int unregister_zs_hook(unsigned int channel)
+int unregister_zs_hook(unsigned int channel)
{
struct dec_serial *info = &zs_soft[channel];
* Serial console driver
* ------------------------------------------------------------
*/
-#ifdef CONFIG_SERIAL_CONSOLE
+#ifdef CONFIG_SERIAL_DEC_CONSOLE
/*
static int __init serial_console_setup(struct console *co, char *options)
{
struct dec_serial *info;
- int baud = 9600;
- int bits = 8;
- int parity = 'n';
- int cflag = CREAD | HUPCL | CLOCAL;
- char *s;
+ int baud = 9600;
+ int bits = 8;
+ int parity = 'n';
+ int cflag = CREAD | HUPCL | CLOCAL;
+ int clk_divisor = 16;
+ int brg;
+ char *s;
unsigned long flags;
if(!BUS_PRESENT)
case 9600:
default:
cflag |= B9600;
+ /*
+ * Set this to a sane value to prevent a divide error.
+ */
+ baud = 9600;
break;
}
switch(bits) {
break;
}
co->cflag = cflag;
-#if 1
+
save_and_cli(flags);
+ /*
+ * Set up the baud rate generator.
+ */
+ brg = BPS_TO_BRG(baud, zs_parms->clock / clk_divisor);
+ info->zs_channel->curregs[R12] = (brg & 255);
+ info->zs_channel->curregs[R13] = ((brg >> 8) & 255);
+
+ /*
+ * Set byte size and parity.
+ */
+ if (bits == 7) {
+ info->zs_channel->curregs[R3] |= Rx7;
+ info->zs_channel->curregs[R5] |= Tx7;
+ } else {
+ info->zs_channel->curregs[R3] |= Rx8;
+ info->zs_channel->curregs[R5] |= Tx8;
+ }
+ if (cflag & PARENB) {
+ info->zs_channel->curregs[R4] |= PAR_ENA;
+ }
+ if (!(cflag & PARODD)) {
+ info->zs_channel->curregs[R4] |= PAR_EVEN;
+ }
+ info->zs_channel->curregs[R4] |= SB1;
+
/*
* Turn on RTS and DTR.
*/
zs_rtsdtr(info, RTS | DTR, 1);
/*
- * Finally, enable sequencing
+ * Finally, enable sequencing.
*/
- info->zs_channel->curregs[3] |= (RxENABLE | Rx8);
- info->zs_channel->curregs[5] |= (TxENAB | Tx8);
- info->zs_channel->curregs[9] |= (VIS);
- write_zsreg(info->zs_channel, 3, info->zs_channel->curregs[3]);
- write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]);
- write_zsreg(info->zs_channel, 9, info->zs_channel->curregs[9]);
+ info->zs_channel->curregs[R3] |= RxENABLE;
+ info->zs_channel->curregs[R5] |= TxENAB;
/*
* Clear the interrupt registers.
*/
- write_zsreg(info->zs_channel, 0, ERR_RES);
- write_zsreg(info->zs_channel, 0, RES_H_IUS);
+ write_zsreg(info->zs_channel, R0, ERR_RES);
+ write_zsreg(info->zs_channel, R0, RES_H_IUS);
/*
- * Set the speed of the serial port
+ * Load up the new values.
*/
- change_speed(info);
+ load_zsregs(info->zs_channel, info->zs_channel->curregs);
/* Save the current value of RR0 */
- info->read_reg_zero = read_zsreg(info->zs_channel, 0);
+ info->read_reg_zero = read_zsreg(info->zs_channel, R0);
- zs_soft[co->index].clk_divisor = 16;
+ zs_soft[co->index].clk_divisor = clk_divisor;
zs_soft[co->index].zs_baud = get_zsbaud(&zs_soft[co->index]);
restore_flags(flags);
-#endif
+
return 0;
}
{
register_console(&sercons);
}
-#endif /* ifdef CONFIG_SERIAL_CONSOLE */
+#endif /* ifdef CONFIG_SERIAL_DEC_CONSOLE */
#ifdef CONFIG_KGDB
struct dec_zschannel *zs_kgdbchan;
int one, nine;
nine = read_zsreg(chan, 9);
if (yes == 1) {
- one = EXT_INT_ENAB|INT_ALL_Rx;
+ one = EXT_INT_ENAB|RxINT_ALL;
nine |= MIE;
printk("turning serial ints on\n");
} else {
write_zsreg(chan, 9, nine);
}
-static int kgdbhook_init_channel(struct dec_serial* info)
+static int kgdbhook_init_channel(void *handle)
{
return 0;
}
-static void kgdbhook_init_info(struct dec_serial* info)
+static void kgdbhook_init_info(void *handle)
{
}
-static void kgdbhook_rx_char(struct dec_serial* info,
- unsigned char ch, unsigned char stat)
+static void kgdbhook_rx_char(void *handle, unsigned char ch, unsigned char fl)
{
+ struct dec_serial *info = handle;
+
+ if (fl != TTY_NORMAL)
+ return;
if (ch == 0x03 || ch == '$')
breakpoint();
- if (stat & (Rx_OVR|FRM_ERR|PAR_ERR))
- write_zsreg(info->zs_channel, 0, ERR_RES);
}
/* This sets up the serial port we're using, and turns on
* for /dev/ttyb which is determined in setup_arch() from the
* boot command line flags.
*/
-struct zs_hook zs_kgdbhook = {
- init_channel : kgdbhook_init_channel,
- init_info : kgdbhook_init_info,
- cflags : B38400|CS8|CLOCAL,
- rx_char : kgdbhook_rx_char,
+struct dec_serial_hook zs_kgdbhook = {
+ .init_channel = kgdbhook_init_channel,
+ .init_info = kgdbhook_init_info,
+ .rx_char = kgdbhook_rx_char,
+ .cflags = B38400 | CS8 | CLOCAL,
}
void __init zs_kgdb_hook(int tty_num)