本案例用于抄作业,直接复制修改就可以快速编写驱动。
当你对驱动非常熟悉的时候,不需要每次都要写,除非对驱动生疏,那么建议自己手动敲代码;写程序就应该是复制粘贴,hahaha…
device部分
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/timer.h>
#include <linux/jiffies.h>
#include <linux/platform_device.h>
#define LED_NAME "nameLED3"
#define CHRDEV_COUNT_MAX 1
struct led_platform_dev_t{
struct cdev cdev; //注册设备
struct class *class; //类
struct device *device; //设备
dev_t devid; //设备id
int major; //主设备号
int minor; //次设备号
struct device_node *nd;
int led_gpio;
struct timer_list timer;//定时器
};
struct led_platform_dev_t led_platform_dev;
void led_device_release(struct device *dev)
{
printk("led_device_release\r\n");
}
static struct resource res[2] = {
[0] = {
.start = 0x200000001,
.end = 0x200000005,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = 0x200000006,
.end = 0x200000007,
.flags = IORESOURCE_MEM,
},
};
static struct platform_device led_platform_device = {
.name = "platform_led",//-1表示无此设备
.dev = {
.release = led_device_release,
},
.num_resources = ARRAY_SIZE(res),
.resource = res,
};
static struct file_operations led_platform_fops={
.owner = THIS_MODULE,
// .open = led3_open,
// .release = led3_release,
// .write = led3_write,
// //.read = led3_read,
// .unlocked_ioctl = led3_ioctl,
};
//驱动入口
static int __init led_platform_init(void)
{
int ret = 0;
ret = platform_device_register(&led_platform_device);
printk("led platform init\r\n");
return 0;
}
static void __exit led_platform_exit(void)
{
platform_device_unregister(&led_platform_device);
printk("led platform exit!\r\n");
}
//注册驱动和卸载
module_init(led_platform_init);
module_exit(led_platform_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("China Shanghai/zhouchenliang");
driver部分
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/timer.h>
#include <linux/jiffies.h>
#include <linux/ide.h>
#include <linux/ioport.h>
#include <linux/platform_device.h>
#define LED_NAME "nameLED3"
#define CHRDEV_COUNT_MAX 1
struct led_platform_dev_t{
struct cdev cdev; //注册设备
struct class *class; //类
struct device *device; //设备
dev_t devid; //设备id
int major; //主设备号
int minor; //次设备号
struct device_node *nd;
int led_gpio;
struct timer_list timer;//定时器
};
struct led_platform_dev_t led_platform_dev;
static int led_platform_open(struct inode *inode,struct file *filp)
{
printk("led_platform_open\r\n");
filp->private_data = &led_platform_dev;//文件私有数据
return 0;
}
static int led_platform_release(struct inode *inode,struct file *filp)
{
printk("led_platform_release\r\n");
//struct led_platform_dev_t *dev = (struct led_platform_dev_t)filp->private_data;
return 0;
}
static ssize_t led_platform_write(struct file *filp,const __user char *buf,size_t count, loff_t *ppos)
{
int ret = 0;
// ret = copy_from_user(writeBuf,buf,count);
// if(ret < 0)
// {
// printk("led_write copy_from_user error\r\n");
// return -1;
// }
printk("led_platform_write\r\n");
return 0;
}
static struct file_operations led_platform_fops={
.owner = THIS_MODULE,
.open = led_platform_open,
.release = led_platform_release,
.write = led_platform_write,
// //.read = led3_read,
// .unlocked_ioctl = led3_ioctl,
};
static int led_driver_probe(struct platform_device *dev)
{
// int i=0;
// struct resource *led_source[2];
//1.从设备里面获取资源
// for(i=0;i<2;i++)
// {
// led_source[i] = platform_get_resource(dev,IORESOURCE_MEM,i);
// if(led_source[i] == NULL)
// {
// return -EINVAL;
// }
// }
//内存映射
//IMX6U_CCM_CCGR1 = ioremap(ledsource[0]->start,resource_size(led_source[0]));
int ret = -1;
/*设备号注册*/
led_platform_dev.major = 0;//直接系统申请设备号
if(led_platform_dev.major)//给定主设备号
{
led_platform_dev.devid = MKDEV(led_platform_dev.major,0);
ret = register_chrdev_region(led_platform_dev.devid,CHRDEV_COUNT_MAX,LED_NAME);
}
else//没有给定主设备号
{
ret = alloc_chrdev_region(&led_platform_dev.devid,0,CHRDEV_COUNT_MAX,LED_NAME);//自动申请设备号
led_platform_dev.major = MAJOR(led_platform_dev.devid);
led_platform_dev.minor = MINOR(led_platform_dev.devid);
}
if(ret < 0)
{
printk("register_chdev_region faild!\r\n");
return -EIO;
}
/*注册字符设备*/
led_platform_dev.cdev.owner = THIS_MODULE;
cdev_init(&led_platform_dev.cdev,&led_platform_fops);//初始化
ret = cdev_add(&led_platform_dev.cdev,led_platform_dev.devid,CHRDEV_COUNT_MAX);//添加函数
if(ret < 0)
{
printk("cdev_init faild!\r\n");
cdev_del(&led_platform_dev.cdev);
unregister_chrdev_region(led_platform_dev.devid,CHRDEV_COUNT_MAX);
return -EIO;
}
/*自动创建设备节点*/
led_platform_dev.class = class_create(led_platform_fops.owner,LED_NAME);
if(IS_ERR(led_platform_dev.class))
{
cdev_del(&led_platform_dev.cdev);
unregister_chrdev_region(led_platform_dev.devid,CHRDEV_COUNT_MAX);
return PTR_ERR(led_platform_dev.class);
}
led_platform_dev.device = device_create(led_platform_dev.class,NULL,led_platform_dev.devid,NULL,LED_NAME);
if(IS_ERR(led_platform_dev.device))
{
class_destroy(led_platform_dev.class);
cdev_del(&led_platform_dev.cdev);
unregister_chrdev_region(led_platform_dev.devid,CHRDEV_COUNT_MAX);
return PTR_ERR(led_platform_dev.device);
}
//设备树,获取设备节点
#if 0
led_platform_dev.nd = of_find_node_by_path("/gpioled");
if(led_platform_dev.nd == NULL)
{
printk("of_find_node_by_path faild!\r\n");
return -EINVAL;
}
#endif
led_platform_dev.nd = dev->dev.of_node;
// //获取LED对应的GPIO
led_platform_dev.led_gpio = of_get_named_gpio(led_platform_dev.nd,"gpios",0);
if(led_platform_dev.led_gpio < 0)
{
printk("of_get_named_gpio faild!\r\n");
return -EINVAL;
}
// //申请IO
// ret = gpio_request(led_platform_dev.led_gpio,"gpio_pin_1");
// if(ret)
// {
// printk("gpio_request faild!\r\n");
// return -EINVAL;
// }
// //使用IO 设置为输出
// ret = gpio_direction_output(led_platform_dev.led_gpio,1);
// if(ret)
// {
// printk("gpio_direction_output faild!\r\n");
// return -EINVAL;
// }
// //输出低电平 ,点亮led灯
// gpio_set_value(led_platform_dev.led_gpio,1);
printk("led_driver_probe\r\n");
return 0;
}
static int led_driver_remove(struct platform_device *dev)
{
//关闭led灯
// gpio_set_value(led_platform_dev.led_gpio,0);
/*删除字符设备*/
cdev_del(&led_platform_dev.cdev);
/*注销字符设备*/
unregister_chrdev_region(led_platform_dev.devid,CHRDEV_COUNT_MAX);
/*删除设备*/
device_destroy(led_platform_dev.class,led_platform_dev.devid);
/*删除类*/
class_destroy(led_platform_dev.class);
//释放IO
gpio_free(led_platform_dev.led_gpio);
printk("led_driver_remove\r\n");
return 0;
}
static const struct of_device_id led_of_match[] =
{
{
.compatible = "gpio-leds",
.data = NULL
},
{
/*Sentinel*/
},
};
static struct platform_driver led_platform_driver = {
.driver = {
//.name = "sunxi-init-gpio",//无设备树的时候,用于名字匹配
.of_match_table = of_match_ptr(led_of_match),//设备树匹配表
},
.probe = led_driver_probe,
.remove = led_driver_remove,
};
//驱动入口
static int __init led_platform_init(void)
{
int ret = 0;
//注册platform驱动
ret = platform_driver_register(&led_platform_driver);
if(ret){
pr_err("led_platform_init user platform_driver_register fail\n");
return -1;
}
printk("led_platform_init\r\n");
return ret;
}
static void __exit led_platform_exit(void)
{
platform_driver_unregister(&led_platform_driver);
printk("led_platform_exit\r\n");
}
//注册驱动和卸载
module_init(led_platform_init);
module_exit(led_platform_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("China Shanghai/zhouchenliang");