友善之臂mini2440<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
linux-<?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />2.6.29.1
arm-linux-gcc-4.3.2
自己写的mini2440的led驱动和测试程序,下面是添加注释的源码和makefile。
//s3c24xx_leds.c
#include <linux/module.h> //模块加载的头文件
#include <linux/kernel.h> // 内核头文件
//所以模块代码都包含以上两个头文件
#include <linux/fs.h> //定义file_operations结构
#include <linux/init.h> //用户定义的模块初始化函数需要引用的头文件
#include <linux/delay.h> //延时函数的头文件
#include <mach/regs-gpio.h> //定义GPIO寄存器相关的宏
#include <mach/hardware.h> //硬件相关的函数
#define DEVICE_NAME "leds"
#define LED_MAJOR 231
#define IOCTL_LED_ON 0
#define IOCTL_LED_OFF 1
//连接led的GPIO管脚的宏,定义在/arch/arm/mach-s3c2410/include/mach/regs-gpio.h
static unsigned long led_table [] = {
S3C2410_GPB5,
S3C2410_GPB6,
S3C2410_GPB7,
S3C2410_GPB8,
};
//设置GPIO管脚为输出的宏,定义在/arch/arm/mach-s3c2410/include/mach/regs-gpio.h
static unsigned int led_cfg_table [] = {
S3C2410_GPB5_OUTP,
S3C2410_GPB6_OUTP,
S3C2410_GPB7_OUTP,
S3C2410_GPB8_OUTP,
};
//驱动接口函数open的用户实现。
static int s3c24xx_leds_open(struct inode *inode, struct file *file)
{
int i;
for (i = 0; i < 4; i++) {
//设置gpio管脚状态的函数,定义在mach/hardware.h,参数的宏定义在mach/hardware.h
s3c2410_gpio_cfgpin(led_table, led_cfg_table);
}
return 0;
}
//驱动接口函数ioctl的用户实现。
static int s3c24xx_leds_ioctl(
struct inode *inode,
struct file *file,
unsigned int cmd,
unsigned long arg)
{
if (arg > 4) {
return -EINVAL;
}
switch(cmd) {
case IOCTL_LED_ON:
//设置gpio管脚输出电平的函数,定义在mach/hardware.h
s3c2410_gpio_setpin(led_table[arg], 0);
return 0;
case IOCTL_LED_OFF:
s3c2410_gpio_setpin(led_table[arg], 1);
return 0;
default:
return -EINVAL;
}
}
static struct file_operations s3c24xx_leds_fops = {
.owner = THIS_MODULE,
//指向编译模块是自动创建的__this_module变量的宏,无需关注
.open = s3c24xx_leds_open,
.ioctl = s3c24xx_leds_ioctl,
};
static int __init s3c24xx_leds_init(void)
{
int ret;
ret = register_chrdev(LED_MAJOR, DEVICE_NAME, &s3c24xx_leds_fops);
if (ret < 0) {
printk(DEVICE_NAME " can't register major number\n");
return ret;
}
printk(DEVICE_NAME " initialized\n");
return 0;
}
static void __exit s3c24xx_leds_exit(void)
{
unregister_chrdev(LED_MAJOR, DEVICE_NAME);
}
module_init(s3c24xx_leds_init);
module_exit(s3c24xx_leds_exit);
//end
应用程序执行的open、inctl等系统调用,它们的参数与驱动程序中相应函数的参数不是一一对应的,其中经过了内核文件系统层的转换。
系统调用函数的原型如下:
int open(const char *pathname, int flags);
int ioctl (int d, int request, …);
ssize_t read(int fd, void *buf, size_t count);
ssize_t write(int fd, const void *buf, size_t count);
file_operations结构中的成员如下:
int (*open) (struct inode *inode, struct file *filp);
int (*ioctl) (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg);
ssize_t (*read) (struct file *filp, char __user *buff, size_t count, loff_t *offp);
ssize_t (*write) (struct file *filp, const char __user *buff, size_t count), loft *offp);
…
1. 系统调用的open函数只需传入设备文件路径和打开状态;
2. 系统调用的ioctl函数参数个数可变,一般为三个,后面两个参数与file_operations结构中ioctl成员的后两个参数对应;
3. 系统调用的read函数传入的buf、count,对应file_operations结构中的buf、count参数,而offp表示用户在文件中进行存取操作的位置,当执行玩读写操作后有驱动程序设置。
4. 系统调用的write函数与read类似。
Makefile:
CROSS=arm-linux-
KERNELDIR = /home/bob/linux_src/linux-2.6.29.1
#定义内核源码的路径
PWD := $(shell pwd)
#获取当前路径
.PHONY: modules clean
#指明modules、clean为伪目标
obj-m += s3c24xx_leds.o
#表示要构造的模块名为s3c24xx_leds.ko
modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
#-C:进入$(KERNELDIR)后再执行make,读取那里的Makefile。
#M=$(PWM):然后返回当前的位置(驱动源代码的位置)继续执行当前的Makefile。
clean:
rm -rf *.o *~ core .depend .*.cmd *.mod.c .tmp_versions
#end
测试代码:
https://static.assets-stash.eet-china.com/album/old-resources/2009/8/31/c932d790-4339-4e98-bc24-05d3c6827cfb.rar
用户539229 2009-9-6 10:18
huotingtu_505472073 2009-9-1 10:37