*
* 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, 2005 Maciej W. Rozycki
*
* For the rest of the code the original Copyright applies:
* Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
* is shared with DSRS(DTE) at pin 23.
*/
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/ioport.h>
-#ifdef CONFIG_SERIAL_CONSOLE
+#include <linux/spinlock.h>
+#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>
-#ifdef CONFIG_MACH_DECSTATION
+
#include <asm/dec/interrupts.h>
+#include <asm/dec/ioasic_addrs.h>
#include <asm/dec/machtype.h>
+#include <asm/dec/serial.h>
+#include <asm/dec/system.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)
-#define BUS_PRESENT (DS_BUS_PRESENT || BAGET_BUS_PRESENT)
+DEFINE_SPINLOCK(zs_lock);
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);
-
static struct tty_driver *serial_driver;
/* serial subtype definitions */
/*
* Debugging.
*/
-#undef SERIAL_DEBUG_INTR
#undef SERIAL_DEBUG_OPEN
#undef SERIAL_DEBUG_FLOW
#undef SERIAL_DEBUG_THROTTLE
#define RS_STROBE_TIME 10
#define RS_ISR_PASS_LIMIT 256
-#define _INLINE_ inline
-
static void probe_sccs(void);
static void change_speed(struct dec_serial *info);
static void rs_wait_until_sent(struct tty_struct *tty, int timeout);
-/*
- * tmp_buf is used as a temporary buffer by serial_write. We need to
- * lock it in case the copy_from_user blocks while swapping in a page,
- * and some other program tries to do a serial write at the same time.
- * Since the lock will only come under contention when the system is
- * swapping and available memory is low, it makes sense to share one
- * buffer across all the serial ports, since it significantly saves
- * memory if large numbers of serial ports are open.
- */
-static unsigned char tmp_buf[4096]; /* This is cheating */
-static DECLARE_MUTEX(tmp_buf_sem);
-
static inline int serial_paranoia_check(struct dec_serial *info,
char *name, const char *routine)
{
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]);
{
unsigned long flags;
-
- save_flags(flags); cli();
+ spin_lock_irqsave(&zs_lock, flags);
if (info->zs_channel != info->zs_chan_a) {
if (set) {
info->zs_chan_a->curregs[5] |= (which & (RTS | DTR));
}
write_zsreg(info->zs_chan_a, 5, info->zs_chan_a->curregs[5]);
}
- restore_flags(flags);
+ spin_unlock_irqrestore(&zs_lock, flags);
}
/* Utility routines for the Zilog */
* -----------------------------------------------------------------------
*/
-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.
*/
-static _INLINE_ void rs_sched_event(struct dec_serial *info,
- int event)
+static void rs_sched_event(struct dec_serial *info, int event)
{
info->event |= 1 << event;
- queue_task(&info->tqueue, &tq_zs_serial);
- mark_bh(SERIAL_BH);
+ tasklet_schedule(&info->tlet);
}
-static _INLINE_ void receive_chars(struct dec_serial *info,
- struct pt_regs *regs)
+static void receive_chars(struct dec_serial *info)
{
struct tty_struct *tty = info->tty;
unsigned char ch, stat, flag;
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)) {
- handle_sysrq(ch, regs, NULL);
+ /* Ignore the null char got when BREAK is removed. */
+ if (ch == 0)
+ continue;
+ if (time_before(jiffies, break_pressed + HZ * 5)) {
+ handle_sysrq(ch, 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);
rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
}
-static _INLINE_ void status_handle(struct dec_serial *info)
+static void status_handle(struct dec_serial *info)
{
unsigned char stat;
/* 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 {
/*
* This is the serial driver's generic interrupt routine
*/
-void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+static irqreturn_t rs_interrupt(int irq, void *dev_id)
{
struct dec_serial *info = (struct dec_serial *) dev_id;
+ irqreturn_t status = IRQ_NONE;
unsigned char zs_intreg;
int shift;
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 = IRQ_HANDLED;
+
if (zs_intreg & CHBRxIP) {
- receive_chars(info, regs);
+ receive_chars(info);
}
if (zs_intreg & CHBTxIP) {
transmit_chars(info);
status_handle(info);
}
}
-
+
/* Why do we need this ? */
write_zsreg(info->zs_channel, 0, RES_H_IUS);
+
+ return status;
}
#ifdef ZS_DEBUG_REGS
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();
+ spin_lock_irqsave(&zs_lock, flags);
if (info->zs_channel->curregs[5] & TxENAB) {
info->zs_channel->curregs[5] &= ~TxENAB;
write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]);
}
- restore_flags(flags);
+ spin_unlock_irqrestore(&zs_lock, flags);
#endif
}
{
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();
+
+ spin_lock_irqsave(&zs_lock, flags);
#if 1
if (info->xmit_cnt && info->xmit_buf && !(info->zs_channel->curregs[5] & TxENAB)) {
info->zs_channel->curregs[5] |= TxENAB;
transmit_chars(info);
}
#endif
- restore_flags(flags);
+ spin_unlock_irqrestore(&zs_lock, flags);
}
/*
* interrupt driver proper are done; the interrupt driver schedules
* them using rs_sched_event(), and they get done here.
*/
-static void do_serial_bh(void)
-{
- run_task_queue(&tq_zs_serial);
-}
-static void do_softint(void *private_)
+static void do_softint(unsigned long private_)
{
struct dec_serial *info = (struct dec_serial *) private_;
struct tty_struct *tty;
-
+
tty = info->tty;
if (!tty)
return;
if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
tty_wakeup(tty);
+ wake_up_interruptible(&tty->write_wait);
}
}
-int zs_startup(struct dec_serial * info)
+static int zs_startup(struct dec_serial * info)
{
unsigned long flags;
return -ENOMEM;
}
- save_flags(flags); cli();
+ spin_lock_irqsave(&zs_lock, flags);
#ifdef SERIAL_DEBUG_OPEN
printk("starting up ttyS%d (irq %d)...", info->line, info->irq);
/*
* 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);
+ spin_unlock_irqrestore(&zs_lock, flags);
return 0;
}
printk("Shutting down serial port %d (irq %d)....", info->line,
info->irq);
#endif
-
- save_flags(flags); cli(); /* Disable interrupts */
-
+
+ spin_lock_irqsave(&zs_lock, flags);
+
if (info->xmit_buf) {
free_page((unsigned long) info->xmit_buf);
info->xmit_buf = 0;
set_bit(TTY_IO_ERROR, &info->tty->flags);
info->flags &= ~ZILOG_INITIALIZED;
- restore_flags(flags);
+ spin_unlock_irqrestore(&zs_lock, flags);
}
/*
i += 15;
}
- save_flags(flags); cli();
+ spin_lock_irqsave(&zs_lock, flags);
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;
/* Load up the new values */
load_zsregs(info->zs_channel, info->zs_channel->curregs);
- restore_flags(flags);
+ spin_unlock_irqrestore(&zs_lock, flags);
}
static void rs_flush_chars(struct tty_struct *tty)
return;
/* Enable transmitter */
- save_flags(flags); cli();
+ spin_lock_irqsave(&zs_lock, flags);
transmit_chars(info);
- restore_flags(flags);
+ spin_unlock_irqrestore(&zs_lock, 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;
if (!tty || !info->xmit_buf)
return 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));
+ spin_lock_irqsave(&zs_lock, flags);
+ 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));
- memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
- up(&tmp_buf_sem);
- } else
- memcpy(info->xmit_buf + info->xmit_head, buf, c);
+ memcpy(info->xmit_buf + info->xmit_head, buf, c);
info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
info->xmit_cnt += c;
- restore_flags(flags);
+ spin_unlock_irqrestore(&zs_lock, flags);
buf += c;
count -= c;
total += c;
if (info->xmit_cnt && !tty->stopped && !info->tx_stopped
&& !info->tx_active)
transmit_chars(info);
- restore_flags(flags);
+ spin_unlock_irqrestore(&zs_lock, flags);
return total;
}
{
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();
+ spin_lock_irq(&zs_lock);
info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
- sti();
+ spin_unlock_irq(&zs_lock);
tty_wakeup(tty);
}
/*
* ------------------------------------------------------------
* 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();
+ spin_lock_irqsave(&zs_lock, flags);
info->x_char = STOP_CHAR(tty);
if (!info->tx_active)
transmit_chars(info);
- restore_flags(flags);
+ spin_unlock_irqrestore(&zs_lock, flags);
}
if (C_CRTSCTS(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();
+ spin_lock_irqsave(&zs_lock, flags);
if (info->x_char)
info->x_char = 0;
else {
if (!info->tx_active)
transmit_chars(info);
}
- restore_flags(flags);
+ spin_unlock_irqrestore(&zs_lock, flags);
}
if (C_CRTSCTS(tty)) {
* 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)
{
unsigned char status;
- cli();
+ spin_lock(&zs_lock);
status = read_zsreg(info->zs_channel, 0);
- sti();
+ spin_unlock_irq(&zs_lock);
put_user(status,value);
return 0;
}
if (info->zs_channel == info->zs_chan_a)
result = 0;
else {
- cli();
+ spin_lock(&zs_lock);
control = info->zs_chan_a->curregs[5];
status_a = read_zsreg(info->zs_chan_a, 0);
status_b = read_zsreg(info->zs_channel, 0);
- sti();
+ spin_unlock_irq(&zs_lock);
result = ((control & RTS) ? TIOCM_RTS: 0)
| ((control & DTR) ? TIOCM_DTR: 0)
| ((status_b & DCD) ? TIOCM_CAR: 0)
}
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;
- unsigned int arg, bits;
if (info->hook)
return -ENODEV;
if (info->zs_channel == info->zs_chan_a)
return 0;
- cli();
+ spin_lock(&zs_lock);
if (set & TIOCM_RTS)
info->zs_chan_a->curregs[5] |= RTS;
if (set & TIOCM_DTR)
if (clear & TIOCM_DTR)
info->zs_chan_a->curregs[5] &= ~DTR;
write_zsreg(info->zs_chan_a, 5, info->zs_chan_a->curregs[5]);
- sti();
+ spin_unlock_irq(&zs_lock);
return 0;
}
if (!info->port)
return;
- save_flags(flags); cli();
+ spin_lock_irqsave(&zs_lock, flags);
if (break_state == -1)
info->zs_channel->curregs[5] |= SND_BRK;
else
info->zs_channel->curregs[5] &= ~SND_BRK;
write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]);
- restore_flags(flags);
+ spin_unlock_irqrestore(&zs_lock, flags);
}
static int rs_ioctl(struct tty_struct *tty, struct file * file,
unsigned int cmd, unsigned long arg)
{
- int error;
struct dec_serial * info = (struct dec_serial *)tty->driver_data;
if (info->hook)
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:
+ if (!access_ok(VERIFY_WRITE, (void *)arg,
+ sizeof(struct serial_struct)))
+ return -EFAULT;
+ 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 */
+ if (!access_ok(VERIFY_WRITE, (void *)arg,
+ sizeof(unsigned int)))
+ return -EFAULT;
+ return get_lsr_info(info, (unsigned int *)arg);
+
+ case TIOCSERGSTRUCT:
+ if (!access_ok(VERIFY_WRITE, (void *)arg,
+ sizeof(struct dec_serial)))
+ return -EFAULT;
+ copy_from_user((struct dec_serial *)arg, info,
+ sizeof(struct dec_serial));
+ return 0;
+
+ default:
+ return -ENOIOCTLCMD;
+ }
return 0;
}
-static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios)
+static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{
struct dec_serial *info = (struct dec_serial *)tty->driver_data;
int was_stopped;
/*
* ------------------------------------------------------------
* 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();
-
+
+ spin_lock_irqsave(&zs_lock, flags);
+
if (tty_hung_up_p(filp)) {
- restore_flags(flags);
+ spin_unlock_irqrestore(&zs_lock, flags);
return;
}
-
+
#ifdef SERIAL_DEBUG_OPEN
printk("rs_close ttyS%d, count = %d\n", info->line, info->count);
#endif
info->count = 0;
}
if (info->count) {
- restore_flags(flags);
+ spin_unlock_irqrestore(&zs_lock, flags);
return;
}
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;
info->tty = 0;
if (info->blocked_open) {
if (info->close_delay) {
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(info->close_delay);
+ msleep_interruptible(jiffies_to_msecs(info->close_delay));
}
wake_up_interruptible(&info->open_wait);
}
info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CLOSING);
wake_up_interruptible(&info->close_wait);
- restore_flags(flags);
+ spin_unlock_irqrestore(&zs_lock, flags);
}
/*
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);
+ msleep_interruptible(jiffies_to_msecs(char_time));
if (signal_pending(current))
break;
if (timeout && time_after(jiffies, orig_jiffies + timeout))
/*
* rs_hangup() --- called by tty_hangup() when a hangup is signaled.
*/
-void rs_hangup(struct tty_struct *tty)
+static void rs_hangup(struct tty_struct *tty)
{
struct dec_serial * info = (struct dec_serial *)tty->driver_data;
#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.
printk("block_til_ready before block: ttyS%d, count = %d\n",
info->line, info->count);
#endif
- cli();
- if (!tty_hung_up_p(filp))
+ spin_lock(&zs_lock);
+ if (!tty_hung_up_p(filp))
info->count--;
- sti();
+ spin_unlock_irq(&zs_lock);
info->blocked_open++;
while (1) {
- cli();
+ spin_lock(&zs_lock);
if (tty->termios->c_cflag & CBAUD)
zs_rtsdtr(info, RTS | DTR, 1);
- sti();
+ spin_unlock_irq(&zs_lock);
set_current_state(TASK_INTERRUPTIBLE);
if (tty_hung_up_p(filp) ||
!(info->flags & ZILOG_INITIALIZED)) {
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
* the IRQ chain. It also performs the serial-specific
* initialization for the tty structure.
*/
-int rs_open(struct tty_struct *tty, struct file * filp)
+static int rs_open(struct tty_struct *tty, struct file * filp)
{
struct dec_serial *info;
int retval, line;
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
- * system_base for this case :-(. HK
- */
+
switch(mips_machtype) {
#ifdef CONFIG_MACH_DECSTATION
case MACH_DS5000_2X0:
- system_base = 0xbf800000;
+ case MACH_DS5900:
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;
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;
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_parms->channel_b_offset);
- zs_channels[n_channels].data =
+ zs_channels[n_channels].control =
+ (volatile void *)CKSEG1ADDR(dec_kn_slot_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].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.
+ * Thus request_region would fail.
*/
if (!request_region((unsigned long)
zs_channels[n_channels].control,
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);
+ spin_lock_irqsave(&zs_lock, 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);
+ }
+ spin_unlock_irqrestore(&zs_lock, flags);
}
-static struct tty_operations serial_ops = {
+static const struct tty_operations serial_ops = {
.open = rs_open,
.close = rs_close,
.write = rs_write,
int __init zs_init(void)
{
int channel, i;
- unsigned long flags;
struct dec_serial *info;
if(!BUS_PRESENT)
return -ENODEV;
- /* Setup base handler, and timer table. */
- init_bh(SERIAL_BH, do_serial_bh);
-
/* 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;
/* Not all of this is exactly right for us. */
serial_driver->owner = THIS_MODULE;
- serial_driver->devfs_name = "tts/";
serial_driver->name = "ttyS";
serial_driver->major = TTY_MAJOR;
serial_driver->minor_start = 64;
serial_driver->init_termios = tty_std_termios;
serial_driver->init_termios.c_cflag =
B9600 | CS8 | CREAD | HUPCL | CLOCAL;
- serial_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
+ serial_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
tty_set_operations(serial_driver, &serial_ops);
if (tty_register_driver(serial_driver))
- panic("Couldn't register serial driver\n");
+ panic("Couldn't register serial driver");
- save_flags(flags); cli();
+ for (info = zs_chain, i = 0; info; info = info->zs_next, i++) {
- 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]);
-
- zs_soft[channel].clk_divisor = 16;
- zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]);
-
- 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.routine = do_softint;
- info->tqueue.data = info;
+ tasklet_init(&info->tlet, do_softint, (unsigned long)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, IRQF_SHARED,
+ "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)
+static int 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 (loops && !(read_zsreg(chan, 0) & Tx_BUF_EMP))
+ loops--;
- 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;
-
- 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)
+static int 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);
+
+ spin_lock_irqsave(&zs_lock, 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
+ spin_unlock_irqrestore(&zs_lock, flags);
+
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)
set_debug_traps(); /* init stub */
}
#endif /* ifdef CONFIG_KGDB */
-
-