字符设备驱动

以下代码并未编译测试,代码编译过程中可能有语法出错,代码仅供参考,只是提供一个字符设备设计的思路。

//led.c
#include<linux/module.h>//内核模块头文件
#include<linux/init.h>//内核模块头文件
#include<linux/cdev.h>//cdev file_operations 头文件
#include<linux/fs.h>//cdev file_operations 头文件
#include<linux/io.h> //ioremap头文件
#inculde"led.h"
MOUDLE_LICENSE("GPL");//模块遵守的协议
int led_init()
{
    return 0;
}
void led_exit()
{
}

module_init(led_init);
module_exit(led_exit());
以上为内核模块,任何一个驱动程序必须要有的部分,接下来完成对模块的扩充。
//makefile 用于编译内核模块,编译led.c文件
obj-m := led.o   //注意led.o对应led.c
KDIR := 内核代码路径   //注:你开发板所用的内核 
all:
    make -C $(KDIR) M=(PWD) modules CROSS_COMPILE=arm-linux- ARCH=arm
clean:
    rm -f *.o *.ko *.order *.symvers 
//led.c
#include<linux/module.h>//内核模块头文件
#include<linux/init.h>//内核模块头文件
#include<linux/cdev.h>//cdev file_operations 头文件
#include<linux/fs.h>//cdev file_operations 头文件
#include<linux/io.h> //ioremap头文件
MOUDLE_LICENSE("GPL");//模块遵守的协议
struct cdev led_cdev; //驱动初始化第一步:分配设备描述结构
dev_t dev_number;   //定义设备号变量
#define GPNCON 0x7f008800
#define GPNDTA 0x7f008808
unsigned int * led_config;
unsigned int * led_data;
//通常打开文件时完成对LED的控制和数据寄存器的初始化
int len_open(struct inode *node, struct file *filp)
{

    //linux系统中使用的是虚拟地址因此要用ioremap把实际地址转化为虚拟地址
    led_config = ioremap(GPNCON,4);
    writel(0x11110000,led_config);  //把0x11110000写入led_config指向的地址空间中,完成对控制寄存器的初始化
    led_data = ipremap(GPNDTA,4);
    return 0;
}
long len_ioctl(struct file *filp, unsigned int cmd, unsigned long args)
{
    switch(cmd)
    {
        case LED_ON:
        writew(0x00,led_data);
        return 0;
        case LED_OFF:
        writew(0xff,led_data);
        return 0;
        defaulet:
        printf("cmd error!\n");
        return cmd;
    }
}
struct file_operations led_fops=
{
    open = len_open,
    .unlocked_ioctl = len_ioctl,
};
int led_init()
{
    cdev_init(&led_cdev,&led_fops);//驱动初始化第二步:初始化设备描述结构 注:参数1:设备描述结构参数2:文件操作函数集
    //动态分配主设备号
    alloc_chrdev_region(&dev_number,0,1,"myled"); // 参数1.返回主设备号保存于dev_number中参数2.次设备号的基准,从第几个次设备号开始分配。参数3.分配的次设备号个数 参数4.驱动的名字
    cdev_add(&led_cdev,dev_number,1); //第三步:注册设备描述结构
    return 0;
}
void led_exit()
{
    cdev_del(&led_cdev); //第四步:注销设备描述结构
    unregister)chrdev(dev_number,1);//释放设备号
}

module_init(led_init);
module_exit(led_exit);
//led.h
#define led_MAGIC 'L' //第一幻术
#define LED_ON _IO(led_MAGIC ,0)
#define LED_OFF _IO(led_MAGIC,1)
//编写应用程序led_app.c 对驱动程序进行测试
#include<stdio.h>
int main(int argc,char *argv)
{
    int fd;
    int cmd = 0
    fd = open("dev/myled",O_RDWR);  //这里的myled要与mknod 创建的字符设备文件名一样
    cmd = atoi(argv[1]);  //将字符转化为int型
    if(cmd==1)
    {
        ioctl(fd,LED_ON);
    }
    if(cmd==2)
    {
        ioctl(fd,LED_OFF);
    }
    return 0;
}
//编译led_app.c 注意使用arm-linux-gcc 且最好使用静态编译,因为防止开发板中没有我们所需的动态链接库

arm-linux-gcc -static led_app.c -o led_app
make 后生成led.ko
把led.ko和led_app复制到开发板的文件系统下,
insmod led.ko
如果安装模块出错,则执行如下命令
//////////////////////////////////
mkdir -p /lib/modules/$(uname -r)
///////////////////////////////

//创建字符设备文件 创建的目的:应用程序首先通过文件名myled找到字符设备文件,然后字符设备文件通过主设备号找到设备驱动程序
mknod /dev/myled c 主设备号 次设备号
主设备号可以在cat /dev/devices查看  注:是在开发板系统中,不是虚拟机中
./led_app 1 //led_app点亮
./led_app 2 //led_app熄灭
rmmod led  卸载led
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值