aboutsummaryrefslogtreecommitdiff
path: root/drivers/usb/gadget/function/f_diag.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/gadget/function/f_diag.c')
-rw-r--r--drivers/usb/gadget/function/f_diag.c62
1 files changed, 61 insertions, 1 deletions
diff --git a/drivers/usb/gadget/function/f_diag.c b/drivers/usb/gadget/function/f_diag.c
index 3b57ad9c..4aaeb1e5 100644
--- a/drivers/usb/gadget/function/f_diag.c
+++ b/drivers/usb/gadget/function/f_diag.c
@@ -27,6 +27,13 @@
#include <linux/workqueue.h>
#include <linux/debugfs.h>
#include <linux/kmemleak.h>
+#ifdef CONFIG_DIAG_OVER_TTY
+#include <linux/usb/tty_diag.h>
+#include <linux/of.h>
+
+static bool tty_mode;
+module_param(tty_mode, bool, S_IRUGO);
+#endif
static DEFINE_SPINLOCK(ch_lock);
static LIST_HEAD(usb_diag_ch_list);
@@ -174,6 +181,23 @@ static inline struct diag_context *func_to_diag(struct usb_function *f)
return container_of(f, struct diag_context, function);
}
+#ifdef CONFIG_DIAG_OVER_TTY
+static bool factory_cable_present(void)
+{
+ struct device_node *np;
+ bool fact_cable;
+
+ np = of_find_node_by_path("/chosen");
+ fact_cable = of_property_read_bool(np, "mmi,factory-cable");
+ of_node_put(np);
+
+ if (!np || !fact_cable)
+ return false;
+
+ return true;
+}
+#endif
+
/* Called with ctxt->lock held; i.e. only use with kref_put_spinlock_irqsave */
static void diag_context_release(struct kref *kref)
{
@@ -302,6 +326,17 @@ struct usb_diag_ch *usb_diag_open(const char *name, void *priv,
unsigned long flags;
int found = 0;
+#ifdef CONFIG_DIAG_OVER_TTY
+ static bool init;
+
+ if (!init) {
+ init = true;
+ tty_mode = factory_cable_present();
+ }
+
+ if (tty_mode)
+ return tty_diag_channel_open(name, priv, notify);
+#endif
spin_lock_irqsave(&ch_lock, flags);
/* Check if we already have a channel with this name */
list_for_each_entry(ch, &usb_diag_ch_list, list) {
@@ -342,6 +377,10 @@ void usb_diag_close(struct usb_diag_ch *ch)
struct diag_context *dev = NULL;
unsigned long flags;
+#ifdef CONFIG_DIAG_OVER_TTY
+ if (tty_mode)
+ return tty_diag_channel_close(ch);
+#endif
spin_lock_irqsave(&ch_lock, flags);
ch->priv = NULL;
ch->notify = NULL;
@@ -392,6 +431,10 @@ int usb_diag_alloc_req(struct usb_diag_ch *ch, int n_write, int n_read)
int i;
unsigned long flags;
+#ifdef CONFIG_DIAG_OVER_TTY
+ if (tty_mode)
+ return 0;
+#endif
if (!ctxt)
return -ENODEV;
@@ -437,7 +480,15 @@ EXPORT_SYMBOL(usb_diag_alloc_req);
int usb_diag_request_size(struct usb_diag_ch *ch)
{
struct diag_context *ctxt = ch->priv_usb;
- struct usb_composite_dev *cdev = ctxt->cdev;
+ struct usb_composite_dev *cdev = NULL;
+
+ /* MOT: qcom code need to check if the pointer is null
+ anyway, we use the default size for tty mode
+ */
+ if (ctxt != NULL && ctxt->cdev != NULL)
+ cdev = ctxt->cdev;
+ else
+ return CI_MAX_REQUEST_SIZE;
if (gadget_is_dwc3(cdev->gadget))
return DWC3_MAX_REQUEST_SIZE;
@@ -467,6 +518,10 @@ int usb_diag_read(struct usb_diag_ch *ch, struct diag_request *d_req)
struct usb_ep *out;
static DEFINE_RATELIMIT_STATE(rl, 10*HZ, 1);
+#ifdef CONFIG_DIAG_OVER_TTY
+ if (tty_mode)
+ return tty_diag_channel_read(ch, d_req);
+#endif
if (!ctxt)
return -ENODEV;
@@ -544,6 +599,11 @@ int usb_diag_write(struct usb_diag_ch *ch, struct diag_request *d_req)
struct usb_ep *in;
static DEFINE_RATELIMIT_STATE(rl, 10*HZ, 1);
+#ifdef CONFIG_DIAG_OVER_TTY
+ if (tty_mode)
+ return tty_diag_channel_write(ch, d_req);
+#endif
+
if (!ctxt)
return -ENODEV;