/* * This routine sends a break character out the serial port. */ static void send_break(struct dz_serial *info, int duration) { unsigned long flags; unsigned short tmp, mask; if (!info->port) return; mask = 1 << info->line; tmp = dz_in(info, DZ_TCR); tmp |= mask; current->state = TASK_INTERRUPTIBLE; save_flags(flags); cli(); dz_out(info, DZ_TCR, tmp); schedule_timeout(duration); tmp &= ~mask; dz_out(info, DZ_TCR, tmp); restore_flags(flags); }
/* * ------------------------------------------------------------------- * shutdown () * * 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 shutdown(struct dz_serial *info) { unsigned long flags; unsigned short tmp; if (!info->is_initialized) return; save_flags(flags); cli(); dz_stop(info->tty); info->cflags &= ~DZ_CREAD; /* turn off receive enable flag */ dz_out(info, DZ_LPR, info->cflags); if (info->xmit_buf) { /* free Tx buffer */ free_page((unsigned long) info->xmit_buf); info->xmit_buf = 0; } if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) { tmp = dz_in(info, DZ_TCR); if (tmp & DZ_MODEM_DTR) { tmp &= ~DZ_MODEM_DTR; dz_out(info, DZ_TCR, tmp); } } if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); info->is_initialized = 0; restore_flags(flags); }
static void dz_reset(struct dz_port *dport) { dz_out(dport, DZ_CSR, DZ_CLR); while (dz_in(dport, DZ_CSR) & DZ_CLR); iob(); /* enable scanning */ dz_out(dport, DZ_CSR, DZ_MSE); }
static int __init dz_console_setup(struct console *co, char *options) { struct dz_port *dport = &dz_ports[CONSOLE_LINE]; int baud = 9600; int bits = 8; int parity = 'n'; int flow = 'n'; int ret; unsigned short mask, tmp; if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); dz_reset(dport); ret = uart_set_options(&dport->port, co, baud, parity, bits, flow); if (ret == 0) { mask = 1 << dport->port.line; tmp = dz_in(dport, DZ_TCR); /* read the TX flag */ if (!(tmp & mask)) { tmp |= mask; /* set the TX flag */ dz_out(dport, DZ_TCR, tmp); } } return ret; }
static void dz_stop_rx(struct uart_port *uport) { struct dz_port *dport = (struct dz_port *)uport; unsigned long flags; spin_lock_irqsave(&dport->port.lock, flags); dport->cflag &= ~DZ_CREAD; dz_out(dport, DZ_LPR, dport->cflag | dport->port.line); spin_unlock_irqrestore(&dport->port.lock, flags); }
/* * ------------------------------------------------------------------- * startup () * * various initialization tasks * ------------------------------------------------------------------- */ static int startup(struct dz_serial *info) { unsigned long page, flags; unsigned short tmp; if (info->is_initialized) return 0; save_flags(flags); cli(); if (!info->port) { if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); restore_flags(flags); return -ENODEV; } if (!info->xmit_buf) { page = get_free_page(GFP_KERNEL); if (!page) { restore_flags(flags); return -ENOMEM; } info->xmit_buf = (unsigned char *) page; } if (info->tty) clear_bit(TTY_IO_ERROR, &info->tty->flags); /* enable the interrupt and the scanning */ tmp = dz_in(info, DZ_CSR); tmp |= (DZ_RIE | DZ_TIE | DZ_MSE); dz_out(info, DZ_CSR, tmp); info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; /* set up the speed */ change_speed(info); /* clear the line transmitter buffer I can't figure out why I need to do this - but its necessary - in order for the console portion and the interrupt portion to live happily side by side. */ /* clear the line transmitter buffer I can't figure out why I need to do this - but its necessary - in order for the console portion and the interrupt portion to live happily side by side. */ info->is_initialized = 1; restore_flags(flags); return 0; }
static void dz_start(struct tty_struct *tty) { struct dz_serial *info = (struct dz_serial *) tty->driver_data; unsigned short mask, tmp; mask = 1 << info->line; tmp = dz_in(info, DZ_TCR); /* read the TX flag */ tmp |= mask; /* set the TX flag */ dz_out(info, DZ_TCR, tmp); }
static void dz_start_tx(struct uart_port *uport) { struct dz_port *dport = (struct dz_port *)uport; unsigned short tmp, mask = 1 << dport->port.line; unsigned long flags; spin_lock_irqsave(&dport->port.lock, flags); tmp = dz_in(dport, DZ_TCR); /* read the TX flag */ tmp |= mask; /* set the TX flag */ dz_out(dport, DZ_TCR, tmp); spin_unlock_irqrestore(&dport->port.lock, flags); }
/* * ------------------------------------------------------------ * transmit_char () * * This routine deals with outputs to any lines. * ------------------------------------------------------------ */ static inline void dz_transmit_chars(struct dz_port *dport_in) { struct dz_port *dport; struct circ_buf *xmit; unsigned short status; unsigned char tmp; status = dz_in(dport_in, DZ_CSR); dport = &dz_ports[LINE(status)]; xmit = &dport->port.info->xmit; if (dport->port.x_char) { /* XON/XOFF chars */ dz_out(dport, DZ_TDR, dport->port.x_char); dport->port.icount.tx++; dport->port.x_char = 0; return; } /* If nothing to do or stopped or hardware stopped. */ if (uart_circ_empty(xmit) || uart_tx_stopped(&dport->port)) { dz_stop_tx(&dport->port); return; } /* * If something to do... (remember the dz has no output fifo, * so we go one char at a time) :-< */ tmp = xmit->buf[xmit->tail]; xmit->tail = (xmit->tail + 1) & (DZ_XMIT_SIZE - 1); dz_out(dport, DZ_TDR, tmp); dport->port.icount.tx++; if (uart_circ_chars_pending(xmit) < DZ_WAKEUP_CHARS) uart_write_wakeup(&dport->port); /* Are we are done. */ if (uart_circ_empty(xmit)) dz_stop_tx(&dport->port); }
static void dz_set_mctrl(struct uart_port *uport, unsigned int mctrl) { struct dz_port *dport = (struct dz_port *)uport; unsigned short tmp; if (dport->port.line == DZ_MODEM) { tmp = dz_in(dport, DZ_TCR); if (mctrl & TIOCM_DTR) tmp &= ~DZ_MODEM_DTR; else tmp |= DZ_MODEM_DTR; dz_out(dport, DZ_TCR, tmp); } }
static void dz_break_ctl(struct uart_port *uport, int break_state) { struct dz_port *dport = (struct dz_port *)uport; unsigned long flags; unsigned short tmp, mask = 1 << uport->line; spin_lock_irqsave(&uport->lock, flags); tmp = dz_in(dport, DZ_TCR); if (break_state) tmp |= mask; else tmp &= ~mask; dz_out(dport, DZ_TCR, tmp); spin_unlock_irqrestore(&uport->lock, flags); }
static void dz_stop(struct tty_struct *tty) { struct dz_serial *info; unsigned short mask, tmp; if (tty == 0) return; info = (struct dz_serial *) tty->driver_data; mask = 1 << info->line; tmp = dz_in(info, DZ_TCR); /* read the TX flag */ tmp &= ~mask; /* clear the TX flag */ dz_out(info, DZ_TCR, tmp); }
/* * ------------------------------------------------------------------- * startup () * * various initialization tasks * ------------------------------------------------------------------- */ static int dz_startup(struct uart_port *uport) { struct dz_port *dport = (struct dz_port *)uport; unsigned long flags; unsigned short tmp; spin_lock_irqsave(&dport->port.lock, flags); /* enable the interrupt and the scanning */ tmp = dz_in(dport, DZ_CSR); tmp |= DZ_RIE | DZ_TIE | DZ_MSE; dz_out(dport, DZ_CSR, tmp); spin_unlock_irqrestore(&dport->port.lock, flags); return 0; }
static void dz_set_mctrl(struct uart_port *uport, unsigned int mctrl) { /* * FIXME: Handle the 3100/5000 as appropriate. --macro */ struct dz_port *dport = (struct dz_port *)uport; unsigned short tmp; if (dport->port.line == DZ_MODEM) { tmp = dz_in(dport, DZ_TCR); if (mctrl & TIOCM_DTR) tmp &= ~DZ_MODEM_DTR; else tmp |= DZ_MODEM_DTR; dz_out(dport, DZ_TCR, tmp); } }
static void dz_break_ctl(struct uart_port *uport, int break_state) { /* * FIXME: Can't access BREAK bits in TDR easily; * reuse the code for polled TX. --macro */ struct dz_port *dport = (struct dz_port *)uport; unsigned long flags; unsigned short tmp, mask = 1 << dport->port.line; spin_lock_irqsave(&uport->lock, flags); tmp = dz_in(dport, DZ_TCR); if (break_state) tmp |= mask; else tmp &= ~mask; dz_out(dport, DZ_TCR, tmp); spin_unlock_irqrestore(&uport->lock, flags); }
static void dz_console_put_char(struct dz_port *dport, unsigned char ch) { unsigned long flags; int loops = 2500; unsigned short tmp = ch; /* this code sends stuff out to serial device - spinning its wheels and waiting. */ spin_lock_irqsave(&dport->port.lock, flags); /* spin our wheels */ while (((dz_in(dport, DZ_CSR) & DZ_TRDY) != DZ_TRDY) && loops--) /* FIXME: cpu_relax, udelay? --rmk */ ; /* Actually transmit the character. */ dz_out(dport, DZ_TDR, tmp); spin_unlock_irqrestore(&dport->port.lock, flags); }
static void dz_console_put_char(unsigned char ch) { unsigned long flags; int loops = 2500; unsigned short tmp = ch; /* this code sends stuff out to serial device - spinning its wheels and waiting. */ /* force the issue - point it at lines[3] */ dz_console = &multi[CONSOLE_LINE]; save_flags(flags); cli(); /* spin our wheels */ while (((dz_in(dz_console, DZ_CSR) & DZ_TRDY) != DZ_TRDY) && loops--); /* Actually transmit the character. */ dz_out(dz_console, DZ_TDR, tmp); restore_flags(flags); }
/* * ------------------------------------------------------------------- * startup () * * various initialization tasks * ------------------------------------------------------------------- */ static int dz_startup(struct uart_port *uport) { struct dz_port *dport = (struct dz_port *)uport; unsigned long flags; unsigned short tmp; /* The dz lines for the mouse/keyboard must be * opened using their respective drivers. */ if ((dport->port.line == DZ_KEYBOARD) || (dport->port.line == DZ_MOUSE)) return -ENODEV; spin_lock_irqsave(&dport->port.lock, flags); /* enable the interrupt and the scanning */ tmp = dz_in(dport, DZ_CSR); tmp |= DZ_RIE | DZ_TIE | DZ_MSE; dz_out(dport, DZ_CSR, tmp); spin_unlock_irqrestore(&dport->port.lock, flags); return 0; }
/* * ------------------------------------------------------------------- * dz_console_putchar() -- transmit a character * * Polled transmission. This is tricky. We need to mask transmit * interrupts so that they do not interfere, enable the transmitter * for the line requested and then wait till the transmit scanner * requests data for this line. But it may request data for another * line first, in which case we have to disable its transmitter and * repeat waiting till our line pops up. Only then the character may * be transmitted. Finally, the state of the transmitter mask is * restored. Welcome to the world of PDP-11! * ------------------------------------------------------------------- */ static void dz_console_putchar(struct uart_port *uport, int ch) { struct dz_port *dport = (struct dz_port *)uport; unsigned long flags; unsigned short csr, tcr, trdy, mask; int loops = 10000; spin_lock_irqsave(&dport->port.lock, flags); csr = dz_in(dport, DZ_CSR); dz_out(dport, DZ_CSR, csr & ~DZ_TIE); tcr = dz_in(dport, DZ_TCR); tcr |= 1 << dport->port.line; mask = tcr; dz_out(dport, DZ_TCR, mask); iob(); spin_unlock_irqrestore(&dport->port.lock, flags); while (loops--) { trdy = dz_in(dport, DZ_CSR); if (!(trdy & DZ_TRDY)) continue; trdy = (trdy & DZ_TLINE) >> 8; if (trdy == dport->port.line) break; mask &= ~(1 << trdy); dz_out(dport, DZ_TCR, mask); iob(); udelay(2); } if (loops) /* Cannot send otherwise. */ dz_out(dport, DZ_TDR, ch); dz_out(dport, DZ_TCR, tcr); dz_out(dport, DZ_CSR, csr); }
static int __init dz_console_setup(struct console *co, char *options) { int baud = 9600; int bits = 8; int parity = 'n'; int cflag = CREAD | HUPCL | CLOCAL; char *s; unsigned short mask, tmp; if (options) { baud = simple_strtoul(options, NULL, 10); s = options; while (*s >= '0' && *s <= '9') s++; if (*s) parity = *s++; if (*s) bits = *s - '0'; } /* * Now construct a cflag setting. */ switch (baud) { case 1200: cflag |= DZ_B1200; break; case 2400: cflag |= DZ_B2400; break; case 4800: cflag |= DZ_B4800; break; case 9600: default: cflag |= DZ_B9600; break; } switch (bits) { case 7: cflag |= DZ_CS7; break; default: case 8: cflag |= DZ_CS8; break; } switch (parity) { case 'o': case 'O': cflag |= DZ_PARODD; break; case 'e': case 'E': cflag |= DZ_PARENB; break; } co->cflag = cflag; /* TOFIX: force to console line */ dz_console = &multi[CONSOLE_LINE]; if ((mips_machtype == MACH_DS23100) || (mips_machtype == MACH_DS5100)) dz_console->port = KN01_DZ11_BASE; else dz_console->port = KN02_DZ11_BASE; dz_console->line = CONSOLE_LINE; dz_out(dz_console, DZ_CSR, DZ_CLR); while ((tmp = dz_in(dz_console, DZ_CSR)) & DZ_CLR); /* enable scanning */ dz_out(dz_console, DZ_CSR, DZ_MSE); /* Set up flags... */ dz_console->cflags = 0; dz_console->cflags |= DZ_B9600; dz_console->cflags |= DZ_CS8; dz_console->cflags |= DZ_PARENB; dz_out(dz_console, DZ_LPR, dz_console->cflags); mask = 1 << dz_console->line; tmp = dz_in(dz_console, DZ_TCR); /* read the TX flag */ if (!(tmp & mask)) { tmp |= mask; /* set the TX flag */ dz_out(dz_console, DZ_TCR, tmp); } return 0; }
static void dz_set_termios(struct uart_port *uport, struct ktermios *termios, struct ktermios *old_termios) { struct dz_port *dport = (struct dz_port *)uport; unsigned long flags; unsigned int cflag, baud; cflag = dport->port.line; switch (termios->c_cflag & CSIZE) { case CS5: cflag |= DZ_CS5; break; case CS6: cflag |= DZ_CS6; break; case CS7: cflag |= DZ_CS7; break; case CS8: default: cflag |= DZ_CS8; } if (termios->c_cflag & CSTOPB) cflag |= DZ_CSTOPB; if (termios->c_cflag & PARENB) cflag |= DZ_PARENB; if (termios->c_cflag & PARODD) cflag |= DZ_PARODD; baud = uart_get_baud_rate(uport, termios, old_termios, 50, 9600); switch (baud) { case 50: cflag |= DZ_B50; break; case 75: cflag |= DZ_B75; break; case 110: cflag |= DZ_B110; break; case 134: cflag |= DZ_B134; break; case 150: cflag |= DZ_B150; break; case 300: cflag |= DZ_B300; break; case 600: cflag |= DZ_B600; break; case 1200: cflag |= DZ_B1200; break; case 1800: cflag |= DZ_B1800; break; case 2000: cflag |= DZ_B2000; break; case 2400: cflag |= DZ_B2400; break; case 3600: cflag |= DZ_B3600; break; case 4800: cflag |= DZ_B4800; break; case 7200: cflag |= DZ_B7200; break; case 9600: default: cflag |= DZ_B9600; } if (termios->c_cflag & CREAD) cflag |= DZ_RXENAB; spin_lock_irqsave(&dport->port.lock, flags); dz_out(dport, DZ_LPR, cflag | dport->port.line); dport->cflag = cflag; /* setup accept flag */ dport->port.read_status_mask = DZ_OERR; if (termios->c_iflag & INPCK) dport->port.read_status_mask |= DZ_FERR | DZ_PERR; /* characters to ignore */ uport->ignore_status_mask = 0; if (termios->c_iflag & IGNPAR) dport->port.ignore_status_mask |= DZ_FERR | DZ_PERR; spin_unlock_irqrestore(&dport->port.lock, flags); }
/* * ------------------------------------------------------------ * receive_char () * * This routine deals with inputs from any lines. * ------------------------------------------------------------ */ static inline void receive_chars(struct dz_serial *info_in) { struct dz_serial *info; struct tty_struct *tty = 0; struct async_icount *icount; int ignore = 0; unsigned short status, tmp; unsigned char ch; /* this code is going to be a problem... the call to tty_flip_buffer is going to need to be rethought... */ do { status = dz_in(info_in, DZ_RBUF); info = lines[LINE(status)]; /* punt so we don't get duplicate characters */ if (!(status & DZ_DVAL)) goto ignore_char; ch = UCHAR(status); /* grab the char */ #if 0 if (info->is_console) { if (ch == 0) return; /* it's a break ... */ } #endif tty = info->tty; /* now tty points to the proper dev */ icount = &info->icount; if (!tty) break; if (tty->flip.count >= TTY_FLIPBUF_SIZE) break; *tty->flip.char_buf_ptr = ch; *tty->flip.flag_buf_ptr = 0; icount->rx++; /* keep track of the statistics */ if (status & (DZ_OERR | DZ_FERR | DZ_PERR)) { if (status & DZ_PERR) /* parity error */ icount->parity++; else if (status & DZ_FERR) /* frame error */ icount->frame++; if (status & DZ_OERR) /* overrun error */ icount->overrun++; /* check to see if we should ignore the character and mask off conditions that should be ignored */ if (status & info->ignore_status_mask) { if (++ignore > 100) break; goto ignore_char; } /* mask off the error conditions we want to ignore */ tmp = status & info->read_status_mask; if (tmp & DZ_PERR) { *tty->flip.flag_buf_ptr = TTY_PARITY; #ifdef DEBUG_DZ debug_console("PERR\n", 5); #endif } else if (tmp & DZ_FERR) { *tty->flip.flag_buf_ptr = TTY_FRAME; #ifdef DEBUG_DZ debug_console("FERR\n", 5); #endif } if (tmp & DZ_OERR) { #ifdef DEBUG_DZ debug_console("OERR\n", 5); #endif if (tty->flip.count < TTY_FLIPBUF_SIZE) { tty->flip.count++; tty->flip.flag_buf_ptr++; tty->flip.char_buf_ptr++; *tty->flip.flag_buf_ptr = TTY_OVERRUN; } } } tty->flip.flag_buf_ptr++; tty->flip.char_buf_ptr++; tty->flip.count++; ignore_char: } while (status & DZ_DVAL); if (tty) tty_flip_buffer_push(tty); } /* * ------------------------------------------------------------ * transmit_char () * * This routine deals with outputs to any lines. * ------------------------------------------------------------ */ static inline void transmit_chars(struct dz_serial *info) { unsigned char tmp; if (info->x_char) { /* XON/XOFF chars */ dz_out(info, DZ_TDR, info->x_char); info->icount.tx++; info->x_char = 0; return; } /* if nothing to do or stopped or hardware stopped */ if ((info->xmit_cnt <= 0) || info->tty->stopped || info->tty->hw_stopped) { dz_stop(info->tty); return; } /* * if something to do ... (rember the dz has no output fifo so we go * one char at a time :-< */ tmp = (unsigned short) info->xmit_buf[info->xmit_tail++]; dz_out(info, DZ_TDR, tmp); info->xmit_tail = info->xmit_tail & (DZ_XMIT_SIZE - 1); info->icount.tx++; if (--info->xmit_cnt < WAKEUP_CHARS) dz_sched_event(info, DZ_EVENT_WRITE_WAKEUP); /* Are we done */ if (info->xmit_cnt <= 0) dz_stop(info->tty); }
/* * ------------------------------------------------------------------- * change_speed () * * set the baud rate. * ------------------------------------------------------------------- */ static void change_speed(struct dz_serial *info) { unsigned long flags; unsigned cflag; int baud; if (!info->tty || !info->tty->termios) return; save_flags(flags); cli(); info->cflags = info->line; cflag = info->tty->termios->c_cflag; switch (cflag & CSIZE) { case CS5: info->cflags |= DZ_CS5; break; case CS6: info->cflags |= DZ_CS6; break; case CS7: info->cflags |= DZ_CS7; break; case CS8: default: info->cflags |= DZ_CS8; } if (cflag & CSTOPB) info->cflags |= DZ_CSTOPB; if (cflag & PARENB) info->cflags |= DZ_PARENB; if (cflag & PARODD) info->cflags |= DZ_PARODD; baud = tty_get_baud_rate(info->tty); switch (baud) { case 50: info->cflags |= DZ_B50; break; case 75: info->cflags |= DZ_B75; break; case 110: info->cflags |= DZ_B110; break; case 134: info->cflags |= DZ_B134; break; case 150: info->cflags |= DZ_B150; break; case 300: info->cflags |= DZ_B300; break; case 600: info->cflags |= DZ_B600; break; case 1200: info->cflags |= DZ_B1200; break; case 1800: info->cflags |= DZ_B1800; break; case 2000: info->cflags |= DZ_B2000; break; case 2400: info->cflags |= DZ_B2400; break; case 3600: info->cflags |= DZ_B3600; break; case 4800: info->cflags |= DZ_B4800; break; case 7200: info->cflags |= DZ_B7200; break; case 9600: default: info->cflags |= DZ_B9600; } info->cflags |= DZ_RXENAB; dz_out(info, DZ_LPR, info->cflags); /* setup accept flag */ info->read_status_mask = DZ_OERR; if (I_INPCK(info->tty)) info->read_status_mask |= (DZ_FERR | DZ_PERR); /* characters to ignore */ info->ignore_status_mask = 0; if (I_IGNPAR(info->tty)) info->ignore_status_mask |= (DZ_FERR | DZ_PERR); restore_flags(flags); }
/* * ------------------------------------------------------------ * receive_char () * * This routine deals with inputs from any lines. * ------------------------------------------------------------ */ static inline void dz_receive_chars(struct dz_port *dport) { struct tty_struct *tty = NULL; struct uart_icount *icount; int ignore = 0; unsigned short status, tmp; unsigned char ch, flag; /* this code is going to be a problem... the call to tty_flip_buffer is going to need to be rethought... */ do { status = dz_in(dport, DZ_RBUF); /* punt so we don't get duplicate characters */ if (!(status & DZ_DVAL)) goto ignore_char; ch = UCHAR(status); /* grab the char */ flag = TTY_NORMAL; #if 0 if (info->is_console) { if (ch == 0) return; /* it's a break ... */ } #endif tty = dport->port.info->tty;/* now tty points to the proper dev */ icount = &dport->port.icount; if (!tty) break; if (tty->flip.count >= TTY_FLIPBUF_SIZE) break; icount->rx++; /* keep track of the statistics */ if (status & (DZ_OERR | DZ_FERR | DZ_PERR)) { if (status & DZ_PERR) /* parity error */ icount->parity++; else if (status & DZ_FERR) /* frame error */ icount->frame++; if (status & DZ_OERR) /* overrun error */ icount->overrun++; /* check to see if we should ignore the character and mask off conditions that should be ignored */ if (status & dport->port.ignore_status_mask) { if (++ignore > 100) break; goto ignore_char; } /* mask off the error conditions we want to ignore */ tmp = status & dport->port.read_status_mask; if (tmp & DZ_PERR) { flag = TTY_PARITY; #ifdef DEBUG_DZ debug_console("PERR\n", 5); #endif } else if (tmp & DZ_FERR) { flag = TTY_FRAME; #ifdef DEBUG_DZ debug_console("FERR\n", 5); #endif } if (tmp & DZ_OERR) { #ifdef DEBUG_DZ debug_console("OERR\n", 5); #endif tty_insert_flip_char(tty, ch, flag); ch = 0; flag = TTY_OVERRUN; } } tty_insert_flip_char(tty, ch, flag); ignore_char: } while (status & DZ_DVAL); if (tty) tty_flip_buffer_push(tty); } /* * ------------------------------------------------------------ * transmit_char () * * This routine deals with outputs to any lines. * ------------------------------------------------------------ */ static inline void dz_transmit_chars(struct dz_port *dport) { struct circ_buf *xmit = &dport->port.info->xmit; unsigned char tmp; if (dport->port.x_char) { /* XON/XOFF chars */ dz_out(dport, DZ_TDR, dport->port.x_char); dport->port.icount.tx++; dport->port.x_char = 0; return; } /* if nothing to do or stopped or hardware stopped */ if (uart_circ_empty(xmit) || uart_tx_stopped(&dport->port)) { dz_stop_tx(&dport->port, 0); return; } /* * if something to do ... (rember the dz has no output fifo so we go * one char at a time :-< */ tmp = xmit->buf[xmit->tail]; xmit->tail = (xmit->tail + 1) & (DZ_XMIT_SIZE - 1); dz_out(dport, DZ_TDR, tmp); dport->port.icount.tx++; if (uart_circ_chars_pending(xmit) < DZ_WAKEUP_CHARS) uart_write_wakeup(&dport->port); /* Are we done */ if (uart_circ_empty(xmit)) dz_stop_tx(&dport->port, 0); } /* * ------------------------------------------------------------ * check_modem_status () * * Only valid for the MODEM line duh ! * ------------------------------------------------------------ */ static inline void check_modem_status(struct dz_port *dport) { unsigned short status; /* if not ne modem line just return */ if (dport->port.line != DZ_MODEM) return; status = dz_in(dport, DZ_MSR); /* it's easy, since DSR2 is the only bit in the register */ if (status) dport->port.icount.dsr++; }
int __init dz_init(void) { int i; long flags; struct dz_serial *info; /* Setup base handler, and timer table. */ init_bh(SERIAL_BH, do_serial_bh); show_serial_version(); memset(&serial_driver, 0, sizeof(struct tty_driver)); serial_driver.magic = TTY_DRIVER_MAGIC; #if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS)) serial_driver.name = "ttyS"; #else serial_driver.name = "tts/%d"; #endif serial_driver.major = TTY_MAJOR; serial_driver.minor_start = 64; serial_driver.num = DZ_NB_PORT; serial_driver.type = TTY_DRIVER_TYPE_SERIAL; serial_driver.subtype = SERIAL_TYPE_NORMAL; serial_driver.init_termios = tty_std_termios; serial_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; serial_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS; serial_driver.refcount = &serial_refcount; serial_driver.table = serial_table; serial_driver.termios = serial_termios; serial_driver.termios_locked = serial_termios_locked; serial_driver.open = dz_open; serial_driver.close = dz_close; serial_driver.write = dz_write; serial_driver.flush_chars = dz_flush_chars; serial_driver.write_room = dz_write_room; serial_driver.chars_in_buffer = dz_chars_in_buffer; serial_driver.flush_buffer = dz_flush_buffer; serial_driver.ioctl = dz_ioctl; serial_driver.throttle = dz_throttle; serial_driver.unthrottle = dz_unthrottle; serial_driver.send_xchar = dz_send_xchar; serial_driver.set_termios = dz_set_termios; serial_driver.stop = dz_stop; serial_driver.start = dz_start; serial_driver.hangup = dz_hangup; /* * The callout device is just like normal device except for * major number and the subtype code. */ callout_driver = serial_driver; #if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS)) callout_driver.name = "cua"; #else callout_driver.name = "cua/%d"; #endif callout_driver.major = TTYAUX_MAJOR; callout_driver.subtype = SERIAL_TYPE_CALLOUT; if (tty_register_driver(&serial_driver)) panic("Couldn't register serial driver"); if (tty_register_driver(&callout_driver)) panic("Couldn't register callout driver"); save_flags(flags); cli(); for (i = 0; i < DZ_NB_PORT; i++) { info = &multi[i]; lines[i] = info; info->magic = SERIAL_MAGIC; if (mips_machtype == MACH_DS23100 || mips_machtype == MACH_DS5100) info->port = (unsigned long) KN01_DZ11_BASE; else info->port = (unsigned long) KN02_DZ11_BASE; info->line = i; info->tty = 0; info->close_delay = 50; info->closing_wait = 3000; info->x_char = 0; info->event = 0; info->count = 0; info->blocked_open = 0; info->tqueue.routine = do_softint; info->tqueue.data = info; info->tqueue_hangup.routine = do_serial_hangup; info->tqueue_hangup.data = info; info->callout_termios = callout_driver.init_termios; info->normal_termios = serial_driver.init_termios; init_waitqueue_head(&info->open_wait); init_waitqueue_head(&info->close_wait); /* * If we are pointing to address zero then punt - not correctly * set up in setup.c to handle this. */ if (!info->port) return 0; printk("ttyS%02d at 0x%08x (irq = %d)\n", info->line, info->port, dec_interrupt[DEC_IRQ_DZ11]); tty_register_devfs(&serial_driver, 0, serial_driver.minor_start + info->line); tty_register_devfs(&callout_driver, 0, callout_driver.minor_start + info->line); } /* reset the chip */ #ifndef CONFIG_SERIAL_DEC_CONSOLE dz_out(info, DZ_CSR, DZ_CLR); while (dz_in(info, DZ_CSR) & DZ_CLR); iob(); /* enable scanning */ dz_out(info, DZ_CSR, DZ_MSE); #endif /* order matters here... the trick is that flags is updated... in request_irq - to immediatedly obliterate it is unwise. */ restore_flags(flags); if (request_irq(dec_interrupt[DEC_IRQ_DZ11], dz_interrupt, SA_INTERRUPT, "DZ", lines[0])) panic("Unable to register DZ interrupt"); return 0; }