头文件:
#ifndef _LED_CONFIG_H
#define _LED_CONFIG_H
#define LED_CON 0
#define LED_ON 1
#define LED_OFF 2
#endif
内核下面的驱动模块:
#include <linux/module.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include "../led_config.h"
#include <linux/errno.h>
#define PHYS_BASE 0x56000040
#define SIZE 12
#define setbit(data,pos,len,val) do{/
data &=~((~(~0<<len))<<pos);/
data |=val<<pos;/
}while(0)
struct led_driver{
unsigned long gpecon;
unsigned long gpedat;
unsigned long gpeup;
unsigned long virt_base;
struct cdev led_dev;
unsigned long major;
unsigned long minor;
dev_t devno;
void (*conf)(struct led_driver *);
void (*on)(struct led_driver *);
void (*off)(struct led_driver *);
};
struct led_driver *md;
void con_led(struct led_driver *led)
{
unsigned long tmp;
tmp=ioread32(led->gpecon);
setbit(tmp,24,2,1);
iowrite32(tmp,led->gpecon);
tmp=ioread32(led->gpeup);
setbit(tmp,12,1,0);
iowrite32(tmp,led->gpeup);
printk("init config led/n");
}
void on_led(struct led_driver *led)
{
unsigned long tmp;
tmp=ioread32(led->gpedat);
setbit(tmp,12,1,0);
iowrite32(tmp,led->gpedat);
}
void off_led(struct led_driver *led)
{
unsigned long tmp;
tmp=ioread32(led->gpedat);
setbit(tmp,12,1,1);
iowrite32(tmp,led->gpedat);
}
int init_led_device(struct led_driver *led)
{
led->virt_base=ioremap(PHYS_BASE,SIZE);
led->gpecon=led->virt_base+0x0;
led->gpedat=led->virt_base+0x04;
led->gpeup=led->virt_base+0x08;
led->conf=con_led;
led->on=on_led;
led->off=off_led;
printk("init suceess/n");
return 0;
}
int led_ioctl(struct inode *inod,struct file *filp,unsigned int cmd,unsigned long args )
{
switch(cmd)
{
case LED_ON:
md->on(md);
break;
case LED_OFF:
md->off(md);
break;
case LED_CON:
md->conf(md);
break;
default:
printk("<kernel > don't know the cmd/n");
return -EINVAL;
}
return 0;
}
struct file_operations f_ops={
.owner=THIS_MODULE,
.ioctl=led_ioctl,
};
int init_led(void)
{
md=kmalloc(sizeof(struct led_driver),GFP_KERNEL);
if(NULL==md){
printk("the kernel has no enough space/n");
goto ERROR1;
}
md->major=0;
md->minor=0;
if(md->major){
md->devno=MKDEV(md->major,md->minor);
register_chrdev_region(md->devno,1,"led driver");
}else{
alloc_chrdev_region(&md->devno,md->minor,1,"led driver");
printk("<kernel>%d,%d/n",MAJOR(md->devno),MINOR(md->devno));
}
cdev_init(&md->led_dev,&f_ops);
if(init_led_device(md)){
printk("init the led device failed/n");
goto ERROR2;
}
if(cdev_add(&md->led_dev,md->devno,1)){
printk("add the led device failed/n");
goto ERROR2;
}
printk("the led device been ready/n");
return 0;
ERROR2:
unregister_chrdev_region(md->devno,1);
kfree(md);
return -ENODEV;
ERROR1:
return -ENOMEM;
}
void exit_led(void)
{
cdev_del(&md->led_dev);
unregister_chrdev_region(md->devno,1);
kfree(md);
}
module_init(init_led);
module_exit(exit_led);
MODULE_LICENSE("GPL");
应用层调用:
#include <stdio.h>
#include "../led_config.h"
#include <error.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc ,char **argv)
{
int fd;
fd=open("/dev/test",O_RDWR);
if(fd<0){
perror("open the device");
return -1;
}
if(argc!=2){
printf("has no parment/n");
return -1;
}
ioctl(fd,LED_CON);
if(strncasecmp(argv[1],"on",2)==0){
printf("LED ON/n");
ioctl(fd,LED_ON);
}
if(strncasecmp(argv[1],"off",3)==0){
printf("LED OFF/n");
ioctl(fd,LED_OFF);
}
close(fd);
return 0;
}