cdev设备 字符设备驱动例子

发布时间 2023-04-01 03:15:35作者: lydstory
#include <linux/init.h>
#include <linux/module.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/uaccess.h>
#include <linux/fcntl.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/signal.h>
#include <asm-generic/siginfo.h>

#define NAME "cdev_demo"
#define COUNT 3
#define KBUFSIZE 64
#define GPIOA28 28


dev_t dev_no;
struct cdev *cdevp = NULL;
struct class *cls = NULL;
struct device *devp = NULL;


char Kbuf[KBUFSIZE] = {'\0'};
int Kbufcount = 0;
int irq_a28 = 0;
struct fasync_struct *fasync;



irqreturn_t key_irq_handler(int irqno, void *args)
{
    kill_fasync(&fasync,SIGIO,POLL_IN);
    printk(KERN_DEBUG "[%s-%s-%d]:Interrupt...\n",\
                __FILE__,__func__,__LINE__);
    return IRQ_HANDLED;
}


static int demo_open(struct inode *inode, struct file *filp)
{
    printk(KERN_DEBUG "[%s-%s-%d]: runned...\n",__FILE__,__func__,__LINE__);
    return 0;
}
    
static int demo_release(struct inode *inode, struct file *filp)
{
    printk(KERN_DEBUG "[%s-%s-%d]: runned...\n",\
            __FILE__,__func__,__LINE__);
    return 0;
}

ssize_t demo_read(struct file *filp, char __user *buf, size_t size, loff_t *pos)
{
    if(size > Kbufcount){
        size = Kbufcount;
    }

    if(copy_to_user(buf, Kbuf, size)){
        printk(KERN_ERR "[%s-%s-%d]: copy_to_user failed...\n",\
            __FILE__,__func__,__LINE__);
        return -EAGAIN;
    }
    Kbufcount = 0;
    printk(KERN_DEBUG "[%s-%s-%d]: runned...\n",\
            __FILE__,__func__,__LINE__);
    
    return size;    
}

ssize_t demo_write(struct file *filp, const char __user *buf, size_t size, loff_t *pos)
{
    if(size > KBUFSIZE){
        size = KBUFSIZE;
    }

    if(copy_from_user(Kbuf,buf, size)){
        printk(KERN_ERR "[%s-%s-%d]: copy_from_user failed...\n",\
            __FILE__,__func__,__LINE__);
        return -EAGAIN;
    }
    Kbufcount = size;
    printk(KERN_DEBUG "[%s-%s-%d]: Kbuf:%s...\n",\
            __FILE__,__func__,__LINE__,Kbuf);
    
    return size;
}

int demo_fasync(int fd, struct file *filp, int on)
{
    return fasync_helper(fd, filp, on , &fasync);
}


struct file_operations fops = {
    .owner   = THIS_MODULE,
    .open      = demo_open,
    .release = demo_release,
    .read    = demo_read,
    .write   = demo_write,
    .fasync  = demo_fasync,
};

static int __init demo_init(void)
{
    int ret = 0 ,i = 0;
    
    //0、申请设备号
    ret = alloc_chrdev_region(&dev_no, 0 , COUNT , NAME);
    if(ret < 0){
        printk(KERN_ERR "[%s-%s-%d]:alloc_chrdev_region failed...\n",\
            __FILE__,__func__,__LINE__);
        goto err0;
    }
    printk(KERN_DEBUG "[%s-%s-%d]:devno->major:%d--minor:%d--...\n",\
            __FILE__,__func__,__LINE__,MAJOR(dev_no),MINOR(dev_no));
    //1、分配cdev结构体
    cdevp = cdev_alloc();
    if(cdevp == NULL){
        printk(KERN_ERR "[%s-%s-%d]:cdev_alloc failed...\n",\
            __FILE__,__func__,__LINE__);    
        ret = -ENOMEM;
        goto err1;
    }
    
    //2、初始化cdev结构体
    cdev_init(cdevp, &fops);
    
    //3、添加到内核中,由内核统一管理
    ret = cdev_add(cdevp, dev_no, COUNT);
    if(ret < 0){
        goto err1;
    }


    //4、class create
    cls = class_create(THIS_MODULE,NAME);
    if(IS_ERR(cls)){
        printk(KERN_ERR "[%s-%s-%d]:class_create...\n",\
            __FILE__,__func__,__LINE__);
        ret = PTR_ERR(cls);
        goto err2;
    }

    //5、device create
    for(i = 0 ; i < COUNT ; i++){
        devp = device_create(cls, NULL , MKDEV(MAJOR(dev_no),i) , NULL, "%s%d",NAME,i);
        if(IS_ERR(devp)){
            printk(KERN_ERR "[%s-%s-%d]:device_create[%d]...\n",\
                __FILE__,__func__,__LINE__,i);
            ret = PTR_ERR(devp);
            goto err3;
        }
    }

    irq_a28 = gpio_to_irq(GPIOA28);
    if(irq_a28 < 0){
        printk(KERN_ERR "[%s-%s-%d]:call failed...\n",\
                __FILE__,__func__,__LINE__);
        ret = irq_a28;
        goto err3;
    }

    ret = request_irq(irq_a28,key_irq_handler,IRQF_TRIGGER_FALLING,"gpioa28_key", NULL);
    if(ret < 0){
        printk(KERN_ERR "[%s-%s-%d]:call failed...\n",\
                __FILE__,__func__,__LINE__);
        goto err3;
    }
    
    return 0;

err3:
    for(--i;i>=0;i--){
        device_destroy(cls,MKDEV(MAJOR(dev_no),i));
    }
    class_destroy(cls);
err2:
    cdev_del(cdevp);
err1:
    unregister_chrdev_region(dev_no, COUNT);
err0:
    return ret;
    
}

static void __exit demo_exit(void)
{

    int i = 0;
    free_irq(irq_a28, NULL);
    for(i=0;i < COUNT;i++){
        device_destroy(cls,MKDEV(MAJOR(dev_no),i));
    }
    class_destroy(cls);

    //cdev从内核中删除
    cdev_del(cdevp);
    //设备号资源释放
    unregister_chrdev_region(dev_no, COUNT);
}

module_init(demo_init);
module_exit(demo_exit);
MODULE_LICENSE("GPL");

 

KDIR:=/home/edu/SAMBA_SHARE/BK2101/Driver/03_kernel/kernel-3.4.39
#KDIR:= /lib/modules/`uname -r`/build
PWD := $(shell pwd)

obj-m += demo.o

modules:
	make -C $(KDIR) M=$(PWD)  modules
	#cp *.ko ~/rootfs/home
clean:
	make -C $(KDIR) M=$(PWD) clean 

  

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

char buf[32];

fd_set r_fds;


void sig_callback(int sig)
{
    printf("sig callback...\n");
}

int main(int argc, const char *argv[])
{
    int ret = 0;

    signal(SIGIO, sig_callback);

    int fd = open("/dev/cdev_demo0",O_RDWR);
    if(fd < 0){
        perror("open");
        return -1;
    }

    fcntl(fd,F_SETOWN,getpid());
    fcntl(fd,F_SETFL,fcntl(fd,F_GETFL)|FASYNC);


    while(1){
        
    }
    
    //close(fd);

    return 0;
}