USB-serial updates for v4.11-rc1

These updates include
 
  - a new driver for Renesas uPD78F0730-based devices
 
  - several fixes of failures to check for short transfers, some of which could
    lead to minor information leaks, and in one case a loop-condition underflow
 
  - a fix of a long-standing regression in the ftdi_sio driver which resulted
    in excessive bulk-in interrupts
 
  - a fix for ftdi_sio line-status over-reporting which could lead to an
    endless stream of NULL-characters being forwarded to user space
 
  - a fix for a regression in the console driver
 
  - a fix for another mos7840 NULL-pointer dereference due to a missing endpoint
    sanity check
 
 Included are also some clean ups and fixes for various minor issues, as well as
 a couple of new device IDs that came in late.
 
 All but the final patch have been in linux-next with no reported issues.
 
 Signed-off-by: Johan Hovold <johan@kernel.org>
 -----BEGIN PGP SIGNATURE-----
 
 iQIuBAABCAAYBQJYnGAqERxqb2hhbkBrZXJuZWwub3JnAAoJEEEN5E/e4bSVONQP
 /ixZnWgUgAkDk0lHuXwZvYrmXssM2cEAuN1CZkddKyp8h0LhNSVy8Nat4zGJh4kc
 Nvdln6qPunaKrCL0nV7uaBLRKlCYFmmMLwGRSXOXe3CkQ05oM+o5SOvI+f8qqHWZ
 efEUtfBc24FAp7gM521sQkPVK6bwj2OzaLXw2DVYhuPip5ZvjNHiqjvpjMddV8mz
 mF+tE/qpbIWWP+QXuMPUZ4+gDPA7rq+AIeWAH3JDtZIXCivJBlDYWbX8GGEy7kFU
 p50xSZfcLjcfpz0UGhFPfRXGbABjWegVzwWrRBngeXoY1kyRuz4BtUKM22NcAOff
 IHCo+/9mu3lFa3Il9c7i23EbhTeY5Vrl4xiwuF9FWYiwNj0N8GZkFaoVuH3tofn2
 4S3oJhHvwe8IgKWAo9mnuk5Et9dGCh4WblTueucHwExfLwddaiM1Xv/y7SKGEeTd
 IZKxInXHn9niDcjMBeod91BMZBvrlt1Wri147LvF5kUk7eeB/i0M2IiflYXTfVAl
 Qq/5FAfDLvmjUWsZFRYQCTGd4ykuGeU2vAKeL8kaG6cadvJhBZfnz2J9UYYoVgLi
 zUKdCXcppumainjP4AxiR0hOk9wCEMjWtAuSWUNh5gfxTDMB1ObadIOBaWFuZSSI
 goj5jqNCc1xlzLsPmtUQmCBS8/Bv3ux67fxk2ys3tgKR
 =Ma49
 -----END PGP SIGNATURE-----

Merge tag 'usb-serial-4.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/johan/usb-serial into usb-next

Johan writes:

USB-serial updates for v4.11-rc1

These updates include

 - a new driver for Renesas uPD78F0730-based devices

 - several fixes of failures to check for short transfers, some of which could
   lead to minor information leaks, and in one case a loop-condition underflow

 - a fix of a long-standing regression in the ftdi_sio driver which resulted
   in excessive bulk-in interrupts

 - a fix for ftdi_sio line-status over-reporting which could lead to an
   endless stream of NULL-characters being forwarded to user space

 - a fix for a regression in the console driver

 - a fix for another mos7840 NULL-pointer dereference due to a missing endpoint
   sanity check

Included are also some clean ups and fixes for various minor issues, as well as
a couple of new device IDs that came in late.

All but the final patch have been in linux-next with no reported issues.

Signed-off-by: Johan Hovold <johan@kernel.org>
This commit is contained in:
Greg Kroah-Hartman 2017-02-09 13:57:05 +01:00
commit 54a21903df
27 changed files with 772 additions and 388 deletions

View file

@ -713,6 +713,15 @@ config USB_SERIAL_QT2
To compile this driver as a module, choose M here: the
module will be called quatech-serial.
config USB_SERIAL_UPD78F0730
tristate "USB Renesas uPD78F0730 Single Port Serial Driver"
help
Say Y here if you want to use the Renesas uPD78F0730
serial driver.
To compile this driver as a module, choose M here: the
module will be called upd78f0730.
config USB_SERIAL_DEBUG
tristate "USB Debugging Device"
help

View file

@ -56,6 +56,7 @@ obj-$(CONFIG_USB_SERIAL_SSU100) += ssu100.o
obj-$(CONFIG_USB_SERIAL_SYMBOL) += symbolserial.o
obj-$(CONFIG_USB_SERIAL_WWAN) += usb_wwan.o
obj-$(CONFIG_USB_SERIAL_TI) += ti_usb_3410_5052.o
obj-$(CONFIG_USB_SERIAL_UPD78F0730) += upd78f0730.o
obj-$(CONFIG_USB_SERIAL_VISOR) += visor.o
obj-$(CONFIG_USB_SERIAL_WISHBONE) += wishbone-serial.o
obj-$(CONFIG_USB_SERIAL_WHITEHEAT) += whiteheat.o

View file

@ -99,10 +99,17 @@ static int ark3116_read_reg(struct usb_serial *serial,
usb_rcvctrlpipe(serial->dev, 0),
0xfe, 0xc0, 0, reg,
buf, 1, ARK_TIMEOUT);
if (result < 0)
if (result < 1) {
dev_err(&serial->interface->dev,
"failed to read register %u: %d\n",
reg, result);
if (result >= 0)
result = -EIO;
return result;
else
return buf[0];
}
return buf[0];
}
static inline int calc_divisor(int bps)
@ -118,17 +125,11 @@ static inline int calc_divisor(int bps)
static int ark3116_attach(struct usb_serial *serial)
{
/* make sure we have our end-points */
if ((serial->num_bulk_in == 0) ||
(serial->num_bulk_out == 0) ||
(serial->num_interrupt_in == 0)) {
dev_err(&serial->dev->dev,
"%s - missing endpoint - "
"bulk in: %d, bulk out: %d, int in %d\n",
KBUILD_MODNAME,
serial->num_bulk_in,
serial->num_bulk_out,
serial->num_interrupt_in);
return -EINVAL;
if (serial->num_bulk_in == 0 ||
serial->num_bulk_out == 0 ||
serial->num_interrupt_in == 0) {
dev_err(&serial->interface->dev, "missing endpoint\n");
return -ENODEV;
}
return 0;
@ -186,10 +187,8 @@ static int ark3116_port_probe(struct usb_serial_port *port)
if (priv->irda)
ark3116_write_reg(serial, 0x9, 0);
dev_info(&serial->dev->dev,
"%s using %s mode\n",
KBUILD_MODNAME,
priv->irda ? "IrDA" : "RS232");
dev_info(&port->dev, "using %s mode\n", priv->irda ? "IrDA" : "RS232");
return 0;
}
@ -325,9 +324,8 @@ static void ark3116_set_termios(struct tty_struct *tty,
/* check for software flow control */
if (I_IXOFF(tty) || I_IXON(tty)) {
dev_warn(&serial->dev->dev,
"%s: don't know how to do software flow control\n",
KBUILD_MODNAME);
dev_warn(&port->dev,
"software flow control not implemented\n");
}
/* Don't rewrite B0 */
@ -346,8 +344,8 @@ static void ark3116_close(struct usb_serial_port *port)
ark3116_write_reg(serial, UART_IER, 0);
usb_serial_generic_close(port);
if (serial->num_interrupt_in)
usb_kill_urb(port->interrupt_in_urb);
usb_kill_urb(port->interrupt_in_urb);
}
static int ark3116_open(struct tty_struct *tty, struct usb_serial_port *port)
@ -366,23 +364,29 @@ static int ark3116_open(struct tty_struct *tty, struct usb_serial_port *port)
dev_dbg(&port->dev,
"%s - usb_serial_generic_open failed: %d\n",
__func__, result);
goto err_out;
goto err_free;
}
/* remove any data still left: also clears error state */
ark3116_read_reg(serial, UART_RX, buf);
/* read modem status */
priv->msr = ark3116_read_reg(serial, UART_MSR, buf);
result = ark3116_read_reg(serial, UART_MSR, buf);
if (result < 0)
goto err_close;
priv->msr = *buf;
/* read line status */
priv->lsr = ark3116_read_reg(serial, UART_LSR, buf);
result = ark3116_read_reg(serial, UART_LSR, buf);
if (result < 0)
goto err_close;
priv->lsr = *buf;
result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
if (result) {
dev_err(&port->dev, "submit irq_in urb failed %d\n",
result);
ark3116_close(port);
goto err_out;
goto err_close;
}
/* activate interrupts */
@ -395,8 +399,15 @@ static int ark3116_open(struct tty_struct *tty, struct usb_serial_port *port)
if (tty)
ark3116_set_termios(tty, port, NULL);
err_out:
kfree(buf);
return 0;
err_close:
usb_serial_generic_close(port);
err_free:
kfree(buf);
return result;
}
@ -602,9 +613,8 @@ static void ark3116_read_int_callback(struct urb *urb)
result = usb_submit_urb(urb, GFP_ATOMIC);
if (result)
dev_err(&urb->dev->dev,
"%s - Error %d submitting interrupt urb\n",
__func__, result);
dev_err(&port->dev, "failed to resubmit interrupt urb: %d\n",
result);
}

View file

