#undef DEBUG_HARD
#undef USE_CTRL_O_SYSRQ
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/tty.h>
#include <linux/pmu.h>
#include <linux/bitops.h>
#include <linux/sysrq.h>
+#include <linux/mutex.h>
#include <asm/sections.h>
#include <asm/io.h>
#include <asm/irq.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
*/
static struct uart_pmac_port pmz_ports[MAX_ZS_PORTS];
static int pmz_ports_count;
-static DECLARE_MUTEX(pmz_irq_sem);
+static DEFINE_MUTEX(pmz_irq_mutex);
static struct uart_driver pmz_uart_reg = {
.owner = THIS_MODULE,
.driver_name = "ttyS",
- .devfs_name = "tts/",
.dev_name = "ttyS",
.major = TTY_MAJOR,
};
}
}
-static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap,
- struct pt_regs *regs)
+static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap)
{
struct tty_struct *tty = NULL;
- unsigned char ch, r1, drop, error;
+ unsigned char ch, r1, drop, error, flag;
int loops = 0;
- retry:
/* The interrupt can be enabled when the port isn't open, typically
* that happens when using one port is open and the other closed (stale
* interrupt) or when one port is used as a console.
error = 0;
drop = 0;
- if (unlikely(tty->flip.count >= TTY_FLIPBUF_SIZE)) {
- /* Have to drop the lock here */
- pmz_debug("pmz: flip overflow\n");
- spin_unlock(&uap->port.lock);
- tty->flip.work.func((void *)tty);
- spin_lock(&uap->port.lock);
- if (tty->flip.count >= TTY_FLIPBUF_SIZE)
- drop = 1;
- if (ZS_IS_ASLEEP(uap))
- return NULL;
- if (!ZS_IS_OPEN(uap))
- goto retry;
- }
-
r1 = read_zsreg(uap, R1);
ch = read_zsdata(uap);
if (uap->port.sysrq) {
int swallow;
spin_unlock(&uap->port.lock);
- swallow = uart_handle_sysrq_char(&uap->port, ch, regs);
+ swallow = uart_handle_sysrq_char(&uap->port, ch);
spin_lock(&uap->port.lock);
if (swallow)
goto next_char;
if (drop)
goto next_char;
- *tty->flip.char_buf_ptr = ch;
- *tty->flip.flag_buf_ptr = TTY_NORMAL;
+ flag = TTY_NORMAL;
uap->port.icount.rx++;
if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR | BRK_ABRT)) {
uap->port.icount.overrun++;
r1 &= uap->port.read_status_mask;
if (r1 & BRK_ABRT)
- *tty->flip.flag_buf_ptr = TTY_BREAK;
+ flag = TTY_BREAK;
else if (r1 & PAR_ERR)
- *tty->flip.flag_buf_ptr = TTY_PARITY;
+ flag = TTY_PARITY;
else if (r1 & CRC_ERR)
- *tty->flip.flag_buf_ptr = TTY_FRAME;
+ flag = TTY_FRAME;
}
if (uap->port.ignore_status_mask == 0xff ||
(r1 & uap->port.ignore_status_mask) == 0) {
- tty->flip.flag_buf_ptr++;
- tty->flip.char_buf_ptr++;
- tty->flip.count++;
- }
- if ((r1 & Rx_OVR) &&
- tty->flip.count < TTY_FLIPBUF_SIZE) {
- *tty->flip.flag_buf_ptr = TTY_OVERRUN;
- tty->flip.flag_buf_ptr++;
- tty->flip.char_buf_ptr++;
- tty->flip.count++;
+ tty_insert_flip_char(tty, ch, flag);
}
+ if (r1 & Rx_OVR)
+ tty_insert_flip_char(tty, 0, TTY_OVERRUN);
next_char:
/* We can get stuck in an infinite loop getting char 0 when the
* line is in a wrong HW state, we break that here.
return tty;
}
-static void pmz_status_handle(struct uart_pmac_port *uap, struct pt_regs *regs)
+static void pmz_status_handle(struct uart_pmac_port *uap)
{
unsigned char status;
}
/* Hrm... we register that twice, fixme later.... */
-static irqreturn_t pmz_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t pmz_interrupt(int irq, void *dev_id)
{
struct uart_pmac_port *uap = dev_id;
struct uart_pmac_port *uap_a;
write_zsreg(uap_a, R0, RES_H_IUS);
zssync(uap_a);
if (r3 & CHAEXT)
- pmz_status_handle(uap_a, regs);
+ pmz_status_handle(uap_a);
if (r3 & CHARxIP)
- tty = pmz_receive_chars(uap_a, regs);
+ tty = pmz_receive_chars(uap_a);
if (r3 & CHATxIP)
pmz_transmit_chars(uap_a);
rc = IRQ_HANDLED;
write_zsreg(uap_b, R0, RES_H_IUS);
zssync(uap_b);
if (r3 & CHBEXT)
- pmz_status_handle(uap_b, regs);
+ pmz_status_handle(uap_b);
if (r3 & CHBRxIP)
- tty = pmz_receive_chars(uap_b, regs);
+ tty = pmz_receive_chars(uap_b);
if (r3 & CHBTxIP)
pmz_transmit_chars(uap_b);
rc = IRQ_HANDLED;
/*
* Get Modem Control bits (only the input ones, the core will
* or that with a cached value of the control ones)
- * The port lock is not held.
+ * The port lock is held and interrupts are disabled.
*/
static unsigned int pmz_get_mctrl(struct uart_port *port)
{
if (ZS_IS_ASLEEP(uap) || uap->node == NULL)
return 0;
- status = pmz_peek_status(to_pmz(port));
+ status = read_zsreg(uap, R0);
ret = 0;
if (status & DCD)
/*
* Stop TX side. Dealt like sunzilog at next Tx interrupt,
- * though for DMA, we will have to do a bit more. What is
- * the meaning of the tty_stop bit ? XXX
+ * though for DMA, we will have to do a bit more.
* The port lock is held and interrupts are disabled.
*/
-static void pmz_stop_tx(struct uart_port *port, unsigned int tty_stop)
+static void pmz_stop_tx(struct uart_port *port)
{
to_pmz(port)->flags |= PMACZILOG_FLAG_TX_STOPPED;
}
* Kick the Tx side.
* The port lock is held and interrupts are disabled.
*/
-static void pmz_start_tx(struct uart_port *port, unsigned int tty_start)
+static void pmz_start_tx(struct uart_port *port)
{
struct uart_pmac_port *uap = to_pmz(port);
unsigned char status;
if (uap->node == NULL)
return -ENODEV;
- down(&pmz_irq_sem);
+ mutex_lock(&pmz_irq_mutex);
uap->flags |= PMACZILOG_FLAG_IS_OPEN;
}
pmz_get_port_A(uap)->flags |= PMACZILOG_FLAG_IS_IRQ_ON;
- if (request_irq(uap->port.irq, pmz_interrupt, SA_SHIRQ, "PowerMac Zilog", uap)) {
+ if (request_irq(uap->port.irq, pmz_interrupt, IRQF_SHARED, "PowerMac Zilog", uap)) {
dev_err(&uap->dev->ofdev.dev,
"Unable to register zs interrupt handler.\n");
pmz_set_scc_power(uap, 0);
- up(&pmz_irq_sem);
+ mutex_unlock(&pmz_irq_mutex);
return -ENXIO;
}
- up(&pmz_irq_sem);
+ mutex_unlock(&pmz_irq_mutex);
/* Right now, we deal with delay by blocking here, I'll be
* smarter later on
if (uap->node == NULL)
return;
- down(&pmz_irq_sem);
+ mutex_lock(&pmz_irq_mutex);
/* Release interrupt handler */
free_irq(uap->port.irq, uap);
if (ZS_IS_CONS(uap) || ZS_IS_ASLEEP(uap)) {
spin_unlock_irqrestore(&port->lock, flags);
- up(&pmz_irq_sem);
+ mutex_unlock(&pmz_irq_mutex);
return;
}
spin_unlock_irqrestore(&port->lock, flags);
- up(&pmz_irq_sem);
+ mutex_unlock(&pmz_irq_mutex);
pmz_debug("pmz: shutdown() done.\n");
}
}
-static void __pmz_set_termios(struct uart_port *port, struct termios *termios,
- struct termios *old)
+static void __pmz_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
{
struct uart_pmac_port *uap = to_pmz(port);
unsigned long baud;
if (ZS_IS_ASLEEP(uap))
return;
- memcpy(&uap->termios_cache, termios, sizeof(struct termios));
+ memcpy(&uap->termios_cache, termios, sizeof(struct ktermios));
/* XXX Check which revs of machines actually allow 1 and 4Mb speeds
* on the IR dongle. Note that the IRTTY driver currently doesn't know
}
/* The port lock is not held. */
-static void pmz_set_termios(struct uart_port *port, struct termios *termios,
- struct termios *old)
+static void pmz_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
{
struct uart_pmac_port *uap = to_pmz(port);
unsigned long flags;
static int __init pmz_init_port(struct uart_pmac_port *uap)
{
struct device_node *np = uap->node;
- char *conn;
- struct slot_names_prop {
+ const char *conn;
+ const struct slot_names_prop {
int count;
char name[1];
} *slots;
int len;
+ struct resource r_ports, r_rxdma, r_txdma;
/*
* Request & map chip registers
*/
- uap->port.mapbase = np->addrs[0].address;
+ if (of_address_to_resource(np, 0, &r_ports))
+ return -ENODEV;
+ uap->port.mapbase = r_ports.start;
uap->port.membase = ioremap(uap->port.mapbase, 0x1000);
uap->control_reg = uap->port.membase;
* Request & map DBDMA registers
*/
#ifdef HAS_DBDMA
- if (np->n_addrs >= 3 && np->n_intrs >= 3)
+ if (of_address_to_resource(np, 1, &r_txdma) == 0 &&
+ of_address_to_resource(np, 2, &r_rxdma) == 0)
uap->flags |= PMACZILOG_FLAG_HAS_DMA;
+#else
+ memset(&r_txdma, 0, sizeof(struct resource));
+ memset(&r_rxdma, 0, sizeof(struct resource));
#endif
if (ZS_HAS_DMA(uap)) {
- uap->tx_dma_regs = ioremap(np->addrs[np->n_addrs - 2].address, 0x1000);
+ uap->tx_dma_regs = ioremap(r_txdma.start, 0x100);
if (uap->tx_dma_regs == NULL) {
uap->flags &= ~PMACZILOG_FLAG_HAS_DMA;
goto no_dma;
}
- uap->rx_dma_regs = ioremap(np->addrs[np->n_addrs - 1].address, 0x1000);
+ uap->rx_dma_regs = ioremap(r_rxdma.start, 0x100);
if (uap->rx_dma_regs == NULL) {
iounmap(uap->tx_dma_regs);
uap->tx_dma_regs = NULL;
uap->flags &= ~PMACZILOG_FLAG_HAS_DMA;
goto no_dma;
}
- uap->tx_dma_irq = np->intrs[1].line;
- uap->rx_dma_irq = np->intrs[2].line;
+ uap->tx_dma_irq = irq_of_parse_and_map(np, 1);
+ uap->rx_dma_irq = irq_of_parse_and_map(np, 2);
}
no_dma:
uap->flags |= PMACZILOG_FLAG_IS_IRDA;
uap->port_type = PMAC_SCC_ASYNC;
/* 1999 Powerbook G3 has slot-names property instead */
- slots = (struct slot_names_prop *)get_property(np, "slot-names", &len);
+ slots = get_property(np, "slot-names", &len);
if (slots && slots->count > 0) {
if (strcmp(slots->name, "IrDA") == 0)
uap->flags |= PMACZILOG_FLAG_IS_IRDA;
if (ZS_IS_INTMODEM(uap)) {
struct device_node* i2c_modem = find_devices("i2c-modem");
if (i2c_modem) {
- char* mid = get_property(i2c_modem, "modem-id", NULL);
+ const char* mid =
+ get_property(i2c_modem, "modem-id", NULL);
if (mid) switch(*mid) {
case 0x04 :
case 0x05 :
/*
* Init remaining bits of "port" structure
*/
- uap->port.iotype = SERIAL_IO_MEM;
- uap->port.irq = np->intrs[0].line;
+ uap->port.iotype = UPIO_MEM;
+ uap->port.irq = irq_of_parse_and_map(np, 0);
uap->port.uartclk = ZS_CLOCK;
uap->port.fifosize = 1;
uap->port.ops = &pmz_pops;
/*
* Called upon match with an escc node in the devive-tree.
*/
-static int pmz_attach(struct macio_dev *mdev, const struct of_match *match)
+static int pmz_attach(struct macio_dev *mdev, const struct of_device_id *match)
{
int i;
}
-static int pmz_suspend(struct macio_dev *mdev, u32 pm_state)
+static int pmz_suspend(struct macio_dev *mdev, pm_message_t pm_state)
{
struct uart_pmac_port *uap = dev_get_drvdata(&mdev->ofdev.dev);
struct uart_state *state;
return 0;
}
- if (pm_state == mdev->ofdev.dev.power.power_state || pm_state < 2)
+ if (pm_state.event == mdev->ofdev.dev.power.power_state.event)
return 0;
pmz_debug("suspend, switching to state %d\n", pm_state);
state = pmz_uart_reg.state + uap->port.line;
- down(&pmz_irq_sem);
- down(&state->sem);
+ mutex_lock(&pmz_irq_mutex);
+ mutex_lock(&state->mutex);
spin_lock_irqsave(&uap->port.lock, flags);
/* Shut the chip down */
pmz_set_scc_power(uap, 0);
- up(&state->sem);
- up(&pmz_irq_sem);
+ mutex_unlock(&state->mutex);
+ mutex_unlock(&pmz_irq_mutex);
pmz_debug("suspend, switching complete\n");
if (uap == NULL)
return 0;
- if (mdev->ofdev.dev.power.power_state == 0)
+ if (mdev->ofdev.dev.power.power_state.event == PM_EVENT_ON)
return 0;
pmz_debug("resume, switching to state 0\n");
state = pmz_uart_reg.state + uap->port.line;
- down(&pmz_irq_sem);
- down(&state->sem);
+ mutex_lock(&pmz_irq_mutex);
+ mutex_lock(&state->mutex);
spin_lock_irqsave(&uap->port.lock, flags);
if (!ZS_IS_OPEN(uap) && !ZS_IS_CONS(uap)) {
}
bail:
- up(&state->sem);
- up(&pmz_irq_sem);
+ mutex_unlock(&state->mutex);
+ mutex_unlock(&pmz_irq_mutex);
/* Right now, we deal with delay by blocking here, I'll be
* smarter later on
pmz_debug("resume, switching complete\n");
- mdev->ofdev.dev.power.power_state = 0;
+ mdev->ofdev.dev.power.power_state.event = PM_EVENT_ON;
return 0;
}
return rc;
}
-static struct of_match pmz_match[] =
+static struct of_device_id pmz_match[] =
{
{
.name = "ch-a",
- .type = OF_ANY_MATCH,
- .compatible = OF_ANY_MATCH
},
{
.name = "ch-b",
- .type = OF_ANY_MATCH,
- .compatible = OF_ANY_MATCH
},
{},
};
+MODULE_DEVICE_TABLE (of, pmz_match);
static struct macio_driver pmz_driver =
{
#ifdef CONFIG_SERIAL_PMACZILOG_CONSOLE
+static void pmz_console_putchar(struct uart_port *port, int ch)
+{
+ struct uart_pmac_port *uap = (struct uart_pmac_port *)port;
+
+ /* Wait for the transmit buffer to empty. */
+ while ((read_zsreg(uap, R0) & Tx_BUF_EMP) == 0)
+ udelay(5);
+ write_zsdata(uap, ch);
+}
+
/*
* Print a string to the serial port trying not to disturb
* any possible real use of the port...
{
struct uart_pmac_port *uap = &pmz_ports[con->index];
unsigned long flags;
- int i;
if (ZS_IS_ASLEEP(uap))
return;
write_zsreg(uap, R1, uap->curregs[1] & ~TxINT_ENAB);
write_zsreg(uap, R5, uap->curregs[5] | TxENABLE | RTS | DTR);
- for (i = 0; i < count; i++) {
- /* Wait for the transmit buffer to empty. */
- while ((read_zsreg(uap, R0) & Tx_BUF_EMP) == 0)
- udelay(5);
- write_zsdata(uap, s[i]);
- if (s[i] == 10) {
- while ((read_zsreg(uap, R0) & Tx_BUF_EMP) == 0)
- udelay(5);
- write_zsdata(uap, R13);
- }
- }
+ uart_console_write(&uap->port, s, count, pmz_console_putchar);
/* Restore the values in the registers. */
write_zsreg(uap, R1, uap->curregs[1]);