static inline void n_tty_receive_break(struct tty_struct *tty) { if (I_IGNBRK(tty)) return; if (I_BRKINT(tty)) { isig(SIGINT, tty, 1); return; } if (I_PARMRK(tty)) { put_tty_queue('\377', tty); put_tty_queue('\0', tty); } put_tty_queue('\0', tty); wake_up_interruptible(&tty->read_wait); }
static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old) { int canon_change = 1; BUG_ON(!tty); if (old) canon_change = (old->c_lflag ^ tty->termios->c_lflag) & ICANON; if (canon_change) { memset(&tty->read_flags, 0, sizeof tty->read_flags); tty->canon_head = tty->read_tail; tty->canon_data = 0; tty->erasing = 0; } if (canon_change && !L_ICANON(tty) && tty->read_cnt) wake_up_interruptible(&tty->read_wait); tty->icanon = (L_ICANON(tty) != 0); if (test_bit(TTY_HW_COOK_IN, &tty->flags)) { tty->raw = 1; tty->real_raw = 1; n_tty_set_room(tty); return; } if (I_ISTRIP(tty) || I_IUCLC(tty) || I_IGNCR(tty) || I_ICRNL(tty) || I_INLCR(tty) || L_ICANON(tty) || I_IXON(tty) || L_ISIG(tty) || L_ECHO(tty) || I_PARMRK(tty)) { memset(tty->process_char_map, 0, 256/8); if (I_IGNCR(tty) || I_ICRNL(tty)) set_bit('\r', tty->process_char_map); if (I_INLCR(tty)) set_bit('\n', tty->process_char_map); if (L_ICANON(tty)) { set_bit(ERASE_CHAR(tty), tty->process_char_map); set_bit(KILL_CHAR(tty), tty->process_char_map); set_bit(EOF_CHAR(tty), tty->process_char_map); set_bit('\n', tty->process_char_map); set_bit(EOL_CHAR(tty), tty->process_char_map); if (L_IEXTEN(tty)) { set_bit(WERASE_CHAR(tty), tty->process_char_map); set_bit(LNEXT_CHAR(tty), tty->process_char_map); set_bit(EOL2_CHAR(tty), tty->process_char_map); if (L_ECHO(tty)) set_bit(REPRINT_CHAR(tty), tty->process_char_map); } } if (I_IXON(tty)) { set_bit(START_CHAR(tty), tty->process_char_map); set_bit(STOP_CHAR(tty), tty->process_char_map); } if (L_ISIG(tty)) { set_bit(INTR_CHAR(tty), tty->process_char_map); set_bit(QUIT_CHAR(tty), tty->process_char_map); set_bit(SUSP_CHAR(tty), tty->process_char_map); } clear_bit(__DISABLED_CHAR, tty->process_char_map); tty->raw = 0; tty->real_raw = 0; } else { tty->raw = 1; if ((I_IGNBRK(tty) || (!I_BRKINT(tty) && !I_PARMRK(tty))) && (I_IGNPAR(tty) || !I_INPCK(tty)) && (tty->driver->flags & TTY_DRIVER_REAL_RAW)) tty->real_raw = 1; else tty->real_raw = 0; } n_tty_set_room(tty); wake_up_interruptible(&tty->write_wait); wake_up_interruptible(&tty->read_wait); }
/* * This routine is called to set the UART divisor registers to match * the specified baud rate for a serial port. */ static void change_speed(struct tty_struct *tty, struct serial_state *info, struct ktermios *old_termios) { struct tty_port *port = &info->tport; int quot = 0, baud_base, baud; unsigned cflag, cval = 0; int bits; unsigned long flags; cflag = tty->termios->c_cflag; /* Byte size is always 8 bits plus parity bit if requested */ cval = 3; bits = 10; if (cflag & CSTOPB) { cval |= 0x04; bits++; } if (cflag & PARENB) { cval |= UART_LCR_PARITY; bits++; } if (!(cflag & PARODD)) cval |= UART_LCR_EPAR; #ifdef CMSPAR if (cflag & CMSPAR) cval |= UART_LCR_SPAR; #endif /* Determine divisor based on baud rate */ baud = tty_get_baud_rate(tty); if (!baud) baud = 9600; /* B0 transition handled in rs_set_termios */ baud_base = info->baud_base; if (baud == 38400 && (port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) quot = info->custom_divisor; else { if (baud == 134) /* Special case since 134 is really 134.5 */ quot = (2*baud_base / 269); else if (baud) quot = baud_base / baud; } /* If the quotient is zero refuse the change */ if (!quot && old_termios) { /* FIXME: Will need updating for new tty in the end */ tty->termios->c_cflag &= ~CBAUD; tty->termios->c_cflag |= (old_termios->c_cflag & CBAUD); baud = tty_get_baud_rate(tty); if (!baud) baud = 9600; if (baud == 38400 && (port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) quot = info->custom_divisor; else { if (baud == 134) /* Special case since 134 is really 134.5 */ quot = (2*baud_base / 269); else if (baud) quot = baud_base / baud; } } /* As a last resort, if the quotient is zero, default to 9600 bps */ if (!quot) quot = baud_base / 9600; info->quot = quot; info->timeout = ((info->xmit_fifo_size*HZ*bits*quot) / baud_base); info->timeout += HZ/50; /* Add .02 seconds of slop */ /* CTS flow control flag and modem status interrupts */ info->IER &= ~UART_IER_MSI; if (port->flags & ASYNC_HARDPPS_CD) info->IER |= UART_IER_MSI; if (cflag & CRTSCTS) { port->flags |= ASYNC_CTS_FLOW; info->IER |= UART_IER_MSI; } else port->flags &= ~ASYNC_CTS_FLOW; if (cflag & CLOCAL) port->flags &= ~ASYNC_CHECK_CD; else { port->flags |= ASYNC_CHECK_CD; info->IER |= UART_IER_MSI; } /* TBD: * Does clearing IER_MSI imply that we should disable the VBL interrupt ? */ /* * Set up parity check flag */ info->read_status_mask = UART_LSR_OE | UART_LSR_DR; if (I_INPCK(tty)) info->read_status_mask |= UART_LSR_FE | UART_LSR_PE; if (I_BRKINT(tty) || I_PARMRK(tty)) info->read_status_mask |= UART_LSR_BI; /* * Characters to ignore */ info->ignore_status_mask = 0; if (I_IGNPAR(tty)) info->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; if (I_IGNBRK(tty)) { info->ignore_status_mask |= UART_LSR_BI; /* * If we're ignore parity and break indicators, ignore * overruns too. (For real raw support). */ if (I_IGNPAR(tty)) info->ignore_status_mask |= UART_LSR_OE; } /* * !!! ignore all characters if CREAD is not set */ if ((cflag & CREAD) == 0) info->ignore_status_mask |= UART_LSR_DR; local_irq_save(flags); { short serper; /* Set up the baud rate */ serper = quot - 1; /* Enable or disable parity bit */ if(cval & UART_LCR_PARITY) serper |= (SERPER_PARENB); custom.serper = serper; mb(); } local_irq_restore(flags); }
/* * Function ircomm_tty_change_speed (driver) * * Change speed of the driver. If the remote device is a DCE, then this * should make it change the speed of its serial port */ static void ircomm_tty_change_speed(struct ircomm_tty_cb *self) { unsigned cflag, cval; int baud; IRDA_DEBUG(2, "%s()\n", __func__ ); if (!self->tty || !self->tty->termios || !self->ircomm) return; cflag = self->tty->termios->c_cflag; /* byte size and parity */ switch (cflag & CSIZE) { case CS5: cval = IRCOMM_WSIZE_5; break; case CS6: cval = IRCOMM_WSIZE_6; break; case CS7: cval = IRCOMM_WSIZE_7; break; case CS8: cval = IRCOMM_WSIZE_8; break; default: cval = IRCOMM_WSIZE_5; break; } if (cflag & CSTOPB) cval |= IRCOMM_2_STOP_BIT; if (cflag & PARENB) cval |= IRCOMM_PARITY_ENABLE; if (!(cflag & PARODD)) cval |= IRCOMM_PARITY_EVEN; /* Determine divisor based on baud rate */ baud = tty_get_baud_rate(self->tty); if (!baud) baud = 9600; /* B0 transition handled in rs_set_termios */ self->settings.data_rate = baud; ircomm_param_request(self, IRCOMM_DATA_RATE, FALSE); /* CTS flow control flag and modem status interrupts */ if (cflag & CRTSCTS) { self->flags |= ASYNC_CTS_FLOW; self->settings.flow_control |= IRCOMM_RTS_CTS_IN; /* This got me. Bummer. Jean II */ if (self->service_type == IRCOMM_3_WIRE_RAW) IRDA_WARNING("%s(), enabling RTS/CTS on link that doesn't support it (3-wire-raw)\n", __func__); } else { self->flags &= ~ASYNC_CTS_FLOW; self->settings.flow_control &= ~IRCOMM_RTS_CTS_IN; } if (cflag & CLOCAL) self->flags &= ~ASYNC_CHECK_CD; else self->flags |= ASYNC_CHECK_CD; #if 0 /* * Set up parity check flag */ if (I_INPCK(self->tty)) driver->read_status_mask |= LSR_FE | LSR_PE; if (I_BRKINT(driver->tty) || I_PARMRK(driver->tty)) driver->read_status_mask |= LSR_BI; /* * Characters to ignore */ driver->ignore_status_mask = 0; if (I_IGNPAR(driver->tty)) driver->ignore_status_mask |= LSR_PE | LSR_FE; if (I_IGNBRK(self->tty)) { self->ignore_status_mask |= LSR_BI; /* * If we're ignore parity and break indicators, ignore * overruns too. (For real raw support). */ if (I_IGNPAR(self->tty)) self->ignore_status_mask |= LSR_OE; } #endif self->settings.data_format = cval; ircomm_param_request(self, IRCOMM_DATA_FORMAT, FALSE); ircomm_param_request(self, IRCOMM_FLOW_CONTROL, TRUE); }
static void n_tty_set_termios(struct tty_struct *tty, struct termios * old) { if (!tty) return; tty->icanon = (L_ICANON(tty) != 0); if (test_bit(TTY_HW_COOK_IN, &tty->flags)) { tty->raw = 1; tty->real_raw = 1; return; } if (I_ISTRIP(tty) || I_IUCLC(tty) || I_IGNCR(tty) || I_ICRNL(tty) || I_INLCR(tty) || L_ICANON(tty) || I_IXON(tty) || L_ISIG(tty) || L_ECHO(tty) || I_PARMRK(tty)) { cli(); memset(tty->process_char_map, 0, 256/8); if (I_IGNCR(tty) || I_ICRNL(tty)) set_bit('\r', &tty->process_char_map); if (I_INLCR(tty)) set_bit('\n', &tty->process_char_map); if (L_ICANON(tty)) { set_bit(ERASE_CHAR(tty), &tty->process_char_map); set_bit(KILL_CHAR(tty), &tty->process_char_map); set_bit(EOF_CHAR(tty), &tty->process_char_map); set_bit('\n', &tty->process_char_map); set_bit(EOL_CHAR(tty), &tty->process_char_map); if (L_IEXTEN(tty)) { set_bit(WERASE_CHAR(tty), &tty->process_char_map); set_bit(LNEXT_CHAR(tty), &tty->process_char_map); set_bit(EOL2_CHAR(tty), &tty->process_char_map); if (L_ECHO(tty)) set_bit(REPRINT_CHAR(tty), &tty->process_char_map); } } if (I_IXON(tty)) { set_bit(START_CHAR(tty), &tty->process_char_map); set_bit(STOP_CHAR(tty), &tty->process_char_map); } if (L_ISIG(tty)) { set_bit(INTR_CHAR(tty), &tty->process_char_map); set_bit(QUIT_CHAR(tty), &tty->process_char_map); set_bit(SUSP_CHAR(tty), &tty->process_char_map); } clear_bit(__DISABLED_CHAR, &tty->process_char_map); sti(); tty->raw = 0; tty->real_raw = 0; } else { tty->raw = 1; if ((I_IGNBRK(tty) || (!I_BRKINT(tty) && !I_PARMRK(tty))) && (I_IGNPAR(tty) || !I_INPCK(tty)) && (tty->driver.flags & TTY_DRIVER_REAL_RAW)) tty->real_raw = 1; else tty->real_raw = 0; } }
/* * This routine is called to set the UART divisor registers to match * the specified baud rate for a serial port. */ static void change_speed(ser_info_t *info) { int baud_rate; unsigned cflag, cval, scval, prev_mode; int i, bits, sbits, idx; unsigned long flags; struct serial_state *state; volatile struct smc_regs *smcp; volatile struct scc_regs *sccp; if (!info->port.tty || !info->port.tty->termios) return; cflag = info->port.tty->termios->c_cflag; state = info->state; /* Character length programmed into the mode register is the * sum of: 1 start bit, number of data bits, 0 or 1 parity bit, * 1 or 2 stop bits, minus 1. * The value 'bits' counts this for us. */ cval = 0; scval = 0; /* byte size and parity */ switch (cflag & CSIZE) { case CS5: bits = 5; break; case CS6: bits = 6; break; case CS7: bits = 7; break; case CS8: bits = 8; break; /* Never happens, but GCC is too dumb to figure it out */ default: bits = 8; break; } sbits = bits - 5; if (cflag & CSTOPB) { cval |= SMCMR_SL; /* Two stops */ scval |= SCU_PMSR_SL; bits++; } if (cflag & PARENB) { cval |= SMCMR_PEN; scval |= SCU_PMSR_PEN; bits++; } if (!(cflag & PARODD)) { cval |= SMCMR_PM_EVEN; scval |= (SCU_PMSR_REVP | SCU_PMSR_TEVP); } /* Determine divisor based on baud rate */ i = cflag & CBAUD; if (i >= (sizeof(baud_table)/sizeof(int))) baud_rate = 9600; else baud_rate = baud_table[i]; info->timeout = (TX_BUF_SIZE*HZ*bits); info->timeout += HZ/50; /* Add .02 seconds of slop */ #ifdef modem_control /* CTS flow control flag and modem status interrupts */ info->IER &= ~UART_IER_MSI; if (info->flags & ASYNC_HARDPPS_CD) info->IER |= UART_IER_MSI; if (cflag & CRTSCTS) { info->flags |= ASYNC_CTS_FLOW; info->IER |= UART_IER_MSI; } else info->flags &= ~ASYNC_CTS_FLOW; if (cflag & CLOCAL) info->flags &= ~ASYNC_CHECK_CD; else { info->flags |= ASYNC_CHECK_CD; info->IER |= UART_IER_MSI; } serial_out(info, UART_IER, info->IER); #endif /* * Set up parity check flag */ info->read_status_mask = (BD_SC_EMPTY | BD_SC_OV); if (I_INPCK(info->port.tty)) info->read_status_mask |= BD_SC_FR | BD_SC_PR; if (I_BRKINT(info->port.tty) || I_PARMRK(info->port.tty)) info->read_status_mask |= BD_SC_BR; /* * Characters to ignore */ info->ignore_status_mask = 0; if (I_IGNPAR(info->port.tty)) info->ignore_status_mask |= BD_SC_PR | BD_SC_FR; if (I_IGNBRK(info->port.tty)) { info->ignore_status_mask |= BD_SC_BR; /* * If we're ignore parity and break indicators, ignore * overruns too. (For real raw support). */ if (I_IGNPAR(info->port.tty)) info->ignore_status_mask |= BD_SC_OV; } /* * !!! ignore all characters if CREAD is not set */ if ((cflag & CREAD) == 0) info->read_status_mask &= ~BD_SC_EMPTY; local_irq_save(flags); /* Start bit has not been added (so don't, because we would just * subtract it later), and we need to add one for the number of * stops bits (there is always at least one). */ bits++; idx = PORT_NUM(state->smc_scc_num); if (state->smc_scc_num & NUM_IS_SCC) { sccp = &pquicc->scc_regs[idx]; sccp->scc_psmr = (sbits << 12) | scval; } else { smcp = &pquicc->smc_regs[idx]; /* Set the mode register. We want to keep a copy of the * enables, because we want to put them back if they were * present. */ prev_mode = smcp->smc_smcmr; smcp->smc_smcmr = smcr_mk_clen(bits) | cval | SMCMR_SM_UART; smcp->smc_smcmr |= (prev_mode & (SMCMR_REN | SMCMR_TEN)); } m360_cpm_setbrg((state - rs_table), baud_rate); local_irq_restore(flags); }
static void copy_to_cooked(struct tty_struct * tty) { int c, special_flag; unsigned long flags; if (!tty) { printk("copy_to_cooked: called with NULL tty\n"); return; } if (!tty->write) { printk("copy_to_cooked: tty %d has null write routine\n", tty->line); } while (1) { /* * Check to see how much room we have left in the * secondary queue. Send a throttle command or abort * if necessary. */ c = LEFT(&tty->secondary); if (tty->throttle && (c < SQ_THRESHOLD_LW) && !set_bit(TTY_SQ_THROTTLED, &tty->flags)) tty->throttle(tty, TTY_THROTTLE_SQ_FULL); if (c == 0) break; save_flags(flags); cli(); if (!EMPTY(&tty->read_q)) { c = tty->read_q.buf[tty->read_q.tail]; special_flag = clear_bit(tty->read_q.tail, &tty->readq_flags); INC(tty->read_q.tail); restore_flags(flags); } else { restore_flags(flags); break; } if (special_flag) { tty->char_error = c; continue; } if (tty->char_error) { if (tty->char_error == TTY_BREAK) { tty->char_error = 0; if (I_IGNBRK(tty)) continue; /* A break is handled by the lower levels. */ if (I_BRKINT(tty)) continue; if (I_PARMRK(tty)) { put_tty_queue('\377', &tty->secondary); put_tty_queue('\0', &tty->secondary); } put_tty_queue('\0', &tty->secondary); continue; } if (tty->char_error == TTY_OVERRUN) { tty->char_error = 0; printk("tty%d: input overrun\n", tty->line); continue; } /* Must be a parity or frame error */ tty->char_error = 0; if (I_IGNPAR(tty)) { continue; } if (I_PARMRK(tty)) { put_tty_queue('\377', &tty->secondary); put_tty_queue('\0', &tty->secondary); put_tty_queue(c, &tty->secondary); } else put_tty_queue('\0', &tty->secondary); continue; } if (I_ISTRIP(tty)) c &= 0x7f; if (!tty->lnext) { if (c == '\r') { if (I_IGNCR(tty)) continue; if (I_ICRNL(tty)) c = '\n'; } else if (c == '\n' && I_INLCR(tty)) c = '\r'; } if (I_IUCLC(tty) && L_IEXTEN(tty)) c=tolower(c); if (c == __DISABLED_CHAR) tty->lnext = 1; if (L_ICANON(tty) && !tty->lnext) { if (c == ERASE_CHAR(tty) || c == KILL_CHAR(tty) || (c == WERASE_CHAR(tty) && L_IEXTEN(tty))) { eraser(c, tty); continue; } if (c == LNEXT_CHAR(tty) && L_IEXTEN(tty)) { tty->lnext = 1; if (L_ECHO(tty)) { if (tty->erasing) { opost('/', tty); tty->erasing = 0; } if (L_ECHOCTL(tty)) { opost('^', tty); opost('\b', tty); } } continue; } if (c == REPRINT_CHAR(tty) && L_ECHO(tty) && L_IEXTEN(tty)) { unsigned long tail = tty->canon_head; if (tty->erasing) { opost('/', tty); tty->erasing = 0; } echo_char(c, tty); opost('\n', tty); while (tail != tty->secondary.head) { echo_char(tty->secondary.buf[tail], tty); INC(tail); } continue; } } if (I_IXON(tty) && !tty->lnext) { if ((tty->stopped && I_IXANY(tty) && L_IEXTEN(tty)) || c == START_CHAR(tty)) { start_tty(tty); continue; } if (c == STOP_CHAR(tty)) { stop_tty(tty); continue; } } if (L_ISIG(tty) && !tty->lnext) { if (c == INTR_CHAR(tty)) { isig(SIGINT, tty); continue; } if (c == QUIT_CHAR(tty)) { isig(SIGQUIT, tty); continue; } if (c == SUSP_CHAR(tty)) { if (!is_orphaned_pgrp(tty->pgrp)) isig(SIGTSTP, tty); continue; } } if (tty->erasing) { opost('/', tty); tty->erasing = 0; } if (c == '\n' && !tty->lnext) { if (L_ECHO(tty) || (L_ICANON(tty) && L_ECHONL(tty))) opost('\n', tty); } else if (L_ECHO(tty)) { /* Don't echo the EOF char in canonical mode. Sun handles this differently by echoing the char and then backspacing, but that's a hack. */ if (c != EOF_CHAR(tty) || !L_ICANON(tty) || tty->lnext) { /* Record the column of first canon char. */ if (tty->canon_head == tty->secondary.head) tty->canon_column = tty->column; echo_char(c, tty); } } if (I_PARMRK(tty) && c == (unsigned char) '\377' && (c != EOF_CHAR(tty) || !L_ICANON(tty) || tty->lnext)) put_tty_queue(c, &tty->secondary); if (L_ICANON(tty) && !tty->lnext && (c == '\n' || c == EOF_CHAR(tty) || c == EOL_CHAR(tty) || (c == EOL2_CHAR(tty) && L_IEXTEN(tty)))) { if (c == EOF_CHAR(tty)) c = __DISABLED_CHAR; set_bit(tty->secondary.head, &tty->secondary_flags); put_tty_queue(c, &tty->secondary); tty->canon_head = tty->secondary.head; tty->canon_data++; } else put_tty_queue(c, &tty->secondary); tty->lnext = 0; } if (!EMPTY(&tty->write_q)) TTY_WRITE_FLUSH(tty); if (L_ICANON(tty) ? tty->canon_data : !EMPTY(&tty->secondary)) wake_up_interruptible(&tty->secondary.proc_list); if (tty->throttle && (LEFT(&tty->read_q) >= RQ_THRESHOLD_HW) && clear_bit(TTY_RQ_THROTTLED, &tty->flags)) tty->throttle(tty, TTY_THROTTLE_RQ_AVAIL); }
static void send_intr(void) { if (!tty || (tty->termios && I_IGNBRK(tty))) return; tty_insert_flip_char(tty, 0, TTY_BREAK); }
void ipoctal_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { unsigned int cflag; unsigned char mr1 = 0; unsigned char mr2 = 0; unsigned char csr = 0; unsigned char imr = 0; unsigned char imr_brk = 0; unsigned int channel = tty->index; int index = *(int *)tty->driver_data; struct ipoctal *ipoctal; int block = channel / 2; ipoctal = &ipoctal_installed[index]; cflag = tty->termios->c_cflag; if (old_termios) { if((cflag == old_termios->c_cflag) && (RELEVANT_IFLAG(tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) return; } ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.w.cr, CR_DISABLE_RX | CR_DISABLE_TX); ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[channel].u.w.cr, CR_CMD_RESET_RX); ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[channel].u.w.cr, CR_CMD_RESET_TX); ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[channel].u.w.cr, CR_CMD_RESET_ERR_STATUS); ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[channel].u.w.cr, CR_CMD_RESET_MR); /* Set Bits per chars */ switch(cflag & CSIZE) { case CS6 : mr1 |= MR1_CHRL_6_BITS; break; case CS7 : mr1 |= MR1_CHRL_7_BITS; break; default: case CS8 : mr1 |= MR1_CHRL_8_BITS; break; break; } /* Set Parity */ if (cflag & PARENB) if(cflag & PARODD) mr1 |= MR1_PARITY_ON | MR1_PARITY_ODD; else mr1 |= MR1_PARITY_ON | MR1_PARITY_EVEN; else mr1 |= MR1_PARITY_OFF; /* Set stop bits */ if (cflag & CSTOPB) mr2 |= MR2_STOP_BITS_LENGTH_2; else mr2 |= MR2_STOP_BITS_LENGTH_1; /* Set the flow control */ switch(ipoctal->board_id) { case IP_OCTAL_232_ID : if (cflag & CRTSCTS) { mr1 |= MR1_RxRTS_CONTROL_ON; mr2 |= MR2_TxRTS_CONTROL_OFF | MR2_CTS_ENABLE_TX_ON; ipoctal->chan_config[channel].flow_control = 1; } else { mr1 |= MR1_RxRTS_CONTROL_OFF; mr2 |= MR2_TxRTS_CONTROL_OFF | MR2_CTS_ENABLE_TX_OFF; ipoctal->chan_config[channel].flow_control = 0; } break; case IP_OCTAL_422_ID : mr1 |= MR1_RxRTS_CONTROL_OFF; mr2 |= MR2_TxRTS_CONTROL_OFF | MR2_CTS_ENABLE_TX_OFF; ipoctal->chan_config[channel].flow_control = 0; break; case IP_OCTAL_485_ID : mr1 |= MR1_RxRTS_CONTROL_OFF; mr2 |= MR2_TxRTS_CONTROL_ON | MR2_CTS_ENABLE_TX_OFF; ipoctal->chan_config[channel].flow_control = 0; break; default: return; break; } /* Set baud rate */ switch(tty_get_baud_rate(tty)) { case 75: csr |= TX_CLK_75 | RX_CLK_75; break; case 110: csr |= TX_CLK_110 | RX_CLK_110; break; case 150: csr |= TX_CLK_150 | RX_CLK_150; break; case 300: csr |= TX_CLK_300 | RX_CLK_300; break; case 600: csr |= TX_CLK_600 | RX_CLK_600; break; case 1200: csr |= TX_CLK_1200 | RX_CLK_1200; break; case 1800: csr |= TX_CLK_1800 | RX_CLK_1800; break; case 2000: csr |= TX_CLK_2000 | RX_CLK_2000; break; case 2400: csr |= TX_CLK_2400 | RX_CLK_2400; break; case 4800: csr |= TX_CLK_4800 | RX_CLK_4800; break; case 9600: csr |= TX_CLK_9600 | RX_CLK_9600; break; case 19200: csr |= TX_CLK_19200 | RX_CLK_19200; break; case 38400: csr |= TX_CLK_38400 | RX_CLK_38400; break; default: printk(KERN_ERR PFX "Slot [%d:%d] Channel %c : Illegal baud rate value: %d !\n", ipoctal->slot_id->carrier_number, ipoctal->slot_id->slot_position, 'a'+channel, tty_get_baud_rate(tty)); return; } /* Set ignore break status */ imr = ipoctal_read_io_reg( ipoctal, &ipoctal->block_regs[block].u.w.imr); if((channel % 2) == 1) imr_brk = IMR_DELTA_BREAK_B; else imr_brk = IMR_DELTA_BREAK_A; if (I_IGNBRK(tty)) imr &= ~imr_brk; else imr |= imr_brk; ipoctal_write_io_reg( ipoctal, &ipoctal->block_regs[block].u.w.imr, imr); mr1 |= MR1_ERROR_CHAR; mr1 |= MR1_RxINT_RxRDY; ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.w.mr, mr1); ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.w.mr, mr2); ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.w.csr, csr); ipoctal->chan_config[channel].baud = tty_get_baud_rate(tty); ipoctal->chan_config[channel].bits_per_char = cflag & CSIZE; ipoctal->chan_config[channel].parity = cflag & PARENB; ipoctal->chan_config[channel].stop_bits = cflag & CSTOPB; }
/* * This routine is called to set the UART divisor registers to match * the specified baud rate for a serial port. */ static void change_speed(struct async_struct *info) { unsigned cflag; int line; mach_port_t device_port; kern_return_t kr; struct tty_status ttstat; mach_msg_type_number_t ttstat_count; if (!info->tty || !info->tty->termios) return; cflag = info->tty->termios->c_cflag; line = MINOR(info->tty->device) - info->tty->driver.minor_start; device_port = info->device_port; ttstat_count = TTY_STATUS_COUNT; if (device_port != MACH_PORT_NULL) { kr = device_get_status(device_port, TTY_STATUS_NEW, (dev_status_t) &ttstat, &ttstat_count); if (kr != D_SUCCESS) { MACH3_DEBUG(1, kr, ("change_speed(dev 0x%x): " "device_get_status(TTY_STATUS_NEW)", info->tty->device)); return; } } /* Mach break handling is obsolete with "new" out-of-band. */ ttstat.tt_breakc = 0; ttstat.tt_flags &= ~(TF_ODDP | TF_EVENP | TF_LITOUT | TF_NOHANG | TF_8BIT | TF_READ | TF_HUPCLS | TF_OUT_OF_BAND | TF_INPCK | TF_CRTSCTS); ttstat.tt_flags |= TF_OUT_OF_BAND; /* we always want OUT_OF_BAND */ /* Convert from POSIX to MACH speed */ if ((cflag & CBAUD) < (sizeof(baud_table)/sizeof(baud_table[0]))) ttstat.tt_ispeed = ttstat.tt_ospeed = baud_table[cflag & CBAUD]; else /* Largest possible baud rate (for the moment) */ ttstat.tt_ispeed = ttstat.tt_ospeed = 230400; if (cflag & CRTSCTS) { info->flags |= ASYNC_CTS_FLOW; } else info->flags &= ~ASYNC_CTS_FLOW; if (cflag & CLOCAL) info->flags &= ~ASYNC_CHECK_CD; else { info->flags |= ASYNC_CHECK_CD; } #define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) if (I_INPCK(info->tty)) info->read_status_mask |= UART_LSR_FE | UART_LSR_PE; if (I_BRKINT(info->tty) || I_PARMRK(info->tty)) info->read_status_mask |= UART_LSR_BI; info->ignore_status_mask = 0; if (I_IGNPAR(info->tty)) { info->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; info->read_status_mask |= UART_LSR_PE | UART_LSR_FE; } if (I_IGNBRK(info->tty)) { info->ignore_status_mask |= UART_LSR_BI; info->read_status_mask |= UART_LSR_BI; /* * If we're ignore parity and break indicators, ignore * overruns too. (For real raw support). */ if (I_IGNPAR(info->tty)) { info->ignore_status_mask |= UART_LSR_OE; info->read_status_mask |= UART_LSR_OE; } } if (cflag & PARENB) { ttstat.tt_flags |= TF_INPCK; ttstat.tt_flags |= (cflag & PARODD) ? TF_ODDP : TF_EVENP; } if ((cflag & CSIZE) != CS7) { /* assume CS8 */ ttstat.tt_flags |= TF_LITOUT | TF_8BIT; } if (cflag & CLOCAL) ttstat.tt_flags |= TF_NOHANG; if (cflag & CREAD) ttstat.tt_flags |= TF_READ; if (cflag & HUPCL) ttstat.tt_flags |= TF_HUPCLS; if (cflag & CRTSCTS) ttstat.tt_flags |= TF_CRTSCTS; if (device_port != MACH_PORT_NULL) { kr = device_set_status(device_port, TTY_STATUS_NEW, (dev_status_t) &ttstat, ttstat_count); if (kr != D_SUCCESS) { MACH3_DEBUG(1, kr, ("change_speed(dev 0x%x): " "device_set_status(TTY_STATUS_NEW)", info->tty->device)); } } }