Chinaunix首页 | 论坛 | 博客
  • 博客访问: 259230
  • 博文数量: 56
  • 博客积分: 1264
  • 博客等级: 中尉
  • 技术积分: 491
  • 用 户 组: 普通用户
  • 注册时间: 2011-07-19 15:16
文章分类

全部博文(56)

文章存档

2012年(10)

2011年(46)

分类: LINUX

2011-07-19 17:03:51

//myled.c
/*-------------------------------------------
开发环境      :Fedora 13 (2.6.33.3-85.fc13.i686)
目标系统      :linux-2.6.14.1
目标板        :致远 Magic 2410
交叉编译工具   :arm-linux-gcc 3.4.1
作者             :chockly@126.com
时间          :2010.9.16
---------------------------------------------*/
#include
#include
#include
//#include "linux/uaccess.h"
//#include "linux/io.h"
#include "asm/io.h"

//目标板 GPECON GPEDAT 物理地址
#define Phy_Addr_GPECON 0x56000040
#define Phy_Addr_GPEDAT 0x56000044

#define LED_ON    1
#define LED_OFF    0

MODULE_LICENSE("GPL");
MODULE_AUTHOR("chockly@126.com");

struct led_dev
{
    struct cdev cdev;
    dev_t dev;
};

static long *pGPECON;
static long *pGPEDAT;

static struct led_dev myled;

static int led_open(struct inode *inode, struct file *file)
{
    printk(KERN_INFO "led_open ok.\n");
    return 0;
}
static int led_close(struct inode *inode, struct file *file)
{
    printk(KERN_INFO "led_close ok.\n");
    return 0;
}
static int led_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
    switch(cmd)
    {
        case LED_ON:
            *pGPECON =(*pGPECON & (~(0x0F<<22))) | (0x05<<22);//设置GPE11、GPE12输出模式
            *pGPEDAT = *pGPEDAT | (0x03<<11);  //置GPE11,GPE12高电平
            printk(KERN_INFO "led_on ok.\n");
            break;
        case LED_OFF:
            *pGPECON =(*pGPECON & (~(0x0F<<22))) | (0x05<<22);//设置GPE11、GPE12输出模式
            *pGPEDAT = *pGPEDAT & (~(0x03<<11)); //置GPE11,GPE12低电平
            printk(KERN_INFO "led_off ok.\n");
            break;
        default:
            break;
    }

    return 0;
}

static struct file_operations led_fops=
{
    .owner        =    THIS_MODULE,
    .open        =    led_open,
    .release    =    led_close,   
    .ioctl        =    led_ioctl,
};
static __init int led_init(void)
{
    int err;
    //设备注册
    if((err=alloc_chrdev_region(&myled.dev, 0, 1, "myled"))<0)
    {
        printk(KERN_INFO "led_init: alloc_chrdev_region() err=%d!\n",-err);
        goto alloc_chrdev_region_fail;
    }
    //printk(KERN_INFO "led_init dev(%d,%d)!\n",MAJOR(myled.dev),MINOR(myleg.dev));

    //从物理地址转换到内存虚地址
    pGPECON=(void*)ioremap(Phy_Addr_GPECON,sizeof(long));
    if(pGPECON==NULL)
    {
        printk(KERN_INFO "pGPECON_ioremap_failed!\n");
        goto pGPECON_ioremap_fail;
    }
    pGPEDAT=(void*)ioremap(Phy_Addr_GPEDAT,sizeof(long));
    if(pGPEDAT==NULL)
    {
        printk(KERN_INFO "pGPEDAT_ioremap_failed!\n");
        goto pGPEDAT_ioremap_fail;
    }

    cdev_init(&myled.cdev, &led_fops);
    myled.cdev.owner=led_fops.owner;

    if((err=cdev_add(&myled.cdev, myled.dev, 1))<0)
    {
        printk(KERN_INFO "led_init: cdev_add() err=%d!\n", -err);
        goto cdev_add_fail;
    }
    printk(KERN_INFO "led_init ok.\n");
    return 0;
   
cdev_add_fail:
    iounmap(pGPEDAT);
pGPEDAT_ioremap_fail:
    iounmap(pGPECON);
pGPECON_ioremap_fail:
    unregister_chrdev_region(myled.dev,1);
alloc_chrdev_region_fail:
    return err;
}
static __exit void led_exit(void)
{
    cdev_del(&myled.cdev);
    unregister_chrdev_region(myled.dev,1);
   
    iounmap(pGPEDAT);
    iounmap(pGPECON);
   
    printk(KERN_INFO "led_exit ok.\n");
}

module_init(led_init);
module_exit(led_exit);

//Makefile
ifeq ($(KERNELRELEASE),)
KERNELDIR ?= /usr/src/linux-2.6.14.1

PWD:=$(shell pwd)

modules:
    $(MAKE) -C $(KERNELDIR) M=$(PWD) modules

modules_install:
    $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install

clean:
    -rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions

.PHONY:modules modules_install clean

else
    obj-m:=myled.o
endif

//测试 myled_test.c
#include
#include
#include
#include
#include

#define LED_ON    1
#define LED_OFF    0
int main()
{
    /*FILE *fp;
    int c;
    fp=fopen("/dev/myled","w");
    c=getchar();
    fclose(fp);
    */
    char c;
    int fd;
    fd=open("/dev/myled",O_RDWR);
    c=getchar();
    while('a'!=c)
    {
        //scanf("%c",&c);
        switch(c)
        {
            case 'n':
                ioctl(fd, LED_ON, NULL);
                break;
            case 'f':
                ioctl(fd, LED_OFF, NULL);
                break;
            default:
                break;
        }
        //c=getchar();
        scanf("%c",&c);
    }
    close(fd);
    return 0;
}
阅读(1344) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~