资料链接:
============================================================================================
1. 驱动设计
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
static struct cdev gec6818_led_cdev; //字符设备结构体
static dev_t led_num=0; //设备号
static int gec6818_led_open (struct inode * inode, struct file *file)
{
printk("gec6818_led_open \n");
return 0;
}
static int gec6818_led_release (struct inode * inode, struct file *file)
{
printk("gec6818_led_release \n");
return 0;
}
static ssize_t gec6818_led_write (struct file * file, const char __user * buf, size_t len, loff_t * off)
{
int rt;
char kbuf[64]={0};
//判断当前len是否合法
if(len > sizeof kbuf)
return -EINVAL; //返回参数无效错误码
//从用户空间拷贝数据
rt = copy_from_user(kbuf,buf,len);
//获取成功复制的字节数
len = len - rt;
printk("gec6818_led_write,kbuf[%s],len[%d]\n",kbuf,len);
return len;
}
static ssize_t gec6818_led_read (struct file *file, char __user *buf, size_t len, loff_t * offs)
{
int rt;
char kbuf[5]={'1','2','3','4','\0'};
//判断当前len是否合法
if(len > sizeof kbuf)
return -EINVAL; //返回参数无效错误码
//从内核空间拷贝到用户空间
rt = copy_to_user(buf,kbuf,len);
//获取成功复制的字节数
len = len - rt;
printk("gec6818_led_read,__user buf[%s],len[%d]\n",buf,len);
return len;
}
static const struct file_operations gec6818_led_fops = {
.owner = THIS_MODULE,
.write = gec6818_led_write,
.open = gec6818_led_open,
.release = gec6818_led_release,
.read = gec6818_led_read,
};
//入口函数
static int __init gec6818_led_init(void)
{
int rt=0;
//动态申请设备号
rt=alloc_chrdev_region(&led_num,0,1,"gec6818_leds");
if(rt < 0)
{
printk("alloc_chrdev_region fail\n");
return rt;
}
printk("led_major = %d\n",MAJOR(led_num));
printk("led_minor = %d\n",MINOR(led_num));
//字符设备初始化
cdev_init(&gec6818_led_cdev,&gec6818_led_fops);
//字符设备添加到内核
rt = cdev_add(&gec6818_led_cdev,led_num,1);
if(rt < 0)
{
printk("cdev_add fail\n");
goto fail_cdev_add;
}
printk("gec6818 led init\n");
return 0;
fail_cdev_add:
unregister_chrdev_region(led_num,1);
return rt;
}
//出口函数
static void __exit gec6818_led_exit(void)
{
cdev_del(&gec6818_led_cdev);
unregister_chrdev_region(led_num,1);
printk("gec6818 led exit\n");
}
//驱动程序的入口:insmod led_drv.ko调用module_init,module_init又会去调用gec6818_led_init。
module_init(gec6818_led_init);
//驱动程序的出口:rmsmod led_drv调用module_exit,module_exit又会去调用gec6818_led_exit。
module_exit(gec6818_led_exit)
//模块描述
MODULE_AUTHOR("stephenwen88@163.com"); //作者信息
MODULE_DESCRIPTION("gec6818 led driver"); //模块功能说明
MODULE_LICENSE("GPL"); //许可证:驱动遵循GPL协议
========================================================================================================
2. 用户程序设计
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char **argv)
{
int fd=-1;
int len;
char buf[64]="hello teacher.wen";
//打开gec6818_leds设备
fd = open("/dev/gec6818_leds",O_RDWR);
if(fd < 0)
{
perror("open /dev/gec6818_leds:");
return fd;
}
sleep(2);
write(fd,buf,strlen(buf));
sleep(2);
len = read(fd,buf,5);
if(len > 0)
printf("read buf:%s\n len=%d\n",buf,len);
sleep(2);
close(fd);
return 0;
}