Chinaunix首页 | 论坛 | 博客
  • 博客访问: 724670
  • 博文数量: 105
  • 博客积分: 3532
  • 博客等级: 中校
  • 技术积分: 1328
  • 用 户 组: 普通用户
  • 注册时间: 2010-04-20 18:57
文章分类

全部博文(105)

文章存档

2015年(1)

2014年(1)

2013年(7)

2012年(14)

2011年(21)

2010年(61)

分类: 嵌入式

2010-08-28 14:05:23

  1. 操作系统:linux-2.6.34
    硬件平台:pw2440(cpu is s3c2440)
    编译器:arm-none-eabi-gcc v4.4.1
  2. 电路,只针对被红圈圈起来部分
  3. code1:一个公用头文件 ypublic.h

    #ifndef __Y_PUBLIC__
    #define __Y_PUBLIC__

    #include <linux/ioport.h>
    #include <linux/timer.h>

    #include <asm/io.h>

    #define SETB(n) (1<<(n))
    #define CLRB(n) (~ SETB(n))
    #define SETN(v,n) (v<<n)

    //#define MS(n) (HZ*(n)/1000)

    #define PI 3.1415927
    #define uint unsigned int
    #define uchar unsigned char
    #define ulong unsigned long
    #define byte uchar

    //io

    #define Y2440_IO_IN 0
    #define Y2440_IO_OUT 1
    #define Y2440_IO_EINT 2
    #define Y2440_IO_OUT_H 1
    #define Y2440_IO_OUT_L 0

    #define SETNB(v,d,n,w) \
        ({\
        unsigned long rs;\
        unsigned int v1=v;\
        unsigned int d1=d;\
        unsigned int n1=n;\
        unsigned int w1=w;\
        rs=0xffffffff;\
        rs=rs<<(32-n1-w1);\
        rs=rs>>(32-w1);\
        rs=~(rs<<n1);\
        rs=d&rs|(v1<<n1);\
        rs;\
        })

    uint setNB(uint v,uint d,uint n,uint w)
    {
        uint rs;
        rs=0xffffffff;
        rs=rs<<(32-n-w);
        rs=rs>>(32-w);
        rs=~(rs<<n);
        rs=(d&rs)|(v<<n);
        return rs;
    }
    static void* yioremap(ulong start,ulong n,char name[])
    {
        if(request_mem_region(start,n,name)==NULL)return NULL;
        return ioremap(start,n);
    }

    static void yiounmap(ulong start,ulong n)
    {
        iounmap((void*)start);
        release_mem_region(start,n);
    }

    static ulong fortimems(ulong ms)
    {
        return (jiffies+HZ*ms/1000);
    }

    #define MS(n) fortimems(n)
    #endif

  4. code2:按键驱动 我取名为 uart.c

    #include <linux/module.h>
    #include <linux/init.h>
    #include <linux/cdev.h>
    #include <linux/ioport.h>
    #include <linux/fs.h>
    #include <linux/slab.h>
    #include <linux/interrupt.h>

    #include <mach/irqs.h>

    #include <asm/io.h>
    #include "ypublic.h"

    MODULE_LICENSE("Dual BSD/GPL");
    #define YMAJOR 100
    #define YMINOR 1
    #define YDEVICENAME "keydriver"
    #define YBUFSIZE 10
    #define UBRDIVn(baud) ()


    //io

    #define UARTBASE(n) (0x50000000+(0x00004000<<(n)))
    #define UARTREGNUM 3
    #define YUART0 UARTBASE(0)
    #define YUART1 UARTBASE(1)
    #define YUART2 UARTBASE(2)
    #define YINFRARED_MODE SETB(6)
    #define YNOPARITY 0
    #define Y2STOPBIT SETB(2)
    #define Y8BITS SETN(3,0)



    typedef struct{
        ulong ULCON;
        ulong UCON;
        ulong UFCON;
        ulong UMCON;
        ulong UTRSTAT;
        ulong UERSTAT;
        ulong UFSTAT;
        ulong UMSTAT;
        ulong UTXH;
        ulong URXH;
        ulong UBRDIV;
    }YRUart;

    typedef struct {
        struct cdev dev;
        uchar inbuf[YBUFSIZE];
        uchar outbuf[YBUFSIZE];
    }ycdev;

    uint _pst;//记录按键的之前的状态

    ycdev *_pdev;
    static int _major=YMAJOR;
    YRUart *_uart;
    static struct timer_list _tm;

    //io regs

    #define GPBBASE 0x56000010
    #define GPGBASE 0x56000060
    ulong rgpbcon,rgpbdat,rgpbup;
    ulong rgpgcon,rgpgdat,rgpgup;

    void setIoConf(uint func,uint ionum,uint reg)
    {
        //set gpio function model

        
        uint dat =ioread32(reg);
        dat=setNB(func,dat,ionum*2,2);
        iowrite32(dat,reg);
    }

    static void* initio(void)
    {
        if(request_mem_region(UARTBASE(0),sizeof(YRUart),"UART")==NULL)
            return NULL;
        _uart=(YRUart *)ioremap(UARTBASE(0),sizeof(YRUart));
        return (void*)_uart;
    }

    void releaseio(void)
    {
    #if 1
        if(_uart!=NULL){
            iounmap((void*)UARTBASE(0));
            release_mem_region(UARTBASE(0),sizeof(YRUart));
        }
        #endif
    }

    static irqreturn_t onIrq(int irq,void *dev_id)
    {
        //interrupt service function,disable current irq,and elimination of button's jitter

        disable_irq_nosync((uint)dev_id);
        _tm.expires=MS(20);
        add_timer(&_tm);
        
        return IRQ_HANDLED;
    }

    void initUart(void)
    {
        iowrite32(Y8BITS,&_uart->ULCON);
    }

    static void onTime(ulong arg)
    {
    #if 0
        uint dat;
        dat=ioread32(rgpbdat);
        if(dat&SETB(10)){
            iowrite32((~(SETB(7)|SETB(10)))&dat,rgpbdat);
            }
        else{
            iowrite32(SETB(7)|SETB(10)|dat,rgpbdat);
            }
        _tm.expires=MS(2000);
        add_timer(&_tm);
    #else
        
        setIoConf(Y2440_IO_IN,8,rgpgcon);
        if((ioread32(rgpgdat)&SETB(8))==0){
            //have a key down

            
            //set another io output height

            iowrite32(SETB(11)|ioread32(rgpgdat),rgpgdat);
            //should be true

            if(ioread32(rgpgdat)&SETB(8)){
                printk(KERN_INFO "have key down\n");
                _pst=1;
                _tm.expires=MS(100);
                add_timer(&_tm);

            }
            //have a expect

            else printk(KERN_ERR "error 2\n");
            //set another io output low

            iowrite32(CLRB(11)&ioread32(rgpgdat),rgpgdat);

        }
        else{
            //key up

            
            if(_pst==1){
                _pst=0;
                printk(KERN_INFO "have key up\n");
            }
            else printk(KERN_INFO "error 3\n");
            setIoConf(Y2440_IO_EINT,8,rgpgcon);
            enable_irq(IRQ_EINT16);    
        }            
    #endif
    }

    int yopen(struct inode *pinode,struct file *pfile)
    {
        return 0;
    }

    int yrelease(struct inode *pinode,struct file *pfile)
    {
        return 0;
    }

    static struct file_operations _fops={
        .open=yopen,
        .release=yrelease,
    };

    int __init yinit(void)
    {
        dev_t devno=MKDEV(YMAJOR,YMINOR);
        int rs;
        uint tmp;
        if(_major){
                rs=register_chrdev_region(devno,1,YDEVICENAME);
            }
        else{
            rs=alloc_chrdev_region(&devno,YMINOR,1,YDEVICENAME);
            _major=MAJOR(devno);
            }
        if(rs<0)return rs;
        _pdev=kmalloc(sizeof(ycdev),GFP_KERNEL);
        if(!_pdev){
            
            rs= -ENOMEM;
            goto fail1;
            }
        cdev_init(&_pdev->dev,&_fops);
        _pdev->dev.owner=THIS_MODULE;
        rs=cdev_add(&_pdev->dev,MKDEV(_major,YMINOR),0);
        if(rs){
            rs=-EBUSY;
            goto fail2;
            }
    #if 0
        if(initio()==NULL)
            printk(KERN_ERR"ioremap failed\n");
        else printk(KERN_ERR"ioremap success\n");
    #endif
        //get GPIO register's base address

        rgpbcon=(ulong)yioremap(GPBBASE,12,"gpbreg");
        rgpgcon=(ulong)yioremap(GPGBASE,12,"gpgreg");
        if(rgpbcon==0||rgpgcon==0)goto fail2;
        else{
            rgpbdat=rgpbcon+4;
            rgpbup=rgpbcon+8;
            
            //turn off two led

            setIoConf(Y2440_IO_OUT,7,rgpbcon);
            setIoConf(Y2440_IO_OUT,10,rgpbcon);
            iowrite32(SETB(7)|SETB(10)|ioread32(rgpbup),rgpbup);
            iowrite32(SETB(7)|SETB(10)|ioread32(rgpbdat),rgpbdat);
            
            rgpgdat=rgpgcon+4;
            rgpgup=rgpgcon+8;
            //config number 8 io to interrupt model,11 io to output model

            setIoConf(Y2440_IO_EINT,8,rgpgcon);
            setIoConf(Y2440_IO_OUT,11,rgpgcon);
            iowrite32(SETB(8)|SETB(11)|ioread32(rgpgup),rgpgup);
            iowrite32(CLRB(11)&ioread32(rgpgdat),rgpgdat);
            rs=request_irq(IRQ_EINT16,onIrq,IRQF_DISABLED,"IRQ16",(void *)(IRQ_EINT16));
            if(rs)printk(KERN_INFO"irq failed");
            }

        //init io's pre-state and timer

        _pst=0;
        setup_timer(&_tm,onTime,IRQ_EINT16);
        
        printk(KERN_INFO "driver ok\n");
        return 0;
    fail2:
        printk(KERN_ERR "fail2\n");
        kfree(_pdev);
    fail1:
        printk(KERN_ERR "fail1\n");
        unregister_chrdev_region(devno,1);
        return -EBUSY;
    }

    void __exit yexit(void)
    {
        del_timer(&_tm);
        yiounmap(GPBBASE,12);
        cdev_del(&_pdev->dev);
        kfree(_pdev);
        unregister_chrdev_region(MKDEV(_major,YMINOR),1);
    }

    MODULE_AUTHOR("MrY");
    module_init(yinit);
    module_exit(yexit);


  5. 结果:
    挂载驱动,然后按下上面的被红圈的按键
阅读(1100) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~