patch-2.2.18 linux/drivers/macintosh/macserial.c
Next file: linux/drivers/macintosh/macserial.h
Previous file: linux/drivers/macintosh/mac_keyb.c
Back to the patch index
Back to the overall index
- Lines: 209
- Date:
Wed Nov 8 23:00:34 2000
- Orig file:
v2.2.17/drivers/macintosh/macserial.c
- Orig date:
Sat Sep 9 18:42:38 2000
diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/macintosh/macserial.c linux/drivers/macintosh/macserial.c
@@ -953,6 +953,67 @@
info->dma_initted = 1;
}
+/*
+ * FixZeroBug....Works around a bug in the SCC receving channel.
+ * Taken from Darwin code, 15 Sept. 2000 -DanM
+ *
+ * The following sequence prevents a problem that is seen with O'Hare ASICs
+ * (most versions -- also with some Heathrow and Hydra ASICs) where a zero
+ * at the input to the receiver becomes 'stuck' and locks up the receiver.
+ * This problem can occur as a result of a zero bit at the receiver input
+ * coincident with any of the following events:
+ *
+ * The SCC is initialized (hardware or software).
+ * A framing error is detected.
+ * The clocking option changes from synchronous or X1 asynchronous
+ * clocking to X16, X32, or X64 asynchronous clocking.
+ * The decoding mode is changed among NRZ, NRZI, FM0, or FM1.
+ *
+ * This workaround attempts to recover from the lockup condition by placing
+ * the SCC in synchronous loopback mode with a fast clock before programming
+ * any of the asynchronous modes.
+ */
+static void fix_zero_bug_scc(struct mac_serial * info)
+{
+ write_zsreg(info->zs_channel, 9,
+ (info->zs_channel == info->zs_chan_a? CHRA: CHRB));
+ udelay(10);
+ write_zsreg(info->zs_channel, 9,
+ ((info->zs_channel == info->zs_chan_a? CHRA: CHRB) | NV));
+
+ write_zsreg(info->zs_channel, 4, (X1CLK | EXTSYNC));
+
+ /* I think this is wrong....but, I just copying code....
+ */
+ write_zsreg(info->zs_channel, 3, (8 & ~RxENABLE));
+
+ write_zsreg(info->zs_channel, 5, (8 & ~TxENAB));
+ write_zsreg(info->zs_channel, 9, NV); /* Didn't we already do this? */
+ write_zsreg(info->zs_channel, 11, (RCBR | TCBR));
+ write_zsreg(info->zs_channel, 12, 0);
+ write_zsreg(info->zs_channel, 13, 0);
+ write_zsreg(info->zs_channel, 14, (LOOPBAK | SSBR));
+ write_zsreg(info->zs_channel, 14, (LOOPBAK | SSBR | BRENABL));
+ write_zsreg(info->zs_channel, 3, (8 | RxENABLE));
+ write_zsreg(info->zs_channel, 0, RES_EXT_INT);
+ write_zsreg(info->zs_channel, 0, RES_EXT_INT); /* to kill some time */
+
+ /* The channel should be OK now, but it is probably receiving
+ * loopback garbage.
+ * Switch to asynchronous mode, disable the receiver,
+ * and discard everything in the receive buffer.
+ */
+ write_zsreg(info->zs_channel, 9, NV);
+ write_zsreg(info->zs_channel, 4, PAR_ENA);
+ write_zsreg(info->zs_channel, 3, (8 & ~RxENABLE));
+
+ while (read_zsreg(info->zs_channel, 0) & Rx_CH_AV) {
+ (void)read_zsreg(info->zs_channel, 8);
+ write_zsreg(info->zs_channel, 0, RES_EXT_INT);
+ write_zsreg(info->zs_channel, 0, ERR_RES);
+ }
+}
+
static int setup_scc(struct mac_serial * info)
{
unsigned long flags;
@@ -961,6 +1022,9 @@
save_flags(flags); cli(); /* Disable interrupts */
+ /* Nice buggy HW ... */
+ fix_zero_bug_scc(info);
+
/*
* Reset the chip.
*/
@@ -1081,7 +1145,7 @@
info->curregs[5] &= ~TxENAB;
if (!info->tty || C_HUPCL(info->tty))
- info->curregs[5] &= ~(DTR | RTS);
+ info->curregs[5] &= ~DTR;
info->pendregs[5] = info->curregs[5];
write_zsreg(info->zs_channel, 5, info->curregs[5]);
@@ -1253,7 +1317,7 @@
/* assert DTR, wait 30ms, talk to the chip */
write_zsreg(info->zs_channel, 5, Tx8 | TxENAB | RTS | DTR);
- udelay(30000);
+ mdelay(30);
while (read_zsreg(info->zs_channel, 0) & Rx_CH_AV)
read_zsdata(info->zs_channel);
@@ -1592,17 +1656,35 @@
if (C_CRTSCTS(tty)) {
/*
* Here we want to turn off the RTS line. On Macintoshes,
- * we only get the DTR line, which goes to both DTR and
- * RTS on the modem. RTS doesn't go out to the serial
- * port socket. So you should make sure your modem is
- * set to ignore DTR if you're using CRTSCTS.
+ * the external serial ports using a DIN-8 or DIN-9
+ * connector only have the DTR line (which is usually
+ * wired to both RTS and DTR on an external modem in
+ * the cable). RTS doesn't go out to the serial port
+ * socket, it acts as an output enable for the transmit
+ * data line. So in this case we don't drop RTS.
+ *
+ * Macs with internal modems generally do have both RTS
+ * and DTR wired to the modem, so in that case we do
+ * drop RTS.
*/
+ if (info->is_internal_modem) {
+ save_flags(flags); cli();
+ info->curregs[5] &= ~RTS;
+ info->pendregs[5] &= ~RTS;
+ write_zsreg(info->zs_channel, 5, info->curregs[5]);
+ restore_flags(flags);
+ }
+ }
+
+#ifdef CDTRCTS
+ if (tty->termios->c_cflag & CDTRCTS) {
save_flags(flags); cli();
- info->curregs[5] &= ~(DTR | RTS);
- info->pendregs[5] &= ~(DTR | RTS);
+ info->curregs[5] &= ~DTR;
+ info->pendregs[5] &= ~DTR;
write_zsreg(info->zs_channel, 5, info->curregs[5]);
restore_flags(flags);
}
+#endif /* CDTRCTS */
}
static void rs_unthrottle(struct tty_struct * tty)
@@ -1629,14 +1711,25 @@
restore_flags(flags);
}
- if (C_CRTSCTS(tty)) {
- /* Assert RTS and DTR lines */
+ if (C_CRTSCTS(tty) && info->is_internal_modem) {
+ /* Assert RTS line */
save_flags(flags); cli();
- info->curregs[5] |= DTR | RTS;
- info->pendregs[5] |= DTR | RTS;
+ info->curregs[5] |= RTS;
+ info->pendregs[5] |= RTS;
write_zsreg(info->zs_channel, 5, info->curregs[5]);
restore_flags(flags);
}
+
+#ifdef CDTRCTS
+ if (tty->termios->c_cflag & CDTRCTS) {
+ /* Assert DTR line */
+ save_flags(flags); cli();
+ info->curregs[5] |= DTR;
+ info->pendregs[5] |= DTR;
+ write_zsreg(info->zs_channel, 5, info->curregs[5]);
+ restore_flags(flags);
+ }
+#endif
}
/*
@@ -2311,6 +2404,7 @@
/* setup misc varariables */
zss->kgdb_channel = 0;
zss->is_cobalt_modem = device_is_compatible(ch, "cobalt");
+ zss->is_internal_modem = zss->is_cobalt_modem;
/* XXX tested only with wallstreet PowerBook,
should do no harm anyway */
@@ -2318,8 +2412,12 @@
zss->is_irda = conn && (strcmp(conn, "infrared") == 0);
/* 1999 Powerbook G3 has slot-names property instead */
slots = (struct slot_names_prop *)get_property(ch, "slot-names", &len);
- if (slots && slots->count > 0 && strcmp(slots->name, "IrDA") == 0)
- zss->is_irda = 1;
+ if (slots && slots->count > 0) {
+ if (strcmp(slots->name, "IrDA") == 0)
+ zss->is_irda = 1;
+ else if (strcmp(slots->name, "Modem") == 0)
+ zss->is_internal_modem = 1;
+ }
if (zss->has_dma) {
zss->dma_priv = NULL;
@@ -2560,6 +2658,8 @@
printk(", port = %s", connector);
if (info->is_cobalt_modem)
printk(" (cobalt modem)");
+ else if (info->is_internal_modem)
+ printk(" (internal modem)");
if (info->is_irda)
printk(" (IrDA)");
printk("\n");
@@ -2898,7 +2998,7 @@
/*
* Register console.
*/
-__initfunc (long serial_console_init(long kmem_start, long kmem_end))
+__initfunc (long mac_scc_console_init(long kmem_start, long kmem_end))
{
register_console(&sercons);
return kmem_start;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)