//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;
}
阅读(1259) | 评论(1) | 转发(0) |