實現了對s3c6410開發板led燈的控制
led_dev.c:
#include<linux/init.h>
#include<linux/module.h>
#include<linux/platform_device.h>
#include<linux/device.h>
#define DEVICE_NAME "tiny6410_leds"
static struct resource tiny6410_leds_resource[] = {
[0] = {
.start = 0x7f008800,
.end = 0x7f008800 + 16, //16字節,包括gpkcon0,gpkcon1,gpkdat,gpkpud
.flags = IORESOURCE_MEM,
},
};
static void tiny6410_leds_platform_device_release(struct device *dev)
{
printk("[remove platform_device]\n");
return ;
}
//初始化,並添加資源
static struct platform_device tiny6410_leds_platform_device = {
.name = DEVICE_NAME,
.id = -1, //表示同名的驅動只有一個
.num_resources = ARRAY_SIZE(tiny6410_leds_resource),
.resource = tiny6410_leds_resource,
.dev = {
.release = tiny6410_leds_platform_device_release,
},
};
static int __init tiny6410_leds_platform_device_init(void)
{
printk("[tiny6410_leds_platform_device init]\n");
return platform_device_register(&tiny6410_leds_platform_device); // >0表示添加platform_device失敗
}
static void __exit tiny6410_leds_platform_device_exit(void)
{
printk("[tiny6410_leds_platform_device exit]\n");
platform_device_unregister(&tiny6410_leds_platform_device);
}
module_init(tiny6410_leds_platform_device_init);
module_exit(tiny6410_leds_platform_device_exit);
MODULE_AUTHOR("ZHYANG");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("tiny6410_leds_platform_device");
led_drv.c:
#include<linux/init.h>
#include<linux/module.h>
#include<linux/fs.h>
#include<linux/platform_device.h>
#include<linux/miscdevice.h>
#include<linux/device.h>
#include<linux/pci.h>
#include<linux/uaccess.h>
#define DEVICE_NAME "tiny6410_leds"
// static struct class *tiny6410_leds_class = NULL; //miscdevice會自動創建設備節點,手動申請設備號會用到
// static struct device *tiny6410_leds_device = NULL; //這邊佔不演示
// 方法:在__init函數中先class_create,再device_create
// 在__exit中先device_destroy,再class_destroy
static volatile unsigned long *gpkcon0 = NULL;
static volatile unsigned long *gpkdat = NULL;
static int tiny6410_leds_open(struct inode *inode,struct file *filp)
{
unsigned long tmp;
//配置GPKCON0的GPK4-GPK7位爲0001輸出
tmp = readl(gpkcon0);
tmp = (tmp & ~(0xffff << 16)) | (0x1111 << 16);
writel(tmp,gpkcon0);
//初始化GPK4-GPK7爲1,即燈滅
tmp = readl(gpkdat);
tmp |= (0xF << 4);
writel(tmp,gpkdat);
printk("[tiny6410_leds_open]\n");
return 0;
}
static ssize_t tiny6410_leds_write(struct file *filp,const char __user *buf,size_t count,loff_t *ppos)
{
char val; //1或0表示全亮滅
unsigned long tmp;
int ret = copy_from_user(&val,buf,count);
// printk("[val = %c]\n",val);
if(val=='1'){
tmp = readl(gpkdat);
tmp &= ~(0xf << 4);
writel(tmp,gpkdat);
}else{
tmp = readl(gpkdat);
tmp |= 0xf << 4;
writel(tmp,gpkdat);
}
printk("[tiny6410_leds_write]\n");
return ret;
}
//文件操作結構體的初始化
static struct file_operations tiny6410_leds_fops = {
.owner = THIS_MODULE,
.open = tiny6410_leds_open,
.write = tiny6410_leds_write,
};
//雜項設備的初始化
static struct miscdevice tiny6410_leds_miscdevice = {
.minor = MISC_DYNAMIC_MINOR,
.name = DEVICE_NAME, //特殊,name必須這麼指定,因爲Misc會自動創建設備節點
.fops = &tiny6410_leds_fops,
};
static int __devinit tiny6410_leds_platform_driver_probe(struct platform_device *pdev)
{
int ret;
struct resource *res_gpk;
ret = misc_register(&tiny6410_leds_miscdevice);//註冊雜項設備
res_gpk = platform_get_resource(pdev,IORESOURCE_MEM,0); //獲取平臺設備資源0
gpkcon0 = ioremap(res_gpk->start,16); //物理地址到虛擬地址的映射
gpkdat = gpkcon0 + 2;
printk("[tiny6410_leds_platform_driver_probe]\n");
return ret;
}
static int __devexit tiny6410_leds_platform_driver_remove(struct platform_device *pdev)
{
iounmap(gpkcon0); //取消映射
misc_deregister(&tiny6410_leds_miscdevice);//註銷雜項設備
printk("[tiny6410_leds_platform_driver_remove]\n");
return 0;
}
//platform_driver初始化
static struct platform_driver tiny6410_leds_platform_driver = {
.probe = tiny6410_leds_platform_driver_probe,
.remove = tiny6410_leds_platform_driver_remove,
.driver = {
.owner = THIS_MODULE,
.name = DEVICE_NAME,
},
};
static int __init tiny6410_leds_platform_driver_init(void)
{
printk("[tiny6410_leds_platform_driver_init]\n");
return platform_driver_register(&tiny6410_leds_platform_driver); //註冊平臺驅動
}
static void __exit tiny6410_leds_platform_driver_exit(void)
{
printk("[tiny6410_leds_platform_driver_exit]\n");
platform_driver_unregister(&tiny6410_leds_platform_driver); //註銷平臺驅動
}
module_init(tiny6410_leds_platform_driver_init);
module_exit(tiny6410_leds_platform_driver_exit);
MODULE_AUTHOR("ZHYANG");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("tiny6410_leds_platform_driver");
Makefile:
obj-m := led_drv.o led_dev.o
KDIR := /opt/FriendlyARM/mini6410/linux/linux-2.6.38/
all:
make -C $(KDIR) M=$(PWD) modules
clean:
rm -f *.ko *.o *.mod.* *.order *.symvers
測試程序test_led.c:
#include<stdio.h>
#include<fcntl.h>
int main(int argc,char **argv)
{
int fd;
char on; //1亮0滅
if(argc != 2){
printf("usage:./test_led 0|1\n");
return -1;
}
on = *argv[1];
// printf("%c\n",on);
fd = open("/dev/tiny6410_leds",O_RDWR);
if(fd < 0){
printf("open device tiny6410_leds failed\n");
return -1;
}
if(write(fd,&on,1) == 0) //0表示成功
printf("write success\n");
else printf("write fail\n");
close(fd);
return 0;
}
步驟:
1.make生成兩個.ko文件,裝載到板子裏,lsmod或ls /sys/bus/platform/device和driver都能看到對應的tiny6410_leds
2.arm-linux-gcc 編譯生成測試程序
3.先停止板上的led流水燈:/etc/rc.d/init.d/leds stop,然後 ./test_led 0全滅 ./test_led 1全亮