/////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////
#include<linux/init.h>
#include<linux/module.h>
#include<linux/fs.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/device.h>
#include <linux/cdev.h>
#define GLOBAL_LED_MAJOR 250
static unsigned int global_led_major = GLOBAL_LED_MAJOR;主设备号
static struct cdev *led_cdev = NULL; 指向cdev结构体
static struct class *led_class = NULL; 为下面自动生成设备文件做准备
static volatile unsigned long *gpfcon = NULL;
static volatile unsigned long *gpfdat = NULL;
static volatile unsigned long *gpfup = NULL;
static int mini2440_led_open(struct inode * inode,struct file * file)
{
printk("mini2440_open[kernel_space]\n");
*gpfcon &=~((0x3<<0) | (0x3<<8) |(0x3<<10) |(0x3<<12)|(0x3<<14));
*gpfcon |= (0x1<<0) | (0x1<<8) |(0x1<<10) |(0x1<<12)|(0x1<<14);
return 0;
}
static ssize_t mini2440_led_read(struct file * file,const char __user * in,size_t size,loff_t * off)
{
printk("mini2440_read[kernel_space]\n");
return 0;
}
static ssize_t mini2440_led_write(struct file * file,const char __user * in,size_t size,loff_t * off)
{
char ker_buf;
printk("mini2440_write[kernel_space]\n");
ret = copy_from_user(&ker_buf,in,size);
printk("ker_buf =%d\n",ker_buf);
if(ker_buf)
{
*gpfdat &=~((0x1<<4)|(0x1<<5)|(0x1<<6)|(0x1<<7));
*gpfdat |= (0x1<<0);
}
else
{
*gpfdat |=(0x1<<4)|(0x1<<5)|(0x1<<6)|(0x1<<7);
*gpfdat &= ~(0x1<<0);
}
return 0;
}
struct file_operations led_fops = {
.owner = THIS_MODULE,
.open = mini2440_led_open,
.read = mini2440_led_read,
.write = mini2440_led_write,
};
int mini2440_led_init(void)
{
int result;
int err;
if (global_led_major) {
result = register_chrdev_region(devno,1,"led_driver");注册使用人为指定的设备号,可以从cat /proc/devices 看到"led_driver"
printk("sd!");
} else {
result = alloc_chrdev_region(&devno,0,1,"led_driver");由系统分配指定设备号 存放在devno参数中
global_led_major = MAJOR(devno);提取主设备号
printk("zd!");
}
if (result < 0){
}
led_cdev = cdev_alloc();动态分配得到一个cdev
cdev_init(led_cdev,&led_fops);初始化cdev 将得到的cdev与具体操作绑定在一起
led_cdev->owner = THIS_MODULE;
err = cdev_add(led_cdev,devno,1);将使用devno设备号的绑定了led_fops的cdev注册到内核中
led_class = class_create(THIS_MODULE,"led_class");先生存一个class类,再生成设备文件
device_create(led_class,NULL,MKDEV(global_led_major,0),NULL,"mini2440_led"); 在/dev下生存设备文件
物理地址空间映射到虚拟地址空间 这里将从物理地址0x56000010开始的12字节的物理空间映射到虚拟地址空间
gpfcon = ioremap(0X56000010,12);
gpfdat = gpfcon + 1;
gpfup = gpfcon + 2;
if (err) {
printk(KERN_NOTICE"Error %d adding led_cdev",err);
return -1;
} else {
printk("mini2440_led_init ok!\n");
return 0;
}
}
void mini2440_led_exit(void)
{
cdev_del(led_cdev);从内核中注销cdev结构体
iounmap(gpfcon);注销物理地址空间与虚拟地址空间的映射
kfree(led_cdev);释放动态分配到的led_cdev
unregister_chrdev_region(MKDEV(global_led_major,0),1);注销使用过的设备号
device_destroy(led_class, MKDEV(global_led_major,0));
class_destroy(led_class);
}
MODULE_AUTHOR("aaaa");
MODULE_LICENSE("GPL");
module_param(global_led_major,int,S_IRUGO);
module_init(mini2440_led_init);
module_exit(mini2440_led_exit);
//////////////////////////////////////////////
ifneq ($(KERNELRELEASE), )
obj-m := mini2440_led.o
else
KDIR := /home/tools/linux-2.6.32.2
all:
make -C $(KDIR) M=/linux_prg modules
clean:
rm -f *.ko *.o *.mod.o *.mod.c *.symvers
endif
////////////////////////////////////////////////
清除:make clean
编译【自动寻找Makefile文件】:make
////////////////////////////////////////////////
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc,char **argv)
{
int fd;
char val;
fd =open("/dev/mini2440_led",O_RDWR);
if(fd<0)
{
printf("cannot open /dev/led!\n");
return 0;
}
printf("open /dev/mini2440_led[usr_space]!\n");
if(strcmp(argv[1],"on")==0)
{
val =1;
}
else
{
val =0;
}
write(fd,&val,1);
printf("finish!\n");
return 0;
}
////////////////////////////////////////////////
arm-linux-gcc mini2440_app.c -o mini2440_led_app
////////////////////////////////////////////////
点亮以及蜂鸣器响 ./mini2440_led_app on
不亮以及蜂鸣器不响 ./mini2440_led_app off
////////////////////////////////////////////////
模块加载函数的流程:(卸载函数与之相反)
1:向系统申请设备号(或向系统注册自己设定的设备号)
2:向系统申请一块cdev结构体
3:初始化cdev:cdev_init(led_cdev,&led_fops);绑定操作函数