diff --git a/lib/librte_eal/common/eal_common_dev.c b/lib/librte_eal/common/eal_common_dev.c
index eae5656..92a5a94 100644
--- a/lib/librte_eal/common/eal_common_dev.c
+++ b/lib/librte_eal/common/eal_common_dev.c
@@ -32,6 +32,7 @@
  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include <stdio.h>
 #include <string.h>
 #include <inttypes.h>
 #include <sys/queue.h>
@@ -40,6 +41,7 @@
 #include <rte_devargs.h>
 #include <rte_debug.h>
 #include <rte_devargs.h>
+#include <rte_log.h>
 
 #include "eal_private.h"
 
@@ -62,6 +64,32 @@ rte_eal_driver_unregister(struct rte_driver *driver)
 }
 
 int
+rte_eal_vdev_init(const char *name, const char *args)
+{
+	struct rte_driver *driver;
+
+	if (name == NULL)
+		return -EINVAL;
+
+	TAILQ_FOREACH(driver, &dev_driver_list, next) {
+		if (driver->type != PMD_VDEV)
+			continue;
+
+		/*
+		 * search a driver prefix in virtual device name.
+		 * For example, if the driver is pcap PMD, driver->name
+		 * will be "eth_pcap", but "name" will be "eth_pcapN".
+		 * So use strncmp to compare.
+		 */
+		if (!strncmp(driver->name, name, strlen(driver->name)))
+			return driver->init(name, args);
+	}
+
+	RTE_LOG(ERR, EAL, "no driver found for %s\n", name);
+	return -EINVAL;
+}
+
+int
 rte_eal_dev_init(void)
 {
 	struct rte_devargs *devargs;
@@ -79,22 +107,11 @@ rte_eal_dev_init(void)
 		if (devargs->type != RTE_DEVTYPE_VIRTUAL)
 			continue;
 
-		TAILQ_FOREACH(driver, &dev_driver_list, next) {
-			if (driver->type != PMD_VDEV)
-				continue;
-
-			/* search a driver prefix in virtual device name */
-			if (!strncmp(driver->name, devargs->virtual.drv_name,
-					strlen(driver->name))) {
-				driver->init(devargs->virtual.drv_name,
-					devargs->args);
-				break;
-			}
-		}
-
-		if (driver == NULL) {
-			rte_panic("no driver found for %s\n",
-				  devargs->virtual.drv_name);
+		if (rte_eal_vdev_init(devargs->virtual.drv_name,
+					devargs->args)) {
+			RTE_LOG(ERR, EAL, "failed to initialize %s device\n",
+					devargs->virtual.drv_name);
+			return -1;
 		}
 	}
 
@@ -107,3 +124,31 @@ rte_eal_dev_init(void)
 	}
 	return 0;
 }
+
+#ifdef RTE_LIBRTE_EAL_HOTPLUG
+int
+rte_eal_vdev_uninit(const char *name)
+{
+	struct rte_driver *driver;
+
+	if (name == NULL)
+		return -EINVAL;
+
+	TAILQ_FOREACH(driver, &dev_driver_list, next) {
+		if (driver->type != PMD_VDEV)
+			continue;
+
+		/*
+		 * search a driver prefix in virtual device name.
+		 * For example, if the driver is pcap PMD, driver->name
+		 * will be "eth_pcap", but "name" will be "eth_pcapN".
+		 * So use strncmp to compare.
+		 */
+		if (!strncmp(driver->name, name, strlen(driver->name)))
+			return driver->uninit(name);
+	}
+
+	RTE_LOG(ERR, EAL, "no driver found for %s\n", name);
+	return -EINVAL;
+}
+#endif /* RTE_LIBRTE_EAL_HOTPLUG */
diff --git a/lib/librte_eal/common/eal_common_devargs.c b/lib/librte_eal/common/eal_common_devargs.c
index eadd719..9b110f7 100644
--- a/lib/librte_eal/common/eal_common_devargs.c
+++ b/lib/librte_eal/common/eal_common_devargs.c
@@ -44,13 +44,46 @@
 struct rte_devargs_list devargs_list =
 	TAILQ_HEAD_INITIALIZER(devargs_list);
 
