Merge "usb: gadget: f_cdev: Handle notification request properly"

This commit is contained in:
Linux Build Service Account 2016-08-29 00:49:25 -07:00 committed by Gerrit - the friendly Code Review server
commit 50618ab44f

View file

@ -66,6 +66,7 @@ struct cserial {
struct usb_request *notify_req;
struct usb_cdc_line_coding port_line_coding;
u8 pending;
u8 q_again;
u8 data_id;
u16 serial_state;
u16 port_handshake_bits;
@ -538,8 +539,6 @@ static int usb_cser_notify(struct f_cdev *port, u8 type, u16 value,
}
req = port->port_usb.notify_req;
port->port_usb.notify_req = NULL;
port->port_usb.pending = false;
req->length = len;
notify = req->buf;
@ -559,7 +558,9 @@ static int usb_cser_notify(struct f_cdev *port, u8 type, u16 value,
if (status < 0) {
pr_err("port %s can't notify serial state, %d\n",
port->name, status);
port->port_usb.notify_req = req;
spin_lock_irqsave(&port->port_lock, flags);
port->port_usb.pending = false;
spin_unlock_irqrestore(&port->port_lock, flags);
}
return status;
@ -569,18 +570,24 @@ static int port_notify_serial_state(struct cserial *cser)
{
struct f_cdev *port = cser_to_port(cser);
int status;
unsigned long flags;
struct usb_composite_dev *cdev = port->port_usb.func.config->cdev;
if (port->port_usb.notify_req) {
spin_lock_irqsave(&port->port_lock, flags);
if (!port->port_usb.pending) {
port->port_usb.pending = true;
spin_unlock_irqrestore(&port->port_lock, flags);
dev_dbg(&cdev->gadget->dev, "port %d serial state %04x\n",
port->port_num, port->port_usb.serial_state);
status = usb_cser_notify(port, USB_CDC_NOTIFY_SERIAL_STATE,
0, &port->port_usb.serial_state,
sizeof(port->port_usb.serial_state));
spin_lock_irqsave(&port->port_lock, flags);
} else {
port->port_usb.pending = true;
port->port_usb.q_again = true;
status = 0;
}
spin_unlock_irqrestore(&port->port_lock, flags);
return status;
}
@ -588,14 +595,17 @@ static int port_notify_serial_state(struct cserial *cser)
static void usb_cser_notify_complete(struct usb_ep *ep, struct usb_request *req)
{
struct f_cdev *port = req->context;
u8 doit = false;
unsigned long flags;
if (req->status != -ESHUTDOWN)
doit = port->port_usb.pending;
port->port_usb.notify_req = req;
if (doit && port->is_connected)
spin_lock_irqsave(&port->port_lock, flags);
port->port_usb.pending = false;
if (req->status != -ESHUTDOWN && port->port_usb.q_again) {
port->port_usb.q_again = false;
spin_unlock_irqrestore(&port->port_lock, flags);
port_notify_serial_state(&port->port_usb);
spin_lock_irqsave(&port->port_lock, flags);
}
spin_unlock_irqrestore(&port->port_lock, flags);
}
static void dun_cser_connect(struct cserial *cser)
{
@ -674,8 +684,11 @@ static int dun_cser_send_ctrl_bits(struct cserial *cser, int ctrl_bits)
static void usb_cser_free_req(struct usb_ep *ep, struct usb_request *req)
{
kfree(req->buf);
usb_ep_free_request(ep, req);
if (req) {
kfree(req->buf);
usb_ep_free_request(ep, req);
req = NULL;
}
}
static void usb_cser_free_requests(struct usb_ep *ep, struct list_head *head)
@ -820,7 +833,6 @@ static void usb_cser_unbind(struct usb_configuration *c, struct usb_function *f)
usb_free_all_descriptors(f);
usb_cser_free_req(port->port_usb.notify, port->port_usb.notify_req);
port->port_usb.notify_req = NULL;
}
static int usb_cser_alloc_requests(struct usb_ep *ep, struct list_head *head,
@ -1452,6 +1464,8 @@ int usb_cser_connect(struct f_cdev *port)
cser->out->driver_data = port;
spin_lock_irqsave(&port->port_lock, flags);
cser->pending = false;
cser->q_again = false;
port->is_connected = true;
spin_unlock_irqrestore(&port->port_lock, flags);