@ -93,8 +93,8 @@ MODULE_DEVICE_TABLE(usb, id_table);
struct ch341_private {
spinlock_t lock; /* access lock */
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 mcr;
u8 msr;
u8 lcr;
};
@ -107,8 +107,8 @@ static int ch341_control_out(struct usb_device *dev, u8 request,
{
int r;
dev_dbg(&dev->dev, "ch341_control_out(%02x,%02x,%04x,%04x)\n",
USB_DIR_OUT|0x40, (int)request, (int)value, (int)index);
dev_dbg(&dev->dev, "%s - (%02x,%04x,%04x)\n", __func__,
request, value, index);
r = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), request,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
@ -125,9 +125,8 @@ static int ch341_control_in(struct usb_device *dev,
{
int r;
dev_dbg(&dev->dev, "ch341_control_in(%02x,%02x,%04x,%04x,%p,%u)\n",
USB_DIR_IN|0x40, (int)request, (int)value, (int)index, buf,
(int)bufsize);
dev_dbg(&dev->dev, "%s - (%02x,%04x,%04x,%u)\n", __func__,
request, value, index, bufsize);
r = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), request,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
@ -210,7 +209,7 @@ static int ch341_get_status(struct usb_device *dev, struct ch341_private *priv)
goto out;
spin_lock_irqsave(&priv->lock, flags);
priv->line_status = (~(*buffer)) & CH341_BITS_MODEM_STAT;
priv->msr = (~(*buffer)) & CH341_BITS_MODEM_STAT;
spin_unlock_irqrestore(&priv->lock, flags);
out: kfree(buffer);
@ -239,30 +238,11 @@ static int ch341_configure(struct usb_device *dev, struct ch341_private *priv)
if (r < 0)
goto out;
/* expect two bytes 0x56 0x00 */
r = ch341_control_in(dev, CH341_REQ_READ_REG, 0x2518, 0, buffer, size);
if (r < 0)
goto out;
r = ch341_control_out(dev, CH341_REQ_WRITE_REG, 0x2518, 0x0050);
if (r < 0)
goto out;
/* expect 0xff 0xee */
r = ch341_get_status(dev, priv);
if (r < 0)
goto out;
r = ch341_set_baudrate_lcr(dev, priv, priv->lcr);
if (r < 0)
goto out;
r = ch341_set_handshake(dev, priv->line_control);
if (r < 0)
goto out;
/* expect 0x9f 0xee */
r = ch341_get_status(dev, priv);
r = ch341_set_handshake(dev, priv->mcr);
out: kfree(buffer);
return r;
@ -279,6 +259,11 @@ static int ch341_port_probe(struct usb_serial_port *port)
spin_lock_init(&priv->lock);
priv->baud_rate = DEFAULT_BAUD_RATE;
/*
* Some CH340 devices appear unable to change the initial LCR
* settings, so set a sane 8N1 default.
*/
priv->lcr = CH341_LCR_ENABLE_RX | CH341_LCR_ENABLE_TX | CH341_LCR_CS8;
r = ch341_configure(port->serial->dev, priv);
if (r < 0)
@ -304,7 +289,7 @@ static int ch341_port_remove(struct usb_serial_port *port)
static int ch341_carrier_raised(struct usb_serial_port *port)
{
struct ch341_private *priv = usb_get_serial_port_data(port);
if (priv->line_status & CH341_BIT_DCD)
if (priv->msr & CH341_BIT_DCD)
return 1;
return 0;
}
@ -317,11 +302,11 @@ static void ch341_dtr_rts(struct usb_serial_port *port, int on)
/* drop DTR and RTS */
spin_lock_irqsave(&priv->lock, flags);
if (on)
priv->line_control |= CH341_BIT_RTS | CH341_BIT_DTR;
priv->mcr |= CH341_BIT_RTS | CH341_BIT_DTR;
else
priv->line_control &= ~(CH341_BIT_RTS | CH341_BIT_DTR);
priv->mcr &= ~(CH341_BIT_RTS | CH341_BIT_DTR);
spin_unlock_irqrestore(&priv->lock, flags);
ch341_set_handshake(port->serial->dev, priv->line_control);
ch341_set_handshake(port->serial->dev, priv->mcr);
}
static void ch341_close(struct usb_serial_port *port)
@ -334,14 +319,9 @@ static void ch341_close(struct usb_serial_port *port)
/* open this device, set default parameters */
static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port)
{
struct usb_serial *serial = port->serial;
struct ch341_private *priv = usb_get_serial_port_data(port);
int r;
r = ch341_configure(serial->dev, priv);
if (r)
return r;
if (tty)
ch341_set_termios(tty, port, NULL);
@ -353,6 +333,12 @@ static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port)
return r;
}
r = ch341_get_status(port->serial->dev, priv);
if (r < 0) {
dev_err(&port->dev, "failed to read modem status: %d\n", r);
goto err_kill_interrupt_urb;
}
r = usb_serial_generic_open(tty, port);
if (r)
goto err_kill_interrupt_urb;
@ -374,7 +360,7 @@ static void ch341_set_termios(struct tty_struct *tty,
struct ch341_private *priv = usb_get_serial_port_data(port);
unsigned baud_rate;
unsigned long flags;
unsigned char ctrl;
u8 lcr;
int r;
/* redundant changes may cause the chip to lose bytes */
@ -383,54 +369,54 @@ static void ch341_set_termios(struct tty_struct *tty,
baud_rate = tty_get_baud_rate(tty);
ctrl = CH341_LCR_ENABLE_RX | CH341_LCR_ENABLE_TX;
lcr = CH341_LCR_ENABLE_RX | CH341_LCR_ENABLE_TX;
switch (C_CSIZE(tty)) {
case CS5:
ctrl |= CH341_LCR_CS5;
lcr |= CH341_LCR_CS5;
break;
case CS6:
ctrl |= CH341_LCR_CS6;
lcr |= CH341_LCR_CS6;
break;
case CS7:
ctrl |= CH341_LCR_CS7;
lcr |= CH341_LCR_CS7;
break;
case CS8:
ctrl |= CH341_LCR_CS8;
lcr |= CH341_LCR_CS8;
break;
}
if (C_PARENB(tty)) {
ctrl |= CH341_LCR_ENABLE_PAR;
lcr |= CH341_LCR_ENABLE_PAR;
if (C_PARODD(tty) == 0)
ctrl |= CH341_LCR_PAR_EVEN;
lcr |= CH341_LCR_PAR_EVEN;
if (C_CMSPAR(tty))
ctrl |= CH341_LCR_MARK_SPACE;
lcr |= CH341_LCR_MARK_SPACE;
}
if (C_CSTOPB(tty))
ctrl |= CH341_LCR_STOP_BITS_2;
lcr |= CH341_LCR_STOP_BITS_2;
if (baud_rate) {
priv->baud_rate = baud_rate;
r = ch341_set_baudrate_lcr(port->serial->dev, priv, ctrl);
r = ch341_set_baudrate_lcr(port->serial->dev, priv, lcr);
if (r < 0 && old_termios) {
priv->baud_rate = tty_termios_baud_rate(old_termios);
tty_termios_copy_hw(&tty->termios, old_termios);
} else if (r == 0) {
priv->lcr = ctrl;
priv->lcr = lcr;
}
}
spin_lock_irqsave(&priv->lock, flags);
if (C_BAUD(tty) == B0)
priv->line_control &= ~(CH341_BIT_DTR | CH341_BIT_RTS);
priv->mcr &= ~(CH341_BIT_DTR | CH341_BIT_RTS);
else if (old_termios && (old_termios->c_cflag & CBAUD) == B0)
priv->line_control |= (CH341_BIT_DTR | CH341_BIT_RTS);
priv->mcr |= (CH341_BIT_DTR | CH341_BIT_RTS);
spin_unlock_irqrestore(&priv->lock, flags);
ch341_set_handshake(port->serial->dev, priv->line_control);
ch341_set_handshake(port->serial->dev, priv->mcr);
}
static void ch341_break_ctl(struct tty_struct *tty, int break_state)
@ -486,20 +472,20 @@ static int ch341_tiocmset(struct tty_struct *tty,
spin_lock_irqsave(&priv->lock, flags);
if (set & TIOCM_RTS)
priv->line_control |= CH341_BIT_RTS;
priv->mcr |= CH341_BIT_RTS;
if (set & TIOCM_DTR)
priv->line_control |= CH341_BIT_DTR;
priv->mcr |= CH341_BIT_DTR;
if (clear & TIOCM_RTS)
priv->line_control &= ~CH341_BIT_RTS;
priv->mcr &= ~CH341_BIT_RTS;
if (clear & TIOCM_DTR)
priv->line_control &= ~CH341_BIT_DTR;
control = priv->line_control;
priv->mcr &= ~CH341_BIT_DTR;
control = priv->mcr;
spin_unlock_irqrestore(&priv->lock, flags);
return ch341_set_handshake(port->serial->dev, control);
}
static void ch341_update_line_status(struct usb_serial_port *port,
static void ch341_update_status(struct usb_serial_port *port,
unsigned char *data, size_t len)
{
struct ch341_private *priv = usb_get_serial_port_data(port);
@ -514,8 +500,8 @@ static void ch341_update_line_status(struct usb_serial_port *port,
status = ~data[2] & CH341_BITS_MODEM_STAT;
spin_lock_irqsave(&priv->lock, flags);
delta = status ^ priv->line_status;
priv->line_status = status;
delta = status ^ priv->msr;
priv->msr = status;
spin_unlock_irqrestore(&priv->lock, flags);
if (data[1] & CH341_MULT_STAT)
@ -568,7 +554,7 @@ static void ch341_read_int_callback(struct urb *urb)
}
usb_serial_debug_data(&port->dev, __func__, len, data);
ch341_update_line_status(port, data, len);
ch341_update_status(port, data, len);
exit:
status = usb_submit_urb(urb, GFP_ATOMIC);
if (status) {
@ -587,8 +573,8 @@ static int ch341_tiocmget(struct tty_struct *tty)
unsigned int result;
spin_lock_irqsave(&priv->lock, flags);
mcr = priv->line_control;
status = priv->line_status;
mcr = priv->mcr;
status = priv->msr;
spin_unlock_irqrestore(&priv->lock, flags);
result = ((mcr & CH341_BIT_DTR) ? TIOCM_DTR : 0)
@ -619,6 +605,12 @@ static int ch341_reset_resume(struct usb_serial *serial)
ret);
return ret;
}
ret = ch341_get_status(port->serial->dev, priv);
if (ret < 0) {
dev_err(&port->dev, "failed to read modem status: %d\n",
ret);
}
}
return usb_serial_generic_resume(serial);

View file

@ -143,6 +143,7 @@ static int usb_console_setup(struct console *co, char *options)
tty->driver = usb_serial_tty_driver;
tty->index = co->index;
init_ldsem(&tty->ldisc_sem);
spin_lock_init(&tty->files_lock);
INIT_LIST_HEAD(&tty->tty_files);
kref_get(&tty->driver->kref);
__module_get(tty->driver->owner);
@ -264,8 +265,7 @@ static struct console usbcons = {
void usb_serial_console_disconnect(struct usb_serial *serial)
{
if (serial && serial->port && serial->port[0]
&& serial->port[0] == usbcons_info.port) {
if (serial->port[0] == usbcons_info.port) {
usb_serial_console_exit();
usb_serial_put(serial);
}

View file

@ -178,6 +178,8 @@ static const struct usb_device_id id_table[] = {
{ USB_DEVICE(0x1901, 0x0190) }, /* GE B850 CP2105 Recorder interface */
{ USB_DEVICE(0x1901, 0x0193) }, /* GE B650 CP2104 PMC interface */
{ USB_DEVICE(0x1901, 0x0194) }, /* GE Healthcare Remote Alarm Box */
{ USB_DEVICE(0x1901, 0x0195) }, /* GE B850/B650/B450 CP2104 DP UART interface */
{ USB_DEVICE(0x1901, 0x0196) }, /* GE B850 CP2105 DP UART interface */
{ USB_DEVICE(0x19CF, 0x3000) }, /* Parrot NMEA GPS Flight Recorder */
{ USB_DEVICE(0x1ADB, 0x0001) }, /* Schweitzer Engineering C662 Cable */
{ USB_DEVICE(0x1B1C, 0x1C00) }, /* Corsair USB Dongle */

View file

@ -1069,7 +1069,6 @@ static void cypress_read_int_callback(struct urb *urb)
unsigned char *data = urb->transfer_buffer;
unsigned long flags;
char tty_flag = TTY_NORMAL;
int havedata = 0;
int bytes = 0;
int result;
int i = 0;
@ -1118,16 +1117,12 @@ static void cypress_read_int_callback(struct urb *urb)
priv->current_status = data[0] & 0xF8;
bytes = data[1] + 2;
i = 2;
if (bytes > 2)
havedata = 1;
break;
case packet_format_2:
/* This is for the CY7C63743... */
priv->current_status = data[0] & 0xF8;
bytes = (data[0] & 0x07) + 1;
i = 1;
if (bytes > 1)
havedata = 1;
break;
}
spin_unlock_irqrestore(&priv->lock, flags);

View file

@ -1398,25 +1398,30 @@ static int digi_read_inb_callback(struct urb *urb)
{
struct usb_serial_port *port = urb->context;
struct digi_port *priv = usb_get_serial_port_data(port);
int opcode = ((unsigned char *)urb->transfer_buffer)[0];
int len = ((unsigned char *)urb->transfer_buffer)[1];
int port_status = ((unsigned char *)urb->transfer_buffer)[2];
unsigned char *data = ((unsigned char *)urb->transfer_buffer) + 3;
unsigned char *buf = urb->transfer_buffer;
int opcode;
int len;
int port_status;
unsigned char *data;
int flag, throttled;
int status = urb->status;
/* do not process callbacks on closed ports */
/* but do continue the read chain */
if (urb->status == -ENOENT)
return 0;
/* short/multiple packet check */
if (urb->actual_length < 2) {
dev_warn(&port->dev, "short packet received\n");
return -1;
}
opcode = buf[0];
len = buf[1];
if (urb->actual_length != len + 2) {
dev_err(&port->dev, "%s: INCOMPLETE OR MULTIPLE PACKET, "
"status=%d, port=%d, opcode=%d, len=%d, "
"actual_length=%d, status=%d\n", __func__, status,
priv->dp_port_num, opcode, len, urb->actual_length,
port_status);
dev_err(&port->dev, "malformed packet received: port=%d, opcode=%d, len=%d, actual_length=%u\n",
priv->dp_port_num, opcode, len, urb->actual_length);
return -1;
}
if (opcode == DIGI_CMD_RECEIVE_DATA && len < 1) {
dev_err(&port->dev, "malformed data packet received\n");
return -1;
}
@ -1430,6 +1435,9 @@ static int digi_read_inb_callback(struct urb *urb)
/* receive data */
if (opcode == DIGI_CMD_RECEIVE_DATA) {
port_status = buf[2];
data = &buf[3];
/* get flag from port_status */
flag = 0;
@ -1482,16 +1490,20 @@ static int digi_read_oob_callback(struct urb *urb)
struct usb_serial *serial = port->serial;
struct tty_struct *tty;
struct digi_port *priv = usb_get_serial_port_data(port);
unsigned char *buf = urb->transfer_buffer;
int opcode, line, status, val;
int i;
unsigned int rts;
if (urb->actual_length < 4)
return -1;
/* handle each oob command */
for (i = 0; i < urb->actual_length - 3;) {
opcode = ((unsigned char *)urb->transfer_buffer)[i++];
line = ((unsigned char *)urb->transfer_buffer)[i++];
status = ((unsigned char *)urb->transfer_buffer)[i++];
val = ((unsigned char *)urb->transfer_buffer)[i++];
for (i = 0; i < urb->actual_length - 4; i += 4) {
opcode = buf[i];
line = buf[i + 1];
status = buf[i + 2];
val = buf[i + 3];
dev_dbg(&port->dev, "digi_read_oob_callback: opcode=%d, line=%d, status=%d, val=%d\n",
opcode, line, status, val);

View file

@ -1439,10 +1439,13 @@ static int read_latency_timer(struct usb_serial_port *port)
FTDI_SIO_GET_LATENCY_TIMER_REQUEST_TYPE,
0, priv->interface,
buf, 1, WDR_TIMEOUT);
if (rv < 0)
if (rv < 1) {
dev_err(&port->dev, "Unable to read latency timer: %i\n", rv);
else
if (rv >= 0)
rv = -EIO;
} else {
priv->latency = buf[0];
}
kfree(buf);
@ -1531,7 +1534,7 @@ static int set_serial_info(struct tty_struct *tty,
}
static int get_lsr_info(struct usb_serial_port *port,
struct serial_struct __user *retinfo)
unsigned int __user *retinfo)
{
struct ftdi_private *priv = usb_get_serial_port_data(port);
unsigned int result = 0;
@ -1802,8 +1805,6 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port)
mutex_init(&priv->cfg_lock);
priv->flags = ASYNC_LOW_LATENCY;
if (quirk && quirk->port_probe)
quirk->port_probe(priv);
@ -2067,6 +2068,20 @@ static int ftdi_process_packet(struct usb_serial_port *port,
priv->prev_status = status;
}
/* save if the transmitter is empty or not */
if (packet[1] & FTDI_RS_TEMT)
priv->transmit_empty = 1;
else
priv->transmit_empty = 0;
len -= 2;
if (!len)
return 0; /* status only */
/*
* Break and error status must only be processed for packets with
* data payload to avoid over-reporting.
*/
flag = TTY_NORMAL;
if (packet[1] & FTDI_RS_ERR_MASK) {
/* Break takes precedence over parity, which takes precedence
@ -2089,15 +2104,6 @@ static int ftdi_process_packet(struct usb_serial_port *port,
}
}
/* save if the transmitter is empty or not */
if (packet[1] & FTDI_RS_TEMT)
priv->transmit_empty = 1;
else
priv->transmit_empty = 0;
len -= 2;
if (!len)
return 0; /* status only */
port->icount.rx += len;
ch = packet + 2;
@ -2428,8 +2434,12 @@ static int ftdi_get_modem_status(struct usb_serial_port *port,
FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE,
0, priv->interface,
buf, len, WDR_TIMEOUT);
if (ret < 0) {
/* NOTE: We allow short responses and handle that below. */
if (ret < 1) {
dev_err(&port->dev, "failed to get modem status: %d\n", ret);
if (ret >= 0)
ret = -EIO;
ret = usb_translate_errors(ret);
goto out;
}
@ -2480,20 +2490,15 @@ static int ftdi_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg)
{
struct usb_serial_port *port = tty->driver_data;
void __user *argp = (void __user *)arg;
/* Based on code from acm.c and others */
switch (cmd) {
case TIOCGSERIAL: /* gets serial port data */
return get_serial_info(port,
(struct serial_struct __user *) arg);
case TIOCSSERIAL: /* sets serial port data */
return set_serial_info(tty, port,
(struct serial_struct __user *) arg);
case TIOCGSERIAL:
return get_serial_info(port, argp);
case TIOCSSERIAL:
return set_serial_info(tty, port, argp);
case TIOCSERGETLSR:
return get_lsr_info(port, (struct serial_struct __user *)arg);
break;
return get_lsr_info(port, argp);
default:
break;
}

View file

@ -492,20 +492,24 @@ static int get_epic_descriptor(struct edgeport_serial *ep)
int result;
struct usb_serial *serial = ep->serial;
struct edgeport_product_info *product_info = &ep->product_info;
struct edge_compatibility_descriptor *epic = &ep->epic_descriptor;
struct edge_compatibility_descriptor *epic;
struct edge_compatibility_bits *bits;
struct device *dev = &serial->dev->dev;
ep->is_epic = 0;
epic = kmalloc(sizeof(*epic), GFP_KERNEL);
if (!epic)
return -ENOMEM;
result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
USB_REQUEST_ION_GET_EPIC_DESC,
0xC0, 0x00, 0x00,
&ep->epic_descriptor,
sizeof(struct edge_compatibility_descriptor),
epic, sizeof(*epic),
300);
if (result > 0) {
if (result == sizeof(*epic)) {
ep->is_epic = 1;
memcpy(&ep->epic_descriptor, epic, sizeof(*epic));
memset(product_info, 0, sizeof(struct edgeport_product_info));
product_info->NumPorts = epic->NumPorts;
@ -534,8 +538,16 @@ static int get_epic_descriptor(struct edgeport_serial *ep)
dev_dbg(dev, " IOSPWriteLCR : %s\n", bits->IOSPWriteLCR ? "TRUE": "FALSE");
dev_dbg(dev, " IOSPSetBaudRate : %s\n", bits->IOSPSetBaudRate ? "TRUE": "FALSE");
dev_dbg(dev, " TrueEdgeport : %s\n", bits->TrueEdgeport ? "TRUE": "FALSE");
result = 0;
} else if (result >= 0) {
dev_warn(&serial->interface->dev, "short epic descriptor received: %d\n",
result);
result = -EIO;
}
kfree(epic);
return result;
}
@ -1560,7 +1572,6 @@ static int get_serial_info(struct edgeport_port *edge_port,
tmp.line = edge_port->port->minor;
tmp.port = edge_port->port->port_number;
tmp.irq = 0;
tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;
tmp.xmit_fifo_size = edge_port->maxTxCredits;
tmp.baud_base = 9600;
tmp.close_delay = 5*HZ;
@ -2090,8 +2101,7 @@ static int rom_write(struct usb_serial *serial, __u16 extAddr, __u16 addr,
* rom_read
* reads a number of bytes from the Edgeport device starting at the given
* address.
* If successful returns the number of bytes read, otherwise it returns
* a negative error number of the problem.
* Returns zero on success or a negative error number.
****************************************************************************/
static int rom_read(struct usb_serial *serial, __u16 extAddr,
__u16 addr, __u16 length, __u8 *data)
@ -2116,12 +2126,17 @@ static int rom_read(struct usb_serial *serial, __u16 extAddr,
USB_REQUEST_ION_READ_ROM,
0xC0, addr, extAddr, transfer_buffer,
current_length, 300);
if (result < 0)
if (result < current_length) {
if (result >= 0)
result = -EIO;
break;
}
memcpy(data, transfer_buffer, current_length);
length -= current_length;
addr += current_length;
data += current_length;
result = 0;
}
kfree(transfer_buffer);
@ -2575,9 +2590,10 @@ static void get_manufacturing_desc(struct edgeport_serial *edge_serial)
EDGE_MANUF_DESC_LEN,
(__u8 *)(&edge_serial->manuf_descriptor));
if (response < 1)
dev_err(dev, "error in getting manufacturer descriptor\n");
else {
if (response < 0) {
dev_err(dev, "error in getting manufacturer descriptor: %d\n",
response);
} else {
char string[30];
dev_dbg(dev, "**Manufacturer Descriptor\n");
dev_dbg(dev, " RomSize: %dK\n",
@ -2634,9 +2650,10 @@ static void get_boot_desc(struct edgeport_serial *edge_serial)
EDGE_BOOT_DESC_LEN,
(__u8 *)(&edge_serial->boot_descriptor));
if (response < 1)
dev_err(dev, "error in getting boot descriptor\n");
else {
if (response < 0) {
dev_err(dev, "error in getting boot descriptor: %d\n",
response);
} else {
dev_dbg(dev, "**Boot Descriptor:\n");
dev_dbg(dev, " BootCodeLength: %d\n",
le16_to_cpu(edge_serial->boot_descriptor.BootCodeLength));
@ -2779,7 +2796,7 @@ static int edge_startup(struct usb_serial *serial)
dev_info(&serial->dev->dev, "%s detected\n", edge_serial->name);
/* Read the epic descriptor */
if (get_epic_descriptor(edge_serial) <= 0) {
if (get_epic_descriptor(edge_serial) < 0) {
/* memcpy descriptor to Supports structures */
memcpy(&edge_serial->epic_descriptor.Supports, descriptor,
sizeof(struct edge_compatibility_bits));

View file

@ -2468,7 +2468,6 @@ static int get_serial_info(struct edgeport_port *edge_port,
tmp.line = edge_port->port->minor;
tmp.port = edge_port->port->port_number;
tmp.irq = 0;
tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;
tmp.xmit_fifo_size = edge_port->port->bulk_out_size;
tmp.baud_base = 9600;
tmp.close_delay = 5*HZ;

View file

@ -976,7 +976,6 @@ static int iuu_open(struct tty_struct *tty, struct usb_serial_port *port)
{
struct usb_serial *serial = port->serial;
struct device *dev = &port->dev;
u8 *buf;
int result;
int baud;
u32 actual;
@ -991,20 +990,8 @@ static int iuu_open(struct tty_struct *tty, struct usb_serial_port *port)
usb_clear_halt(serial->dev, port->write_urb->pipe);
usb_clear_halt(serial->dev, port->read_urb->pipe);
buf = kmalloc(10, GFP_KERNEL);
if (buf == NULL)
return -ENOMEM;
priv->poll = 0;
/* initialize writebuf */
#define FISH(a, b, c, d) do { \
result = usb_control_msg(port->serial->dev, \
usb_rcvctrlpipe(port->serial->dev, 0), \
b, a, c, d, buf, 1, 1000); \
dev_dbg(dev, "0x%x:0x%x:0x%x:0x%x %d - %x\n", a, b, c, d, result, \
buf[0]); } while (0);
#define SOUP(a, b, c, d) do { \
result = usb_control_msg(port->serial->dev, \
usb_sndctrlpipe(port->serial->dev, 0), \
@ -1017,7 +1004,7 @@ static int iuu_open(struct tty_struct *tty, struct usb_serial_port *port)
/* sprintf(buf ,"%c%c%c%c",0x03,0x02,0x02,0x0); */
SOUP(0x03, 0x02, 0x02, 0x0);
kfree(buf);
iuu_led(port, 0xF000, 0xF000, 0, 0xFF);
iuu_uart_on(port);
if (boost < 100)

View file

@ -139,6 +139,7 @@ static void keyspan_pda_rx_interrupt(struct urb *urb)
{
struct usb_serial_port *port = urb->context;
unsigned char *data = urb->transfer_buffer;
unsigned int len = urb->actual_length;
int retval;
int status = urb->status;
struct keyspan_pda_private *priv;
@ -159,18 +160,26 @@ static void keyspan_pda_rx_interrupt(struct urb *urb)
goto exit;
}
if (len < 1) {
dev_warn(&port->dev, "short message received\n");
goto exit;
}
/* see if the message is data or a status interrupt */
switch (data[0]) {
case 0:
/* rest of message is rx data */
if (urb->actual_length) {
tty_insert_flip_string(&port->port, data + 1,
urb->actual_length - 1);
tty_flip_buffer_push(&port->port);
}
if (len < 2)
break;
tty_insert_flip_string(&port->port, data + 1, len - 1);
tty_flip_buffer_push(&port->port);
break;
case 1:
/* status interrupt */
if (len < 3) {
dev_warn(&port->dev, "short interrupt message received\n");
break;
}
dev_dbg(&port->dev, "rx int, d1=%d, d2=%d\n", data[1], data[2]);
switch (data[1]) {
case 1: /* modemline change */

View file

@ -89,7 +89,6 @@ static struct usb_serial_driver kl5kusb105d_device = {
.open = klsi_105_open,
.close = klsi_105_close,
.set_termios = klsi_105_set_termios,
/*.break_ctl = klsi_105_break_ctl,*/
.tiocmget = klsi_105_tiocmget,
.port_probe = klsi_105_port_probe,
.port_remove = klsi_105_port_remove,
@ -104,16 +103,15 @@ static struct usb_serial_driver * const serial_drivers[] = {
};
struct klsi_105_port_settings {
__u8 pktlen; /* always 5, it seems */
__u8 baudrate;
__u8 databits;
__u8 unknown1;
__u8 unknown2;
} __attribute__ ((packed));
u8 pktlen; /* always 5, it seems */
u8 baudrate;
u8 databits;
u8 unknown1;
u8 unknown2;
};
struct klsi_105_private {
struct klsi_105_port_settings cfg;
struct ktermios termios;
unsigned long line_state; /* modem line settings */
spinlock_t lock;
};
@ -143,10 +141,12 @@ static int klsi_105_chg_port_settings(struct usb_serial_port *port,
if (rc < 0)
dev_err(&port->dev,
"Change port settings failed (error = %d)\n", rc);
dev_info(&port->serial->dev->dev,
"%d byte block, baudrate %x, databits %d, u1 %d, u2 %d\n",
settings->pktlen, settings->baudrate, settings->databits,
settings->unknown1, settings->unknown2);
dev_dbg(&port->dev,
"pktlen %u, baudrate 0x%02x, databits %u, u1 %u, u2 %u\n",
settings->pktlen, settings->baudrate, settings->databits,
settings->unknown1, settings->unknown2);
return rc;
}
@ -175,8 +175,6 @@ static int klsi_105_get_line_state(struct usb_serial_port *port,
u8 *status_buf;
__u16 status;
dev_info(&port->serial->dev->dev, "sending SIO Poll request\n");
status_buf = kmalloc(KLSI_STATUSBUF_LEN, GFP_KERNEL);
if (!status_buf)
return -ENOMEM;
@ -199,8 +197,8 @@ static int klsi_105_get_line_state(struct usb_serial_port *port,
} else {
status = get_unaligned_le16(status_buf);
dev_info(&port->serial->dev->dev, "read status %x %x\n",
status_buf[0], status_buf[1]);
dev_dbg(&port->dev, "read status %02x %02x\n",
status_buf[0], status_buf[1]);
*line_state_p = klsi_105_status2linestate(status);
}
@ -233,8 +231,6 @@ static int klsi_105_port_probe(struct usb_serial_port *port)
spin_lock_init(&priv->lock);
/* priv->termios is left uninitialized until port opening */
usb_set_serial_port_data(port, priv);
return 0;
@ -255,7 +251,6 @@ static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port)
struct klsi_105_private *priv = usb_get_serial_port_data(port);
int retval = 0;
int rc;
int i;
unsigned long line_state;
struct klsi_105_port_settings *cfg;
unsigned long flags;
@ -278,14 +273,7 @@ static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port)
cfg->unknown2 = 1;
klsi_105_chg_port_settings(port, cfg);
/* set up termios structure */
spin_lock_irqsave(&priv->lock, flags);
priv->termios.c_iflag = tty->termios.c_iflag;
priv->termios.c_oflag = tty->termios.c_oflag;
priv->termios.c_cflag = tty->termios.c_cflag;
priv->termios.c_lflag = tty->termios.c_lflag;
for (i = 0; i < NCCS; i++)
priv->termios.c_cc[i] = tty->termios.c_cc[i];
priv->cfg.pktlen = cfg->pktlen;
priv->cfg.baudrate = cfg->baudrate;
priv->cfg.databits = cfg->databits;
@ -438,19 +426,6 @@ static void klsi_105_set_termios(struct tty_struct *tty,
*/
baud = tty_get_baud_rate(tty);
if ((cflag & CBAUD) != (old_cflag & CBAUD)) {
/* reassert DTR and (maybe) RTS on transition from B0 */
if ((old_cflag & CBAUD) == B0) {
dev_dbg(dev, "%s: baud was B0\n", __func__);
#if 0
priv->control_state |= TIOCM_DTR;
/* don't set RTS if using hardware flow control */
if (!(old_cflag & CRTSCTS))
priv->control_state |= TIOCM_RTS;
mct_u232_set_modem_ctrl(serial, priv->control_state);
#endif
}
}
switch (baud) {
case 0: /* handled below */
break;
@ -484,17 +459,14 @@ static void klsi_105_set_termios(struct tty_struct *tty,
baud = 9600;
break;
}
if ((cflag & CBAUD) == B0) {
dev_dbg(dev, "%s: baud is B0\n", __func__);
/* Drop RTS and DTR */
/* maybe this should be simulated by sending read
* disable and read enable messages?
*/
#if 0
priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS);
mct_u232_set_modem_ctrl(serial, priv->control_state);
#endif
}
/*
* FIXME: implement B0 handling
*
* Maybe this should be simulated by sending read disable and read
* enable messages?
*/
tty_encode_baud_rate(tty, baud, baud);
if ((cflag & CSIZE) != (old_cflag & CSIZE)) {
@ -528,22 +500,6 @@ static void klsi_105_set_termios(struct tty_struct *tty,
|| (cflag & CSTOPB) != (old_cflag & CSTOPB)) {
/* Not currently supported */
tty->termios.c_cflag &= ~(PARENB|PARODD|CSTOPB);
#if 0
priv->last_lcr = 0;
/* set the parity */
if (cflag & PARENB)
priv->last_lcr |= (cflag & PARODD) ?
MCT_U232_PARITY_ODD : MCT_U232_PARITY_EVEN;
else
priv->last_lcr |= MCT_U232_PARITY_NONE;
/* set the number of stop bits */
priv->last_lcr |= (cflag & CSTOPB) ?
MCT_U232_STOP_BITS_2 : MCT_U232_STOP_BITS_1;
mct_u232_set_line_ctrl(serial, priv->last_lcr);
#endif
}
/*
* Set flow control: well, I do not really now how to handle DTR/RTS.
@ -554,14 +510,6 @@ static void klsi_105_set_termios(struct tty_struct *tty,
|| (cflag & CRTSCTS) != (old_cflag & CRTSCTS)) {
/* Not currently supported */
tty->termios.c_cflag &= ~CRTSCTS;
/* Drop DTR/RTS if no flow control otherwise assert */
#if 0
if ((iflag & IXOFF) || (iflag & IXON) || (cflag & CRTSCTS))
priv->control_state |= TIOCM_DTR | TIOCM_RTS;
else
priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS);
mct_u232_set_modem_ctrl(serial, priv->control_state);
#endif
}
memcpy(cfg, &priv->cfg, sizeof(*cfg));
spin_unlock_irqrestore(&priv->lock, flags);
@ -572,25 +520,6 @@ static void klsi_105_set_termios(struct tty_struct *tty,
kfree(cfg);
}
#if 0
static void mct_u232_break_ctl(struct tty_struct *tty, int break_state)
{
struct usb_serial_port *port = tty->driver_data;
struct usb_serial *serial = port->serial;
struct mct_u232_private *priv =
(struct mct_u232_private *)port->private;
unsigned char lcr = priv->last_lcr;
dev_dbg(&port->dev, "%s - state=%d\n", __func__, break_state);
/* LOCKING */
if (break_state)
lcr |= MCT_U232_SET_BREAK;
mct_u232_set_line_ctrl(serial, lcr);
}
#endif
static int klsi_105_tiocmget(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;

View file

@ -322,8 +322,12 @@ static int mct_u232_get_modem_stat(struct usb_serial_port *port,
MCT_U232_GET_REQUEST_TYPE,
0, 0, buf, MCT_U232_GET_MODEM_STAT_SIZE,
WDR_TIMEOUT);
if (rc < 0) {
if (rc < MCT_U232_GET_MODEM_STAT_SIZE) {
dev_err(&port->dev, "Get MODEM STATus failed (error = %d)\n", rc);
if (rc >= 0)
rc = -EIO;
*msr = 0;
} else {
*msr = buf[0];

View file

@ -135,23 +135,8 @@ static void metrousb_read_int_callback(struct urb *urb)
throttled = metro_priv->throttled;
spin_unlock_irqrestore(&metro_priv->lock, flags);
/* Continue trying to read if set. */
if (!throttled) {
usb_fill_int_urb(port->interrupt_in_urb, port->serial->dev,
usb_rcvintpipe(port->serial->dev, port->interrupt_in_endpointAddress),
port->interrupt_in_urb->transfer_buffer,
port->interrupt_in_urb->transfer_buffer_length,
metrousb_read_int_callback, port, 1);
result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
if (result)
dev_err(&port->dev,
"%s - failed submitting interrupt in urb, error code=%d\n",
__func__, result);
}
return;
if (throttled)
return;
exit:
/* Try to resubmit the urb. */
result = usb_submit_urb(urb, GFP_ATOMIC);
@ -161,19 +146,8 @@ static void metrousb_read_int_callback(struct urb *urb)
__func__, result);
}
static void metrousb_write_int_callback(struct urb *urb)
{
struct usb_serial_port *port = urb->context;
dev_warn(&port->dev, "%s not implemented yet.\n",
__func__);
}
static void metrousb_cleanup(struct usb_serial_port *port)
{
dev_dbg(&port->dev, "%s\n", __func__);
usb_unlink_urb(port->interrupt_in_urb);
usb_kill_urb(port->interrupt_in_urb);
metrousb_send_unidirectional_cmd(UNI_CMD_CLOSE, port);
@ -186,8 +160,6 @@ static int metrousb_open(struct tty_struct *tty, struct usb_serial_port *port)
unsigned long flags = 0;
int result = 0;
dev_dbg(&port->dev, "%s\n", __func__);
/* Make sure the urb is initialized. */
if (!port->interrupt_in_urb) {
dev_err(&port->dev, "%s - interrupt urb not initialized\n",
@ -227,8 +199,6 @@ static int metrousb_open(struct tty_struct *tty, struct usb_serial_port *port)
__func__, result);
goto exit;
}
dev_dbg(&port->dev, "%s - port open\n", __func__);
exit:
return result;
}
@ -290,8 +260,6 @@ static void metrousb_throttle(struct tty_struct *tty)
struct metrousb_private *metro_priv = usb_get_serial_port_data(port);
unsigned long flags = 0;
dev_dbg(tty->dev, "%s\n", __func__);
/* Set the private information for the port to stop reading data. */
spin_lock_irqsave(&metro_priv->lock, flags);
metro_priv->throttled = 1;
@ -305,8 +273,6 @@ static int metrousb_tiocmget(struct tty_struct *tty)
struct metrousb_private *metro_priv = usb_get_serial_port_data(port);
unsigned long flags = 0;
dev_dbg(tty->dev, "%s\n", __func__);
spin_lock_irqsave(&metro_priv->lock, flags);
control_state = metro_priv->control_state;
spin_unlock_irqrestore(&metro_priv->lock, flags);
@ -350,15 +316,12 @@ static void metrousb_unthrottle(struct tty_struct *tty)
unsigned long flags = 0;
int result = 0;
dev_dbg(tty->dev, "%s\n", __func__);
/* Set the private information for the port to resume reading data. */
spin_lock_irqsave(&metro_priv->lock, flags);
metro_priv->throttled = 0;
spin_unlock_irqrestore(&metro_priv->lock, flags);
/* Submit the urb to read from the port. */
port->interrupt_in_urb->dev = port->serial->dev;
result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
if (result)
dev_err(tty->dev,
@ -377,7 +340,6 @@ static struct usb_serial_driver metrousb_device = {
.open = metrousb_open,
.close = metrousb_cleanup,
.read_int_callback = metrousb_read_int_callback,
.write_int_callback = metrousb_write_int_callback,
.port_probe = metrousb_port_probe,
.port_remove = metrousb_port_remove,
.throttle = metrousb_throttle,

View file

@ -234,11 +234,16 @@ static int read_mos_reg(struct usb_serial *serial, unsigned int serial_portnum,
status = usb_control_msg(usbdev, pipe, request, requesttype, value,
index, buf, 1, MOS_WDR_TIMEOUT);
if (status == 1)
if (status == 1) {
*data = *buf;
else if (status < 0)
} else {
dev_err(&usbdev->dev,
"mos7720: usb_control_msg() failed: %d\n", status);
if (status >= 0)
status = -EIO;
*data = 0;
}
kfree(buf);
return status;
@ -1846,7 +1851,6 @@ static int get_serial_info(struct moschip_port *mos7720_port,
tmp.line = mos7720_port->port->minor;
tmp.port = mos7720_port->port->port_number;
tmp.irq = 0;
tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;
tmp.xmit_fifo_size = NUM_URBS * URB_TRANSFER_BUFFER_SIZE;
tmp.baud_base = 9600;
tmp.close_delay = 5*HZ;

View file

@ -284,9 +284,15 @@ static int mos7840_get_reg_sync(struct usb_serial_port *port, __u16 reg,
ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), MCS_RDREQ,
MCS_RD_RTYPE, 0, reg, buf, VENDOR_READ_LENGTH,
MOS_WDR_TIMEOUT);
if (ret < VENDOR_READ_LENGTH) {
if (ret >= 0)
ret = -EIO;
goto out;
}
*val = buf[0];
dev_dbg(&port->dev, "%s offset is %x, return val %x\n", __func__, reg, *val);
out:
kfree(buf);
return ret;
}
@ -352,8 +358,13 @@ static int mos7840_get_uart_reg(struct usb_serial_port *port, __u16 reg,
ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), MCS_RDREQ,
MCS_RD_RTYPE, Wval, reg, buf, VENDOR_READ_LENGTH,
MOS_WDR_TIMEOUT);
if (ret < VENDOR_READ_LENGTH) {
if (ret >= 0)
ret = -EIO;
goto out;
}
*val = buf[0];
out:
kfree(buf);
return ret;
}
@ -1023,6 +1034,7 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port)
* (can't set it up in mos7840_startup as the structures *
* were not set up at that time.) */
if (port0->open_ports == 1) {
/* FIXME: Buffer never NULL, so URB is not submitted. */
if (serial->port[0]->interrupt_in_buffer == NULL) {
/* set up interrupt urb */
usb_fill_int_urb(serial->port[0]->interrupt_in_urb,
@ -1479,10 +1491,10 @@ static int mos7840_tiocmget(struct tty_struct *tty)
return -ENODEV;
status = mos7840_get_uart_reg(port, MODEM_STATUS_REGISTER, &msr);
if (status != 1)
if (status < 0)
return -EIO;
status = mos7840_get_uart_reg(port, MODEM_CONTROL_REGISTER, &mcr);
if (status != 1)
if (status < 0)
return -EIO;
result = ((mcr & MCR_DTR) ? TIOCM_DTR : 0)
| ((mcr & MCR_RTS) ? TIOCM_RTS : 0)
@ -1952,7 +1964,6 @@ static int mos7840_get_serial_info(struct moschip_port *mos7840_port,
tmp.line = mos7840_port->port->minor;
tmp.port = mos7840_port->port->port_number;
tmp.irq = 0;
tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;
tmp.xmit_fifo_size = NUM_URBS * URB_TRANSFER_BUFFER_SIZE;
tmp.baud_base = 9600;
tmp.close_delay = 5 * HZ;
@ -2106,7 +2117,8 @@ static int mos7840_calc_num_ports(struct usb_serial *serial)
static int mos7840_attach(struct usb_serial *serial)
{
if (serial->num_bulk_in < serial->num_ports ||
serial->num_bulk_out < serial->num_ports) {
serial->num_bulk_out < serial->num_ports ||
serial->num_interrupt_in < 1) {
dev_err(&serial->interface->dev, "missing endpoints\n");
return -ENODEV;
}

View file

@ -142,7 +142,7 @@ static int opticon_open(struct tty_struct *tty, struct usb_serial_port *port)
usb_clear_halt(port->serial->dev, port->read_urb->pipe);
res = usb_serial_generic_open(tty, port);
if (!res)
if (res)
return res;
/* Request CTS line state, sometimes during opening the current
@ -343,7 +343,6 @@ static int get_serial_info(struct usb_serial_port *port,
tmp.line = port->minor;
tmp.port = 0;
tmp.irq = 0;
tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;
tmp.xmit_fifo_size = 1024;
tmp.baud_base = 9600;
tmp.close_delay = 5*HZ;

View file

@ -450,7 +450,7 @@ static int pl2303_get_line_request(struct usb_serial_port *port,
if (ret != 7) {
dev_err(&port->dev, "%s - failed: %d\n", __func__, ret);
if (ret > 0)
if (ret >= 0)
ret = -EIO;
return ret;
@ -470,12 +470,8 @@ static int pl2303_set_line_request(struct usb_serial_port *port,
ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE,
0, 0, buf, 7, 100);
if (ret != 7) {
if (ret < 0) {
dev_err(&port->dev, "%s - failed: %d\n", __func__, ret);
if (ret > 0)
ret = -EIO;
return ret;
}

View file

@ -188,22 +188,22 @@ static inline int qt2_setdevice(struct usb_device *dev, u8 *data)
}
static inline int qt2_getdevice(struct usb_device *dev, u8 *data)
{
return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
QT_SET_GET_DEVICE, 0xc0, 0, 0,
data, 3, QT2_USB_TIMEOUT);
}
static inline int qt2_getregister(struct usb_device *dev,
u8 uart,
u8 reg,
u8 *data)
{
return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
QT_SET_GET_REGISTER, 0xc0, reg,
uart, data, sizeof(*data), QT2_USB_TIMEOUT);
int ret;
ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
QT_SET_GET_REGISTER, 0xc0, reg,
uart, data, sizeof(*data), QT2_USB_TIMEOUT);
if (ret < sizeof(*data)) {
if (ret >= 0)
ret = -EIO;
}
return ret;
}
static inline int qt2_setregister(struct usb_device *dev,
@ -372,9 +372,11 @@ static int qt2_open(struct tty_struct *tty, struct usb_serial_port *port)
0xc0, 0,
device_port, data, 2, QT2_USB_TIMEOUT);
if (status < 0) {
if (status < 2) {
dev_err(&port->dev, "%s - open port failed %i\n", __func__,
status);
if (status >= 0)
status = -EIO;
kfree(data);
return status;
}
@ -463,7 +465,6 @@ static int get_serial_info(struct usb_serial_port *port,
tmp.line = port->minor;
tmp.port = 0;
tmp.irq = 0;
tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;
tmp.xmit_fifo_size = port->bulk_out_size;
tmp.baud_base = 9600;
tmp.close_delay = 5*HZ;

View file

@ -137,24 +137,9 @@ static int is_himemory(const u8 ifnum,
return 0;
}
static int sierra_calc_interface(struct usb_serial *serial)
static u8 sierra_interface_num(struct usb_serial *serial)
{
int interface;
struct usb_interface *p_interface;
struct usb_host_interface *p_host_interface;
/* Get the interface structure pointer from the serial struct */
p_interface = serial->interface;
/* Get a pointer to the host interface structure */
p_host_interface = p_interface->cur_altsetting;
/* read the interface descriptor for this active altsetting
* to find out the interface number we are on
*/
interface = p_host_interface->desc.bInterfaceNumber;
return interface;
return serial->interface->cur_altsetting->desc.bInterfaceNumber;
}
static int sierra_probe(struct usb_serial *serial,
@ -165,7 +150,7 @@ static int sierra_probe(struct usb_serial *serial,
u8 ifnum;
udev = serial->dev;
ifnum = sierra_calc_interface(serial);
ifnum = sierra_interface_num(serial);
/*
* If this interface supports more than 1 alternate
@ -178,9 +163,6 @@ static int sierra_probe(struct usb_serial *serial,
usb_set_interface(udev, ifnum, 1);
}
/* ifnum could have changed - by calling usb_set_interface */
ifnum = sierra_calc_interface(serial);
if (is_blacklisted(ifnum,
(struct sierra_iface_info *)id->driver_info)) {
dev_dbg(&serial->dev->dev,
@ -342,7 +324,7 @@ static int sierra_send_setup(struct usb_serial_port *port)
/* If composite device then properly report interface */
if (serial->num_ports == 1) {
interface = sierra_calc_interface(serial);
interface = sierra_interface_num(serial);
/* Control message is sent only to interfaces with
* interrupt_in endpoints
*/
@ -916,7 +898,7 @@ static int sierra_port_probe(struct usb_serial_port *port)
/* Determine actual memory requirements */
if (serial->num_ports == 1) {
/* Get interface number for composite device */
ifnum = sierra_calc_interface(serial);
ifnum = sierra_interface_num(serial);
himemoryp = &typeB_interface_list;
} else {
/* This is really the usb-serial port number of the interface

View file

@ -232,11 +232,17 @@ static int spcp8x5_get_msr(struct usb_serial_port *port, u8 *status)
ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
GET_UART_STATUS, GET_UART_STATUS_TYPE,
0, GET_UART_STATUS_MSR, buf, 1, 100);
if (ret < 0)
if (ret < 1) {
dev_err(&port->dev, "failed to get modem status: %d\n", ret);
if (ret >= 0)
ret = -EIO;
goto out;
}
dev_dbg(&port->dev, "0xc0:0x22:0:6 %d - 0x02%x\n", ret, *buf);
*status = *buf;
ret = 0;
out:
kfree(buf);
return ret;

View file

@ -80,9 +80,17 @@ static inline int ssu100_setdevice(struct usb_device *dev, u8 *data)
static inline int ssu100_getdevice(struct usb_device *dev, u8 *data)
{
return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
QT_SET_GET_DEVICE, 0xc0, 0, 0,
data, 3, 300);
int ret;
ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
QT_SET_GET_DEVICE, 0xc0, 0, 0,
data, 3, 300);
if (ret < 3) {
if (ret >= 0)
ret = -EIO;
}
return ret;
}
static inline int ssu100_getregister(struct usb_device *dev,
@ -90,10 +98,17 @@ static inline int ssu100_getregister(struct usb_device *dev,
unsigned short reg,
u8 *data)
{
return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
QT_SET_GET_REGISTER, 0xc0, reg,
uart, data, sizeof(*data), 300);
int ret;
ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
QT_SET_GET_REGISTER, 0xc0, reg,
uart, data, sizeof(*data), 300);
if (ret < sizeof(*data)) {
if (ret >= 0)
ret = -EIO;
}
return ret;
}
@ -289,8 +304,10 @@ static int ssu100_open(struct tty_struct *tty, struct usb_serial_port *port)
QT_OPEN_CLOSE_CHANNEL,
QT_TRANSFER_IN, 0x01,
0, data, 2, 300);
if (result < 0) {
if (result < 2) {
dev_dbg(&port->dev, "%s - open failed %i\n", __func__, result);
if (result >= 0)
result = -EIO;
kfree(data);
return result;
}
@ -322,7 +339,6 @@ static int get_serial_info(struct usb_serial_port *port,
tmp.line = port->minor;
tmp.port = 0;
tmp.irq = 0;
tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;
tmp.xmit_fifo_size = port->bulk_out_size;
tmp.baud_base = 9600;
tmp.close_delay = 5*HZ;

View file

@ -1553,13 +1553,10 @@ static int ti_command_out_sync(struct ti_device *tdev, __u8 command,
(USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT),
value, moduleid, data, size, 1000);
if (status == size)
status = 0;
if (status < 0)
return status;
if (status > 0)
status = -ECOMM;
return status;
return 0;
}
@ -1575,8 +1572,7 @@ static int ti_command_in_sync(struct ti_device *tdev, __u8 command,
if (status == size)
status = 0;
if (status > 0)
else if (status >= 0)
status = -ECOMM;
return status;

View file

@ -0,0 +1,440 @@
/*
* Renesas Electronics uPD78F0730 USB to serial converter driver
*
* Copyright (C) 2014,2016 Maksim Salau <maksim.salau@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation.
*
* Protocol of the adaptor is described in the application note U19660EJ1V0AN00
* μPD78F0730 8-bit Single-Chip Microcontroller
* USB-to-Serial Conversion Software
* <https://www.renesas.com/en-eu/doc/DocumentServer/026/U19660EJ1V0AN00.pdf>
*
* The adaptor functionality is limited to the following:
* - data bits: 7 or 8
* - stop bits: 1 or 2
* - parity: even, odd or none
* - flow control: none
* - baud rates: 0, 2400, 4800, 9600, 19200, 38400, 57600, 115200
* - signals: DTR, RTS and BREAK
*/
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/usb.h>
#include <linux/usb/serial.h>
#define DRIVER_DESC "Renesas uPD78F0730 USB to serial converter driver"
#define DRIVER_AUTHOR "Maksim Salau <maksim.salau@gmail.com>"
static const struct usb_device_id id_table[] = {
{ USB_DEVICE(0x045B, 0x0212) }, /* YRPBRL78G13, YRPBRL78G14 */
{ USB_DEVICE(0x0409, 0x0063) }, /* V850ESJX3-STICK */
{}
};
MODULE_DEVICE_TABLE(usb, id_table);
/*
* Each adaptor is associated with a private structure, that holds the current
* state of control signals (DTR, RTS and BREAK).
*/
struct upd78f0730_port_private {
struct mutex lock; /* mutex to protect line_signals */
u8 line_signals;
};
/* Op-codes of control commands */
#define UPD78F0730_CMD_LINE_CONTROL 0x00
#define UPD78F0730_CMD_SET_DTR_RTS 0x01
#define UPD78F0730_CMD_SET_XON_XOFF_CHR 0x02
#define UPD78F0730_CMD_OPEN_CLOSE 0x03
#define UPD78F0730_CMD_SET_ERR_CHR 0x04
/* Data sizes in UPD78F0730_CMD_LINE_CONTROL command */
#define UPD78F0730_DATA_SIZE_7_BITS 0x00
#define UPD78F0730_DATA_SIZE_8_BITS 0x01
#define UPD78F0730_DATA_SIZE_MASK 0x01
/* Stop-bit modes in UPD78F0730_CMD_LINE_CONTROL command */
#define UPD78F0730_STOP_BIT_1_BIT 0x00
#define UPD78F0730_STOP_BIT_2_BIT 0x02
#define UPD78F0730_STOP_BIT_MASK 0x02
/* Parity modes in UPD78F0730_CMD_LINE_CONTROL command */
#define UPD78F0730_PARITY_NONE 0x00
#define UPD78F0730_PARITY_EVEN 0x04
#define UPD78F0730_PARITY_ODD 0x08
#define UPD78F0730_PARITY_MASK 0x0C
/* Flow control modes in UPD78F0730_CMD_LINE_CONTROL command */
#define UPD78F0730_FLOW_CONTROL_NONE 0x00
#define UPD78F0730_FLOW_CONTROL_HW 0x10
#define UPD78F0730_FLOW_CONTROL_SW 0x20
#define UPD78F0730_FLOW_CONTROL_MASK 0x30
/* Control signal bits in UPD78F0730_CMD_SET_DTR_RTS command */
#define UPD78F0730_RTS 0x01
#define UPD78F0730_DTR 0x02
#define UPD78F0730_BREAK 0x04
/* Port modes in UPD78F0730_CMD_OPEN_CLOSE command */
#define UPD78F0730_PORT_CLOSE 0x00
#define UPD78F0730_PORT_OPEN 0x01
/* Error character substitution modes in UPD78F0730_CMD_SET_ERR_CHR command */
#define UPD78F0730_ERR_CHR_DISABLED 0x00
#define UPD78F0730_ERR_CHR_ENABLED 0x01
/*
* Declaration of command structures
*/
/* UPD78F0730_CMD_LINE_CONTROL command */
struct upd78f0730_line_control {
u8 opcode;
__le32 baud_rate;
u8 params;
} __packed;
/* UPD78F0730_CMD_SET_DTR_RTS command */
struct upd78f0730_set_dtr_rts {
u8 opcode;
u8 params;
};
/* UPD78F0730_CMD_SET_XON_OFF_CHR command */
struct upd78f0730_set_xon_xoff_chr {
u8 opcode;
u8 xon;
u8 xoff;
};
/* UPD78F0730_CMD_OPEN_CLOSE command */
struct upd78f0730_open_close {
u8 opcode;
u8 state;
};
/* UPD78F0730_CMD_SET_ERR_CHR command */
struct upd78f0730_set_err_chr {
u8 opcode;
u8 state;
u8 err_char;
};
static int upd78f0730_send_ctl(struct usb_serial_port *port,
const void *data, int size)
{
struct usb_device *usbdev = port->serial->dev;
void *buf;
int res;
if (size <= 0 || !data)
return -EINVAL;
buf = kmemdup(data, size, GFP_KERNEL);
if (!buf)
return -ENOMEM;
res = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x00,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
0x0000, 0x0000, buf, size, USB_CTRL_SET_TIMEOUT);
kfree(buf);
if (res != size) {
struct device *dev = &port->dev;
dev_err(dev, "failed to send control request %02x: %d\n",
*(u8 *)data, res);
/* The maximum expected length of a transfer is 6 bytes */
if (res >= 0)
res = -EIO;
return res;
}
return 0;
}
static int upd78f0730_port_probe(struct usb_serial_port *port)
{
struct upd78f0730_port_private *private;
private = kzalloc(sizeof(*private), GFP_KERNEL);
if (!private)
return -ENOMEM;
mutex_init(&private->lock);
usb_set_serial_port_data(port, private);
return 0;
}
static int upd78f0730_port_remove(struct usb_serial_port *port)
{
struct upd78f0730_port_private *private;
private = usb_get_serial_port_data(port);
mutex_destroy(&private->lock);
kfree(private);
return 0;
}
static int upd78f0730_tiocmget(struct tty_struct *tty)
{
struct device *dev = tty->dev;
struct upd78f0730_port_private *private;
struct usb_serial_port *port = tty->driver_data;
int signals;
int res;
private = usb_get_serial_port_data(port);
mutex_lock(&private->lock);
signals = private->line_signals;
mutex_unlock(&private->lock);
res = ((signals & UPD78F0730_DTR) ? TIOCM_DTR : 0) |
((signals & UPD78F0730_RTS) ? TIOCM_RTS : 0);
dev_dbg(dev, "%s - res = %x\n", __func__, res);
return res;
}
static int upd78f0730_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear)
{
struct device *dev = tty->dev;
struct usb_serial_port *port = tty->driver_data;
struct upd78f0730_port_private *private;
struct upd78f0730_set_dtr_rts request;
int res;
private = usb_get_serial_port_data(port);
mutex_lock(&private->lock);
if (set & TIOCM_DTR) {
private->line_signals |= UPD78F0730_DTR;
dev_dbg(dev, "%s - set DTR\n", __func__);
}
if (set & TIOCM_RTS) {
private->line_signals |= UPD78F0730_RTS;
dev_dbg(dev, "%s - set RTS\n", __func__);
}
if (clear & TIOCM_DTR) {
private->line_signals &= ~UPD78F0730_DTR;
dev_dbg(dev, "%s - clear DTR\n", __func__);
}
if (clear & TIOCM_RTS) {
private->line_signals &= ~UPD78F0730_RTS;
dev_dbg(dev, "%s - clear RTS\n", __func__);
}
request.opcode = UPD78F0730_CMD_SET_DTR_RTS;
request.params = private->line_signals;
res = upd78f0730_send_ctl(port, &request, sizeof(request));
mutex_unlock(&private->lock);
return res;
}
static void upd78f0730_break_ctl(struct tty_struct *tty, int break_state)
{
struct device *dev = tty->dev;
struct upd78f0730_port_private *private;
struct usb_serial_port *port = tty->driver_data;
struct upd78f0730_set_dtr_rts request;
private = usb_get_serial_port_data(port);
mutex_lock(&private->lock);
if (break_state) {
private->line_signals |= UPD78F0730_BREAK;
dev_dbg(dev, "%s - set BREAK\n", __func__);
} else {
private->line_signals &= ~UPD78F0730_BREAK;
dev_dbg(dev, "%s - clear BREAK\n", __func__);
}
request.opcode = UPD78F0730_CMD_SET_DTR_RTS;
request.params = private->line_signals;
upd78f0730_send_ctl(port, &request, sizeof(request));
mutex_unlock(&private->lock);
}
static void upd78f0730_dtr_rts(struct usb_serial_port *port, int on)
{
struct tty_struct *tty = port->port.tty;
unsigned int set = 0;
unsigned int clear = 0;
if (on)
set = TIOCM_DTR | TIOCM_RTS;
else
clear = TIOCM_DTR | TIOCM_RTS;
upd78f0730_tiocmset(tty, set, clear);
}
static speed_t upd78f0730_get_baud_rate(struct tty_struct *tty)
{
const speed_t baud_rate = tty_get_baud_rate(tty);
const speed_t supported[] = {
0, 2400, 4800, 9600, 19200, 38400, 57600, 115200
};
int i;
for (i = ARRAY_SIZE(supported) - 1; i >= 0; i--) {
if (baud_rate == supported[i])
return baud_rate;
}
/* If the baud rate is not supported, switch to the default one */
tty_encode_baud_rate(tty, 9600, 9600);
return tty_get_baud_rate(tty);
}
static void upd78f0730_set_termios(struct tty_struct *tty,
struct usb_serial_port *port,
struct ktermios *old_termios)
{
struct device *dev = &port->dev;
struct upd78f0730_line_control request;
speed_t baud_rate;
if (old_termios && !tty_termios_hw_change(&tty->termios, old_termios))
return;
if (C_BAUD(tty) == B0)
upd78f0730_dtr_rts(port, 0);
else if (old_termios && (old_termios->c_cflag & CBAUD) == B0)
upd78f0730_dtr_rts(port, 1);
baud_rate = upd78f0730_get_baud_rate(tty);
request.opcode = UPD78F0730_CMD_LINE_CONTROL;
request.baud_rate = cpu_to_le32(baud_rate);
request.params = 0;
dev_dbg(dev, "%s - baud rate = %d\n", __func__, baud_rate);
switch (C_CSIZE(tty)) {
case CS7:
request.params |= UPD78F0730_DATA_SIZE_7_BITS;
dev_dbg(dev, "%s - 7 data bits\n", __func__);
break;
default:
tty->termios.c_cflag &= ~CSIZE;
tty->termios.c_cflag |= CS8;
dev_warn(dev, "data size is not supported, using 8 bits\n");
/* fall through */
case CS8:
request.params |= UPD78F0730_DATA_SIZE_8_BITS;
dev_dbg(dev, "%s - 8 data bits\n", __func__);
break;
}
if (C_PARENB(tty)) {
if (C_PARODD(tty)) {
request.params |= UPD78F0730_PARITY_ODD;
dev_dbg(dev, "%s - odd parity\n", __func__);
} else {
request.params |= UPD78F0730_PARITY_EVEN;
dev_dbg(dev, "%s - even parity\n", __func__);
}
if (C_CMSPAR(tty)) {
tty->termios.c_cflag &= ~CMSPAR;
dev_warn(dev, "MARK/SPACE parity is not supported\n");
}
} else {
request.params |= UPD78F0730_PARITY_NONE;
dev_dbg(dev, "%s - no parity\n", __func__);
}
if (C_CSTOPB(tty)) {
request.params |= UPD78F0730_STOP_BIT_2_BIT;
dev_dbg(dev, "%s - 2 stop bits\n", __func__);
} else {
request.params |= UPD78F0730_STOP_BIT_1_BIT;
dev_dbg(dev, "%s - 1 stop bit\n", __func__);
}
if (C_CRTSCTS(tty)) {
tty->termios.c_cflag &= ~CRTSCTS;
dev_warn(dev, "RTSCTS flow control is not supported\n");
}
if (I_IXOFF(tty) || I_IXON(tty)) {
tty->termios.c_iflag &= ~(IXOFF | IXON);
dev_warn(dev, "XON/XOFF flow control is not supported\n");
}
request.params |= UPD78F0730_FLOW_CONTROL_NONE;
dev_dbg(dev, "%s - no flow control\n", __func__);
upd78f0730_send_ctl(port, &request, sizeof(request));
}
static int upd78f0730_open(struct tty_struct *tty, struct usb_serial_port *port)
{
struct upd78f0730_open_close request = {
.opcode = UPD78F0730_CMD_OPEN_CLOSE,
.state = UPD78F0730_PORT_OPEN
};
int res;
res = upd78f0730_send_ctl(port, &request, sizeof(request));
if (res)
return res;
if (tty)
upd78f0730_set_termios(tty, port, NULL);
return usb_serial_generic_open(tty, port);
}
static void upd78f0730_close(struct usb_serial_port *port)
{
struct upd78f0730_open_close request = {
.opcode = UPD78F0730_CMD_OPEN_CLOSE,
.state = UPD78F0730_PORT_CLOSE
};
usb_serial_generic_close(port);
upd78f0730_send_ctl(port, &request, sizeof(request));
}
static struct usb_serial_driver upd78f0730_device = {
.driver = {
.owner = THIS_MODULE,
.name = "upd78f0730",
},
.id_table = id_table,
.num_ports = 1,
.port_probe = upd78f0730_port_probe,
.port_remove = upd78f0730_port_remove,
.open = upd78f0730_open,
.close = upd78f0730_close,
.set_termios = upd78f0730_set_termios,
.tiocmget = upd78f0730_tiocmget,
.tiocmset = upd78f0730_tiocmset,
.dtr_rts = upd78f0730_dtr_rts,
.break_ctl = upd78f0730_break_ctl,
};
static struct usb_serial_driver * const serial_drivers[] = {
&upd78f0730_device,
NULL
};
module_usb_serial_driver(serial_drivers, id_table);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_LICENSE("GPL v2");

View file

@ -487,7 +487,6 @@ static int whiteheat_ioctl(struct tty_struct *tty,
serstruct.type = PORT_16654;
serstruct.line = port->minor;
serstruct.port = port->port_number;
serstruct.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;
serstruct.xmit_fifo_size = kfifo_size(&port->write_fifo);
serstruct.custom_divisor = 0;
serstruct.baud_base = 460800;