summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/arm/msm/imem.txt9
-rw-r--r--drivers/usb/gadget/function/f_diag.c83
-rw-r--r--include/linux/qcom/diag_dload.h32
3 files changed, 99 insertions, 25 deletions
diff --git a/Documentation/devicetree/bindings/arm/msm/imem.txt b/Documentation/devicetree/bindings/arm/msm/imem.txt
index 630fa1a07f11..d1f8ce1e5ac8 100644
--- a/Documentation/devicetree/bindings/arm/msm/imem.txt
+++ b/Documentation/devicetree/bindings/arm/msm/imem.txt
@@ -57,6 +57,15 @@ Emergency Download Mode:
-compatible: "qcom,msm-imem-emergency_download_mode"
-reg: start address and size of emergency_download_mode region in imem
+USB Diag Cookies:
+-----------------
+Memory region used to store USB PID and serial numbers to be used by
+bootloader in download mode.
+
+Required properties:
+-compatible: "qcom,msm-imem-diag-dload"
+-reg: start address and size of USB Diag download mode region in imem
+
Example:
qcom,msm-imem {
diff --git a/drivers/usb/gadget/function/f_diag.c b/drivers/usb/gadget/function/f_diag.c
index 3754ca281998..edb3343f87e1 100644
--- a/drivers/usb/gadget/function/f_diag.c
+++ b/drivers/usb/gadget/function/f_diag.c
@@ -2,7 +2,7 @@
* Diag Function Device - Route ARM9 and ARM11 DIAG messages
* between HOST and DEVICE.
* Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2008-2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2008-2016, The Linux Foundation. All rights reserved.
* Author: Brian Swetland <swetland@google.com>
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -18,6 +18,7 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/kref.h>
+#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/ratelimit.h>
@@ -27,10 +28,13 @@
#include <linux/workqueue.h>
#include <linux/debugfs.h>
#include <linux/kmemleak.h>
+#include <linux/qcom/diag_dload.h>
static DEFINE_SPINLOCK(ch_lock);
static LIST_HEAD(usb_diag_ch_list);
+static struct dload_struct __iomem *diag_dload;
+
static struct usb_interface_descriptor intf_desc = {
.bLength = sizeof intf_desc,
.bDescriptorType = USB_DT_INTERFACE,
@@ -154,7 +158,6 @@ struct diag_context {
spinlock_t lock;
unsigned configured;
struct usb_composite_dev *cdev;
- int (*update_pid_and_serial_num)(uint32_t, const char *);
struct usb_diag_ch *ch;
struct kref kref;
@@ -189,36 +192,48 @@ static void diag_update_pid_and_serial_num(struct diag_context *ctxt)
struct usb_composite_dev *cdev = ctxt->cdev;
struct usb_gadget_strings *table;
struct usb_string *s;
-
- if (!ctxt->update_pid_and_serial_num)
- return;
+ struct dload_struct local_diag_dload = { 0 };
/*
- * update pid and serail number to dload only if diag
+ * update pid and serial number to dload only if diag
* interface is zeroth interface.
*/
if (intf_desc.bInterfaceNumber)
return;
- /* pass on product id and serial number to dload */
- if (!cdev->desc.iSerialNumber) {
- ctxt->update_pid_and_serial_num(
- cdev->desc.idProduct, 0);
+ if (!diag_dload) {
+ pr_debug("%s: unable to update PID and serial_no\n", __func__);
return;
}
- /*
- * Serial number is filled by the composite driver. So
- * it is fair enough to assume that it will always be
- * found at first table of strings.
- */
- table = *(cdev->driver->strings);
- for (s = table->strings; s && s->s; s++)
- if (s->id == cdev->desc.iSerialNumber) {
- ctxt->update_pid_and_serial_num(
- cdev->desc.idProduct, s->s);
- break;
+ /* update pid */
+ local_diag_dload.magic_struct.pid = PID_MAGIC_ID;
+ local_diag_dload.pid = cdev->desc.idProduct;
+
+ /* pass on product id and serial number to dload */
+ if (cdev->desc.iSerialNumber) {
+ /*
+ * Serial number is filled by the composite driver. So
+ * it is fair enough to assume that it will always be
+ * found at first table of strings.
+ */
+ table = *(cdev->driver->strings);
+ for (s = table->strings; s && s->s; s++) {
+ if (s->id == cdev->desc.iSerialNumber) {
+ local_diag_dload.magic_struct.serial_num =
+ SERIAL_NUM_MAGIC_ID;
+ strlcpy(local_diag_dload.serial_number, s->s,
+ SERIAL_NUMBER_LENGTH);
+ break;
+ }
}
+ }
+
+ pr_debug("%s: dload:%p pid:%x serial_num:%s\n",
+ __func__, diag_dload, local_diag_dload.pid,
+ local_diag_dload.serial_number);
+
+ memcpy_toio(diag_dload, &local_diag_dload, sizeof(local_diag_dload));
}
static void diag_write_complete(struct usb_ep *ep,
@@ -767,7 +782,12 @@ static int diag_function_bind(struct usb_configuration *c,
if (!f->ss_descriptors)
goto fail;
}
- diag_update_pid_and_serial_num(ctxt);
+
+ /* Allow only first diag channel to update pid and serial no */
+ if (ctxt == list_first_entry(&diag_dev_list,
+ struct diag_context, list_item))
+ diag_update_pid_and_serial_num(ctxt);
+
return 0;
fail:
if (f->ss_descriptors)
@@ -784,8 +804,7 @@ fail:
}
-int diag_function_add(struct usb_configuration *c, const char *name,
- int (*update_pid)(uint32_t, const char *))
+int diag_function_add(struct usb_configuration *c, const char *name)
{
struct diag_context *dev;
struct usb_diag_ch *_ch;
@@ -818,7 +837,6 @@ int diag_function_add(struct usb_configuration *c, const char *name,
*/
dev->ch = _ch;
- dev->update_pid_and_serial_num = update_pid;
dev->cdev = c->cdev;
dev->function.name = _ch->name;
dev->function.fs_descriptors = fs_diag_desc;
@@ -941,6 +959,9 @@ static void diag_cleanup(void)
struct usb_diag_ch *_ch;
unsigned long flags;
+ if (diag_dload)
+ iounmap(diag_dload);
+
fdiag_debugfs_remove();
list_for_each_safe(act, tmp, &usb_diag_ch_list) {
@@ -958,9 +979,21 @@ static void diag_cleanup(void)
static int diag_setup(void)
{
+ struct device_node *np;
+
INIT_LIST_HEAD(&diag_dev_list);
fdiag_debugfs_init();
+ np = of_find_compatible_node(NULL, NULL, "qcom,msm-imem-diag-dload");
+ if (!np)
+ np = of_find_compatible_node(NULL, NULL, "qcom,android-usb");
+
+ if (!np) {
+ pr_warn("diag: failed to find diag_dload imem node\n");
+ return 0;
+ }
+ diag_dload = of_iomap(np, 0);
+
return 0;
}
diff --git a/include/linux/qcom/diag_dload.h b/include/linux/qcom/diag_dload.h
new file mode 100644
index 000000000000..83c7f2d45f2d
--- /dev/null
+++ b/include/linux/qcom/diag_dload.h
@@ -0,0 +1,32 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __LINUX_DIAG_DLOAD_H__
+#define __LINUX_DIAG_DLOAD_H__
+
+
+#define PID_MAGIC_ID 0x71432909
+#define SERIAL_NUM_MAGIC_ID 0x61945374
+#define SERIAL_NUMBER_LENGTH 128
+
+struct magic_num_struct {
+ uint32_t pid;
+ uint32_t serial_num;
+};
+
+struct dload_struct {
+ uint32_t pid;
+ char serial_number[SERIAL_NUMBER_LENGTH];
+ struct magic_num_struct magic_struct;
+};
+
+#endif