patch-2.1.129 linux/drivers/sbus/char/su.c

Next file: linux/drivers/sbus/char/zs.c
Previous file: linux/drivers/sbus/char/sab82532.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.128/linux/drivers/sbus/char/su.c linux/drivers/sbus/char/su.c
@@ -1,4 +1,4 @@
-/* $Id: su.c,v 1.12 1998/10/25 04:24:52 ecd Exp $
+/* $Id: su.c,v 1.16 1998/11/14 23:02:54 ecd Exp $
  * su.c: Small serial driver for keyboard/mouse interface on sparc32/PCI
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -37,7 +37,7 @@
 	printk("(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n",		\
 	       kdevname(tty->device), (info->flags), serial_refcount,	\
 	       info->count,tty->count,s);				\
-} while (0);
+} while (0)
 #else
 #define DBG_CNT(s)
 #endif
@@ -146,7 +146,7 @@
 };
 
 static char *serial_name = "PCIO serial driver";
-static char *serial_version = "1.1";
+static char serial_version[16];
 
 static DECLARE_TASK_QUEUE(tq_serial);
 
@@ -251,10 +251,10 @@
 	/*
 	 * MrCoffee has weird schematics: IRQ4 & P10(?) pins of SuperIO are
 	 * connected with a gate then go to SlavIO. When IRQ4 goes tristated
-	 * gate gives logical one. Since we use level triggered interrupts
+	 * gate outputs a logical one. Since we use level triggered interrupts
 	 * we have lockup and watchdog reset. We cannot mask IRQ because
-	 * keyboard shares IRQ with us (Bob Smelik: I would not hire you).
-	 * P3: Assure that OUT2 never goes down.
+	 * keyboard shares IRQ with us (Word has it as Bob Smelik's design).
+	 * This problem is similar to what Alpha people suffer, see serial.c.
 	 */
 	if (offset == UART_MCR) value |= UART_MCR_OUT2;
 	*(volatile unsigned char *)(info->port + offset) = value;
