[PATCH] Adding rpc server

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Daniel
I've tried to import the SMD server pack into the kernel.
But somehow it went wrong.
Any suggestions?

best regards
	leviathan
---
 arch/arm/mach-msm/Kconfig                          |   25 +
 arch/arm/mach-msm/Makefile                         |    4 +-
 arch/arm/mach-msm/board-trout-battery.c            |  796 ++++++++++++
 arch/arm/mach-msm/board-trout-hsusb.c              |  352 ++++++
 arch/arm/mach-msm/gpio_chip.h                      |   38 +
 arch/arm/mach-msm/include/mach/board-hsusb.h       |   68 +
 arch/arm/mach-msm/include/mach/board.h             |    2 +
 arch/arm/mach-msm/smd_rpcrouter.c                  | 1310 ++++++++++++++++++++
 arch/arm/mach-msm/smd_rpcrouter.h                  |  195 +++
 arch/arm/mach-msm/smd_rpcrouter_device.c           |  377 ++++++
 arch/arm/mach-msm/smd_rpcrouter_servers.c          |  229 ++++
 drivers/staging/dream/include/mach/msm_rpcrouter.h |    1 +
 12 files changed, 3395 insertions(+), 2 deletions(-)
 create mode 100644 arch/arm/mach-msm/board-trout-battery.c
 create mode 100644 arch/arm/mach-msm/board-trout-hsusb.c
 create mode 100644 arch/arm/mach-msm/gpio_chip.h
 create mode 100644 arch/arm/mach-msm/include/mach/board-hsusb.h
 create mode 100644 arch/arm/mach-msm/smd_rpcrouter.c
 create mode 100644 arch/arm/mach-msm/smd_rpcrouter.h
 create mode 100644 arch/arm/mach-msm/smd_rpcrouter_device.c
 create mode 100644 arch/arm/mach-msm/smd_rpcrouter_servers.c

diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 737cf3e..7eb8722 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -1,5 +1,30 @@
 if ARCH_MSM
 
+config MSM_AMSS_VERSION
+        int
+        default 6210 if MSM_AMSS_VERSION_6210
+        default 6220 if MSM_AMSS_VERSION_6220
+        default 6225 if MSM_AMSS_VERSION_6225
+        default 6350 if MSM_AMSS_VERSION_6350
+
+choice
+        prompt "AMSS modem firmware version"
+
+        default MSM_AMSS_VERSION_6225
+
+        config MSM_AMSS_VERSION_6210
+                bool "6.2.10"
+
+        config MSM_AMSS_VERSION_6220
+                bool "6.2.20"
+
+        config MSM_AMSS_VERSION_6225
+                bool "6.2.20 + New ADSP"
+
+        config MSM_AMSS_VERSION_6350
+                bool "6.3.50"
+endchoice
+
 choice
 	prompt "Qualcomm MSM SoC Type"
 	default ARCH_MSM7X00A
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index cdd1caf..6f4da0d 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -13,10 +13,10 @@ endif
 
 obj-$(CONFIG_ARCH_QSD8X50) += sirc.o
 obj-$(CONFIG_MSM_SMD) += smd.o smd_debug.o
+obj-$(CONFIG_MSM_SMD) += smd_rpcrouter.o smd_rpcrouter_device.o smd_rpcrouter_servers.o
 obj-$(CONFIG_MSM_SMD) += last_radio_log.o
 
-obj-$(CONFIG_MACH_TROUT) += board-trout.o board-trout-gpio.o board-trout-mmc.o devices-msm7x00.o
-obj-$(CONFIG_MACH_TROUT) += board-trout.o board-trout-gpio.o board-trout-mmc.o board-trout-panel.o devices-msm7x00.o
+obj-$(CONFIG_MACH_TROUT) += board-trout.o board-trout-gpio.o board-trout-mmc.o board-trout-hsusb.o board-trout-battery.o board-trout-panel.o devices-msm7x00.o
 obj-$(CONFIG_MACH_HALIBUT) += board-halibut.o devices-msm7x00.o
 obj-$(CONFIG_ARCH_MSM7X30) += board-msm7x30.o devices-msm7x30.o
 obj-$(CONFIG_ARCH_QSD8X50) += board-qsd8x50.o devices-qsd8x50.o
