mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-25 02:09:42 +00:00
USB-serial fixes for v4.10-rc3
These fixes address a number of long-standing issues in various USB-serial drivers which would lead to crashes should a malicious device lack the expected endpoints. Included are also a few related fixes, and a couple of unrelated ones that were found during my survey (e.g. a memleak and a sleep-while-atomic). A compiler warning revealed an error-handling issue in the new f81534 driver which is also fixed. Signed-off-by: Johan Hovold <johan@kernel.org> -----BEGIN PGP SIGNATURE----- iQIuBAABCAAYBQJYbludERxqb2hhbkBrZXJuZWwub3JnAAoJEEEN5E/e4bSV9TsP /0ksvJrvpRxqCN5WWgEm5pb4kH/Cq8KPtGAVraAyC7+fVOTab++33ehEb3BxEDQN 53fQhfPPuHP98Fkp52CtoKbxJNkpmojTp/kkI9QTnnRdujAe9XURHrr1KCBB4+Ve Wg6uCOSqSSbOxlp8Qp/vY5yiaev6CFAFZ6Gn4tG8J8chQwpeK8jk2AX0S2+RcCOv ICyAwOFJ7GgV/DSDqPLXviFzLEOexMD/9us9eRSF1OiP5zv7s+m/f0hrsZGnfMhS B5D+3z28PAMED1U/OkVXCLRO5jdZDOF8O93t4QPbayliQEvY0SMNwpTj/fRuhzar EBHUszcYPMcmPqODzRDqBr+e6yoqiLGj98BJqFI2FDg/AXNCKdOWHmCmmBQ27ijr YI2MfpbhnJ9xtXsfAaPutd9D27TtJvVMQ1gvPNmEtn+ic+BNeEnWKwCmeYoxhn4O j6ZcZxRzTZj1JA8olbKCBQ/kzrnW+aQj3IPxoFW3oqgp9KwhV4t946dQdd1q8jq5 cs8uBWQe+jofHxTqx9DN4i3LPFNB93OBl5zue69i11KgKem2GPKfK1a3y9k1P7Eg dBQOTWTaiqH2Asz8QYHVkAz9wq3K92QBdwPANZodrEedDpgJ5/+JeaXKfsIuMfXa EhBu79t6wDrF+x9yuKnWDaWzSTvclrqhFXe9bt5/zZC6 =eRM2 -----END PGP SIGNATURE----- Merge tag 'usb-serial-4.10-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/johan/usb-serial into usb-linus Johan writes: USB-serial fixes for v4.10-rc3 These fixes address a number of long-standing issues in various USB-serial drivers which would lead to crashes should a malicious device lack the expected endpoints. Included are also a few related fixes, and a couple of unrelated ones that were found during my survey (e.g. a memleak and a sleep-while-atomic). A compiler warning revealed an error-handling issue in the new f81534 driver which is also fixed. Signed-off-by: Johan Hovold <johan@kernel.org>
This commit is contained in:
commit
c8d204b38a
16 changed files with 167 additions and 58 deletions
|
@ -50,6 +50,7 @@
|
|||
#define CYBERJACK_PRODUCT_ID 0x0100
|
||||
|
||||
/* Function prototypes */
|
||||
static int cyberjack_attach(struct usb_serial *serial);
|
||||
static int cyberjack_port_probe(struct usb_serial_port *port);
|
||||
static int cyberjack_port_remove(struct usb_serial_port *port);
|
||||
static int cyberjack_open(struct tty_struct *tty,
|
||||
|
@ -77,6 +78,7 @@ static struct usb_serial_driver cyberjack_device = {
|
|||
.description = "Reiner SCT Cyberjack USB card reader",
|
||||
.id_table = id_table,
|
||||
.num_ports = 1,
|
||||
.attach = cyberjack_attach,
|
||||
.port_probe = cyberjack_port_probe,
|
||||
.port_remove = cyberjack_port_remove,
|
||||
.open = cyberjack_open,
|
||||
|
@ -100,6 +102,14 @@ struct cyberjack_private {
|
|||
short wrsent; /* Data already sent */
|
||||
};
|
||||
|
||||
static int cyberjack_attach(struct usb_serial *serial)
|
||||
{
|
||||
if (serial->num_bulk_out < serial->num_ports)
|
||||
return -ENODEV;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cyberjack_port_probe(struct usb_serial_port *port)
|
||||
{
|
||||
struct cyberjack_private *priv;
|
||||
|
|
|
@ -1237,6 +1237,7 @@ static int f81534_attach(struct usb_serial *serial)
|
|||
static int f81534_port_probe(struct usb_serial_port *port)
|
||||
{
|
||||
struct f81534_port_private *port_priv;
|
||||
int ret;
|
||||
|
||||
port_priv = devm_kzalloc(&port->dev, sizeof(*port_priv), GFP_KERNEL);
|
||||
if (!port_priv)
|
||||
|
@ -1246,10 +1247,11 @@ static int f81534_port_probe(struct usb_serial_port *port)
|
|||
mutex_init(&port_priv->mcr_mutex);
|
||||
|
||||
/* Assign logic-to-phy mapping */
|
||||
port_priv->phy_num = f81534_logic_to_phy_port(port->serial, port);
|
||||
if (port_priv->phy_num < 0 || port_priv->phy_num >= F81534_NUM_PORT)
|
||||
return -ENODEV;
|
||||
ret = f81534_logic_to_phy_port(port->serial, port);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
port_priv->phy_num = ret;
|
||||
usb_set_serial_port_data(port, port_priv);
|
||||
dev_dbg(&port->dev, "%s: port_number: %d, phy_num: %d\n", __func__,
|
||||
port->port_number, port_priv->phy_num);
|
||||
|
|
|
@ -1043,6 +1043,7 @@ static int garmin_write_bulk(struct usb_serial_port *port,
|
|||
"%s - usb_submit_urb(write bulk) failed with status = %d\n",
|
||||
__func__, status);
|
||||
count = status;
|
||||
kfree(buffer);
|
||||
}
|
||||
|
||||
/* we are done with this urb, so let the host driver
|
||||
|
|
|
@ -2751,6 +2751,11 @@ static int edge_startup(struct usb_serial *serial)
|
|||
EDGE_COMPATIBILITY_MASK1,
|
||||
EDGE_COMPATIBILITY_MASK2 };
|
||||
|
||||
if (serial->num_bulk_in < 1 || serial->num_interrupt_in < 1) {
|
||||
dev_err(&serial->interface->dev, "missing endpoints\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
dev = serial->dev;
|
||||
|
||||
/* create our private serial structure */
|
||||
|
|
|
@ -1499,8 +1499,7 @@ static int do_boot_mode(struct edgeport_serial *serial,
|
|||
|
||||
dev_dbg(dev, "%s - Download successful -- Device rebooting...\n", __func__);
|
||||
|
||||
/* return an error on purpose */
|
||||
return -ENODEV;
|
||||
return 1;
|
||||
}
|
||||
|
||||
stayinbootmode:
|
||||
|
@ -1508,7 +1507,7 @@ static int do_boot_mode(struct edgeport_serial *serial,
|
|||
dev_dbg(dev, "%s - STAYING IN BOOT MODE\n", __func__);
|
||||
serial->product_info.TiMode = TI_MODE_BOOT;
|
||||
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int ti_do_config(struct edgeport_port *port, int feature, int on)
|
||||
|
@ -2546,6 +2545,13 @@ static int edge_startup(struct usb_serial *serial)
|
|||
int status;
|
||||
u16 product_id;
|
||||
|
||||
/* Make sure we have the required endpoints when in download mode. */
|
||||
if (serial->interface->cur_altsetting->desc.bNumEndpoints > 1) {
|
||||
if (serial->num_bulk_in < serial->num_ports ||
|
||||
serial->num_bulk_out < serial->num_ports)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* create our private serial structure */
|
||||
edge_serial = kzalloc(sizeof(struct edgeport_serial), GFP_KERNEL);
|
||||
if (!edge_serial)
|
||||
|
@ -2553,14 +2559,18 @@ static int edge_startup(struct usb_serial *serial)
|
|||
|
||||
mutex_init(&edge_serial->es_lock);
|
||||
edge_serial->serial = serial;
|
||||
INIT_DELAYED_WORK(&edge_serial->heartbeat_work, edge_heartbeat_work);
|
||||
usb_set_serial_data(serial, edge_serial);
|
||||
|
||||
status = download_fw(edge_serial);
|
||||
if (status) {
|
||||
if (status < 0) {
|
||||
kfree(edge_serial);
|
||||
return status;
|
||||
}
|
||||
|
||||
if (status > 0)
|
||||
return 1; /* bind but do not register any ports */
|
||||
|
||||
product_id = le16_to_cpu(
|
||||
edge_serial->serial->dev->descriptor.idProduct);
|
||||
|
||||
|
@ -2572,7 +2582,6 @@ static int edge_startup(struct usb_serial *serial)
|
|||
}
|
||||
}
|
||||
|
||||
INIT_DELAYED_WORK(&edge_serial->heartbeat_work, edge_heartbeat_work);
|
||||
edge_heartbeat_schedule(edge_serial);
|
||||
|
||||
return 0;
|
||||
|
@ -2580,6 +2589,9 @@ static int edge_startup(struct usb_serial *serial)
|
|||
|
||||
static void edge_disconnect(struct usb_serial *serial)
|
||||
{
|
||||
struct edgeport_serial *edge_serial = usb_get_serial_data(serial);
|
||||
|
||||
cancel_delayed_work_sync(&edge_serial->heartbeat_work);
|
||||
}
|
||||
|
||||
static void edge_release(struct usb_serial *serial)
|
||||
|
|
|
@ -68,6 +68,16 @@ struct iuu_private {
|
|||
u32 clk;
|
||||
};
|
||||
|
||||
static int iuu_attach(struct usb_serial *serial)
|
||||
{
|
||||
unsigned char num_ports = serial->num_ports;
|
||||
|
||||
if (serial->num_bulk_in < num_ports || serial->num_bulk_out < num_ports)
|
||||
return -ENODEV;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iuu_port_probe(struct usb_serial_port *port)
|
||||
{
|
||||
struct iuu_private *priv;
|
||||
|
@ -1196,6 +1206,7 @@ static struct usb_serial_driver iuu_device = {
|
|||
.tiocmset = iuu_tiocmset,
|
||||
.set_termios = iuu_set_termios,
|
||||
.init_termios = iuu_init_termios,
|
||||
.attach = iuu_attach,
|
||||
.port_probe = iuu_port_probe,
|
||||
.port_remove = iuu_port_remove,
|
||||
};
|
||||
|
|
|
@ -699,6 +699,19 @@ MODULE_FIRMWARE("keyspan_pda/keyspan_pda.fw");
|
|||
MODULE_FIRMWARE("keyspan_pda/xircom_pgs.fw");
|
||||
#endif
|
||||
|
||||
static int keyspan_pda_attach(struct usb_serial *serial)
|
||||
{
|
||||
unsigned char num_ports = serial->num_ports;
|
||||
|
||||
if (serial->num_bulk_out < num_ports ||
|
||||
serial->num_interrupt_in < num_ports) {
|
||||
dev_err(&serial->interface->dev, "missing endpoints\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int keyspan_pda_port_probe(struct usb_serial_port *port)
|
||||
{
|
||||
|
||||
|
@ -776,6 +789,7 @@ static struct usb_serial_driver keyspan_pda_device = {
|
|||
.break_ctl = keyspan_pda_break_ctl,
|
||||
.tiocmget = keyspan_pda_tiocmget,
|
||||
.tiocmset = keyspan_pda_tiocmset,
|
||||
.attach = keyspan_pda_attach,
|
||||
.port_probe = keyspan_pda_port_probe,
|
||||
.port_remove = keyspan_pda_port_remove,
|
||||
};
|
||||
|
|
|
@ -51,6 +51,7 @@
|
|||
|
||||
|
||||
/* Function prototypes */
|
||||
static int kobil_attach(struct usb_serial *serial);
|
||||
static int kobil_port_probe(struct usb_serial_port *probe);
|
||||
static int kobil_port_remove(struct usb_serial_port *probe);
|
||||
static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port);
|
||||
|
@ -86,6 +87,7 @@ static struct usb_serial_driver kobil_device = {
|
|||
.description = "KOBIL USB smart card terminal",
|
||||
.id_table = id_table,
|
||||
.num_ports = 1,
|
||||
.attach = kobil_attach,
|
||||
.port_probe = kobil_port_probe,
|
||||
.port_remove = kobil_port_remove,
|
||||
.ioctl = kobil_ioctl,
|
||||
|
@ -113,6 +115,16 @@ struct kobil_private {
|
|||
};
|
||||
|
||||
|
||||
static int kobil_attach(struct usb_serial *serial)
|
||||
{
|
||||
if (serial->num_interrupt_out < serial->num_ports) {
|
||||
dev_err(&serial->interface->dev, "missing interrupt-out endpoint\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kobil_port_probe(struct usb_serial_port *port)
|
||||
{
|
||||
struct usb_serial *serial = port->serial;
|
||||
|
|
|
@ -65,8 +65,6 @@ struct moschip_port {
|
|||
struct urb *write_urb_pool[NUM_URBS];
|
||||
};
|
||||
|
||||
static struct usb_serial_driver moschip7720_2port_driver;
|
||||
|
||||
#define USB_VENDOR_ID_MOSCHIP 0x9710
|
||||
#define MOSCHIP_DEVICE_ID_7720 0x7720
|
||||
#define MOSCHIP_DEVICE_ID_7715 0x7715
|
||||
|
@ -970,25 +968,6 @@ static void mos7720_bulk_out_data_callback(struct urb *urb)
|
|||
tty_port_tty_wakeup(&mos7720_port->port->port);
|
||||
}
|
||||
|
||||
/*
|
||||
* mos77xx_probe
|
||||
* this function installs the appropriate read interrupt endpoint callback
|
||||
* depending on whether the device is a 7720 or 7715, thus avoiding costly
|
||||
* run-time checks in the high-frequency callback routine itself.
|
||||
*/
|
||||
static int mos77xx_probe(struct usb_serial *serial,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
if (id->idProduct == MOSCHIP_DEVICE_ID_7715)
|
||||
moschip7720_2port_driver.read_int_callback =
|
||||
mos7715_interrupt_callback;
|
||||
else
|
||||
moschip7720_2port_driver.read_int_callback =
|
||||
mos7720_interrupt_callback;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mos77xx_calc_num_ports(struct usb_serial *serial)
|
||||
{
|
||||
u16 product = le16_to_cpu(serial->dev->descriptor.idProduct);
|
||||
|
@ -1917,6 +1896,11 @@ static int mos7720_startup(struct usb_serial *serial)
|
|||
u16 product;
|
||||
int ret_val;
|
||||
|
||||
if (serial->num_bulk_in < 2 || serial->num_bulk_out < 2) {
|
||||
dev_err(&serial->interface->dev, "missing bulk endpoints\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
product = le16_to_cpu(serial->dev->descriptor.idProduct);
|
||||
dev = serial->dev;
|
||||
|
||||
|
@ -1941,19 +1925,18 @@ static int mos7720_startup(struct usb_serial *serial)
|
|||
tmp->interrupt_in_endpointAddress;
|
||||
serial->port[1]->interrupt_in_urb = NULL;
|
||||
serial->port[1]->interrupt_in_buffer = NULL;
|
||||
|
||||
if (serial->port[0]->interrupt_in_urb) {
|
||||
struct urb *urb = serial->port[0]->interrupt_in_urb;
|
||||
|
||||
urb->complete = mos7715_interrupt_callback;
|
||||
}
|
||||
}
|
||||
|
||||
/* setting configuration feature to one */
|
||||
usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
|
||||
(__u8)0x03, 0x00, 0x01, 0x00, NULL, 0x00, 5000);
|
||||
|
||||
/* start the interrupt urb */
|
||||
ret_val = usb_submit_urb(serial->port[0]->interrupt_in_urb, GFP_KERNEL);
|
||||
if (ret_val)
|
||||
dev_err(&dev->dev,
|
||||
"%s - Error %d submitting control urb\n",
|
||||
__func__, ret_val);
|
||||
|
||||
#ifdef CONFIG_USB_SERIAL_MOS7715_PARPORT
|
||||
if (product == MOSCHIP_DEVICE_ID_7715) {
|
||||
ret_val = mos7715_parport_init(serial);
|
||||
|
@ -1961,6 +1944,13 @@ static int mos7720_startup(struct usb_serial *serial)
|
|||
return ret_val;
|
||||
}
|
||||
#endif
|
||||
/* start the interrupt urb */
|
||||
ret_val = usb_submit_urb(serial->port[0]->interrupt_in_urb, GFP_KERNEL);
|
||||
if (ret_val) {
|
||||
dev_err(&dev->dev, "failed to submit interrupt urb: %d\n",
|
||||
ret_val);
|
||||
}
|
||||
|
||||
/* LSR For Port 1 */
|
||||
read_mos_reg(serial, 0, MOS7720_LSR, &data);
|
||||
dev_dbg(&dev->dev, "LSR:%x\n", data);
|
||||
|
@ -1970,6 +1960,8 @@ static int mos7720_startup(struct usb_serial *serial)
|
|||
|
||||
static void mos7720_release(struct usb_serial *serial)
|
||||
{
|
||||
usb_kill_urb(serial->port[0]->interrupt_in_urb);
|
||||
|
||||
#ifdef CONFIG_USB_SERIAL_MOS7715_PARPORT
|
||||
/* close the parallel port */
|
||||
|
||||
|
@ -2019,11 +2011,6 @@ static int mos7720_port_probe(struct usb_serial_port *port)
|
|||
if (!mos7720_port)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Initialize all port interrupt end point to port 0 int endpoint.
|
||||
* Our device has only one interrupt endpoint common to all ports.
|
||||
*/
|
||||
port->interrupt_in_endpointAddress =
|
||||
port->serial->port[0]->interrupt_in_endpointAddress;
|
||||
mos7720_port->port = port;
|
||||
|
||||
usb_set_serial_port_data(port, mos7720_port);
|
||||
|
@ -2053,7 +2040,6 @@ static struct usb_serial_driver moschip7720_2port_driver = {
|
|||
.close = mos7720_close,
|
||||
.throttle = mos7720_throttle,
|
||||
.unthrottle = mos7720_unthrottle,
|
||||
.probe = mos77xx_probe,
|
||||
.attach = mos7720_startup,
|
||||
.release = mos7720_release,
|
||||
.port_probe = mos7720_port_probe,
|
||||
|
@ -2067,7 +2053,7 @@ static struct usb_serial_driver moschip7720_2port_driver = {
|
|||
.chars_in_buffer = mos7720_chars_in_buffer,
|
||||
.break_ctl = mos7720_break,
|
||||
.read_bulk_callback = mos7720_bulk_in_callback,
|
||||
.read_int_callback = NULL /* dynamically assigned in probe() */
|
||||
.read_int_callback = mos7720_interrupt_callback,
|
||||
};
|
||||
|
||||
static struct usb_serial_driver * const serial_drivers[] = {
|
||||
|
|
|
@ -214,7 +214,6 @@ MODULE_DEVICE_TABLE(usb, id_table);
|
|||
|
||||
struct moschip_port {
|
||||
int port_num; /*Actual port number in the device(1,2,etc) */
|
||||
struct urb *write_urb; /* write URB for this port */
|
||||
struct urb *read_urb; /* read URB for this port */
|
||||
__u8 shadowLCR; /* last LCR value received */
|
||||
__u8 shadowMCR; /* last MCR value received */
|
||||
|
@ -1037,9 +1036,7 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port)
|
|||
serial,
|
||||
serial->port[0]->interrupt_in_urb->interval);
|
||||
|
||||
/* start interrupt read for mos7840 *
|
||||
* will continue as long as mos7840 is connected */
|
||||
|
||||
/* start interrupt read for mos7840 */
|
||||
response =
|
||||
usb_submit_urb(serial->port[0]->interrupt_in_urb,
|
||||
GFP_KERNEL);
|
||||
|
@ -1186,7 +1183,6 @@ static void mos7840_close(struct usb_serial_port *port)
|
|||
}
|
||||
}
|
||||
|
||||
usb_kill_urb(mos7840_port->write_urb);
|
||||
usb_kill_urb(mos7840_port->read_urb);
|
||||
mos7840_port->read_urb_busy = false;
|
||||
|
||||
|
@ -1199,12 +1195,6 @@ static void mos7840_close(struct usb_serial_port *port)
|
|||
}
|
||||
}
|
||||
|
||||
if (mos7840_port->write_urb) {
|
||||
/* if this urb had a transfer buffer already (old tx) free it */
|
||||
kfree(mos7840_port->write_urb->transfer_buffer);
|
||||
usb_free_urb(mos7840_port->write_urb);
|
||||
}
|
||||
|
||||
Data = 0x0;
|
||||
mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data);
|
||||
|
||||
|
@ -2113,6 +2103,17 @@ static int mos7840_calc_num_ports(struct usb_serial *serial)
|
|||
return mos7840_num_ports;
|
||||
}
|
||||
|
||||
static int mos7840_attach(struct usb_serial *serial)
|
||||
{
|
||||
if (serial->num_bulk_in < serial->num_ports ||
|
||||
serial->num_bulk_out < serial->num_ports) {
|
||||
dev_err(&serial->interface->dev, "missing endpoints\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mos7840_port_probe(struct usb_serial_port *port)
|
||||
{
|
||||
struct usb_serial *serial = port->serial;
|
||||
|
@ -2388,6 +2389,7 @@ static struct usb_serial_driver moschip7840_4port_device = {
|
|||
.tiocmset = mos7840_tiocmset,
|
||||
.tiocmiwait = usb_serial_generic_tiocmiwait,
|
||||
.get_icount = usb_serial_generic_get_icount,
|
||||
.attach = mos7840_attach,
|
||||
.port_probe = mos7840_port_probe,
|
||||
.port_remove = mos7840_port_remove,
|
||||
.read_bulk_callback = mos7840_bulk_in_callback,
|
||||
|
|
|
@ -38,6 +38,7 @@ static int omninet_write(struct tty_struct *tty, struct usb_serial_port *port,
|
|||
const unsigned char *buf, int count);
|
||||
static int omninet_write_room(struct tty_struct *tty);
|
||||
static void omninet_disconnect(struct usb_serial *serial);
|
||||
static int omninet_attach(struct usb_serial *serial);
|
||||
static int omninet_port_probe(struct usb_serial_port *port);
|
||||
static int omninet_port_remove(struct usb_serial_port *port);
|
||||
|
||||
|
@ -56,6 +57,7 @@ static struct usb_serial_driver zyxel_omninet_device = {
|
|||
.description = "ZyXEL - omni.net lcd plus usb",
|
||||
.id_table = id_table,
|
||||
.num_ports = 1,
|
||||
.attach = omninet_attach,
|
||||
.port_probe = omninet_port_probe,
|
||||
.port_remove = omninet_port_remove,
|
||||
.open = omninet_open,
|
||||
|
@ -104,6 +106,17 @@ struct omninet_data {
|
|||
__u8 od_outseq; /* Sequence number for bulk_out URBs */
|
||||
};
|
||||
|
||||
static int omninet_attach(struct usb_serial *serial)
|
||||
{
|
||||
/* The second bulk-out endpoint is used for writing. */
|
||||
if (serial->num_bulk_out < 2) {
|
||||
dev_err(&serial->interface->dev, "missing endpoints\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int omninet_port_probe(struct usb_serial_port *port)
|
||||
{
|
||||
struct omninet_data *od;
|
||||
|
|
|
@ -134,6 +134,7 @@ static int oti6858_chars_in_buffer(struct tty_struct *tty);
|
|||
static int oti6858_tiocmget(struct tty_struct *tty);
|
||||
static int oti6858_tiocmset(struct tty_struct *tty,
|
||||
unsigned int set, unsigned int clear);
|
||||
static int oti6858_attach(struct usb_serial *serial);
|
||||
static int oti6858_port_probe(struct usb_serial_port *port);
|
||||
static int oti6858_port_remove(struct usb_serial_port *port);
|
||||
|
||||
|
@ -158,6 +159,7 @@ static struct usb_serial_driver oti6858_device = {
|
|||
.write_bulk_callback = oti6858_write_bulk_callback,
|
||||
.write_room = oti6858_write_room,
|
||||
.chars_in_buffer = oti6858_chars_in_buffer,
|
||||
.attach = oti6858_attach,
|
||||
.port_probe = oti6858_port_probe,
|
||||
.port_remove = oti6858_port_remove,
|
||||
};
|
||||
|
@ -324,6 +326,20 @@ static void send_data(struct work_struct *work)
|
|||
usb_serial_port_softint(port);
|
||||
}
|
||||
|
||||
static int oti6858_attach(struct usb_serial *serial)
|
||||
{
|
||||
unsigned char num_ports = serial->num_ports;
|
||||
|
||||
if (serial->num_bulk_in < num_ports ||
|
||||
serial->num_bulk_out < num_ports ||
|
||||
serial->num_interrupt_in < num_ports) {
|
||||
dev_err(&serial->interface->dev, "missing endpoints\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int oti6858_port_probe(struct usb_serial_port *port)
|
||||
{
|
||||
struct oti6858_private *priv;
|
||||
|
|
|
@ -220,9 +220,17 @@ static int pl2303_probe(struct usb_serial *serial,
|
|||
static int pl2303_startup(struct usb_serial *serial)
|
||||
{
|
||||
struct pl2303_serial_private *spriv;
|
||||
unsigned char num_ports = serial->num_ports;
|
||||
enum pl2303_type type = TYPE_01;
|
||||
unsigned char *buf;
|
||||
|
||||
if (serial->num_bulk_in < num_ports ||
|
||||
serial->num_bulk_out < num_ports ||
|
||||
serial->num_interrupt_in < num_ports) {
|
||||
dev_err(&serial->interface->dev, "missing endpoints\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
spriv = kzalloc(sizeof(*spriv), GFP_KERNEL);
|
||||
if (!spriv)
|
||||
return -ENOMEM;
|
||||
|
|
|
@ -408,16 +408,12 @@ static void qt2_close(struct usb_serial_port *port)
|
|||
{
|
||||
struct usb_serial *serial;
|
||||
struct qt2_port_private *port_priv;
|
||||
unsigned long flags;
|
||||
int i;
|
||||
|
||||
serial = port->serial;
|
||||
port_priv = usb_get_serial_port_data(port);
|
||||
|
||||
spin_lock_irqsave(&port_priv->urb_lock, flags);
|
||||
usb_kill_urb(port_priv->write_urb);
|
||||
port_priv->urb_in_use = false;
|
||||
spin_unlock_irqrestore(&port_priv->urb_lock, flags);
|
||||
|
||||
/* flush the port transmit buffer */
|
||||
i = usb_control_msg(serial->dev,
|
||||
|
|
|
@ -154,6 +154,19 @@ static int spcp8x5_probe(struct usb_serial *serial,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int spcp8x5_attach(struct usb_serial *serial)
|
||||
{
|
||||
unsigned char num_ports = serial->num_ports;
|
||||
|
||||
if (serial->num_bulk_in < num_ports ||
|
||||
serial->num_bulk_out < num_ports) {
|
||||
dev_err(&serial->interface->dev, "missing endpoints\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int spcp8x5_port_probe(struct usb_serial_port *port)
|
||||
{
|
||||
const struct usb_device_id *id = usb_get_serial_data(port->serial);
|
||||
|
@ -477,6 +490,7 @@ static struct usb_serial_driver spcp8x5_device = {
|
|||
.tiocmget = spcp8x5_tiocmget,
|
||||
.tiocmset = spcp8x5_tiocmset,
|
||||
.probe = spcp8x5_probe,
|
||||
.attach = spcp8x5_attach,
|
||||
.port_probe = spcp8x5_port_probe,
|
||||
.port_remove = spcp8x5_port_remove,
|
||||
};
|
||||
|
|
|
@ -579,6 +579,13 @@ static int ti_startup(struct usb_serial *serial)
|
|||
goto free_tdev;
|
||||
}
|
||||
|
||||
if (serial->num_bulk_in < serial->num_ports ||
|
||||
serial->num_bulk_out < serial->num_ports) {
|
||||
dev_err(&serial->interface->dev, "missing endpoints\n");
|
||||
status = -ENODEV;
|
||||
goto free_tdev;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
free_tdev:
|
||||
|
|
Loading…
Reference in a new issue