基于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;
}