在mini2440中,led,按键等驱动默认已经被编译入内核,所以一直不知道同一个硬件设备资源能不能作为多个模块,编译入内核。
故重写了一个myled.ko,系统默认是led.ko,并用应用程序检测。
myled.c
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/gpio.h>
#include <linux/ioctl.h>
#include <linux/cdev.h>
#include <linux/mm.h>
#include <linux/device.h>
#include <mach/regs-gpio.h>
#include <mach/hardware.h>
#include <asm/uaccess.h>
#include <asm/atomic.h>
#include <asm/unistd.h>
//**************
static struct device *dev;
//*************
#define DEVICE_NAME "myled"
static struct cdev *cdevp=NULL;//定义一个cdev结构体,并初始化
static dev_t devno;//定义一个设备号
static unsigned long led_table[] = {
S3C2410_GPB(5),//定义端口
S3C2410_GPB(6),
S3C2410_GPB(7),
S3C2410_GPB(8),
};
static unsigned int led_cfg_table[] = {
S3C2410_GPIO_OUTPUT,//定义寄存器状态
S3C2410_GPIO_OUTPUT,
S3C2410_GPIO_OUTPUT,
S3C2410_GPIO_OUTPUT,
};
static int s3c2440_leds_ioctl(struct inode *inode,struct file *filp,unsigned int cmd,unsigned long arg)
{
switch(cmd)
{
case 0:
case 1:
if(arg>3)
{
return -EINVAL;
}
s3c2410_gpio_setpin(led_table[arg],!cmd);
return 0;
default:
return -EINVAL;
}
}
//应用程序与驱动映
static struct file_operations myled_fops = {
.owner = THIS_MODULE,
.ioctl = s3c2440_leds_ioctl,
};
//**************
static struct class *led_class;
//**************
static int __init myled_init_module(void)
{
int ret;
int i,err;
ret = alloc_chrdev_region(&devno,0,1,DEVICE_NAME);//注册设备
if(ret < 0)
{
printk(DEVICE_NAME "can't get the major number\n");
return ret;
}
//****************************
led_class= class_create(THIS_MODULE,DEVICE_NAME);
if(IS_ERR(led_class))
{
printk("Err: failed in leds-class.\n");
return -1;
}
dev=device_create(led_class,NULL,devno,NULL,DEVICE_NAME);
//**************************
cdevp = cdev_alloc();//动态申请一个cdev内存
cdev_init(cdevp,&myled_fops);//初始化cdev
cdevp->owner = THIS_MODULE;
err=cdev_add(cdevp,devno,1);
if(err)
{
printk(KERN_NOTICE "Error %d adding cdev",err);
unregister_chrdev_region(devno,1);
return -EFAULT;
}
for(i=0;i<4;i++)
{
s3c2410_gpio_cfgpin(led_table[i],led_cfg_table[i]);
s3c2410_gpio_setpin(led_table[i],1)
}
printk(DEVICE_NAME "\tinitialized! 2012-12-9\n");
return 0;
}
static void __exit myled_exit_module(void)
{
cdev_del(cdevp);
unregister_chrdev_region(devno,1);
//****************
device_destroy(led_class,devno);
class_destroy(led_class);
/*****************
printk(DEVICE_NAME "\tunloaded by tong2012-12-9\n");
}
module_init(myled_init_module);
module_exit(myled_exit_module);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("tong 2012-12-9");
Makefile如下
ifneq ($(KERNELRELEASE),)
obj-m:=myled.o
else
KDIR := /opt/FriendlyARM/mini2440/linux-2.6.32.2_fa
all:
make -C $(KDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=arm-linux-
clean:
rm -f *.ko *.o *.mod.o *.mod.c *.symvers
endif
拷贝到开发板上,insmod myled.ko可在/dev下生成设备节点myled.ko
现在采用系统给出的例程,但修改设备节点为myled,
led.c (必须使用交叉编译器)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
int main(int argc, char **argv)
{
int on;
int led_no;
int fd;
if (argc != 3 || sscanf(argv[1], "%d", &led_no) != 1 || sscanf(argv[2],"%d", &on) != 1 ||
on < 0 || on > 1 || led_no < 0 || led_no > 3) {
fprintf(stderr, "Usage: leds led_no 0|1\n");
exit(1);
}
fd = open("/dev/myled", 0);
if (fd < 0) {
fd = open("/dev/myled", 0);
}
if (fd < 0) {
perror("open device leds");
exit(1);
}
ioctl(fd, on, led_no);
close(fd);
return 0;
}
先用/etc/rc.d/init.d/leds stop关闭系统初始化中,开启的让四个led循环闪动的服务,
通过ioctl函数可以控制让哪个led,是亮还是灭,能成功。
说明了,同一个硬件设备资源能被作为多个模块,换成不同的名字,互不干扰,也就是说可以同时硬件资源可以为应用程序中的多种服务工作,可以联想一下智能手机是如何工作的。