static void mxu1_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios) { struct mxu1_port *mxport = usb_get_serial_port_data(port); struct mxu1_uart_config *config; tcflag_t cflag, iflag; speed_t baud; int status; unsigned int mcr; dev_dbg(&port->dev, "%s\n", __func__); cflag = tty->termios.c_cflag; iflag = tty->termios.c_iflag; if (old_termios && !tty_termios_hw_change(&tty->termios, old_termios) && tty->termios.c_iflag == old_termios->c_iflag) { dev_dbg(&port->dev, "%s - nothing to change\n", __func__); return; } dev_dbg(&port->dev, "%s - clfag %08x, iflag %08x\n", __func__, cflag, iflag); if (old_termios) { dev_dbg(&port->dev, "%s - old clfag %08x, old iflag %08x\n", __func__, old_termios->c_cflag, old_termios->c_iflag); } config = kzalloc(sizeof(*config), GFP_KERNEL); if (!config) return; config->wFlags = 0; /* these flags must be set */ config->wFlags |= MXU1_UART_ENABLE_MS_INTS; config->wFlags |= MXU1_UART_ENABLE_AUTO_START_DMA; if (mxport->mxp_send_break == MXU1_LCR_BREAK) config->wFlags |= MXU1_UART_SEND_BREAK_SIGNAL; config->bUartMode = (u8)(mxport->mxp_uart_mode); switch (C_CSIZE(tty)) { case CS5: config->bDataBits = MXU1_UART_5_DATA_BITS; break; case CS6: config->bDataBits = MXU1_UART_6_DATA_BITS; break; case CS7: config->bDataBits = MXU1_UART_7_DATA_BITS; break; default: case CS8: config->bDataBits = MXU1_UART_8_DATA_BITS; break; } if (C_PARENB(tty)) { config->wFlags |= MXU1_UART_ENABLE_PARITY_CHECKING; if (C_CMSPAR(tty)) { if (C_PARODD(tty)) config->bParity = MXU1_UART_MARK_PARITY; else config->bParity = MXU1_UART_SPACE_PARITY; } else { if (C_PARODD(tty)) config->bParity = MXU1_UART_ODD_PARITY; else config->bParity = MXU1_UART_EVEN_PARITY; } } else { config->bParity = MXU1_UART_NO_PARITY; } if (C_CSTOPB(tty)) config->bStopBits = MXU1_UART_2_STOP_BITS; else config->bStopBits = MXU1_UART_1_STOP_BITS; if (C_CRTSCTS(tty)) { /* RTS flow control must be off to drop RTS for baud rate B0 */ if (C_BAUD(tty) != B0) config->wFlags |= MXU1_UART_ENABLE_RTS_IN; config->wFlags |= MXU1_UART_ENABLE_CTS_OUT; } if (I_IXOFF(tty) || I_IXON(tty)) { config->cXon = START_CHAR(tty); config->cXoff = STOP_CHAR(tty); if (I_IXOFF(tty)) config->wFlags |= MXU1_UART_ENABLE_X_IN; if (I_IXON(tty)) config->wFlags |= MXU1_UART_ENABLE_X_OUT; } baud = tty_get_baud_rate(tty); if (!baud) baud = 9600; config->wBaudRate = MXU1_BAUD_BASE / baud; dev_dbg(&port->dev, "%s - BaudRate=%d, wBaudRate=%d, wFlags=0x%04X, bDataBits=%d, bParity=%d, bStopBits=%d, cXon=%d, cXoff=%d, bUartMode=%d\n", __func__, baud, config->wBaudRate, config->wFlags, config->bDataBits, config->bParity, config->bStopBits, config->cXon, config->cXoff, config->bUartMode); cpu_to_be16s(&config->wBaudRate); cpu_to_be16s(&config->wFlags); status = mxu1_send_ctrl_data_urb(port->serial, MXU1_SET_CONFIG, 0, MXU1_UART1_PORT, (u8 *)config, sizeof(*config)); if (status) dev_err(&port->dev, "cannot set config: %d\n", status); mutex_lock(&mxport->mxp_mutex); mcr = mxport->mxp_mcr; if (C_BAUD(tty) == B0) mcr &= ~(MXU1_MCR_DTR | MXU1_MCR_RTS); else if (old_termios && (old_termios->c_cflag & CBAUD) == B0) mcr |= ~(MXU1_MCR_DTR | MXU1_MCR_RTS); status = mxu1_set_mcr(port, mcr); if (status) dev_err(&port->dev, "cannot set modem control: %d\n", status); else mxport->mxp_mcr = mcr; mutex_unlock(&mxport->mxp_mutex); kfree(config); }
static void pl2303_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios) { struct usb_serial *serial = port->serial; struct pl2303_serial_private *spriv = usb_get_serial_data(serial); struct pl2303_private *priv = usb_get_serial_port_data(port); unsigned long flags; unsigned char *buf; int i; u8 control; if (old_termios && !tty_termios_hw_change(&tty->termios, old_termios)) return; buf = kzalloc(7, GFP_KERNEL); if (!buf) { dev_err(&port->dev, "%s - out of memory.\n", __func__); /* Report back no change occurred */ if (old_termios) tty->termios = *old_termios; return; } i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE, 0, 0, buf, 7, 100); dev_dbg(&port->dev, "0xa1:0x21:0:0 %d - %7ph\n", i, buf); switch (C_CSIZE(tty)) { case CS5: buf[6] = 5; break; case CS6: buf[6] = 6; break; case CS7: buf[6] = 7; break; default: case CS8: buf[6] = 8; } dev_dbg(&port->dev, "data bits = %d\n", buf[6]); /* For reference buf[0]:buf[3] baud rate value */ pl2303_encode_baudrate(tty, port, &buf[0]); /* For reference buf[4]=0 is 1 stop bits */ /* For reference buf[4]=1 is 1.5 stop bits */ /* For reference buf[4]=2 is 2 stop bits */ if (C_CSTOPB(tty)) { /* * NOTE: Comply with "real" UARTs / RS232: * use 1.5 instead of 2 stop bits with 5 data bits */ if (C_CSIZE(tty) == CS5) { buf[4] = 1; dev_dbg(&port->dev, "stop bits = 1.5\n"); } else { buf[4] = 2; dev_dbg(&port->dev, "stop bits = 2\n"); } } else { buf[4] = 0; dev_dbg(&port->dev, "stop bits = 1\n"); } if (C_PARENB(tty)) { /* For reference buf[5]=0 is none parity */ /* For reference buf[5]=1 is odd parity */ /* For reference buf[5]=2 is even parity */ /* For reference buf[5]=3 is mark parity */ /* For reference buf[5]=4 is space parity */ if (C_PARODD(tty)) { if (tty->termios.c_cflag & CMSPAR) { buf[5] = 3; dev_dbg(&port->dev, "parity = mark\n"); } else { buf[5] = 1; dev_dbg(&port->dev, "parity = odd\n"); } } else { if (tty->termios.c_cflag & CMSPAR) { buf[5] = 4; dev_dbg(&port->dev, "parity = space\n"); } else { buf[5] = 2; dev_dbg(&port->dev, "parity = even\n"); } } } else { buf[5] = 0; dev_dbg(&port->dev, "parity = none\n"); } /* * Some PL2303 are known to lose bytes if you change serial settings * even to the same values as before. Thus we actually need to filter * in this specific case. * * Note that the tty_termios_hw_change check above is not sufficient * as a previously requested baud rate may differ from the one * actually used (and stored in old_termios). * * NOTE: No additional locking needed for line_settings as it is * only used in set_termios, which is serialised against itself. */ if (!old_termios || memcmp(buf, priv->line_settings, 7)) { i = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE, 0, 0, buf, 7, 100); dev_dbg(&port->dev, "0x21:0x20:0:0 %d\n", i); if (i == 7) memcpy(priv->line_settings, buf, 7); } /* change control lines if we are switching to or from B0 */ spin_lock_irqsave(&priv->lock, flags); control = priv->line_control; if (C_BAUD(tty) == B0) priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS); else if (old_termios && (old_termios->c_cflag & CBAUD) == B0) priv->line_control |= (CONTROL_DTR | CONTROL_RTS); if (control != priv->line_control) { control = priv->line_control; spin_unlock_irqrestore(&priv->lock, flags); pl2303_set_control_lines(port, control); } else { spin_unlock_irqrestore(&priv->lock, flags); } memset(buf, 0, 7); i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE, 0, 0, buf, 7, 100); dev_dbg(&port->dev, "0xa1:0x21:0:0 %d - %7ph\n", i, buf); if (C_CRTSCTS(tty)) { if (spriv->type == HX) pl2303_vendor_write(0x0, 0x61, serial); else pl2303_vendor_write(0x0, 0x41, serial); } else { pl2303_vendor_write(0x0, 0x0, serial); } kfree(buf); }