2_写一个点LED驱动

  1. 写出驱动程序的框架
  2. 完善硬件的操作:
    a. 看原理图,确定引脚
    b. 看2440手册
    c. 写代码 ,写单片机代码的时候是直接操作物理地址,
    而写Linux驱动代码的时候就不能直接操作物理地址,得操作虚拟地址,虚
    拟地址怎么来?用ioremap映射,ioremap是一个函数把物理地址映射为虚
    拟地址。

这里写图片描述

这里写图片描述

驱动程序first_drv.c

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/arch/regs-gpio.h>
#include <asm/hardware.h>

static struct class *firstdrv_class;                //一个类
static struct class_device  *firstdrv_class_dev;    //类下面再建立一个设备

volatile unsigned long *gpfcon = NULL;  //定义一个全局变量,初始值为0
volatile unsigned long *gpfdat = NULL;

static int first_drv_open(struct inode *inode, struct file *file)  //应用程序里面打开设备文件的时候就会进入到内核里面,
                                                                   //调用驱动程序里面的first_drv_open
{                                                                      
    /* 配置GPF4,GPF5,GPF6为输出*/
    *gpfcon &= ~((0x3<<(4*2)) | (0x3<<(5*2)) | (0x3<<(6*2)));   //清零
    *gpfcon |=   ((1<<(4*2)) | (1<<(5*2)) | (1<<(6*2)));        //设置引脚为输出
    return 0;
}

static ssize_t first_drv_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
{
    int val;                            //用户程序传进来的值buf, count,怎么才能取得到,用copy_from_user函数

    copy_from_user(&val, buf, count);   //这个函数对应firstdrvtest里的write函数,buf对应write函数里的&val
                                        //count对应write函数里的4
       //copy_to_user(&val, buf, count);  内核空间向用户空间传递数据

    if (val == 1)
    {
        *gpfdat &= ~((1<<4) |(1<<5)|(1<<6));  //点灯
    }
    else
    {
        *gpfdat |= (1<<4) |(1<<5)|(1<<6);     //灭灯
    }

    return 0;
}

static struct file_operations first_drv_fops = {
    .owner  =   THIS_MODULE,        // 这是一个宏,推向编译模块时自动创建的__this_module变量 
    .open   =   first_drv_open,            
    .write  =   first_drv_write,       
};

int major;
int first_drv_init(void)                                      //主设备号可写0,让系统自动给我们分配
{
    major=register_chrdev(0, "first_drv", &first_drv_fops);   //注册,告诉内核,"first_drv"名字可随便写

    firstdrv_class = class_create(THIS_MODULE, "firstdrv");   //创建一个类,类下面再创建一个设备

    firstdrv_class_dev = class_device_create(firstdrv_class, NULL, MKDEV(major, 0), NULL, "xyz");     

    gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16);   //16字节,这两个指针指向虚拟地址
    gpfdat =  gpfcon+1;    // +1,是指针的操作
    return 0;                                                   
}

static void first_drv_exit(void)
{
    unregister_chrdev(major, "first_drv");         //卸载
    class_device_unregister(firstdrv_class_dev);   //删除节点及信息
    class_destroy(firstdrv_class);
    iounmap(gpfcon);                               //去掉地址映射
}
module_init(first_drv_init);
module_exit(first_drv_exit);
MODULE_LICENSE("GPL");

应用程序firstdrvtest.c

#include <sys/types.h>     /*应用程序调用open,  write函数,这两个函数是C库实现的*/
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>

/* firstdrvtest on
  * firstdrvtest off
  */

int main(int argc, char **argv)
{
    int fd;          
    int val = 1;
    fd = open("/dev/xyz", O_RDWR);    //open一个设备,O_RDWR以可读写方式打开文件
    if(fd<0)                          //open返回值:成功则返回文件描述符,否则返回 -1
        printf("can't open!\n");      //-1<0 打不开文件

    if(argc != 2)                     //如果命令行字符串不是2个的话,就打印输出命令行的格式
        printf("Usage :\n");
        printf("%s, <on | off>\n", argv[0] );   //argv[0] 保存的是程序名firstdrvtest,
                                                //<on | off>尖括号表示参数不可省略, |表示可写on也可写off

    if(strcmp(argv[1], "on") == 0)   //命令行的第二个字符串与字符串"on"进行比较,若相等值为0
    {
        val = 1;
    }
    else
    {
        val = 0;
    }

    write(fd, &val, 4);  //write函数把val所指的内存写入4个字节到参数fd所指的文件内
    return 0;            //write函数把0或1告诉驱动程序first_drv里的first_drv_write函数
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值