struct ch341_private {
spinlock_t lock; /* access lock */
wait_queue_head_t delta_msr_wait; /* wait queue for modem status */
+ int delta_msr_cond;
unsigned baud_rate; /* set baud rate */
u8 line_control; /* set line control value RTS/DTR */
u8 line_status; /* active status of modem control inputs */
u8 multi_status_change; /* status changed multiple since last call */
- struct usb_device *dev;
+ struct usb_serial *serial;
};
static int ch341_control_out(struct usb_device *dev, u8 request,
}
static int ch341_set_baudrate(struct usb_device *dev,
+ struct tty_struct *tty,
struct ch341_private *priv)
{
short a, b;
int r;
unsigned long factor;
short divisor;
+ unsigned baud;
+ unsigned t1, t2;
dbg("ch341_set_baudrate(%d)", priv->baud_rate);
- if (!priv->baud_rate)
- return -EINVAL;
+ if (priv->baud_rate > CH341_BAUDBASE_FACTOR)
+ priv->baud_rate = CH341_BAUDBASE_FACTOR;
+
factor = (CH341_BAUDBASE_FACTOR / priv->baud_rate);
divisor = CH341_BAUDBASE_DIVMAX;
divisor--;
}
- if (factor > 0xfff0)
- return -EINVAL;
+ if (factor > 0xfff0) { /* Clamp */
+ factor = 0xfff0;
+ divisor = 0;
+ }
+
+ t1 = factor;
+ for (t2 = divisor; t2 <= CH341_BAUDBASE_DIVMAX; t2++) {
+ t1 >>= 3;
+ }
+ baud = CH341_BAUDBASE_FACTOR / t1;
+
+ if (baud && tty)
+ tty_encode_baud_rate(tty, baud, baud);
factor = 0x10000 - factor;
a = (factor & 0xff00) | divisor;
if (r < 0)
goto out;
- r = ch341_set_baudrate(dev, priv);
+ r = ch341_set_baudrate(dev, NULL, priv);
if (r < 0)
goto out;
if (r < 0)
goto out;
- r = ch341_set_baudrate(dev, priv);
+ r = ch341_set_baudrate(dev, NULL, priv);
if (r < 0)
goto out;
priv->baud_rate = DEFAULT_BAUD_RATE;
priv->line_control = CH341_BIT_RTS | CH341_BIT_DTR;
- priv->dev = serial->dev;
- priv->adapter.owner = THIS_MODULE;
+ priv->serial = serial;
r = ch341_configure(serial->dev, priv);
if (r < 0)
usb_set_serial_port_data(serial->port[0], priv);
- dev_info(&priv->adapter.dev, "connected ch341 device\n");
-
return 0;
error: kfree(priv);
{
struct ch341_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
- unsigned int c_cflag;
dbg("%s - port %d", __func__, port->number);
usb_kill_urb(port->interrupt_in_urb);
if (tty) {
- c_cflag = tty->termios->c_cflag;
- if (c_cflag & HUPCL) {
+ if (C_HUPCL(tty)) {
/* drop DTR and RTS */
spin_lock_irqsave(&priv->lock, flags);
priv->line_control = 0;
}
}
wake_up_interruptible(&priv->delta_msr_wait);
+ priv->delta_msr_cond = 1;
}
dbg("ch341_open()");
priv->baud_rate = DEFAULT_BAUD_RATE;
- priv->line_control = CH341_BIT_RTS | CH341_BIT_DTR;
+
+ if (C_CLOCAL(tty)) {
+ priv->line_control = CH341_BIT_RTS | CH341_BIT_DTR;
+ } else {
+ priv->line_control = 0;
+ }
r = ch341_configure(serial->dev, priv);
if (r)
if (r)
goto out;
- r = ch341_set_baudrate(serial->dev, priv);
+ r = ch341_set_baudrate(serial->dev, tty, priv);
if (r)
goto out;
dbg("ch341_set_termios()");
- if (!tty || !tty->termios)
+ if (!tty)
return;
baud_rate = tty_get_baud_rate(tty);
spin_lock_irqsave(&priv->lock, flags);
priv->line_control |= (CH341_BIT_DTR | CH341_BIT_RTS);
spin_unlock_irqrestore(&priv->lock, flags);
- ch341_set_baudrate(port->serial->dev, priv);
+ ch341_set_baudrate(port->serial->dev, tty, priv);
} else {
spin_lock_irqsave(&priv->lock, flags);
priv->line_control &= ~(CH341_BIT_DTR | CH341_BIT_RTS);
* (cflag & PARENB) : parity {NONE, EVEN, ODD}
* (cflag & CSTOPB) : stop bits [1, 2]
*/
+ tty->termios->c_cflag &= ~(CSIZE | PARENB | CSTOPB);
+
}
static int ch341_tiocmset(struct tty_struct *tty, struct file *file,
priv->multi_status_change = 1;
spin_unlock_irqrestore(&priv->lock, flags);
wake_up_interruptible(&priv->delta_msr_wait);
+ priv->delta_msr_cond = 1;
}
exit:
spin_unlock_irqrestore(&priv->lock, flags);
while (!multi_change) {
- interruptible_sleep_on(&priv->delta_msr_wait);
+ priv->delta_msr_cond = 0;
+ wait_event_interruptible(priv->delta_msr_wait,
+ (priv->delta_msr_cond == 1));
/* see if a signal did it */
if (signal_pending(current))
return -ERESTARTSYS;