Commit a6d2de9c authored by Johan Hovold's avatar Johan Hovold Committed by Greg Kroah-Hartman

USB: mos7840: fix race in register handling

commit d8a083cc upstream.

Fix race in mos7840_get_reg which unconditionally manipulated the
control urb (which may already be in use) by adding a control-urb busy
flag.
Signed-off-by: default avatarJohan Hovold <jhovold@gmail.com>
[bwh: Backported to 3.2: adjust context]
Signed-off-by: default avatarBen Hutchings <ben@decadent.org.uk>
Cc: Yang Yingliang <yangyingliang@huawei.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 6ff428d6
...@@ -185,6 +185,10 @@ ...@@ -185,6 +185,10 @@
#define URB_TRANSFER_BUFFER_SIZE 32 /* URB Size */ #define URB_TRANSFER_BUFFER_SIZE 32 /* URB Size */
enum mos7840_flag {
MOS7840_FLAG_CTRL_BUSY,
};
static const struct usb_device_id moschip_port_id_table[] = { static const struct usb_device_id moschip_port_id_table[] = {
{USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7840)}, {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7840)},
{USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7820)}, {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7820)},
...@@ -258,6 +262,8 @@ struct moschip_port { ...@@ -258,6 +262,8 @@ struct moschip_port {
struct urb *write_urb_pool[NUM_URBS]; struct urb *write_urb_pool[NUM_URBS];
char busy[NUM_URBS]; char busy[NUM_URBS];
bool read_urb_busy; bool read_urb_busy;
unsigned long flags;
}; };
...@@ -519,11 +525,11 @@ static void mos7840_control_callback(struct urb *urb) ...@@ -519,11 +525,11 @@ static void mos7840_control_callback(struct urb *urb)
/* this urb is terminated, clean up */ /* this urb is terminated, clean up */
dbg("%s - urb shutting down with status: %d", __func__, dbg("%s - urb shutting down with status: %d", __func__,
status); status);
return; goto out;
default: default:
dbg("%s - nonzero urb status received: %d", __func__, dbg("%s - nonzero urb status received: %d", __func__,
status); status);
return; goto out;
} }
dbg("%s urb buffer size is %d", __func__, urb->actual_length); dbg("%s urb buffer size is %d", __func__, urb->actual_length);
...@@ -536,6 +542,8 @@ static void mos7840_control_callback(struct urb *urb) ...@@ -536,6 +542,8 @@ static void mos7840_control_callback(struct urb *urb)
mos7840_handle_new_msr(mos7840_port, regval); mos7840_handle_new_msr(mos7840_port, regval);
else if (mos7840_port->MsrLsr == 1) else if (mos7840_port->MsrLsr == 1)
mos7840_handle_new_lsr(mos7840_port, regval); mos7840_handle_new_lsr(mos7840_port, regval);
out:
clear_bit_unlock(MOS7840_FLAG_CTRL_BUSY, &mos7840_port->flags);
} }
static int mos7840_get_reg(struct moschip_port *mcs, __u16 Wval, __u16 reg, static int mos7840_get_reg(struct moschip_port *mcs, __u16 Wval, __u16 reg,
...@@ -546,6 +554,9 @@ static int mos7840_get_reg(struct moschip_port *mcs, __u16 Wval, __u16 reg, ...@@ -546,6 +554,9 @@ static int mos7840_get_reg(struct moschip_port *mcs, __u16 Wval, __u16 reg,
unsigned char *buffer = mcs->ctrl_buf; unsigned char *buffer = mcs->ctrl_buf;
int ret; int ret;
if (test_and_set_bit_lock(MOS7840_FLAG_CTRL_BUSY, &mcs->flags))
return -EBUSY;
dr->bRequestType = MCS_RD_RTYPE; dr->bRequestType = MCS_RD_RTYPE;
dr->bRequest = MCS_RDREQ; dr->bRequest = MCS_RDREQ;
dr->wValue = cpu_to_le16(Wval); /* 0 */ dr->wValue = cpu_to_le16(Wval); /* 0 */
...@@ -557,6 +568,9 @@ static int mos7840_get_reg(struct moschip_port *mcs, __u16 Wval, __u16 reg, ...@@ -557,6 +568,9 @@ static int mos7840_get_reg(struct moschip_port *mcs, __u16 Wval, __u16 reg,
mos7840_control_callback, mcs); mos7840_control_callback, mcs);
mcs->control_urb->transfer_buffer_length = 2; mcs->control_urb->transfer_buffer_length = 2;
ret = usb_submit_urb(mcs->control_urb, GFP_ATOMIC); ret = usb_submit_urb(mcs->control_urb, GFP_ATOMIC);
if (ret)
clear_bit_unlock(MOS7840_FLAG_CTRL_BUSY, &mcs->flags);
return ret; return ret;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment