标签:__ 直接 led int ret 寄存器 操作 include class
驱动程序
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <asm/uaccess.h>
#include <asm/io.h>
static unsigned int major;
static struct device * led_dev;
static struct class * led_class;
static volatile unsigned long * GPC0_CON;
static volatile unsigned long * GPC0_DAT;
int led_open (struct inode * node, struct file * filp)
{
printk("----------%s------------\n",__FUNCTION__);
return 0;
}
int led_release (struct inode *node, struct file * filp)
{
printk("----------%s------------\n",__FUNCTION__);
return 0;
}
ssize_t led_write(struct file * filp, const char __user * buff, size_t count, loff_t * offset)
{
ssize_t ret;
int led_cmd;
printk("----------%s------------\n",__FUNCTION__);
//参数1:内核空间的buff地址
//参数2:用户空间的buff地址
//参数3:传递的长度
//返回值: 返回0表示成功,如果拷贝出现异常,返回值表示没有拷贝成功的个数
ret = copy_from_user(&led_cmd, buff, count); //从用户空间拷贝到内核空间
//copy_to_user(void __user * to, const void * from, unsigned long n)从内核空间到用户空间的拷贝
if(ret > 0)
{
printk("copy_from_user error\n");
return ret;
}
if(led_cmd == 0) //关灯
{
*GPC0_DAT &= ~(0x03 << 3);
}
else //开灯
{
*GPC0_DAT |= (0x03 << 3);
}
return 0;
}
const struct file_operations fops ={
.owner = THIS_MODULE, // 可有可无
.open = led_open,
.write = led_write,
.release = led_release,
};
static int __init drv_led_init(void)
{
//1. 申请/注册一个设备号
// 设备号是一个32为的无符号整型,高12位是主设备号,低20位为次设备号
// 主设备号:表示哪一类设备
// 次设备号:表示哪一个设备
int ret;
//静态注册
major = 250; // cat /proc/devices找一个别人没有用到的
//参数1:主设备号
//参数2:设备描述,自定义
//参数3:struct file_operations结构体变量
ret = register_chrdev(major, "drv_led", &fops);
if(ret < 0)
{
printk("register_chrdev error\n");
return -EINVAL;
}
// 2. 创建类
//参数1: THIS_MODULE,表示当前模块
//参数2: /sys/class/下创建的目录名称,自定义
led_class = class_create(THIS_MODULE, "led_class");
if(IS_ERR(led_class))
{
printk("class_create error\n");
ret = PTR_ERR(led_class);
goto err_class_create;
}
//3. 创建设备结点
// 手动创建设备节点的方法: mknod /dev/drv_led c 250 0
// 参数1: 创建的类
// 参数2: 设备的父类
// 参数3: 设备号,包括了主设备号和次设备号,用MKDEV来合成
// 参数4: 设备文件的私有数据
// 参数5: 设备节点名称
led_dev = device_create(led_class, NULL, MKDEV(major, 0), NULL, "drv_led");
if(IS_ERR(led_dev))
{
printk("device_create error\n");
ret = PTR_ERR(led_dev);
goto err_device_create;
}
//4. 硬件初始化
//参数1:要映射的物理地址的起始
//参数2:要映射的大小
GPC0_CON = ioremap(0xE0200060,8);
GPC0_DAT = GPC0_CON + 1;
//控制寄存器的[19:12]清零
*GPC0_CON &= ~(0xff << 12);
//控制寄存器的[19:12]赋值为0001 0001
*GPC0_CON |= (0x11 << 12);
//数据寄存器清零,关闭当前所有的LED
*GPC0_DAT &= ~(0x03 << 3);
return 0;
err_device_create:
class_destroy(led_class);
err_class_create:
unregister_chrdev(major, "drv_led");
return ret;
}
static void __exit drv_led_exit(void)
{
iounmap(GPC0_CON);
device_destroy(led_class, MKDEV(major, 0));
class_destroy(led_class);
unregister_chrdev(major, "drv_led");
}
//模块的入口函数
module_init(drv_led_init);
//模块的出口函数
module_exit(drv_led_exit);
//要遵循GPL协议
MODULE_LICENSE("GPL");
应用程序
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(void)
{
int fd;
int on;
int count = 5;
fd = open("/dev/drv_led",O_RDWR);
if(fd < 0)
{
perror("open");
exit(1);
}
while(count--)
{
on = 1;
write(fd, &on, sizeof(on));
sleep(2);
on = 0;
write(fd, &on, sizeof(on));
sleep(2);
}
close(fd);
return 0;
}
标签:__,直接,led,int,ret,寄存器,操作,include,class 来源: https://blog.csdn.net/weixin_49551849/article/details/112630796
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。