在Linux之中,約定如果設備不屬於任何的總線,則可以把它注冊為虛擬的platform設備。
下面就簡單來學習一下一個簡單的platform設備是怎麼創建出來的。
一般注冊platform驅動的步驟是:
1,platform_device_create注冊一個設備
2,platform_driver_create注冊一個驅動。
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 = {
}
};
platform_device和platform_driver的名字必須一致
然後在chrdev_probe中完成注冊一個字符設備。一般注冊字符設備的流程如下:
1,alloc_chrdev_region分配一個未使用的設備號
2,cdev_init和cdev_add使用(1)分配到的設備號添加一個字符設備
如果到這裡就結束了,我們就需要使用分配到的設備號手動去建立/dev下面的設備節點,,,
在這裡可以使用class_create和device_create讓udev deamon自動為我們創建設備節點
3,class_create(THIS_MODULE, "chrdev");
4,device_create(chrdev_class, NULL, chrdev_devno, NULL, "chrdev");
當使用insmod把模塊加載到系統之後,www.linuxidc.com 就會在/dev下面自動創建名為"chrdev"的設備節點,模塊名字應該盡量跟注冊驅動的名字一致,不然可能會遇到不可測的問題。
源文件:chrdev.c
[cpp]
- #include <linux/module.h>
- #include <linux/init.h>
- #include <linux/platform_device.h>
- #include <linux/cdev.h>
- #include <linux/fs.h>
- ////////////////////////////////////////////////////////////////////////////////
- /*
- * Yao.GUET
- * http://blog.csdn.net/Yao_GUET
- * a simple platform character driver
- */
- ////////////////////////////////////////////////////////////////////////////////
- MODULE_LICENSE("Dual BSD/GPL");
- ////////////////////////////////////////////////////////////////////////////////
- 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;
- }
-
- static int chrdev_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg) {
- printk(KERN_ALERT "chrdev release!\n");
- return 0;
- }
-
- // Kernel interface
- static struct file_operations chrdev_fops = {
- .owner = THIS_MODULE,
- .ioctl = chrdev_ioctl,
- .open = chrdev_open,
- .release = chrdev_release,
- };
-
-
- #define CHRDEV_NAME "chrdev"
- // driver interface
- 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));
-
- cdev_init(&chrdev_cdev, &chrdev_fops);
- chrdev_cdev.owner = THIS_MODULE;
- // add a character device
- 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);