diff --git a/arch/arm/mach-msm/board-trout-battery.c b/arch/arm/mach-msm/board-trout-battery.c
new file mode 100644
index 0000000..2ea57b8
--- /dev/null
+++ b/arch/arm/mach-msm/board-trout-battery.c
@@ -0,0 +1,796 @@
+/* arch/arm/mach-msm/htc_battery.c
+ *
+ * Copyright (C) 2008 HTC Corporation.
+ * Copyright (C) 2008 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/power_supply.h>
+#include <linux/platform_device.h>
+#include <linux/debugfs.h>
+#include "../drivers/staging/dream/include/linux/wakelock.h"
+#include <asm/gpio.h>
+#include "../drivers/staging/dream/include/mach/msm_rpcrouter.h"
+#include <mach/board.h>
+#include <asm/mach-types.h>
+#include "board-trout.h"
+
+static struct wake_lock vbus_wake_lock;
+
+#define TRACE_BATT 0
+
+#if TRACE_BATT
+#include <linux/rtc.h>
+
+#define BATT(x...) do { \
+struct timespec ts; \
+struct rtc_time tm; \
+getnstimeofday(&ts); \
+rtc_time_to_tm(ts.tv_sec, &tm); \
+printk(KERN_INFO "[BATT] " x); \
+printk(" at %lld (%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n", \
+ktime_to_ns(ktime_get()), tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, \
+tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec); \
+} while (0)
+#else
+#define BATT(x...) do {} while (0)
+#endif
+
+/* rpc related */
+#define APP_BATT_PDEV_NAME		"rs30100001:00000000"
+#define APP_BATT_PROG			0x30100001
+#define APP_BATT_VER			MSM_RPC_VERS(0,0)
+#define HTC_PROCEDURE_BATTERY_NULL	0
+#define HTC_PROCEDURE_GET_BATT_LEVEL	1
+#define HTC_PROCEDURE_GET_BATT_INFO	2
+#define HTC_PROCEDURE_GET_CABLE_STATUS	3
+#define HTC_PROCEDURE_SET_BATT_DELTA	4
+
+/* module debugger */
+#define HTC_BATTERY_DEBUG		1
+#define BATTERY_PREVENTION		1
+
+/* Enable this will shut down if no battery */
+#define ENABLE_BATTERY_DETECTION	0
+/* Sapphire pin changes:
+ *  USB_ID (GPIO 90) is renamed to AC_IN (GPIO 30)
+ *  CHARGER_EN (CPLD MISC2 bit[0]) is move to PMIC (MPP_14).
+ *  ISET (CPLD MISC2 bit[1]) is move to PMIC (MPP_13). */
+#define GPIO_SAPPHIRE_USB_ID	30
+
+#define GPIO_BATTERY_DETECTION		21
+#define GPIO_BATTERY_CHARGER_EN		128
+
+/* Charge current selection */
+#define GPIO_BATTERY_CHARGER_CURRENT	129
+
+typedef enum {
+	DISABLE = 0,
+	ENABLE_SLOW_CHG,
+	ENABLE_FAST_CHG
+} batt_ctl_t;
+
+/* This order is the same as htc_power_supplies[]
+ * And it's also the same as htc_cable_status_update()
+ */
+typedef enum {
+	CHARGER_BATTERY = 0,
+	CHARGER_USB,
+	CHARGER_AC
+} charger_type_t;
+
+const char *charger_tags[] = {"none", "USB", "AC"};
+
+struct battery_info_reply {
+	u32 batt_id;		/* Battery ID from ADC */
+	u32 batt_vol;		/* Battery voltage from ADC */
+	u32 batt_temp;		/* Battery Temperature (C) from formula and ADC */
+	u32 batt_current;	/* Battery current from ADC */
+	u32 level;		/* formula */
+	u32 charging_source;	/* 0: no cable, 1:usb, 2:AC */
+	u32 charging_enabled;	/* 0: Disable, 1: Enable */
+	u32 full_bat;		/* Full capacity of battery (mAh) */
+};
+
+struct htc_battery_info {
+	int present;
+	unsigned long update_time;
+
+	/* lock to protect the battery info */
+	struct mutex lock;
+
+	/* lock held while calling the arm9 to query the battery info */
+	struct mutex rpc_lock;
+	struct battery_info_reply rep;
+};
+
+static struct msm_rpc_endpoint *endpoint;
+
+static struct htc_battery_info htc_batt_info;
+
+static unsigned int cache_time = 1000;
+
+static int htc_battery_initial = 0;
+
+static enum power_supply_property htc_battery_properties[] = {
+	POWER_SUPPLY_PROP_STATUS,
+	POWER_SUPPLY_PROP_HEALTH,
+	POWER_SUPPLY_PROP_PRESENT,
+	POWER_SUPPLY_PROP_TECHNOLOGY,
+	POWER_SUPPLY_PROP_CAPACITY,
+};
+
+static enum power_supply_property htc_power_properties[] = {
+	POWER_SUPPLY_PROP_ONLINE,
+};
+
+static char *supply_list[] = {
+	"battery",
+};
+
+/* HTC dedicated attributes */
+static ssize_t htc_battery_show_property(struct device *dev,
+					  struct device_attribute *attr,
+					  char *buf);
+
+static int htc_power_get_property(struct power_supply *psy, 
+				    enum power_supply_property psp,
+				    union power_supply_propval *val);
+
+static int htc_battery_get_property(struct power_supply *psy, 
+				    enum power_supply_property psp,
+				    union power_supply_propval *val);
+
+static struct power_supply htc_power_supplies[] = {
+	{
+		.name = "battery",
+		.type = POWER_SUPPLY_TYPE_BATTERY,
+		.properties = htc_battery_properties,
+		.num_properties = ARRAY_SIZE(htc_battery_properties),
+		.get_property = htc_battery_get_property,
+	},
+	{
+		.name = "usb",
+		.type = POWER_SUPPLY_TYPE_USB,
+		.supplied_to = supply_list,
+		.num_supplicants = ARRAY_SIZE(supply_list),
+		.properties = htc_power_properties,
+		.num_properties = ARRAY_SIZE(htc_power_properties),
+		.get_property = htc_power_get_property,
+	},
+	{
+		.name = "ac",
+		.type = POWER_SUPPLY_TYPE_MAINS,
+		.supplied_to = supply_list,
+		.num_supplicants = ARRAY_SIZE(supply_list),
+		.properties = htc_power_properties,
+		.num_properties = ARRAY_SIZE(htc_power_properties),
+		.get_property = htc_power_get_property,
+	},
+};
+
+static int g_usb_online;
+
+/* -------------------------------------------------------------------------- */
+
+#if defined(CONFIG_DEBUG_FS)
+int htc_battery_set_charging(batt_ctl_t ctl);
+static int batt_debug_set(void *data, u64 val)
+{
+	return htc_battery_set_charging((batt_ctl_t) val);
+}
+
+static int batt_debug_get(void *data, u64 *val)
+{
+	return -ENOSYS;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(batt_debug_fops, batt_debug_get, batt_debug_set, "%llu\n");
+static int __init batt_debug_init(void)
+{
+	struct dentry *dent;
+
+	dent = debugfs_create_dir("htc_battery", 0);
+	if (IS_ERR(dent))
+		return PTR_ERR(dent);
+
+	debugfs_create_file("charger_state", 0644, dent, NULL, &batt_debug_fops);
+
+	return 0;
+}
+
+device_initcall(batt_debug_init);
+#endif
+
+static int init_batt_gpio(void)
+{
+	if (!machine_is_trout())
+		return 0;
+
+	if (gpio_request(GPIO_BATTERY_DETECTION, "batt_detect") < 0)
+		goto gpio_failed;
+	if (gpio_request(GPIO_BATTERY_CHARGER_EN, "charger_en") < 0)
+		goto gpio_failed;
+	if (gpio_request(GPIO_BATTERY_CHARGER_CURRENT, "charge_current") < 0)
+		goto gpio_failed;
+
+	return 0;
+
+gpio_failed:	
+	return -EINVAL;
+	
+}
+
+/* 
+ *	battery_charging_ctrl - battery charing control.
+ * 	@ctl:			battery control command
+ *
+ */
+static int battery_charging_ctrl(batt_ctl_t ctl)
+{
+	int result = 0;
+
+	/* The charing operations are move to A9 in Sapphire. */
+	if (!machine_is_trout())
+		return result;
+
+	switch (ctl) {
+	case DISABLE:
+		BATT("charger OFF");
+		/* 0 for enable; 1 disable */
+		result = gpio_direction_output(GPIO_BATTERY_CHARGER_EN, 1);
+		break;
+	case ENABLE_SLOW_CHG:
+		BATT("charger ON (SLOW)");
+		result = gpio_direction_output(GPIO_BATTERY_CHARGER_CURRENT, 0);
+		result = gpio_direction_output(GPIO_BATTERY_CHARGER_EN, 0);
+		break;
+	case ENABLE_FAST_CHG:
+		BATT("charger ON (FAST)");
+		result = gpio_direction_output(GPIO_BATTERY_CHARGER_CURRENT, 1);
+		result = gpio_direction_output(GPIO_BATTERY_CHARGER_EN, 0);
+		break;
+	default:
+		printk(KERN_ERR "Not supported battery ctr called.!\n");
+		result = -EINVAL;
+		break;
+	}
+	
+	return result;
+}
+
+int htc_battery_set_charging(batt_ctl_t ctl)
+{
+	int rc;
+	
+	if ((rc = battery_charging_ctrl(ctl)) < 0)
+		goto result;
+	
+	if (!htc_battery_initial) {
+		htc_batt_info.rep.charging_enabled = ctl & 0x3;
+	} else {
+		mutex_lock(&htc_batt_info.lock);
+		htc_batt_info.rep.charging_enabled = ctl & 0x3;
+		mutex_unlock(&htc_batt_info.lock);
+	}
+result:	
+	return rc;
+}
+
+int htc_battery_status_update(u32 curr_level)
+{
+	int notify;
+	if (!htc_battery_initial)
+		return 0;
+
+	mutex_lock(&htc_batt_info.lock);
+	notify = (htc_batt_info.rep.level != curr_level);
+	htc_batt_info.rep.level = curr_level;
+	mutex_unlock(&htc_batt_info.lock);
+
+	if (notify)
+		power_supply_changed(&htc_power_supplies[CHARGER_BATTERY]);
+	return 0;
+}
+
+int htc_cable_status_update(int status)
+{
+	int rc = 0;
+	unsigned last_source;
+
+	if (!htc_battery_initial)
+		return 0;
+	
+	if (status < CHARGER_BATTERY || status > CHARGER_AC) {
+		BATT("%s: Not supported cable status received!", __func__);
+		return -EINVAL;
+	}
+	mutex_lock(&htc_batt_info.lock);
+	/* A9 reports USB charging when helf AC cable in and China AC charger. */
+	/* Work arround: notify userspace AC charging first,
+	and notify USB charging again when receiving usb connected notificaiton from usb driver. */
+	last_source = htc_batt_info.rep.charging_source;
+	if (status == CHARGER_USB && g_usb_online == 0)
+		htc_batt_info.rep.charging_source = CHARGER_AC;
+	else {
+		htc_batt_info.rep.charging_source  = status;
+		/* usb driver will not notify usb offline. */
+		if (status == CHARGER_BATTERY && g_usb_online == 1)
+			g_usb_online = 0;
+	}
+
+	/* TODO: Don't call usb driver again with the same cable status. */
+	msm_hsusb_set_vbus_state(status == CHARGER_USB);
+
+	if (htc_batt_info.rep.charging_source != last_source) {
+		if (htc_batt_info.rep.charging_source == CHARGER_USB ||
+			htc_batt_info.rep.charging_source == CHARGER_AC) {
+		wake_lock(&vbus_wake_lock);
+	} else {
+		/* give userspace some time to see the uevent and update
+		 * LED state or whatnot...
+		 */
+		wake_lock_timeout(&vbus_wake_lock, HZ / 2);
+	}
+		if (htc_batt_info.rep.charging_source == CHARGER_BATTERY || last_source == CHARGER_BATTERY)
+	power_supply_changed(&htc_power_supplies[CHARGER_BATTERY]);
+		if (htc_batt_info.rep.charging_source == CHARGER_USB || last_source == CHARGER_USB)
+	power_supply_changed(&htc_power_supplies[CHARGER_USB]);
+		if (htc_batt_info.rep.charging_source == CHARGER_AC || last_source == CHARGER_AC)
+	power_supply_changed(&htc_power_supplies[CHARGER_AC]);
+	}
+	mutex_unlock(&htc_batt_info.lock);
+
+	return rc;
+}
+
+/* A9 reports USB charging when helf AC cable in and China AC charger. */
+/* Work arround: notify userspace AC charging first,
+and notify USB charging again when receiving usb connected notification from usb driver. */
+void notify_usb_connected(int online)
+{
+	mutex_lock(&htc_batt_info.lock);
+
+	BATT("%s: online=%d, g_usb_online=%d", __func__, online, g_usb_online);
+
+	if (g_usb_online != online) {
+		g_usb_online = online;
+		if (online && htc_batt_info.rep.charging_source == CHARGER_AC) {
+			mutex_unlock(&htc_batt_info.lock);
+			htc_cable_status_update(CHARGER_USB);
+			mutex_lock(&htc_batt_info.lock);
+		} else if (online) {
+			BATT("warning: usb connected but charging source=%d", htc_batt_info.rep.charging_source);
+		}
+	}
+	mutex_unlock(&htc_batt_info.lock);
+}
+
+static int htc_get_batt_info(struct battery_info_reply *buffer)
+{
+	struct rpc_request_hdr req;
+	
+	struct htc_get_batt_info_rep {
+		struct rpc_reply_hdr hdr;
+		struct battery_info_reply info;
+	} rep;
+	
+	int rc;
+
+	if (buffer == NULL) 
+		return -EINVAL;
+
+	rc = msm_rpc_call_reply(endpoint, HTC_PROCEDURE_GET_BATT_INFO,
+				&req, sizeof(req),
+				&rep, sizeof(rep),
+				5 * HZ);
+	if ( rc < 0 ) 
+		return rc;
+	
+	mutex_lock(&htc_batt_info.lock);
+	buffer->batt_id 		= be32_to_cpu(rep.info.batt_id);
+	buffer->batt_vol 		= be32_to_cpu(rep.info.batt_vol);
+	buffer->batt_temp 		= be32_to_cpu(rep.info.batt_temp);
+	buffer->batt_current 		= be32_to_cpu(rep.info.batt_current);
+	buffer->level 			= be32_to_cpu(rep.info.level);
+	/* Move the rules of charging_source to cable_status_update. */
+	/* buffer->charging_source 	= be32_to_cpu(rep.info.charging_source); */
+	buffer->charging_enabled 	= be32_to_cpu(rep.info.charging_enabled);
+	buffer->full_bat 		= be32_to_cpu(rep.info.full_bat);
+	mutex_unlock(&htc_batt_info.lock);
+
+	return 0;
+}
+
+/* -------------------------------------------------------------------------- */
+static int htc_power_get_property(struct power_supply *psy, 
+				    enum power_supply_property psp,
+				    union power_supply_propval *val)
+{
+	charger_type_t charger;
+	
+	mutex_lock(&htc_batt_info.lock);
+	charger = htc_batt_info.rep.charging_source;
+	mutex_unlock(&htc_batt_info.lock);
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_ONLINE:
+		if (psy->type == POWER_SUPPLY_TYPE_MAINS)
+			val->intval = (charger ==  CHARGER_AC ? 1 : 0);
+		else if (psy->type == POWER_SUPPLY_TYPE_USB)
+			val->intval = (charger ==  CHARGER_USB ? 1 : 0);
+		else
+			val->intval = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+	
+	return 0;
+}
+
+static int htc_battery_get_charging_status(void)
+{
+	u32 level;
+	charger_type_t charger;	
+	int ret;
+	
+	mutex_lock(&htc_batt_info.lock);
+	charger = htc_batt_info.rep.charging_source;
+	
+	switch (charger) {
+	case CHARGER_BATTERY:
+		ret = POWER_SUPPLY_STATUS_DISCHARGING;
+		break;
+	case CHARGER_USB:
+	case CHARGER_AC:
+		level = htc_batt_info.rep.level;
+		if (level == 100)
+			ret = POWER_SUPPLY_STATUS_FULL;
+		else
+			ret = POWER_SUPPLY_STATUS_CHARGING;
+		break;
+	default:
+		ret = POWER_SUPPLY_STATUS_UNKNOWN;
+	}
+	mutex_unlock(&htc_batt_info.lock);
+	return ret;
+}
+
+static int htc_battery_get_property(struct power_supply *psy, 
+				    enum power_supply_property psp,
+				    union power_supply_propval *val)
+{
+	switch (psp) {
+	case POWER_SUPPLY_PROP_STATUS:
+		val->intval = htc_battery_get_charging_status();
+		break;
+	case POWER_SUPPLY_PROP_HEALTH:
+		val->intval = POWER_SUPPLY_HEALTH_GOOD;
+		break;
+	case POWER_SUPPLY_PROP_PRESENT:
+		val->intval = htc_batt_info.present;
+		break;
+	case POWER_SUPPLY_PROP_TECHNOLOGY:
+		val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
+		break;
+	case POWER_SUPPLY_PROP_CAPACITY:
+		mutex_lock(&htc_batt_info.lock);
+		val->intval = htc_batt_info.rep.level;
+		mutex_unlock(&htc_batt_info.lock);
+		break;
+	default:		
+		return -EINVAL;
+	}
+	
+	return 0;
+}
+
+#define HTC_BATTERY_ATTR(_name)							\
+{										\
+	.attr = { .name = #_name, .mode = S_IRUGO, .owner = THIS_MODULE },	\
+	.show = htc_battery_show_property,					\
+	.store = NULL,								\
+}
+
+static struct device_attribute htc_battery_attrs[] = {
+	HTC_BATTERY_ATTR(batt_id),
+	HTC_BATTERY_ATTR(batt_vol),
+	HTC_BATTERY_ATTR(batt_temp),
+	HTC_BATTERY_ATTR(batt_current),
+	HTC_BATTERY_ATTR(charging_source),
+	HTC_BATTERY_ATTR(charging_enabled),
+	HTC_BATTERY_ATTR(full_bat),
+};
+
+enum {
+	BATT_ID = 0,
+	BATT_VOL,
+	BATT_TEMP,
+	BATT_CURRENT,
+	CHARGING_SOURCE,
+	CHARGING_ENABLED,
+	FULL_BAT,
+};
+
+static int htc_rpc_set_delta(unsigned delta)
+{
+	struct set_batt_delta_req {
+		struct rpc_request_hdr hdr;
+		uint32_t data;
+	} req;
+
+	req.data = cpu_to_be32(delta);
+	return msm_rpc_call(endpoint, HTC_PROCEDURE_SET_BATT_DELTA,
+			    &req, sizeof(req), 5 * HZ);
+}
+
+
+static ssize_t htc_battery_set_delta(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf, size_t count)
+{
+	int rc;
+	unsigned long delta = 0;
+	
+	delta = simple_strtoul(buf, NULL, 10);
+
+	if (delta > 100)
+		return -EINVAL;
+
+	mutex_lock(&htc_batt_info.rpc_lock);
+	rc = htc_rpc_set_delta(delta);
+	mutex_unlock(&htc_batt_info.rpc_lock);
+	if (rc < 0)
+		return rc;
+	return count;
+}
+
+static struct device_attribute htc_set_delta_attrs[] = {
+	__ATTR(delta, S_IWUSR | S_IWGRP, NULL, htc_battery_set_delta),
+};
+
+static int htc_battery_create_attrs(struct device * dev)
+{
+	int i, j, rc;
+	
+	for (i = 0; i < ARRAY_SIZE(htc_battery_attrs); i++) {
+		rc = device_create_file(dev, &htc_battery_attrs[i]);
+		if (rc)
+			goto htc_attrs_failed;
+	}
+
+	for (j = 0; j < ARRAY_SIZE(htc_set_delta_attrs); j++) {
+		rc = device_create_file(dev, &htc_set_delta_attrs[j]);
+		if (rc)
+			goto htc_delta_attrs_failed;
+	}
+	
+	goto succeed;
+	
+htc_attrs_failed:
+	while (i--)
+		device_remove_file(dev, &htc_battery_attrs[i]);
+htc_delta_attrs_failed:
+	while (j--)
+		device_remove_file(dev, &htc_set_delta_attrs[i]);
+succeed:	
+	return rc;
+}
+
+static ssize_t htc_battery_show_property(struct device *dev,
+					 struct device_attribute *attr,
+					 char *buf)
+{
+	int i = 0;
+	const ptrdiff_t off = attr - htc_battery_attrs;
+	
+	/* rpc lock is used to prevent two threads from calling
+	 * into the get info rpc at the same time
+	 */
+
+	mutex_lock(&htc_batt_info.rpc_lock);
+	/* check cache time to decide if we need to update */
+	if (htc_batt_info.update_time &&
+            time_before(jiffies, htc_batt_info.update_time +
+                                msecs_to_jiffies(cache_time)))
+                goto dont_need_update;
+	
+	if (htc_get_batt_info(&htc_batt_info.rep) < 0) {
+		printk(KERN_ERR "%s: rpc failed!!!\n", __FUNCTION__);
+	} else {
+		htc_batt_info.update_time = jiffies;
+	}
+dont_need_update:
+	mutex_unlock(&htc_batt_info.rpc_lock);
+
+	mutex_lock(&htc_batt_info.lock);
+	switch (off) {
+	case BATT_ID:
+		i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
+			       htc_batt_info.rep.batt_id);
+		break;
+	case BATT_VOL:
+		i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
+			       htc_batt_info.rep.batt_vol);
+		break;
+	case BATT_TEMP:
+		i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
+			       htc_batt_info.rep.batt_temp);
+		break;
+	case BATT_CURRENT:
+		i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
+			       htc_batt_info.rep.batt_current);
+		break;
+	case CHARGING_SOURCE:
+		i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
+			       htc_batt_info.rep.charging_source);
+		break;
+	case CHARGING_ENABLED:
+		i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
+			       htc_batt_info.rep.charging_enabled);
+		break;		
+	case FULL_BAT:
+		i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
+			       htc_batt_info.rep.full_bat);
+		break;
+	default:
+		i = -EINVAL;
+	}	
+	mutex_unlock(&htc_batt_info.lock);
+	
+	return i;
+}
+
+static int htc_battery_probe(struct platform_device *pdev)
+{
+	int i, rc;
+
+	/* init battery gpio */
+	if ((rc = init_batt_gpio()) < 0) {
+		printk(KERN_ERR "%s: init battery gpio failed!\n", __FUNCTION__);
+		return rc;
+	}
+
+	/* init structure data member */
+	htc_batt_info.update_time 	= jiffies;
+	/* A9 will shutdown the phone if battery is pluged out, so this value is always 1.
+	htc_batt_info.present 		= gpio_get_value(GPIO_TROUT_MBAT_IN);
+	*/
+	htc_batt_info.present 		= 1;
+
+	/* init rpc */
+	endpoint = msm_rpc_connect(APP_BATT_PROG, APP_BATT_VER, 0);
+	if (IS_ERR(endpoint)) {
+		printk(KERN_ERR "%s: init rpc failed! rc = %ld\n",
+		       __FUNCTION__, PTR_ERR(endpoint));
+		return rc;
+	}
+
+	/* init power supplier framework */
+	for (i = 0; i < ARRAY_SIZE(htc_power_supplies); i++) {
+		rc = power_supply_register(&pdev->dev, &htc_power_supplies[i]);
+		if (rc)
+			printk(KERN_ERR "Failed to register power supply (%d)\n", rc);	
+	}
+
+	/* create htc detail attributes */
+	htc_battery_create_attrs(htc_power_supplies[CHARGER_BATTERY].dev);
+
+	/* After battery driver gets initialized, send rpc request to inquiry
+	 * the battery status in case of we lost some info
+	 */
+	htc_battery_initial = 1;
+
+	mutex_lock(&htc_batt_info.rpc_lock);
+	htc_batt_info.rep.charging_source = CHARGER_BATTERY;
+	if (htc_get_batt_info(&htc_batt_info.rep) < 0)
+		printk(KERN_ERR "%s: get info failed\n", __FUNCTION__);
+
+	if (htc_rpc_set_delta(1) < 0)
+		printk(KERN_ERR "%s: set delta failed\n", __FUNCTION__);
+	htc_batt_info.update_time = jiffies;
+	mutex_unlock(&htc_batt_info.rpc_lock);
+
+	return 0;
+}
+
+static struct platform_driver htc_battery_driver = {
+	.probe	= htc_battery_probe,
+	.driver	= {
+		.name	= APP_BATT_PDEV_NAME,
+		.owner	= THIS_MODULE,
+	},
+};
+
+/* batt_mtoa server definitions */
+#define BATT_MTOA_PROG				0x30100000
+#define BATT_MTOA_VERS				0
+#define RPC_BATT_MTOA_NULL			0
+#define RPC_BATT_MTOA_SET_CHARGING_PROC		1
+#define RPC_BATT_MTOA_CABLE_STATUS_UPDATE_PROC	2
+#define RPC_BATT_MTOA_LEVEL_UPDATE_PROC		3
+
+struct rpc_batt_mtoa_set_charging_args {
+	int enable;
+};
+
+struct rpc_batt_mtoa_cable_status_update_args {
+	int status;
+};
+
+struct rpc_dem_battery_update_args {
+	uint32_t level;
+};
+
+static int handle_battery_call(struct msm_rpc_server *server,
+			       struct rpc_request_hdr *req, unsigned len)
+{	
+	switch (req->procedure) {
+	case RPC_BATT_MTOA_NULL:
+		return 0;
+
+	case RPC_BATT_MTOA_SET_CHARGING_PROC: {
+		struct rpc_batt_mtoa_set_charging_args *args;
+		args = (struct rpc_batt_mtoa_set_charging_args *)(req + 1);
+		args->enable = be32_to_cpu(args->enable);
+		BATT("set_charging: enable=%d",args->enable);
+		htc_battery_set_charging(args->enable);
+		return 0;
+	}
+	case RPC_BATT_MTOA_CABLE_STATUS_UPDATE_PROC: {
+		struct rpc_batt_mtoa_cable_status_update_args *args;
+		args = (struct rpc_batt_mtoa_cable_status_update_args *)(req + 1);
+		args->status = be32_to_cpu(args->status);
+		BATT("cable_status_update: status=%d",args->status);
+		htc_cable_status_update(args->status);
+		return 0;
+	}
+	case RPC_BATT_MTOA_LEVEL_UPDATE_PROC: {
+		struct rpc_dem_battery_update_args *args;
+		args = (struct rpc_dem_battery_update_args *)(req + 1);
+		args->level = be32_to_cpu(args->level);
+		BATT("dem_battery_update: level=%d",args->level);
+		htc_battery_status_update(args->level);
+		return 0;
+	}
+	default:
+		printk(KERN_ERR "%s: program 0x%08x:%d: unknown procedure %d\n",
+		       __FUNCTION__, req->prog, req->vers, req->procedure);
+		return -ENODEV;
+	}
+}
+
+static struct msm_rpc_server battery_server = {
+	.prog = BATT_MTOA_PROG,
+	.vers = BATT_MTOA_VERS,
+	.rpc_call = handle_battery_call,
+};
+
+static int __init htc_battery_init(void)
+{
+	wake_lock_init(&vbus_wake_lock, WAKE_LOCK_SUSPEND, "vbus_present");
+	mutex_init(&htc_batt_info.lock);
+	mutex_init(&htc_batt_info.rpc_lock);
+	msm_rpc_create_server(&battery_server);
+	platform_driver_register(&htc_battery_driver);
+	return 0;
+}
+
+module_init(htc_battery_init);
+MODULE_DESCRIPTION("HTC Battery Driver");
+MODULE_LICENSE("GPL");
+
diff --git a/arch/arm/mach-msm/board-trout-hsusb.c b/arch/arm/mach-msm/board-trout-hsusb.c
new file mode 100644
index 0000000..a4af380
--- /dev/null
+++ b/arch/arm/mach-msm/board-trout-hsusb.c
@@ -0,0 +1,352 @@
+/* linux/arch/arm/mach-msm/devices.c
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2007-2009 HTC Corporation.
+ * Author: Thomas Tsai <thomas_tsai@xxxxxxx>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+
+#include <linux/dma-mapping.h>
+#include <mach/msm_iomap.h>
+#include <mach/dma.h>
+#include "gpio_chip.h"
+#include "devices.h"
+#include <mach/board.h>
+#include <mach/board-hsusb.h>
+#include <mach/msm_hsusb.h>
+
+#ifdef CONFIG_USB_FUNCTION
+#include <linux/usb/mass_storage_function.h>
+#endif
+
+#include <asm/mach/flash.h>
+#include <asm/setup.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/delay.h>
+#include "../drivers/staging/dream/include/mach/msm_rpcrouter.h"
+#include <mach/msm_iomap.h>
+#include <mach/mmc.h>
+
+static char *df_serialno = "000000000000";
+
+#if 0
+struct platform_device *devices[] __initdata = {
+	&msm_device_nand,
+	&msm_device_smd,
+	&msm_device_i2c,
+};
+
+void __init msm_add_devices(void)
+{
+	platform_add_devices(devices, ARRAY_SIZE(devices));
+}
+#endif
+
+#define HSUSB_API_INIT_PHY_PROC	2
+#define HSUSB_API_PROG		0x30000064
+#define HSUSB_API_VERS MSM_RPC_VERS(1,1)
+
+static void internal_phy_reset(void)
+{
+	struct msm_rpc_endpoint *usb_ep;
+	int rc;
+	struct hsusb_phy_start_req {
+		struct rpc_request_hdr hdr;
+	} req;
+
+	printk(KERN_INFO "msm_hsusb_phy_reset\n");
+
+	usb_ep = msm_rpc_connect(HSUSB_API_PROG, HSUSB_API_VERS, 0);
+	if (IS_ERR(usb_ep)) {
+		printk(KERN_ERR "%s: init rpc failed! error: %ld\n",
+				__func__, PTR_ERR(usb_ep));
+		goto close;
+	}
+	rc = msm_rpc_call(usb_ep, HSUSB_API_INIT_PHY_PROC,
+			&req, sizeof(req), 5 * HZ);
+	if (rc < 0)
+		printk(KERN_ERR "%s: rpc call failed! (%d)\n", __func__, rc);
+
+close:
+	msm_rpc_close(usb_ep);
+}
+
+/* adjust eye diagram, disable vbusvalid interrupts */
+static int hsusb_phy_init_seq[] = { 0x40, 0x31, 0x1D, 0x0D, 0x1D, 0x10, -1 };
+
+#ifdef CONFIG_USB_FUNCTION
+static char *usb_functions[] = {
+#if defined(CONFIG_USB_FUNCTION_MASS_STORAGE) || defined(CONFIG_USB_FUNCTION_UMS)
+	"usb_mass_storage",
+#endif
+#ifdef CONFIG_USB_FUNCTION_ADB
+	"adb",
+#endif
+};
+
+static struct msm_hsusb_product usb_products[] = {
+	{
+		.product_id	= 0x0c01,
+		.functions	= 0x00000001, /* usb_mass_storage */
+	},
+	{
+		.product_id	= 0x0c02,
+		.functions	= 0x00000003, /* usb_mass_storage + adb */
+	},
+};
+#endif
+
+struct msm_hsusb_platform_data msm_hsusb_pdata = {
+	.phy_reset = internal_phy_reset,
+	.phy_init_seq = hsusb_phy_init_seq,
+	.usb_connected = notify_usb_connected,
+#ifdef CONFIG_USB_FUNCTION
+	.vendor_id = 0x0bb4,
+	.product_id = 0x0c02,
+	.version = 0x0100,
+	.product_name = "Android Phone",
+	.manufacturer_name = "HTC",
+
+	.functions = usb_functions,
+	.num_functions = ARRAY_SIZE(usb_functions),
+	.products = usb_products,
+	.num_products = ARRAY_SIZE(usb_products),
+#endif
+};
+
+#ifdef CONFIG_USB_FUNCTION
+static struct usb_mass_storage_platform_data mass_storage_pdata = {
+	.nluns = 1,
+	.buf_size = 16384,
+	.vendor = "HTC     ",
+	.product = "Android Phone   ",
+	.release = 0x0100,
+};
+
+static struct platform_device usb_mass_storage_device = {
+	.name = "usb_mass_storage",
+	.id = -1,
+	.dev = {
+		.platform_data = &mass_storage_pdata,
+		},
+};
+#endif
+
+#ifdef CONFIG_USB_ANDROID
+static struct android_usb_platform_data android_usb_pdata = {
+	.vendor_id	= 0x0bb4,
+	.product_id	= 0x0c01,
+	.adb_product_id	= 0x0c02,
+	.version	= 0x0100,
+	.product_name	= "Android Phone",
+	.manufacturer_name = "HTC",
+	.nluns = 1,
+};
+
+static struct platform_device android_usb_device = {
+	.name	= "android_usb",
+	.id		= -1,
+	.dev		= {
+		.platform_data = &android_usb_pdata,
+	},
+};
+#endif
+
+void __init msm_add_usb_devices(void (*phy_reset) (void))
+{
+	/* setup */
+	if (phy_reset)
+		msm_hsusb_pdata.phy_reset = phy_reset;
+	msm_device_hsusb.dev.platform_data = &msm_hsusb_pdata;
+	platform_device_register(&msm_device_hsusb);
+#ifdef CONFIG_USB_FUNCTION_MASS_STORAGE
+	platform_device_register(&usb_mass_storage_device);
+#endif
+#ifdef CONFIG_USB_ANDROID
+	platform_device_register(&android_usb_device);
+#endif
+}
+
+static struct resource ram_console_resource[] = {
+	{
+		.flags	= IORESOURCE_MEM,
+	}
+};
+
+static struct platform_device ram_console_device = {
+	.name = "ram_console",
+	.id = -1,
+	.num_resources  = ARRAY_SIZE(ram_console_resource),
+	.resource       = ram_console_resource,
+};
+
+#define PM_LIBPROG      0x30000061
+#if (CONFIG_MSM_AMSS_VERSION == 6220) || (CONFIG_MSM_AMSS_VERSION == 6225)
+#define PM_LIBVERS      0xfb837d0b
+#else
+#define PM_LIBVERS      0x10001
+#endif
+
+#if 0
+static struct platform_device *msm_serial_devices[] __initdata = {
+	&msm_device_uart1,
+	&msm_device_uart2,
+	&msm_device_uart3,
+	#ifdef CONFIG_SERIAL_MSM_HS
+	&msm_device_uart_dm1,
+	&msm_device_uart_dm2,
+	#endif
+};
+
+int __init msm_add_serial_devices(unsigned num)
+{
+	if (num > MSM_SERIAL_NUM)
+		return -EINVAL;
+
+	return platform_device_register(msm_serial_devices[num]);
+}
+#endif
+
+#define ATAG_SMI 0x4d534D71
+/* setup calls mach->fixup, then parse_tags, parse_cmdline
+ * We need to setup meminfo in mach->fixup, so this function
+ * will need to traverse each tag to find smi tag.
+ */
+int __init parse_tag_smi(const struct tag *tags)
+{
+	int smi_sz = 0, find = 0;
+	struct tag *t = (struct tag *)tags;
+
+	for (; t->hdr.size; t = tag_next(t)) {
+		if (t->hdr.tag == ATAG_SMI) {
+			printk(KERN_DEBUG "find the smi tag\n");
+			find = 1;
+			break;
+		}
+	}
+	if (!find)
+		return -1;
+
+	printk(KERN_DEBUG "parse_tag_smi: smi size = %d\n", t->u.mem.size);
+	smi_sz = t->u.mem.size;
+	return smi_sz;
+}
+__tagtable(ATAG_SMI, parse_tag_smi);
+
+
+#define ATAG_HWID 0x4d534D72
+int __init parse_tag_hwid(const struct tag *tags)
+{
+	int hwid = 0, find = 0;
+	struct tag *t = (struct tag *)tags;
+
+	for (; t->hdr.size; t = tag_next(t)) {
+		if (t->hdr.tag == ATAG_HWID) {
+			printk(KERN_DEBUG "find the hwid tag\n");
+			find = 1;
+			break;
+		}
+	}
+
+	if (find)
+		hwid = t->u.revision.rev;
+	printk(KERN_DEBUG "parse_tag_hwid: hwid = 0x%x\n", hwid);
+	return hwid;
+}
+__tagtable(ATAG_HWID, parse_tag_hwid);
+
+#define ATAG_SKUID 0x4d534D73
+int __init parse_tag_skuid(const struct tag *tags)
+{
+	int skuid = 0, find = 0;
+	struct tag *t = (struct tag *)tags;
+
+	for (; t->hdr.size; t = tag_next(t)) {
+		if (t->hdr.tag == ATAG_SKUID) {
+			printk(KERN_DEBUG "find the skuid tag\n");
+			find = 1;
+			break;
+		}
+	}
+
+	if (find)
+		skuid = t->u.revision.rev;
+	printk(KERN_DEBUG "parse_tag_skuid: hwid = 0x%x\n", skuid);
+	return skuid;
+}
+__tagtable(ATAG_SKUID, parse_tag_skuid);
+
+#define ATAG_ENGINEERID 0x4d534D75
+int __init parse_tag_engineerid(const struct tag *tags)
+{
+	int engineerid = 0, find = 0;
+	struct tag *t = (struct tag *)tags;
+
+	for (; t->hdr.size; t = tag_next(t)) {
+		if (t->hdr.tag == ATAG_ENGINEERID) {
+			printk(KERN_DEBUG "find the engineer tag\n");
+			find = 1;
+			break;
+		}
+	}
+
+	if (find)
+		engineerid = t->u.revision.rev;
+	printk(KERN_DEBUG "parse_tag_engineerid: hwid = 0x%x\n", engineerid);
+	return engineerid;
+}
+__tagtable(ATAG_ENGINEERID, parse_tag_engineerid);
+
+static int mfg_mode;
+int __init board_mfg_mode_init(char *s)
+{
+	if (!strcmp(s, "normal"))
+		mfg_mode = 0;
+	else if (!strcmp(s, "factory2"))
+		mfg_mode = 1;
+	else if (!strcmp(s, "recovery"))
+		mfg_mode = 2;
+	else if (!strcmp(s, "charge"))
+		mfg_mode = 3;
+
+	return 1;
+}
+__setup("androidboot.mode=", board_mfg_mode_init);
+
+
+int board_mfg_mode(void)
+{
+	return mfg_mode;
+}
+
+static int __init board_serialno_setup(char *serialno)
+{
+	char *str;
+
+	/* use default serial number when mode is factory2 */
+	if (mfg_mode == 1 || !strlen(serialno))
+		str = df_serialno;
+	else
+		str = serialno;
+#ifdef CONFIG_USB_FUNCTION
+	msm_hsusb_pdata.serial_number = str;
+#endif
+#ifdef CONFIG_USB_ANDROID
+	android_usb_pdata.serial_number = str;
+#endif
+	return 1;
+}
+
+__setup("androidboot.serialno=", board_serialno_setup);
diff --git a/arch/arm/mach-msm/gpio_chip.h b/arch/arm/mach-msm/gpio_chip.h
new file mode 100644
index 0000000..eab9f09
--- /dev/null
+++ b/arch/arm/mach-msm/gpio_chip.h
@@ -0,0 +1,38 @@
+/* arch/arm/mach-msm/gpio_chip.h
+ *
+ * Copyright (C) 2007 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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_GPIO_CHIP_H
+#define _LINUX_GPIO_CHIP_H
+
+#include <linux/list.h>
+
+struct gpio_chip {
+	struct list_head list;
+	struct gpio_state *state;
+
+	unsigned int start;
+	unsigned int end;
+
+	int (*configure)(struct gpio_chip *chip, unsigned int gpio, unsigned long flags);
+	int (*get_irq_num)(struct gpio_chip *chip, unsigned int gpio, unsigned int *irqp, unsigned long *irqnumflagsp);
+	int (*read)(struct gpio_chip *chip, unsigned int gpio);
+	int (*write)(struct gpio_chip *chip, unsigned int gpio, unsigned on);
+	int (*read_detect_status)(struct gpio_chip *chip, unsigned int gpio);
+	int (*clear_detect_status)(struct gpio_chip *chip, unsigned int gpio);
+};
+
+int register_gpio_chip(struct gpio_chip *gpio_chip);
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/board-hsusb.h b/arch/arm/mach-msm/include/mach/board-hsusb.h
new file mode 100644
index 0000000..994accd
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/board-hsusb.h
@@ -0,0 +1,68 @@
+/* arch/arm/mach-msm/include/mach/BOARD_HTC.h
+ * Copyright (C) 2007-2009 HTC Corporation.
+ * Author: Thomas Tsai <thomas_tsai@xxxxxxx>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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 __ASM_ARCH_MSM_BOARD_HTC_H
+#define __ASM_ARCH_MSM_BOARD_HTC_H
+
+#include <linux/types.h>
+#include <linux/list.h>
+#include <asm/setup.h>
+
+struct msm_pmem_setting{
+	resource_size_t pmem_start;
+	resource_size_t pmem_size;
+	resource_size_t pmem_adsp_start;
+	resource_size_t pmem_adsp_size;
+	resource_size_t pmem_gpu0_start;
+	resource_size_t pmem_gpu0_size;
+	resource_size_t pmem_gpu1_start;
+	resource_size_t pmem_gpu1_size;
+	resource_size_t pmem_camera_start;
+	resource_size_t pmem_camera_size;
+	resource_size_t ram_console_start;
+	resource_size_t ram_console_size;
+};
+
+enum {
+	MSM_SERIAL_UART1	= 0,
+	MSM_SERIAL_UART2,
+	MSM_SERIAL_UART3,
+#ifdef CONFIG_SERIAL_MSM_HS
+	MSM_SERIAL_UART1DM,
+	MSM_SERIAL_UART2DM,
+#endif
+	MSM_SERIAL_NUM,
+};
+
+
+/* common init routines for use by arch/arm/mach-msm/board-*.c */
+
+void __init msm_add_usb_devices(void (*phy_reset) (void));
+void __init msm_add_mem_devices(struct msm_pmem_setting *setting);
+void __init msm_init_pmic_vibrator(void);
+
+struct mmc_platform_data;
+int __init msm_add_sdcc_devices(unsigned int controller, struct mmc_platform_data *plat);
+int __init msm_add_serial_devices(unsigned uart);
+
+int __init board_mfg_mode(void);
+int __init parse_tag_smi(const struct tag *tags);
+int __init parse_tag_hwid(const struct tag * tags);
+int __init parse_tag_skuid(const struct tag * tags);
+int parse_tag_engineerid(const struct tag * tags);
+
+void notify_usb_connected(int online);
+
+char *board_serialno(void);
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index e302fbd..fd2c087 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -41,4 +41,6 @@ void __init msm_init_gpio(void);
 void __init msm_clock_init(struct clk *clock_tbl, unsigned num_clocks);
 void __init msm_acpu_clock_init(struct msm_acpu_clock_platform_data *);
 
