PS:花了一个晚上,将led驱动搞定了,很欣慰啊,下面记录下这个经过。
1.[看TE6410底板原理图] 在飞凌TE6410的开发板上面任意找一个空闲的GPIO口,然后再GPIO口上面挂载一个led。比如在GPP1上面挂载一个led;
2.[S3C6410用户手册] 找到有关GPP的一章节,看到如下语句:
3.[回到虚拟机] 现在可以写驱动程序了,当然预先要知道内核模块的知识,因为我打算采用内核模块的方式来加载驱动。内核模块的知识就不介绍了;
1)先写驱动函数led.c:参考http://blog.youkuaiyun.com/eastmoon502136/article/details/7705733
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <asm/irq.h>
#include <mach/gpio.h>
#include <mach/map.h>
#include <mach/gpio-bank-p.h>
#include <mach/regs-gpio.h>
#include <plat/gpio-cfg.h>
#include <mach/hardware.h>
#include <linux/io.h>
MODULE_LICENSE("GPL");
#define LED_MAJOR 240
int led_open(struct inode *inode, struct file *filp)
{
unsigned int tmp;
tmp = readl(S3C64XX_GPPCON);//read the value of GPPCON
tmp = (tmp & ~(0xffff)|(0x4)); //set the GPIO output mode
writel(tmp, S3C64XX_GPPCON);//set the value of GPPCON
printk(KERN_EMERG"led_open!\n");//print
return 0;
}
ssize_t led_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
printk(KERN_EMERG"led_read!\n");
return count;
}
ssize_t led_write(struct file *filp,const char __user *buf, size_t count, loff_t *f_pos)
{
char mbuf[10];
unsigned int tmp;
copy_from_user(mbuf,buf,count);
switch(mbuf[0])
{
case 0:
tmp = readl(S3C64XX_GPPDAT);
tmp |= (0x2);
writel(tmp, S3C64XX_GPPDAT);
break;
default:
break;
}
printk(KERN_EMERG"led_write!\n");
return count;
}
int led_release(struct inode *inode, struct file *filp)
{
printk(KERN_EMERG"led_release!\n");
return 0;
}
struct file_operations my_fops = {
.owner = THIS_MODULE,
.open = led_open,
.read = led_read,
.write = led_write,
.release = led_release,
};
static int led_init(void)
{
int rc;
printk(KERN_EMERG"Test led dev\n");
rc = register_chrdev(LED_MAJOR, "led_GPP1", &my_fops);
if(rc < 0)
{
printk(KERN_EMERG"register %s dev error\n", "led_GPP1");
return -1;
}
printk(KERN_EMERG"register led dev OK!\n");
return 0;
}
static void led_exit(void)
{
unregister_chrdev(LED_MAJOR, "led_GPP1");
printk(KERN_EMERG"Good Bye!\n");
}
module_init(led_init);
module_exit(led_exit);
2).写Makefile文件:这个参考 http://avrgroup.5d6d.net/archiver/tid-6614.html
ifneq ($(KERNELRELEASE),)
obj-m := led.o //obj-m是将led.o加入内核模块
else
KDIR := /joe/linux-3.0.1 //linux3.0.1的系统目录 joe是我自己建立的工作目录
all:
make -C $(KDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=arm-linux- //一定要制定交叉编译工具
clean:
rm -f *.ko *.o *.mod.o *.mod.c *.symvers
endif
3).在终端输入make命令:生成led.ko内核模块文件
4.编写一个测试程序led_test.c:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define DEVICE "/dev/led_GPP1"
int main(void)
{
int fd, i;
char buf[1] = {0};
fd = open(DEVICE, O_RDWR);
if(fd < 0)
{
printf("Open /dev/led_gpp1 file error\n");
return -1;
}
while(1)
{
write(fd, &buf[0], 1);
}
close(fd);
return 0;
}
5.交叉编译一下led_test.c 生成二进制文件led_test
6.将led.ko,led_test两个文件拷贝到sdcard,然后放到开发板上面去测试一下:
7.启动开发板,
[root@FORLINX6410]#
[root@FORLINX6410]#
[root@FORLINX6410]#
[root@FORLINX6410]#
[root@FORLINX6410]# mknod /dev/led_GPP1 c 240 0 //建立设备节点
[root@FORLINX6410]# ls /dev/led
[root@FORLINX6410]# ls /dev/led_GPP1
/dev/led_GPP1 //建立成功
[root@FORLINX6410]# insmod //查看系统载入的模块
[root@FORLINX6410]# insmod /sdcard/led.ko //挂载led.ko驱动模块
Test led dev
register led dev OK!
[root@FORLINX6410]# lsmod
led 1866 0 - Live 0xbf000000 //查看
[root@FORLINX6410]#
[root@FORLINX6410]#
[root@FORLINX6410]#
[root@FORLINX6410]# ./sdcard/
led_
[root@FORLINX6410]# ./sdcard/led_test //测试程序
led_open!
led_write! //成功
led_write!
led_write!
led_write!
明天将问题补充完整:
1.驱动程序一定要包含必要的头文件,否则会出错;
2.一定要想手动新建设备文件,然后才能加载模块,运行程序。目前还不知道怎么在驱动程序里面新建设备节点;
3.不能卸载掉驱动模块。