V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Distributions
Ubuntu
Fedora
CentOS
中文资源站
网易开源镜像站
logbang
V2EX  ›  Linux

自己写的简单的字符设备驱动,不能实现功能,搞不懂,求帮忙分析找错

  •  
  •   logbang · 2015-03-02 18:29:56 +08:00 · 2202 次点击
    这是一个创建于 3558 天前的主题,其中的信息可能已经有所发展或是发生改变。

    问题在帖子的最后。先贴代码:

    驱动的pressure.c:

    /*
    功能:
    外部中断4接一个人体红外感应,默认感应到有人体,如果人MISS了,低电平触发外
    部中断,此时nLED_2(GPB6)亮,并且打印BABY MISS !!!
    */

    include <linux/module.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 <linux/device.h>

    include <linux/interrupt.h>

    include <asm/uaccess.h>

    include <asm/irq.h>

    include <asm/io.h>

    include <asm/arch/regs-gpio.h>

    include <asm/hardware.h>

    volatile unsigned long *gpbcon = NULL; // nLED_2(GPB6)
    volatile unsigned long *gpbdat = NULL;
    volatile unsigned long *gpfcon = NULL; // EINT4 ( GPF4 )
    volatile unsigned long *gpfdat = NULL;
    volatile unsigned long *eintmask = NULL;
    volatile unsigned long *eintpend = NULL;

    unsigned int val = 0;

    static struct class *pressuredrv_class;
    static struct class_device *pressuredrv_class_dev;

    //等待队列
    static DECLARE_WAIT_QUEUE_HEAD(pressure_waitq);

    /* 中断事件标志, 中断服务程序将它置1,pressure_read将它清0 */
    static volatile int ev_press = 0;

    static irqreturn_t pressure_irq(int irq, void dev_id)
    {
    //((*eintpend) & (1<<4)) = 1;
    val = (*eintpend) & (1<<4); //读取EINTPEND寄存器的第4位的值
    while (!val); //如果标志位置1
    ev_press = 1; /
    表示中断发生了 /
    wake_up_interruptible(&pressure_waitq); /
    唤醒休眠的进程 */
    return IRQ_RETVAL(IRQ_HANDLED);
    }

    static int pressure_open(struct inode inode, struct file *file)
    {
    *gpbcon &= ~(0x3<<(06*2)); /
    配置GPB6为输出引脚 */

    *gpbcon |= (0x1<<(06*2));
    *eintmask &= ~(0x1<<4); //把EINTMASK的第4位设为0,使能中断
    request_irq(IRQ_EINT4, pressure_irq, IRQT_LOW, "PRESSURE", NULL); //设置外部中断4
    return 0;
    }

    static int pressure_read(struct file file, char __user *buf, size_t size, loff_t *ppos)
    {
    /*如果没有检测到外部中断4,休眠
    /
    wait_event_interruptible(pressure_waitq, ev_press);

    /*如果有外部中断,返回val值*/
        copy_to_user(buf, val, 1);
        ev_press = 0;  
        return 0;
    

    }

    static ssize_t pressure_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
    {
    int con = 0;
    copy_from_user(&con,buf,1);
    if (con == 1)
    {
    //亮灯报警
    *gpbdat &= ~(1<<6);
    }
    else
    {
    //灭灯
    *gpbdat |= (1<<6);
    }
    }

    static ssize_t pressure_close(struct inode *inode, struct file *file)
    {
    free_irq(IRQ_EINT4, NULL);
    return 0;
    }

    static struct file_operations pressure_drv_fops = {
    .owner = THIS_MODULE,
    .open = pressure_open,
    .read = pressure_read,

    .release = pressure_close,

    };

    int major;
    static int __init pressure_drv_init(void)
    {

    major = register_chrdev(0, "pressure_drv", &pressure_drv_fops);
        pressuredrv_class = class_create(THIS_MODULE, "pressure_drv");
        pressuredrv_class_dev = class_device_create(pressuredrv_class, NULL, MKDEV(major, 0), NULL, "PressureDrv");
        gpbcon = (volatile unsigned long *)ioremap(0x56000010, 16);
        gpbdat = gpbcon + 1;
        gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16);
        gpfdat = gpbcon + 1;
        eintmask = (volatile unsigned long *)ioremap(0x560000A4, 8);
        eintpend = (volatile unsigned long *)ioremap(0x560000A8, 8);
        return 0;
    

    }

    static void __exit pressure_drv_exit(void)
    {

    unregister_chrdev(major, "pressure_drv");
    class_device_unregister(pressuredrv_class_dev);
    class_destroy(pressuredrv_class);
    iounmap(gpbcon);
    iounmap(gpfcon);
    iounmap(eintmask);
    iounmap(eintpend);
    }

    module_init(pressure_drv_init);
    module_exit(pressure_drv_exit);

    MODULE_LICENSE("GPL");

    应用程序的app.c :

    include <sys/types.h>

    include <sys/stat.h>

    include <fcntl.h>

    include <stdio.h>

    include <poll.h>

    int main(int argc, char **argv)
    {
    int fd;
    int con = 0;
    int val = 0;

    fd = open("/dev/PressureDrv",O_RDWR);
        if (fd < 0)
        {
                printf("can't open!\n");
        }
        while (1);
        {
                read(fd,val,1);
                if (val) //val是eintpend第4位的值,如果被置1,表明有中断发生
                {
                        printf("BABY MISS !!!\n");
                        con = 1;  //;亮灯报警
                }
                else
                {
                        con = 0;  //不报警
                        //printf("HELLO !!!\n");
                }
        }
    

    }

    现在的问题是我加载了模块,并且运行了应用程序之后,灯马上就亮了,一直亮不会灭,而且没有任何打印信息输出

    Panic
        1
    Panic  
       2015-03-02 19:18:27 +08:00
    while(1) 后面有分号, 大bug
    jesse_luo
        2
    jesse_luo  
       2015-03-02 21:53:12 +08:00
    @Panic 哈哈哈一语中的

    另外 lz 最好放在 github 或者 gist 上,太难看了……
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1205 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 23:23 · PVG 07:23 · LAX 15:23 · JFK 18:23
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.