/* * 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 asdg_enab_tx_int(struct async_struct *info, int enab_flag) { int ch; struct SCCHalf *port = (struct SCCHalf *)info->port; #ifdef DEBUG printk("asdg_enab_tx_int: enab_flag= %d\n", enab_flag); #endif if(enab_flag) { if( (ch=rs_get_tx_char(info)) >=0) { #ifdef DEBUG printk("{%x}", ch); #endif write_zsdata(port, ch); } else { #ifdef DEBUG printk("{%x}", ch); #endif write_zsreg(port, R0, RES_Tx_P); } } else write_zsreg(port, R0, RES_Tx_P); }
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); }
/* * 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 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); }
/* * 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); }
/* Interrupt Service Routine */ static void asdg_interrupt(int irq, void *data, struct pt_regs *fp) { int i; u_char ivec; /* Interrupt vector - not sure if it is needed */ u_char ip; /* IP bits from card */ int ch; /* Received or xmitted char */ struct SCC *scc; struct async_struct *infoA; struct async_struct *infoB; /* Check all cards */ for(i=0; i<nr_asdg; i+=2) { infoB = &rs_table[lines[i]]; infoA = &rs_table[lines[i+1]]; scc = (struct SCC *)infoA->board_base; ivec=read_zsreg(&scc->B, R2); /* Get Interrupt Vector and ignore it :-) */ ip=read_zsreg(&scc->A, R3); /* Get IP bits */ if(ip & CHBEXT) { /* Channel B ext/status */ #ifdef INTDEBUG printk("Channel B Ext/Stat"); #endif write_zsreg(&scc->B, R0, RES_EXT_INT); } if(ip & CHBTxIP) { /* Channel B TBE */ #ifdef INTDEBUG printk("Chan B TBE\n"); #endif if( (ch=rs_get_tx_char(infoB)) >=0 ) { #ifdef INTDEBUG // printk("{%x}", ch); #endif write_zsdata(&scc->B, ch); } else { #ifdef INTDEBUG // printk("{%x}", ch); #endif write_zsreg(&scc->B, R0, RES_Tx_P); } } if(ip & CHBRxIP) { /* Channel B Rx Char Avail */ #ifdef INTDEBUG printk("Channel B Rx char avail"); #endif while( (read_zsreg(&scc->B, R0) & Rx_CH_AV) != 0) { ch=read_zsdata(&scc->B); rs_receive_char(infoB, ch , 0); #ifdef INTDEBUG printk("Received Char Chan B: %c\n", ch); #endif } } if(ip & CHAEXT) { /* Channel A ext/status */ #ifdef INTDEBUG printk("Channel A Ext/Stat"); #endif write_zsreg(&scc->A, R0, RES_EXT_INT); } if(ip & CHATxIP) {/* Channel A TBE */ #ifdef INTDEBUG printk("Chan A TBE\n"); #endif if( (ch=rs_get_tx_char(infoA)) >=0) { #ifdef INTDEBUG // printk("{%x}", ch); #endif write_zsdata(&scc->A, ch); } else { #ifdef INTDEBUG // printk("{%x}", ch); #endif write_zsreg(&scc->A, R0, RES_Tx_P); } } if(ip & CHARxIP) { /* Channel A Rx Char Avail */ #ifdef INTDEBUG printk("Channel A Rx char avail"); #endif while( (read_zsreg(&scc->A, R0) & Rx_CH_AV) != 0) { ch=read_zsdata(&scc->A); rs_receive_char(infoA, ch , 0); #ifdef INTDEBUG printk("Received Char Chan A: %c\n", ch); #endif } } } }