• 嵌入式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 "); 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 "); } 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
    ");
            printf("eg:/dev/my_leds <on"off>
    ");
            return 0;
        }
        fd = open(argv[1], O_RDWR);
        if(fd<0)
        {
            printf("open failed
    ");
            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 ",val);
    return 0; }

     完

  • 相关阅读:
    IP地址与域名的关系
    微信公众平台开发
    jquery实现对div的拖拽功能
    js控制表格实时编辑
    删除提示框插件
    基于jquery的bootstrap在线文本编辑器插件Summernote (转)
    从输入网址到显示网页的过程中发生了什么?
    TP框架---thinkphp中ajax分页
    使背景图片适应不同分辨率电脑
    TP框架---验证码
  • 原文地址:https://www.cnblogs.com/ynxf/p/5995419.html
Copyright © 2020-2023  润新知