/* * Print a string to the serial port trying not to disturb * any possible real use of the port... */ static void pmz_console_write(struct console *con, const char *s, unsigned int count) { struct uart_pmac_port *uap = &pmz_ports[con->index]; unsigned long flags; int i; spin_lock_irqsave(&uap->port.lock, flags); /* Turn of interrupts and enable the transmitter. */ 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); } } /* Restore the values in the registers. */ write_zsreg(uap, R1, uap->curregs[1]); /* Don't disable the transmitter. */ spin_unlock_irqrestore(&uap->port.lock, flags); }
static void z8530_dma_rx(struct z8530_channel *chan) { if(chan->rxdma_on) { /* Special condition check only */ u8 status; read_zsreg(chan, R7); read_zsreg(chan, R6); status=read_zsreg(chan, R1); if(status&END_FR) { z8530_rx_done(chan); /* Fire up the next one */ } write_zsctrl(chan, ERR_RES); write_zsctrl(chan, RES_H_IUS); } else { /* DMA is off right now, drain the slow way */ z8530_rx(chan); } }
static void pmz_status_handle(struct uart_pmac_port *uap) { unsigned char status; status = read_zsreg(uap, R0); write_zsreg(uap, R0, RES_EXT_INT); zssync(uap); if (ZS_IS_OPEN(uap) && ZS_WANTS_MODEM_STATUS(uap)) { if (status & SYNC_HUNT) uap->port.icount.dsr++; /* The Zilog just gives us an interrupt when DCD/CTS/etc. change. * But it does not tell us which bit has changed, we have to keep * track of this ourselves. * The CTS input is inverted for some reason. -- paulus */ if ((status ^ uap->prev_status) & DCD) uart_handle_dcd_change(&uap->port, (status & DCD)); if ((status ^ uap->prev_status) & CTS) uart_handle_cts_change(&uap->port, !(status & CTS)); wake_up_interruptible(&uap->port.info->delta_msr_wait); } if (status & BRK_ABRT) uap->flags |= PMACZILOG_FLAG_BREAK; uap->prev_status = status; }
static void z8530_status(struct z8530_channel *chan) { u8 status, altered; status = read_zsreg(chan, R0); altered = chan->status ^ status; chan->status = status; if (status & TxEOM) { /* printk("%s: Tx underrun.\n", chan->dev->name); */ chan->netdevice->stats.tx_fifo_errors++; write_zsctrl(chan, ERR_RES); z8530_tx_done(chan); } if (altered & chan->dcdcheck) { if (status & chan->dcdcheck) { printk(KERN_INFO "%s: DCD raised\n", chan->dev->name); write_zsreg(chan, R3, chan->regs[3] | RxENABLE); if (chan->netdevice) netif_carrier_on(chan->netdevice); } else { printk(KERN_INFO "%s: DCD lost\n", chan->dev->name); write_zsreg(chan, R3, chan->regs[3] & ~RxENABLE); z8530_flush_fifo(chan); if (chan->netdevice) netif_carrier_off(chan->netdevice); } } write_zsctrl(chan, RES_EXT_INT); write_zsctrl(chan, RES_H_IUS); }
static void z8530_tx(struct z8530_channel *c) { while(c->txcount) { /* FIFO full ? */ if(!(read_zsreg(c, R0)&4)) return; c->txcount--; /* * Shovel out the byte */ write_zsreg(c, R8, *c->tx_ptr++); write_zsctrl(c, RES_H_IUS); /* We are about to underflow */ if(c->txcount==0) { write_zsctrl(c, RES_EOM_L); write_zsreg(c, R10, c->regs[10]&~ABUNDER); } } /* * End of frame TX - fire another one */ write_zsctrl(c, RES_Tx_P); z8530_tx_done(c); write_zsctrl(c, RES_H_IUS); }
int z8530_channel_load(struct z8530_channel *c, u8 *rtable) { unsigned long flags; spin_lock_irqsave(c->lock, flags); while(*rtable!=255) { int reg=*rtable++; if(reg>0x0F) write_zsreg(c, R15, c->regs[15]|1); write_zsreg(c, reg&0x0F, *rtable); if(reg>0x0F) write_zsreg(c, R15, c->regs[15]&~1); c->regs[reg]=*rtable++; } c->rx_function=z8530_null_rx; c->skb=NULL; c->tx_skb=NULL; c->tx_next_skb=NULL; c->mtu=1500; c->max=0; c->count=0; c->status=read_zsreg(c, R0); c->sync=1; write_zsreg(c, R3, c->regs[R3]|RxENABLE); spin_unlock_irqrestore(c->lock, flags); return 0; }
static irqreturn_t ip22zilog_interrupt(int irq, void *dev_id) { struct uart_ip22zilog_port *up = dev_id; while (up) { struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(&up->port); unsigned char r3; bool push = false; spin_lock(&up->port.lock); r3 = read_zsreg(channel, R3); /* Channel A */ if (r3 & (CHAEXT | CHATxIP | CHARxIP)) { writeb(RES_H_IUS, &channel->control); ZSDELAY(); ZS_WSYNC(channel); if (r3 & CHARxIP) push = ip22zilog_receive_chars(up, channel); if (r3 & CHAEXT) ip22zilog_status_handle(up, channel); if (r3 & CHATxIP) ip22zilog_transmit_chars(up, channel); } spin_unlock(&up->port.lock); if (push) tty_flip_buffer_push(&up->port.state->port); /* Channel B */ up = up->next; channel = ZILOG_CHANNEL_FROM_PORT(&up->port); push = false; spin_lock(&up->port.lock); if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) { writeb(RES_H_IUS, &channel->control); ZSDELAY(); ZS_WSYNC(channel); if (r3 & CHBRxIP) push = ip22zilog_receive_chars(up, channel); if (r3 & CHBEXT) ip22zilog_status_handle(up, channel); if (r3 & CHBTxIP) ip22zilog_transmit_chars(up, channel); } spin_unlock(&up->port.lock); if (push) tty_flip_buffer_push(&up->port.state->port); up = up->next; } return IRQ_HANDLED; }
static void z8530_status_clear(struct z8530_channel *chan) { u8 status=read_zsreg(chan, R0); if(status&TxEOM) write_zsctrl(chan, ERR_RES); write_zsctrl(chan, RES_EXT_INT); write_zsctrl(chan, RES_H_IUS); }
/* Return !=0 iff no more characters in Tx FIFO */ static int asdg_trans_empty(struct async_struct *info) { #ifdef DEBUG printk("asdg_trans_empty"); #endif return read_zsreg((struct SCCHalf *)info->port, R1) & ALL_SNT; }
int z8530_sync_dma_close(struct net_device *dev, struct z8530_channel *c) { u8 chk; unsigned long flags; c->irqs = &z8530_nop; c->max = 0; c->sync = 0; /* * Disable the PC DMA channels */ flags=claim_dma_lock(); disable_dma(c->rxdma); clear_dma_ff(c->rxdma); c->rxdma_on = 0; disable_dma(c->txdma); clear_dma_ff(c->txdma); release_dma_lock(flags); c->txdma_on = 0; c->tx_dma_used = 0; spin_lock_irqsave(c->lock, flags); /* * Disable DMA control mode */ c->regs[R1]&= ~WT_RDY_ENAB; write_zsreg(c, R1, c->regs[R1]); c->regs[R1]&= ~(WT_RDY_RT|WT_FN_RDYFN|INT_ERR_Rx); c->regs[R1]|= INT_ALL_Rx; write_zsreg(c, R1, c->regs[R1]); c->regs[R14]&= ~DTRREQ; write_zsreg(c, R14, c->regs[R14]); if(c->rx_buf[0]) { free_page((unsigned long)c->rx_buf[0]); c->rx_buf[0]=NULL; } if(c->tx_dma_buf[0]) { free_page((unsigned long)c->tx_dma_buf[0]); c->tx_dma_buf[0]=NULL; } chk=read_zsreg(c,R0); write_zsreg(c, R3, c->regs[R3]); z8530_rtsdtr(c,0); spin_unlock_irqrestore(c->lock, flags); return 0; }
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); }
/* * Real startup routine, powers up the hardware and sets up * the SCC. Returns a delay in ms where you need to wait before * actually using the port, this is typically the internal modem * powerup delay. This routine expect the lock to be taken. */ static int __pmz_startup(struct uart_pmac_port *uap) { int pwr_delay = 0; memset(&uap->curregs, 0, sizeof(uap->curregs)); /* Power up the SCC & underlying hardware (modem/irda) */ pwr_delay = pmz_set_scc_power(uap, 1); /* Nice buggy HW ... */ pmz_fix_zero_bug_scc(uap); /* Reset the channel */ uap->curregs[R9] = 0; write_zsreg(uap, 9, ZS_IS_CHANNEL_A(uap) ? CHRA : CHRB); zssync(uap); udelay(10); write_zsreg(uap, 9, 0); zssync(uap); /* Clear the interrupt registers */ write_zsreg(uap, R1, 0); write_zsreg(uap, R0, ERR_RES); write_zsreg(uap, R0, ERR_RES); write_zsreg(uap, R0, RES_H_IUS); write_zsreg(uap, R0, RES_H_IUS); /* Setup some valid baud rate */ uap->curregs[R4] = X16CLK | SB1; uap->curregs[R3] = Rx8; uap->curregs[R5] = Tx8 | RTS; if (!ZS_IS_IRDA(uap)) uap->curregs[R5] |= DTR; uap->curregs[R12] = 0; uap->curregs[R13] = 0; uap->curregs[R14] = BRENAB; /* Clear handshaking, enable BREAK interrupts */ uap->curregs[R15] = BRKIE; /* Master interrupt enable */ uap->curregs[R9] |= NV | MIE; pmz_load_zsregs(uap, uap->curregs); /* Enable receiver and transmitter. */ write_zsreg(uap, R3, uap->curregs[R3] |= RxENABLE); write_zsreg(uap, R5, uap->curregs[R5] |= TxENABLE); /* Remember status for DCD/CTS changes */ uap->prev_status = read_zsreg(uap, R0); return pwr_delay; }
/* * Peek the status register, lock not held by caller */ static inline u8 pmz_peek_status(struct uart_pmac_port *uap) { unsigned long flags; u8 status; spin_lock_irqsave(&uap->port.lock, flags); status = read_zsreg(uap, R0); spin_unlock_irqrestore(&uap->port.lock, flags); return status; }
static void z8530_flush_fifo(struct z8530_channel *c) { read_zsreg(c, R1); read_zsreg(c, R1); read_zsreg(c, R1); read_zsreg(c, R1); if(c->dev->type==Z85230) { read_zsreg(c, R1); read_zsreg(c, R1); read_zsreg(c, R1); read_zsreg(c, R1); } }
/* * FixZeroBug....Works around a bug in the SCC receving channel. * Inspired 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 pmz_fix_zero_bug_scc(struct uart_pmac_port *uap) { write_zsreg(uap, 9, ZS_IS_CHANNEL_A(uap) ? CHRA : CHRB); zssync(uap); udelay(10); write_zsreg(uap, 9, (ZS_IS_CHANNEL_A(uap) ? CHRA : CHRB) | NV); zssync(uap); write_zsreg(uap, 4, X1CLK | MONSYNC); write_zsreg(uap, 3, Rx8); write_zsreg(uap, 5, Tx8 | RTS); write_zsreg(uap, 9, NV); /* Didn't we already do this? */ write_zsreg(uap, 11, RCBR | TCBR); write_zsreg(uap, 12, 0); write_zsreg(uap, 13, 0); write_zsreg(uap, 14, (LOOPBAK | BRSRC)); write_zsreg(uap, 14, (LOOPBAK | BRSRC | BRENAB)); write_zsreg(uap, 3, Rx8 | RxENABLE); write_zsreg(uap, 0, RES_EXT_INT); write_zsreg(uap, 0, RES_EXT_INT); write_zsreg(uap, 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(uap, 9, NV); write_zsreg(uap, 4, X16CLK | SB_MASK); write_zsreg(uap, 3, Rx8); while (read_zsreg(uap, 0) & Rx_CH_AV) { (void)read_zsreg(uap, 8); write_zsreg(uap, 0, RES_EXT_INT); write_zsreg(uap, 0, ERR_RES); } }
static unsigned int asdg_get_modem_info(struct async_struct *info) { u_char status=read_zsreg((struct SCCHalf *)info->port, R0); #ifdef DEBUG printk("asdg_get_modem_info\n"); #endif return( ( (info->MCR & MCR_DTR) ? TIOCM_DTR : 0) | ( (info->MCR & MCR_RTS) ? TIOCM_RTS : 0) | ( (status & DCD) ? TIOCM_CAR : 0) | ( (status & CTS) ? 0 : TIOCM_CTS) | /* TICM_RNG */ 0); }
static void z8530_dma_status(struct z8530_channel *chan) { u8 status, altered; status=read_zsreg(chan, R0); altered=chan->status^status; chan->status=status; if(chan->dma_tx) { if(status&TxEOM) { unsigned long flags; flags=claim_dma_lock(); disable_dma(chan->txdma); clear_dma_ff(chan->txdma); chan->txdma_on=0; release_dma_lock(flags); z8530_tx_done(chan); } } if(altered&chan->dcdcheck) { if(status&chan->dcdcheck) { printk(KERN_INFO "%s: DCD raised\n", chan->dev->name); write_zsreg(chan, R3, chan->regs[3]|RxENABLE); if(chan->netdevice && ((chan->netdevice->type == ARPHRD_HDLC) || (chan->netdevice->type == ARPHRD_PPP))) sppp_reopen(chan->netdevice); } else { printk(KERN_INFO "%s:DCD lost\n", chan->dev->name); write_zsreg(chan, R3, chan->regs[3]&~RxENABLE); z8530_flush_fifo(chan); } } write_zsctrl(chan, RES_EXT_INT); write_zsctrl(chan, RES_H_IUS); }
int z8530_sync_close(struct net_device *dev, struct z8530_channel *c) { u8 chk; unsigned long flags; spin_lock_irqsave(c->lock, flags); c->irqs = &z8530_nop; c->max = 0; c->sync = 0; chk=read_zsreg(c,R0); write_zsreg(c, R3, c->regs[R3]); z8530_rtsdtr(c,0); spin_unlock_irqrestore(c->lock, flags); return 0; }
static void z8530_rx_clear(struct z8530_channel *c) { /* * Data and status bytes */ u8 stat; read_zsdata(c); stat=read_zsreg(c, R1); if(stat&END_FR) write_zsctrl(c, RES_Rx_CRC); /* * Clear irq */ write_zsctrl(c, ERR_RES); write_zsctrl(c, RES_H_IUS); }
/* * 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 held and interrupts are disabled. */ static unsigned int pmz_get_mctrl(struct uart_port *port) { struct uart_pmac_port *uap = to_pmz(port); unsigned char status; unsigned int ret; if (ZS_IS_ASLEEP(uap) || uap->node == NULL) return 0; status = read_zsreg(uap, R0); ret = 0; if (status & DCD) ret |= TIOCM_CAR; if (status & SYNC_HUNT) ret |= TIOCM_DSR; if (!(status & CTS)) ret |= TIOCM_CTS; return ret; }
/* * Kick the Tx side. * The port lock is held and interrupts are disabled. */ static void pmz_start_tx(struct uart_port *port) { struct uart_pmac_port *uap = to_pmz(port); unsigned char status; pmz_debug("pmz: start_tx()\n"); 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. */ if (!(status & Tx_BUF_EMP)) return; /* Send the first character to jump-start the TX done * IRQ sending engine. */ if (port->x_char) { write_zsdata(uap, port->x_char); zssync(uap); port->icount.tx++; port->x_char = 0; } else { struct circ_buf *xmit = &port->info->xmit; write_zsdata(uap, xmit->buf[xmit->tail]); zssync(uap); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); port->icount.tx++; if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(&uap->port); } pmz_debug("pmz: start_tx() done.\n"); }
static void __init ip22zilog_init_hw(void) { int i; for (i = 0; i < NUM_CHANNELS; i++) { struct uart_ip22zilog_port *up = &ip22zilog_port_table[i]; struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(&up->port); unsigned long flags; int baud, brg; spin_lock_irqsave(&up->port.lock, flags); if (ZS_IS_CHANNEL_A(up)) { write_zsreg(channel, R9, FHWRES); ZSDELAY_LONG(); (void) read_zsreg(channel, R0); } /* Normal serial TTY. */ up->parity_mask = 0xff; up->curregs[R1] = EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB; up->curregs[R4] = PAR_EVEN | X16CLK | SB1; up->curregs[R3] = RxENAB | Rx8; up->curregs[R5] = TxENAB | Tx8; up->curregs[R9] = NV | MIE; up->curregs[R10] = NRZ; up->curregs[R11] = TCBR | RCBR; baud = 9600; brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR); up->curregs[R12] = (brg & 0xff); up->curregs[R13] = (brg >> 8) & 0xff; up->curregs[R14] = BRENAB; __load_zsregs(channel, up->curregs); /* set master interrupt enable */ write_zsreg(channel, R9, up->curregs[R9]); spin_unlock_irqrestore(&up->port.lock, flags); } }
static void ip22zilog_clear_fifo(struct zilog_channel *channel) { int i; for (i = 0; i < 32; i++) { unsigned char regval; regval = readb(&channel->control); ZSDELAY(); if (regval & Rx_CH_AV) break; regval = read_zsreg(channel, R1); readb(&channel->data); ZSDELAY(); if (regval & (PAR_ERR | Rx_OVR | CRC_ERR)) { writeb(ERR_RES, &channel->control); ZSDELAY(); ZS_WSYNC(channel); } } }
/* * Set the irda codec on the imac to the specified baud rate. */ static void pmz_irda_setup(struct uart_pmac_port *uap, unsigned long *baud) { u8 cmdbyte; int t, version; switch (*baud) { /* SIR modes */ case 2400: cmdbyte = 0x53; break; case 4800: cmdbyte = 0x52; break; case 9600: cmdbyte = 0x51; break; case 19200: cmdbyte = 0x50; break; case 38400: cmdbyte = 0x4f; break; case 57600: cmdbyte = 0x4e; break; case 115200: cmdbyte = 0x4d; break; /* The FIR modes aren't really supported at this point, how * do we select the speed ? via the FCR on KeyLargo ? */ case 1152000: cmdbyte = 0; break; case 4000000: cmdbyte = 0; break; default: /* 9600 */ cmdbyte = 0x51; *baud = 9600; break; } /* Wait for transmitter to drain */ t = 10000; while ((read_zsreg(uap, R0) & Tx_BUF_EMP) == 0 || (read_zsreg(uap, R1) & ALL_SNT) == 0) { if (--t <= 0) { dev_err(&uap->dev->ofdev.dev, "transmitter didn't drain\n"); return; } udelay(10); } /* Drain the receiver too */ t = 100; (void)read_zsdata(uap); (void)read_zsdata(uap); (void)read_zsdata(uap); mdelay(10); while (read_zsreg(uap, R0) & Rx_CH_AV) { read_zsdata(uap); mdelay(10); if (--t <= 0) { dev_err(&uap->dev->ofdev.dev, "receiver didn't drain\n"); return; } } /* Switch to command mode */ uap->curregs[R5] |= DTR; write_zsreg(uap, R5, uap->curregs[R5]); zssync(uap); mdelay(1); /* Switch SCC to 19200 */ pmz_convert_to_zs(uap, CS8, 0, 19200); pmz_load_zsregs(uap, uap->curregs); mdelay(1); /* Write get_version command byte */ write_zsdata(uap, 1); t = 5000; while ((read_zsreg(uap, R0) & Rx_CH_AV) == 0) { if (--t <= 0) { dev_err(&uap->dev->ofdev.dev, "irda_setup timed out on get_version byte\n"); goto out; } udelay(10); } version = read_zsdata(uap); if (version < 4) { dev_info(&uap->dev->ofdev.dev, "IrDA: dongle version %d not supported\n", version); goto out; } /* Send speed mode */ write_zsdata(uap, cmdbyte); t = 5000; while ((read_zsreg(uap, R0) & Rx_CH_AV) == 0) { if (--t <= 0) { dev_err(&uap->dev->ofdev.dev, "irda_setup timed out on speed mode byte\n"); goto out; } udelay(10); } t = read_zsdata(uap); if (t != cmdbyte) dev_err(&uap->dev->ofdev.dev, "irda_setup speed mode byte = %x (%x)\n", t, cmdbyte); dev_info(&uap->dev->ofdev.dev, "IrDA setup for %ld bps, dongle version: %d\n", *baud, version); (void)read_zsdata(uap); (void)read_zsdata(uap); (void)read_zsdata(uap); out: /* Switch back to data mode */ uap->curregs[R5] &= ~DTR; write_zsreg(uap, R5, uap->curregs[R5]); zssync(uap); (void)read_zsdata(uap); (void)read_zsdata(uap); (void)read_zsdata(uap); }
static bool ip22zilog_receive_chars(struct uart_ip22zilog_port *up, struct zilog_channel *channel) { unsigned char ch, flag; unsigned int r1; bool push = up->port.state != NULL; for (;;) { ch = readb(&channel->control); ZSDELAY(); if (!(ch & Rx_CH_AV)) break; r1 = read_zsreg(channel, R1); if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR)) { writeb(ERR_RES, &channel->control); ZSDELAY(); ZS_WSYNC(channel); } ch = readb(&channel->data); ZSDELAY(); ch &= up->parity_mask; /* Handle the null char got when BREAK is removed. */ if (!ch) r1 |= up->tty_break; /* A real serial line, record the character and status. */ flag = TTY_NORMAL; up->port.icount.rx++; if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR | Rx_SYS | Rx_BRK)) { up->tty_break = 0; if (r1 & (Rx_SYS | Rx_BRK)) { up->port.icount.brk++; if (r1 & Rx_SYS) continue; r1 &= ~(PAR_ERR | CRC_ERR); } else if (r1 & PAR_ERR) up->port.icount.parity++; else if (r1 & CRC_ERR) up->port.icount.frame++; if (r1 & Rx_OVR) up->port.icount.overrun++; r1 &= up->port.read_status_mask; if (r1 & Rx_BRK) flag = TTY_BREAK; else if (r1 & PAR_ERR) flag = TTY_PARITY; else if (r1 & CRC_ERR) flag = TTY_FRAME; } if (uart_handle_sysrq_char(&up->port, ch)) continue; if (push) uart_insert_char(&up->port, r1, Rx_OVR, ch, flag); } return push; }
/* This function must only be called when the TX is not busy. The UART * port lock must be held and local interrupts disabled. */ static void __load_zsregs(struct zilog_channel *channel, unsigned char *regs) { int i; /* Let pending transmits finish. */ for (i = 0; i < 1000; i++) { unsigned char stat = read_zsreg(channel, R1); if (stat & ALL_SNT) break; udelay(100); } writeb(ERR_RES, &channel->control); ZSDELAY(); ZS_WSYNC(channel); ip22zilog_clear_fifo(channel); /* Disable all interrupts. */ write_zsreg(channel, R1, regs[R1] & ~(RxINT_MASK | TxINT_ENAB | EXT_INT_ENAB)); /* Set parity, sync config, stop bits, and clock divisor. */ write_zsreg(channel, R4, regs[R4]); /* Set misc. TX/RX control bits. */ write_zsreg(channel, R10, regs[R10]); /* Set TX/RX controls sans the enable bits. */ write_zsreg(channel, R3, regs[R3] & ~RxENAB); write_zsreg(channel, R5, regs[R5] & ~TxENAB); /* Synchronous mode config. */ write_zsreg(channel, R6, regs[R6]); write_zsreg(channel, R7, regs[R7]); /* Don't mess with the interrupt vector (R2, unused by us) and * master interrupt control (R9). We make sure this is setup * properly at probe time then never touch it again. */ /* Disable baud generator. */ write_zsreg(channel, R14, regs[R14] & ~BRENAB); /* Clock mode control. */ write_zsreg(channel, R11, regs[R11]); /* Lower and upper byte of baud rate generator divisor. */ write_zsreg(channel, R12, regs[R12]); write_zsreg(channel, R13, regs[R13]); /* Now rewrite R14, with BRENAB (if set). */ write_zsreg(channel, R14, regs[R14]); /* External status interrupt control. */ write_zsreg(channel, R15, regs[R15]); /* Reset external status interrupts. */ write_zsreg(channel, R0, RES_EXT_INT); write_zsreg(channel, R0, RES_EXT_INT); /* Rewrite R3/R5, this time without enables masked. */ write_zsreg(channel, R3, regs[R3]); write_zsreg(channel, R5, regs[R5]); /* Rewrite R1, this time without IRQ enabled masked. */ write_zsreg(channel, R1, regs[R1]); }
/* Hrm... we register that twice, fixme later.... */ static irqreturn_t pmz_interrupt(int irq, void *dev_id) { struct uart_pmac_port *uap = dev_id; struct uart_pmac_port *uap_a; struct uart_pmac_port *uap_b; int rc = IRQ_NONE; struct tty_struct *tty; u8 r3; uap_a = pmz_get_port_A(uap); uap_b = uap_a->mate; spin_lock(&uap_a->port.lock); r3 = read_zsreg(uap_a, R3); #ifdef DEBUG_HARD pmz_debug("irq, r3: %x\n", r3); #endif /* Channel A */ tty = NULL; if (r3 & (CHAEXT | CHATxIP | CHARxIP)) { write_zsreg(uap_a, R0, RES_H_IUS); zssync(uap_a); if (r3 & CHAEXT) pmz_status_handle(uap_a); if (r3 & CHARxIP) tty = pmz_receive_chars(uap_a); if (r3 & CHATxIP) pmz_transmit_chars(uap_a); rc = IRQ_HANDLED; } spin_unlock(&uap_a->port.lock); if (tty != NULL) tty_flip_buffer_push(tty); if (uap_b->node == NULL) goto out; spin_lock(&uap_b->port.lock); tty = NULL; if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) { write_zsreg(uap_b, R0, RES_H_IUS); zssync(uap_b); if (r3 & CHBEXT) pmz_status_handle(uap_b); if (r3 & CHBRxIP) tty = pmz_receive_chars(uap_b); if (r3 & CHBTxIP) pmz_transmit_chars(uap_b); rc = IRQ_HANDLED; } 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; }
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); /* TX still busy? Just wait for the next TX done interrupt. * * It can occur because of how we do serial console writes. It would * be nice to transmit console writes just like we normally would for * a TTY line. (ie. buffered and TX interrupt driven). That is not * easy because console writes cannot sleep. One solution might be * to poll on enough port->xmit space becomming free. -DaveM */ if (!(status & Tx_BUF_EMP)) return; } uap->flags &= ~PMACZILOG_FLAG_TX_ACTIVE; if (ZS_REGS_HELD(uap)) { pmz_load_zsregs(uap, uap->curregs); uap->flags &= ~PMACZILOG_FLAG_REGS_HELD; } if (ZS_TX_STOPPED(uap)) { uap->flags &= ~PMACZILOG_FLAG_TX_STOPPED; goto ack_tx_int; } if (uap->port.x_char) { uap->flags |= PMACZILOG_FLAG_TX_ACTIVE; write_zsdata(uap, uap->port.x_char); zssync(uap); uap->port.icount.tx++; uap->port.x_char = 0; return; } if (uap->port.info == NULL) goto ack_tx_int; xmit = &uap->port.info->xmit; if (uart_circ_empty(xmit)) { uart_write_wakeup(&uap->port); goto ack_tx_int; } if (uart_tx_stopped(&uap->port)) goto ack_tx_int; uap->flags |= PMACZILOG_FLAG_TX_ACTIVE; write_zsdata(uap, xmit->buf[xmit->tail]); zssync(uap); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); uap->port.icount.tx++; if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(&uap->port); return; ack_tx_int: write_zsreg(uap, R0, RES_Tx_P); zssync(uap); }
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.info == NULL || uap->port.info->tty == NULL) { WARN_ON(1); (void)read_zsdata(uap); return NULL; } tty = uap->port.info->tty; while (1) { error = 0; drop = 0; r1 = read_zsreg(uap, R1); ch = read_zsdata(uap); if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR)) { write_zsreg(uap, R0, ERR_RES); zssync(uap); } ch &= uap->parity_mask; 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); 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) goto next_char; flag = TTY_NORMAL; uap->port.icount.rx++; if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR | BRK_ABRT)) { error = 1; if (r1 & BRK_ABRT) { pmz_debug("pmz: got break !\n"); r1 &= ~(PAR_ERR | CRC_ERR); uap->port.icount.brk++; if (uart_handle_break(&uap->port)) goto next_char; } else if (r1 & PAR_ERR) uap->port.icount.parity++; else if (r1 & CRC_ERR) uap->port.icount.frame++; if (r1 & Rx_OVR) uap->port.icount.overrun++; r1 &= uap->port.read_status_mask; if (r1 & BRK_ABRT) flag = TTY_BREAK; else if (r1 & PAR_ERR) flag = TTY_PARITY; else if (r1 & CRC_ERR) flag = TTY_FRAME; } if (uap->port.ignore_status_mask == 0xff || (r1 & uap->port.ignore_status_mask) == 0) { 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. * When that happens, I disable the receive side of the driver. * Note that what I've been experiencing is a real irq loop where * I'm getting flooded regardless of the actual port speed. * Something stange is going on with the HW */ if ((++loops) > 1000) goto flood; ch = read_zsreg(uap, R0); if (!(ch & Rx_CH_AV)) break; } return tty; flood: uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK); write_zsreg(uap, R1, uap->curregs[R1]); zssync(uap); dev_err(&uap->dev->ofdev.dev, "pmz: rx irq flood !\n"); return tty; }
/* * Load all registers to reprogram the port * This function must only be called when the TX is not busy. The UART * port lock must be held and local interrupts disabled. */ 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); if (stat & ALL_SNT) break; udelay(100); } ZS_CLEARERR(uap); zssync(uap); ZS_CLEARFIFO(uap); zssync(uap); ZS_CLEARERR(uap); /* Disable all interrupts. */ write_zsreg(uap, R1, regs[R1] & ~(RxINT_MASK | TxINT_ENAB | EXT_INT_ENAB)); /* Set parity, sync config, stop bits, and clock divisor. */ write_zsreg(uap, R4, regs[R4]); /* Set misc. TX/RX control bits. */ write_zsreg(uap, R10, regs[R10]); /* Set TX/RX controls sans the enable bits. */ write_zsreg(uap, R3, regs[R3] & ~RxENABLE); write_zsreg(uap, R5, regs[R5] & ~TxENABLE); /* now set R7 "prime" on ESCC */ write_zsreg(uap, R15, regs[R15] | EN85C30); write_zsreg(uap, R7, regs[R7P]); /* make sure we use R7 "non-prime" on ESCC */ write_zsreg(uap, R15, regs[R15] & ~EN85C30); /* Synchronous mode config. */ write_zsreg(uap, R6, regs[R6]); write_zsreg(uap, R7, regs[R7]); /* Disable baud generator. */ write_zsreg(uap, R14, regs[R14] & ~BRENAB); /* Clock mode control. */ write_zsreg(uap, R11, regs[R11]); /* Lower and upper byte of baud rate generator divisor. */ write_zsreg(uap, R12, regs[R12]); write_zsreg(uap, R13, regs[R13]); /* Now rewrite R14, with BRENAB (if set). */ write_zsreg(uap, R14, regs[R14]); /* Reset external status interrupts. */ write_zsreg(uap, R0, RES_EXT_INT); write_zsreg(uap, R0, RES_EXT_INT); /* Rewrite R3/R5, this time without enables masked. */ write_zsreg(uap, R3, regs[R3]); write_zsreg(uap, R5, regs[R5]); /* Rewrite R1, this time without IRQ enabled masked. */ write_zsreg(uap, R1, regs[R1]); /* Enable interrupts */ write_zsreg(uap, R9, regs[R9]); }