字符设备实践:
chartest.c:
#include <linux/module.h> //模块的相关头文件
#include <linux/init.h> //初始化的相关头文件
#include <linux/fs.h> //文件操作集合
#include <linux/uaccess.h> //copy_to_user的头文件
#include <linux/cdev.h> //cdev结构体以及cdev_init等
#include <linux/kdev_t.h> //MKDEV所需的头文件
#include <linux/device.h> //class_create,device_create
#include <linux/io.h> //寄存器
dev_t char_dev;
struct cdev muqing_cdev; //cdev结构体用来表示字符设备
struct class *muqing_class; //class类
struct device *muqing_device; //device设备结构体
#define NUMCHAR 1
#define GPIO3_DR 0x209C000 //LED2 Io物理地址
/*********************** echo none > /sys/class/leds/sys-led/trigger”改变LED2的触发方式 ***************************/
unsigned int* gpio3_3; //虚拟地址
#define SIZEBEY 4 //寄存器字节
/*读取*/
ssize_t chartext_read (struct file *file, char __user *ubuf, size_t size, loff_t *loff_t){
char kbuf[64] = "Hello Word";
printk("Hello chartext_read\n");
if( copy_to_user(ubuf,kbuf,strlen(kbuf)) != 0 ){
printk("hd_fops_release error\n");
return 0;
}
return 0;
}
/*写*/
ssize_t chartext_write (struct file *file, const char __user *ubuf, size_t size, loff_t *loff_t){
char kbuf[64] = {0};
printk("Hello chartext_write\n");
if( copy_from_user(kbuf,ubuf,size) != 0 ){
printk("chartext_write error\n");
return 0;
}
if( kbuf[0] == '1' ){
*gpio3_3 |= (1 << 3);
}else if( kbuf[0] == '0' ){
*gpio3_3 &= ~(1 << 3);
}
printk("chartext_write urse is %s\n",kbuf);
return 0;
}
/*打开*/
int chartext_open (struct inode *inode, struct file *file){
printk("Hello chartext_open\n");
return 0;
}
/*关闭*/
int chartext_release (struct inode *inode, struct file *file){
printk("Hello chartext_release\n");
return 0;
}
struct file_operations chartext_fops={ //文件操作集合
.owner = THIS_MODULE,
.read = chartext_read,
.write = chartext_write,
.open = chartext_open,
.release = chartext_release,
};
static int chartext_init(void){
int ret;
/*静态注册设备号
char_dev = MKDEV(100, 30);
ret = register_chrdev_region(char_dev,NUMCHAR,"muqingdev");
if( ret != 0 ){
printk("chartext_init: register_chrdev_region error!!\n");
return ret;
}*/
/*动态注册设备号*/
ret = alloc_chrdev_region(&char_dev,0,NUMCHAR,"alloclcddevice");
if( ret != 0 ){
printk("alloc_chrdev_region: register_chrdev_region error!!\n");
return ret;
}
printk("alloc_chrdev_region: register_chrdev_region ok!!\n");
printk("MAJOR %d\n\n",MAJOR(char_dev));
printk("MINOR %d\n\n",MINOR(char_dev));
/*内存映射*/
gpio3_3 = ioremap(GPIO3_DR, SIZEBEY);
if( gpio3_3 == NULL ){
printk("ioremap error3!!\n");
return 0;
}
printk("ioremap ok3!!\n");
/*初始化cdev*/
muqing_cdev.owner = THIS_MODULE;
cdev_init(&muqing_cdev,&chartext_fops);
/*向内核注册设备*/
cdev_add(&muqing_cdev,char_dev,NUMCHAR);
/*创建类 ,在、sys/class下*/
muqing_class = class_create(THIS_MODULE, "lcdclass");
/*自动创建设备节点, /dev下*/
muqing_device = device_create(muqing_class,NULL,char_dev,NULL,"lcddevice");
printk("chartext_init\n");
return 0;
}
static void chartext_exit(void){//杂项设备驱动
iounmap(gpio3_3);
unregister_chrdev_region(char_dev,NUMCHAR); //注销设备号
cdev_del(&muqing_cdev); //删除设备
device_destroy(muqing_class,char_dev); //注销设备
class_destroy(muqing_class); //删除类
printk("Bye!!!\n");
}
module_init(chartext_init); //驱动模块入口函数
module_exit(chartext_exit); //驱动模块出口函数
MODULE_LICENSE("GPL"); //内核模块声明
app.c:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc,char *argv[]){
int fd;
int i;
char buf[64] = {0};
/*char writebuf[64] = "1";
char writebuf1[64] = "0";*/
fd = open("/dev/lcddevice",O_RDWR);//打开设备节点
if( fd < 0 ){
perror("open error\n");
return fd;
}
read(fd,buf,sizeof(buf));
printf("read buf id %s\n",buf);
write(fd,argv[1],1);
close(fd);
return 0;
}
timer定时器实践:
timerlist.c:
#include <linux/module.h> //模块的相关头文件
#include <linux/init.h> //初始化的相关头文件
#include <linux/timer.h> //定时器
#include <linux/fs.h> //文件操作集合
#include <linux/uaccess.h> //copy_to_user的头文件
#include <linux/kdev_t.h> //MKDEV所需要的头文件
#include <linux/cdev.h> //cdev结构体以及cdev-init
#include <linux/device.h> //class_create,device_create
#include <linux/io.h> //寄存器
dev_t char_dev;
struct cdev muqing_cdev; //cdev结构体用来表示字符设备
struct class *muqing_class; //class类
struct device *muqing_device; //device设备结构体
#define NUMCHAR 2
struct timer_list Mytimer;
unsigned long i = 1;
#define GPIO5_DR 0x20AC000 //蜂鸣器Io物
unsigned int* gpio5_1; //虚拟地址
#define SIZEBEY 4 //寄存器字节
#define GPIO3_DR 0x209C000 //LED2 Io物理地址
/*********************** echo none > /sys/class/leds/sys-led/trigger”改变LED2的触发方式 ***************************/
unsigned int* gpio3_3; //虚拟地址
static void Hello_World(unsigned long arg){
if( i % 2 == 1 ){
*gpio5_1 |= (1 << 1);
}else if( i % 2 == 0 ){
*gpio5_1 &= ~(1 << 1);
}
if( i % 2 == 1 ){
*gpio3_3 |= (1 << 3);
}else if( i % 2 == 0 ){
*gpio3_3 &= ~(1 << 3);
}
i++;
arg = jiffies + 1*HZ;
printk("Hello World!!!\n");
printk("receive timer data: %ld\n",arg);
mod_timer(&Mytimer,arg);
}
static int timer_init(void){
init_timer(&Mytimer);
Mytimer.expires = jiffies + 1*HZ; //超时时间
Mytimer.data = jiffies + 1*HZ;
Mytimer.function = Hello_World;
add_timer(&Mytimer); //将定时器注册到内核,开启定时器
return 0;
}
/*读取*/
ssize_t chartext_read (struct file *file, char __user *ubuf, size_t size, loff_t *loff_t){
char kbuf[64] = "Hello Word";
printk("Hello chartext_read\n");
if( copy_to_user(ubuf,kbuf,strlen(kbuf)) != 0 ){
printk("hd_fops_release error\n");
return 0;
}
return 0;
}
/*写*/
ssize_t chartext_write (struct file *file, const char __user *ubuf, size_t size, loff_t *loff_t){
char kbuf[64] = {0};
printk("Hello chartext_write\n");
if( copy_from_user(kbuf,ubuf,size) != 0 ){
printk("chartext_write error\n");
return 0;
}
if( kbuf[0] == '1' ){
timer_init();
}else if( kbuf[0] == '0' ){
del_timer_sync(&Mytimer);
*gpio5_1 &= ~(1 << 1);
*gpio3_3 |= (1 << 3);
}
printk("chartext_write urse is %s\n",kbuf);
return 0;
}
/*打开*/
int chartext_open (struct inode *inode, struct file *file){
printk("Hello chartext_open\n");
return 0;
}
/*关闭*/
int chartext_release (struct inode *inode, struct file *file){
printk("Hello chartext_release\n");
return 0;
}
struct file_operations chartext_fops={ //文件操作集合
.owner = THIS_MODULE,
.read = chartext_read,
.write = chartext_write,
.open = chartext_open,
.release = chartext_release,
};
static int mytimer_init(void){
int ret;
/*动态注册设备号*/
ret = alloc_chrdev_region(&char_dev,0,NUMCHAR,"alloclcddevice");
if( ret != 0 ){
printk("alloc_chrdev_region: register_chrdev_region error!!\n");
return ret;
}
printk("alloc_chrdev_region: register_chrdev_region ok!!\n");
printk("MAJOR %d\n\n",MAJOR(char_dev));
printk("MINOR %d\n\n",MINOR(char_dev));
/*内存映射*/
gpio5_1 = ioremap(GPIO5_DR, SIZEBEY);
if( gpio5_1 == NULL ){
printk("ioremap error3!!\n");
return 0;
}
gpio3_3 = ioremap(GPIO3_DR, SIZEBEY);
if( gpio3_3 == NULL ){
printk("ioremap error3!!\n");
return 0;
}
printk("ioremap ok3!!\n");
/*初始化cdev*/
muqing_cdev.owner = THIS_MODULE;
cdev_init(&muqing_cdev,&chartext_fops);
/*向内核注册设备*/
cdev_add(&muqing_cdev,char_dev,NUMCHAR);
/*创建类 ,在、sys/class下*/
muqing_class = class_create(THIS_MODULE, "lcdclass");
/*自动创建设备节点, /dev下*/
muqing_device = device_create(muqing_class,NULL,char_dev,NULL,"lcddevice");
printk("chartext_init\n");
return 0;
}
static void mytimer_exit(void){
unregister_chrdev_region(char_dev,NUMCHAR); //注销设备号
cdev_del(&muqing_cdev); //删除设备
device_destroy(muqing_class,char_dev); //注销设备
class_destroy(muqing_class); //删除类
del_timer_sync(&Mytimer); //卸载定时器
*gpio5_1 &= ~(1 << 1);
*gpio3_3 |= (1 << 3);
iounmap(gpio5_1);
iounmap(gpio3_3);
printk("timer bye!\n");
}
module_init(mytimer_init);
module_exit(mytimer_exit);
MODULE_LICENSE("GPL");
app.c:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc,char *argv[]){
int fd;
int i;
char buf[64] = {0};
/*char writebuf[64] = "1";
char writebuf1[64] = "0";*/
fd = open("/dev/lcddevice",O_RDWR);//打开设备节点
if( fd < 0 ){
perror("open error\n");
return fd;
}
read(fd,buf,sizeof(buf));
printf("read buf id %s\n",buf);
write(fd,argv[1],1);
close(fd);
return 0;
}
platform平台总线实践:
paltform_driver.c:
#include <linux/module.h> //模块的相关头文件
#include <linux/init.h> //初始化的相关头文件
#include <linux/platform_device.h>
#include <linux/ioport.h>
#include <linux/fs.h> //文件操作集合
#include <linux/uaccess.h> //copy_to_user的头文件
#include <linux/kdev_t.h> //MKDEV所需要的头文件
#include <linux/cdev.h> //cdev结构体以及cdev-init
#include <linux/device.h> //class_create,device_create
#include <linux/io.h> //寄存器
static int chardev_register(void);
dev_t char_dev;
struct resource * acadada;
struct cdev muqing_cdev; //cdev结构体用来表示字符设备
struct class *muqing_class; //class类
struct device *muqing_device; //device设备结构体
#define NUMCHAR 2
#define GPIO5_DR 0x20AC000 //蜂鸣器Io物
unsigned int* gpio5_1; //虚拟地址
#define SIZEBEY 4 //寄存器字节
int ZCY_platform_probe(struct platform_device *pdev){
acadada = platform_get_resource(pdev,IORESOURCE_MEM,0); //从platform_device.c获取硬件资源
printk("start is :%c\n",acadada->start);
printk("ZCY_platform_probe is ok!\n");
chardev_register();
return 0;
}
int ZCY_platform_remove(struct platform_device *pdev){
printk("ZCY_platform_remove is ok!\n");
return 0;
}
const struct platform_device_id ZCY_id_table={
.name = "ZCY_platform",
};
struct platform_driver ZCY_platform_driver={
.probe = ZCY_platform_probe,
.remove = ZCY_platform_remove,
.driver={
.name = "ZCY_platform",
.owner = THIS_MODULE,
},
.id_table = &ZCY_id_table,
};
/*读取*/
ssize_t chartext_read (struct file *file, char __user *ubuf, size_t size, loff_t *loff_t){
char kbuf[64] = "Hello Word";
printk("Hello chartext_read\n");
if( copy_to_user(ubuf,kbuf,strlen(kbuf)) != 0 ){
printk("hd_fops_release error\n");
return 0;
}
return 0;
}
/*写*/
ssize_t chartext_write (struct file *file, const char __user *ubuf, size_t size, loff_t *loff_t){
char kbuf[64] = {0};
printk("Hello chartext_write\n");
if( copy_from_user(kbuf,ubuf,size) != 0 ){
printk("chartext_write error\n");
return 0;
}
if( kbuf[0] == '1' ){
*gpio5_1 |= (1 << 1);
}else if( kbuf[0] == '0' ){
*gpio5_1 &= ~(1 << 1);
}
printk("chartext_write urse is %s\n",kbuf);
return 0;
}
/*打开*/
int chartext_open (struct inode *inode, struct file *file){
printk("Hello chartext_open\n");
return 0;
}
/*关闭*/
int chartext_release (struct inode *inode, struct file *file){
printk("Hello chartext_release\n");
return 0;
}
struct file_operations chartext_fops={ //文件操作集合
.owner = THIS_MODULE,
.read = chartext_read,
.write = chartext_write,
.open = chartext_open,
.release = chartext_release,
};
static int chardev_register(void){
int ret;
/*动态注册设备号*/
ret = alloc_chrdev_region(&char_dev,0,NUMCHAR,"alloclcddevice");
if( ret != 0 ){
printk("alloc_chrdev_region: register_chrdev_region error!!\n");
return ret;
}
printk("alloc_chrdev_region: register_chrdev_region ok!!\n");
printk("MAJOR %d\n\n",MAJOR(char_dev));
printk("MINOR %d\n\n",MINOR(char_dev));
/*内存映射*/
gpio5_1 = ioremap(GPIO5_DR, SIZEBEY);
if( gpio5_1 == NULL ){
printk("ioremap error3!!\n");
return 0;
}
printk("ioremap ok3!!\n");
/*初始化cdev*/
muqing_cdev.owner = THIS_MODULE;
cdev_init(&muqing_cdev,&chartext_fops);
/*向内核注册设备*/
cdev_add(&muqing_cdev,char_dev,NUMCHAR);
/*创建类 ,在、sys/class下*/
muqing_class = class_create(THIS_MODULE, "lcdclass");
/*自动创建设备节点, /dev下*/
muqing_device = device_create(muqing_class,NULL,char_dev,NULL,"lcddevice");
printk("chartext_init\n");
return 0;
}
static int platform_driver_init(void){
int ret;
ret = platform_driver_register(&ZCY_platform_driver);
if(ret < 0){
printk("platform_driver_register error!\n");
return 0;
}
printk("platform_driver_init is ok!\n");
return 0;
}
static void platform_driver_exit(void){
platform_driver_unregister(&ZCY_platform_driver);
unregister_chrdev_region(char_dev,NUMCHAR); //注销设备号
cdev_del(&muqing_cdev); //删除设备
device_destroy(muqing_class,char_dev); //注销设备
class_destroy(muqing_class); //删除类
*gpio5_1 &= ~(1 << 1);
printk("bye bye!!!\n");
}
module_init(platform_driver_init);
module_exit(platform_driver_exit);
MODULE_LICENSE("GPL");
platform_device.c:
#include <linux/module.h> //模块的相关头文件
#include <linux/init.h> //初始化的相关头文件
#include <linux/platform_device.h>
#include <linux/ioport.h>
struct resource ZCY_resource[]={ //描述资源结构体
[0] = { .start = 0x20AC000, //设备起始地址
.end = 0x20AC003, //设备结束地址
.name = "GPIO5_DR", //资源名
.flags = IORESOURCE_MEM, //标志(物理地址)
}
};
void platform_device_release(struct device *dev){
}
struct platform_device ZCY_platform={ //描述设备结构体
.name = "ZCY_platform", //platform 设备名,用来和驱动相匹配
.id = 1, //号码,防止设备名相同
.dev={
.release = platform_device_release,
},
.num_resources = ARRAY_SIZE(ZCY_resource), //资源结构体数量
.resource = ZCY_resource, //资源结构体名
};
static int platform_driver_init(void){
int ret;
ret = platform_device_register(&ZCY_platform); //注册platform设备
if(ret < 0){
printk("platform_device_register error!\n");
return 0;
}
printk("platform_driver_init is ok!\n");
return 0;
}
static void platform_driver_exit(void){
platform_device_unregister(&ZCY_platform); //注销
printk("bye bye!!!\n");
}
module_init(platform_driver_init);
module_exit(platform_driver_exit);
MODULE_LICENSE("GPL");
app.c:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc,char *argv[]){
int fd;
int i;
char buf[64] = {0};
/*char writebuf[64] = "1";
char writebuf1[64] = "0";*/
fd = open("/dev/lcddevice",O_RDWR);//打开设备节点
if( fd < 0 ){
perror("open error\n");
return fd;
}
read(fd,buf,sizeof(buf));
printf("read buf id %s\n",buf);
write(fd,argv[1],1);
close(fd);
return 0;
}
设备树实践:
device_tree.c:
#include <linux/module.h> //模块的相关头文件
#include <linux/init.h> //初始化的相关头文件
#include <linux/ioport.h>
#include <linux/platform_device.h>
#include <linux/fs.h> //文件操作集合
#include <linux/uaccess.h> //copy_to_user的头文件
#include <linux/kdev_t.h> //MKDEV所需要的头文件
#include <linux/cdev.h> //cdev结构体以及cdev-init
#include <linux/device.h> //class_create,device_create
#include <linux/io.h> //寄存器
#include <linux/of.h>
#include <linux/of_address.h>
//struct device_node //设备节点结构体
//struct property //设备属性结构体
static int chardev_register(void);
dev_t char_dev;
struct resource * acadada;
struct cdev muqing_cdev; //cdev结构体用来表示字符设备
struct class *muqing_class; //class类
struct device *muqing_device; //device设备结构体
#define NUMCHAR 2
#define GPIO5_DR 0x20AC000 //蜂鸣器Io物
unsigned int* gpio5_1; //虚拟地址
#define SIZEBEY 4 //寄存器字节
struct device_node *ZCY_device_nota;
struct property *ZCY_property;
u32 out_values[2] = {0};
unsigned int *addrZCY;
int ZCY_device_tree_probe(struct platform_device *pdev){
ZCY_device_nota = of_find_node_by_path("/test"); //获得设备树文件节点资源函数
if(ZCY_device_nota == NULL){
printk("of_find_node_by_path error!\n");
return 0;
- }
printk("of_find_node_by_path name is: %s\n",ZCY_device_nota->name);
/********************************查找属性 的OF函数***************************************************/
ZCY_property = of_find_property(ZCY_device_nota, "compatible", 0); // 查找指定属性的OF函数
if(ZCY_property == NULL){
printk("of_find_property error!\n");
return 0;
}
printk("of_find_property name is: %s\n",(char *)ZCY_property->value);
of_property_read_u32_array(ZCY_device_nota, "reg", out_values, 2); //读取32位reg属性值
printk("of_property_read_u32_array value is: 0x%x\n",out_values[0]);
addrZCY = of_iomap(ZCY_device_nota, 0);
if(addrZCY == NULL){
printk("of_iomap is error!\n");
return 0;
}
printk("of_iomap is ok!\n");
chardev_register();
return 0;
}
int ZCY_device_tree_remove(struct platform_device *pdev){
printk("ZCY_device_tree_remove is ok!\n");
return 0;
}
const struct of_device_id ZCY_of_match_table[] = {
{
.compatible = "tree_test"
},
};
const struct platform_device_id ZCY_id_table={
.name = "ZCY_platform",
};
struct platform_driver ZCY_platform_driver={
.probe = ZCY_device_tree_probe,
.remove = ZCY_device_tree_remove,
.driver={
.name = "ZCY_platform",
.owner = THIS_MODULE,
.of_match_table = ZCY_of_match_table,
},
.id_table = &ZCY_id_table,
};
/*读取*/
ssize_t chartext_read (struct file *file, char __user *ubuf, size_t size, loff_t *loff_t){
char kbuf[64] = "Hello Word";
printk("Hello chartext_read\n");
if( copy_to_user(ubuf,kbuf,strlen(kbuf)) != 0 ){
printk("hd_fops_release error\n");
return 0;
}
return 0;
}
/*写*/
ssize_t chartext_write (struct file *file, const char __user *ubuf, size_t size, loff_t *loff_t){
char kbuf[64] = {0};
printk("Hello chartext_write\n");
if( copy_from_user(kbuf,ubuf,size) != 0 ){
printk("chartext_write error\n");
return 0;
}
if( kbuf[0] == '1' ){
*gpio5_1 |= (1 << 1);
}else if( kbuf[0] == '0' ){
*gpio5_1 &= ~(1 << 1);
}
printk("chartext_write urse is %s\n",kbuf);
return 0;
}
/*打开*/
int chartext_open (struct inode *inode, struct file *file){
printk("Hello chartext_open\n");
return 0;
}
/*关闭*/
int chartext_release (struct inode *inode, struct file *file){
printk("Hello chartext_release\n");
return 0;
}
struct file_operations chartext_fops={ //文件操作集合
.owner = THIS_MODULE,
.read = chartext_read,
.write = chartext_write,
.open = chartext_open,
.release = chartext_release,
};
static int chardev_register(void){
int ret;
/*动态注册设备号*/
ret = alloc_chrdev_region(&char_dev,0,NUMCHAR,"alloclcddevice");
if( ret != 0 ){
printk("alloc_chrdev_region: register_chrdev_region error!!\n");
return ret;
}
printk("alloc_chrdev_region: register_chrdev_region ok!!\n");
printk("MAJOR %d\n\n",MAJOR(char_dev));
printk("MINOR %d\n\n",MINOR(char_dev));
/*内存映射*/
gpio5_1 = ioremap(GPIO5_DR, SIZEBEY);
if( gpio5_1 == NULL ){
printk("ioremap error3!!\n");
return 0;
}
printk("ioremap ok3!!\n");
/*初始化cdev*/
muqing_cdev.owner = THIS_MODULE;
cdev_init(&muqing_cdev,&chartext_fops);
/*向内核注册设备*/
cdev_add(&muqing_cdev,char_dev,NUMCHAR);
/*创建类 ,在、sys/class下*/
muqing_class = class_create(THIS_MODULE, "lcdclass");
/*自动创建设备节点, /dev下*/
muqing_device = device_create(muqing_class,NULL,char_dev,NULL,"lcddevice");
printk("chartext_init\n");
return 0;
}
static int device_tree_init(void){
int ret;
ret = platform_driver_register(&ZCY_platform_driver);
if(ret < 0){
printk("platform_driver_register error!\n");
return 0;
}
printk("platform_driver_init is ok!\n");
return 0;
}
static void device_tree_exit(void){
platform_driver_unregister(&ZCY_platform_driver);
unregister_chrdev_region(char_dev,NUMCHAR); //注销设备号
cdev_del(&muqing_cdev); //删除设备
device_destroy(muqing_class,char_dev); //注销设备
class_destroy(muqing_class); //删除类
*gpio5_1 &= ~(1 << 1);
printk("bye bye!!!\n");
}
module_init(device_tree_init);
module_exit(device_tree_exit);
MODULE_LICENSE("GPL");
app.c:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc,char *argv[]){
int fd;
int i;
char buf[64] = {0};
/*char writebuf[64] = "1";
char writebuf1[64] = "0";*/
fd = open("/dev/lcddevice",O_RDWR);//打开设备节点
if( fd < 0 ){
perror("open error\n");
return fd;
}
read(fd,buf,sizeof(buf));
printf("read buf id %s\n",buf);
write(fd,argv[1],1);
close(fd);
return 0;
}
?????????
devicetree_GPIO.c:
#include <linux/module.h> //模块的相关头文件
#include <linux/init.h> //初始化的相关头文件
#include <linux/ioport.h>
#include <linux/platform_device.h>
#include <linux/fs.h> //文件操作集合
#include <linux/uaccess.h> //copy_to_user的头文件
#include <linux/kdev_t.h> //MKDEV所需要的头文件
#include <linux/cdev.h> //cdev结构体以及cdev-init
#include <linux/device.h> //class_create,device_create
#include <linux/io.h> //寄存器
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
//struct device_node //设备节点结构体
//struct property //设备属性结构体
static int chardev_register(void);
int ret; //用来判断返回值
dev_t char_dev;
struct cdev muqing_cdev; //cdev结构体用来表示字符设备
struct class *muqing_class; //class类
struct device *muqing_device; //device设备结构体
#define NUMCHAR 1
struct device_node *ZCY_device_nota;
struct property *ZCY_property;
u32 out_values[2] = {0};
int GPIO5_1; //申请的GPIO标号
char *GPIO_beep;//给申请出的GPIO的名字
int ZCY_device_tree_probe(struct platform_device *pdev){
ZCY_device_nota = of_find_node_by_path("/test"); //获得设备树文件节点资源函数
if(ZCY_device_nota == NULL){
printk("of_find_node_by_path error!\n");
return 0;
}
printk("of_find_node_by_path name is: %s\n",ZCY_device_nota->name);
/********************************查找属性 的OF函数***************************************************/
ZCY_property = of_find_property(ZCY_device_nota, "compatible", 0); // 查找指定属性的OF函数
if(ZCY_property == NULL){
printk("of_find_property error!\n");
return 0;
}
printk("of_find_property name is: %s\n",(char *)ZCY_property->value);
of_property_read_u32_array(ZCY_device_nota, "reg", out_values, 2); //读取32位reg属性值
printk("of_property_read_u32_array value is: 0x%x\n",out_values[0]);
GPIO5_1 = of_get_named_gpio(ZCY_device_nota, "gpios", 0);//从设备树中获取GPIO标号
if(GPIO5_1 < 0){
printk("of_get_named_gpio is error!\n");
return 0;
}
printk("of_get_named_gpio is OK!\n");
ret = gpio_request(GPIO5_1, GPIO_beep); //申请GPIO管脚
if(ret != 0){
printk("gpio_request is error!\n");
}
printk("gpio_request is OK!\n");
ret = gpio_direction_output(GPIO5_1, 0); //将申请的GPIO管脚设置为输出,默认输出位0
if(ret < 0){
printk("gpio_direction_output is reeor!\n");
return 0;
}
printk("gpio_direction_output is OK!\n");
//__gpio_set_value(unsigned gpio, int value); //设置GPIO管脚的值
gpio_free(GPIO5_1); //释放标号为GPIO5_1的GPIO管脚
chardev_register();
return 0;
}
int ZCY_device_tree_remove(struct platform_device *pdev){
printk("ZCY_device_tree_remove is ok!\n");
return 0;
}
const struct of_device_id ZCY_of_match_table[] = {
{
.compatible = "tree_test"
},
};
const struct platform_device_id ZCY_id_table={
.name = "ZCY_platform",
};
struct platform_driver ZCY_platform_driver={
.probe = ZCY_device_tree_probe,
.remove = ZCY_device_tree_remove,
.driver={
.name = "ZCY_platform",
.owner = THIS_MODULE,
.of_match_table = ZCY_of_match_table,
},
.id_table = &ZCY_id_table,
};
/*读取*/
ssize_t chartext_read (struct file *file, char __user *ubuf, size_t size, loff_t *loff_t){
char kbuf[64] = "Hello Word";
printk("Hello chartext_read\n");
if( copy_to_user(ubuf,kbuf,strlen(kbuf)) != 0 ){
printk("hd_fops_release error\n");
return 0;
}
return 0;
}
/*写*/
ssize_t chartext_write (struct file *file, const char __user *ubuf, size_t size, loff_t *loff_t){
char kbuf[64] = {0};
printk("Hello chartext_write\n");
if( copy_from_user(kbuf,ubuf,size) != 0 ){
printk("chartext_write error\n");
return 0;
}
if( kbuf[0] == '1' ){
gpio_set_value(GPIO5_1, 1); //设置GPIO管脚的值
}else if( kbuf[0] == '0' ){
gpio_set_value(GPIO5_1, 0); //设置GPIO管脚的值
}
printk("chartext_write urse is %s\n",kbuf);
return 0;
}
/*打开*/
int chartext_open (struct inode *inode, struct file *file){
printk("Hello chartext_open\n");
return 0;
}
/*关闭*/
int chartext_release (struct inode *inode, struct file *file){
printk("Hello chartext_release\n");
return 0;
}
struct file_operations chartext_fops={ //文件操作集合
.owner = THIS_MODULE,
.read = chartext_read,
.write = chartext_write,
.open = chartext_open,
.release = chartext_release,
};
static int chardev_register(void){
/*动态注册设备号*/
ret = alloc_chrdev_region(&char_dev,0,NUMCHAR,"alloclcddevice");
if( ret != 0 ){
printk("alloc_chrdev_region: register_chrdev_region error!!\n");
return ret;
}
printk("alloc_chrdev_region: register_chrdev_region ok!!\n");
printk("MAJOR %d\n\n",MAJOR(char_dev));
printk("MINOR %d\n\n",MINOR(char_dev));
/*初始化cdev*/
muqing_cdev.owner = THIS_MODULE;
cdev_init(&muqing_cdev,&chartext_fops);
printk("01\n");
/*向内核注册设备*/
cdev_add(&muqing_cdev,char_dev,NUMCHAR);
printk("02\n");
/*创建类 ,在、sys/class下*/
muqing_class = class_create(THIS_MODULE, "lcdclass");
printk("03\n");
/*自动创建设备节点, /dev下*/
muqing_device = device_create(muqing_class,NULL,char_dev,NULL,"lcddevice");
printk("chartext_init\n");
return 0;
}
static int device_tree_init(void){
int ret;
ret = platform_driver_register(&ZCY_platform_driver);
if(ret < 0){
printk("platform_driver_register error!\n");
return 0;
}
printk("platform_driver_init is ok!\n");
return 0;
}
static void device_tree_exit(void){
platform_driver_unregister(&ZCY_platform_driver);
unregister_chrdev_region(char_dev,NUMCHAR); //注销设备号
cdev_del(&muqing_cdev); //删除设备
device_destroy(muqing_class,char_dev); //注销设备
class_destroy(muqing_class); //删除类
gpio_set_value(GPIO5_1, 0);
printk("bye bye!!!\n");
}
module_init(device_tree_init);
module_exit(device_tree_exit);
MODULE_LICENSE("GPL");
app.c:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc,char *argv[]){
int fd;
fd = open("/dev/lcddevice",O_RDWR);//打开设备节点
if( fd < 0 ){
perror("open error\n");
return fd;
}
write(fd,argv[1],1);
close(fd);
return 0;
}
test:
device_tree_led_test.c:
#include <linux/module.h> //模块的相关头文件
#include <linux/init.h> //初始化的相关头文件
#include <linux/ioport.h>
#include <linux/platform_device.h>
#include <linux/fs.h> //文件操作集合
#include <linux/uaccess.h> //copy_to_user的头文件
#include <linux/kdev_t.h> //MKDEV所需要的头文件
#include <linux/cdev.h> //cdev结构体以及cdev-init
#include <linux/device.h> //class_create,device_create
#include <linux/io.h> //寄存器
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
//struct device_node //设备节点结构体
//struct property //设备属性结构体
static int chardev_register(void);
int ret; //用来判断返回值
dev_t char_dev;
struct cdev muqing_cdev; //cdev结构体用来表示字符设备
struct class *muqing_class; //class类
struct device *muqing_device; //device设备结构体
#define NUMCHAR 1
struct device_node *ZCY_device_nota;
struct property *ZCY_property;
u32 out_values[2] = {0};
int GPIO1_20; //申请的GPIO标号
char *GPIO_led1;//给申请出的GPIO的名字
int ZCY_device_tree_probe(struct platform_device *pdev){
ZCY_device_nota = of_find_node_by_path("/test"); //获得设备树文件节点资源函数
if(ZCY_device_nota == NULL){
printk("of_find_node_by_path error!\n");
return 0;
}
printk("of_find_node_by_path name is: %s\n",ZCY_device_nota->name);
GPIO1_20 = of_get_named_gpio(ZCY_device_nota, "gpio1", 0);//从设备树中获取GPIO标号
if(GPIO1_20 < 0){
printk("of_get_named_gpio is error!\n");
return 0;
}
printk("of_get_named_gpio is OK!\n");
ret = gpio_request(GPIO1_20, "pinctrl_led"); //申请GPIO管脚
if(ret != 0){
printk("gpio_request is error!\n");
}
printk("gpio_request is OK!\n");
ret = gpio_direction_output(GPIO1_20, 0); //将申请的GPIO管脚设置为输出,默认输出位0
if(ret < 0){
printk("gpio_direction_output is reeor!\n");
return 0;
}
printk("gpio_direction_output is OK!\n");
//__gpio_set_value(unsigned gpio, int value); //设置GPIO管脚的值
gpio_free(GPIO1_20); //释放标号为GPIO5_1的GPIO管脚
chardev_register();
return 0;
}
int ZCY_device_tree_remove(struct platform_device *pdev){
printk("ZCY_device_tree_remove is ok!\n");
return 0;
}
const struct of_device_id ZCY_of_match_table[] = {
{
.compatible = "tree_test"
},
};
const struct platform_device_id ZCY_id_table={
.name = "ZCY_platform",
};
struct platform_driver ZCY_platform_driver={
.probe = ZCY_device_tree_probe,
.remove = ZCY_device_tree_remove,
.driver={
.name = "ZCY_platform",
.owner = THIS_MODULE,
.of_match_table = ZCY_of_match_table,
},
.id_table = &ZCY_id_table,
};
/*读取*/
ssize_t chartext_read (struct file *file, char __user *ubuf, size_t size, loff_t *loff_t){
char kbuf[64] = "Hello Word";
printk("Hello chartext_read\n");
if( copy_to_user(ubuf,kbuf,strlen(kbuf)) != 0 ){
printk("hd_fops_release error\n");
return 0;
}
return 0;
}
/*写*/
ssize_t chartext_write (struct file *file, const char __user *ubuf, size_t size, loff_t *loff_t){
char kbuf[64] = {0};
printk("Hello chartext_write\n");
if( copy_from_user(kbuf,ubuf,size) != 0 ){
printk("chartext_write error\n");
return 0;
}
if( kbuf[0] == '1' ){
gpio_set_value(GPIO1_20, 1); //设置GPIO管脚的值
}else if( kbuf[0] == '0' ){
gpio_set_value(GPIO1_20, 0); //设置GPIO管脚的值
}
printk("chartext_write urse is %s\n",kbuf);
return 0;
}
/*打开*/
int chartext_open (struct inode *inode, struct file *file){
printk("Hello chartext_open\n");
return 0;
}
/*关闭*/
int chartext_release (struct inode *inode, struct file *file){
printk("Hello chartext_release\n");
return 0;
}
struct file_operations chartext_fops={ //文件操作集合
.owner = THIS_MODULE,
.read = chartext_read,
.write = chartext_write,
.open = chartext_open,
.release = chartext_release,
};
static int chardev_register(void){
/*动态注册设备号*/
ret = alloc_chrdev_region(&char_dev,0,NUMCHAR,"alloclcddevice");
if( ret != 0 ){
printk("alloc_chrdev_region: register_chrdev_region error!!\n");
return ret;
}
printk("alloc_chrdev_region: register_chrdev_region ok!!\n");
printk("MAJOR %d\n\n",MAJOR(char_dev));
printk("MINOR %d\n\n",MINOR(char_dev));
/*初始化cdev*/
muqing_cdev.owner = THIS_MODULE;
cdev_init(&muqing_cdev,&chartext_fops);
printk("01\n");
/*向内核注册设备*/
cdev_add(&muqing_cdev,char_dev,NUMCHAR);
printk("02\n");
/*创建类 ,在、sys/class下*/
muqing_class = class_create(THIS_MODULE, "lcdclass");
printk("03\n");
/*自动创建设备节点, /dev下*/
muqing_device = device_create(muqing_class,NULL,char_dev,NULL,"lcddevice");
printk("chartext_init\n");
return 0;
}
static int device_tree_init(void){
int ret;
ret = platform_driver_register(&ZCY_platform_driver);
if(ret < 0){
printk("platform_driver_register error!\n");
return 0;
}
printk("platform_driver_init is ok!\n");
return 0;
}
static void device_tree_exit(void){
platform_driver_unregister(&ZCY_platform_driver);
unregister_chrdev_region(char_dev,NUMCHAR); //注销设备号
cdev_del(&muqing_cdev); //删除设备
device_destroy(muqing_class,char_dev); //注销设备
class_destroy(muqing_class); //删除类
gpio_set_value(GPIO1_20, 0);
printk("bye bye!!!\n");
}
module_init(device_tree_init);
module_exit(device_tree_exit);
MODULE_LICENSE("GPL");
app.c:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc,char *argv[]){
int fd;
fd = open("/dev/lcddevice",O_RDWR);//打开设备节点
if( fd < 0 ){
perror("open error\n");
return fd;
}
write(fd,argv[1],1);
close(fd);
return 0;
}
中断:
ZCY_interrupt.c:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/interrupt.h>
#include <linux/of_irq.h>
//struct device_node //设备节点结构体
//struct property //设备属性结构体
int ret; //用来判断返回值
struct device_node *ZCY_device_nota;//设备树节点
struct property *ZCY_property; //设备树属性
int GPIO5_1; //申请的GPIO标号
char *GPIO_beep;//给申请出的GPIO起一个名字
struct tasklet_struct ZCY_beep_tasklet; //定义tasklet结构体
int irq_num;//中断号
/*
struct timer_list Mytimer; //定时器相关结构体
static int timer_init(void){ //定时器初始化
init_timer(&Mytimer);
Mytimer.expires = jiffies + 1*HZ; //超时时间(定时器到时时间)
Mytimer.data = jiffies + 1*HZ; //要传入function函数的参数
Mytimer.function = Hello_World; //function要执行的函数(定时器到时要执行的函数)
add_timer(&Mytimer); //将定时器注册到内核,开启定时器
return 0;
}
static void Hello_World(unsigned long arg){
if( i % 2 == 1 ){
*gpio5_1 |= (1 << 1);
}else if( i % 2 == 0 ){
*gpio5_1 &= ~(1 << 1);
}
i++;
arg = jiffies + 1*HZ;
printk("Hello World!!!\n");
printk("receive timer data: %ld\n",arg);
mod_timer(&Mytimer,arg);
}*/
irqreturn_t ZCY_beep_func(int irq,void *dev){ //中断函数
printk("start\n");
gpio_set_value(GPIO5_1,0);
tasklet_schedule(&ZCY_beep_tasklet);
printk("end\n");
return IRQ_HANDLED;
}
void tasklet_func(unsigned long data){ //中断下文函数
int i = data;
printk("i is %d \n", i);
while (i--)
printk("ZCY_beep_func is %d \n", i);
}
int ZCY_device_tree_probe(struct platform_device *pdev){
//匹配成功后进入probe函数
ZCY_device_nota = of_find_node_by_path("/test"); //获得设备树文件节点资源函数
if(ZCY_device_nota == NULL){
printk("of_find_node_by_path error!\n");
return 0;
}
printk("of_find_node_by_path name is: %s\n",ZCY_device_nota->name);
GPIO5_1 = of_get_named_gpio(ZCY_device_nota, "gpios", 0);//从设备树中获取GPIO标号
if(GPIO5_1 < 0){
printk("of_get_named_gpio is error!\n");
return 0;
}
printk("of_get_named_gpio is OK!\n");
ret = gpio_request(GPIO5_1, GPIO_beep); //申请GPIO管脚
if(ret != 0){
printk("gpio_request is error!\n");
}
printk("gpio_request is OK!\n");
/*
gpio_direction_input(GPIO5_1);
gpio_set_value(GPIO5_1,0);*/
ret = gpio_direction_output(GPIO5_1, 0); //将申请的GPIO管脚设置为输出,默认输出位0
if(ret < 0){
printk("gpio_direction_output is reeor!\n");
return 0;
}
printk("gpio_direction_output is OK!\n");
/***********************************中断*********************************/
irq_num = gpio_to_irq(GPIO5_1); //通过GPIO标号获得中断号
if(irq_num == 0){
printk("gpio_to_irq is error!!!\n");
return 0;
}
/*
irq_num = irq_of_parse_and_map(ZCY_device_nota,0);//从设备树属性中提取中断号
if(irq_num < 0){
printk("gpio_to_irq is error!!!\n");
return 0;
}*/
printk("irq_num is :%d\n",irq_num);
ret = request_irq(irq_num,ZCY_beep_func,IRQF_TRIGGER_HIGH,"ZCY_interrupt",NULL); //申请中断函数
if(ret < 0){
printk("request_irq is error!!!\n");
return 0;
}
printk("request_irq is OK!\n");
enable_irq(irq_num); //中断使能函数
tasklet_init(&ZCY_beep_tasklet,tasklet_func,100); //初始化tasklet
//__gpio_set_value(unsigned gpio, int value); //设置GPIO管脚的值
printk("GPIO5_1 is :%d\n",gpio_get_value(GPIO5_1));
gpio_set_value(GPIO5_1,1);
printk("GPIO5_1 is :%d\n",gpio_get_value(GPIO5_1));
gpio_set_value(GPIO5_1,0);
return 0;
}
int ZCY_device_tree_remove(struct platform_device *pdev){
printk("ZCY_device_tree_remove is ok!\n");
return 0;
}
const struct of_device_id ZCY_of_match_table[] = { //设备树属性
{
.compatible = "tree_test"
},
};
const struct platform_device_id ZCY_id_table={
.name = "ZCY_platform",
};
struct platform_driver ZCY_platform_driver={
.probe = ZCY_device_tree_probe,
.remove = ZCY_device_tree_remove,
.driver={
.name = "ZCY_platform",
.owner = THIS_MODULE,
.of_match_table = ZCY_of_match_table, //要进行匹配的设备树属性
},
.id_table = &ZCY_id_table,
};
static int device_tree_init(void){ //驱动入口函数
int ret;
ret = platform_driver_register(&ZCY_platform_driver);
if(ret < 0){
printk("platform_driver_register error!\n");
return 0;
}
printk("platform_driver_init is ok!\n");
return 0;
}
static void device_tree_exit(void){ //驱动出口函数
free_irq(irq_num,NULL);
tasklet_kill(&ZCY_beep_tasklet);
gpio_set_value(GPIO5_1, 0);
gpio_free(GPIO5_1); //释放标号为GPIO5_1的GPIO管脚
platform_driver_unregister(&ZCY_platform_driver);
printk("bye bye!!!\n");
}
module_init(device_tree_init);//驱动入口函数
module_exit(device_tree_exit);//驱动出口函数
MODULE_LICENSE("GPL");