+static void msm_hsusb_set_vbus_state(int online); 
+
 #endif
diff --git a/arch/arm/mach-msm/smd_rpcrouter.c b/arch/arm/mach-msm/smd_rpcrouter.c
new file mode 100644
index 0000000..739ac29
--- /dev/null
+++ b/arch/arm/mach-msm/smd_rpcrouter.c
@@ -0,0 +1,1310 @@
+/* arch/arm/mach-msm/smd_rpcrouter.c
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2007-2009 QUALCOMM Incorporated.
+ * Author: San Mehat <san@xxxxxxxxxxx>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+/* TODO: handle cases where smd_write() will tempfail due to full fifo */
+/* TODO: thread priority? schedule a work to bump it? */
+/* TODO: maybe make server_list_lock a mutex */
+/* TODO: pool fragments to avoid kmalloc/kfree churn */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/cdev.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/err.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include "../drivers/staging/dream/include/linux/wakelock.h"
+#include <asm/uaccess.h>
+#include <asm/byteorder.h>
+#include <linux/platform_device.h>
+#include <linux/uaccess.h>
+
+#include <asm/byteorder.h>
+
+#include <mach/msm_smd.h>
+#include "smd_rpcrouter.h"
+
+#define TRACE_R2R_MSG 0
+#define TRACE_R2R_RAW 0
+#define TRACE_RPC_MSG 0
+#define TRACE_NOTIFY_MSG 0
+
+#define MSM_RPCROUTER_DEBUG 0
+#define MSM_RPCROUTER_DEBUG_PKT 0
+#define MSM_RPCROUTER_R2R_DEBUG 0
+#define DUMP_ALL_RECEIVED_HEADERS 0
+
+#define DIAG(x...) printk("[RR] ERROR " x)
+
+#if MSM_RPCROUTER_DEBUG
+#define D(x...) printk(x)
+#else
+#define D(x...) do {} while (0)
+#endif
+
+#if TRACE_R2R_MSG
+#define RR(x...) printk("[RR] "x)
+#else
+#define RR(x...) do {} while (0)
+#endif
+
+#if TRACE_RPC_MSG
+#define IO(x...) printk("[RPC] "x)
+#else
+#define IO(x...) do {} while (0)
+#endif
+
+#if TRACE_NOTIFY_MSG
+#define NTFY(x...) printk(KERN_ERR "[NOTIFY] "x)
+#else
+#define NTFY(x...) do {} while (0)
+#endif
+
+static LIST_HEAD(local_endpoints);
+static LIST_HEAD(remote_endpoints);
+
+static LIST_HEAD(server_list);
+
+static smd_channel_t *smd_channel;
+static int initialized;
+static wait_queue_head_t newserver_wait;
+static wait_queue_head_t smd_wait;
+static int smd_wait_count; /* odd while waiting */
+
+static DEFINE_SPINLOCK(local_endpoints_lock);
+static DEFINE_SPINLOCK(remote_endpoints_lock);
+static DEFINE_SPINLOCK(server_list_lock);
+static DEFINE_SPINLOCK(smd_lock);
+
+static struct workqueue_struct *rpcrouter_workqueue;
+static struct wake_lock rpcrouter_wake_lock;
+static int rpcrouter_need_len;
+
+static atomic_t next_xid = ATOMIC_INIT(1);
+static uint8_t next_pacmarkid;
+
+static void do_read_data(struct work_struct *work);
+static void do_create_pdevs(struct work_struct *work);
+static void do_create_rpcrouter_pdev(struct work_struct *work);
+
+static DECLARE_WORK(work_read_data, do_read_data);
+static DECLARE_WORK(work_create_pdevs, do_create_pdevs);
+static DECLARE_WORK(work_create_rpcrouter_pdev, do_create_rpcrouter_pdev);
+
+#define RR_STATE_IDLE    0
+#define RR_STATE_HEADER  1
+#define RR_STATE_BODY    2
+#define RR_STATE_ERROR   3
+
+struct rr_context {
+	struct rr_packet *pkt;
+	uint8_t *ptr;
+	uint32_t state; /* current assembly state */
+	uint32_t count; /* bytes needed in this state */
+};
+
+struct rr_context the_rr_context;
+
+static struct platform_device rpcrouter_pdev = {
+	.name		= "oncrpc_router",
+	.id		= -1,
+};
+
+
+static int rpcrouter_send_control_msg(union rr_control_msg *msg)
+{
+	struct rr_header hdr;
+	unsigned long flags;
+	int need;
+
+	if (!(msg->cmd == RPCROUTER_CTRL_CMD_HELLO) && !initialized) {
+		printk(KERN_ERR "rpcrouter_send_control_msg(): Warning, "
+		       "router not initialized\n");
+		return -EINVAL;
+	}
+
+	hdr.version = RPCROUTER_VERSION;
+	hdr.type = msg->cmd;
+	hdr.src_pid = RPCROUTER_PID_LOCAL;
+	hdr.src_cid = RPCROUTER_ROUTER_ADDRESS;
+	hdr.confirm_rx = 0;
+	hdr.size = sizeof(*msg);
+	hdr.dst_pid = 0;
+	hdr.dst_cid = RPCROUTER_ROUTER_ADDRESS;
+
+	/* TODO: what if channel is full? */
+
+	need = sizeof(hdr) + hdr.size;
+	spin_lock_irqsave(&smd_lock, flags);
+	while (smd_write_avail(smd_channel) < need) {
+		spin_unlock_irqrestore(&smd_lock, flags);
+		msleep(250);
+		spin_lock_irqsave(&smd_lock, flags);
+	}
+	smd_write(smd_channel, &hdr, sizeof(hdr));
+	smd_write(smd_channel, msg, hdr.size);
+	spin_unlock_irqrestore(&smd_lock, flags);
+	return 0;
+}
+
+static struct rr_server *rpcrouter_create_server(uint32_t pid,
+							uint32_t cid,
+							uint32_t prog,
+							uint32_t ver)
+{
+	struct rr_server *server;
+	unsigned long flags;
+	int rc;
+
+	server = kmalloc(sizeof(struct rr_server), GFP_KERNEL);
+	if (!server)
+		return ERR_PTR(-ENOMEM);
+
+	memset(server, 0, sizeof(struct rr_server));
+	server->pid = pid;
+	server->cid = cid;
+	server->prog = prog;
+	server->vers = ver;
+
+	spin_lock_irqsave(&server_list_lock, flags);
+	list_add_tail(&server->list, &server_list);
+	spin_unlock_irqrestore(&server_list_lock, flags);
+
+	if (pid == RPCROUTER_PID_REMOTE) {
+		rc = msm_rpcrouter_create_server_cdev(server);
+		if (rc < 0)
+			goto out_fail;
+	}
+	return server;
+out_fail:
+	spin_lock_irqsave(&server_list_lock, flags);
+	list_del(&server->list);
+	spin_unlock_irqrestore(&server_list_lock, flags);
+	kfree(server);
+	return ERR_PTR(rc);
+}
+
+static void rpcrouter_destroy_server(struct rr_server *server)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&server_list_lock, flags);
+	list_del(&server->list);
+	spin_unlock_irqrestore(&server_list_lock, flags);
+	device_destroy(msm_rpcrouter_class, server->device_number);
+	kfree(server);
+}
+
+static struct rr_server *rpcrouter_lookup_server(uint32_t prog, uint32_t ver)
+{
+	struct rr_server *server;
+	unsigned long flags;
+
+	spin_lock_irqsave(&server_list_lock, flags);
+	list_for_each_entry(server, &server_list, list) {
+		if (server->prog == prog
+		 && server->vers == ver) {
+			spin_unlock_irqrestore(&server_list_lock, flags);
+			return server;
+		}
+	}
+	spin_unlock_irqrestore(&server_list_lock, flags);
+	return NULL;
+}
+
+static struct rr_server *rpcrouter_lookup_server_by_dev(dev_t dev)
+{
+	struct rr_server *server;
+	unsigned long flags;
+
+	spin_lock_irqsave(&server_list_lock, flags);
+	list_for_each_entry(server, &server_list, list) {
+		if (server->device_number == dev) {
+			spin_unlock_irqrestore(&server_list_lock, flags);
+			return server;
+		}
+	}
+	spin_unlock_irqrestore(&server_list_lock, flags);
+	return NULL;
+}
+
+struct msm_rpc_endpoint *msm_rpcrouter_create_local_endpoint(dev_t dev)
+{
+	struct msm_rpc_endpoint *ept;
+	unsigned long flags;
+
+	ept = kmalloc(sizeof(struct msm_rpc_endpoint), GFP_KERNEL);
+	if (!ept)
+		return NULL;
+	memset(ept, 0, sizeof(struct msm_rpc_endpoint));
+
+	/* mark no reply outstanding */
+	ept->reply_pid = 0xffffffff;
+
+	ept->cid = (uint32_t) ept;
+	ept->pid = RPCROUTER_PID_LOCAL;
+	ept->dev = dev;
+
+	if ((dev != msm_rpcrouter_devno) && (dev != MKDEV(0, 0))) {
+		struct rr_server *srv;
+		/*
+		 * This is a userspace client which opened
+		 * a program/ver devicenode. Bind the client
+		 * to that destination
+		 */
+		srv = rpcrouter_lookup_server_by_dev(dev);
+		/* TODO: bug? really? */
+		BUG_ON(!srv);
+
+		ept->dst_pid = srv->pid;
+		ept->dst_cid = srv->cid;
+		ept->dst_prog = cpu_to_be32(srv->prog);
+		ept->dst_vers = cpu_to_be32(srv->vers);
+		ept->flags |= MSM_RPC_ENABLE_RECEIVE;
+
+		D("Creating local ept %p @ %08x:%08x\n", ept, srv->prog, srv->vers);
+	} else {
+		/* mark not connected */
+		ept->dst_pid = 0xffffffff;
+		D("Creating a master local ept %p\n", ept);
+	}
+
+	init_waitqueue_head(&ept->wait_q);
+	INIT_LIST_HEAD(&ept->read_q);
+	spin_lock_init(&ept->read_q_lock);
+	wake_lock_init(&ept->read_q_wake_lock, WAKE_LOCK_SUSPEND, "rpc_read");
+	INIT_LIST_HEAD(&ept->incomplete);
+
+	spin_lock_irqsave(&local_endpoints_lock, flags);
+	list_add_tail(&ept->list, &local_endpoints);
+	spin_unlock_irqrestore(&local_endpoints_lock, flags);
+	return ept;
+}
+
+int msm_rpcrouter_destroy_local_endpoint(struct msm_rpc_endpoint *ept)
+{
+	int rc;
+	union rr_control_msg msg;
+
+	msg.cmd = RPCROUTER_CTRL_CMD_REMOVE_CLIENT;
+	msg.cli.pid = ept->pid;
+	msg.cli.cid = ept->cid;
+
+	RR("x REMOVE_CLIENT id=%d:%08x\n", ept->pid, ept->cid);
+	rc = rpcrouter_send_control_msg(&msg);
+	if (rc < 0)
+		return rc;
+
+	wake_lock_destroy(&ept->read_q_wake_lock);
+	list_del(&ept->list);
+	kfree(ept);
+	return 0;
+}
+
+static int rpcrouter_create_remote_endpoint(uint32_t cid)
+{
+	struct rr_remote_endpoint *new_c;
+	unsigned long flags;
+
+	new_c = kmalloc(sizeof(struct rr_remote_endpoint), GFP_KERNEL);
+	if (!new_c)
+		return -ENOMEM;
+	memset(new_c, 0, sizeof(struct rr_remote_endpoint));
+
+	new_c->cid = cid;
+	new_c->pid = RPCROUTER_PID_REMOTE;
+	init_waitqueue_head(&new_c->quota_wait);
+	spin_lock_init(&new_c->quota_lock);
+
+	spin_lock_irqsave(&remote_endpoints_lock, flags);
+	list_add_tail(&new_c->list, &remote_endpoints);
+	spin_unlock_irqrestore(&remote_endpoints_lock, flags);
+	return 0;
+}
+
+static struct msm_rpc_endpoint *rpcrouter_lookup_local_endpoint(uint32_t cid)
+{
+	struct msm_rpc_endpoint *ept;
+	unsigned long flags;
+
+	spin_lock_irqsave(&local_endpoints_lock, flags);
+	list_for_each_entry(ept, &local_endpoints, list) {
+		if (ept->cid == cid) {
+			spin_unlock_irqrestore(&local_endpoints_lock, flags);
+			return ept;
+		}
+	}
+	spin_unlock_irqrestore(&local_endpoints_lock, flags);
+	return NULL;
+}
+
+static struct rr_remote_endpoint *rpcrouter_lookup_remote_endpoint(uint32_t cid)
+{
+	struct rr_remote_endpoint *ept;
+	unsigned long flags;
+
+	spin_lock_irqsave(&remote_endpoints_lock, flags);
+	list_for_each_entry(ept, &remote_endpoints, list) {
+		if (ept->cid == cid) {
+			spin_unlock_irqrestore(&remote_endpoints_lock, flags);
+			return ept;
+		}
+	}
+	spin_unlock_irqrestore(&remote_endpoints_lock, flags);
+	return NULL;
+}
+
+static int process_control_msg(union rr_control_msg *msg, int len)
+{
+	union rr_control_msg ctl;
+	struct rr_server *server;
+	struct rr_remote_endpoint *r_ept;
+	int rc = 0;
+	unsigned long flags;
+
+	if (len != sizeof(*msg)) {
+		printk(KERN_ERR "rpcrouter: r2r msg size %d != %d\n",
+		       len, sizeof(*msg));
+		return -EINVAL;
+	}
+
+	switch (msg->cmd) {
+	case RPCROUTER_CTRL_CMD_HELLO:
+		RR("o HELLO\n");
+
+		RR("x HELLO\n");
+		memset(&ctl, 0, sizeof(ctl));
+		ctl.cmd = RPCROUTER_CTRL_CMD_HELLO;
+		rpcrouter_send_control_msg(&ctl);
+
+		initialized = 1;
+
+		/* Send list of servers one at a time */
+		ctl.cmd = RPCROUTER_CTRL_CMD_NEW_SERVER;
+
+		/* TODO: long time to hold a spinlock... */
+		spin_lock_irqsave(&server_list_lock, flags);
+		list_for_each_entry(server, &server_list, list) {
+			ctl.srv.pid = server->pid;
+			ctl.srv.cid = server->cid;
+			ctl.srv.prog = server->prog;
+			ctl.srv.vers = server->vers;
+
+			RR("x NEW_SERVER id=%d:%08x prog=%08x:%08x\n",
+			   server->pid, server->cid,
+			   server->prog, server->vers);
+
+			rpcrouter_send_control_msg(&ctl);
+		}
+		spin_unlock_irqrestore(&server_list_lock, flags);
+
+		queue_work(rpcrouter_workqueue, &work_create_rpcrouter_pdev);
+		break;
+
+	case RPCROUTER_CTRL_CMD_RESUME_TX:
+		RR("o RESUME_TX id=%d:%08x\n", msg->cli.pid, msg->cli.cid);
+
+		r_ept = rpcrouter_lookup_remote_endpoint(msg->cli.cid);
+		if (!r_ept) {
+			printk(KERN_ERR
+			       "rpcrouter: Unable to resume client\n");
+			break;
+		}
+		spin_lock_irqsave(&r_ept->quota_lock, flags);
+		r_ept->tx_quota_cntr = 0;
+		spin_unlock_irqrestore(&r_ept->quota_lock, flags);
+		wake_up(&r_ept->quota_wait);
+		break;
+
+	case RPCROUTER_CTRL_CMD_NEW_SERVER:
+		RR("o NEW_SERVER id=%d:%08x prog=%08x:%08x\n",
+		   msg->srv.pid, msg->srv.cid, msg->srv.prog, msg->srv.vers);
+
+		server = rpcrouter_lookup_server(msg->srv.prog, msg->srv.vers);
+
+		if (!server) {
+			server = rpcrouter_create_server(
+				msg->srv.pid, msg->srv.cid,
+				msg->srv.prog, msg->srv.vers);
+			if (!server)
+				return -ENOMEM;
+			/*
+			 * XXX: Verify that its okay to add the
+			 * client to our remote client list
+			 * if we get a NEW_SERVER notification
+			 */
+			if (!rpcrouter_lookup_remote_endpoint(msg->srv.cid)) {
+				rc = rpcrouter_create_remote_endpoint(
+					msg->srv.cid);
+				if (rc < 0)
+					printk(KERN_ERR
+						"rpcrouter:Client create"
+						"error (%d)\n", rc);
+			}
+			schedule_work(&work_create_pdevs);
+			wake_up(&newserver_wait);
+		} else {
+			if ((server->pid == msg->srv.pid) &&
+			    (server->cid == msg->srv.cid)) {
+				printk(KERN_ERR "rpcrouter: Duplicate svr\n");
+			} else {
+				server->pid = msg->srv.pid;
+				server->cid = msg->srv.cid;
+			}
+		}
+		break;
+
+	case RPCROUTER_CTRL_CMD_REMOVE_SERVER:
+		RR("o REMOVE_SERVER prog=%08x:%d\n",
+		   msg->srv.prog, msg->srv.vers);
+		server = rpcrouter_lookup_server(msg->srv.prog, msg->srv.vers);
+		if (server)
+			rpcrouter_destroy_server(server);
+		break;
+
+	case RPCROUTER_CTRL_CMD_REMOVE_CLIENT:
+		RR("o REMOVE_CLIENT id=%d:%08x\n", msg->cli.pid, msg->cli.cid);
+		if (msg->cli.pid != RPCROUTER_PID_REMOTE) {
+			printk(KERN_ERR
+			       "rpcrouter: Denying remote removal of "
+			       "local client\n");
+			break;
+		}
+		r_ept = rpcrouter_lookup_remote_endpoint(msg->cli.cid);
+		if (r_ept) {
+			spin_lock_irqsave(&remote_endpoints_lock, flags);
+			list_del(&r_ept->list);
+			spin_unlock_irqrestore(&remote_endpoints_lock, flags);
+			kfree(r_ept);
+		}
+
+		/* Notify local clients of this event */
+		printk(KERN_ERR "rpcrouter: LOCAL NOTIFICATION NOT IMP\n");
+		rc = -ENOSYS;
+
+		break;
+	default:
+		RR("o UNKNOWN(%08x)\n", msg->cmd);
+		rc = -ENOSYS;
+	}
+
+	return rc;
+}
+
+static void do_create_rpcrouter_pdev(struct work_struct *work)
+{
+	platform_device_register(&rpcrouter_pdev);
+}
+
+static void do_create_pdevs(struct work_struct *work)
+{
+	unsigned long flags;
+	struct rr_server *server;
+
+	/* TODO: race if destroyed while being registered */
+	spin_lock_irqsave(&server_list_lock, flags);
+	list_for_each_entry(server, &server_list, list) {
+		if (server->pid == RPCROUTER_PID_REMOTE) {
+			if (server->pdev_name[0] == 0) {
+				spin_unlock_irqrestore(&server_list_lock,
+						       flags);
+				msm_rpcrouter_create_server_pdev(server);
+				schedule_work(&work_create_pdevs);
+				return;
+			}
+		}
+	}
+	spin_unlock_irqrestore(&server_list_lock, flags);
+}
+
+static void rpcrouter_smdnotify(void *_dev, unsigned event)
+{
+	if (event != SMD_EVENT_DATA)
+		return;
+
+	if (smd_read_avail(smd_channel) >= rpcrouter_need_len)
+		wake_lock(&rpcrouter_wake_lock);
+	wake_up(&smd_wait);
+}
+
+static void *rr_malloc(unsigned sz)
+{
+	void *ptr = kmalloc(sz, GFP_KERNEL);
+	if (ptr)
+		return ptr;
+
+	printk(KERN_ERR "rpcrouter: kmalloc of %d failed, retrying...\n", sz);
+	do {
+		ptr = kmalloc(sz, GFP_KERNEL);
+	} while (!ptr);
+
+	return ptr;
+}
+
+/* TODO: deal with channel teardown / restore */
+static int rr_read(void *data, int len)
+{
+	int rc;
+	unsigned long flags;
+//	printk("rr_read() %d\n", len);
+	for(;;) {
+		spin_lock_irqsave(&smd_lock, flags);
+		if (smd_read_avail(smd_channel) >= len) {
+			rc = smd_read(smd_channel, data, len);
+			spin_unlock_irqrestore(&smd_lock, flags);
+			if (rc == len)
+				return 0;
+			else
+				return -EIO;
+		}
+		rpcrouter_need_len = len;
+		wake_unlock(&rpcrouter_wake_lock);
+		spin_unlock_irqrestore(&smd_lock, flags);
+
+//		printk("rr_read: waiting (%d)\n", len);
+		smd_wait_count++;
+		wake_up(&smd_wait);
+		wait_event(smd_wait, smd_read_avail(smd_channel) >= len);
+		smd_wait_count++;
+	}
+	return 0;
+}
+
+static uint32_t r2r_buf[RPCROUTER_MSGSIZE_MAX];
+
+static void do_read_data(struct work_struct *work)
+{
+	struct rr_header hdr;
+	struct rr_packet *pkt;
+	struct rr_fragment *frag;
+	struct msm_rpc_endpoint *ept;
+	uint32_t pm, mid;
+	unsigned long flags;
+
+	if (rr_read(&hdr, sizeof(hdr)))
+		goto fail_io;
+
+#if TRACE_R2R_RAW
+	RR("- ver=%d type=%d src=%d:%08x crx=%d siz=%d dst=%d:%08x\n",
+	   hdr.version, hdr.type, hdr.src_pid, hdr.src_cid,
+	   hdr.confirm_rx, hdr.size, hdr.dst_pid, hdr.dst_cid);
+#endif
+
+	if (hdr.version != RPCROUTER_VERSION) {
+		DIAG("version %d != %d\n", hdr.version, RPCROUTER_VERSION);
+		goto fail_data;
+	}
+	if (hdr.size > RPCROUTER_MSGSIZE_MAX) {
+		DIAG("msg size %d > max %d\n", hdr.size, RPCROUTER_MSGSIZE_MAX);
+		goto fail_data;
+	}
+
+	if (hdr.dst_cid == RPCROUTER_ROUTER_ADDRESS) {
+		if (rr_read(r2r_buf, hdr.size))
+			goto fail_io;
+		process_control_msg((void*) r2r_buf, hdr.size);
+		goto done;
+	}
+
+	if (hdr.size < sizeof(pm)) {
+		DIAG("runt packet (no pacmark)\n");
+		goto fail_data;
+	}
+	if (rr_read(&pm, sizeof(pm)))
+		goto fail_io;
+
+	hdr.size -= sizeof(pm);
+
+	frag = rr_malloc(hdr.size + sizeof(*frag));
+	frag->next = NULL;
+	frag->length = hdr.size;
+	if (rr_read(frag->data, hdr.size))
+		goto fail_io;
+
+	ept = rpcrouter_lookup_local_endpoint(hdr.dst_cid);
+	if (!ept) {
+		DIAG("no local ept for cid %08x\n", hdr.dst_cid);
+		kfree(frag);
+		goto done;
+	}
+
+	/* See if there is already a partial packet that matches our mid
+	 * and if so, append this fragment to that packet.
+	 */
+	mid = PACMARK_MID(pm);
+	list_for_each_entry(pkt, &ept->incomplete, list) {
+		if (pkt->mid == mid) {
+			pkt->last->next = frag;
+			pkt->last = frag;
+			pkt->length += frag->length;
+			if (PACMARK_LAST(pm)) {
+				list_del(&pkt->list);
+				goto packet_complete;
+			}
+			goto done;
+		}
+	}
+	/* This mid is new -- create a packet for it, and put it on
+	 * the incomplete list if this fragment is not a last fragment,
+	 * otherwise put it on the read queue.
+	 */
+	pkt = rr_malloc(sizeof(struct rr_packet));
+	pkt->first = frag;
+	pkt->last = frag;
+	memcpy(&pkt->hdr, &hdr, sizeof(hdr));
+	pkt->mid = mid;
+	pkt->length = frag->length;
+	if (!PACMARK_LAST(pm)) {
+		list_add_tail(&pkt->list, &ept->incomplete);
+		goto done;
+	}
+
+packet_complete:
+	spin_lock_irqsave(&ept->read_q_lock, flags);
+	if (ept->flags & MSM_RPC_ENABLE_RECEIVE) {
+		wake_lock(&ept->read_q_wake_lock);
+		list_add_tail(&pkt->list, &ept->read_q);
+		wake_up(&ept->wait_q);
+	} else {
+		pr_warning("smd_rpcrouter: Unexpected incoming data on %08x:%08x\n",
+				be32_to_cpu(ept->dst_prog),
+				be32_to_cpu(ept->dst_vers));
+	}
+	spin_unlock_irqrestore(&ept->read_q_lock, flags);
+done:
+
+	if (hdr.confirm_rx) {
+		union rr_control_msg msg;
+
+		msg.cmd = RPCROUTER_CTRL_CMD_RESUME_TX;
+		msg.cli.pid = hdr.dst_pid;
+		msg.cli.cid = hdr.dst_cid;
+
+		RR("x RESUME_TX id=%d:%08x\n", msg.cli.pid, msg.cli.cid);
+		rpcrouter_send_control_msg(&msg);
+	}
+
+	queue_work(rpcrouter_workqueue, &work_read_data);
+	return;
+
+fail_io:
+fail_data:
+	printk(KERN_ERR "rpc_router has died\n");
+	wake_unlock(&rpcrouter_wake_lock);
+}
+
+void msm_rpc_setup_req(struct rpc_request_hdr *hdr, uint32_t prog,
+		       uint32_t vers, uint32_t proc)
+{
+	memset(hdr, 0, sizeof(struct rpc_request_hdr));
+	hdr->xid = cpu_to_be32(atomic_add_return(1, &next_xid));
+	hdr->rpc_vers = cpu_to_be32(2);
+	hdr->prog = cpu_to_be32(prog);
+	hdr->vers = cpu_to_be32(vers);
+	hdr->procedure = cpu_to_be32(proc);
+}
+
+struct msm_rpc_endpoint *msm_rpc_open(void)
+{
+	struct msm_rpc_endpoint *ept;
+
+	ept = msm_rpcrouter_create_local_endpoint(MKDEV(0, 0));
+	if (ept == NULL)
+		return ERR_PTR(-ENOMEM);
+
+	return ept;
+}
+
+int msm_rpc_close(struct msm_rpc_endpoint *ept)
+{
+	return msm_rpcrouter_destroy_local_endpoint(ept);
+}
+EXPORT_SYMBOL(msm_rpc_close);
+
+int msm_rpc_write(struct msm_rpc_endpoint *ept, void *buffer, int count)
+{
+	struct rr_header hdr;
+	uint32_t pacmark;
+	struct rpc_request_hdr *rq = buffer;
+	struct rr_remote_endpoint *r_ept;
+	unsigned long flags;
+	int needed;
+	DEFINE_WAIT(__wait);
+
+	/* TODO: fragmentation for large outbound packets */
+	if (count > (RPCROUTER_MSGSIZE_MAX - sizeof(uint32_t)) || !count)
+		return -EINVAL;
+
+	/* snoop the RPC packet and enforce permissions */
+
+	/* has to have at least the xid and type fields */
+	if (count < (sizeof(uint32_t) * 2)) {
+		printk(KERN_ERR "rr_write: rejecting runt packet\n");
+		return -EINVAL;
+	}
+
+	if (rq->type == 0) {
+		/* RPC CALL */
+		if (count < (sizeof(uint32_t) * 6)) {
+			printk(KERN_ERR
+			       "rr_write: rejecting runt call packet\n");
+			return -EINVAL;
+		}
+		if (ept->dst_pid == 0xffffffff) {
+			printk(KERN_ERR "rr_write: not connected\n");
+			return -ENOTCONN;
+		}
+
+#if CONFIG_MSM_AMSS_VERSION >= 6350
+		if ((ept->dst_prog != rq->prog) ||
+			!msm_rpc_is_compatible_version(
+					be32_to_cpu(ept->dst_vers),
+					be32_to_cpu(rq->vers))) {
+#else
+		if (ept->dst_prog != rq->prog || ept->dst_vers != rq->vers) {
+#endif
+			printk(KERN_ERR
+			       "rr_write: cannot write to %08x:%d "
+			       "(bound to %08x:%d)\n",
+			       be32_to_cpu(rq->prog), be32_to_cpu(rq->vers),
+			       be32_to_cpu(ept->dst_prog),
+			       be32_to_cpu(ept->dst_vers));
+			return -EINVAL;
+		}
+		hdr.dst_pid = ept->dst_pid;
+		hdr.dst_cid = ept->dst_cid;
+		IO("CALL on ept %p to %08x:%08x @ %d:%08x (%d bytes) (xid %x proc %x)\n",
+		   ept,
+		   be32_to_cpu(rq->prog), be32_to_cpu(rq->vers),
+		   ept->dst_pid, ept->dst_cid, count,
+		   be32_to_cpu(rq->xid), be32_to_cpu(rq->procedure));
+	} else {
+		/* RPC REPLY */
+		/* TODO: locking */
+		if (ept->reply_pid == 0xffffffff) {
+			printk(KERN_ERR
+			       "rr_write: rejecting unexpected reply\n");
+			return -EINVAL;
+		}
+		if (ept->reply_xid != rq->xid) {
+			printk(KERN_ERR
+			       "rr_write: rejecting packet w/ bad xid\n");
+			return -EINVAL;
+		}
+
+		hdr.dst_pid = ept->reply_pid;
+		hdr.dst_cid = ept->reply_cid;
+
+		/* consume this reply */
+		ept->reply_pid = 0xffffffff;
+
+		IO("REPLY on ept %p to xid=%d @ %d:%08x (%d bytes)\n",
+		   ept,
+		   be32_to_cpu(rq->xid), hdr.dst_pid, hdr.dst_cid, count);
+	}
+
+	r_ept = rpcrouter_lookup_remote_endpoint(hdr.dst_cid);
+
+	if (!r_ept) {
+		printk(KERN_ERR
+			"msm_rpc_write(): No route to ept "
+			"[PID %x CID %x]\n", hdr.dst_pid, hdr.dst_cid);
+		return -EHOSTUNREACH;
+	}
+
+	/* Create routing header */
+	hdr.type = RPCROUTER_CTRL_CMD_DATA;
+	hdr.version = RPCROUTER_VERSION;
+	hdr.src_pid = ept->pid;
+	hdr.src_cid = ept->cid;
+	hdr.confirm_rx = 0;
+	hdr.size = count + sizeof(uint32_t);
+
+	for (;;) {
+		prepare_to_wait(&r_ept->quota_wait, &__wait,
+				TASK_INTERRUPTIBLE);
+		spin_lock_irqsave(&r_ept->quota_lock, flags);
+		if (r_ept->tx_quota_cntr < RPCROUTER_DEFAULT_RX_QUOTA)
+			break;
+		if (signal_pending(current) && 
+		    (!(ept->flags & MSM_RPC_UNINTERRUPTIBLE)))
+			break;
+		spin_unlock_irqrestore(&r_ept->quota_lock, flags);
+		schedule();
+	}
+	finish_wait(&r_ept->quota_wait, &__wait);
+
+	if (signal_pending(current) &&
+	    (!(ept->flags & MSM_RPC_UNINTERRUPTIBLE))) {
+		spin_unlock_irqrestore(&r_ept->quota_lock, flags);
+		return -ERESTARTSYS;
+	}
+	r_ept->tx_quota_cntr++;
+	if (r_ept->tx_quota_cntr == RPCROUTER_DEFAULT_RX_QUOTA)
+		hdr.confirm_rx = 1;
+
+	/* bump pacmark while interrupts disabled to avoid race
+	 * probably should be atomic op instead
+	 */
+	pacmark = PACMARK(count, ++next_pacmarkid, 0, 1);
+
+	spin_unlock_irqrestore(&r_ept->quota_lock, flags);
+
+	spin_lock_irqsave(&smd_lock, flags);
+
+	needed = sizeof(hdr) + hdr.size;
+	while (smd_write_avail(smd_channel) < needed) {
+		spin_unlock_irqrestore(&smd_lock, flags);
+		msleep(250);
+		spin_lock_irqsave(&smd_lock, flags);
+	}
+
+	/* TODO: deal with full fifo */
+	smd_write(smd_channel, &hdr, sizeof(hdr));
+	smd_write(smd_channel, &pacmark, sizeof(pacmark));
+	smd_write(smd_channel, buffer, count);
+
+	spin_unlock_irqrestore(&smd_lock, flags);
+
+	return count;
+}
+EXPORT_SYMBOL(msm_rpc_write);
+
+/*
+ * NOTE: It is the responsibility of the caller to kfree buffer
+ */
+int msm_rpc_read(struct msm_rpc_endpoint *ept, void **buffer,
+		 unsigned user_len, long timeout)
+{
+	struct rr_fragment *frag, *next;
+	char *buf;
+	int rc;
+
+	rc = __msm_rpc_read(ept, &frag, user_len, timeout);
+	if (rc <= 0)
+		return rc;
+
+	/* single-fragment messages conveniently can be
+	 * returned as-is (the buffer is at the front)
+	 */
+	if (frag->next == 0) {
+		*buffer = (void*) frag;
+		return rc;
+	}
+
+	/* multi-fragment messages, we have to do it the
+	 * hard way, which is rather disgusting right now
+	 */
+	buf = rr_malloc(rc);
+	*buffer = buf;
+
+	while (frag != NULL) {
+		memcpy(buf, frag->data, frag->length);
+		next = frag->next;
+		buf += frag->length;
+		kfree(frag);
+		frag = next;
+	}
+
+	return rc;
+}
+
+int msm_rpc_call(struct msm_rpc_endpoint *ept, uint32_t proc,
+		 void *_request, int request_size,
+		 long timeout)
+{
+	return msm_rpc_call_reply(ept, proc,
+				  _request, request_size,
+				  NULL, 0, timeout);
+}
+EXPORT_SYMBOL(msm_rpc_call);
+
+int msm_rpc_call_reply(struct msm_rpc_endpoint *ept, uint32_t proc,
+		       void *_request, int request_size,
+		       void *_reply, int reply_size,
+		       long timeout)
+{
+	struct rpc_request_hdr *req = _request;
+	struct rpc_reply_hdr *reply;
+	int rc;
+
+	if (request_size < sizeof(*req))
+		return -ETOOSMALL;
+
+	if (ept->dst_pid == 0xffffffff)
+		return -ENOTCONN;
+
+	/* We can't use msm_rpc_setup_req() here, because dst_prog and
+	 * dst_vers here are already in BE.
+	 */
+	memset(req, 0, sizeof(*req));
+	req->xid = cpu_to_be32(atomic_add_return(1, &next_xid));
+	req->rpc_vers = cpu_to_be32(2);
+	req->prog = ept->dst_prog;
+	req->vers = ept->dst_vers;
+	req->procedure = cpu_to_be32(proc);
+
+	/* Allow replys to be added to the queue */
+	ept->flags |= MSM_RPC_ENABLE_RECEIVE;
+
+	rc = msm_rpc_write(ept, req, request_size);
+	if (rc < 0)
+		goto error;
+
+	for (;;) {
+		rc = msm_rpc_read(ept, (void*) &reply, -1, timeout);
+		if (rc < 0)
+			goto error;
+		if (rc < (3 * sizeof(uint32_t))) {
+			rc = -EIO;
+			break;
+		}
+		/* we should not get CALL packets -- ignore them */
+		if (reply->type == 0) {
+			kfree(reply);
+			continue;
+		}
+		/* If an earlier call timed out, we could get the (no
+		 * longer wanted) reply for it.  Ignore replies that
+		 * we don't expect.
+		 */
+		if (reply->xid != req->xid) {
+			kfree(reply);
+			continue;
+		}
+		if (reply->reply_stat != 0) {
+			rc = -EPERM;
+			break;
+		}
+		if (reply->data.acc_hdr.accept_stat != 0) {
+			rc = -EINVAL;
+			break;
+		}
+		if (_reply == NULL) {
+			rc = 0;
+			break;
+		}
+		if (rc > reply_size) {
+			rc = -ENOMEM;
+		} else {
+			memcpy(_reply, reply, rc);
+		}
+		break;
+	}
+	kfree(reply);
+error:
+	ept->flags &= ~MSM_RPC_ENABLE_RECEIVE;
+	wake_unlock(&ept->read_q_wake_lock);
+
+	return rc;
+}
+EXPORT_SYMBOL(msm_rpc_call_reply);
+
+
+static inline int ept_packet_available(struct msm_rpc_endpoint *ept)
+{
+	unsigned long flags;
+	int ret;
+	spin_lock_irqsave(&ept->read_q_lock, flags);
+	ret = !list_empty(&ept->read_q);
+	spin_unlock_irqrestore(&ept->read_q_lock, flags);
+	return ret;
+}
+
+int __msm_rpc_read(struct msm_rpc_endpoint *ept,
+		   struct rr_fragment **frag_ret,
+		   unsigned len, long timeout)
+{
+	struct rr_packet *pkt;
+	struct rpc_request_hdr *rq;
+	DEFINE_WAIT(__wait);
+	unsigned long flags;
+	int rc;
+
+	IO("READ on ept %p\n", ept);
+
+	if (ept->flags & MSM_RPC_UNINTERRUPTIBLE) {
+		if (timeout < 0) {
+			wait_event(ept->wait_q, ept_packet_available(ept));
+		} else {
+			rc = wait_event_timeout(
+				ept->wait_q, ept_packet_available(ept),
+				timeout);
+			if (rc == 0)
+				return -ETIMEDOUT;
+		}
+	} else {
+		if (timeout < 0) {
+			rc = wait_event_interruptible(
+				ept->wait_q, ept_packet_available(ept));
+			if (rc < 0)
+				return rc;
+		} else {
+			rc = wait_event_interruptible_timeout(
+				ept->wait_q, ept_packet_available(ept),
+				timeout);
+			if (rc == 0)
+				return -ETIMEDOUT;
+		}
+	}
+
+	spin_lock_irqsave(&ept->read_q_lock, flags);
+	if (list_empty(&ept->read_q)) {
+		spin_unlock_irqrestore(&ept->read_q_lock, flags);
+		return -EAGAIN;
+	}
+	pkt = list_first_entry(&ept->read_q, struct rr_packet, list);
+	if (pkt->length > len) {
+		spin_unlock_irqrestore(&ept->read_q_lock, flags);
+		return -ETOOSMALL;
+	}
+	list_del(&pkt->list);
+	if (list_empty(&ept->read_q))
+		wake_unlock(&ept->read_q_wake_lock);
+	spin_unlock_irqrestore(&ept->read_q_lock, flags);
+
+	rc = pkt->length;
+
+	*frag_ret = pkt->first;
+	rq = (void*) pkt->first->data;
+	if ((rc >= (sizeof(uint32_t) * 3)) && (rq->type == 0)) {
+		IO("READ on ept %p is a CALL on %08x:%08x proc %d xid %d\n",
+			ept, be32_to_cpu(rq->prog), be32_to_cpu(rq->vers),
+			be32_to_cpu(rq->procedure),
+			be32_to_cpu(rq->xid));
+		/* RPC CALL */
+		if (ept->reply_pid != 0xffffffff) {
+			printk(KERN_WARNING
+			       "rr_read: lost previous reply xid...\n");
+		}
+		/* TODO: locking? */
+		ept->reply_pid = pkt->hdr.src_pid;
+		ept->reply_cid = pkt->hdr.src_cid;
+		ept->reply_xid = rq->xid;
+	}
+#if TRACE_RPC_MSG
+	else if ((rc >= (sizeof(uint32_t) * 3)) && (rq->type == 1))
+		IO("READ on ept %p is a REPLY\n", ept);
+	else IO("READ on ept %p (%d bytes)\n", ept, rc);
+#endif
+
+	kfree(pkt);
+	return rc;
+}
+
+#if CONFIG_MSM_AMSS_VERSION >= 6350
+int msm_rpc_is_compatible_version(uint32_t server_version,
+				  uint32_t client_version)
+{
+	if ((server_version & RPC_VERSION_MODE_MASK) !=
+	    (client_version & RPC_VERSION_MODE_MASK))
+		return 0;
+
+	if (server_version & RPC_VERSION_MODE_MASK)
+		return server_version == client_version;
+
+	return ((server_version & RPC_VERSION_MAJOR_MASK) ==
+		(client_version & RPC_VERSION_MAJOR_MASK)) &&
+		((server_version & RPC_VERSION_MINOR_MASK) >=
+		(client_version & RPC_VERSION_MINOR_MASK));
+}
+EXPORT_SYMBOL(msm_rpc_is_compatible_version);
+
+static int msm_rpc_get_compatible_server(uint32_t prog,
+					uint32_t ver,
+					uint32_t *found_vers)
+{
+	struct rr_server *server;
+	unsigned long     flags;
+	if (found_vers == NULL)
+		return 0;
+
+	spin_lock_irqsave(&server_list_lock, flags);
+	list_for_each_entry(server, &server_list, list) {
+		if ((server->prog == prog) &&
+		    msm_rpc_is_compatible_version(server->vers, ver)) {
+			*found_vers = server->vers;
+			spin_unlock_irqrestore(&server_list_lock, flags);
+			return 0;
+		}
+	}
+	spin_unlock_irqrestore(&server_list_lock, flags);
+	return -1;
+}
+#endif
+
+struct msm_rpc_endpoint *msm_rpc_connect(uint32_t prog, uint32_t vers, unsigned flags)
+{
+	struct msm_rpc_endpoint *ept;
+	struct rr_server *server;
+
+#if CONFIG_MSM_AMSS_VERSION >= 6350
+	if (!(vers & RPC_VERSION_MODE_MASK)) {
+		uint32_t found_vers;
+		if (msm_rpc_get_compatible_server(prog, vers, &found_vers) < 0)
+			return ERR_PTR(-EHOSTUNREACH);
+		if (found_vers != vers) {
+			D("RPC using new version %08x:{%08x --> %08x}\n",
+			 	prog, vers, found_vers);
+			vers = found_vers;
+		}
+	}
+#endif
+
+	server = rpcrouter_lookup_server(prog, vers);
+	if (!server)
+		return ERR_PTR(-EHOSTUNREACH);
+
+	ept = msm_rpc_open();
+	if (IS_ERR(ept))
+		return ept;
+
+	ept->flags = flags;
+	ept->dst_pid = server->pid;
+	ept->dst_cid = server->cid;
+	ept->dst_prog = cpu_to_be32(prog);
+	ept->dst_vers = cpu_to_be32(vers);
+
+	return ept;
+}
+EXPORT_SYMBOL(msm_rpc_connect);
+
+uint32_t msm_rpc_get_vers(struct msm_rpc_endpoint *ept)
+{
+	return be32_to_cpu(ept->dst_vers);
+}
+EXPORT_SYMBOL(msm_rpc_get_vers);
+
+/* TODO: permission check? */
+int msm_rpc_register_server(struct msm_rpc_endpoint *ept,
+			    uint32_t prog, uint32_t vers)
+{
+	int rc;
+	union rr_control_msg msg;
+	struct rr_server *server;
+
+	server = rpcrouter_create_server(ept->pid, ept->cid,
+					 prog, vers);
+	if (!server)
+		return -ENODEV;
+
+	msg.srv.cmd = RPCROUTER_CTRL_CMD_NEW_SERVER;
+	msg.srv.pid = ept->pid;
+	msg.srv.cid = ept->cid;
+	msg.srv.prog = prog;
+	msg.srv.vers = vers;
+
+	RR("x NEW_SERVER id=%d:%08x prog=%08x:%08x\n",
+	   ept->pid, ept->cid, prog, vers);
+
+	rc = rpcrouter_send_control_msg(&msg);
+	if (rc < 0)
+		return rc;
+
+	ept->flags |= MSM_RPC_ENABLE_RECEIVE;
+	return 0;
+}
+
+/* TODO: permission check -- disallow unreg of somebody else's server */
+int msm_rpc_unregister_server(struct msm_rpc_endpoint *ept,
+			      uint32_t prog, uint32_t vers)
+{
+	struct rr_server *server;
+	server = rpcrouter_lookup_server(prog, vers);
+
+	if (!server)
+		return -ENOENT;
+
+	ept->flags &= ~MSM_RPC_ENABLE_RECEIVE;
+	wake_unlock(&ept->read_q_wake_lock);
+	rpcrouter_destroy_server(server);
+	return 0;
+}
+
+static int msm_rpcrouter_probe(struct platform_device *pdev)
+{
+	int rc;
+
+	/* Initialize what we need to start processing */
+	INIT_LIST_HEAD(&local_endpoints);
+	INIT_LIST_HEAD(&remote_endpoints);
+
+	init_waitqueue_head(&newserver_wait);
+	init_waitqueue_head(&smd_wait);
+	wake_lock_init(&rpcrouter_wake_lock, WAKE_LOCK_SUSPEND, "SMD_RPCCALL");
+
+	rpcrouter_workqueue = create_singlethread_workqueue("rpcrouter");
+	if (!rpcrouter_workqueue)
+		return -ENOMEM;
+
+	rc = msm_rpcrouter_init_devices();
+	if (rc < 0)
+		goto fail_destroy_workqueue;
+
+	/* Open up SMD channel 2 */
+	initialized = 0;
+	rc = smd_open("SMD_RPCCALL", &smd_channel, NULL, rpcrouter_smdnotify);
+	if (rc < 0)
+		goto fail_remove_devices;
+
+	queue_work(rpcrouter_workqueue, &work_read_data);
+	return 0;
+
+ fail_remove_devices:
+	msm_rpcrouter_exit_devices();
+ fail_destroy_workqueue:
+	destroy_workqueue(rpcrouter_workqueue);
+	return rc;
+}
+
+static int msm_rpcrouter_suspend(struct platform_device *pdev,
+					pm_message_t state)
+{
+	/* Wait until the worker thread has waited at least once so that it
+	 * gets a chance to release its wakelock.
+	 */
+	int wait_count = smd_wait_count;
+	if (!(smd_wait_count & 1))
+		wait_event(smd_wait, smd_wait_count != wait_count);
+	return 0;
+}
+
+static struct platform_driver msm_smd_channel2_driver = {
+	.probe		= msm_rpcrouter_probe,
+	.driver		= {
+			.name	= "SMD_RPCCALL",
+			.owner	= THIS_MODULE,
+	},
+	.suspend	= msm_rpcrouter_suspend,
+};
+
+static int __init rpcrouter_init(void)
+{
+	return platform_driver_register(&msm_smd_channel2_driver);
+}
+
+module_init(rpcrouter_init);
+MODULE_DESCRIPTION("MSM RPC Router");
+MODULE_AUTHOR("San Mehat <san@xxxxxxxxxxx>");
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-msm/smd_rpcrouter.h b/arch/arm/mach-msm/smd_rpcrouter.h
new file mode 100644
index 0000000..4279e6f
--- /dev/null
+++ b/arch/arm/mach-msm/smd_rpcrouter.h
@@ -0,0 +1,195 @@
+/** arch/arm/mach-msm/smd_rpcrouter.h
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2007-2008 QUALCOMM Incorporated.
+ * Author: San Mehat <san@xxxxxxxxxxx>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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 _ARCH_ARM_MACH_MSM_SMD_RPCROUTER_H
+#define _ARCH_ARM_MACH_MSM_SMD_RPCROUTER_H
+
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/cdev.h>
+#include <linux/platform_device.h>
+#include "../drivers/staging/dream/include/linux/wakelock.h"
+
+#include <mach/msm_smd.h>
+#include "../drivers/staging/dream/include/mach/msm_rpcrouter.h"
+
+/* definitions for the R2R wire protcol */
+
+#define RPCROUTER_VERSION			1
+#define RPCROUTER_PROCESSORS_MAX		4
+#define RPCROUTER_MSGSIZE_MAX			512
+
+#define RPCROUTER_CLIENT_BCAST_ID		0xffffffff
+#define RPCROUTER_ROUTER_ADDRESS		0xfffffffe
+
+#define RPCROUTER_PID_LOCAL			1
+#define RPCROUTER_PID_REMOTE			0
+
+#define RPCROUTER_CTRL_CMD_DATA			1
+#define RPCROUTER_CTRL_CMD_HELLO		2
+#define RPCROUTER_CTRL_CMD_BYE			3
+#define RPCROUTER_CTRL_CMD_NEW_SERVER		4
+#define RPCROUTER_CTRL_CMD_REMOVE_SERVER	5
+#define RPCROUTER_CTRL_CMD_REMOVE_CLIENT	6
+#define RPCROUTER_CTRL_CMD_RESUME_TX		7
+#define RPCROUTER_CTRL_CMD_EXIT			8
+
+#define RPCROUTER_DEFAULT_RX_QUOTA	5
+
+union rr_control_msg {
+	uint32_t cmd;
+	struct {
+		uint32_t cmd;
+		uint32_t prog;
+		uint32_t vers;
+		uint32_t pid;
+		uint32_t cid;
+	} srv;
+	struct {
+		uint32_t cmd;
+		uint32_t pid;
+		uint32_t cid;
+	} cli;
+};
+
+struct rr_header {
+	uint32_t version;
+	uint32_t type;
+	uint32_t src_pid;
+	uint32_t src_cid;
+	uint32_t confirm_rx;
+	uint32_t size;
+	uint32_t dst_pid;
+	uint32_t dst_cid;
+};
+
+/* internals */
+
+#define RPCROUTER_MAX_REMOTE_SERVERS		100
+
+struct rr_fragment {
+	unsigned char data[RPCROUTER_MSGSIZE_MAX];
+	uint32_t length;
+	struct rr_fragment *next;
+};
+
+struct rr_packet {
+	struct list_head list;
+	struct rr_fragment *first;
+	struct rr_fragment *last;
+	struct rr_header hdr;
+	uint32_t mid;
+	uint32_t length;
+};
+
+#define PACMARK_LAST(n) ((n) & 0x80000000)
+#define PACMARK_MID(n)  (((n) >> 16) & 0xFF)
+#define PACMARK_LEN(n)  ((n) & 0xFFFF)
+
+static inline uint32_t PACMARK(uint32_t len, uint32_t mid, uint32_t first,
+			       uint32_t last)
+{
+	return (len & 0xFFFF) |
+	  ((mid & 0xFF) << 16) |
+	  ((!!first) << 30) |
+	  ((!!last) << 31);
+}
+
+struct rr_server {
+	struct list_head list;
+
+	uint32_t pid;
+	uint32_t cid;
+	uint32_t prog;
+	uint32_t vers;
+
+	dev_t device_number;
+	struct cdev cdev;
+	struct device *device;
+	struct rpcsvr_platform_device p_device;
+	char pdev_name[32];
+};
+
+struct rr_remote_endpoint {
+	uint32_t pid;
+	uint32_t cid;
+
+	int tx_quota_cntr;
+	spinlock_t quota_lock;
+	wait_queue_head_t quota_wait;
+
+	struct list_head list;
+};
+
+struct msm_rpc_endpoint {
+	struct list_head list;
+
+	/* incomplete packets waiting for assembly */
+	struct list_head incomplete;
+
+	/* complete packets waiting to be read */
+	struct list_head read_q;
+	spinlock_t read_q_lock;
+	struct wake_lock read_q_wake_lock;
+	wait_queue_head_t wait_q;
+	unsigned flags;
+
+	/* endpoint address */
+	uint32_t pid;
+	uint32_t cid;
+
+	/* bound remote address
+	 * if not connected (dst_pid == 0xffffffff) RPC_CALL writes fail
+	 * RPC_CALLs must be to the prog/vers below or they will fail
+	 */
+	uint32_t dst_pid;
+	uint32_t dst_cid;
+	uint32_t dst_prog; /* be32 */
+	uint32_t dst_vers; /* be32 */
+
+	/* reply remote address
+	 * if reply_pid == 0xffffffff, none available
+	 * RPC_REPLY writes may only go to the pid/cid/xid of the
+	 * last RPC_CALL we received.
+	 */
+	uint32_t reply_pid;
+	uint32_t reply_cid;
+	uint32_t reply_xid; /* be32 */
+	uint32_t next_pm;   /* Pacmark sequence */
+
+	/* device node if this endpoint is accessed via userspace */
+	dev_t dev;
+};
+
+/* shared between smd_rpcrouter*.c */
+
+int __msm_rpc_read(struct msm_rpc_endpoint *ept,
+		   struct rr_fragment **frag,
+		   unsigned len, long timeout);
+
+struct msm_rpc_endpoint *msm_rpcrouter_create_local_endpoint(dev_t dev);
+int msm_rpcrouter_destroy_local_endpoint(struct msm_rpc_endpoint *ept);
+
+int msm_rpcrouter_create_server_cdev(struct rr_server *server);
+int msm_rpcrouter_create_server_pdev(struct rr_server *server);
+
+int msm_rpcrouter_init_devices(void);
+void msm_rpcrouter_exit_devices(void);
+
+extern dev_t msm_rpcrouter_devno;
+extern struct class *msm_rpcrouter_class;
+#endif
diff --git a/arch/arm/mach-msm/smd_rpcrouter_device.c b/arch/arm/mach-msm/smd_rpcrouter_device.c
new file mode 100644
index 0000000..4ddbcff
--- /dev/null
+++ b/arch/arm/mach-msm/smd_rpcrouter_device.c
@@ -0,0 +1,377 @@
+/* arch/arm/mach-msm/smd_rpcrouter_device.c
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2007-2009 QUALCOMM Incorporated.
+ * Author: San Mehat <san@xxxxxxxxxxx>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/cdev.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/err.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/platform_device.h>
+#include "../drivers/staging/dream/include/linux/msm_rpcrouter.h"
+
+#include <asm/uaccess.h>
+#include <asm/byteorder.h>
+
+#include "smd_rpcrouter.h"
+
+#define SAFETY_MEM_SIZE 65536
+
+/* Next minor # available for a remote server */
+static int next_minor = 1;
+
+struct class *msm_rpcrouter_class;
+dev_t msm_rpcrouter_devno;
+
+static struct cdev rpcrouter_cdev;
+static struct device *rpcrouter_device;
+
+static int rpcrouter_open(struct inode *inode, struct file *filp)
+{
+	int rc;
+	struct msm_rpc_endpoint *ept;
+
+	rc = nonseekable_open(inode, filp);
+	if (rc < 0)
+		return rc;
+
+	ept = msm_rpcrouter_create_local_endpoint(inode->i_rdev);
+	if (!ept)
+		return -ENOMEM;
+
+	filp->private_data = ept;
+	return 0;
+}
+
+static int rpcrouter_release(struct inode *inode, struct file *filp)
+{
+	struct msm_rpc_endpoint *ept;
+	ept = (struct msm_rpc_endpoint *) filp->private_data;
+
+	return msm_rpcrouter_destroy_local_endpoint(ept);
+}
+
+static ssize_t rpcrouter_read(struct file *filp, char __user *buf,
+			      size_t count, loff_t *ppos)
+{
+	struct msm_rpc_endpoint *ept;
+	struct rr_fragment *frag, *next;
+	int rc;
+
+	ept = (struct msm_rpc_endpoint *) filp->private_data;
+
+	rc = __msm_rpc_read(ept, &frag, count, -1);
+	if (rc < 0)
+		return rc;
+
+	count = rc;
+
+	while (frag != NULL) {		
+		if (copy_to_user(buf, frag->data, frag->length)) {
+			printk(KERN_ERR
+			       "rpcrouter: could not copy all read data to user!\n");
+			rc = -EFAULT;
+		}
+		buf += frag->length;
+		next = frag->next;
+		kfree(frag);
+		frag = next;
+	}
+
+	return rc;
+}
+
+static ssize_t rpcrouter_write(struct file *filp, const char __user *buf,
+				size_t count, loff_t *ppos)
+{
+	struct msm_rpc_endpoint	*ept;
+	int rc = 0;
+	void *k_buffer;
+
+	ept = (struct msm_rpc_endpoint *) filp->private_data;
+
+	/* A check for safety, this seems non-standard */
+	if (count > SAFETY_MEM_SIZE)
+		return -EINVAL;
+
+	k_buffer = kmalloc(count, GFP_KERNEL);
+	if (!k_buffer)
+		return -ENOMEM;
+
+	if (copy_from_user(k_buffer, buf, count)) {
+		rc = -EFAULT;
+		goto write_out_free;
+	}
+
+	rc = msm_rpc_write(ept, k_buffer, count);
+	if (rc < 0)
+		goto write_out_free;
+
+	rc = count;
+write_out_free:
+	kfree(k_buffer);
+	return rc;
+}
+
+static unsigned int rpcrouter_poll(struct file *filp,
+				   struct poll_table_struct *wait)
+{
+	struct msm_rpc_endpoint *ept;
+	unsigned mask = 0;
+	ept = (struct msm_rpc_endpoint *) filp->private_data;
+
+	/* If there's data already in the read queue, return POLLIN.
+	 * Else, wait for the requested amount of time, and check again.
+	 */
+
+	if (!list_empty(&ept->read_q))
+		mask |= POLLIN;
+
+	if (!mask) {
+		poll_wait(filp, &ept->wait_q, wait);
+		if (!list_empty(&ept->read_q))
+			mask |= POLLIN;
+	}
+
+	return mask;
+}
+
+static long rpcrouter_ioctl(struct file *filp, unsigned int cmd,
+			    unsigned long arg)
+{
+	struct msm_rpc_endpoint *ept;
+	struct rpcrouter_ioctl_server_args server_args;
+	int rc = 0;
+	uint32_t n;
+
+	ept = (struct msm_rpc_endpoint *) filp->private_data;
+	switch (cmd) {
+
+	case RPC_ROUTER_IOCTL_GET_VERSION:
+		n = RPC_ROUTER_VERSION_V1;
+		rc = put_user(n, (unsigned int *) arg);
+		break;
+
+	case RPC_ROUTER_IOCTL_GET_MTU:
+		/* the pacmark word reduces the actual payload
+		 * possible per message
+		 */
+		n = RPCROUTER_MSGSIZE_MAX - sizeof(uint32_t);
+		rc = put_user(n, (unsigned int *) arg);
+		break;
+
+	case RPC_ROUTER_IOCTL_REGISTER_SERVER:
+		rc = copy_from_user(&server_args, (void *) arg,
+				    sizeof(server_args));
+		if (rc < 0)
+			break;
+		msm_rpc_register_server(ept,
+					server_args.prog,
+					server_args.vers);
+		break;
+
+	case RPC_ROUTER_IOCTL_UNREGISTER_SERVER:
+		rc = copy_from_user(&server_args, (void *) arg,
+				    sizeof(server_args));
+		if (rc < 0)
+			break;
+
+		msm_rpc_unregister_server(ept,
+					  server_args.prog,
+					  server_args.vers);
+		break;
+
+	case RPC_ROUTER_IOCTL_GET_MINOR_VERSION:
+		n = MSM_RPC_GET_MINOR(msm_rpc_get_vers(ept));
+		rc = put_user(n, (unsigned int *)arg);
+		break;
+
+	default:
+		rc = -EINVAL;
+		break;
+	}
+
+	return rc;
+}
+
+static struct file_operations rpcrouter_server_fops = {
+	.owner	 = THIS_MODULE,
+	.open	 = rpcrouter_open,
+	.release = rpcrouter_release,
+	.read	 = rpcrouter_read,
+	.write	 = rpcrouter_write,
+	.poll    = rpcrouter_poll,
+	.unlocked_ioctl	 = rpcrouter_ioctl,
+};
+
+static struct file_operations rpcrouter_router_fops = {
+	.owner	 = THIS_MODULE,
+	.open	 = rpcrouter_open,
+	.release = rpcrouter_release,
+	.read	 = rpcrouter_read,
+	.write	 = rpcrouter_write,
+	.poll    = rpcrouter_poll,
+	.unlocked_ioctl = rpcrouter_ioctl,
+};
+
+int msm_rpcrouter_create_server_cdev(struct rr_server *server)
+{
+	int rc;
+	uint32_t dev_vers;
+
+	if (next_minor == RPCROUTER_MAX_REMOTE_SERVERS) {
+		printk(KERN_ERR
+		       "rpcrouter: Minor numbers exhausted - Increase "
+		       "RPCROUTER_MAX_REMOTE_SERVERS\n");
+		return -ENOBUFS;
+	}
+
+#if CONFIG_MSM_AMSS_VERSION >= 6350
+	/* Servers with bit 31 set are remote msm servers with hashkey version.
+	 * Servers with bit 31 not set are remote msm servers with
+	 * backwards compatible version type in which case the minor number
+	 * (lower 16 bits) is set to zero.
+	 *
+	 */
+	if ((server->vers & RPC_VERSION_MODE_MASK))
+		dev_vers = server->vers;
+	else
+		dev_vers = server->vers & RPC_VERSION_MAJOR_MASK;
+#else
+	dev_vers = server->vers;
+#endif
+
+	server->device_number =
+		MKDEV(MAJOR(msm_rpcrouter_devno), next_minor++);
+
+	server->device =
+		device_create(msm_rpcrouter_class, rpcrouter_device,
+			      server->device_number, NULL, "%.8x:%.8x",
+			      server->prog, dev_vers);
+	if (IS_ERR(server->device)) {
+		printk(KERN_ERR
+		       "rpcrouter: Unable to create device (%ld)\n",
+		       PTR_ERR(server->device));
+		return PTR_ERR(server->device);;
+	}
+
+	cdev_init(&server->cdev, &rpcrouter_server_fops);
+	server->cdev.owner = THIS_MODULE;
+
+	rc = cdev_add(&server->cdev, server->device_number, 1);
+	if (rc < 0) {
+		printk(KERN_ERR
+		       "rpcrouter: Unable to add chrdev (%d)\n", rc);
+		device_destroy(msm_rpcrouter_class, server->device_number);
+		return rc;
+	}
+	return 0;
+}
+
+/* for backward compatible version type (31st bit cleared)
+ * clearing minor number (lower 16 bits) in device name
+ * is neccessary for driver binding
+ */
+int msm_rpcrouter_create_server_pdev(struct rr_server *server)
+{
+	sprintf(server->pdev_name, "rs%.8x:%.8x",
+		server->prog,
+#if CONFIG_MSM_AMSS_VERSION >= 6350
+		(server->vers & RPC_VERSION_MODE_MASK) ? server->vers :
+		(server->vers & RPC_VERSION_MAJOR_MASK));
+#else
+		server->vers);
+#endif
+
+	server->p_device.base.id = -1;
+	server->p_device.base.name = server->pdev_name;
+
+	server->p_device.prog = server->prog;
+	server->p_device.vers = server->vers;
+
+	platform_device_register(&server->p_device.base);
+	return 0;
+}
+
+int msm_rpcrouter_init_devices(void)
+{
+	int rc;
+	int major;
+
+	/* Create the device nodes */
+	msm_rpcrouter_class = class_create(THIS_MODULE, "oncrpc");
+	if (IS_ERR(msm_rpcrouter_class)) {
+		rc = -ENOMEM;
+		printk(KERN_ERR
+		       "rpcrouter: failed to create oncrpc class\n");
+		goto fail;
+	}
+
+	rc = alloc_chrdev_region(&msm_rpcrouter_devno, 0,
+				 RPCROUTER_MAX_REMOTE_SERVERS + 1,
+				 "oncrpc");
+	if (rc < 0) {
+		printk(KERN_ERR
+		       "rpcrouter: Failed to alloc chardev region (%d)\n", rc);
+		goto fail_destroy_class;
+	}
+
+	major = MAJOR(msm_rpcrouter_devno);
+	rpcrouter_device = device_create(msm_rpcrouter_class, NULL,
+					 msm_rpcrouter_devno, NULL, "%.8x:%d",
+					 0, 0);
+	if (IS_ERR(rpcrouter_device)) {
+		rc = -ENOMEM;
+		goto fail_unregister_cdev_region;
+	}
+
+	cdev_init(&rpcrouter_cdev, &rpcrouter_router_fops);
+	rpcrouter_cdev.owner = THIS_MODULE;
+
+	rc = cdev_add(&rpcrouter_cdev, msm_rpcrouter_devno, 1);
+	if (rc < 0)
+		goto fail_destroy_device;
+
+	return 0;
+
+fail_destroy_device:
+	device_destroy(msm_rpcrouter_class, msm_rpcrouter_devno);
+fail_unregister_cdev_region:
+	unregister_chrdev_region(msm_rpcrouter_devno,
+				 RPCROUTER_MAX_REMOTE_SERVERS + 1);
+fail_destroy_class:
+	class_destroy(msm_rpcrouter_class);
+fail:
+	return rc;
+}
+
+void msm_rpcrouter_exit_devices(void)
+{
+	cdev_del(&rpcrouter_cdev);
+	device_destroy(msm_rpcrouter_class, msm_rpcrouter_devno);
+	unregister_chrdev_region(msm_rpcrouter_devno,
+				 RPCROUTER_MAX_REMOTE_SERVERS + 1);
+	class_destroy(msm_rpcrouter_class);
+}
+
diff --git a/arch/arm/mach-msm/smd_rpcrouter_servers.c b/arch/arm/mach-msm/smd_rpcrouter_servers.c
new file mode 100644
index 0000000..e7c1f1d
--- /dev/null
+++ b/arch/arm/mach-msm/smd_rpcrouter_servers.c
@@ -0,0 +1,229 @@
+/* arch/arm/mach-msm/rpc_servers.c
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Author: Iliyan Malchev <ibm@xxxxxxxxxxx>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/cdev.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/kthread.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include "../drivers/staging/dream/include/linux/wakelock.h"
+
+#include <linux/uaccess.h>
+
+#include "../drivers/staging/dream/include/mach/msm_rpcrouter.h"
+#include "../drivers/staging/dream/include/linux/msm_rpcrouter.h"
+
+
+static struct msm_rpc_endpoint *endpoint;
+
+#define FLAG_REGISTERED 0x0001
+
+static LIST_HEAD(rpc_server_list);
+static DEFINE_MUTEX(rpc_server_list_lock);
+static int rpc_servers_active;
+static struct wake_lock rpc_servers_wake_lock;
+
+static void rpc_server_register(struct msm_rpc_server *server)
+{
+	int rc;
+	rc = msm_rpc_register_server(endpoint, server->prog, server->vers);
+	if (rc < 0)
+		printk(KERN_ERR "[rpcserver] error registering %p @ %08x:%d\n",
+		       server, server->prog, server->vers);
+}
+
+static struct msm_rpc_server *rpc_server_find(uint32_t prog, uint32_t vers)
+{
+	struct msm_rpc_server *server;
+
+	mutex_lock(&rpc_server_list_lock);
+	list_for_each_entry(server, &rpc_server_list, list) {
+		if ((server->prog == prog) &&
+#if CONFIG_MSM_AMSS_VERSION >= 6350
+		    msm_rpc_is_compatible_version(server->vers, vers)) {
+#else
+		    server->vers == vers) {
+#endif
+			mutex_unlock(&rpc_server_list_lock);
+			return server;
+		}
+	}
+	mutex_unlock(&rpc_server_list_lock);
+	return NULL;
+}
+
+static void rpc_server_register_all(void)
+{
+	struct msm_rpc_server *server;
+
+	mutex_lock(&rpc_server_list_lock);
+	list_for_each_entry(server, &rpc_server_list, list) {
+		if (!(server->flags & FLAG_REGISTERED)) {
+			rpc_server_register(server);
+			server->flags |= FLAG_REGISTERED;
+		}
+	}
+	mutex_unlock(&rpc_server_list_lock);
+}
+
+int msm_rpc_create_server(struct msm_rpc_server *server)
+{
+	/* make sure we're in a sane state first */
+	server->flags = 0;
+	INIT_LIST_HEAD(&server->list);
+
+	mutex_lock(&rpc_server_list_lock);
+	list_add(&server->list, &rpc_server_list);
+	if (rpc_servers_active) {
+		rpc_server_register(server);
+		server->flags |= FLAG_REGISTERED;
+	}
+	mutex_unlock(&rpc_server_list_lock);
+
+	return 0;
+}
+
+static int rpc_send_accepted_void_reply(struct msm_rpc_endpoint *client,
+					uint32_t xid, uint32_t accept_status)
+{
+	int rc = 0;
+	uint8_t reply_buf[sizeof(struct rpc_reply_hdr)];
+	struct rpc_reply_hdr *reply = (struct rpc_reply_hdr *)reply_buf;
+
+	reply->xid = cpu_to_be32(xid);
+	reply->type = cpu_to_be32(1); /* reply */
+	reply->reply_stat = cpu_to_be32(RPCMSG_REPLYSTAT_ACCEPTED);
+
+	reply->data.acc_hdr.accept_stat = cpu_to_be32(accept_status);
+	reply->data.acc_hdr.verf_flavor = 0;
+	reply->data.acc_hdr.verf_length = 0;
+
+	rc = msm_rpc_write(client, reply_buf, sizeof(reply_buf));
+	if (rc < 0)
+		printk(KERN_ERR
+		       "%s: could not write response: %d\n",
+		       __FUNCTION__, rc);
+
+	return rc;
+}
+
+static int rpc_servers_thread(void *data)
+{
+	void *buffer;
+	struct rpc_request_hdr *req;
+	struct msm_rpc_server *server;
+	int rc;
+
+	for (;;) {
+		wake_unlock(&rpc_servers_wake_lock);
+		rc = wait_event_interruptible( endpoint->wait_q, !list_empty(&endpoint->read_q) );
+		wake_lock(&rpc_servers_wake_lock);
+		rc = msm_rpc_read(endpoint, &buffer, -1, -1);
+		if (rc < 0) {
+			printk(KERN_ERR "%s: could not read: %d\n",
+			       __FUNCTION__, rc);
+			break;
+		}
+		req = (struct rpc_request_hdr *)buffer;
+
+		req->type = be32_to_cpu(req->type);
+		req->xid = be32_to_cpu(req->xid);
+		req->rpc_vers = be32_to_cpu(req->rpc_vers);
+		req->prog = be32_to_cpu(req->prog);
+		req->vers = be32_to_cpu(req->vers);
+		req->procedure = be32_to_cpu(req->procedure);
+
+		server = rpc_server_find(req->prog, req->vers);
+
+		if (req->rpc_vers != 2)
+			continue;
+		if (req->type != 0)
+			continue;
+		if (!server) {
+			rpc_send_accepted_void_reply(
+				endpoint, req->xid,
+				RPC_ACCEPTSTAT_PROG_UNAVAIL);
+			continue;
+		}
+
+		rc = server->rpc_call(server, req, rc);
+
+		switch (rc) {
+		case 0:
+			rpc_send_accepted_void_reply(
+				endpoint, req->xid,
+				RPC_ACCEPTSTAT_SUCCESS);
+			break;
+		default:
+			rpc_send_accepted_void_reply(
+				endpoint, req->xid,
+				RPC_ACCEPTSTAT_PROG_UNAVAIL);
+			break;
+		}
+
+		kfree(buffer);
+	}
+
+	do_exit(0);
+}
+
+static int rpcservers_probe(struct platform_device *pdev)
+{
+	struct task_struct *server_thread;
+
+	endpoint = msm_rpc_open();
+	if (IS_ERR(endpoint))
+		return PTR_ERR(endpoint);
+
+	/* we're online -- register any servers installed beforehand */
+	rpc_servers_active = 1;
+	rpc_server_register_all();
+
+	/* start the kernel thread */
+	server_thread = kthread_run(rpc_servers_thread, NULL, "krpcserversd");
+	if (IS_ERR(server_thread))
+		return PTR_ERR(server_thread);
+
+	return 0;
+}
+
+static struct platform_driver rpcservers_driver = {
+	.probe	= rpcservers_probe,
+	.driver	= {
+		.name	= "oncrpc_router",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init rpc_servers_init(void)
+{
+	wake_lock_init(&rpc_servers_wake_lock, WAKE_LOCK_SUSPEND, "rpc_server");
+	return platform_driver_register(&rpcservers_driver);
+}
+
+module_init(rpc_servers_init);
+
+MODULE_DESCRIPTION("MSM RPC Servers");
+MODULE_AUTHOR("Iliyan Malchev <ibm@xxxxxxxxxxx>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/dream/include/mach/msm_rpcrouter.h b/drivers/staging/dream/include/mach/msm_rpcrouter.h
index 9724ece..5e51705 100644
--- a/drivers/staging/dream/include/mach/msm_rpcrouter.h
+++ b/drivers/staging/dream/include/mach/msm_rpcrouter.h
@@ -125,6 +125,7 @@ struct rpc_reply_hdr
 
 /* flags for msm_rpc_connect() */
 #define MSM_RPC_UNINTERRUPTIBLE 0x0001
+#define MSM_RPC_ENABLE_RECEIVE (0x10000)
 
 /* use IS_ERR() to check for failure */
 struct msm_rpc_endpoint *msm_rpc_open(void);
-- 
1.6.4.4

--
To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [Linux for Sparc]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux MIPS]     [ECOS]     [Asterisk Internet PBX]     [Linux API]

  Powered by Linux