#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef CONFIG_PROC_FS #include #include #include #endif /* CONFIG_PROC_FS */ #define MODULE_NAME "factoryreset" #define FACTORY_RESET_GPIO GPIO(38) static const char factoryreset_driver_version[] = "v1.0"; static int factoryReset = 0; struct miscdevice *mdev = NULL; #ifdef CONFIG_PROC_FS static void *factoryreset_seq_start(struct seq_file *m, loff_t *pos) { return *pos < 1 ? (void *)1 : NULL; } static void *factoryreset_seq_next(struct seq_file *m, void *v, loff_t *pos) { ++*pos; return NULL; } static void factoryreset_seq_stop(struct seq_file *m, void *v) { } static int factoryreset_proc_show(struct seq_file *m, void *v) { seq_printf(m, "%d", factoryReset); return 0; } static const struct seq_operations factoryreset_proc_op = { .start = factoryreset_seq_start, .next = factoryreset_seq_next, .stop = factoryreset_seq_stop, .show = factoryreset_proc_show }; static int factoryreset_proc_open(struct inode *inode, struct file *file) { int ret; struct seq_file *m; ret = seq_open(file, &factoryreset_proc_op); if (ret < 0) return ret; m = file->private_data; m->private = mdev; return 0; } static ssize_t factoryreset_proc_write(struct file *file, const char __user *buf, size_t size, loff_t *ppos) { char *kbuf; int ret = 0; if (size <= 1 || size >= PAGE_SIZE) return -EINVAL; kbuf = kmalloc(size + 1, GFP_KERNEL); if (!kbuf) return -ENOMEM; if (copy_from_user(kbuf, buf, size) != 0) { kfree(kbuf); return -EFAULT; } kbuf[size] = 0; factoryReset = simple_strtoul(kbuf, 0, 0); ret = size; kfree(kbuf); return ret; } static const struct file_operations factoryreset_proc_fops = { .open = factoryreset_proc_open, .write = factoryreset_proc_write, .read = seq_read, .llseek = seq_lseek, .release = seq_release, .owner = THIS_MODULE, }; #endif /* CONFIG_PROC_FS */ static int factoryreset_open(struct inode *inode, struct file *filp) { return 0; } static int factoryreset_release(struct inode *inode, struct file *filp) { return 0; } static int factoryreset_read(struct file *filp, char *buf, size_t count, loff_t *ppos) { int ret; ret = copy_to_user(buf, (void *)&factoryReset, 1); return 1; } static int factoryreset_write(struct file *filp, const char *buf, size_t count, loff_t *ppos) { if (copy_from_user((void *)&factoryReset, buf, 1) != 0) { return -EFAULT; } return 1; } static const struct file_operations factoryreset_fops = { .open = factoryreset_open, .release = factoryreset_release, .read = factoryreset_read, .write = factoryreset_write, .owner = THIS_MODULE, }; static int factoryreset_probe(struct platform_device *pdev) { int ret = -ENODEV; struct proc_dir_entry *ent; ret = gpio_request(FACTORY_RESET_GPIO, "factory_reset"); if (ret != 0) { goto error; } ret = gpio_direction_input(FACTORY_RESET_GPIO); if (ret != 0) { goto error; } factoryReset = (gpio_get_value(FACTORY_RESET_GPIO) == 0); /* Alloc memory for the misc device */ mdev = kzalloc(sizeof(struct miscdevice), GFP_KERNEL); if (!mdev) { printk(KERN_ERR "factoryreset: Failed to allocate misc device structure\n"); ret = -ENOMEM; goto error; } mdev->name = MODULE_NAME; mdev->minor = MISC_DYNAMIC_MINOR; mdev->fops = &factoryreset_fops; ret = misc_register(mdev); if (ret < 0) { printk(KERN_ERR "factoryreset: Error registering misc driver\n"); goto error; } /* Create PROC Entry */ #ifdef CONFIG_PROC_FS { ent = proc_create(MODULE_NAME, 0, NULL, &factoryreset_proc_fops); if (!ent) { printk(KERN_ERR "factoryreset: failed to create proc entry\n"); } } #endif printk(KERN_INFO "factoryreset: probed\n"); return 0; error: printk(KERN_ERR "factoryreset: probe failed\n"); return ret; } static int factoryreset_remove(struct platform_device *pdev) { #ifdef CONFIG_PROC_FS { remove_proc_entry(MODULE_NAME, NULL); } #endif if (mdev) { misc_deregister(mdev); kfree(mdev); mdev = NULL; } gpio_free(FACTORY_RESET_GPIO); return 0; } static void factoryreset_platform_release(struct device *device) { } static struct platform_driver factoryreset_driver = { .probe = factoryreset_probe, .remove = factoryreset_remove, .driver = { .name = MODULE_NAME, .owner = THIS_MODULE, }, }; static struct platform_device factoryreset_pdevice = { .name = MODULE_NAME, .id = 1, .dev = { .release = factoryreset_platform_release, } }; static int __init factoryreset_init(void) { int err = 0; err = platform_driver_register(&factoryreset_driver); if ( err < 0 ) { printk( KERN_ERR "Failed to register factoryreset driver\n" ); return err; } err = platform_device_register(&factoryreset_pdevice); if ( err < 0 ) { platform_driver_unregister( &factoryreset_driver ); printk( KERN_ERR "Failed to register factoryreset driver\n" ); return err; } return err; } static void __exit factoryreset_cleanup(void) { platform_device_unregister(&factoryreset_pdevice); platform_driver_unregister(&factoryreset_driver); } module_init(factoryreset_init); module_exit(factoryreset_cleanup); MODULE_DESCRIPTION("Factory Reset Driver"); MODULE_AUTHOR("Lyrtech RD Inc. "); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:" MODULE_NAME);