/////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////
#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);綁定操作函數