Linux嵌入式驱动学习之路⑩字符设备驱动-my_led

Posted 叶念西风

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux嵌入式驱动学习之路⑩字符设备驱动-my_led相关的知识,希望对你有一定的参考价值。

首先贴上代码:

字符设备驱动代码:

/**
 *file name: led.c
 */

#include <linux/sched.h> #include <linux/signal.h> #include <linux/spinlock.h> #include <linux/errno.h> #include <linux/random.h> #include <linux/poll.h> #include <linux/init.h> #include <linux/slab.h> #include <linux/module.h> #include <linux/wait.h> #include <linux/mutex.h> #include <linux/io.h> #include <linux/fs.h> static struct class *led_class;         //创建类 static struct class_device *led_class_devs[4]; //创建类对应的设备 1个总设备文件 3个单个灯的设备文件 volatile unsigned long *gpfcon = NULL; volatile unsigned long *gpfdat = NULL; int led_open(struct inode *inode, struct file *fp) { int minor = MINOR(inode->i_rdev);        //获取打开设备文件的次设备号 switch(minor) { case 0: *gpfcon &= ~((0x3<<(4*2))|(0x3<<(5*2))|(0x3<<(6*2))); *gpfcon |= (0x1<<(4*2))|(0x1<<(5*2))|(0x1<<(6*2)); break; case 1: *gpfcon &= ~(0x3<<(4*2)); *gpfcon |= (0x1<<(4*2)); break; case 2: *gpfcon &= ~(0x3<<(5*2)); *gpfcon |= (0x1<<(5*2)); break; case 3: *gpfcon &= ~(0x3<<(6*2)); *gpfcon |= (0x1<<(6*2)); break; } return 0; } ssize_t led_read(struct file *fp, char __user *c, size_t *t){     int minor = MINOR(fp->f_dentry->d_inode->i_rdev);
    char leds_status;
    switch(minor)
    {
        case 0:
            leds_status = (~((*gpfdat & ((1<<4)|(1<<5)|(1<<6)))>>4))&0x7;
            copy_to_user(buff,(const void *)&leds_status,1);    //将数据从用户拷贝到内核空间
            break;
        case 1:
            leds_status = (~(*gpfdat>>4))&0x1;
            copy_to_user(buff,(const void *)&leds_status,1);
            break;
        case 2:
            leds_status = (~(*gpfdat>>5))&0x1;
            copy_to_user(buff,(const void *)&leds_status,1);
            break;
        case 3:
            leds_status = (~(*gpfdat>>6))&0x1;
            copy_to_user(buff,(const void *)&leds_status,1);
            break;
    } } ssize_t led_write(
struct file *fp, const char __user *buf, size_t count, loff_t *ppos){ int minor = MINOR(fp->f_dentry->d_inode->i_rdev); int val; copy_from_user(&val, buf, 1); switch(minor) { case 0: val &= 0x1; *gpfdat &= ~((1<<4)|(1<<5)|(1<<6)); *gpfdat |= (val<<4)|(val<<5)|(val<<6); break; case 1: *gpfdat &= ~(1<<4); *gpfdat |= (val&0x1)<<4; break; case 2: *gpfdat &= ~(1<<5); *gpfdat |= (val&0x1)<<5; break; case 3: *gpfdat &= ~(1<<6); *gpfdat |= (val&0x1)<<6; break; } } struct file_operations led_fops={ .owner = THIS_MODULE, .open = led_open, .write = led_write, }; int major; static int led_init(void) { int minor; major = register_chrdev( 0,"led_drv", &led_fops );    //当指定的设备号为0时,系统会自动生成一个设备号 led_class = class_create(THIS_MODULE, "my_leds"); if(IS_ERR(led_class)) return PTR_ERR(led_class); led_class_devs[0] = class_device_create(led_class,NULL,MKDEV(major,0),NULL,"my_leds");  //创建设备文件 if(unlikely(IS_ERR(led_class_devs))) return PTR_ERR(led_class_devs); for( minor=1; minor<4; minor++ ) { led_class_devs[minor] = class_device_create(led_class,NULL,MKDEV(major,minor),NULL,"my_led%d",minor); if(unlikely(IS_ERR(led_class_devs))) return PTR_ERR(led_class_devs); } gpfcon = (volatile unsigned long *)ioremap(0x56000050,16);    //物理地址映射为虚拟地址 gpfdat = gpfcon + 1;        printk("led install Module\n"); return 0; } static void led_exit(void) { unregister_chrdev( major, "led_drv" ); class_device_unregister(led_class_devs[0]);    //注销设备文件 class_device_unregister(led_class_devs[1]); class_device_unregister(led_class_devs[2]); class_device_unregister(led_class_devs[3]); class_destroy(led_class);              //销毁类 iounmap(gpfcon);                   //取消物理地址映射 printk("led Module exit\n"); } module_init(led_init); module_exit(led_exit); MODULE_LICENSE("GPL");

模块的Makefile:

obj-m:=led.o
KERNELDIR:=/home/jz2440/linux-2.6.22.6
PWD:=$(shell pwd)
default:
    $(MAKE) -C $(KERNELDIR)  M=$(PWD) modules
clean:
    rm -rf *.o *.mod.c *.mod.o *.ko *.symvers

测试文件:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>

int main( int argc, char **argv )
{
    int fd;
    int val = 1;
    if(argc != 3 )
    {
        printf("please input righ data\n");
        printf("eg:/dev/my_leds <on\"off>\n");
        return 0;
    }
    fd = open(argv[1], O_RDWR);
    if(fd<0)
    {
        printf("open failed\n");
        return 0;
    }
    
    if(strcmp(argv[2],"on")==0)
    {
        val = 0;
    }
    else
    {
        val = 1;
    }
    write(fd, &val, 4);
   read(fd, &val,1);
    printf("led status =%d\n",val);
return 0; }

 完
























以上是关于Linux嵌入式驱动学习之路⑩字符设备驱动-my_led的主要内容,如果未能解决你的问题,请参考以下文章

Linux嵌入式驱动学习之路(十六)输入子系统

Linux嵌入式驱动学习之路按键驱动

Linux嵌入式驱动学习之路(十九)触摸屏驱动

Linux嵌入式驱动学习之路按键驱动-poll机制

嵌入式Linux驱动学习之路(二十六)DM9000C网卡驱动程序

Linux嵌入式驱动学习之路(十五)按键驱动-定时器防抖