patch-2.1.97 linux/drivers/macintosh/macserial.c
Next file: linux/drivers/macintosh/mediabay.c
Previous file: linux/drivers/macintosh/mackeymap.c
Back to the patch index
Back to the overall index
- Lines: 609
- Date:
Tue Apr 14 17:33:59 1998
- Orig file:
v2.1.96/linux/drivers/macintosh/macserial.c
- Orig date:
Mon Jan 12 15:18:14 1998
diff -u --recursive --new-file v2.1.96/linux/drivers/macintosh/macserial.c linux/drivers/macintosh/macserial.c
@@ -20,13 +20,21 @@
#include <linux/mm.h>
#include <linux/kernel.h>
#include <linux/delay.h>
+#include <linux/init.h>
+#ifdef CONFIG_SERIAL_CONSOLE
+#include <linux/console.h>
+#endif
#include <asm/io.h>
+#include <asm/pgtable.h>
#include <asm/irq.h>
#include <asm/prom.h>
#include <asm/system.h>
#include <asm/segment.h>
#include <asm/bitops.h>
+#ifdef CONFIG_KGDB
+#include <asm/kgdb.h>
+#endif
#include "macserial.h"
@@ -43,7 +51,6 @@
in the order we want. */
#define RECOVERY_DELAY eieio()
-struct mac_zschannel *zs_kgdbchan;
struct mac_zschannel zs_channels[NUM_CHANNELS];
struct mac_serial zs_soft[NUM_CHANNELS];
@@ -51,31 +58,24 @@
struct mac_serial *zs_chain; /* list of all channels */
struct tty_struct zs_ttys[NUM_CHANNELS];
-/** struct tty_struct *zs_constty; **/
-/* Console hooks... */
-static int zs_cons_chan = 0;
-struct mac_serial *zs_consinfo = 0;
-struct mac_zschannel *zs_conschan;
-
-/*
- * Initialization values for when a channel is used for
- * kernel gdb support.
- */
-static unsigned char kgdb_regs[16] = {
- 0, 0, 0, /* write 0, 1, 2 */
- (Rx8 | RxENABLE), /* write 3 */
- (X16CLK | SB1), /* write 4 */
- (Tx8 | TxENAB | RTS), /* write 5 */
- 0, 0, 0, /* write 6, 7, 8 */
- (NV), /* write 9 */
- (NRZ), /* write 10 */
- (TCBR | RCBR), /* write 11 */
- 1, 0, /* 38400 baud divisor, write 12 + 13 */
- (BRENABL), /* write 14 */
- (DCDIE) /* write 15 */
-};
+#ifdef CONFIG_SERIAL_CONSOLE
+static struct console sercons;
+#endif
+#ifdef CONFIG_KGDB
+struct mac_zschannel *zs_kgdbchan;
+static unsigned char scc_inittab[] = {
+ 9, 0x80, /* reset A side (CHRA) */
+ 13, 0, /* set baud rate divisor */
+ 12, 1,
+ 14, 1, /* baud rate gen enable, src=rtxc (BRENABL) */
+ 11, 0x50, /* clocks = br gen (RCBR | TCBR) */
+ 5, 0x6a, /* tx 8 bits, assert RTS (Tx8 | TxENAB | RTS) */
+ 4, 0x44, /* x16 clock, 1 stop (SB1 | X16CLK)*/
+ 3, 0xc1, /* rx enable, 8 bits (RxENABLE | Rx8)*/
+};
+#endif
#define ZS_CLOCK 3686400 /* Z8530 RTxC input clock rate */
DECLARE_TASK_QUEUE(tq_serial);
@@ -90,8 +90,8 @@
/* number of characters left in xmit buffer before we ask for more */
#define WAKEUP_CHARS 256
-/* Debugging... DEBUG_INTR is bad to use when one of the zs
- * lines is your console ;(
+/*
+ * Debugging.
*/
#undef SERIAL_DEBUG_INTR
#undef SERIAL_DEBUG_OPEN
@@ -233,23 +233,6 @@
return;
}
-static inline void kgdb_chaninit(struct mac_serial *ss, int intson, int bps)
-{
- int brg;
-
- if (intson) {
- kgdb_regs[R1] = INT_ALL_Rx;
- kgdb_regs[R9] |= MIE;
- } else {
- kgdb_regs[R1] = 0;
- kgdb_regs[R9] &= ~MIE;
- }
- brg = BPS_TO_BRG(bps, ZS_CLOCK/16);
- kgdb_regs[R12] = brg;
- kgdb_regs[R13] = brg >> 8;
- load_zsregs(ss->zs_channel, kgdb_regs);
-}
-
/* Utility routines for the Zilog */
static inline int get_zsbaud(struct mac_serial *ss)
{
@@ -300,8 +283,6 @@
mark_bh(SERIAL_BH);
}
-extern void breakpoint(void); /* For the KGDB frame character */
-
static _INLINE_ void receive_chars(struct mac_serial *info,
struct pt_regs *regs)
{
@@ -313,17 +294,13 @@
stat = read_zsreg(info->zs_channel, R1);
ch = read_zsdata(info->zs_channel);
-#if 0 /* KGDB not yet supported */
- /* Look for kgdb 'stop' character, consult the gdb documentation
- * for remote target debugging and arch/sparc/kernel/sparc-stub.c
- * to see how all this works.
- */
- if ((info->kgdb_channel) && (ch =='\003')) {
- breakpoint();
- continue;
+#ifdef CONFIG_KGDB
+ if (info->kgdb_channel) {
+ if (ch == 0x03 || ch == '$')
+ breakpoint();
+ return;
}
#endif
-
if (!tty)
continue;
tty_flip_buffer_push(tty);
@@ -767,93 +744,6 @@
restore_flags(flags);
}
-/* This is for console output over ttya/ttyb */
-static void rs_put_char(char ch)
-{
- struct mac_zschannel *chan = zs_conschan;
- int loops = 0;
- unsigned long flags;
-
- if(!chan)
- return;
-
- save_flags(flags); cli();
- while ((read_zsreg(chan, 0) & Tx_BUF_EMP) == 0)
- if (++loops >= 1000000)
- break;
- write_zsdata(chan, ch);
- restore_flags(flags);
-}
-
-/* These are for receiving and sending characters under the kgdb
- * source level kernel debugger.
- */
-void putDebugChar(char kgdb_char)
-{
- struct mac_zschannel *chan = zs_kgdbchan;
-
- while ((read_zsreg(chan, 0) & Tx_BUF_EMP) == 0)
- udelay(5);
- write_zsdata(chan, kgdb_char);
-}
-
-char getDebugChar(void)
-{
- struct mac_zschannel *chan = zs_kgdbchan;
-
- while ((read_zsreg(chan, 0) & Rx_CH_AV) == 0)
- udelay(5);
- return read_zsdata(chan);
-}
-
-/*
- * Fair output driver allows a process to speak.
- */
-static void rs_fair_output(void)
-{
- int left; /* Output no more than that */
- unsigned long flags;
- struct mac_serial *info = zs_consinfo;
- char c;
-
- if (info == 0) return;
- if (info->xmit_buf == 0) return;
-
- save_flags(flags); cli();
- left = info->xmit_cnt;
- while (left != 0) {
- c = info->xmit_buf[info->xmit_tail];
- info->xmit_tail = (info->xmit_tail+1) & (SERIAL_XMIT_SIZE-1);
- info->xmit_cnt--;
- restore_flags(flags);
-
- rs_put_char(c);
-
- save_flags(flags); cli();
- left = MIN(info->xmit_cnt, left-1);
- }
-
- restore_flags(flags);
- return;
-}
-
-/*
- * zs_console_print is registered for printk.
- */
-static void zs_console_print(const char *p)
-{
- char c;
-
- while ((c = *(p++)) != 0) {
- if (c == '\n')
- rs_put_char('\r');
- rs_put_char(c);
- }
-
- /* Comment this if you want to have a strict interrupt-driven output */
- rs_fair_output();
-}
-
static void rs_flush_chars(struct tty_struct *tty)
{
struct mac_serial *info = (struct mac_serial *)tty->driver_data;
@@ -1204,6 +1094,10 @@
int error;
struct mac_serial * info = (struct mac_serial *)tty->driver_data;
+#ifdef CONFIG_KGDB
+ if (info->kgdb_channel)
+ return -ENODEV;
+#endif
if (serial_paranoia_check(info, tty->device, "rs_ioctl"))
return -ENODEV;
@@ -1340,7 +1234,6 @@
* At this point we stop accepting input. To do this, we
* disable the receiver and receive interrupts.
*/
- /** if (!info->iscons) ... **/
info->curregs[3] &= ~RxENABLE;
info->pendregs[3] = info->curregs[3];
write_zsreg(info->zs_channel, 3, info->curregs[3]);
@@ -1580,9 +1473,10 @@
return -ENODEV;
info = zs_soft + line;
- /* Is the kgdb running over this line? */
+#ifdef CONFIG_KGDB
if (info->kgdb_channel)
return -ENODEV;
+#endif
if (serial_paranoia_check(info, tty->device, "rs_open"))
return -ENODEV;
#ifdef SERIAL_DEBUG_OPEN
@@ -1632,6 +1526,13 @@
*tty->termios = info->callout_termios;
change_speed(info);
}
+#ifdef CONFIG_SERIAL_CONSOLE
+ if (sercons.cflag && sercons.index == line) {
+ tty->termios->c_cflag = sercons.cflag;
+ sercons.cflag = 0;
+ change_speed(info);
+ }
+#endif
info->session = current->session;
info->pgrp = current->pgrp;
@@ -1672,15 +1573,15 @@
continue;
}
zs_channels[n].control = (volatile unsigned char *)
- ch->addrs[0].address;
+ ioremap(ch->addrs[0].address, 0x1000);
zs_channels[n].data = zs_channels[n].control
+ ch->addrs[0].size / 2;
zs_soft[n].zs_channel = &zs_channels[n];
- zs_soft[n].irq = ch->intrs[0];
- if (request_irq(ch->intrs[0], rs_interrupt, 0,
+ zs_soft[n].irq = ch->intrs[0].line;
+ if (request_irq(ch->intrs[0].line, rs_interrupt, 0,
"SCC", &zs_soft[n]))
- panic("macserial: can't get irq %d",
- ch->intrs[0]);
+ printk(KERN_ERR "macserial: can't get irq %d\n",
+ ch->intrs[0].line);
/* XXX this assumes the prom puts chan A before B */
if (n & 1)
zs_soft[n].zs_chan_a = &zs_channels[n-1];
@@ -1769,6 +1670,11 @@
save_flags(flags); cli();
for (channel = 0; channel < zs_channels_found; ++channel) {
+#ifdef CONFIG_KGDB
+ if (zs_soft[channel].kgdb_channel) {
+ continue;
+ }
+#endif
zs_soft[channel].clk_divisor = 16;
zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]);
@@ -1779,17 +1685,15 @@
write_zsreg(zs_soft[channel].zs_channel, R9,
(NV | MIE));
}
- /* If this is the kgdb line, enable interrupts because we
- * now want to receive the 'control-c' character from the
- * client attached to us asynchronously.
- */
- if (zs_soft[channel].kgdb_channel)
- kgdb_chaninit(&zs_soft[channel], 1,
- zs_soft[channel].zs_baud);
}
for (info = zs_chain, i = 0; info; info = info->zs_next, i++)
{
+#ifdef CONFIG_KGDB
+ if (info->kgdb_channel) {
+ continue;
+ }
+#endif
info->magic = SERIAL_MAGIC;
info->port = (int) info->zs_channel->control;
info->line = i;
@@ -1832,84 +1736,212 @@
return;
}
-extern void register_console(void (*proc)(const char *));
+/*
+ * ------------------------------------------------------------
+ * Serial console driver
+ * ------------------------------------------------------------
+ */
+#ifdef CONFIG_SERIAL_CONSOLE
+
/*
- * Initialization values for when a channel is used for
- * a serial console.
+ * Print a string to the serial port trying not to disturb
+ * any possible real use of the port...
*/
-static unsigned char cons_init_regs[16] = {
- 0, 0, 0, /* write 0, 1, 2 */
- (Rx8 | RxENABLE), /* write 3 */
- (X16CLK | SB1), /* write 4 */
- (Tx8 | TxENAB | RTS), /* write 5 */
- 0, 0, 0, /* write 6, 7, 8 */
- 0, /* write 9 */
- (NRZ), /* write 10 */
- (TCBR | RCBR), /* write 11 */
- 1, 0, /* 38400 baud divisor, write 12 + 13 */
- (BRENABL), /* write 14 */
- 0 /* write 15 */
-};
+static void serial_console_write(struct console *co, const char *s,
+ unsigned count)
+{
+}
/*
- * Hooks for running a serial console. con_init() calls this if the
- * console is being run over one of the serial ports.
- * 'channel' is decoded as 1=modem, 2=printer.
+ * Receive character from the serial port
*/
-void
-rs_cons_hook(int chip, int out, int channel)
+static int serial_console_wait_key(struct console *co)
{
- int brg;
+ return 0;
+}
- if (!out)
- return;
- if (zs_consinfo != 0) {
- printk("rs_cons_hook called twice?\n");
- return;
- }
- if (zs_chain == 0)
- probe_sccs();
- --channel;
- if (channel < 0 || channel >= zs_channels_found) {
- printk("rs_cons_hook: channel = %d?\n", channel);
- return;
+static kdev_t serial_console_device(struct console *c)
+{
+ return MKDEV(TTY_MAJOR, 64 + c->index);
+}
+
+/*
+ * Setup initial baud/bits/parity. We do two things here:
+ * - construct a cflag setting for the first rs_open()
+ * - initialize the serial port
+ * Return non-zero if we didn't find a serial port.
+ */
+__initfunc(static int serial_console_setup(struct console *co, char *options))
+{
+ struct serial_state *ser;
+ unsigned cval;
+ int baud = 9600;
+ int bits = 8;
+ int parity = 'n';
+ int cflag = CREAD | HUPCL | CLOCAL;
+ int quot = 0;
+ char *s;
+
+ if (options) {
+ baud = simple_strtoul(options, NULL, 10);
+ s = options;
+ while(*s >= '0' && *s <= '9')
+ s++;
+ if (*s)
+ parity = *s++;
+ if (*s)
+ bits = *s - '0';
}
- zs_cons_chan = channel;
- zs_consinfo = &zs_soft[channel];
- zs_conschan = zs_consinfo->zs_channel;
- zs_consinfo->clk_divisor = 16;
- zs_consinfo->zs_baud = 38400;
- zs_consinfo->is_cons = 1;
-
- memcpy(zs_consinfo->curregs, cons_init_regs, sizeof(cons_init_regs));
- brg = BPS_TO_BRG(zs_consinfo->zs_baud, ZS_CLOCK/16);
- zs_consinfo->curregs[R12] = brg;
- zs_consinfo->curregs[R13] = brg >> 8;
- load_zsregs(zs_conschan, zs_consinfo->curregs);
+ /*
+ * Now construct a cflag setting.
+ */
+ switch(baud) {
+ case 1200:
+ cflag |= B1200;
+ break;
+ case 2400:
+ cflag |= B2400;
+ break;
+ case 4800:
+ cflag |= B4800;
+ break;
+ case 19200:
+ cflag |= B19200;
+ break;
+ case 38400:
+ cflag |= B38400;
+ break;
+ case 57600:
+ cflag |= B57600;
+ break;
+ case 115200:
+ cflag |= B115200;
+ break;
+ case 9600:
+ default:
+ cflag |= B9600;
+ break;
+ }
+ switch(bits) {
+ case 7:
+ cflag |= CS7;
+ break;
+ default:
+ case 8:
+ cflag |= CS8;
+ break;
+ }
+ switch(parity) {
+ case 'o': case 'O':
+ cflag |= PARODD;
+ break;
+ case 'e': case 'E':
+ cflag |= PARENB;
+ break;
+ }
+ co->cflag = cflag;
- register_console(zs_console_print);
- printk("zs%d: console I/O\n", channel);
+ return 0;
}
+static struct console sercons = {
+ "ttyS",
+ serial_console_write,
+ NULL,
+ serial_console_device,
+ serial_console_wait_key,
+ NULL,
+ serial_console_setup,
+ CON_PRINTBUFFER,
+ -1,
+ 0,
+ NULL
+};
+
+/*
+ * Register console.
+ */
+__initfunc (long serial_console_init(long kmem_start, long kmem_end))
+{
+ register_console(&sercons);
+ return kmem_start;
+}
+#endif /* ifdef CONFIG_SERIAL_CONSOLE */
+#ifdef CONFIG_KGDB
+/* These are for receiving and sending characters under the kgdb
+ * source level kernel debugger.
+ */
+void putDebugChar(char kgdb_char)
+{
+ struct mac_zschannel *chan = zs_kgdbchan;
+ while ((read_zsreg(chan, 0) & Tx_BUF_EMP) == 0)
+ udelay(5);
+ write_zsdata(chan, kgdb_char);
+}
+char getDebugChar(void)
+{
+ struct mac_zschannel *chan = zs_kgdbchan;
+ while((read_zsreg(chan, 0) & Rx_CH_AV) == 0)
+ eieio(); /*barrier();*/
+ return read_zsdata(chan);
+}
+void kgdb_interruptible(int yes)
+{
+ struct mac_zschannel *chan = zs_kgdbchan;
+ int one, nine;
+ nine = read_zsreg(chan, 9);
+ if (yes == 1) {
+ one = EXT_INT_ENAB|INT_ALL_Rx;
+ nine |= MIE;
+ printk("turning serial ints on\n");
+ } else {
+ one = RxINT_DISAB;
+ nine &= ~MIE;
+ printk("turning serial ints off\n");
+ }
+ write_zsreg(chan, 1, one);
+ write_zsreg(chan, 9, nine);
+}
+/* This sets up the serial port we're using, and turns on
+ * interrupts for that channel, so kgdb is usable once we're done.
+ */
+static inline void kgdb_chaninit(struct mac_zschannel *ms, int intson, int bps)
+{
+ int brg;
+ int i, x;
+ volatile char *sccc = ms->control;
+ brg = BPS_TO_BRG(bps, ZS_CLOCK/16);
+ printk("setting bps on kgdb line to %d [brg=%x]\n", bps, brg);
+ for (i = 20000; i != 0; --i) {
+ x = *sccc; eieio();
+ }
+ for (i = 0; i < sizeof(scc_inittab); ++i) {
+ write_zsreg(ms, scc_inittab[i], scc_inittab[i+1]);
+ i++;
+ }
+}
/* This is called at boot time to prime the kgdb serial debugging
- * serial line. The 'tty_num' argument is 0 for /dev/ttyS0 and 1
- * for /dev/ttyS1 which is determined in setup_arch() from the
+ * serial line. The 'tty_num' argument is 0 for /dev/ttya and 1
+ * for /dev/ttyb which is determined in setup_arch() from the
* boot command line flags.
*/
-void
-rs_kgdb_hook(int tty_num)
+__initfunc(void zs_kgdb_hook(int tty_num))
{
+ /* Find out how many Z8530 SCCs we have */
if (zs_chain == 0)
probe_sccs();
+ zs_soft[tty_num].zs_channel = &zs_channels[tty_num];
zs_kgdbchan = zs_soft[tty_num].zs_channel;
+ zs_soft[tty_num].change_needed = 0;
zs_soft[tty_num].clk_divisor = 16;
- zs_soft[tty_num].zs_baud = get_zsbaud(&zs_soft[tty_num]);
+ zs_soft[tty_num].zs_baud = 38400;
zs_soft[tty_num].kgdb_channel = 1; /* This runs kgdb */
zs_soft[tty_num ^ 1].kgdb_channel = 0; /* This does not */
/* Turn on transmitter/receiver at 8-bits/char */
- kgdb_chaninit(&zs_soft[tty_num], 0, 9600);
- ZS_CLEARERR(zs_kgdbchan);
- ZS_CLEARFIFO(zs_kgdbchan);
+ kgdb_chaninit(zs_soft[tty_num].zs_channel, 1, 38400);
+ printk("KGDB: on channel %d initialized\n", tty_num);
+ set_debug_traps(); /* init stub */
}
+#endif /* ifdef CONFIG_KGDB */
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov