今天阅读嵌入式linux LED驱动程序的时候
驱动实现部分是搞清楚了
但是几个头文件的路径真的把我搞糊涂了LINUX 2.6.13文件组织如下
头文件如下
#include
#include
#include
可我根本就找不到ARM对应的asm这个文件夹,或者说找到了也对应的不是对应S3C24XX的
后来无意间看内核移植的一篇文章讲了链接的实例
所以asm文件应该也是一个连接,那么一切就说的通了
asm文件连接到kernel-2.6.13includeasm-arm文件夹下
#include ==kernel-2.6.13includeasm-armirq.h
#include ==kernel-2.6.13includeasm-armarch-s3c2410
egs-gpio.h
#include ==kernel-2.6.13includeasm-armhardware.h
所以我猜测如果你看到
#include
可能意思是
mach ==kernel-2.6.13archarmmach-s3c2410
#include 操作系统中断
#include 与处理器相关的入口
//#include 与处理器相关的IO口操作
#include 同上
//#include 与处理器相关的硬件
#include 同上
1.Linux
链接概念
Linux
链接分两种,一种被称为硬链接(Hard Link
),另一种被称为符号链接(Symbolic Link
)。默认情况下,ln
命令产生硬链接。
【硬连接】硬连接指通过索引节点来进行连接。在Linux
的文件系统中,保存在磁盘分区中的文件不管是什么类型都给它分配一个编号,称为索引节点号(Inode Index)
。在Linux
中,多个文件名指向同一索引节点是存在的。一般这种连接就是硬连接。硬连接的作用是允许一个文件拥有多个有效路径名,这样用户就可以建立硬连接到重要文件,以防止“
误删”
的功能。其原因如上所述,因为对应该目录的索引节点有一个以上的连接。只删除一个连接并不影响索引节点本身和其它的连接,只有当最后一个连接被删除后,文件的数据块及目录的连接才会被释放。也就是说,文件真正删除的条件是与之相关的所有硬连接文件均被删除。
硬连接的2个限制:
l 不允许给目录创建硬链接
l 只有在同一文件系统中的文件之间才能创建链接。 即不同硬盘分区上的两个文件之间不能够建立硬链接。这是因为硬链接是通过结点指向原始文件的,而文件的i-结点在不同的文件系统中可能会不同。
【软连接】另外一种连接称之为符号连接(Symbolic Link
),也叫软连接。软链接文件有类似于Windows
的快捷方式。它实际上是一个特殊的文件。在符号连接中,文件实际上是一个文本文件,其中包含的有另一文件的位置信息。
这就允许符号链接(经常简写为symlinks)指向位于其他分区、甚至是其他网络硬盘上的某个文件
2.
通过实验加深理解
[oracle@Linux]$ touch f1 #
创建一个测试文件f1
[oracle@Linux]$ ln f1 f2 #
创建f1
的一个硬连接文件f2
[oracle@Linux]$ ln -s f1 f3 #
创建f1
的一个符号连接文件f3
[oracle@Linux]$ ls -li # -i
参数显示文件的inode
节点信息
total 0
9797648 -rw-r--r-- 2 oracle oinstall 0 Apr 21 08:11 f1
9797648 -rw-r--r-- 2 oracle oinstall 0 Apr 21 08:11 f2
9797649 lrwxrwxrwx 1 oracle oinstall 2 Apr 21 08:11 f3 -> f1
从上面的结果中可以看出,硬连接文件f2
与原文件f1
的inode
节点相同,均为9797648
,然而符号连接文件的inode
节点不同。
[oracle@Linux]$ echo "I am f1 file" >>f1
[oracle@Linux]$ cat f1
I am f1 file
[oracle@Linux]$ cat f2
I am f1 file
[oracle@Linux]$ cat f3
I am f1 file
[oracle@Linux]$ rm -f f1
[oracle@Linux]$ cat f2
I am f1 file
[oracle@Linux]$ cat f3
cat: f3: No such file or directory
通过上面的测试可以看出:当删除原始文件f1
后,硬连接f2
不受影响,但是符号连接f3
文件无效
3.
总结依此您可以做一些相关的测试,可以得到以下全部结论:
1).
删除符号连接f3,
对f1,f2
无影响;
2).
删除硬连接f2
,对f1,f3
也无影响;
3).
删除原文件f1
,对硬连接f2
没有影响,导致符号连接f3
失效;
4).
同时删除原文件f1,
硬连接f2
,整个文件会真正的被删除。
下面是一个简单的LED驱动程序实例
http://blog.mcuol.com/User/gaochengnan/Article/13406_1.htm
另外可参考
http://hi.baidu.com/tekuba/item/d72e32eb8f19713d86d9de94
http://longer.spaces.eepw.com.cn/articles/article/item/60415
led驱动实验
源码gaoled.c:
#include "linux/config.h"
#include "linux/module.h"
#include "linux/kernel.h"
#include "linux/fs.h"
#include "linux/init.h"
#include "linux/devfs_fs_kernel.h"
#include "linux/miscdevice.h"
#include "linux/delay.h"
#include "asm/irq.h"
#include "asm/arch/regs-gpio.h"
#include "asm/hardware.h"
#define DEVICE_NAME "gcnled" //定义设备名
#define LED_MAJOR 250 //手动定义主设备号
MODULE_AUTHOR("gcn");
MODULE_DESCRIPTION("S3C2440 LED Driver");
MODULE_LICENSE("GPL");
//定义要操作的设备,把每一个led作为结构体的一个成员
static unsigned long led_table [] =
{
S3C2410_GPF4,
S3C2410_GPF5,
S3C2410_GPF6,
S3C2410_GPF7,
};
//对设备进行设置,此即5个管脚为输出口
static unsigned int led_cfg_table [] =
{
S3C2410_GPF4_OUTP,
S3C2410_GPF5_OUTP,
S3C2410_GPF6_OUTP,
S3C2410_GPF7_OUTP,
};
/*编写s3c2440_led_ioctl函数:设备驱动程序中对设备的I/O通道进行管理的函数,用来实现对led的操作*/是整个驱动程序的核心*/
static int s3c2440_leds_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
if (arg > 3)
{
return -EINVAL;
}
led(cmd)
{
case 0:
case 1:
s3c2410_gpio_setpin(led_table[arg], !cmd);
return 0;
default:
return -EINVAL;
}
}
//定义s3c2440_led_fops:结构体提供基本函数入口点
static struct file_operations s3c2440_leds_fops =
{
.owner = THIS_MODULE,
.ioctl = s3c2440_leds_ioctl,
};
//模块加载函数
static int __init s3c2440_leds_init(void)
{
int ret;
int i;
//注册设备号/* register_chrdev是注册字符设备的函数*/
ret=register_chrdev(LED_MAJOR,DEVICE_NAME,&s3c2440_leds_fops);
if (ret < 0)
{
printk(DEVICE_NAME " can''''''''''''''''''''''''''''''''t register major number
");
return ret;
}
/* 2.6内核驱动注册完后,要用以下代码创建设备文件*/
devfs_mk_cdev(MKDEV(LED_MAJOR, 0), S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, DEVICE_NAME);
for (i = 0; i < 4; i++)
{
s3c2410_gpio_cfgpin(led_table[i], led_cfg_table[i]);
/*相当于open函数将相应端口设置为输出口*/
s3c2410_gpio_setpin(led_table[i], 1);/*端口置1*/
}
printk(DEVICE_NAME " initialized
");/*打印出驱动加载成功的信息*/
return 0;
}
//模块卸载函数
static void __exit s3c2440_leds_exit(void)
{
devfs_remove(DEVICE_NAME);/* 2.6内核驱动要用以下代码移除设备文件*/
unregister_chrdev(LED_MAJOR, DEVICE_NAME);
}
//指定驱动程序的初始化函数和卸载函数
module_init(s3c2440_leds_init);
module_exit(s3c2440_leds_exit);
把gaoled.c考入内核目录下的/devices/char目录下
修改该目录下的makefile:Obj-m += gaoled.o
在内核根目录下运行make modules
会发现生成了gaoled.ko文件
接下来把gaoled.ko转移到开发板上(我是直接用优盘考出来在开发板上挂载的)
在gaoled.c目录下运行 insmod gaoled.ko
打印出gcnled initialized
成功!
查看是否成功可以在开发板上进入/ proc下执行cat devices 可以看到 250 gcnled
注意:编译生成.ko文件是在pc机完成的。
然后在开发板上加载模块insmod xxx.ko
出现问题:devices busy 设备忙碌什么的因为主设备号重复了!我刚开始用的231 改成250之后就好了
以上均亲身实践测试程序通过