summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra
diff options
context:
space:
mode:
authorGary King <gking@nvidia.com>2010-02-26 17:12:39 -0800
committerGerrit Code Review <gerrit2@git-master-01.nvidia.com>2010-02-26 17:12:39 -0800
commitee0c05638d678d01049446b663d06e3c9273767e (patch)
tree33f4aa2d1151a7f186ec2f5caaf55eed02fcafe3 /arch/arm/mach-tegra
parentefc62dffb4c3f76d839174d5b90bed7c4f65c7b4 (diff)
parent92891e2ab3df0eafc3f064c410d8ac47187ccb07 (diff)
Merge "tegra NVEC: Bus driver architecture for nvec drivers" into android-tegra-2.6.29
Diffstat (limited to 'arch/arm/mach-tegra')
-rw-r--r--arch/arm/mach-tegra/include/nvec_device.h81
-rw-r--r--arch/arm/mach-tegra/nvec_user.c648
2 files changed, 458 insertions, 271 deletions
diff --git a/arch/arm/mach-tegra/include/nvec_device.h b/arch/arm/mach-tegra/include/nvec_device.h
new file mode 100644
index 000000000000..71c1f761906b
--- /dev/null
+++ b/arch/arm/mach-tegra/include/nvec_device.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2010 NVIDIA Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of the NVIDIA Corporation nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef INCLUDED_NVEC_DEVICE_H
+#define INCLUDED_NVEC_DEVICE_H
+
+
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+
+#define nvec_get_drvdata(f) dev_get_drvdata(&(f)->dev)
+#define nvec_set_drvdata(f,d) dev_set_drvdata(&(f)->dev, d)
+
+struct nvec_driver;
+
+struct nvec_device {
+ char *name;
+ struct device *parent;
+ struct device dev;
+ struct bus_type *bus; /* type of bus device is on */
+ struct nvec_driver *driver; /* which driver has allocated this
+ device */
+};
+
+extern int nvec_register_device(struct nvec_device *pdev);
+extern void nvec_unregister_device(struct nvec_device *pdev);
+
+/*
+ * NVEC function device driver
+ */
+struct nvec_driver {
+ char *name;
+ struct device_driver driver;
+ struct device dev;
+
+ int (*probe)(struct nvec_device *);
+ void (*remove)(struct nvec_device *);
+
+ int (*suspend)(struct nvec_device *dev, pm_message_t state);
+ int (*resume)(struct nvec_device *dev);
+};
+
+extern int nvec_register_driver(struct nvec_driver *);
+extern void nvec_unregister_driver(struct nvec_driver *);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif // INCLUDED_NVEC_DEVICE_H
diff --git a/arch/arm/mach-tegra/nvec_user.c b/arch/arm/mach-tegra/nvec_user.c
index b11c00e0c0c4..8ee0240b219a 100644
--- a/arch/arm/mach-tegra/nvec_user.c
+++ b/arch/arm/mach-tegra/nvec_user.c
@@ -1,271 +1,377 @@
-/*
- * arch/arm/mach-tegra/nvec_user.c
- *
- * User-land access to NvEc embedded controller features
- *
- * Copyright (c) 2008-2009, NVIDIA Corporation.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#include <linux/module.h>
-#include <linux/proc_fs.h>
-#include <linux/platform_device.h>
-#include <linux/miscdevice.h>
-#include "linux/nvos_ioctl.h"
-#include "nvec.h"
-#include "linux/nvec_ioctls.h"
-#include "nvreftrack.h"
-#include "nvassert.h"
-
-static NvRtHandle s_RtHandle = NULL;
-
-NvError NvECPackage_Dispatch(void *InBuffer, NvU32 InSize, void *OutBuffer,
- NvU32 OutSize, NvDispatchCtx* Ctx);
-
-static int nvec_open(struct inode *inode, struct file *file);
-static int nvec_close(struct inode *inode, struct file *file);
-static long nvec_unlocked_ioctl(struct file *file,
- unsigned int cmd, unsigned long arg);
-
-int nvec_open(struct inode *inode, struct file *file)
-{
- NvRtClientHandle Client;
-
- if (NvRtRegisterClient(s_RtHandle, &Client) != NvSuccess)
- return -ENOMEM;
-
- file->private_data = (void*)Client;
- return 0;
-}
-
-int nvec_close(struct inode *inode, struct file *file)
-{
- NvRtClientHandle client = (NvRtClientHandle)file->private_data;
-
- if (NvRtUnregisterClient(s_RtHandle, client)) {
- NvDispatchCtx dctx;
-
- dctx.Rt = s_RtHandle;
- dctx.Client = client;
- dctx.PackageIdx = 0;
-
- // TODO: Enable this code for freeing up leaked handles
- #if 0
- for (;;)
- {
- void* ptr = NvRtFreeObjRef(&dctx,
- NvRtObjType_NvEc_NvEcHandle, NULL);
- if (!ptr) break;
- NVRT_LEAK("NvEc", "NvEcHandle", ptr);
- NvEcClose(ptr);
- }
- #endif
-
- NvRtUnregisterClient(s_RtHandle, client);
- }
- return 0;
-}
-
-long nvec_unlocked_ioctl(struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- NvError err;
- NvOsIoctlParams p;
- NvU32 size;
- NvU32 small_buf[8];
- void *ptr = 0;
- long e;
- NvBool bAlloc = NV_FALSE;
-
- switch( cmd ) {
- case NvECKernelIoctls_Generic:
- {
- NvDispatchCtx dctx;
-
- dctx.Rt = s_RtHandle;
- dctx.Client = (NvRtClientHandle)file->private_data;
- dctx.PackageIdx = 0;
-
- err = NvOsCopyIn(&p, (void *)arg, sizeof(p));
- if (err != NvSuccess) {
- printk("NvECKernelIoctls_Generic: copy in failed\n");
- goto fail;
- }
-
- size = p.InBufferSize + p.InOutBufferSize + p.OutBufferSize;
- if (size <= sizeof(small_buf)) {
- ptr = small_buf;
- } else {
- ptr = NvOsAlloc(size);
- if (!ptr) {
- printk("NvECKernelIoctls_Generic: alloc err\n");
- goto fail;
- }
-
- bAlloc = NV_TRUE;
- }
-
- err = NvOsCopyIn(ptr, p.pBuffer, p.InBufferSize +
- p.InOutBufferSize);
- if (err != NvSuccess) {
- printk("NvECKernelIoctls_Generic: copy in failure\n");
- goto fail;
- }
-
- err = NvECPackage_Dispatch(ptr,
- p.InBufferSize + p.InOutBufferSize,
- ((NvU8 *)ptr) + p.InBufferSize, p.InOutBufferSize +
- p.OutBufferSize, &dctx);
- if (err != NvSuccess) {
- printk("NvECKernelIoctls_Generic: dispatch failure\n");
- goto fail;
- }
-
- if (p.InOutBufferSize || p.OutBufferSize) {
- err = NvOsCopyOut(
- ((NvU8 *)((NvOsIoctlParams *)arg)->pBuffer) +
- p.InBufferSize,
- ((NvU8 *)ptr) + p.InBufferSize,
- p.InOutBufferSize + p.OutBufferSize);
- if (err != NvSuccess) {
- printk("NvECKernelIoctls_Generic: copyout err\n");
- goto fail;
- }
- }
-
- break;
- }
- default:
- printk("unknown ioctl code\n");
- goto fail;
- }
- e = 0;
- goto clean;
-
-fail:
- e = -EINVAL;
-
-clean:
- if (bAlloc)
- NvOsFree(ptr);
-
- return e;
-}
-
-#define DEVICE_NAME "nvec"
-
-static const struct file_operations nvec_fops =
-{
- .owner = THIS_MODULE,
- .open = nvec_open,
- .release = nvec_close,
- .unlocked_ioctl = nvec_unlocked_ioctl,
-};
-
-static struct miscdevice nvec_dev =
-{
- .name = DEVICE_NAME,
- .fops = &nvec_fops,
- .minor = MISC_DYNAMIC_MINOR,
-};
-
-static NvEcHandle s_NvEcHandle = NULL;
-
-static int __init nvec_probe(struct platform_device *pdev)
-{
- int e = 0;
- NvError status;
- NvU32 NumTypes = 1; // TODO: must have NvRtObjType_NvEc_Num instead;
-
- NV_ASSERT(s_RtHandle == NULL);
-
- if (NvRtCreate(1, &NumTypes, &s_RtHandle) != NvSuccess) {
- printk("nvec NvRtCreate returned error\n");
- return -ENOMEM;
- }
-
- status = NvEcOpen(&s_NvEcHandle, 0);
- if (status != NvError_Success) {
- printk("nvec NvEcOpen returned 0x%x\n", status);
- return -EINVAL;
- }
-
- e = misc_register(&nvec_dev);
- if (e < 0) {
- if (s_RtHandle) {
- NvRtDestroy(s_RtHandle);
- s_RtHandle = NULL;
- }
- printk("nvec failed to open\n");
- }
- return e;
-}
-
-static int nvec_remove(struct platform_device *pdev)
-{
- NvEcClose(s_NvEcHandle);
- misc_deregister( &nvec_dev );
- NvRtDestroy(s_RtHandle);
- s_RtHandle = NULL;
- return 0;
-}
-
-static int nvec_suspend(struct platform_device *pdev, pm_message_t state)
-{
- NvError e = NvEcPowerSuspend(NvEcPowerState_Suspend);
- if (e != NvSuccess)
- return -1;
-
- return 0;
-}
-
-static int nvec_resume(struct platform_device *pdev)
-{
- NvError e = NvEcPowerResume();
- if (e != NvSuccess)
- return -1;
-
- return 0;
-}
-
-static void nvec_shutdown(struct platform_device *pdev)
-{
- NvEcPowerSuspend(NvEcPowerState_PowerDown);
-}
-
-static struct platform_driver tegra_nvec_driver = {
- .probe = nvec_probe,
- .remove = nvec_remove,
- .suspend = nvec_suspend,
- .resume = nvec_resume,
- .shutdown = nvec_shutdown,
- .driver = {
- .name = "nvec",
- },
-};
-
-static int __devinit nvec_init( void )
-{
- return platform_driver_register(&tegra_nvec_driver);
-}
-
-static void __exit nvec_deinit( void )
-{
- return platform_driver_unregister(&tegra_nvec_driver);
-}
-
-module_init(nvec_init);
-module_exit(nvec_deinit);
+/*
+ * arch/arm/mach-tegra/nvec_user.c
+ *
+ * User-land access to NvEc embedded controller features
+ *
+ * Copyright (c) 2008-2009, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+#include <linux/platform_device.h>
+#include <linux/miscdevice.h>
+#include "linux/nvos_ioctl.h"
+#include "nvec.h"
+#include "linux/nvec_ioctls.h"
+#include "nvreftrack.h"
+#include "nvassert.h"
+#include "nvec_device.h"
+
+static NvRtHandle s_RtHandle = NULL;
+int device_count = 0;
+
+#define dev_to_nvec_driver(d) container_of(d, struct nvec_driver, driver)
+#define to_nvec_device(x) container_of((x), struct nvec_device, dev)
+
+NvError NvECPackage_Dispatch(void *InBuffer, NvU32 InSize, void *OutBuffer,
+ NvU32 OutSize, NvDispatchCtx* Ctx);
+
+static int nvec_open(struct inode *inode, struct file *file);
+static int nvec_close(struct inode *inode, struct file *file);
+static long nvec_unlocked_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg);
+
+int nvec_open(struct inode *inode, struct file *file)
+{
+ NvRtClientHandle Client;
+
+ if (NvRtRegisterClient(s_RtHandle, &Client) != NvSuccess)
+ return -ENOMEM;
+
+ file->private_data = (void*)Client;
+ return 0;
+}
+
+int nvec_close(struct inode *inode, struct file *file)
+{
+ NvRtClientHandle client = (NvRtClientHandle)file->private_data;
+
+ if (NvRtUnregisterClient(s_RtHandle, client)) {
+ NvDispatchCtx dctx;
+
+ dctx.Rt = s_RtHandle;
+ dctx.Client = client;
+ dctx.PackageIdx = 0;
+
+ // TODO: Enable this code for freeing up leaked handles
+ #if 0
+ for (;;)
+ {
+ void* ptr = NvRtFreeObjRef(&dctx,
+ NvRtObjType_NvEc_NvEcHandle, NULL);
+ if (!ptr) break;
+ NVRT_LEAK("NvEc", "NvEcHandle", ptr);
+ NvEcClose(ptr);
+ }
+ #endif
+
+ NvRtUnregisterClient(s_RtHandle, client);
+ }
+ return 0;
+}
+
+long nvec_unlocked_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ NvError err;
+ NvOsIoctlParams p;
+ NvU32 size;
+ NvU32 small_buf[8];
+ void *ptr = 0;
+ long e;
+ NvBool bAlloc = NV_FALSE;
+
+ switch( cmd ) {
+ case NvECKernelIoctls_Generic:
+ {
+ NvDispatchCtx dctx;
+
+ dctx.Rt = s_RtHandle;
+ dctx.Client = (NvRtClientHandle)file->private_data;
+ dctx.PackageIdx = 0;
+
+ err = NvOsCopyIn(&p, (void *)arg, sizeof(p));
+ if (err != NvSuccess) {
+ printk("NvECKernelIoctls_Generic: copy in failed\n");
+ goto fail;
+ }
+
+ size = p.InBufferSize + p.InOutBufferSize + p.OutBufferSize;
+ if (size <= sizeof(small_buf)) {
+ ptr = small_buf;
+ } else {
+ ptr = NvOsAlloc(size);
+ if (!ptr) {
+ printk("NvECKernelIoctls_Generic: alloc err\n");
+ goto fail;
+ }
+
+ bAlloc = NV_TRUE;
+ }
+
+ err = NvOsCopyIn(ptr, p.pBuffer, p.InBufferSize +
+ p.InOutBufferSize);
+ if (err != NvSuccess) {
+ printk("NvECKernelIoctls_Generic: copy in failure\n");
+ goto fail;
+ }
+
+ err = NvECPackage_Dispatch(ptr,
+ p.InBufferSize + p.InOutBufferSize,
+ ((NvU8 *)ptr) + p.InBufferSize, p.InOutBufferSize +
+ p.OutBufferSize, &dctx);
+ if (err != NvSuccess) {
+ printk("NvECKernelIoctls_Generic: dispatch failure\n");
+ goto fail;
+ }
+
+ if (p.InOutBufferSize || p.OutBufferSize) {
+ err = NvOsCopyOut(
+ ((NvU8 *)((NvOsIoctlParams *)arg)->pBuffer) +
+ p.InBufferSize,
+ ((NvU8 *)ptr) + p.InBufferSize,
+ p.InOutBufferSize + p.OutBufferSize);
+ if (err != NvSuccess) {
+ printk("NvECKernelIoctls_Generic: copyout err\n");
+ goto fail;
+ }
+ }
+
+ break;
+ }
+ default:
+ printk("unknown ioctl code\n");
+ goto fail;
+ }
+ e = 0;
+ goto clean;
+
+fail:
+ e = -EINVAL;
+
+clean:
+ if (bAlloc)
+ NvOsFree(ptr);
+
+ return e;
+}
+
+#define DEVICE_NAME "nvec"
+
+static const struct file_operations nvec_fops =
+{
+ .owner = THIS_MODULE,
+ .open = nvec_open,
+ .release = nvec_close,
+ .unlocked_ioctl = nvec_unlocked_ioctl,
+};
+
+static struct miscdevice nvec_dev =
+{
+ .name = DEVICE_NAME,
+ .fops = &nvec_fops,
+ .minor = MISC_DYNAMIC_MINOR,
+};
+
+static NvEcHandle s_NvEcHandle = NULL;
+
+static int nvec_bus_probe(struct device *_dev)
+{
+ struct nvec_driver *drv = dev_to_nvec_driver(_dev->driver);
+ struct nvec_device *dev = to_nvec_device(_dev);
+
+ return drv->probe(dev);
+}
+
+static int nvec_bus_remove(struct device *_dev)
+{
+ return 0;
+}
+
+int nvec_bus_match(struct device *_dev, struct device_driver *drv)
+{
+ struct nvec_device *dev = to_nvec_device(_dev);
+
+ return (strcmp(dev->name, drv->name) == 0);
+}
+
+static int nvec_bus_suspend(struct device *_dev, pm_message_t state)
+{
+ struct nvec_driver *drv = dev_to_nvec_driver(_dev->driver);
+ struct nvec_device *dev = to_nvec_device(_dev);
+ NvError e = NvError_Success;
+
+ device_count--;
+ drv->suspend(dev, state);
+
+ if (!device_count)
+ {
+ e = NvEcPowerSuspend(NvEcPowerState_Suspend);
+ if (e != NvSuccess) {
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static int nvec_bus_resume(struct device *_dev)
+{
+ struct nvec_driver *drv = dev_to_nvec_driver(_dev->driver);
+ struct nvec_device *dev = to_nvec_device(_dev);
+
+ if (!device_count)
+ {
+ NvError e = NvEcPowerResume();
+ if (e != NvSuccess) {
+ return -1;
+ }
+ }
+
+ device_count++;
+ drv->resume(dev);
+ return 0;
+}
+
+static void nvec_bus_shutdown(struct device *pdev)
+{
+ NvEcPowerSuspend(NvEcPowerState_PowerDown);
+}
+
+static struct bus_type nvec_bus_type = {
+ .name = DEVICE_NAME,
+ .match = nvec_bus_match,
+ .probe = nvec_bus_probe,
+ .remove = nvec_bus_remove,
+ .suspend = nvec_bus_suspend,
+ .resume = nvec_bus_resume,
+ .shutdown = nvec_bus_shutdown,
+};
+
+static struct device nvec_bus_dev = {
+ .init_name = DEVICE_NAME
+};
+
+int nvec_register_driver(struct nvec_driver *drv)
+{
+ drv->driver.name = drv->name;
+ drv->driver.bus = &nvec_bus_type;
+ return driver_register(&drv->driver);
+}
+EXPORT_SYMBOL_GPL(nvec_register_driver);
+
+void nvec_unregister_driver(struct nvec_driver *drv)
+{
+ drv->driver.bus = &nvec_bus_type;
+ driver_unregister(&drv->driver);
+}
+EXPORT_SYMBOL_GPL(nvec_unregister_driver);
+
+int nvec_register_device(struct nvec_device *pdev)
+{
+ if (!pdev)
+ return -EINVAL;
+
+ if (!pdev->dev.parent)
+ pdev->dev.parent = &nvec_bus_dev;
+
+ pdev->dev.bus = &nvec_bus_type;
+
+ dev_set_name(&pdev->dev, pdev->name);
+
+ device_count++;
+ return device_register(&pdev->dev);
+}
+EXPORT_SYMBOL_GPL(nvec_register_device);
+
+void nvec_unregister_device(struct nvec_device *pdev)
+{
+ if (pdev) {
+ device_count--;
+ device_unregister(&pdev->dev);
+ }
+}
+EXPORT_SYMBOL_GPL(nvec_unregister_device);
+
+static int __init nvec_init(void)
+{
+ int err = 0;
+ NvError status = NvSuccess;
+ NvU32 NumTypes = 1; // TODO: must have NvRtObjType_NvEc_Num instead;
+
+ err = device_register(&nvec_bus_dev);
+ if (err)
+ return err;
+
+ err = bus_register(&nvec_bus_type);
+ if (err){
+ device_unregister(&nvec_bus_dev);
+ return err;
+ }
+
+
+ NV_ASSERT(s_RtHandle == NULL);
+
+ if (NvRtCreate(1, &NumTypes, &s_RtHandle) != NvSuccess) {
+ printk("nvec NvRtCreate returned error\n");
+ bus_unregister(&nvec_bus_type);
+ device_unregister(&nvec_bus_dev);
+ return -ENOMEM;
+ }
+
+ status = NvEcOpen(&s_NvEcHandle, 0);
+ if (status != NvError_Success) {
+ printk("nvec NvEcOpen returned 0x%x\n", status);
+ NvRtDestroy(s_RtHandle);
+ s_RtHandle = NULL;
+ bus_unregister(&nvec_bus_type);
+ device_unregister(&nvec_bus_dev);
+ return -EINVAL;
+ }
+
+ err = misc_register(&nvec_dev);
+ if (err < 0) {
+ if (s_RtHandle) {
+ NvEcClose(s_NvEcHandle);
+ s_NvEcHandle = NULL;
+ NvRtDestroy(s_RtHandle);
+ s_RtHandle = NULL;
+ bus_unregister(&nvec_bus_type);
+ device_unregister(&nvec_bus_dev);
+ }
+ printk("nvec failed to open\n");
+ }
+
+ return err;
+}
+
+static void __exit nvec_exit(void)
+{
+ NvEcClose(s_NvEcHandle);
+ s_NvEcHandle = NULL;
+ misc_deregister( &nvec_dev );
+ NvRtDestroy(s_RtHandle);
+ s_RtHandle = NULL;
+
+ bus_unregister(&nvec_bus_type);
+ device_unregister(&nvec_bus_dev);
+}
+
+module_init(nvec_init);
+module_exit(nvec_exit);
+
+MODULE_LICENSE("GPL"); \ No newline at end of file