当前位置: 首页 > 嵌入式Linux > 正文

我的内核学习笔记3:我的platform驱动模板文件

前面的例子已经实现platform驱动了,可以将之前的字符设备驱动整合到这个驱动中,实际上我也做了这一步。因为没有什么技术含量,所以忽视它的存在(就不发表出来)。这篇文章是将实现好的基于platform模型的字符设备驱动简化成一个可用的模板。如要实现字符设备,可直接套用此模板。

由于注释写得比较多,不再花笔墨作多余的事了。

/** * @file foo_drv.c * @author Late Lee <latelee@163.com> * @date Tue Nov 12 22:21:19 2013 * * @brief platform模型示例 * * @note 基于platform模型的字符设备驱动示例,添加自动创建设备文件功能。此部分代码可在init时做,也可在probe中做。 */ #include <linux/module.h> #include <linux/kernel.h> /**< printk() */ #include <linux/init.h> #include <linux/platform_device.h> #include <linux/cdev.h> /**< cdev_* */ #include <linux/fs.h> #include <asm/uaccess.h> /**< copy_*_user */ #include <linux/types.h> /**< size_t */ #include <linux/errno.h> /**< error codes */ #include <linux/string.h> // 避免删掉模块时出现警告 static void foo_dev_release(struct device* dev) { // printk(KERN_NOTICE "do %s case of: Device xxx does not have a release() function, it is broken and must be fixed.\n", __func__); return; } // platform设备 static struct platform_device foo_device = { .name = "foo", .id = -1, .dev = { //.platform_data = &foo_pdata, .release = &foo_dev_release, }, }; #define DEBUG #ifdef DEBUG /* KERN_INFO */ #define debug(fmt, ...) printk(KERN_NOTICE fmt, ##__VA_ARGS__) #else #define debug(fmt, ...) #endif #define DEV_NAME "foo" // 指定设备号或自动创建设备号 //#define HAVE_MAJOR #ifdef HAVE_MAJOR #define DEVICE_MAJOR 248 #else #define DEVICE_MAJOR 0 #endif #define FOO_NR_DEVS 1 static struct cdev foo_cdev; static int foo_major = DEVICE_MAJOR; static int foo_minor = 0; static int foo_nr_devs = FOO_NR_DEVS; static dev_t foo_devno; static struct class* foo_class; static int foo_open(struct inode *inode, struct file *filp) { //debug("in %s()\n", __func__); //debug("%s() inode: 0x%08x\n", __func__, inode->i_rdev); return 0; } // close时调用此函数 static int foo_release(struct inode *inode, struct file *filp) { //debug("in %s()\n", __func__); return 0; } static ssize_t foo_read(struct file *filp, char *buf, size_t count, loff_t *f_ops) { int ret = 0; return ret; } static ssize_t foo_write(struct file *filp, const char *buf, size_t count, loff_t *f_ops) { int ret = 0; return ret; } static int foo_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) // 2.6.36及以上版本使用下列函数 // static long foo_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { } static struct file_operations foo_fops = { .owner = THIS_MODULE, .open = foo_open, .release = foo_release, .read = foo_read, .write = foo_write, .ioctl = foo_ioctl, //2.6.36及以上版本使用下列接口 // .unlocked_ioctl = foo_ioctl, }; static int foo_remove(struct platform_device *dev) { unregister_chrdev_region(foo_devno, 1); cdev_del(&foo_cdev); device_destroy(foo_class, foo_devno); class_destroy(foo_class); //printk(KERN_NOTICE "remove...\n"); return 0; } static int foo_probe(struct platform_device *dev) { int ret = 0; // 初始化,关联文件操作结构体 cdev_init(&foo_cdev, &foo_fops); foo_cdev.owner = THIS_MODULE; if (foo_major) { foo_devno = MKDEV(foo_major, foo_minor); ret = register_chrdev_region(foo_devno, foo_nr_devs, DEV_NAME); } else { ret = alloc_chrdev_region(&foo_devno, foo_minor, foo_nr_devs, DEV_NAME); /* get devno */ foo_major = MAJOR(foo_devno); /* get major */ } if (ret < 0) { dev_err(&foo_device.dev, "can't get major %d\n", foo_major); return -EINVAL; } ret = cdev_add(&foo_cdev, foo_devno, 1); if (ret < 0) { dev_err(&foo_device.dev, "cdev_add failure!\n"); return -EINVAL; } // 自动创建/dev下的节点,名称为DEV_NAME foo_class = class_create(THIS_MODULE, DEV_NAME); if (IS_ERR(foo_class)) { dev_err(&foo_device.dev, "failed to create class.\n"); return -EINVAL; } device_create(foo_class, NULL, foo_devno, NULL, DEV_NAME); dev_info(&foo_device.dev, "Register /dev/%s ok: major: %d minor: %d devno: 0x%08x\n", DEV_NAME, foo_major, foo_minor, foo_devno); return ret; } // driver static struct platform_driver foo_driver = { .probe = foo_probe, .remove = foo_remove, .driver = { .name = "foo", .owner = THIS_MODULE, }, }; static int __init foo_drv_init(void) { int ret = 0; // 先注册设备(适用于静态定义设备结构体) ret = platform_device_register(&foo_device); if (ret) { dev_err(&foo_device.dev, "platform_device_register failed!\n"); return ret; } // 再注册驱动 ret = platform_driver_register(&foo_driver); if (ret) { dev_err(&foo_device.dev, "platform_driver_register failed!\n"); return ret; } dev_info(&foo_device.dev, "Init %s OK!\n", DEV_NAME); return ret; } static void __exit foo_drv_exit(void) { // 先卸载驱动 platform_driver_unregister(&foo_driver); // 再卸载设备 platform_device_unregister(&foo_device); } module_init(foo_drv_init); module_exit(foo_drv_exit); MODULE_AUTHOR("Late Lee"); MODULE_DESCRIPTION("Simple platform driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:foo");

本文固定链接: http://www.latelee.org/embedded-linux/kernel-note-3-platform-template.html

目前暂无评论

发表评论

*

快捷键:Ctrl+Enter