s5pv210驱动之流水灯程序2

基于linux-3.2.8内核,如下驱动程序:

#include <linux/module.h>
#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/device.h>


static struct class *leddrv_class;
static struct device	*leddrv_class_dev;

volatile unsigned long virt, phys;//用于存放虚拟地址和物理地址
volatile unsigned long *GPC0CON, *GPC0DAT;//用与存放两个个寄存器的地址
//#define GPC0CON		*((volatile unsigned int *)0xE0200060)
//#define GPC0DAT		*((volatile unsigned int *)0xE0200064)
//static dev_t devt;	
static void all_led_off(void);
static void led_config(void)
{
	phys = 0xE0200060; 

	//在虚拟地址空间中申请一块长度为0x10的连续空间
	//这样,物理地址phys到phys+0x10对应虚拟地址virt到virt+0x10
	virt =(unsigned long)ioremap(phys, 0x10);
	GPC0CON = (unsigned long *)(virt + 0x00);//指定需要操作的三个寄存器的地址
	GPC0DAT = (unsigned long *)(virt + 0x04);
	*GPC0CON &= ~(0xFF << 12);
	*GPC0CON |= 0x11 << 12;			// 配置GPC0_3和GPC0_4为输出
	all_led_off();
}

static void led_on(void)
{
		*GPC0DAT |= 1 << 3;		// 点亮LED1
		*GPC0DAT |= 1 << 4;		// 点亮LED2
}
static void all_led_off(void)
{

	*GPC0DAT &= ~(0x3 << 3);		// 熄灭LED1和LED2

}


static int led_drv_open(struct inode *inode, struct file *file)
{
	printk("led_drv_open\n");
	led_config();
	all_led_off();
//	led_on();
	return 0;
}

static ssize_t led_drv_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
{
	char val = 0;
	//printk("first_drv_write\n");
	copy_from_user(&val, buf, count); //	copy_to_user();
	printk("led process %c\n",val);
	switch(val)
	{
			case '1':
				*GPC0DAT |= 1 << 3;		// 点亮LED1
				*GPC0DAT &= ~(1 << 4);		//灭2
				break;
			case '2':
				*GPC0DAT |= 1 << 4;
				*GPC0DAT &= ~(1 << 3);	
				break;
			case '3':
				 led_on();
				 break;
			case '4':
				 all_led_off();
				 break;
		 default:
		 		 all_led_off();
		 		 break;
	}
	return 0;
}

static ssize_t led_drv_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
	
		return 0;
}



static struct file_operations led_drv_fops = {
    .owner  =   THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
    .open   =   led_drv_open,     
		.write	=	led_drv_write,	
		.read		= led_drv_read,   
};




int major;
static int led_drv_init(void)
{
	major = register_chrdev(0, "led_drv", &led_drv_fops); // 注册, 告诉内核

	leddrv_class = class_create(THIS_MODULE, "leddrv");

	leddrv_class_dev = device_create(leddrv_class, NULL, MKDEV(major, 0), NULL, "led"); /* /dev/xyz */

	//gpbcon = (volatile unsigned long *)ioremap(0xE0200060, 16);
	//gpbdat = gpbcon + 1;

	return 0;
}

static void led_drv_exit(void)
{
	all_led_off();
	unregister_chrdev(major, "led_drv"); // 卸载
	
	device_unregister(leddrv_class_dev);
	class_destroy(leddrv_class);
	//iounmap(gpbcon);
	iounmap((void *)virt); //撤销映射关系
}

module_init(led_drv_init);
module_exit(led_drv_exit);


MODULE_LICENSE("GPL");

测试程序如下:

#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>

int main(int argc,char **argv)
{
    int fd;
    char val = 0;
    char *s = malloc(100);
    fd = open("/dev/led_drv",777);
    if(fd<0)
<span style="white-space:pre">	</span><span style="font-family: Arial, Helvetica, sans-serif;">printf("can't open \n");</span>
<span style="white-space:pre">	</span>return -1;    
<span style="white-space:pre">	</span>while(1)
	{
		printf("输入1:1灯亮\n输入2:2灯亮\n输入3:所有灯亮\n输入4:所有灯灭\n输入5:退出\n请输入");	
		scanf("%s",s);
		getchar();
		val = s[0];
		write(fd,&val,1);
		if(val == '5')
		<span style="white-space:pre">	</span>break;
	}
<span style="white-space:pre">	</span>free(s);
  //  write(fd,&val,4);
    return 0;

}



猜你喜欢

转载自blog.csdn.net/humanspider1/article/details/40638811