summaryrefslogtreecommitdiff
path: root/drivers/usb/serial/metro-usb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/serial/metro-usb.c')
-rw-r--r--drivers/usb/serial/metro-usb.c66
1 files changed, 38 insertions, 28 deletions
diff --git a/drivers/usb/serial/metro-usb.c b/drivers/usb/serial/metro-usb.c
index cc84da8dbb84..028878292901 100644
--- a/drivers/usb/serial/metro-usb.c
+++ b/drivers/usb/serial/metro-usb.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
Some of this code is credited to Linux USB open source files that are
distributed with Linux.
@@ -45,6 +46,7 @@ struct metrousb_private {
static const struct usb_device_id id_table[] = {
{ USB_DEVICE(FOCUS_VENDOR_ID, FOCUS_PRODUCT_ID_BI) },
{ USB_DEVICE(FOCUS_VENDOR_ID, FOCUS_PRODUCT_ID_UNI) },
+ { USB_DEVICE_INTERFACE_CLASS(0x0c2e, 0x0730, 0xff) }, /* MS7820 */
{ }, /* Terminating entry. */
};
MODULE_DEVICE_TABLE(usb, id_table);
@@ -53,21 +55,33 @@ MODULE_DEVICE_TABLE(usb, id_table);
#define UNI_CMD_OPEN 0x80
#define UNI_CMD_CLOSE 0xFF
-static inline int metrousb_is_unidirectional_mode(struct usb_serial_port *port)
+static int metrousb_is_unidirectional_mode(struct usb_serial *serial)
{
- __u16 product_id = le16_to_cpu(
- port->serial->dev->descriptor.idProduct);
+ u16 product_id = le16_to_cpu(serial->dev->descriptor.idProduct);
return product_id == FOCUS_PRODUCT_ID_UNI;
}
+static int metrousb_calc_num_ports(struct usb_serial *serial,
+ struct usb_serial_endpoints *epds)
+{
+ if (metrousb_is_unidirectional_mode(serial)) {
+ if (epds->num_interrupt_out == 0) {
+ dev_err(&serial->interface->dev, "interrupt-out endpoint missing\n");
+ return -ENODEV;
+ }
+ }
+
+ return 1;
+}
+
static int metrousb_send_unidirectional_cmd(u8 cmd, struct usb_serial_port *port)
{
int ret;
int actual_len;
u8 *buffer_cmd = NULL;
- if (!metrousb_is_unidirectional_mode(port))
+ if (!metrousb_is_unidirectional_mode(port->serial))
return 0;
buffer_cmd = kzalloc(sizeof(cmd), GFP_KERNEL);
@@ -95,9 +109,9 @@ static void metrousb_read_int_callback(struct urb *urb)
struct usb_serial_port *port = urb->context;
struct metrousb_private *metro_priv = usb_get_serial_port_data(port);
unsigned char *data = urb->transfer_buffer;
+ unsigned long flags;
int throttled = 0;
int result = 0;
- unsigned long flags = 0;
dev_dbg(&port->dev, "%s\n", __func__);
@@ -157,16 +171,9 @@ static int metrousb_open(struct tty_struct *tty, struct usb_serial_port *port)
{
struct usb_serial *serial = port->serial;
struct metrousb_private *metro_priv = usb_get_serial_port_data(port);
- unsigned long flags = 0;
+ unsigned long flags;
int result = 0;
- /* Make sure the urb is initialized. */
- if (!port->interrupt_in_urb) {
- dev_err(&port->dev, "%s - interrupt urb not initialized\n",
- __func__);
- return -ENODEV;
- }
-
/* Set the private data information for the port. */
spin_lock_irqsave(&metro_priv->lock, flags);
metro_priv->control_state = 0;
@@ -188,7 +195,7 @@ static int metrousb_open(struct tty_struct *tty, struct usb_serial_port *port)
dev_err(&port->dev,
"%s - failed submitting interrupt in urb, error code=%d\n",
__func__, result);
- goto exit;
+ return result;
}
/* Send activate cmd to device */
@@ -197,9 +204,14 @@ static int metrousb_open(struct tty_struct *tty, struct usb_serial_port *port)
dev_err(&port->dev,
"%s - failed to configure device, error code=%d\n",
__func__, result);
- goto exit;
+ goto err_kill_urb;
}
-exit:
+
+ return 0;
+
+err_kill_urb:
+ usb_kill_urb(port->interrupt_in_urb);
+
return result;
}
@@ -244,21 +256,19 @@ static int metrousb_port_probe(struct usb_serial_port *port)
return 0;
}
-static int metrousb_port_remove(struct usb_serial_port *port)
+static void metrousb_port_remove(struct usb_serial_port *port)
{
struct metrousb_private *metro_priv;
metro_priv = usb_get_serial_port_data(port);
kfree(metro_priv);
-
- return 0;
}
static void metrousb_throttle(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct metrousb_private *metro_priv = usb_get_serial_port_data(port);
- unsigned long flags = 0;
+ unsigned long flags;
/* Set the private information for the port to stop reading data. */
spin_lock_irqsave(&metro_priv->lock, flags);
@@ -271,7 +281,7 @@ static int metrousb_tiocmget(struct tty_struct *tty)
unsigned long control_state = 0;
struct usb_serial_port *port = tty->driver_data;
struct metrousb_private *metro_priv = usb_get_serial_port_data(port);
- unsigned long flags = 0;
+ unsigned long flags;
spin_lock_irqsave(&metro_priv->lock, flags);
control_state = metro_priv->control_state;
@@ -286,10 +296,10 @@ static int metrousb_tiocmset(struct tty_struct *tty,
struct usb_serial_port *port = tty->driver_data;
struct usb_serial *serial = port->serial;
struct metrousb_private *metro_priv = usb_get_serial_port_data(port);
- unsigned long flags = 0;
+ unsigned long flags;
unsigned long control_state = 0;
- dev_dbg(tty->dev, "%s - set=%d, clear=%d\n", __func__, set, clear);
+ dev_dbg(&port->dev, "%s - set=%d, clear=%d\n", __func__, set, clear);
spin_lock_irqsave(&metro_priv->lock, flags);
control_state = metro_priv->control_state;
@@ -313,7 +323,7 @@ static void metrousb_unthrottle(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct metrousb_private *metro_priv = usb_get_serial_port_data(port);
- unsigned long flags = 0;
+ unsigned long flags;
int result = 0;
/* Set the private information for the port to resume reading data. */
@@ -324,19 +334,19 @@ static void metrousb_unthrottle(struct tty_struct *tty)
/* Submit the urb to read from the port. */
result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
if (result)
- dev_err(tty->dev,
+ dev_err(&port->dev,
"failed submitting interrupt in urb error code=%d\n",
result);
}
static struct usb_serial_driver metrousb_device = {
.driver = {
- .owner = THIS_MODULE,
.name = "metro-usb",
},
.description = "Metrologic USB to Serial",
.id_table = id_table,
- .num_ports = 1,
+ .num_interrupt_in = 1,
+ .calc_num_ports = metrousb_calc_num_ports,
.open = metrousb_open,
.close = metrousb_cleanup,
.read_int_callback = metrousb_read_int_callback,
@@ -355,7 +365,7 @@ static struct usb_serial_driver * const serial_drivers[] = {
module_usb_serial_driver(serial_drivers, id_table);
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Philip Nicastro");
MODULE_AUTHOR("Aleksey Babahin <tamerlan311@gmail.com>");
MODULE_DESCRIPTION(DRIVER_DESC);