📄 mac_scc.c
字号:
else shift = 0; /* Channel B */ for (;;) { zs_intreg = read_zsreg(info->private->zs_chan_a, 3);#ifdef SCC_DEBUG printk("mac_SCC: status %x shift %d shifted %x \n", zs_intreg, shift, zs_intreg >> shift);#endif zs_intreg = zs_intreg >> shift; if ((zs_intreg & CHAN_IRQMASK) == 0) break; if (zs_intreg & CHBRxIP) receive_chars(info, regs); if (zs_intreg & CHBTxIP) transmit_chars(info); if (zs_intreg & CHBEXT) status_handle(info); }}/* * ------------------------------------------------------------------- * Here ends the serial interrupt routines. * ------------------------------------------------------------------- *//* * ------------------------------------------------------------ * rs_stop() and rs_start() * * This routines are called before setting or resetting tty->stopped. * ------------------------------------------------------------ */static void SCC_enab_tx_int( struct m68k_async_struct *info, int enab_flag ){ unsigned long flags; if (enab_flag) {#if 0 save_flags(flags); cli(); if (info->private->curregs[5] & TxENAB) { info->private->curregs[5] &= ~TxENAB; info->private->pendregs[5] &= ~TxENAB; write_zsreg(info->private->zs_channel, 5, info->private->curregs[5]); } restore_flags(flags);#endif /* FIXME: should call transmit_chars here ??? */ transmit_chars(info); } else { save_flags(flags); cli();#if 0 if ( info->xmit_cnt && info->xmit_buf && !(info->private->curregs[5] & TxENAB)) { info->private->curregs[5] |= TxENAB; info->private->pendregs[5] = info->private->curregs[5]; write_zsreg(info->private->zs_channel, 5, info->private->curregs[5]); }#else if ( info->xmit_cnt && info->xmit_buf && !info->private->tx_active) { transmit_chars(info); }#endif restore_flags(flags); }}#if 0/* * leftover from original driver ... */static int SCC_startup(struct m68k_async_struct * info){ unsigned long flags; save_flags(flags); cli();#ifdef SERIAL_DEBUG_OPEN printk("starting up ttyS%d (irq %d)...", info->line, info->irq);#endif /* * Clear the receive FIFO. */ ZS_CLEARFIFO(info->private->zs_channel); info->xmit_fifo_size = 1; /* * Clear the interrupt registers. */ write_zsreg(info->private->zs_channel, 0, ERR_RES); write_zsreg(info->private->zs_channel, 0, RES_H_IUS); /* * Turn on RTS and DTR. */ zs_rtsdtr(info, 1); /* * Finally, enable sequencing and interrupts */ info->private->curregs[1] = (info->private->curregs[1] & ~0x18) | (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB); info->private->pendregs[1] = info->private->curregs[1]; info->private->curregs[3] |= (RxENABLE | Rx8); info->private->pendregs[3] = info->private->curregs[3]; info->private->curregs[5] |= (TxENAB | Tx8); info->private->pendregs[5] = info->private->curregs[5]; info->private->curregs[9] |= (NV | MIE); info->private->pendregs[9] = info->private->curregs[9]; write_zsreg(info->private->zs_channel, 3, info->private->curregs[3]); write_zsreg(info->private->zs_channel, 5, info->private->curregs[5]); write_zsreg(info->private->zs_channel, 9, info->private->curregs[9]); /* * Set the speed of the serial port */ SCC_change_speed(info); /* Save the current value of RR0 */ info->private->read_reg_zero = read_zsreg(info->private->zs_channel, 0); restore_flags(flags); return 0;}#endif/* FIXME: are these required ?? */static int SCC_check_open( struct m68k_async_struct *info, struct tty_struct *tty, struct file *file ){ /* check on the basis of info->whatever ?? */ if (info->private->kgdb_channel || info->private->is_cons) return -EBUSY; return( 0 );}static void SCC_init( struct m68k_async_struct *info ){ /* FIXME: init currently done in probe_sccs() */ /* BUT: startup part needs to be done here! */#ifdef SCC_DEBUG printk("mac_SCC: init, info %lx, info->port %lx \n", info, info->port);#endif /* * Clear the receive FIFO. */ ZS_CLEARFIFO(info->private->zs_channel); info->xmit_fifo_size = 1; /* * Clear the interrupt registers. */ write_zsreg(info->private->zs_channel, 0, ERR_RES); write_zsreg(info->private->zs_channel, 0, RES_H_IUS); /* * Turn on RTS and DTR. */ zs_rtsdtr(info, 1); /* * Finally, enable sequencing and interrupts */ info->private->curregs[1] = (info->private->curregs[1] & ~0x18) | (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB); info->private->pendregs[1] = info->private->curregs[1]; info->private->curregs[3] |= (RxENABLE | Rx8); info->private->pendregs[3] = info->private->curregs[3]; info->private->curregs[5] |= (TxENAB | Tx8); info->private->pendregs[5] = info->private->curregs[5]; info->private->curregs[9] |= (NV | MIE); info->private->pendregs[9] = info->private->curregs[9]; write_zsreg(info->private->zs_channel, 3, info->private->curregs[3]); write_zsreg(info->private->zs_channel, 5, info->private->curregs[5]); write_zsreg(info->private->zs_channel, 9, info->private->curregs[9]); /* * Set the speed of the serial port - done in startup() !! */#if 0 SCC_change_speed(info);#endif /* Save the current value of RR0 */ info->private->read_reg_zero = read_zsreg(info->private->zs_channel, 0);}static void SCC_init_port( struct m68k_async_struct *info, int type, int channel ){ static int got_autovector = 0;#ifdef SCC_DEBUG printk("mac_SCC: init_port, info %x \n", info);#endif info->sw = &SCC_switch; info->private = &zs_soft_private[channel]; info->private->zs_channel = &zs_channels[channel]; info->irq = IRQ4; info->private->clk_divisor = 16; info->private->zs_baud = get_zsbaud(info); info->port = (int) info->private->zs_channel->control; /* * MSch: Extended interrupt scheme: * The generic m68k interrupt code can't use multiple handlers for * the same interrupt source (no chained interrupts). * We have to plug in a 'master' interrupt handler instead, calling * mac_SCC_interrupt with the proper arguments ... */ if (!got_autovector) { if(sys_request_irq(IRQ4, mac_SCC_handler, 0, "SCC master", info)) panic("macserial: can't get irq %d", IRQ4);#ifdef SCC_DEBUG printk("mac_SCC: got SCC master interrupt %d, channel %d info %p\n", IRQ4, channel, info);#endif got_autovector = 1; } if (info->private->zs_chan_a == info->private->zs_channel) { /* Channel A */ if (request_irq(IRQ_SCCA, mac_SCC_interrupt, 0, "SCC A", info)) panic("mac_SCC: can't get irq %d", IRQ_SCCA);#ifdef SCC_DEBUG printk("mac_SCC: got SCC A interrupt %d, channel %d info %p\n", IRQ_SCCA, channel, info);#endif } else { /* Channel B */ if (request_irq(IRQ_SCCB, mac_SCC_interrupt, 0, "SCC B", info)) panic("mac_SCC: can't get irq %d", IRQ_SCCB);#ifdef SCC_DEBUG printk("mac_SCC: got SCC B interrupt %d, channel %d info %p\n", IRQ_SCCB, channel, info);#endif } /* If console serial line, then enable interrupts. */ if (info->private->is_cons) { printk("mac_SCC: console line %d; enabling interrupt!\n", info->line); write_zsreg(info->private->zs_channel, R1, (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB)); write_zsreg(info->private->zs_channel, R9, (NV | MIE)); write_zsreg(info->private->zs_channel, R10, (NRZ)); write_zsreg(info->private->zs_channel, R3, (Rx8 | RxENABLE)); write_zsreg(info->private->zs_channel, R5, (Tx8 | TxENAB)); } /* If this is the kgdb line, enable interrupts because we * now want to receive the 'control-c' character from the * client attached to us asynchronously. */ if (info->private->kgdb_channel) { printk("mac_SCC: kgdb line %d; enabling interrupt!\n", info->line); kgdb_chaninit(info, 1, info->private->zs_baud); } /* Report settings (in m68kserial.c) */#ifndef CONFIG_MAC printk("ttyS%d at 0x%08x (irq = %d)", info->line, info->port, info->irq); printk(" is a Z8530 SCC\n");#endif}/* * This routine will shutdown a serial port; interrupts are disabled, and * DTR is dropped if the hangup on close termio flag is on. */static void SCC_deinit(struct m68k_async_struct * info, int leave_dtr){ unsigned long flags; save_flags(flags); cli(); /* Disable interrupts */ info->private->pendregs[1] = info->private->curregs[1] = 0; write_zsreg(info->private->zs_channel, 1, 0); /* no interrupts */ info->private->curregs[3] &= ~RxENABLE; info->private->pendregs[3] = info->private->curregs[3]; write_zsreg(info->private->zs_channel, 3, info->private->curregs[3]); info->private->curregs[5] &= ~TxENAB; if (!leave_dtr) info->private->curregs[5] &= ~(DTR | RTS); else info->private->curregs[5] &= ~(RTS); info->private->pendregs[5] = info->private->curregs[5]; write_zsreg(info->private->zs_channel, 5, info->private->curregs[5]); restore_flags(flags);}/* FIXME !!! */static int SCC_check_custom_divisor( struct m68k_async_struct *info, int baud_base, int divisor ){ return 0;}/* * This routine is called to set the UART divisor registers to match * the specified baud rate for a serial port. */static void SCC_change_speed(struct m68k_async_struct *info){ unsigned short port; unsigned cflag; int i; int brg; unsigned long flags; if (!info->tty || !info->tty->termios) return; cflag = info->tty->termios->c_cflag; if (!(port = info->port)) return; i = cflag & CBAUD; if (i == 0 && !(info->flags & ASYNC_SPD_MASK)) { /* speed == 0 -> drop DTR */ save_flags(flags); cli(); info->private->curregs[5] &= ~(DTR | RTS); write_zsreg(info->private->zs_channel, 5, info->private->curregs[5]); restore_flags(flags); return; } if (i & CBAUDEX) { /* XXX CBAUDEX is not obeyed. * It is impossible at a 32bits PPC. XXX?? * But we have to report this to user ... someday. */ i = B9600; } save_flags(flags); cli(); info->private->zs_baud = baud_table[i]; info->private->clk_divisor = 16; info->private->curregs[4] = X16CLK; info->private->curregs[11] = TCBR | RCBR; brg = BPS_TO_BRG(info->private->zs_baud, ZS_CLOCK/info->private->clk_divisor); info->private->curregs[12] = (brg & 255); info->private->curregs[13] = ((brg >> 8) & 255); info->private->curregs[14] = BRENABL; /* byte size and parity */ info->private->curregs[3] &= ~RxNBITS_MASK; info->private->curregs[5] &= ~TxNBITS_MASK; switch (cflag & CSIZE) { case CS5: info->private->curregs[3] |= Rx5; info->private->curregs[5] |= Tx5; break; case CS6: info->private->curregs[3] |= Rx6; info->private->curregs[5] |= Tx6; break; case CS7: info->private->curregs[3] |= Rx7; info->private->curregs[5] |= Tx7; break; case CS8: default: /* defaults to 8 bits */ info->private->curregs[3] |= Rx8; info->private->curregs[5] |= Tx8; break; } info->private->pendregs[3] = info->private->curregs[3]; info->private->pendregs[5] = info->private->curregs[5]; info->private->curregs[4] &= ~(SB_MASK | PAR_ENA | PAR_EVEN); if (cflag & CSTOPB) { info->private->curregs[4] |= SB2; } else { info->private->curregs[4] |= SB1; } if (cflag & PARENB) { info->private->curregs[4] |= PAR_ENA; } if (!(cflag & PARODD)) { info->private->curregs[4] |= PAR_EVEN; } info->private->pendregs[4] = info->private->curregs[4]; info->private->curregs[15] &= ~(DCDIE | CTSIE); if (!(cflag & CLOCAL)) { info->private->curregs[15] |= DCDIE; } if (cflag & CRTSCTS) { info->private->curregs[15] |= CTSIE; if ((read_zsreg(info->private->zs_channel, 0) & CTS) != 0) info->private->tx_stopped = 1; } else info->private->tx_stopped = 0; info->private->pendregs[15] = info->private->curregs[15]; /* Load up the new values */ load_zsregs(info->private->zs_channel, info->private->curregs); restore_flags(flags);}/* This is for console output over ttya/ttyb */static void SCC_put_char(char ch){ struct mac_zschannel *chan = zs_conschan; int loops = 0; unsigned long flags; if(!chan) return; save_flags(flags); cli(); while ((read_zsreg(chan, 0) & Tx_BUF_EMP) == 0 && loops < 10000) { loops++; udelay(5); } write_zsdata(chan, ch); restore_flags(flags);}/* These are for receiving and sending characters under the kgdb * source level kernel debugger. */void putDebugChar(char kgdb_char){ struct mac_zschannel *chan = zs_kgdbchan; while ((read_zsreg(chan, 0) & Tx_BUF_EMP) == 0) udelay(5); write_zsdata(chan, kgdb_char);}char getDebugChar(void){ struct mac_zschannel *chan = zs_kgdbchan; while ((read_zsreg(chan, 0) & Rx_CH_AV) == 0) udelay(5); return read_zsdata(chan);}/* * Fair output driver allows a process to speak. */static void SCC_fair_output(void){ int left; /* Output no more than that */ unsigned long flags; struct m68k_async_struct *info = zs_consinfo; char c; if (info == 0) return; if (info->xmit_buf == 0) return; save_flags(flags); cli(); left = info->xmit_cnt; while (left != 0) { c = info->xmit_buf[info->xmit_tail]; info->xmit_tail = (info->xmit_tail+1) & (SERIAL_XMIT_SIZE-1); info->xmit_cnt--; restore_flags(flags); SCC_put_char(c); save_flags(flags); cli(); left = MIN(info->xmit_cnt, left-1); } restore_flags(flags); return;}/* * zs_console_print is registered for printk. */static void zs_console_print(const char *p){ char c; while ((c = *(p++)) != 0) { if (c == '\n') SCC_put_char('\r'); SCC_put_char(c); } /* Comment this if you want to have a strict interrupt-driven output */ SCC_fair_output();}/* FIXME: check with SCC_enab_tx_int!! */#if 0
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -