当前位置: 代码迷 >> 综合 >> 01_字符设备驱动初体验
  详细解决方案

01_字符设备驱动初体验

热度:114   发布时间:2023-10-24 01:06:00.0

一:驱动基本框架

1:创建入口函数demo_init()和出口函数demo_exit()并用module_init(),module_exit(),MODULE_LICENSE("GPL")函数进行注册

二:填充驱动框架

1:入口函数中注册设备register_chrdev(),创建类class_create()以及设备节点class_device_create()

2:创建入口函数中“注册设备”时所需的file_operations结构体demo_fops

    static struct file_operations demo_fops

3:出口函数中删除设备节点class_device_unregister(),类class_destroy(),注销设备unregister_chrdev()

4:在file_operations中对应的接口函数中实现对硬件的操作

三:源码

1:drv.c

#include <linux/module.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <linux/poll.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/arch/regs-gpio.h>
#include <asm/hardware.h>static struct class *demo_class;
static struct class_device *demo_class_dev;// gpf0,2
volatile unsigned long *gpfcon;
volatile unsigned long *gpfdat;
// gpg3,11
volatile unsigned long *gpgcon;
volatile unsigned long *gpgdat;static struct timer_list key_timer;static DECLARE_WAIT_QUEUE_HEAD(irq_waitq);
static volatile int ev_press = 0;static struct fasync_struct *signal_fasync;struct pin_desc{unsigned int pin;unsigned int key_val;
};struct pin_desc pins_desc[3] = {{S3C2410_GPF0,  0x01},{S3C2410_GPF2,  0x02},{S3C2410_GPG3,  0x03}, 
};static struct pin_desc *irq_pd;#if 0   //定义原子操作
static atomic_t canopen = ATOMIC_INIT(1);
#else   //定义互斥锁
static DECLARE_MUTEX(key_lock);
#endifstatic unsigned char key_val;static irqreturn_t keys_irq(int irq, void *dev_id)
{irq_pd = (struct pin_desc *)dev_id;mod_timer(&key_timer, jiffies+HZ/100);// jiffies + 10msreturn IRQ_RETVAL(IRQ_HANDLED);
}static int demo_open(struct inode *inode, struct file *file)
{
//申请资源
#if 0if(!atomic_dec_and_test(&canopen)){atomic_inc(&canopen);return -EBUSY;}
#elseif(file->f_flags & O_NONBLOCK)// 非阻塞,获取不到资源则立即返回{if(down_trylock(&key_lock))return -EBUSY;}else{down(&key_lock);    }
#endifrequest_irq(IRQ_EINT0,  keys_irq, IRQT_BOTHEDGE, "s2", &pins_desc[0]);request_irq(IRQ_EINT2,  keys_irq, IRQT_BOTHEDGE, "s3", &pins_desc[1]);request_irq(IRQ_EINT11, keys_irq, IRQT_BOTHEDGE, "s4", &pins_desc[2]);return 0;
}ssize_t demo_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
{if(size != 1)return -EINVAL;if(file->f_flags & O_NONBLOCK)    {if(!ev_press)return -EAGAIN;}else{/* 判断是否有按键按下并进行休眠选择 */wait_event_interruptible(irq_waitq, ev_press);}copy_to_user(buf, &key_val, 1);ev_press = 0;return 1;
}int demo_release(struct inode *inode, struct file *file)
{
//释放资源
#if 0atomic_inc(&canopen);
#elseup(&key_lock);
#endiffree_irq(IRQ_EINT0,  &pins_desc[0]);free_irq(IRQ_EINT2,  &pins_desc[1]);free_irq(IRQ_EINT11, &pins_desc[2]);return 0;
}static unsigned int demo_poll(struct file *file, struct poll_table_struct *wait)
{   //sys_pollunsigned int mask = 0;poll_wait(file, &irq_waitq, wait);if(ev_press)mask |= POLLIN | POLLRDNORM;return mask;    
}static int demo_fasync(int fd, struct file *filp, int on)
{printk("driver: demo_fasync\n");return fasync_helper (fd, filp, on, &signal_fasync);
}static struct file_operations demo_fops = 
{.owner   = THIS_MODULE,.open    = demo_open,.read    = demo_read,.release = demo_release,.poll    = demo_poll,.fasync  = demo_fasync,
};int major;
static void key_timer_fun(unsigned long time)
{struct pin_desc *pindesc = irq_pd;unsigned int pinval;if(!pindesc)return;pinval = s3c2410_gpio_getpin(pindesc->pin);if(pinval){key_val = 0x80 | pindesc->key_val;}else{key_val = pindesc->key_val;}ev_press = 1;wake_up_interruptible(&irq_waitq);kill_fasync(&signal_fasync, SIGIO, POLL_IN);
}static int demo_init(void)
{init_timer(&key_timer);key_timer.function = key_timer_fun; add_timer(&key_timer);major = register_chrdev(major, "demo_drv", &demo_fops);demo_class = class_create(THIS_MODULE, "demo_class");demo_class_dev = class_device_create(demo_class, NULL, MKDEV(major, 0), NULL, "demo");//    gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16);
//    gpfdat = gpfcon + 1;//    gpgcon = (volatile unsigned long *)ioremap(0x56000060, 16);
//    gpgdat = gpgcon + 1;return 0;
}static void demo_exit(void)
{class_device_unregister(demo_class_dev);class_destroy(demo_class);unregister_chrdev(major, "demo_drv");//    iounmap(gpfcon);
//    iounmap(gpgcon);
}module_init(demo_init);
module_exit(demo_exit);MODULE_LICENSE("GPL");

2:test.c

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <poll.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>int fd;void signal_fun(int signum)
{unsigned char key_val;read(fd, &key_val, 1);printf("key_val: 0x%x\n", key_val);
}int main(int argc, char **argv)
{unsigned char key_val;int ret;int oflags;signal(SIGIO, signal_fun);//	fd = open("/dev/demo", O_RDWR | O_NONBLOCK);fd = open("/dev/demo", O_RDWR);if (fd < 0){printf("can't open!\n");return -1;}fcntl(fd, F_SETOWN, getpid()); //告诉内核oflags = fcntl(fd, F_GETFL);fcntl(fd, F_SETFL, oflags | FASYNC);//改变fasync,会调用驱动中的fasync函数指针对应的函数。while (1){   read(fd, &key_val, 1);printf("key_val: 0x%x\n", key_val);sleep(5);}return 0;
}

  相关解决方案