现在的位置: 首页 > 综合 > 正文

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

2018年02月07日 ⁄ 综合 ⁄ 共 2785字 ⁄ 字号 评论关闭
硬软件环境: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

抱歉!评论已关闭.