platform_device:
#include <linux/kernel.h> #include <linux/init.h> #include <linux/types.h> #include <linux/spinlock.h> #include <linux/blkdev.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/errno.h> #include <linux/mm.h> #include <linux/cdev.h> #include <linux/platform_device.h> static int chrdev_open(struct inode *inode, struct file *file) { printk(KERN_ALERT "chrdev open!\n"); return 0; } static int chrdev_release(struct inode *inode, struct file *file) { printk(KERN_ALERT "chrdev release!\n"); return 0; } int temp_data = 0; static int chrdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { switch(cmd) { case 0x100: if(copy_from_user(&temp_data, (int *)arg, sizeof(int))) return -EFAULT; break; case 0x101: if(copy_to_user( (int *)arg, &temp_data, sizeof(int))) return -EFAULT; break; } printk(KERN_ALERT "chrdev_ioctl: 0x%x temp_data=%d\n", cmd, temp_data); return 0; } // Kernel interface static struct file_operations chrdev_fops = { .owner = THIS_MODULE, .unlocked_ioctl = chrdev_ioctl, .open = chrdev_open, .release = chrdev_release, }; #define CHRDEV_NAME "miscdriver" static struct class *chrdev_class = NULL; static struct device *chrdev_device = NULL; static dev_t chrdev_devno; static struct cdev chrdev_cdev; static int chrdev_probe(struct platform_device *dev) { int ret = 0, err = 0; printk(KERN_ALERT "chrdev probe!\n"); // alloc character device number ret = alloc_chrdev_region(&chrdev_devno, 0, 1, CHRDEV_NAME); if (ret) { printk(KERN_ALERT " alloc_chrdev_region failed!\n"); goto PROBE_ERR; } printk(KERN_ALERT " major:%d minor:%d\n", MAJOR(chrdev_devno), MINOR(chrdev_devno)); // add a character device cdev_init(&chrdev_cdev, &chrdev_fops); chrdev_cdev.owner = THIS_MODULE; err = cdev_add(&chrdev_cdev, chrdev_devno, 1); if (err) { printk(KERN_ALERT " cdev_add failed!\n"); goto PROBE_ERR; } // create the device class chrdev_class = class_create(THIS_MODULE, CHRDEV_NAME); if (IS_ERR(chrdev_class)) { printk(KERN_ALERT " class_create failed!\n"); goto PROBE_ERR; } // create the device node in /dev chrdev_device = device_create(chrdev_class, NULL, chrdev_devno, NULL, CHRDEV_NAME); if (NULL == chrdev_device) { printk(KERN_ALERT " device_create failed!\n"); goto PROBE_ERR; } printk(KERN_ALERT " chrdev probe ok!\n"); return 0; PROBE_ERR: if (err) cdev_del(&chrdev_cdev); if (ret) unregister_chrdev_region(chrdev_devno, 1); return -1; } static int chrdev_remove (struct platform_device *dev) { printk(KERN_ALERT " chrdev remove!\n"); cdev_del(&chrdev_cdev); unregister_chrdev_region(chrdev_devno, 1); device_destroy(chrdev_class, chrdev_devno); class_destroy(chrdev_class); return 0; } // platform_device and platform_driver must has a same name! // or it will not work normally static struct platform_driver chrdev_platform_driver = { .probe = chrdev_probe, .remove = chrdev_remove, .driver = { .name = CHRDEV_NAME, .owner = THIS_MODULE, }, }; static struct platform_device chrdev_platform_device = { .name = CHRDEV_NAME, .id = 0, .dev = { } }; static __init int chrdev_init(void) { int ret = 0; printk(KERN_ALERT "chrdev init!\n"); ret = platform_device_register(&chrdev_platform_device); if (ret) { printk(KERN_ALERT " platform_device_register failed!\n"); return ret; } ret = platform_driver_register(&chrdev_platform_driver); if (ret) { printk(KERN_ALERT " platform_driver_register failed!\n"); return ret; } printk(KERN_ALERT " chrdev_init ok!\n"); return ret; } static __exit void chrdev_exit(void) { printk(KERN_ALERT "chrdev exit!\n"); platform_driver_unregister(&chrdev_platform_driver); } module_init(chrdev_init); module_exit(chrdev_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Decly");