diff options
Diffstat (limited to 'drivers/tty/serial/pmac_zilog.c')
| -rw-r--r-- | drivers/tty/serial/pmac_zilog.c | 421 | 
1 files changed, 137 insertions, 284 deletions
diff --git a/drivers/tty/serial/pmac_zilog.c b/drivers/tty/serial/pmac_zilog.c index 5acd24a27d0..e9c2dfe471a 100644 --- a/drivers/tty/serial/pmac_zilog.c +++ b/drivers/tty/serial/pmac_zilog.c @@ -99,6 +99,9 @@ MODULE_LICENSE("GPL");  #define PMACZILOG_NAME		"ttyPZ"  #endif +#define pmz_debug(fmt, arg...)	pr_debug("ttyPZ%d: " fmt, uap->port.line, ## arg) +#define pmz_error(fmt, arg...)	pr_err("ttyPZ%d: " fmt, uap->port.line, ## arg) +#define pmz_info(fmt, arg...)	pr_info("ttyPZ%d: " fmt, uap->port.line, ## arg)  /*   * For the sake of early serial console, we can do a pre-probe @@ -106,7 +109,6 @@ MODULE_LICENSE("GPL");   */  static struct uart_pmac_port	pmz_ports[MAX_ZS_PORTS];  static int			pmz_ports_count; -static DEFINE_MUTEX(pmz_irq_mutex);  static struct uart_driver pmz_uart_reg = {  	.owner		=	THIS_MODULE, @@ -126,9 +128,6 @@ static void pmz_load_zsregs(struct uart_pmac_port *uap, u8 *regs)  {  	int i; -	if (ZS_IS_ASLEEP(uap)) -		return; -  	/* Let pending transmits finish.  */  	for (i = 0; i < 1000; i++) {  		unsigned char stat = read_zsreg(uap, R1); @@ -216,32 +215,24 @@ static void pmz_maybe_update_regs(struct uart_pmac_port *uap)  	}  } +static void pmz_interrupt_control(struct uart_pmac_port *uap, int enable) +{ +	if (enable) { +		uap->curregs[1] |= INT_ALL_Rx | TxINT_ENAB; +		if (!ZS_IS_EXTCLK(uap)) +			uap->curregs[1] |= EXT_INT_ENAB; +	} else { +		uap->curregs[1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK); +	} +	write_zsreg(uap, R1, uap->curregs[1]); +} +  static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap)  {  	struct tty_struct *tty = NULL;  	unsigned char ch, r1, drop, error, flag;  	int loops = 0; -	/* 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. -	 */ -	if (!ZS_IS_OPEN(uap)) { -		pmz_debug("pmz: draining input\n"); -		/* Port is closed, drain input data */ -		for (;;) { -			if ((++loops) > 1000) -				goto flood; -			(void)read_zsreg(uap, R1); -			write_zsreg(uap, R0, ERR_RES); -			(void)read_zsdata(uap); -			ch = read_zsreg(uap, R0); -			if (!(ch & Rx_CH_AV)) -				break; -		} -		return NULL; -	} -  	/* Sanity check, make sure the old bug is no longer happening */  	if (uap->port.state == NULL || uap->port.state->port.tty == NULL) {  		WARN_ON(1); @@ -339,9 +330,7 @@ static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap)  	return tty;   flood: -	uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK); -	write_zsreg(uap, R1, uap->curregs[R1]); -	zssync(uap); +	pmz_interrupt_control(uap, 0);  	pmz_error("pmz: rx irq flood !\n");  	return tty;  } @@ -383,8 +372,6 @@ static void pmz_transmit_chars(struct uart_pmac_port *uap)  {  	struct circ_buf *xmit; -	if (ZS_IS_ASLEEP(uap)) -		return;  	if (ZS_IS_CONS(uap)) {  		unsigned char status = read_zsreg(uap, R0); @@ -481,6 +468,10 @@ static irqreturn_t pmz_interrupt(int irq, void *dev_id)  	/* Channel A */  	tty = NULL;  	if (r3 & (CHAEXT | CHATxIP | CHARxIP)) { +		if (!ZS_IS_OPEN(uap_a)) { +			pmz_debug("ChanA interrupt while open !\n"); +			goto skip_a; +		}  		write_zsreg(uap_a, R0, RES_H_IUS);  		zssync(uap_a);		  		if (r3 & CHAEXT) @@ -491,16 +482,21 @@ static irqreturn_t pmz_interrupt(int irq, void *dev_id)  			pmz_transmit_chars(uap_a);  		rc = IRQ_HANDLED;  	} + skip_a:  	spin_unlock(&uap_a->port.lock);  	if (tty != NULL)  		tty_flip_buffer_push(tty); -	if (uap_b->node == NULL) +	if (!uap_b)  		goto out;  	spin_lock(&uap_b->port.lock);  	tty = NULL;  	if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) { +		if (!ZS_IS_OPEN(uap_a)) { +			pmz_debug("ChanB interrupt while open !\n"); +			goto skip_b; +		}  		write_zsreg(uap_b, R0, RES_H_IUS);  		zssync(uap_b);  		if (r3 & CHBEXT) @@ -511,14 +507,12 @@ static irqreturn_t pmz_interrupt(int irq, void *dev_id)  			pmz_transmit_chars(uap_b);  		rc = IRQ_HANDLED;  	} + skip_b:  	spin_unlock(&uap_b->port.lock);  	if (tty != NULL)  		tty_flip_buffer_push(tty);   out: -#ifdef DEBUG_HARD -	pmz_debug("irq done.\n"); -#endif  	return rc;  } @@ -543,12 +537,8 @@ static inline u8 pmz_peek_status(struct uart_pmac_port *uap)   */  static unsigned int pmz_tx_empty(struct uart_port *port)  { -	struct uart_pmac_port *uap = to_pmz(port);  	unsigned char status; -	if (ZS_IS_ASLEEP(uap) || uap->node == NULL) -		return TIOCSER_TEMT; -  	status = pmz_peek_status(to_pmz(port));  	if (status & Tx_BUF_EMP)  		return TIOCSER_TEMT; @@ -570,8 +560,7 @@ static void pmz_set_mctrl(struct uart_port *port, unsigned int mctrl)  	if (ZS_IS_IRDA(uap))  		return;  	/* We get called during boot with a port not up yet */ -	if (ZS_IS_ASLEEP(uap) || -	    !(ZS_IS_OPEN(uap) || ZS_IS_CONS(uap))) +	if (!(ZS_IS_OPEN(uap) || ZS_IS_CONS(uap)))  		return;  	set_bits = clear_bits = 0; @@ -590,8 +579,7 @@ static void pmz_set_mctrl(struct uart_port *port, unsigned int mctrl)  	/* NOTE: Not subject to 'transmitter active' rule.  */   	uap->curregs[R5] |= set_bits;  	uap->curregs[R5] &= ~clear_bits; -	if (ZS_IS_ASLEEP(uap)) -		return; +  	write_zsreg(uap, R5, uap->curregs[R5]);  	pmz_debug("pmz_set_mctrl: set bits: %x, clear bits: %x -> %x\n",  		  set_bits, clear_bits, uap->curregs[R5]); @@ -609,9 +597,6 @@ static unsigned int pmz_get_mctrl(struct uart_port *port)  	unsigned char status;  	unsigned int ret; -	if (ZS_IS_ASLEEP(uap) || uap->node == NULL) -		return 0; -  	status = read_zsreg(uap, R0);  	ret = 0; @@ -649,9 +634,6 @@ static void pmz_start_tx(struct uart_port *port)  	uap->flags |= PMACZILOG_FLAG_TX_ACTIVE;  	uap->flags &= ~PMACZILOG_FLAG_TX_STOPPED; -	if (ZS_IS_ASLEEP(uap) || uap->node == NULL) -		return; -  	status = read_zsreg(uap, R0);  	/* TX busy?  Just wait for the TX done interrupt.  */ @@ -690,9 +672,6 @@ static void pmz_stop_rx(struct uart_port *port)  {  	struct uart_pmac_port *uap = to_pmz(port); -	if (ZS_IS_ASLEEP(uap) || uap->node == NULL) -		return; -  	pmz_debug("pmz: stop_rx()()\n");  	/* Disable all RX interrupts.  */ @@ -711,14 +690,12 @@ static void pmz_enable_ms(struct uart_port *port)  	struct uart_pmac_port *uap = to_pmz(port);  	unsigned char new_reg; -	if (ZS_IS_IRDA(uap) || uap->node == NULL) +	if (ZS_IS_IRDA(uap))  		return;  	new_reg = uap->curregs[R15] | (DCDIE | SYNCIE | CTSIE);  	if (new_reg != uap->curregs[R15]) {  		uap->curregs[R15] = new_reg; -		if (ZS_IS_ASLEEP(uap)) -			return;  		/* NOTE: Not subject to 'transmitter active' rule. */  		write_zsreg(uap, R15, uap->curregs[R15]);  	} @@ -734,8 +711,6 @@ static void pmz_break_ctl(struct uart_port *port, int break_state)  	unsigned char set_bits, clear_bits, new_reg;  	unsigned long flags; -	if (uap->node == NULL) -		return;  	set_bits = clear_bits = 0;  	if (break_state) @@ -748,12 +723,6 @@ static void pmz_break_ctl(struct uart_port *port, int break_state)  	new_reg = (uap->curregs[R5] | set_bits) & ~clear_bits;  	if (new_reg != uap->curregs[R5]) {  		uap->curregs[R5] = new_reg; - -		/* NOTE: Not subject to 'transmitter active' rule. */ -		if (ZS_IS_ASLEEP(uap)) { -			spin_unlock_irqrestore(&port->lock, flags); -			return; -		}  		write_zsreg(uap, R5, uap->curregs[R5]);  	} @@ -927,14 +896,21 @@ static int __pmz_startup(struct uart_pmac_port *uap)  static void pmz_irda_reset(struct uart_pmac_port *uap)  { +	unsigned long flags; + +	spin_lock_irqsave(&uap->port.lock, flags);  	uap->curregs[R5] |= DTR;  	write_zsreg(uap, R5, uap->curregs[R5]);  	zssync(uap); -	mdelay(110); +	spin_unlock_irqrestore(&uap->port.lock, flags); +	msleep(110); + +	spin_lock_irqsave(&uap->port.lock, flags);  	uap->curregs[R5] &= ~DTR;  	write_zsreg(uap, R5, uap->curregs[R5]);  	zssync(uap); -	mdelay(10); +	spin_unlock_irqrestore(&uap->port.lock, flags); +	msleep(10);  }  /* @@ -949,13 +925,6 @@ static int pmz_startup(struct uart_port *port)  	pmz_debug("pmz: startup()\n"); -	if (ZS_IS_ASLEEP(uap)) -		return -EAGAIN; -	if (uap->node == NULL) -		return -ENODEV; - -	mutex_lock(&pmz_irq_mutex); -  	uap->flags |= PMACZILOG_FLAG_IS_OPEN;  	/* A console is never powered down. Else, power up and @@ -966,18 +935,14 @@ static int pmz_startup(struct uart_port *port)  		pwr_delay = __pmz_startup(uap);  		spin_unlock_irqrestore(&port->lock, flags);  	}	 - -	pmz_get_port_A(uap)->flags |= PMACZILOG_FLAG_IS_IRQ_ON; +	sprintf(uap->irq_name, PMACZILOG_NAME"%d", uap->port.line);  	if (request_irq(uap->port.irq, pmz_interrupt, IRQF_SHARED, -			"SCC", uap)) { +			uap->irq_name, uap)) {  		pmz_error("Unable to register zs interrupt handler.\n");  		pmz_set_scc_power(uap, 0); -		mutex_unlock(&pmz_irq_mutex);  		return -ENXIO;  	} -	mutex_unlock(&pmz_irq_mutex); -  	/* Right now, we deal with delay by blocking here, I'll be  	 * smarter later on  	 */ @@ -990,12 +955,9 @@ static int pmz_startup(struct uart_port *port)  	if (ZS_IS_IRDA(uap))  		pmz_irda_reset(uap); -	/* Enable interrupts emission from the chip */ +	/* Enable interrupt requests for the channel */  	spin_lock_irqsave(&port->lock, flags); -	uap->curregs[R1] |= INT_ALL_Rx | TxINT_ENAB; -	if (!ZS_IS_EXTCLK(uap)) -		uap->curregs[R1] |= EXT_INT_ENAB; -	write_zsreg(uap, R1, uap->curregs[R1]); +	pmz_interrupt_control(uap, 1);  	spin_unlock_irqrestore(&port->lock, flags);  	pmz_debug("pmz: startup() done.\n"); @@ -1010,49 +972,35 @@ static void pmz_shutdown(struct uart_port *port)  	pmz_debug("pmz: shutdown()\n"); -	if (uap->node == NULL) -		return; - -	mutex_lock(&pmz_irq_mutex); - -	/* Release interrupt handler */ -	free_irq(uap->port.irq, uap); -  	spin_lock_irqsave(&port->lock, flags); -	uap->flags &= ~PMACZILOG_FLAG_IS_OPEN; +	/* Disable interrupt requests for the channel */ +	pmz_interrupt_control(uap, 0); -	if (!ZS_IS_OPEN(uap->mate)) -		pmz_get_port_A(uap)->flags &= ~PMACZILOG_FLAG_IS_IRQ_ON; +	if (!ZS_IS_CONS(uap)) { +		/* Disable receiver and transmitter */ +		uap->curregs[R3] &= ~RxENABLE; +		uap->curregs[R5] &= ~TxENABLE; -	/* Disable interrupts */ -	if (!ZS_IS_ASLEEP(uap)) { -		uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK); -		write_zsreg(uap, R1, uap->curregs[R1]); -		zssync(uap); +		/* Disable break assertion */ +		uap->curregs[R5] &= ~SND_BRK; +		pmz_maybe_update_regs(uap);  	} -	if (ZS_IS_CONS(uap) || ZS_IS_ASLEEP(uap)) { -		spin_unlock_irqrestore(&port->lock, flags); -		mutex_unlock(&pmz_irq_mutex); -		return; -	} +	spin_unlock_irqrestore(&port->lock, flags); + +	/* Release interrupt handler */ +	free_irq(uap->port.irq, uap); -	/* Disable receiver and transmitter.  */ -	uap->curregs[R3] &= ~RxENABLE; -	uap->curregs[R5] &= ~TxENABLE; +	spin_lock_irqsave(&port->lock, flags); -	/* Disable all interrupts and BRK assertion.  */ -	uap->curregs[R5] &= ~SND_BRK; -	pmz_maybe_update_regs(uap); +	uap->flags &= ~PMACZILOG_FLAG_IS_OPEN; -	/* Shut the chip down */ -	pmz_set_scc_power(uap, 0); +	if (!ZS_IS_CONS(uap)) +		pmz_set_scc_power(uap, 0);	/* Shut the chip down */  	spin_unlock_irqrestore(&port->lock, flags); -	mutex_unlock(&pmz_irq_mutex); -  	pmz_debug("pmz: shutdown() done.\n");  } @@ -1300,9 +1248,6 @@ static void __pmz_set_termios(struct uart_port *port, struct ktermios *termios,  	pmz_debug("pmz: set_termios()\n"); -	if (ZS_IS_ASLEEP(uap)) -		return; -  	memcpy(&uap->termios_cache, termios, sizeof(struct ktermios));  	/* XXX Check which revs of machines actually allow 1 and 4Mb speeds @@ -1352,19 +1297,15 @@ static void pmz_set_termios(struct uart_port *port, struct ktermios *termios,  	spin_lock_irqsave(&port->lock, flags);	  	/* Disable IRQs on the port */ -	uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK); -	write_zsreg(uap, R1, uap->curregs[R1]); +	pmz_interrupt_control(uap, 0);  	/* Setup new port configuration */  	__pmz_set_termios(port, termios, old);  	/* Re-enable IRQs on the port */ -	if (ZS_IS_OPEN(uap)) { -		uap->curregs[R1] |= INT_ALL_Rx | TxINT_ENAB; -		if (!ZS_IS_EXTCLK(uap)) -			uap->curregs[R1] |= EXT_INT_ENAB; -		write_zsreg(uap, R1, uap->curregs[R1]); -	} +	if (ZS_IS_OPEN(uap)) +		pmz_interrupt_control(uap, 1); +  	spin_unlock_irqrestore(&port->lock, flags);  } @@ -1604,25 +1545,34 @@ static void pmz_dispose_port(struct uart_pmac_port *uap)   */  static int pmz_attach(struct macio_dev *mdev, const struct of_device_id *match)  { +	struct uart_pmac_port *uap;  	int i;  	/* Iterate the pmz_ports array to find a matching entry  	 */  	for (i = 0; i < MAX_ZS_PORTS; i++) -		if (pmz_ports[i].node == mdev->ofdev.dev.of_node) { -			struct uart_pmac_port *uap = &pmz_ports[i]; +		if (pmz_ports[i].node == mdev->ofdev.dev.of_node) +			break; +	if (i >= MAX_ZS_PORTS) +		return -ENODEV; -			uap->dev = mdev; -			dev_set_drvdata(&mdev->ofdev.dev, uap); -			if (macio_request_resources(uap->dev, "pmac_zilog")) -				printk(KERN_WARNING "%s: Failed to request resource" -				       ", port still active\n", -				       uap->node->name); -			else -				uap->flags |= PMACZILOG_FLAG_RSRC_REQUESTED;				 -			return 0; -		} -	return -ENODEV; + +	uap = &pmz_ports[i]; +	uap->dev = mdev; +	uap->port.dev = &mdev->ofdev.dev; +	dev_set_drvdata(&mdev->ofdev.dev, uap); + +	/* We still activate the port even when failing to request resources +	 * to work around bugs in ancient Apple device-trees +	 */ +	if (macio_request_resources(uap->dev, "pmac_zilog")) +		printk(KERN_WARNING "%s: Failed to request resource" +		       ", port still active\n", +		       uap->node->name); +	else +		uap->flags |= PMACZILOG_FLAG_RSRC_REQUESTED; + +	return uart_add_one_port(&pmz_uart_reg, &uap->port);  }  /* @@ -1636,12 +1586,15 @@ static int pmz_detach(struct macio_dev *mdev)  	if (!uap)  		return -ENODEV; +	uart_remove_one_port(&pmz_uart_reg, &uap->port); +  	if (uap->flags & PMACZILOG_FLAG_RSRC_REQUESTED) {  		macio_release_resources(uap->dev);  		uap->flags &= ~PMACZILOG_FLAG_RSRC_REQUESTED;  	}  	dev_set_drvdata(&mdev->ofdev.dev, NULL);  	uap->dev = NULL; +	uap->port.dev = NULL;  	return 0;  } @@ -1650,59 +1603,13 @@ static int pmz_detach(struct macio_dev *mdev)  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; -	unsigned long flags;  	if (uap == NULL) {  		printk("HRM... pmz_suspend with NULL uap\n");  		return 0;  	} -	if (pm_state.event == mdev->ofdev.dev.power.power_state.event) -		return 0; - -	pmz_debug("suspend, switching to state %d\n", pm_state.event); - -	state = pmz_uart_reg.state + uap->port.line; - -	mutex_lock(&pmz_irq_mutex); -	mutex_lock(&state->port.mutex); - -	spin_lock_irqsave(&uap->port.lock, flags); - -	if (ZS_IS_OPEN(uap) || ZS_IS_CONS(uap)) { -		/* Disable receiver and transmitter.  */ -		uap->curregs[R3] &= ~RxENABLE; -		uap->curregs[R5] &= ~TxENABLE; - -		/* Disable all interrupts and BRK assertion.  */ -		uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK); -		uap->curregs[R5] &= ~SND_BRK; -		pmz_load_zsregs(uap, uap->curregs); -		uap->flags |= PMACZILOG_FLAG_IS_ASLEEP; -		mb(); -	} - -	spin_unlock_irqrestore(&uap->port.lock, flags); - -	if (ZS_IS_OPEN(uap) || ZS_IS_OPEN(uap->mate)) -		if (ZS_IS_ASLEEP(uap->mate) && ZS_IS_IRQ_ON(pmz_get_port_A(uap))) { -			pmz_get_port_A(uap)->flags &= ~PMACZILOG_FLAG_IS_IRQ_ON; -			disable_irq(uap->port.irq); -		} - -	if (ZS_IS_CONS(uap)) -		uap->port.cons->flags &= ~CON_ENABLED; - -	/* Shut the chip down */ -	pmz_set_scc_power(uap, 0); - -	mutex_unlock(&state->port.mutex); -	mutex_unlock(&pmz_irq_mutex); - -	pmz_debug("suspend, switching complete\n"); - -	mdev->ofdev.dev.power.power_state = pm_state; +	uart_suspend_port(&pmz_uart_reg, &uap->port);  	return 0;  } @@ -1711,76 +1618,20 @@ static int pmz_suspend(struct macio_dev *mdev, pm_message_t pm_state)  static int pmz_resume(struct macio_dev *mdev)  {  	struct uart_pmac_port *uap = dev_get_drvdata(&mdev->ofdev.dev); -	struct uart_state *state; -	unsigned long flags; -	int pwr_delay = 0;  	if (uap == NULL)  		return 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; - -	mutex_lock(&pmz_irq_mutex); -	mutex_lock(&state->port.mutex); - -	spin_lock_irqsave(&uap->port.lock, flags); -	if (!ZS_IS_OPEN(uap) && !ZS_IS_CONS(uap)) { -		spin_unlock_irqrestore(&uap->port.lock, flags); -		goto bail; -	} -	pwr_delay = __pmz_startup(uap); - -	/* Take care of config that may have changed while asleep */ -	__pmz_set_termios(&uap->port, &uap->termios_cache, NULL); - -	if (ZS_IS_OPEN(uap)) { -		/* Enable interrupts */		 -		uap->curregs[R1] |= INT_ALL_Rx | TxINT_ENAB; -		if (!ZS_IS_EXTCLK(uap)) -			uap->curregs[R1] |= EXT_INT_ENAB; -		write_zsreg(uap, R1, uap->curregs[R1]); -	} - -	spin_unlock_irqrestore(&uap->port.lock, flags); - -	if (ZS_IS_CONS(uap)) -		uap->port.cons->flags |= CON_ENABLED; - -	/* Re-enable IRQ on the controller */ -	if (ZS_IS_OPEN(uap) && !ZS_IS_IRQ_ON(pmz_get_port_A(uap))) { -		pmz_get_port_A(uap)->flags |= PMACZILOG_FLAG_IS_IRQ_ON; -		enable_irq(uap->port.irq); -	} - - bail: -	mutex_unlock(&state->port.mutex); -	mutex_unlock(&pmz_irq_mutex); - -	/* Right now, we deal with delay by blocking here, I'll be -	 * smarter later on -	 */ -	if (pwr_delay != 0) { -		pmz_debug("pmz: delaying %d ms\n", pwr_delay); -		msleep(pwr_delay); -	} - -	pmz_debug("resume, switching complete\n"); - -	mdev->ofdev.dev.power.power_state.event = PM_EVENT_ON; +	uart_resume_port(&pmz_uart_reg, &uap->port);  	return 0;  }  /*   * Probe all ports in the system and build the ports array, we register - * with the serial layer at this point, the macio-type probing is only - * used later to "attach" to the sysfs tree so we get power management - * events + * with the serial layer later, so we get a proper struct device which + * allows the tty to attach properly. This is later than it used to be + * but the tty layer really wants it that way.   */  static int __init pmz_probe(void)  { @@ -1816,8 +1667,10 @@ static int __init pmz_probe(void)  		/*  		 * Fill basic fields in the port structures  		 */ -		pmz_ports[count].mate		= &pmz_ports[count+1]; -		pmz_ports[count+1].mate		= &pmz_ports[count]; +		if (node_b != NULL) { +			pmz_ports[count].mate		= &pmz_ports[count+1]; +			pmz_ports[count+1].mate		= &pmz_ports[count]; +		}  		pmz_ports[count].flags		= PMACZILOG_FLAG_IS_CHANNEL_A;  		pmz_ports[count].node		= node_a;  		pmz_ports[count+1].node		= node_b; @@ -1855,8 +1708,8 @@ static int __init pmz_init_port(struct uart_pmac_port *uap)  	struct resource *r_ports;  	int irq; -	r_ports = platform_get_resource(uap->node, IORESOURCE_MEM, 0); -	irq = platform_get_irq(uap->node, 0); +	r_ports = platform_get_resource(uap->pdev, IORESOURCE_MEM, 0); +	irq = platform_get_irq(uap->pdev, 0);  	if (!r_ports || !irq)  		return -ENODEV; @@ -1885,19 +1738,19 @@ static int __init pmz_probe(void)  	pmz_ports_count = 0; -	pmz_ports[0].mate      = &pmz_ports[1];  	pmz_ports[0].port.line = 0;  	pmz_ports[0].flags     = PMACZILOG_FLAG_IS_CHANNEL_A; -	pmz_ports[0].node      = &scc_a_pdev; +	pmz_ports[0].pdev      = &scc_a_pdev;  	err = pmz_init_port(&pmz_ports[0]);  	if (err)  		return err;  	pmz_ports_count++; +	pmz_ports[0].mate      = &pmz_ports[1];  	pmz_ports[1].mate      = &pmz_ports[0];  	pmz_ports[1].port.line = 1;  	pmz_ports[1].flags     = 0; -	pmz_ports[1].node      = &scc_b_pdev; +	pmz_ports[1].pdev      = &scc_b_pdev;  	err = pmz_init_port(&pmz_ports[1]);  	if (err)  		return err; @@ -1913,16 +1766,35 @@ static void pmz_dispose_port(struct uart_pmac_port *uap)  static int __init pmz_attach(struct platform_device *pdev)  { +	struct uart_pmac_port *uap;  	int i; +	/* Iterate the pmz_ports array to find a matching entry */  	for (i = 0; i < pmz_ports_count; i++) -		if (pmz_ports[i].node == pdev) -			return 0; -	return -ENODEV; +		if (pmz_ports[i].pdev == pdev) +			break; +	if (i >= pmz_ports_count) +		return -ENODEV; + +	uap = &pmz_ports[i]; +	uap->port.dev = &pdev->dev; +	platform_set_drvdata(pdev, uap); + +	return uart_add_one_port(&pmz_uart_reg, &uap->port);  }  static int __exit pmz_detach(struct platform_device *pdev)  { +	struct uart_pmac_port *uap = platform_get_drvdata(pdev); + +	if (!uap) +		return -ENODEV; + +	uart_remove_one_port(&pmz_uart_reg, &uap->port); + +	platform_set_drvdata(pdev, NULL); +	uap->port.dev = NULL; +  	return 0;  } @@ -1954,38 +1826,13 @@ static struct console pmz_console = {   */  static int __init pmz_register(void)  { -	int i, rc; -	  	pmz_uart_reg.nr = pmz_ports_count;  	pmz_uart_reg.cons = PMACZILOG_CONSOLE;  	/*  	 * Register this driver with the serial core  	 */ -	rc = uart_register_driver(&pmz_uart_reg); -	if (rc) -		return rc; - -	/* -	 * Register each port with the serial core -	 */ -	for (i = 0; i < pmz_ports_count; i++) { -		struct uart_pmac_port *uport = &pmz_ports[i]; -		/* NULL node may happen on wallstreet */ -		if (uport->node != NULL) -			rc = uart_add_one_port(&pmz_uart_reg, &uport->port); -		if (rc) -			goto err_out; -	} - -	return 0; -err_out: -	while (i-- > 0) { -		struct uart_pmac_port *uport = &pmz_ports[i]; -		uart_remove_one_port(&pmz_uart_reg, &uport->port); -	} -	uart_unregister_driver(&pmz_uart_reg); -	return rc; +	return uart_register_driver(&pmz_uart_reg);  }  #ifdef CONFIG_PPC_PMAC @@ -2084,10 +1931,13 @@ static void __exit exit_pmz(void)  	for (i = 0; i < pmz_ports_count; i++) {  		struct uart_pmac_port *uport = &pmz_ports[i]; -		if (uport->node != NULL) { -			uart_remove_one_port(&pmz_uart_reg, &uport->port); +#ifdef CONFIG_PPC_PMAC +		if (uport->node != NULL)  			pmz_dispose_port(uport); -		} +#else +		if (uport->pdev != NULL) +			pmz_dispose_port(uport); +#endif  	}  	/* Unregister UART driver */  	uart_unregister_driver(&pmz_uart_reg); @@ -2114,8 +1964,6 @@ static void pmz_console_write(struct console *con, const char *s, unsigned int c  	struct uart_pmac_port *uap = &pmz_ports[con->index];  	unsigned long flags; -	if (ZS_IS_ASLEEP(uap)) -		return;  	spin_lock_irqsave(&uap->port.lock, flags);  	/* Turn of interrupts and enable the transmitter. */ @@ -2160,8 +2008,13 @@ static int __init pmz_console_setup(struct console *co, char *options)  	if (co->index >= pmz_ports_count)  		co->index = 0;  	uap = &pmz_ports[co->index]; +#ifdef CONFIG_PPC_PMAC  	if (uap->node == NULL)  		return -ENODEV; +#else +	if (uap->pdev == NULL) +		return -ENODEV; +#endif  	port = &uap->port;  	/*  |