+int
+rte_eal_parse_devargs_str(const char *devargs_str,
+			char **drvname, char **drvargs)
+{
+	char *sep;
+
+	if ((devargs_str) == NULL || (drvname) == NULL || (drvargs == NULL))
+		return -1;
+
+	*drvname = strdup(devargs_str);
+	if (drvname == NULL) {
+		RTE_LOG(ERR, EAL,
+			"cannot allocate temp memory for driver name\n");
+		return -1;
+	}
+
+	/* set the first ',' to '\0' to split name and arguments */
+	sep = strchr(*drvname, ',');
+	if (sep != NULL) {
+		sep[0] = '\0';
+		*drvargs = strdup(sep + 1);
+	} else {
+		*drvargs = strdup("");
+	}
+
+	if (*drvargs == NULL) {
+		RTE_LOG(ERR, EAL,
+			"cannot allocate temp memory for driver arguments\n");
+		free(*drvname);
+		return -1;
+	}
+	return 0;
+}
+
 /* store a whitelist parameter for later parsing */
 int
 rte_eal_devargs_add(enum rte_devtype devtype, const char *devargs_str)
 {
 	struct rte_devargs *devargs = NULL;
 	char *buf = NULL;
-	char *sep;
 	int ret;
 
 	/* use malloc instead of rte_malloc as it's called early at init */
@@ -62,25 +95,8 @@ rte_eal_devargs_add(enum rte_devtype devtype, const char *devargs_str)
 	memset(devargs, 0, sizeof(*devargs));
 	devargs->type = devtype;
 
-	buf = strdup(devargs_str);
-	if (buf == NULL) {
-		RTE_LOG(ERR, EAL, "cannot allocate temp memory for devargs\n");
-		goto fail;
-	}
-
-	/* set the first ',' to '\0' to split name and arguments */
-	sep = strchr(buf, ',');
-	if (sep != NULL) {
-		sep[0] = '\0';
-		devargs->args = strdup(sep + 1);
-	} else {
-		devargs->args = strdup("");
-	}
-
-	if (devargs->args == NULL) {
-		RTE_LOG(ERR, EAL, "cannot allocate for devargs args\n");
+	if (rte_eal_parse_devargs_str(devargs_str, &buf, &devargs->args))
 		goto fail;
-	}
 
 	switch (devargs->type) {
 	case RTE_DEVTYPE_WHITELISTED_PCI:
diff --git a/lib/librte_eal/common/include/rte_dev.h b/lib/librte_eal/common/include/rte_dev.h
index f7e3a10..f601d21 100644
--- a/lib/librte_eal/common/include/rte_dev.h
+++ b/lib/librte_eal/common/include/rte_dev.h
@@ -57,6 +57,11 @@ TAILQ_HEAD(rte_driver_list, rte_driver);
 typedef int (rte_dev_init_t)(const char *name, const char *args);
 
 /**
+ * Uninitilization function called for each device driver once.
+ */
+typedef int (rte_dev_uninit_t)(const char *name);
+
+/**
  * Driver type enumeration
  */
 enum pmd_type {
@@ -72,6 +77,7 @@ struct rte_driver {
 	enum pmd_type type;		   /**< PMD Driver type */
 	const char *name;                   /**< Driver name. */
 	rte_dev_init_t *init;              /**< Device init. function. */
+	rte_dev_uninit_t *uninit;          /**< Device uninit. function. */
 };
 
 /**
@@ -97,6 +103,28 @@ void rte_eal_driver_unregister(struct rte_driver *driver);
  */
 int rte_eal_dev_init(void);
 
+/**
+ * Initialize a driver specified by name.
+ *
+ * @param name
+ *   The pointer to a driver name to be initialized.
+ * @param args
+ *   The pointer to arguments used by driver initialization.
+ * @return
+ *  0 on success, negative on error
+ */
+int rte_eal_vdev_init(const char *name, const char *args);
+
+/**
+ * Uninitalize a driver specified by name.
+ *
+ * @param name
+ *   The pointer to a driver name to be initialized.
+ * @return
+ *  0 on success, negative on error
+ */
+int rte_eal_vdev_uninit(const char *name);
+
 #define PMD_REGISTER_DRIVER(d)\
 void devinitfn_ ##d(void);\
 void __attribute__((constructor, used)) devinitfn_ ##d(void)\
diff --git a/lib/librte_eal/common/include/rte_devargs.h b/lib/librte_eal/common/include/rte_devargs.h
index 6834333..039f728 100644
--- a/lib/librte_eal/common/include/rte_devargs.h
+++ b/lib/librte_eal/common/include/rte_devargs.h
@@ -99,6 +99,34 @@ TAILQ_HEAD(rte_devargs_list, rte_devargs);
 extern struct rte_devargs_list devargs_list;
 
 /**
+ * Parse a devargs string.
+ *
+ * For PCI devices, the format of arguments string is "PCI_ADDR" or
+ * "PCI_ADDR,key=val,key2=val2,...". Examples: "08:00.1", "0000:5:00.0",
+ * "04:00.0,arg=val".
+ *
+ * For virtual devices, the format of arguments string is "DRIVER_NAME*"
+ * or "DRIVER_NAME*,key=val,key2=val2,...". Examples: "eth_ring",
+ * "eth_ring0", "eth_pmdAnything,arg=0:arg2=1".
+ *
+ * The function parses the arguments string to get driver name and driver
+ * arguments.
+ *
+ * @param devargs_str
+ *   The arguments as given by the user.
+ * @param drvname
+ *   The pointer to the string to store parsed driver name.
+ * @param drvargs
+ *   The pointer to the string to store parsed driver arguments.
+ *
+ * @return
+ *   - 0 on success
+ *   - A negative value on error
+ */
+int rte_eal_parse_devargs_str(const char *devargs_str,
+				char **drvname, char **drvargs);
+
+/**
  * Add a device to the user device list
  *
  * For PCI devices, the format of arguments string is "PCI_ADDR" or
diff --git a/lib/librte_eal/linuxapp/eal/rte_eal_version.map b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
index 5478492..214643d 100644
--- a/lib/librte_eal/linuxapp/eal/rte_eal_version.map
+++ b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
@@ -38,6 +38,7 @@ DPDK_2.0 {
 	rte_eal_lcore_role;
 	rte_eal_mp_remote_launch;
 	rte_eal_mp_wait_lcore;
+	rte_eal_parse_devargs_str;
 	rte_eal_pci_close_one;
 	rte_eal_pci_dump;
 	rte_eal_pci_probe;
@@ -50,6 +51,8 @@ DPDK_2.0 {
 	rte_eal_tailq_lookup_by_idx;
 	rte_eal_tailq_reserve;
 	rte_eal_tailq_reserve_by_idx;
+	rte_eal_vdev_init;
+	rte_eal_vdev_uninit;
 	rte_eal_wait_lcore;
 	rte_exit;
 	rte_get_hpet_cycles;