@@ -386,14 +386,13 @@
 	icount = &info->icount;
 	do {
 		ch = serial_inp(info, UART_RX);
-
 		if (tty->flip.count >= TTY_FLIPBUF_SIZE)
 			break;
 		*tty->flip.char_buf_ptr = ch;
 		icount->rx++;
 
 #ifdef SERIAL_DEBUG_INTR
-		printk("DR%02x:%02x...", ch, *status);
+		printk("D%02x:%02x.", ch, *status);
 #endif
 		*tty->flip.flag_buf_ptr = 0;
 		if (*status & (UART_LSR_BI | UART_LSR_PE |
@@ -417,8 +416,12 @@
 			 * should be ignored.
 			 */
 			if (*status & info->ignore_status_mask) {
-				if (++ignored > 100)
+				if (++ignored > 100) {
+#ifdef SERIAL_DEBUG_INTR
+					printk("ign100..");
+#endif
 					break;
+				}
 				goto ignore_char;
 			}
 			*status &= info->read_status_mask;
@@ -454,6 +457,9 @@
 	ignore_char:
 		*status = serial_inp(info, UART_LSR);
 	} while (*status & UART_LSR_DR);
+#ifdef SERIAL_DEBUG_INTR
+	printk("E%02x.R%d", *status, tty->flip.count);
+#endif
 	tty_flip_buffer_push(tty);
 }
 
@@ -490,7 +496,7 @@
 		su_sched_event(info, RS_EVENT_WRITE_WAKEUP);
 
 #ifdef SERIAL_DEBUG_INTR
-	printk("THRE...");
+	printk("T%d...", info->xmit_cnt);
 #endif
 	if (intr_done)
 		*intr_done = 0;
@@ -580,7 +586,7 @@
 	unsigned char status;
 
 #ifdef SERIAL_DEBUG_INTR
-	printk("su_interrupt(%s)...", __irq_itoa(irq));
+	printk("su_kbd_ms_interrupt(%s)...", __irq_itoa(irq));
 #endif
 	if (!info)
 		return;
@@ -611,12 +617,16 @@
 	int pass_counter = 0;
 
 #ifdef SERIAL_DEBUG_INTR
-	printk("su_interrupt(%s)...", __irq_itoa(irq));
+	printk("su_serial_interrupt(%s)...", __irq_itoa(irq));
 #endif
 	info = (struct su_struct *)dev_id;
-	if (!info || !info->tty)
+	if (!info || !info->tty) {
+#ifdef SERIAL_DEBUG_INTR
+		printk("strain\n");
+#endif
 		return;
-	
+	}
+
 	do {
 		status = serial_inp(info, UART_LSR);
 #ifdef SERIAL_DEBUG_INTR
@@ -629,8 +639,8 @@
 			transmit_chars(info, 0);
 
 		if (pass_counter++ > RS_ISR_PASS_LIMIT) {
-#if 0
-			printk("rs loop break\n");
+#ifdef SERIAL_DEBUG_INTR
+			printk("rs loop break");
 #endif
 			break; 	/* Prevent infinite loops */
 		}
@@ -658,18 +668,16 @@
  * interrupt driver proper are done; the interrupt driver schedules
  * them using su_sched_event(), and they get done here.
  */
-static void
-do_serial_bh(void)
+static void do_serial_bh(void)
 {
 	run_task_queue(&tq_serial);
 }
 
-static void
-do_softint(void *private_)
+static void do_softint(void *private_)
 {
 	struct su_struct	*info = (struct su_struct *) private_;
 	struct tty_struct	*tty;
-	
+
 	tty = info->tty;
 	if (!tty)
 		return;
@@ -724,7 +732,8 @@
 	cli();
 
 #ifdef SERIAL_DEBUG_OPEN
-	printk("starting up ttys%d (irq %d)...", info->line, state->irq);
+	printk("starting up ttys%d (irq %s)...", info->line,
+	       __irq_itoa(info->irq));
 #endif
 
 	if (uart_config[info->type].flags & UART_STARTECH) {
@@ -1269,12 +1278,13 @@
 su_flush_buffer(struct tty_struct *tty)
 {
 	struct su_struct *info = (struct su_struct *)tty->driver_data;
+	unsigned long flags;
 
 	if (serial_paranoia_check(info, tty->device, "su_flush_buffer"))
 		return;
-	cli();
+	save_flags(flags); cli();
 	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
-	sti();
+	restore_flags(flags);
 	wake_up_interruptible(&tty->write_wait);
 	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
 	    tty->ldisc.write_wakeup)
@@ -1313,41 +1323,43 @@
 su_throttle(struct tty_struct * tty)
 {
 	struct su_struct *info = (struct su_struct *)tty->driver_data;
+	unsigned long flags;
 #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->device, "su_throttle"))
 		return;
-	
+
 	if (I_IXOFF(tty))
 		su_send_xchar(tty, STOP_CHAR(tty));
 
 	if (tty->termios->c_cflag & CRTSCTS)
 		info->MCR &= ~UART_MCR_RTS;
 
-	cli();
+	save_flags(flags); cli();
 	serial_out(info, UART_MCR, info->MCR);
-	sti();
+	restore_flags(flags);
 }
 
 static void
 su_unthrottle(struct tty_struct * tty)
 {
 	struct su_struct *info = (struct su_struct *)tty->driver_data;
+	unsigned long flags;
 #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->device, "su_unthrottle"))
 		return;
-	
+
 	if (I_IXOFF(tty)) {
 		if (info->x_char)
 			info->x_char = 0;
@@ -1356,9 +1368,9 @@
 	}
 	if (tty->termios->c_cflag & CRTSCTS)
 		info->MCR |= UART_MCR_RTS;
-	cli();
+	save_flags(flags); cli();
 	serial_out(info, UART_MCR, info->MCR);
-	sti();
+	restore_flags(flags);
 }
 
 /*
@@ -1382,10 +1394,11 @@
 {
 	unsigned char status;
 	unsigned int result;
+	unsigned long flags;
 
-	cli();
+	save_flags(flags); cli();
 	status = serial_in(info, UART_LSR);
-	sti();
+	restore_flags(flags);
 	result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
 	return put_user(result,value);
 }
@@ -1396,11 +1409,12 @@
 {
 	unsigned char control, status;
 	unsigned int result;
+	unsigned long flags;
 
 	control = info->MCR;
-	cli();
+	save_flags(flags); cli();
 	status = serial_in(info, UART_MSR);
-	sti();
+	restore_flags(flags);
 	result =  ((control & UART_MCR_RTS) ? TIOCM_RTS : 0)
 		| ((control & UART_MCR_DTR) ? TIOCM_DTR : 0)
 #ifdef TIOCM_OUT1
@@ -1419,6 +1433,7 @@
 {
 	int error;
 	unsigned int arg;
+	unsigned long flags;
 
 	error = get_user(arg, value);
 	if (error)
@@ -1465,9 +1480,9 @@
 	default:
 		return -EINVAL;
 	}
-	cli();
+	save_flags(flags); cli();
 	serial_out(info, UART_MCR, info->MCR);
-	sti();
+	restore_flags(flags);
 	return 0;
 }
 
@@ -1589,13 +1604,14 @@
 		default:
 			return -ENOIOCTLCMD;
 		}
-	/* return 0; */ /* Trigger warnings is fall through by a chance. */
+	/* return 0; */ /* Trigger warnings if fall through by a chance. */
 }
 
 static void
 su_set_termios(struct tty_struct *tty, struct termios *old_termios)
 {
 	struct su_struct *info = (struct su_struct *)tty->driver_data;
+	unsigned long flags;
 
 	if (   (tty->termios->c_cflag == old_termios->c_cflag)
 	    && (   RELEVANT_IFLAG(tty->termios->c_iflag) 
@@ -1608,11 +1624,11 @@
 	if ((old_termios->c_cflag & CBAUD) &&
 	    !(tty->termios->c_cflag & CBAUD)) {
 		info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS);
-		cli();
+		save_flags(flags); cli();
 		serial_out(info, UART_MCR, info->MCR);
-		sti();
+		restore_flags(flags);
 	}
-	
+
 	/* Handle transition away from B0 status */
 	if (!(old_termios->c_cflag & CBAUD) &&
 	    (tty->termios->c_cflag & CBAUD)) {
@@ -1621,9 +1637,9 @@
 		    !test_bit(TTY_THROTTLED, &tty->flags)) {
 			info->MCR |= UART_MCR_RTS;
 		}
-		cli();
+		save_flags(flags); cli();
 		serial_out(info, UART_MCR, info->MCR);
-		sti();
+		restore_flags(flags);
 	}
 	
 	/* Handle turning off CRTSCTS */
@@ -1771,6 +1787,9 @@
 	if (info->type == PORT_UNKNOWN)
 		return;
 
+	if (info->xmit_fifo_size == 0)
+		return; /* Just in case ... */
+
 	orig_jiffies = jiffies;
 	/*
 	 * Set the check interval to be 1/5 of the estimated time to
@@ -1838,8 +1857,9 @@
 		struct su_struct *info)
 {
 	struct wait_queue wait = { current, NULL };
-	int		retval;
-	int		do_clocal = 0;
+	int		  retval;
+	int		  do_clocal = 0, extra_count = 0;
+	unsigned long	  flags;
 
 	/*
 	 * If the device is in the middle of being closed, then block
@@ -1909,19 +1929,21 @@
 	printk("block_til_ready before block: ttys%d, count = %d\n",
 	       info->line, info->count);
 #endif
-	cli();
-	if (!tty_hung_up_p(filp)) 
+	save_flags(flags); cli();
+	if (!tty_hung_up_p(filp)) {
+		extra_count = 1;
 		info->count--;
-	sti();
+	}
+	restore_flags(flags);
 	info->blocked_open++;
 	while (1) {
-		cli();
+		save_flags(flags); cli();
 		if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
 		    (tty->termios->c_cflag & CBAUD))
 			serial_out(info, UART_MCR,
 				   serial_inp(info, UART_MCR) |
 				   (UART_MCR_DTR | UART_MCR_RTS));
-		sti();
+		restore_flags(flags);
 		current->state = TASK_INTERRUPTIBLE;
 		if (tty_hung_up_p(filp) ||
 		    !(info->flags & ASYNC_INITIALIZED)) {
@@ -1952,7 +1974,7 @@
 	}
 	current->state = TASK_RUNNING;
 	remove_wait_queue(&info->open_wait, &wait);
-	if (!tty_hung_up_p(filp))
+	if (extra_count)
 		info->count++;
 	info->blocked_open--;
 #ifdef SERIAL_DEBUG_OPEN
@@ -1982,16 +2004,19 @@
 	if ((line < 0) || (line >= NR_PORTS))
 		return -ENODEV;
 	info = su_table + line;
-	if (serial_paranoia_check(info, tty->device, "su_open"))
-		return -ENODEV;
 	info->count++;
+	tty->driver_data = info;
+	info->tty = tty;
+
+	if (serial_paranoia_check(info, tty->device, "su_open")) {
+		info->count--;
+		return -ENODEV;
+	}
 
 #ifdef SERIAL_DEBUG_OPEN
 	printk("su_open %s%d, count = %d\n", tty->driver.name, info->line,
 	       info->count);
 #endif
-	tty->driver_data = info;
-	info->tty = tty;
 	info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
 
 	if (!tmp_buf) {
@@ -2066,8 +2091,9 @@
 static __inline__ int
 line_info(char *buf, struct su_struct *info)
 {
-	char	stat_buf[30], control, status;
-	int	ret;
+	char		stat_buf[30], control, status;
+	int		ret;
+	unsigned long	flags;
 
 	ret = sprintf(buf, "%d: uart:%s port:%X irq:%s",
 		      info->line, uart_config[info->type].name, 
@@ -2081,10 +2107,10 @@
 	/*
 	 * Figure out the current RS-232 lines
 	 */
-	cli();
+	save_flags(flags); cli();
 	status = serial_in(info, UART_MSR);
 	control = info ? info->MCR : serial_in(info, UART_MCR);
-	sti();
+	restore_flags(flags);
 
 	stat_buf[0] = 0;
 	stat_buf[1] = 0;
@@ -2165,9 +2191,15 @@
  * number, and identifies which options were configured into this
  * driver.
  */
-static __inline__
-void show_su_version(void)
+__initfunc(static __inline__ void show_su_version(void))
 {
+	char *revision = "$Revision: 1.16 $";
+	char *version, *p;
+
+	version = strchr(revision, ' ');
+	strcpy(serial_version, ++version);
+	p = strchr(serial_version, ' ');
+	*p = '\0';
  	printk(KERN_INFO "%s version %s\n", serial_name, serial_version);
 }
 
@@ -2249,23 +2281,21 @@
 	 * 0x80 is a non-existent port; which should be safe since
 	 * include/asm/io.h also makes this assumption.
 	 */
-	scratch = serial_in(info, UART_IER);
-	su_outb(info, UART_IER, 0);
-	scratch2 = serial_in(info, UART_IER);
-	su_outb(info, UART_IER, scratch);
+	scratch = serial_inp(info, UART_IER);
+	serial_outp(info, UART_IER, 0);
+	scratch2 = serial_inp(info, UART_IER);
+	serial_outp(info, UART_IER, scratch);
 	if (scratch2) {
 		restore_flags(flags);
 		return;		/* We failed; there's nothing here */
 	}
 
-#if 0 /* P3 You will never beleive but SuperIO fails this test in MrCoffee. */
-	scratch = serial_in(info, UART_MCR);
-	su_outb(info, UART_MCR, UART_MCR_LOOP | scratch);
-	scratch2 = serial_in(info, UART_MSR);
-	su_outb(info, UART_MCR, UART_MCR_LOOP | 0x0A);
-	status1 = serial_in(info, UART_MSR) & 0xF0;
-	su_outb(info, UART_MCR, scratch);
-	su_outb(info, UART_MSR, scratch2);
+#if 0 /* P3: This does not work on MrCoffee. OUT2 is 0x80 - should work... */
+	scratch = serial_inp(info, UART_MCR);
+	serial_outp(info, UART_MCR, UART_MCR_LOOP | scratch);
+	serial_outp(info, UART_MCR, UART_MCR_LOOP | 0x0A);
+	status1 = serial_inp(info, UART_MSR) & 0xF0;
+	serial_outp(info, UART_MCR, scratch);
 	if (status1 != 0x90) {
 		restore_flags(flags);
 		return;
@@ -2273,10 +2303,10 @@
 #endif
 
 	scratch2 = serial_in(info, UART_LCR);
-	su_outb(info, UART_LCR, 0xBF);	/* set up for StarTech test */
-	su_outb(info, UART_EFR, 0);	/* EFR is the same as FCR */
-	su_outb(info, UART_LCR, 0);
-	su_outb(info, UART_FCR, UART_FCR_ENABLE_FIFO);
+	serial_outp(info, UART_LCR, 0xBF);	/* set up for StarTech test */
+	serial_outp(info, UART_EFR, 0);		/* EFR is the same as FCR */
+	serial_outp(info, UART_LCR, 0);
+	serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO);
 	scratch = serial_in(info, UART_IIR) >> 6;
 	switch (scratch) {
 		case 0:
@@ -2294,38 +2324,38 @@
 	}
 	if (info->type == PORT_16550A) {
 		/* Check for Startech UART's */
-		su_outb(info, UART_LCR, scratch2 | UART_LCR_DLAB);
-		if (su_inb(info, UART_EFR) == 0) {
+		serial_outp(info, UART_LCR, scratch2 | UART_LCR_DLAB);
+		if (serial_in(info, UART_EFR) == 0) {
 			info->type = PORT_16650;
 		} else {
-			su_outb(info, UART_LCR, 0xBF);
-			if (su_inb(info, UART_EFR) == 0)
+			serial_outp(info, UART_LCR, 0xBF);
+			if (serial_in(info, UART_EFR) == 0)
 				info->type = PORT_16650V2;
 		}
 	}
 	if (info->type == PORT_16550A) {
 		/* Check for TI 16750 */
-		su_outb(info, UART_LCR, scratch2 | UART_LCR_DLAB);
-		su_outb(info, UART_FCR,
+		serial_outp(info, UART_LCR, scratch2 | UART_LCR_DLAB);
+		serial_outp(info, UART_FCR,
 			    UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
-		scratch = su_inb(info, UART_IIR) >> 5;
+		scratch = serial_in(info, UART_IIR) >> 5;
 		if (scratch == 7) {
-			su_outb(info, UART_LCR, 0);
-			su_outb(info, UART_FCR, UART_FCR_ENABLE_FIFO);
-			scratch = su_inb(info, UART_IIR) >> 5;
+			serial_outp(info, UART_LCR, 0);
+			serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO);
+			scratch = serial_in(info, UART_IIR) >> 5;
 			if (scratch == 6)
 				info->type = PORT_16750;
 		}
-		su_outb(info, UART_FCR, UART_FCR_ENABLE_FIFO);
+		serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO);
 	}
-	su_outb(info, UART_LCR, scratch2);
+	serial_outp(info, UART_LCR, scratch2);
 	if (info->type == PORT_16450) {
-		scratch = su_inb(info, UART_SCR);
-		su_outb(info, UART_SCR, 0xa5);
-		status1 = su_inb(info, UART_SCR);
-		su_outb(info, UART_SCR, 0x5a);
-		status2 = su_inb(info, UART_SCR);
-		su_outb(info, UART_SCR, scratch);
+		scratch = serial_in(info, UART_SCR);
+		serial_outp(info, UART_SCR, 0xa5);
+		status1 = serial_in(info, UART_SCR);
+		serial_outp(info, UART_SCR, 0x5a);
+		status2 = serial_in(info, UART_SCR);
+		serial_outp(info, UART_SCR, scratch);
 
 		if ((status1 != 0xa5) || (status2 != 0x5a))
 			info->type = PORT_8250;
@@ -2349,9 +2379,10 @@
 	/*
 	 * Reset the UART.
 	 */
-	su_outb(info, UART_MCR, 0x00);
-	su_outb(info, UART_FCR, (UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT));
-	su_inb(info, UART_RX);
+	serial_outp(info, UART_MCR, 0x00);
+	serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR|UART_FCR_CLEAR_XMIT));
+	(void)serial_in(info, UART_RX);
+	serial_outp(info, UART_IER, 0x00);
 
 	restore_flags(flags);
 }

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov