summaryrefslogtreecommitdiffstats
path: root/drivers/sbus/char
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1999-06-13 16:29:25 +0000
committerRalf Baechle <ralf@linux-mips.org>1999-06-13 16:29:25 +0000
commitdb7d4daea91e105e3859cf461d7e53b9b77454b2 (patch)
tree9bb65b95440af09e8aca63abe56970dd3360cc57 /drivers/sbus/char
parent9c1c01ead627bdda9211c9abd5b758d6c687d8ac (diff)
Merge with Linux 2.2.8.
Diffstat (limited to 'drivers/sbus/char')
-rw-r--r--drivers/sbus/char/bpp.c24
-rw-r--r--drivers/sbus/char/flash.c4
-rw-r--r--drivers/sbus/char/pcikbd.c36
-rw-r--r--drivers/sbus/char/sab82532.c10
-rw-r--r--drivers/sbus/char/su.c46
-rw-r--r--drivers/sbus/char/sunkbd.c9
-rw-r--r--drivers/sbus/char/sunmouse.c32
-rw-r--r--drivers/sbus/char/sunserial.c8
-rw-r--r--drivers/sbus/char/vfc_dev.c2
-rw-r--r--drivers/sbus/char/zs.c178
10 files changed, 220 insertions, 129 deletions
diff --git a/drivers/sbus/char/bpp.c b/drivers/sbus/char/bpp.c
index 0121a03e7..de9321d40 100644
--- a/drivers/sbus/char/bpp.c
+++ b/drivers/sbus/char/bpp.c
@@ -337,7 +337,7 @@ static int wait_for(unsigned short set, unsigned short clr,
* responds real good. The first while loop guesses an expire
* time accounting for possible wraparound of jiffies.
*/
- while (time_after_eq(jiffies, extime) extime = jiffies + 1;
+ while (time_after_eq(jiffies, extime)) extime = jiffies + 1;
while ( (time_before(jiffies, extime))
&& (((pins & set) != set) || ((pins & clr) != 0)) ) {
pins = get_pins(minor);
@@ -470,13 +470,14 @@ static int bpp_open(struct inode *inode, struct file *f)
* mode as this is a reasonable place to clean up from messes made by
* ioctls, or other mayhem.
*/
-static void bpp_release(struct inode *inode, struct file *f)
+static int bpp_release(struct inode *inode, struct file *f)
{
unsigned minor = MINOR(inode->i_rdev);
instances[minor].opened = 0;
if (instances[minor].mode != COMPATIBILITY)
terminate(minor);
+ return 0;
}
static long read_nibble(unsigned minor, char *c, unsigned long cnt)
@@ -624,11 +625,10 @@ static long read_ecp(unsigned minor, char *c, unsigned long cnt)
return cnt - remaining;
}
-static long bpp_read(struct inode *inode, struct file *f,
- char *c, unsigned long cnt)
+static ssize_t bpp_read(struct file *f, char *c, size_t cnt, loff_t * ppos)
{
long rc;
- const unsigned minor = MINOR(inode->i_rdev);
+ const unsigned minor = MINOR(f->f_dentry->d_inode->i_rdev);
if (minor >= BPP_NO) return -ENODEV;
if (!instances[minor].present) return -ENODEV;
@@ -694,10 +694,12 @@ static long write_compat(unsigned minor, const char *c, unsigned long cnt)
unsigned long remaining = cnt;
+
while (remaining > 0) {
unsigned char byte;
- c += 1;
+
get_user_ret(byte, c, -EFAULT);
+ c += 1;
rc = wait_for(BPP_GP_nAck, BPP_GP_Busy, TIME_IDLE_LIMIT, minor);
if (rc == -1) return -ETIMEDOUT;
@@ -774,11 +776,10 @@ static long write_ecp(unsigned minor, const char *c, unsigned long cnt)
* that. Otherwise, terminate and do my writing in compat mode. This
* is the safest course as any device can handle it.
*/
-static long bpp_write(struct inode *inode, struct file *f,
- const char *c, unsigned long cnt)
+static ssize_t bpp_write(struct file *f, const char *c, size_t cnt, loff_t * ppos)
{
long errno = 0;
- unsigned minor = MINOR(inode->i_rdev);
+ const unsigned minor = MINOR(f->f_dentry->d_inode->i_rdev);
if (minor >= BPP_NO) return -ENODEV;
if (!instances[minor].present) return -ENODEV;
@@ -861,6 +862,11 @@ static struct file_operations bpp_fops = {
bpp_open,
NULL, /* flush */
bpp_release,
+ NULL, /* fsync */
+ NULL, /* fasync */
+ NULL, /* check media change */
+ NULL, /* revalidate */
+ NULL, /* lock */
};
#if defined(__i386__)
diff --git a/drivers/sbus/char/flash.c b/drivers/sbus/char/flash.c
index cea0c5131..6bd2eabfb 100644
--- a/drivers/sbus/char/flash.c
+++ b/drivers/sbus/char/flash.c
@@ -1,4 +1,4 @@
-/* $Id: flash.c,v 1.10 1998/08/26 10:29:41 davem Exp $
+/* $Id: flash.c,v 1.11 1999/03/09 14:06:45 davem Exp $
* flash.c: Allow mmap access to the OBP Flash, for OBP updates.
*
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
@@ -72,8 +72,6 @@ flash_mmap(struct file *file, struct vm_area_struct *vma)
if (remap_page_range(vma->vm_start, addr, size, vma->vm_page_prot))
return -EAGAIN;
- vma->vm_file = file;
- file->f_count++;
return 0;
}
diff --git a/drivers/sbus/char/pcikbd.c b/drivers/sbus/char/pcikbd.c
index 297b8f9ae..ef19f74b9 100644
--- a/drivers/sbus/char/pcikbd.c
+++ b/drivers/sbus/char/pcikbd.c
@@ -1,4 +1,4 @@
-/* $Id: pcikbd.c,v 1.24 1998/11/08 11:15:24 davem Exp $
+/* $Id: pcikbd.c,v 1.27 1999/05/09 06:40:47 ecd Exp $
* pcikbd.c: Ultra/AX PC keyboard support.
*
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
@@ -228,8 +228,6 @@ unsigned char pcikbd_sysrq_xlate[128] =
"\r\000/"; /* 0x60 - 0x6f */
#endif
-static unsigned int prev_scancode = 0;
-
int pcikbd_setkeycode(unsigned int scancode, unsigned int keycode)
{
if(scancode < SC_LIM || scancode > 255 || keycode > 127)
@@ -262,29 +260,23 @@ int do_acknowledge(unsigned char scancode)
return 0;
}
}
- if(scancode == 0) {
- prev_scancode = 0;
- return 0;
- }
return 1;
}
-int pcikbd_pretranslate(unsigned char scancode, char raw_mode)
+int pcikbd_translate(unsigned char scancode, unsigned char *keycode,
+ char raw_mode)
{
- if(scancode == 0xff) {
- prev_scancode = 0;
+ static int prev_scancode = 0;
+
+ if (scancode == 0xe0 || scancode == 0xe1) {
+ prev_scancode = scancode;
return 0;
}
- if(scancode == 0xe0 || scancode == 0xe1) {
- prev_scancode = scancode;
+ if (scancode == 0x00 || scancode == 0xff) {
+ prev_scancode = 0;
return 0;
}
- return 1;
-}
-
-int pcikbd_translate(unsigned char scancode, unsigned char *keycode,
- char raw_mode)
-{
+ scancode &= 0x7f;
if(prev_scancode) {
if(prev_scancode != 0xe0) {
if(prev_scancode == 0xe1 && scancode == 0x1d) {
@@ -338,7 +330,7 @@ pcikbd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
break;
scancode = pcikbd_inb(pcikbd_iobase + KBD_DATA_REG);
if((status & KBD_STAT_OBF) && do_acknowledge(scancode))
- handle_scancode(scancode);
+ handle_scancode(scancode, !(scancode & 0x80));
status = pcikbd_inb(pcikbd_iobase + KBD_STATUS_REG);
} while(status & KBD_STAT_OBF);
mark_bh(KEYBOARD_BH);
@@ -985,9 +977,11 @@ found:
}
queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL);
+ if (!queue) {
+ printk("pcimouse_init: kmalloc(aux_queue) failed.\n");
+ return -ENOMEM;
+ }
memset(queue, 0, sizeof(*queue));
- queue->head = queue->tail = 0;
- queue->proc_list = NULL;
if (request_irq(pcimouse_irq, &pcimouse_interrupt,
SA_SHIRQ, "mouse", (void *)pcimouse_iobase)) {
diff --git a/drivers/sbus/char/sab82532.c b/drivers/sbus/char/sab82532.c
index 1ea317726..bbbd7c670 100644
--- a/drivers/sbus/char/sab82532.c
+++ b/drivers/sbus/char/sab82532.c
@@ -1,4 +1,4 @@
-/* $Id: sab82532.c,v 1.27 1998/11/08 11:15:25 davem Exp $
+/* $Id: sab82532.c,v 1.30 1999/03/24 11:34:52 davem Exp $
* sab82532.c: ASYNC Driver for the SIEMENS SAB82532 DUSCC.
*
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
@@ -2136,7 +2136,7 @@ sab82532_kgdb_hook(int line))
__initfunc(static inline void show_serial_version(void))
{
- char *revision = "$Revision: 1.27 $";
+ char *revision = "$Revision: 1.30 $";
char *version, *p;
version = strchr(revision, ' ');
@@ -2359,8 +2359,10 @@ void cleanup_module(void)
restore_flags(flags);
for (i = 0; i < NR_PORTS; i++) {
- if (sab82532_table[i].type != PORT_UNKNOWN)
- release_region(sab82532_table[i].port, 8);
+ struct sab82532 *info = (struct sab82532 *)sab82532_table[i]->driver_data;
+ if (info->type != PORT_UNKNOWN)
+ release_region((unsigned long)info->regs,
+ sizeof(union sab82532_async_regs));
}
if (tmp_buf) {
free_page((unsigned long) tmp_buf);
diff --git a/drivers/sbus/char/su.c b/drivers/sbus/char/su.c
index b4ab6693f..70e4f3657 100644
--- a/drivers/sbus/char/su.c
+++ b/drivers/sbus/char/su.c
@@ -1,4 +1,4 @@
-/* $Id: su.c,v 1.16 1998/11/14 23:02:54 ecd Exp $
+/* $Id: su.c,v 1.18 1999/01/02 16:47:37 davem Exp $
* su.c: Small serial driver for keyboard/mouse interface on sparc32/PCI
*
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
@@ -157,7 +157,7 @@ static int serial_refcount;
#define WAKEUP_CHARS 256
static void autoconfig(struct su_struct *info);
-static void change_speed(struct su_struct *info);
+static void change_speed(struct su_struct *info, struct termios *old);
static void su_wait_until_sent(struct tty_struct *tty, int timeout);
/*
@@ -845,7 +845,7 @@ startup(struct su_struct *info)
/*
* and set the speed of the serial port
*/
- change_speed(info);
+ change_speed(info, 0);
info->flags |= ASYNC_INITIALIZED;
restore_flags(flags);
@@ -948,7 +948,8 @@ su_get_baud_rate(struct su_struct *info)
* the specified baud rate for a serial port.
*/
static void
-change_speed(struct su_struct *info)
+change_speed(struct su_struct *info,
+ struct termios *old_termios)
{
int quot = 0, baud;
unsigned int cval, fcr = 0;
@@ -999,7 +1000,25 @@ change_speed(struct su_struct *info)
else if (baud)
quot = info->baud_base / baud;
}
- /* If the quotient is ever zero, default to 9600 bps */
+ /* If the quotient is zero refuse the change */
+ if (!quot && old_termios) {
+ info->tty->termios->c_cflag &= ~CBAUD;
+ info->tty->termios->c_cflag |= (old_termios->c_cflag & CBAUD);
+ baud = tty_get_baud_rate(info->tty);
+ if (!baud)
+ baud = 9600;
+ if (baud == 38400 &&
+ ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST))
+ quot = info->custom_divisor;
+ else {
+ if (baud == 134)
+ /* Special case since 134 is really 134.5 */
+ quot = (2*info->baud_base / 269);
+ else if (baud)
+ quot = info->baud_base / baud;
+ }
+ }
+ /* As a last resort, if the quotient is zero, default to 9600 bps */
if (!quot)
quot = info->baud_base / 9600;
info->timeout = ((info->xmit_fifo_size*HZ*bits*quot) / info->baud_base);
@@ -1157,7 +1176,7 @@ su_change_mouse_baud(int baud)
info->cflag |= 1200;
break;
}
- change_speed(info);
+ change_speed(info, 0);
}
static void
@@ -1303,6 +1322,9 @@ su_send_xchar(struct tty_struct *tty, char ch)
if (serial_paranoia_check(info, tty->device, "su_send_char"))
return;
+ if (!(info->flags & ASYNC_INITIALIZED))
+ return;
+
info->x_char = ch;
if (ch) {
/* Make sure transmit interrupts are on */
@@ -1618,7 +1640,7 @@ su_set_termios(struct tty_struct *tty, struct termios *old_termios)
== RELEVANT_IFLAG(old_termios->c_iflag)))
return;
- change_speed(info);
+ change_speed(info, old_termios);
/* Handle transition to B0 status */
if ((old_termios->c_cflag & CBAUD) &&
@@ -2067,13 +2089,13 @@ su_open(struct tty_struct *tty, struct file * filp)
*tty->termios = info->normal_termios;
else
*tty->termios = info->callout_termios;
- change_speed(info);
+ change_speed(info, 0);
}
#ifdef CONFIG_SERIAL_CONSOLE
if (sercons.cflag && sercons.index == line) {
tty->termios->c_cflag = sercons.cflag;
sercons.cflag = 0;
- change_speed(info);
+ change_speed(info, 0);
}
#endif
info->session = current->session;
@@ -2193,7 +2215,7 @@ done:
*/
__initfunc(static __inline__ void show_su_version(void))
{
- char *revision = "$Revision: 1.16 $";
+ char *revision = "$Revision: 1.18 $";
char *version, *p;
version = strchr(revision, ' ');
@@ -2207,8 +2229,8 @@ __initfunc(static __inline__ void show_su_version(void))
* This routine is called by su_init() to initialize a specific serial
* port. It determines what type of UART chip this serial port is
* using: 8250, 16450, 16550, 16550A. The important question is
- * whether or not this UART is a 16550A or not, since this will
- * determine whether or not we can use its FIFO features or not.
+ * whether or not this UART is a 16550A, since this will determine
+ * whether or not we can use its FIFO features.
*/
static void
autoconfig(struct su_struct *info)
diff --git a/drivers/sbus/char/sunkbd.c b/drivers/sbus/char/sunkbd.c
index b720afbec..41ffe9159 100644
--- a/drivers/sbus/char/sunkbd.c
+++ b/drivers/sbus/char/sunkbd.c
@@ -514,8 +514,13 @@ void sunkbd_inchar(unsigned char ch, struct pt_regs *regs)
mark_bh(CONSOLE_BH);
add_keyboard_randomness(keycode);
+ tty = ttytab? ttytab[fg_console]: NULL;
+ if (tty && (!tty->driver_data)) {
+ /* This is to workaround ugly bug in tty_io.c, which
+ does not do locking when it should */
+ tty = NULL;
+ }
kbd = kbd_table + fg_console;
- tty = ttytab[fg_console];
if((raw_mode = (kbd->kbdmode == VC_RAW))) {
if (kbd_redirected == fg_console+1)
push_kbd (keycode);
@@ -1474,7 +1479,7 @@ kbd_close (struct inode *i, struct file *f)
return 0;
if (kbd_redirected)
- kbd_table [kbd_opened-1].kbdmode = VC_XLATE;
+ kbd_table [kbd_redirected-1].kbdmode = VC_XLATE;
kbd_redirected = 0;
kbd_opened = 0;
diff --git a/drivers/sbus/char/sunmouse.c b/drivers/sbus/char/sunmouse.c
index 1c000b661..8547e47dd 100644
--- a/drivers/sbus/char/sunmouse.c
+++ b/drivers/sbus/char/sunmouse.c
@@ -94,7 +94,7 @@ extern void mouse_put_char(char ch);
#undef SMOUSE_DEBUG
-static void
+static int
push_event (Firm_event *ev)
{
int next = (sunmouse.head + 1) % EV_SIZE;
@@ -102,7 +102,9 @@ push_event (Firm_event *ev)
if (next != sunmouse.tail){
sunmouse.queue.ev [sunmouse.head] = *ev;
sunmouse.head = next;
+ return 1;
}
+ return 0;
}
static int
@@ -150,7 +152,11 @@ void sun_mouse_change_baud(void)
extern void rs_change_mouse_baud(int newbaud);
if(mouse_baud == 1200)
+ mouse_baud = 2400;
+ else if(mouse_baud == 2400)
mouse_baud = 4800;
+ else if(mouse_baud == 4800)
+ mouse_baud = 9600;
else
mouse_baud = 1200;
@@ -196,7 +202,7 @@ void
sun_mouse_inbyte(unsigned char byte)
{
signed char mvalue;
- int d;
+ int d, pushed = 0;
Firm_event ev;
add_mouse_randomness (byte);
@@ -290,29 +296,31 @@ sun_mouse_inbyte(unsigned char byte)
}
ev.time = xtime;
ev.value = ev.value ? VKEY_DOWN : VKEY_UP;
- push_event (&ev);
+ pushed += push_event (&ev);
}
if (sunmouse.delta_x){
ev.id = LOC_X_DELTA;
ev.time = xtime;
ev.value = sunmouse.delta_x;
- push_event (&ev);
+ pushed += push_event (&ev);
sunmouse.delta_x = 0;
}
if (sunmouse.delta_y){
ev.id = LOC_Y_DELTA;
ev.time = xtime;
ev.value = sunmouse.delta_y;
- push_event (&ev);
+ pushed += push_event (&ev);
}
- /* We just completed a transaction, wake up whoever is awaiting
- * this event.
- */
- sunmouse.ready = 1;
- if (sunmouse.fasync)
- kill_fasync (sunmouse.fasync, SIGIO);
- wake_up_interruptible(&sunmouse.proc_list);
+ if(pushed != 0) {
+ /* We just completed a transaction, wake up whoever is awaiting
+ * this event.
+ */
+ sunmouse.ready = 1;
+ if (sunmouse.fasync)
+ kill_fasync (sunmouse.fasync, SIGIO);
+ wake_up_interruptible(&sunmouse.proc_list);
+ }
return;
}
diff --git a/drivers/sbus/char/sunserial.c b/drivers/sbus/char/sunserial.c
index 30ff83e4f..075062cf1 100644
--- a/drivers/sbus/char/sunserial.c
+++ b/drivers/sbus/char/sunserial.c
@@ -1,4 +1,4 @@
-/* $Id: sunserial.c,v 1.67 1998/10/25 03:22:46 jj Exp $
+/* $Id: sunserial.c,v 1.68 1998/12/09 18:53:51 davem Exp $
* serial.c: Serial port driver infrastructure for the Sparc.
*
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
@@ -401,10 +401,10 @@ sun_serial_setup(unsigned long memory_start))
return memory_start;
#ifdef __sparc_v9__
- ret = prom_finddevice("/ssp-serial");
- if (ret && ret != -1) {
+ { extern int this_is_starfire;
/* Hello, Starfire. Pleased to meet you :) */
- return memory_start;
+ if(this_is_starfire != 0)
+ return memory_start;
}
#endif
diff --git a/drivers/sbus/char/vfc_dev.c b/drivers/sbus/char/vfc_dev.c
index 48661f34b..9ebc20c71 100644
--- a/drivers/sbus/char/vfc_dev.c
+++ b/drivers/sbus/char/vfc_dev.c
@@ -582,8 +582,6 @@ static int vfc_mmap(struct inode *inode, struct file *file,
if(ret)
return -EAGAIN;
- vma->vm_file = file;
- file->f_count++;
return 0;
}
diff --git a/drivers/sbus/char/zs.c b/drivers/sbus/char/zs.c
index 67aa3c574..9195f5a0e 100644
--- a/drivers/sbus/char/zs.c
+++ b/drivers/sbus/char/zs.c
@@ -1,4 +1,4 @@
-/* $Id: zs.c,v 1.32 1998/11/08 11:15:29 davem Exp $
+/* $Id: zs.c,v 1.41 1999/04/16 16:22:27 jj Exp $
* zs.c: Zilog serial port driver for the Sparc.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -53,6 +53,22 @@ static int num_serial = 2; /* sun4/sun4c/sun4m - Two chips on board. */
#define KEYBOARD_LINE 0x2
#define MOUSE_LINE 0x3
+/* On 32-bit sparcs we need to delay after register accesses
+ * to accomodate sun4 systems, but we do not need to flush writes.
+ * On 64-bit sparc we only need to flush single writes to ensure
+ * completion.
+ */
+#ifndef __sparc_v9__
+#define ZSDELAY() udelay(5)
+#define ZSDELAY_LONG() udelay(20)
+#define ZS_WSYNC(channel) do { } while(0)
+#else
+#define ZSDELAY()
+#define ZSDELAY_LONG()
+#define ZS_WSYNC(channel) \
+ ((void) *((volatile unsigned char *)(&((channel)->control))))
+#endif
+
struct sun_zslayout **zs_chips;
struct sun_zschannel **zs_channels;
struct sun_zschannel *zs_mousechan;
@@ -200,9 +216,9 @@ static inline unsigned char read_zsreg(struct sun_zschannel *channel,
unsigned char retval;
channel->control = reg;
- udelay(5);
+ ZSDELAY();
retval = channel->control;
- udelay(5);
+ ZSDELAY();
return retval;
}
@@ -210,9 +226,9 @@ static inline void write_zsreg(struct sun_zschannel *channel,
unsigned char reg, unsigned char value)
{
channel->control = reg;
- udelay(5);
+ ZSDELAY();
channel->control = value;
- udelay(5);
+ ZSDELAY();
}
static inline void load_zsregs(struct sun_serial *info, unsigned char *regs)
@@ -239,7 +255,7 @@ static inline void load_zsregs(struct sun_serial *info, unsigned char *regs)
write_zsreg(channel, R9, CHRA);
else
write_zsreg(channel, R9, CHRB);
- udelay(20); /* wait for some old sun4's */
+ ZSDELAY_LONG();
write_zsreg(channel, R4, regs[R4]);
write_zsreg(channel, R3, regs[R3] & ~RxENAB);
write_zsreg(channel, R5, regs[R5] & ~TxENAB);
@@ -267,10 +283,16 @@ static inline void zs_put_char(struct sun_zschannel *channel, char ch)
{
int loops = ZS_PUT_CHAR_MAX_DELAY;
+ /* Do not change this to use ZSDELAY as this is
+ * a timed polling loop and on sparc64 ZSDELAY
+ * is a nop. -DaveM
+ */
while((channel->control & Tx_BUF_EMP) == 0 && --loops)
udelay(5);
+
channel->data = ch;
- udelay(5);
+ ZSDELAY();
+ ZS_WSYNC(channel);
}
/* Sets or clears DTR/RTS on the requested line */
@@ -420,7 +442,7 @@ static _INLINE_ void receive_chars(struct sun_serial *info, struct pt_regs *regs
do {
ch = (info->zs_channel->data) & info->parity_mask;
- udelay(5);
+ ZSDELAY();
/* If this is the console keyboard, we need to handle
* L1-A's here.
@@ -482,7 +504,7 @@ static _INLINE_ void receive_chars(struct sun_serial *info, struct pt_regs *regs
/* Check if we have another character... */
stat = info->zs_channel->control;
- udelay(5);
+ ZSDELAY();
if (!(stat & Rx_CH_AV))
break;
@@ -507,7 +529,8 @@ static _INLINE_ void transmit_chars(struct sun_serial *info)
if((info->xmit_cnt <= 0) || (tty != 0 && tty->stopped)) {
/* That's peculiar... */
info->zs_channel->control = RES_Tx_P;
- udelay(5);
+ ZSDELAY();
+ ZS_WSYNC(info->zs_channel);
return;
}
@@ -521,7 +544,8 @@ static _INLINE_ void transmit_chars(struct sun_serial *info)
if(info->xmit_cnt <= 0) {
info->zs_channel->control = RES_Tx_P;
- udelay(5);
+ ZSDELAY();
+ ZS_WSYNC(info->zs_channel);
}
}
@@ -531,10 +555,11 @@ static _INLINE_ void status_handle(struct sun_serial *info)
/* Get status from Read Register 0 */
status = info->zs_channel->control;
- udelay(5);
+ ZSDELAY();
/* Clear status condition... */
info->zs_channel->control = RES_EXT_INT;
- udelay(5);
+ ZSDELAY();
+ ZS_WSYNC(info->zs_channel);
#if 0
if(status & DCD) {
@@ -571,7 +596,7 @@ static _INLINE_ void special_receive(struct sun_serial *info)
stat = read_zsreg(info->zs_channel, R1);
if (stat & (PAR_ERR | Rx_OVR | CRC_ERR)) {
ch = info->zs_channel->data;
- udelay(5);
+ ZSDELAY();
}
if (!tty)
@@ -592,7 +617,8 @@ done:
queue_task(&tty->flip.tqueue, &tq_timer);
clear:
info->zs_channel->control = ERR_RES;
- udelay(5);
+ ZSDELAY();
+ ZS_WSYNC(info->zs_channel);
}
@@ -772,9 +798,12 @@ static int startup(struct sun_serial * info)
* Clear the interrupt registers.
*/
info->zs_channel->control = ERR_RES;
- udelay(5);
+ ZSDELAY();
+ ZS_WSYNC(info->zs_channel);
+
info->zs_channel->control = RES_H_IUS;
- udelay(5);
+ ZSDELAY();
+ ZS_WSYNC(info->zs_channel);
/*
* Now, initialize the Zilog
@@ -798,9 +827,12 @@ static int startup(struct sun_serial * info)
* And clear the interrupt registers again for luck.
*/
info->zs_channel->control = ERR_RES;
- udelay(5);
+ ZSDELAY();
+ ZS_WSYNC(info->zs_channel);
+
info->zs_channel->control = RES_H_IUS;
- udelay(5);
+ ZSDELAY();
+ ZS_WSYNC(info->zs_channel);
if (info->tty)
clear_bit(TTY_IO_ERROR, &info->tty->flags);
@@ -1006,6 +1038,7 @@ void putDebugChar(char kgdb_char)
while((chan->control & Tx_BUF_EMP)==0)
udelay(5);
chan->data = kgdb_char;
+ ZS_WSYNC(chan);
}
char getDebugChar(void)
@@ -1013,7 +1046,7 @@ char getDebugChar(void)
struct sun_zschannel *chan = zs_kgdbchan;
while((chan->control & Rx_CH_AV)==0)
- barrier();
+ udelay(5);
return chan->data;
}
@@ -1254,6 +1287,9 @@ static int set_serial_info(struct sun_serial * info,
goto check_and_exit;
}
+ if(new_serial.baud_base < 9600)
+ return -EINVAL;
+
if (info->count > 1)
return -EBUSY;
@@ -1291,6 +1327,7 @@ static int get_lsr_info(struct sun_serial * info, unsigned int *value)
cli();
status = info->zs_channel->control;
+ ZSDELAY();
sti();
put_user_ret(status,value, -EFAULT);
return 0;
@@ -1303,6 +1340,7 @@ static int get_modem_info(struct sun_serial * info, unsigned int *value)
cli();
status = info->zs_channel->control;
+ ZSDELAY();
sti();
result = ((info->curregs[5] & RTS) ? TIOCM_RTS : 0)
| ((info->curregs[5] & DTR) ? TIOCM_DTR : 0)
@@ -1806,7 +1844,7 @@ int zs_open(struct tty_struct *tty, struct file * filp)
static void show_serial_version(void)
{
- char *revision = "$Revision: 1.32 $";
+ char *revision = "$Revision: 1.41 $";
char *version, *p;
version = strchr(revision, ' ');
@@ -1853,8 +1891,8 @@ get_zs(int chip))
int len = prom_getproperty(zsnode, "address",
(void *) vaddr, sizeof(vaddr));
- if(len == -1) {
- struct linux_sbus *sbus;
+ if(len == -1 || central_bus != NULL) {
+ struct linux_sbus *sbus = NULL;
struct linux_sbus_device *sdev = NULL;
/* "address" property is not guarenteed,
@@ -1862,20 +1900,40 @@ get_zs(int chip))
* anyways by our clever TLB miss handling
* scheme, so don't fail here. -DaveM
*/
- for_each_sbus(sbus) {
- for_each_sbusdev(sdev, sbus) {
- if (sdev->prom_node == zsnode)
- goto found;
+ if (central_bus == NULL) {
+ for_each_sbus(sbus) {
+ for_each_sbusdev(sdev, sbus) {
+ if (sdev->prom_node == zsnode)
+ goto found;
+ }
}
}
found:
- if (sdev == NULL)
+ if (sdev == NULL && central_bus == NULL)
prom_halt();
- prom_apply_sbus_ranges(sbus, sdev->reg_addrs, 1, sdev);
- mapped_addr = (unsigned long)
- sparc_alloc_io(sdev->reg_addrs[0].phys_addr, 0,
- PAGE_SIZE, "Zilog Registers",
- sdev->reg_addrs[0].which_io, 0x0);
+ if (central_bus == NULL) {
+ prom_apply_sbus_ranges(sbus, sdev->reg_addrs, 1, sdev);
+ mapped_addr = (unsigned long)
+ sparc_alloc_io(sdev->reg_addrs[0].phys_addr, 0,
+ PAGE_SIZE, "Zilog Registers",
+ sdev->reg_addrs[0].which_io, 0x0);
+ } else {
+ struct linux_prom_registers zsregs[1];
+ int err;
+
+ err = prom_getproperty(zsnode, "reg",
+ (char *)&zsregs[0],
+ sizeof(zsregs));
+ if (err == -1) {
+ prom_printf("ZS: Cannot map Zilog regs.\n");
+ prom_halt();
+ }
+ prom_apply_fhc_ranges(central_bus->child, &zsregs[0], 1);
+ prom_apply_central_ranges(central_bus, &zsregs[0], 1);
+ mapped_addr = (unsigned long)
+ __va((((unsigned long)zsregs[0].which_io)<<32) |
+ (((unsigned long)zsregs[0].phys_addr)));
+ }
} else if(len % sizeof(unsigned int)) {
prom_printf("WHOOPS: proplen for %s "
"was %d, need multiple of "
@@ -1954,25 +2012,27 @@ get_zs(int chip))
/* Can use the prom for other machine types */
zsnode = prom_getchild(prom_root_node);
if (sparc_cpu_model == sun4d) {
- int board, node;
+ int node;
+ int no = 0;
tmpnode = zsnode;
+ zsnode = 0;
+ bbnode = 0;
while (tmpnode && (tmpnode = prom_searchsiblings(tmpnode, "cpu-unit"))) {
- board = prom_getintdefault (tmpnode, "board#", -1);
- if (board == (chip >> 1)) {
- node = prom_getchild(tmpnode);
- if (node && (node = prom_searchsiblings(node, "bootbus"))) {
+ bbnode = prom_getchild(tmpnode);
+ if (bbnode && (bbnode = prom_searchsiblings(bbnode, "bootbus"))) {
+ if (no == (chip >> 1)) {
cpunode = tmpnode;
- bbnode = node;
- zsnode = prom_getchild(node);
+ zsnode = prom_getchild(bbnode);
chipid = (chip & 1);
break;
}
+ no++;
}
tmpnode = prom_getsibling(tmpnode);
}
if (!tmpnode)
- panic ("get_zs: couldn't find board%d's bootbus\n", chip >> 1);
+ panic ("get_zs: couldn't find %dth bootbus\n", chip >> 1);
} else {
tmpnode = prom_searchsiblings(zsnode, "obio");
if(tmpnode)
@@ -2066,13 +2126,12 @@ __initfunc(int zs_probe (unsigned long *memory_start))
node = prom_getchild(prom_root_node);
if (sparc_cpu_model == sun4d) {
- node = prom_searchsiblings(node, "boards");
- if (!node)
- panic ("Cannot find out count of boards");
- else
- node = prom_getchild(node);
- while (node && (node = prom_searchsiblings(node, "bif"))) {
- NUM_SERIAL += 2;
+ int bbnode;
+
+ while (node && (node = prom_searchsiblings(node, "cpu-unit"))) {
+ bbnode = prom_getchild(node);
+ if (bbnode && prom_searchsiblings(bbnode, "bootbus"))
+ NUM_SERIAL += 2;
node = prom_getsibling(node);
}
goto no_probe;
@@ -2082,7 +2141,7 @@ __initfunc(int zs_probe (unsigned long *memory_start))
int central_node;
/* Central bus zilogs must be checked for first,
- * since Enterprise boxes have SBUS as well.
+ * since Enterprise boxes might have SBUSes as well.
*/
central_node = prom_finddevice("/central");
if(central_node != 0 && central_node != -1)
@@ -2219,11 +2278,6 @@ __initfunc(int zs_init(void))
return 0;
#endif
-#ifdef CONFIG_PCI
- if (pci_present())
- return 0;
-#endif
-
/* Setup base handler, and timer table. */
init_bh(SERIAL_BH, do_serial_bh);
timer_table[RS_TIMER].fn = zs_timer;
@@ -2290,13 +2344,21 @@ __initfunc(int zs_init(void))
/* Initialize Softinfo */
zs_prepare();
+ /* Grab IRQ line before poking the chips so we do
+ * not lose any interrupts.
+ */
+ if (request_irq(zilog_irq, zs_interrupt,
+ (SA_INTERRUPT | SA_STATIC_ALLOC),
+ "Zilog8530", zs_chain))
+ panic("Unable to attach zs intr\n");
+
/* Initialize Hardware */
for(channel = 0; channel < NUM_CHANNELS; channel++) {
/* Hardware reset each chip */
if (!(channel & 1)) {
write_zsreg(zs_soft[channel].zs_channel, R9, FHWRES);
- udelay(20); /* wait for some old sun4's */
+ ZSDELAY_LONG();
dummy = read_zsreg(zs_soft[channel].zs_channel, R0);
}
@@ -2462,10 +2524,6 @@ __initfunc(int zs_init(void))
printk(" is a Zilog8530\n");
}
- if (request_irq(zilog_irq, zs_interrupt,
- (SA_INTERRUPT | SA_STATIC_ALLOC),
- "Zilog8530", zs_chain))
- panic("Unable to attach zs intr\n");
restore_flags(flags);
keyboard_zsinit(kbd_put_char);
@@ -2549,7 +2607,7 @@ static void zs_fair_output(struct sun_serial *info)
/* Last character is being transmitted now (hopefully). */
info->zs_channel->control = RES_Tx_P;
- udelay(5);
+ ZSDELAY();
restore_flags(flags);
return;