patch-2.1.129 linux/drivers/macintosh/macserial.c

Next file: linux/drivers/macintosh/macserial.h
Previous file: linux/drivers/macintosh/macio-adb.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.128/linux/drivers/macintosh/macserial.c linux/drivers/macintosh/macserial.c
@@ -33,6 +33,7 @@
 #include <asm/system.h>
 #include <asm/segment.h>
 #include <asm/bitops.h>
+#include <asm/feature.h>
 #ifdef CONFIG_KGDB
 #include <asm/kgdb.h>
 #endif
@@ -165,25 +166,35 @@
 				       unsigned char reg)
 {
 	unsigned char retval;
+	unsigned long flags;
 
+	/*
+	 * We have to make this atomic.
+	 */
+	spin_lock_irqsave(&channel->lock, flags);
 	if (reg != 0) {
 		*channel->control = reg;
 		RECOVERY_DELAY;
 	}
 	retval = *channel->control;
 	RECOVERY_DELAY;
+	spin_unlock_irqrestore(&channel->lock, flags);
 	return retval;
 }
 
 static inline void write_zsreg(struct mac_zschannel *channel,
 			       unsigned char reg, unsigned char value)
 {
+	unsigned long flags;
+
+	spin_lock_irqsave(&channel->lock, flags);
 	if (reg != 0) {
 		*channel->control = reg;
 		RECOVERY_DELAY;
 	}
 	*channel->control = value;
 	RECOVERY_DELAY;
+	spin_unlock_irqrestore(&channel->lock, flags);
 	return;
 }
 
@@ -434,6 +445,10 @@
 
 	for (;;) {
 		zs_intreg = read_zsreg(info->zs_chan_a, 3) >> shift;
+#ifdef SERIAL_DEBUG_INTR
+//		printk("rs_interrupt: irq %d, zs_intreg 0x%x\n", irq, (int)zs_intreg);
+#endif	
+
 		if ((zs_intreg & CHAN_IRQMASK) == 0)
 			break;
 
@@ -1261,6 +1276,15 @@
 	tty->closing = 0;
 	info->event = 0;
 	info->tty = 0;
+
+	if (info->is_cobalt_modem) {
+		/* Power down modem */
+		feature_set(info->dev_node, FEATURE_Modem_Reset);
+		mdelay(15);
+		feature_clear(info->dev_node, FEATURE_Modem_PowerOn);
+		mdelay(15);
+	}
+
 	if (info->blocked_open) {
 		if (info->close_delay) {
 			current->state = TASK_INTERRUPTIBLE;
@@ -1271,6 +1295,7 @@
 	info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CALLOUT_ACTIVE|
 			 ZILOG_CLOSING);
 	wake_up_interruptible(&info->close_wait);
+	
 	restore_flags(flags);
 }
 
@@ -1508,9 +1533,25 @@
 	/*
 	 * Start up serial port
 	 */
+
+	if (info->is_cobalt_modem) {
+		/* Power up modem */
+		feature_set(info->dev_node, FEATURE_Modem_PowerOn);
+		mdelay(250);
+		feature_clear(info->dev_node, FEATURE_Modem_Reset);
+		mdelay(10);
+	}
 	retval = startup(info);
-	if (retval)
+	if (retval) {
+		if (info->is_cobalt_modem) {
+			/* Power down modem */
+			feature_set(info->dev_node, FEATURE_Modem_Reset);
+			mdelay(15);
+			feature_clear(info->dev_node, FEATURE_Modem_PowerOn);
+			mdelay(15);
+		}
 		return retval;
+	}
 
 	retval = block_til_ready(tty, filp, info);
 	if (retval) {
@@ -1518,6 +1559,13 @@
 		printk("rs_open returning after block_til_ready with %d\n",
 		       retval);
 #endif
+		if (info->is_cobalt_modem) {
+			/* Power down modem */
+			feature_set(info->dev_node, FEATURE_Modem_Reset);
+			mdelay(15);
+			feature_clear(info->dev_node, FEATURE_Modem_PowerOn);
+			mdelay(15);
+		}
 		return retval;
 	}
 
@@ -1568,8 +1616,14 @@
 			       dev->full_name);
 			continue;
 		}
+		feature_clear(dev, FEATURE_Serial_reset);
+		mdelay(5);
+		feature_set(dev, FEATURE_Serial_enable);
+		feature_set(dev, FEATURE_Serial_IO_A);
+		feature_set(dev, FEATURE_Serial_IO_B);
+		mdelay(5);
 		for (ch = dev->child; ch != 0; ch = ch->sibling) {
-			if (ch->n_addrs < 1 || ch ->n_intrs < 1) {
+			if (ch->n_addrs < 1 || (ch ->n_intrs < 1)) {
 				printk("Can't use %s: %d addrs %d intrs\n",
 				      ch->full_name, ch->n_addrs, ch->n_intrs);
 				continue;
@@ -1578,8 +1632,20 @@
 				ioremap(ch->addrs[0].address, 0x1000);
 			zs_channels[n].data = zs_channels[n].control
 				+ ch->addrs[0].size / 2;
+			spin_lock_init(&zs_channels[n].lock);
 			zs_soft[n].zs_channel = &zs_channels[n];
+			zs_soft[n].dev_node = ch;
 			zs_soft[n].irq = ch->intrs[0].line;
+			zs_soft[n].is_cobalt_modem = device_is_compatible(ch, "cobalt");
+			if (zs_soft[n].is_cobalt_modem)
+			{
+				/* Just in case the modem is up, shut it down */
+				feature_set(ch, FEATURE_Modem_Reset);
+				mdelay(15);
+				feature_clear(ch, FEATURE_Modem_PowerOn);
+				mdelay(15);
+			}
+
 			/* XXX this assumes the prom puts chan A before B */
 			if (n & 1)
 				zs_soft[n].zs_chan_a = &zs_channels[n-1];
@@ -1696,6 +1762,9 @@
 
 	for (info = zs_chain, i = 0; info; info = info->zs_next, i++)
 	{
+		unsigned char* connector;
+		int lenp;
+
 #ifdef CONFIG_KGDB
 		if (info->kgdb_channel) {
 			continue;
@@ -1719,8 +1788,14 @@
 		info->open_wait = 0;
 		info->close_wait = 0;
 		printk("tty%02d at 0x%08x (irq = %d)", info->line, 
-		       info->port, info->irq);
-		printk(" is a Z8530 ESCC\n");
+			info->port, info->irq);
+		printk(" is a Z8530 ESCC");
+		connector = get_property(info->dev_node, "AAPL,connector", &lenp);
+		if (connector)
+			printk(", port = %s", connector);
+		if (info->is_cobalt_modem)
+			printk(" (cobalt modem)");
+		printk("\n");
 	}
 
 	restore_flags(flags);

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