/*
* Yao.GUET
* http://blog.csdn.net/Yao_GUET
* Linux下面一個簡單的虛擬platform驅動
*/
在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把模組載入到系統之後,就會在/dev下面自動建立名為"chrdev"的裝置節點,模組名字應該盡量跟註冊驅動的名字一致,不然可能會遇到不可測的問題。
源檔案:chrdev.c
#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 interfacestatic struct file_operations chrdev_fops = { .owner = THIS_MODULE, .ioctl = chrdev_ioctl, .open = chrdev_open, .release = chrdev_release,};#define CHRDEV_NAME "chrdev"// driver interfacestatic 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 normallystatic 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);
Makefile:
### Makefileobj-m := chrdev.oKERNEL_DIR := /lib/modules/$(shell uname -r)/buildPWD := $(shell pwd)default:$(MAKE) -C $(KERNEL_DIR) M=$(PWD) modulesclean:$(MAKE) -C $(KERNEL_DIR) M=$(PWD) clean