* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
+ * 2004-08-06 Harald Welte <laforge@gnumonks.org>
+ * - Enable BREAK interrupt
+ * - Add support for sysreq
+ *
* TODO: - Add DMA support
* - Defer port shutdown to a few seconds after close
* - maybe put something right into uap->clk_divisor
#undef DEBUG
#undef DEBUG_HARD
+#undef USE_CTRL_O_SYSRQ
#include <linux/config.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/adb.h>
#include <linux/pmu.h>
+#include <linux/bitops.h>
+#include <linux/sysrq.h>
#include <asm/sections.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/prom.h>
-#include <asm/bitops.h>
#include <asm/machdep.h>
#include <asm/pmac_feature.h>
#include <asm/dbdma.h>
#include <asm/macio.h>
#include <asm/semaphore.h>
+#if defined (CONFIG_SERIAL_PMACZILOG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
#include <linux/serial.h>
#include <linux/serial_core.h>
}
ch &= uap->parity_mask;
- if (ch == 0 && uap->prev_status & BRK_ABRT)
- r1 |= BRK_ABRT;
+ if (ch == 0 && uap->flags & PMACZILOG_FLAG_BREAK) {
+ uap->flags &= ~PMACZILOG_FLAG_BREAK;
+ }
+
+#if defined(CONFIG_MAGIC_SYSRQ) && defined(CONFIG_SERIAL_CORE_CONSOLE)
+#ifdef USE_CTRL_O_SYSRQ
+ /* Handle the SysRq ^O Hack */
+ if (ch == '\x0f') {
+ uap->port.sysrq = jiffies + HZ*5;
+ goto next_char;
+ }
+#endif /* USE_CTRL_O_SYSRQ */
+ if (uap->port.sysrq) {
+ int swallow;
+ spin_unlock(&uap->port.lock);
+ swallow = uart_handle_sysrq_char(&uap->port, ch, regs);
+ spin_lock(&uap->port.lock);
+ if (swallow)
+ goto next_char;
+ }
+#endif /* CONFIG_MAGIC_SYSRQ && CONFIG_SERIAL_CORE_CONSOLE */
/* A real serial line, record the character and status. */
if (drop)
pmz_debug("pmz: got break !\n");
r1 &= ~(PAR_ERR | CRC_ERR);
uap->port.icount.brk++;
- if (uart_handle_break(&uap->port)) {
- pmz_debug("pmz: do handle break !\n");
+ if (uart_handle_break(&uap->port))
goto next_char;
- }
}
else if (r1 & PAR_ERR)
uap->port.icount.parity++;
else if (r1 & CRC_ERR)
*tty->flip.flag_buf_ptr = TTY_FRAME;
}
- if (uart_handle_sysrq_char(&uap->port, ch, regs)) {
- pmz_debug("pmz: sysrq swallowed the char\n");
- goto next_char;
- }
if (uap->port.ignore_status_mask == 0xff ||
(r1 & uap->port.ignore_status_mask) == 0) {
wake_up_interruptible(&uap->port.info->delta_msr_wait);
}
+ if (status & BRK_ABRT)
+ uap->flags |= PMACZILOG_FLAG_BREAK;
+
uap->prev_status = status;
}
uap->curregs[R13] = 0;
uap->curregs[R14] = BRENAB;
- /* Clear handshaking */
- uap->curregs[R15] = 0;
+ /* Clear handshaking, enable BREAK interrupts */
+ uap->curregs[R15] = BRKIE;
/* Master interrupt enable */
uap->curregs[R9] |= NV | MIE;
*/
if (pwr_delay != 0) {
pmz_debug("pmz: delaying %d ms\n", pwr_delay);
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout((pwr_delay * HZ)/1000);
+ msleep(pwr_delay);
}
/* IrDA reset is done now */
/* Load registers to the chip */
pmz_maybe_update_regs(uap);
}
+ uart_update_timeout(port, termios->c_cflag, baud);
+
pmz_debug("pmz: set_termios() done.\n");
}
uap->port.mapbase = np->addrs[0].address;
uap->port.membase = ioremap(uap->port.mapbase, 0x1000);
- uap->control_reg = (volatile u8 *)uap->port.membase;
+ uap->control_reg = uap->port.membase;
uap->data_reg = uap->control_reg + 0x10;
/*
uap->flags |= PMACZILOG_FLAG_HAS_DMA;
#endif
if (ZS_HAS_DMA(uap)) {
- uap->tx_dma_regs = (volatile struct dbdma_regs *)
- ioremap(np->addrs[np->n_addrs - 2].address, 0x1000);
+ uap->tx_dma_regs = ioremap(np->addrs[np->n_addrs - 2].address, 0x1000);
if (uap->tx_dma_regs == NULL) {
uap->flags &= ~PMACZILOG_FLAG_HAS_DMA;
goto no_dma;
}
- uap->rx_dma_regs = (volatile struct dbdma_regs *)
- ioremap(np->addrs[np->n_addrs - 1].address, 0x1000);
+ uap->rx_dma_regs = ioremap(np->addrs[np->n_addrs - 1].address, 0x1000);
if (uap->rx_dma_regs == NULL) {
- iounmap((void *)uap->tx_dma_regs);
+ iounmap(uap->tx_dma_regs);
uap->tx_dma_regs = NULL;
uap->flags &= ~PMACZILOG_FLAG_HAS_DMA;
goto no_dma;
struct device_node *np;
np = uap->node;
- iounmap((void *)uap->rx_dma_regs);
- iounmap((void *)uap->tx_dma_regs);
- iounmap((void *)uap->control_reg);
+ iounmap(uap->rx_dma_regs);
+ iounmap(uap->tx_dma_regs);
+ iounmap(uap->control_reg);
uap->node = NULL;
of_node_put(np);
memset(uap, 0, sizeof(struct uart_pmac_port));
return 0;
}
- if (pm_state == mdev->ofdev.dev.power_state || pm_state < 2)
+ if (pm_state == mdev->ofdev.dev.power.power_state || pm_state < 2)
return 0;
pmz_debug("suspend, switching to state %d\n", pm_state);
pmz_debug("suspend, switching complete\n");
- mdev->ofdev.dev.power_state = pm_state;
+ mdev->ofdev.dev.power.power_state = pm_state;
return 0;
}
if (uap == NULL)
return 0;
- if (mdev->ofdev.dev.power_state == 0)
+ if (mdev->ofdev.dev.power.power_state == 0)
return 0;
pmz_debug("resume, switching to state 0\n");
*/
if (pwr_delay != 0) {
pmz_debug("pmz: delaying %d ms\n", pwr_delay);
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout((pwr_delay * HZ)/1000);
+ msleep(pwr_delay);
}
pmz_debug("resume, switching complete\n");
- mdev->ofdev.dev.power_state = 0;
+ mdev->ofdev.dev.power.power_state = 0;
return 0;
}
unsigned long flags;
int i;
+ if (ZS_IS_ASLEEP(uap))
+ return;
spin_lock_irqsave(&uap->port.lock, flags);
/* Turn of interrupts and enable the transmitter. */