summaryrefslogtreecommitdiff
path: root/drivers/usb/gadget
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/gadget')
-rw-r--r--drivers/usb/gadget/composite.c23
-rw-r--r--drivers/usb/gadget/function/f_gsi.c72
-rw-r--r--drivers/usb/gadget/function/u_ether.c1
3 files changed, 64 insertions, 32 deletions
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 3d17fd93c787..a99405261306 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -27,6 +27,14 @@
#define SSUSB_GADGET_VBUS_DRAW_UNITS 8
#define HSUSB_GADGET_VBUS_DRAW_UNITS 2
+/*
+ * Based on enumerated USB speed, draw power with set_config and resume
+ * HSUSB: 500mA, SSUSB: 900mA
+ */
+#define USB_VBUS_DRAW(speed)\
+ (speed == USB_SPEED_SUPER ?\
+ SSUSB_GADGET_VBUS_DRAW : CONFIG_USB_GADGET_VBUS_DRAW)
+
static bool enable_l1_for_hs;
module_param(enable_l1_for_hs, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(enable_l1_for_hs, "Enable support for L1 LPM for HS devices");
@@ -749,7 +757,6 @@ static int set_config(struct usb_composite_dev *cdev,
struct usb_gadget *gadget = cdev->gadget;
struct usb_configuration *c = NULL;
int result = -EINVAL;
- unsigned power = gadget_is_otg(gadget) ? 8 : 100;
int tmp;
/*
@@ -863,14 +870,8 @@ static int set_config(struct usb_composite_dev *cdev,
}
}
- /* Allow 900mA to draw with Super-Speed */
- if (gadget->speed == USB_SPEED_SUPER)
- power = SSUSB_GADGET_VBUS_DRAW;
- else
- power = CONFIG_USB_GADGET_VBUS_DRAW;
-
done:
- usb_gadget_vbus_draw(gadget, power);
+ usb_gadget_vbus_draw(gadget, USB_VBUS_DRAW(gadget->speed));
if (result >= 0 && cdev->delayed_status)
result = USB_GADGET_DELAYED_STATUS;
return result;
@@ -2319,7 +2320,6 @@ void composite_resume(struct usb_gadget *gadget)
{
struct usb_composite_dev *cdev = get_gadget_data(gadget);
struct usb_function *f;
- u16 maxpower;
int ret;
unsigned long flags;
@@ -2352,10 +2352,7 @@ void composite_resume(struct usb_gadget *gadget)
f->resume(f);
}
- maxpower = cdev->config->MaxPower;
-
- usb_gadget_vbus_draw(gadget, maxpower ?
- maxpower : CONFIG_USB_GADGET_VBUS_DRAW);
+ usb_gadget_vbus_draw(gadget, USB_VBUS_DRAW(gadget->speed));
}
spin_unlock_irqrestore(&cdev->lock, flags);
diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c
index e32348d17b26..80c9928e948e 100644
--- a/drivers/usb/gadget/function/f_gsi.c
+++ b/drivers/usb/gadget/function/f_gsi.c
@@ -36,6 +36,7 @@ MODULE_PARM_DESC(num_out_bufs,
static struct workqueue_struct *ipa_usb_wq;
+static void gsi_rndis_ipa_reset_trigger(struct f_gsi *rndis);
static void ipa_disconnect_handler(struct gsi_data_port *d_port);
static int gsi_ctrl_send_notification(struct f_gsi *gsi,
enum gsi_ctrl_notify_state);
@@ -553,6 +554,7 @@ static void ipa_work_handler(struct work_struct *w)
struct device *dev;
struct device *gad_dev;
struct f_gsi *gsi;
+ bool block_db;
event = read_event(d_port);
@@ -665,7 +667,27 @@ static void ipa_work_handler(struct work_struct *w)
}
break;
case STATE_CONNECTED:
- if (event == EVT_DISCONNECTED) {
+ if (event == EVT_DISCONNECTED || event == EVT_HOST_NRDY) {
+ if (peek_event(d_port) == EVT_HOST_READY) {
+ read_event(d_port);
+ log_event_dbg("%s: NO_OP NRDY_RDY", __func__);
+ break;
+ }
+
+ if (event == EVT_HOST_NRDY) {
+ log_event_dbg("%s: ST_CON_HOST_NRDY\n",
+ __func__);
+ block_db = true;
+ /* stop USB ringing doorbell to GSI(OUT_EP) */
+ usb_gsi_ep_op(d_port->in_ep, (void *)&block_db,
+ GSI_EP_OP_SET_CLR_BLOCK_DBL);
+ gsi_rndis_ipa_reset_trigger(gsi);
+ usb_gsi_ep_op(d_port->in_ep, NULL,
+ GSI_EP_OP_ENDXFER);
+ usb_gsi_ep_op(d_port->out_ep, NULL,
+ GSI_EP_OP_ENDXFER);
+ }
+
ipa_disconnect_work_handler(d_port);
d_port->sm_state = STATE_INITIALIZED;
usb_gadget_autopm_put_async(d_port->gadget);
@@ -1269,7 +1291,7 @@ static void gsi_rndis_open(struct f_gsi *rndis)
rndis_signal_connect(rndis->params);
}
-void gsi_rndis_ipa_reset_trigger(struct f_gsi *rndis)
+static void gsi_rndis_ipa_reset_trigger(struct f_gsi *rndis)
{
unsigned long flags;
@@ -1301,12 +1323,11 @@ void gsi_rndis_flow_ctrl_enable(bool enable, struct rndis_params *param)
d_port = &rndis->d_port;
- if (enable) {
- gsi_rndis_ipa_reset_trigger(rndis);
- usb_gsi_ep_op(d_port->in_ep, NULL, GSI_EP_OP_ENDXFER);
- usb_gsi_ep_op(d_port->out_ep, NULL, GSI_EP_OP_ENDXFER);
- post_event(d_port, EVT_DISCONNECTED);
+ if (enable) {
+ log_event_dbg("%s: posting HOST_NRDY\n", __func__);
+ post_event(d_port, EVT_HOST_NRDY);
} else {
+ log_event_dbg("%s: posting HOST_READY\n", __func__);
post_event(d_port, EVT_HOST_READY);
}
@@ -1359,6 +1380,12 @@ static int gsi_ctrl_send_notification(struct f_gsi *gsi,
return -ENODEV;
}
+ if (atomic_inc_return(&gsi->c_port.notify_count) != 1) {
+ log_event_dbg("delay ep_queue: notify req is busy %d",
+ atomic_read(&gsi->c_port.notify_count));
+ return 0;
+ }
+
event = req->buf;
switch (state) {
@@ -1414,12 +1441,6 @@ static int gsi_ctrl_send_notification(struct f_gsi *gsi,
log_event_dbg("send Notify type %02x", event->bNotificationType);
- if (atomic_inc_return(&gsi->c_port.notify_count) != 1) {
- log_event_dbg("delay ep_queue: notify req is busy %d",
- atomic_read(&gsi->c_port.notify_count));
- return 0;
- }
-
return queue_notification_request(gsi);
}
@@ -1469,7 +1490,8 @@ static void gsi_rndis_response_available(void *_rndis)
{
struct f_gsi *gsi = _rndis;
- gsi_ctrl_send_notification(gsi, GSI_CTRL_NOTIFY_RESPONSE_AVAILABLE);
+ gsi_ctrl_send_notification(gsi,
+ GSI_CTRL_NOTIFY_RESPONSE_AVAILABLE);
}
static void gsi_rndis_command_complete(struct usb_ep *ep,
@@ -2056,6 +2078,8 @@ static void gsi_suspend(struct usb_function *f)
queue_work(gsi->d_port.ipa_usb_wq, &gsi->d_port.usb_ipa_w);
}
+ log_event_dbg("%s: notify_count = %d\n",
+ __func__, atomic_read(&gsi->c_port.notify_count));
log_event_dbg("gsi suspended");
}
@@ -2080,6 +2104,21 @@ static void gsi_resume(struct usb_function *f)
else
remote_wakeup_allowed = f->config->cdev->gadget->remote_wakeup;
+ if (gsi->c_port.notify && !gsi->c_port.notify->desc)
+ config_ep_by_speed(cdev->gadget, f, gsi->c_port.notify);
+
+ log_event_dbg("%s: notify_count = %d\n",
+ __func__, atomic_read(&gsi->c_port.notify_count));
+
+ /* Send notification to host for RMNET, RNDIS and MBIM Interface */
+ if ((gsi->prot_id == IPA_USB_MBIM ||
+ gsi->prot_id == IPA_USB_RNDIS ||
+ gsi->prot_id == IPA_USB_RMNET) &&
+ (atomic_read(&gsi->c_port.notify_count) >= 1)) {
+ log_event_dbg("%s: force_queue\n", __func__);
+ queue_notification_request(gsi);
+ }
+
if (!remote_wakeup_allowed) {
/* Configure EPs for GSI */
@@ -2110,11 +2149,6 @@ static void gsi_resume(struct usb_function *f)
post_event(&gsi->d_port, EVT_RESUMED);
queue_work(gsi->d_port.ipa_usb_wq, &gsi->d_port.usb_ipa_w);
-
- if (gsi->c_port.notify && !gsi->c_port.notify->desc)
- config_ep_by_speed(cdev->gadget, f, gsi->c_port.notify);
-
- atomic_set(&gsi->c_port.notify_count, 0);
log_event_dbg("%s: completed", __func__);
}
diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c
index 76b25445c6ad..dd73dfe5dcab 100644
--- a/drivers/usb/gadget/function/u_ether.c
+++ b/drivers/usb/gadget/function/u_ether.c
@@ -1014,6 +1014,7 @@ struct net_device *gether_setup_name_default(const char *netname)
spin_lock_init(&dev->lock);
spin_lock_init(&dev->req_lock);
INIT_WORK(&dev->work, eth_work);
+ INIT_WORK(&dev->rx_work, process_rx_w);
INIT_LIST_HEAD(&dev->tx_reqs);
INIT_LIST_HEAD(&dev->rx_reqs);