#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
static struct class *firstdrv_class;
static struct class_device *firstdrv_class_dev;
//这个是设备的名称,也就是对应在/dev/test-dev
#define DEV_NAME "test-dev"
//LED灯IO口的地址,也就是刚刚我们在上面的芯片手册看到的Address
#define GPM4COM 0x110002E0
//定义配置模式的指针变量
volatile unsigned long *led_config = NULL ;
//定义配置状态的指针变量
volatile unsigned long *led_dat = NULL ;
//open方法,对LED灯进行初始化
int led_open(struct inode *inode, struct file *filp)
{
printk("led_open\n");//上层程序对LED进行Open操作的时候会执行这个函数
//先对LED的端口进行清0操作
*led_config &= ~((0xf<<(3*4)) | (0xf<<(2*4)) | (0xf<<(1*4)) | (0xf<<(0*4)));
//将4个IO口16位都设置为Output输出状态
*led_config |= ((0x1<<(3*4)) | (0x1<<(2*4)) | (0x1<<(1*4)) | (0x1<<(0*4)));
return 0;
}
//write方法
int led_write(struct file *filp , const char __user *buf , size_t count , loff_t *f_pos)
{
int val ;
//注意,这里是在内核中进行操作,我们需要使用copy_from_user这个函数将用户态的内容拷贝到内核态
copy_from_user(&val , buf , count);
//以下就是当val是哪个值的时候,led就执行相应的操作,这里不多说
switch(val)
{
case 0 :
//对状态寄存器进行赋值,以下雷同
printk(KERN_EMERG"led1_on\n");
*led_dat &= ~(1<<0) ;
break ;
case 1 :
printk(KERN_EMERG"led2_on\n");
*led_dat &= ~(1<<1) ;
break ;
case 2 :
printk(KERN_EMERG"led3_on\n");
*led_dat &= ~(1<<2) ;
break ;
case 3 :
printk(KERN_EMERG"led4_on\n");
*led_dat &= ~(1<<3) ;
break ;
case 4 :
printk(KERN_EMERG"ledall_on\n");
*led_dat &= ~((1<<0) | (1<<1) |(1<<2)| (1<<3));
break ;
case 5 :
printk(KERN_EMERG"ledall_off\n");
*led_dat |= ((1<<0) | (1<<1) |(1<<2)| (1<<3)) ;
break ;
}
return 0;
}
//close方法
int led_close(struct inode *inode, struct file *filp)
{
printk("led_close\n");
*led_dat |= (1<<0) | (1<<1) | (1<<2) | (1<<3); //全灭,因为高电平是灭的,0xf ----> 1111
return 0;
}
//用ioctl这个方法也可以实现LED的操作的,自己去实现吧
#if 0
long led_ioctl(struct file *filp, unsigned int request, unsigned long arg)
{
switch(request)
{
case 0:
printk(KERN_EMERG"led1 on\n");
*led_dat &=~(1<<0) ;
break;
case 1:
printk(KERN_EMERG"led2 on\n");
*led_dat &=~(1<<1) ;
break;
case 3:
printk(KERN_EMERG"led3 on\n");
*led_dat &=~(1<<2) ;
break;
case 4:
printk(KERN_EMERG"led4 on\n");
*led_dat &=~(1<<3) ;
break ;
default :
*led_dat |= 0xf ;
}
}
#endif
//对方法进行初始化
struct file_operations fops = {
.owner = THIS_MODULE ,
.open = led_open,
.release = led_close,
// .unlocked_ioctl = led_ioctl,
.write = led_write,
};
//主设备号
int major ;
//启动函数
static __init int test_init(void)
{
printk("led_init\n");
major = register_chrdev(0, DEV_NAME, &fops);
firstdrv_class = class_create(THIS_MODULE, DEV_NAME);
firstdrv_class_dev = device_create(firstdrv_class, NULL, MKDEV(major, 0), NULL, DEV_NAME); /* /dev/xyz */
led_config = (volatile unsigned long *)ioremap(GPM4COM , 16);
led_dat = led_config + 1 ;
return 0;
}
//注销函数
static __exit void test_exit(void)
{
printk("led_exit\n");
unregister_chrdev(major, DEV_NAME);
device_destroy(firstdrv_class, MKDEV(major, 0));
class_destroy(firstdrv_class);
iounmap(led_config);
}
module_init(test_init);
module_exit(test_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("hai");
MODULE_VERSION("2017.4.29");
//****************myled.c*********************************************//
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc, char **argv)
{
int fd;
int val = 0 ;
//打开对应的设备
fd = open("/dev/test-dev",O_RDWR) ;
if(-1 == fd)
{
printf("open fair!\n");
return -1 ;
}
while(1){
val = 0 ;
write(fd , &val , 4);
sleep(1);
val = 1 ;
write(fd , &val , 4);
sleep(1);
val = 2 ;
write(fd , &val , 4);
sleep(1);
val = 3 ;
write(fd , &val , 4);
sleep(1);
val = 5 ;
write(fd , &val , 4);
sleep(1);
}
return 0;
}
//**********************Makefile*******************************************
KERN_DIR = /home/tools/linux-3.5
all:
make -C $(KERN_DIR) M=`pwd` modules
clean:
make -C $(KERN_DIR) M=`pwd` clean
rm -rf modules.order
obj-m += led_driver.o