字符设备实现控制led的驱动

一个led驱动,做个记号

硬软件环境:s3c2440/linux-2.6.36/busybox-1.18.4/arm-linux-gcc 4.4.3

下面是模块c代码:


#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <asm/io.h>

#include <asm/uaccess.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("zhanglong");

/*
 * 板子上的led1,2,4,8分别对应连在GPF4,5,6,7上
 *
 *GPFCON ==> 0x56000050
 *GPFDAT ==> 0x56000054
 *GPFUP ==> 0x56000058
 *
 */
#define IO_PHYS 0x56000000
#define GPFCON_OFFSET   0x50
#define GPFDAT_OFFSET   0x54
#define GPFUP_OFFSET   0x58

struct led_device_s {
    struct cdev dev;
    dev_t  no;

    short *io_gpfcon;   //注意数据类型, 前面因为错误声明为char型指针,造成结果与预期的不同,郁闷了很久.
    char *io_gpfdat;
    char *io_gpfup;
};

struct led_device_s  my_led[4];

ssize_t my_write(struct file *fp, const char __user *buf, size_t count, loff_t *off)
{
    struct led_device_s *get = fp->private_data;
    unsigned int    minor;

    minor = MINOR(get->no);
   
    *(get->io_gpfcon) &= ~(3 << ((minor * 2) + 8));
    *(get->io_gpfcon) |= (1 << ((minor * 2) + 8));
    *(get->io_gpfup) &= ~(1 << (minor + 4));

    if((*buf == 0) || (*buf == 48)) {
        *(get->io_gpfdat) &= ~(1 << (minor + 4));
    } else {
        *(get->io_gpfdat) |= (1 << (minor + 4));
    }

    return  4;
}

ssize_t my_read(struct file *fp, char __user *buf, size_t count, loff_t *off)
{
    return  4;  //不能返回0, 否则读相关设备时会卡住.
}


int my_open(struct inode *no, struct file *fp)
{
    fp->private_data = container_of(no->i_cdev, struct led_device_s, dev);
    //printk(" kernel: open.\n");

    return 0;
}

int my_release(struct inode *no, struct file *fp)
{
    //printk(" kernel: release.\n");

    return 0;
}

struct file_operations my_ops = {
    .open = my_open,
    .release = my_release,
    .read = my_read,
    .write = my_write,
};

int test_init(void)
{
    int ret = 0;
    char *virt;
    int i;   

    virt = ioremap(IO_PHYS, SZ_4K);

    for (i = 0; i < 4; i ++) {
        my_led[i].no = MKDEV(52, i);
        cdev_init(&my_led[i].dev, &my_ops);

        my_led[i].io_gpfcon = virt + GPFCON_OFFSET;
        my_led[i].io_gpfdat = virt + GPFDAT_OFFSET;
        my_led[i].io_gpfup = virt + GPFUP_OFFSET;
    }

    ret = register_chrdev_region(my_led[0].no, 4, "my dev");
    if (ret) {
        printk(" register device number failed.\n");
        return ret;
    }

    for (i = 0; i < 4; i ++) {
        cdev_add(&my_led[i].dev, my_led[i].no, 1);
    }

    return ret;
}

void test_exit(void)
{
    int i ;
    for (i = 0; i < 4; i ++) {
        cdev_del(&my_led[i].dev);
    }
    unregister_chrdev_region(my_led[0].no, 4);   
}

module_init(test_init);
module_exit(test_exit);

下面是Makefile文件内容

#KERNEL    = /home/zl/my2440-2.6.13
KERNEL    = /media/STUDY/linux/kernel/my2440-2.6.36
#KERNEL    = /lib/modules/$(shell uname -r)/build

default:
    make -C $(KERNEL) M=$(shell pwd) modules

clean:
    make -C $(KERNEL) M=$(shell pwd) modules clean

obj-m    += test.o


执行make命令后,“insmod test.ko”插入模块。用
echo 1 > led0_node
echo 0 > led0_node

echo 1 > led1_node
echo 0 > led1_node

echo 1 > led2_node
echo 0 > led2_node

echo 1 > led3_node
echo 0 > led3_node
即可使led灭或亮

其中led0_node,led1_node,led2_node,led3_node必须是字符设备文件,主,次设备号分别为(52,0)(52,1)(52,2)(52,3)

led0_node,led1_node,led2_node,led3_node对应的GPF4,5,6,7控制的led
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
字符设备驱动 按字节来访问的设备驱动 它被组织为一组完成不同任务的函数集合 通过这些函数使得Linux的字符设备操作犹如文件一样 从应用程序的角度看,硬件设备是一个设备文件 对于应用程序工程师来说,使用设备文件与使用普通文件的方法是相同的。 块设备驱动 以块为单位接受输入和返回输出 Linux允许块设备传送任意数目字节的数据块 Linux对于I/O请求有对应的缓冲区,可以选择响应顺序 块设备可以被随机访问 字符设备驱动程序开发流程 设备号 字符设备驱动的重要数据结构介绍 字符设备的注册流程 字符设备相关操作 创建设备文件 编写驱动程序程序 主设备号 –前12位 表示与设备文件相关联的驱动程序 确定设备类型 次设备号—后20位 表示被驱动程序用来辨别操作的是哪个设备 区分同类设备 file_operations 把系统调用和驱动程序关联起来的关键数据结构 结构的每一个成员都对应着一个系统调用 读取file_operation中相应的函数指针,接着把控制权转交给函数,从而完成了Linux设备驱动程序的工作 中定义的是三个结构体非常重要 file_operations file 代表一个打开的文件 系统中每个打开的文件在内核空间都有一个关联的Struct File 它由内核在打开文件时创建,在文件关闭后释放 inode 用来记录文件的物理信息 一个文件可以打开多个file结构, 但只有一个inode结构 module_init(leddev_init); module_exit(leddev_exit); 创建设备文件 mknod

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值