驱动--(平台设备机制)

总共需要有四个文件,Makefile   led_test.c   led_dev.c   led_drv.c

Makefile

ifeq ($(KERNELRELEASE),)
    KERNELDIR =/home/farsight-xf/linux_src/linux-2.6.35-farsight
    PWD =$(shell pwd)
module:
    $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
    cp led_drv.ko led_dev.ko /opt/filesystem/allen
    
module_install:
    $(MAKE) -C $(KERNELDIR) M=$(PWD) modules install
clean:
    rm -rf *.so *.o *.ko *.mod.c *.order *.symvers

else
    obj-m :=led_drv.o led_dev.o

endif

 

 

led_test.c

#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include<sys/ioctl.h>
#include<unistd.h>
#include<signal.h>

int fd1;
int fd2;
char val1;
char val2;
int ret;
int flags;

void signal_handler(int signal)
{
    ret = read(fd1, &val1, 1);
    switch(val1)
    {
        case 1:            
            val2 = 1;
                break;
        case 2:            
            val2 = 2;
                break;
        case 3:            
            val2 = 3;
                break;
        case 4:            
            val2 = 4;
                break;
        default:            
            val2 = 5;
    }
    write(fd2 ,&val2,1);
    
}

int main(int argc, char **argv)
{

    fd1 = open("/dev/s5pc100_buttons",O_RDWR);
    fd2 = open("/dev/s5pc100_led", O_RDWR);
    if(fd1 < 0)        
    {
        printf("open /dev/buttons failed! \n");
        return -1;        
    }
    if(fd2 < 0)
    {
        printf("open /dev/s5pc100_led error! \n");
        return -1;
    }

    /*--1--信号与信号处理函数绑定*/
    signal(SIGIO,signal_handler);
    /*--2--设置信号的拥有者*/
    fcntl(fd1,F_SETOWN,getpid());
    /*--3--设置异步通知*/
    flags = fcntl(fd1,F_GETFL);
    flags |= FASYNC;
    fcntl(fd1, F_SETFL, flags);
    while(1){
        sleep(1);
        printf("I love sleeping! \n");
    }    
    close(fd1);
    close(fd2);
    return 0;
}


led_dev.c
#include<linux/fs.h>
#include<linux/cdev.h>
#include <linux/platform_device.h>

/*第三步*/
static struct resource s5pc100_led_resources[] = {
    [0] = {
        .start = 0xe03001c0,
        .end = 0xe03001c7,
        .flags = IORESOURCE_MEM,
    },
    [1] = {
        .start =1 ,
        .end = 1,
        .flags = IORESOURCE_IRQ ,
    },
};
static struct resource s5pc100_buttons_resources[] = {
    [0] = {
        .start = 0xE0300C00,
        .end = 0xE0300C07,
        .flags = IORESOURCE_MEM,
    },
    [1] = {
        .start =1 ,
        .end = 1,
        .flags = IORESOURCE_IRQ ,
    },
};


static int s5pc100_led_release(struct device *dev)
{
    return 0;
}
static int s5pc100_buttons_release(struct device *dev)
{
    return 0;
}


/*第二步*/
struct platform_device  s5pc100_dev_led={
    .name = "s5pc100_led",
    .id = -1,
    .num_resources = ARRAY_SIZE(s5pc100_led_resources),
    .resource =s5pc100_led_resources ,
    .dev = {
        .release = s5pc100_led_release,
    }

};
struct platform_device  s5pc100_dev_buttons={
    .name = "s5pc100_buttons",
    .id = -1,
    .num_resources = ARRAY_SIZE(s5pc100_buttons_resources),
    .resource =s5pc100_buttons_resources ,
    .dev = {
        .release = s5pc100_buttons_release,
    }

};


static int __init s5pc100_led_dev_init(void)
{
    /*第一步*/
    platform_device_register(&s5pc100_dev_led);
    platform_device_register(&s5pc100_dev_buttons);
    return 0;
}

static void __exit s5pc100_led_dev_exit(void)
{
    platform_device_unregister(&s5pc100_dev_led);
    platform_device_unregister(&s5pc100_dev_buttons);
}

module_init(s5pc100_led_dev_init);
module_exit(s5pc100_led_dev_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("allen");


led_drv.c
#include<linux/init.h>
#include<linux/module.h>
#include<linux/fs.h>
#include<linux/device.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include<linux/cdev.h>
#include <linux/ioport.h>
#include <linux/skbuff.h>
#include <linux/platform_device.h>

#include<linux/fs.h>
#include<linux/cdev.h>
#include <linux/netdevice.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/ioctl.h>
#include <asm/uaccess.h>
#include <mach/regs-gpio.h>
#include<asm/irq.h>
#include<mach/irqs.h>
#include<linux/interrupt.h>
#include <linux/sched.h>
#include<linux/slab.h>
#include<linux/poll.h>

static volatile unsigned long *gpg3con = NULL;
static volatile unsigned long *gpg3dat = NULL;
static volatile unsigned long *gph0con =NULL;
static volatile unsigned long *gph0dat =NULL;

static unsigned int s5pc100_major = 0;
static unsigned int s5pc100_buttons_major = 0;
static struct class *s5pc100_led_class = NULL;
static struct class *s5pc100_buttons_class = NULL;
static struct cdev *cdev =NULL;

wait_queue_head_t buttons_wq;
struct fasync_struct *mybuttons_fasync;

struct buttons{
    int irq;
    char *name;
    int bit;
    int buttons_val;
    int pin_val;
};

struct buttons buttons_array[6]={
    {IRQ_EINT(1),"key1",1,0x01},
    {IRQ_EINT(2),"key2",2,0x02},
    {IRQ_EINT(3),"key3",3,0x03},
    {IRQ_EINT(4),"key4",4,0x04},
    {IRQ_EINT(6),"key5",6,0x05},
    {IRQ_EINT(7),"key6",7,0x06},
};

char key;

/*定义一个  针对led 的结构体*/
struct s5pc100_led{
    struct cedv *cdev;
    unsigned int pin;
};
/*声明一个结构体指针*/
struct s5pc100_led *s5pc100_ledp;

/*中断第二步,处理程序*/
static irqreturn_t mybutton_handler(int irq,void * dev_id)
{
    struct buttons *cur_pin = (struct buttons *)dev_id;
    
    printk("buttons test ok! \n");
    cur_pin->pin_val = (*gph0dat)&(0x1<<cur_pin->bit);

    if(cur_pin->pin_val){
        /*没有按下*/
        key = cur_pin->buttons_val | 0x80;
    }else{
        key = cur_pin->buttons_val;
    }
    printk("key =%d\n",key);    

    /*---4---唤醒*/
    wake_up_interruptible(&buttons_wq);

    /*发送 信号给应用程序*/
    kill_fasync(&mybuttons_fasync,SIGIO,POLLIN);
    
    return IRQ_HANDLED;
}


int s5pc100_led_open (struct inode *inode, struct file *file)
{
    //*gpg3con &= ~(0xf<<s5pc100_ledp->pin *4);
    //*gpg3con |= (0x1<<s5pc100_ledp->pin *4);
    *gpg3con &= ~0xffff;
    *gpg3con |= 0x1111;
    return 0;
}
static int s5pc100_buttons_open(struct inode *inode, struct file *file)
{
    int i;
    int ret;
    printk("open ok!\n");
    /*中断第一步*/
    for(i = 0; i<6; i++)
    ret = request_irq(buttons_array[i].irq,mybutton_handler,IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING,buttons_array[i].name,&buttons_array[i]);
    return 0;
}
static int s5pc100_buttons_release (struct inode * inode,struct file * file)
{
    int i;
    for(i = 0; i<6; i++)
    free_irq(buttons_array[i].irq,&buttons_array[i]);//中断释放
    return 0;
}

static ssize_t s5pc100_buttons_read(struct file *file, char __user *buf, size_t count, loff_t *opps)
{
    int ret;
    if(key==0 && (file->f_flags & O_NONBLOCK))
        return 0;
    
    /*---3---没有按键按下的时候,则休眠*/
    wait_event_interruptible(buttons_wq,key);
    
    ret = copy_to_user(buf,&key,count);
    key = 0;
    return 1;
}

static int s5pc100_buttons_fasync (int fd, struct file *file, int on)
{
    int tmp;
    tmp = fasync_helper(fd,file,on,&mybuttons_fasync);
    return tmp;
}

ssize_t s5pc100_led_write (struct file *file, const char __user *buf, size_t count, loff_t *opps)
{
    char tmp;
    int ret;
    printk("entered write \n");
    ret = copy_from_user(&tmp,buf,1);
    switch(tmp)
    {
        case 1:
            *gpg3dat |= (0x1<<(s5pc100_ledp->pin));
            break;
        case 2:
            *gpg3dat |= (0x1<<(s5pc100_ledp->pin+1));
            break;
        case 3:
            *gpg3dat |= (0x1<<(s5pc100_ledp->pin+2));
            break;
        case 4:
            *gpg3dat |= (0x1<<(s5pc100_ledp->pin-1));
            break;
        default:
            *gpg3dat = 0x0;
    }
    return 0;
}

struct file_operations s5pc100_led_fops = {
    .owner = THIS_MODULE,
    .open = s5pc100_led_open,
    .write = s5pc100_led_write,
};
struct file_operations s5pc100_buttons_fops={
    .owner = THIS_MODULE,
    .open = s5pc100_buttons_open,
    .release = s5pc100_buttons_release,
    .read = s5pc100_buttons_read,
    .fasync = s5pc100_buttons_fasync,
};

void s5pc100_setup_cdev(void)
{
    dev_t devno = MKDEV(s5pc100_major, 0);
    s5pc100_ledp->cdev = cdev_alloc();
    cdev_init(s5pc100_ledp->cdev,&s5pc100_led_fops);
    cdev_add(s5pc100_ledp->cdev,devno,1);
}
static void s5pc100_buttons_cdev(void)
{
    dev_t devno = MKDEV(s5pc100_buttons_major, 0);
    cdev = cdev_alloc();
    cdev_init(cdev, &s5pc100_buttons_fops);
    cdev->owner = THIS_MODULE;
    cdev_add(cdev,devno,1);
}

int s5pc100_led_probe(struct platform_device *pdev)
{
    dev_t devno;
    struct resource *res;
    printk("entered probe of led\n");
    
    /*获取io 资源*/
    res = platform_get_resource(pdev,IORESOURCE_MEM,0);
    /*映射io 资源*/
    gpg3con = ioremap(res->start, res->end - res->start +1);
    gpg3dat = gpg3con + 1;

    /*为led 结构体分配空间*/
    s5pc100_ledp = kmalloc(sizeof(struct s5pc100_led),GFP_KERNEL);
    /*获取irq 资源*/
    res = platform_get_resource(pdev,IORESOURCE_IRQ,0);
    /*映射irq 资源*/
    s5pc100_ledp->pin = res->start;
    

    /*如果你有子系统的话,就调用子系统的接口函数,
        *注册到子系统里面去如:frambuffer_register
     */
     /*没有子系统的话就注册到内核当中去*/
    /*这种情况就和先前的步骤一样了*/
    alloc_chrdev_region(&devno,0,1,"s5pc100_led");
    s5pc100_major = MAJOR(devno);

    s5pc100_setup_cdev();

    s5pc100_led_class = class_create(THIS_MODULE,"s5pc100_led_class");
    device_create(s5pc100_led_class,NULL,devno,NULL,"s5pc100_led");
    
    return 0;        
}
int s5pc100_buttons_probe(struct platform_device *pdev)
{
    dev_t devno;
    struct resource *res;
    printk("entered probe of buttons\n");
    
    /*获取io 资源*/
    res = platform_get_resource(pdev,IORESOURCE_MEM,0);
    /*映射io 资源*/
    gph0con = ioremap(res->start, res->end - res->start +1);
    gph0dat = gph0con + 1;

    /*如果你有子系统的话,就调用子系统的接口函数,
        *注册到子系统里面去如:frambuffer_register
     */
     /*没有子系统的话就注册到内核当中去*/
    /*这种情况就和先前的步骤一样了*/
    alloc_chrdev_region(&devno,0,1,"s5pc100_buttons");
    s5pc100_buttons_major= MAJOR(devno);

    s5pc100_buttons_cdev();

    s5pc100_buttons_class = class_create(THIS_MODULE,"s5pc100_buttons_class");
    device_create(s5pc100_buttons_class,NULL,devno,NULL,"s5pc100_buttons");

    init_waitqueue_head(&buttons_wq);
    
    return 0;        
}

int s5pc100_led_remove(struct platform_device *pdev)
{
    dev_t devno = MKDEV(s5pc100_major, 0);
    unregister_chrdev_region(devno,1);
    device_destroy(s5pc100_led_class,devno);
    class_destroy(s5pc100_led_class);
    iounmap(gpg3con);
    return 0;
}
int s5pc100_buttons_remove(struct platform_device *pdev)
{
    dev_t devno = MKDEV(s5pc100_buttons_major,0);
    unregister_chrdev_region(devno,1);//设备号
    device_destroy(s5pc100_buttons_class,devno);//设备节点
    class_destroy(s5pc100_buttons_class);
    cdev_del(cdev);//设备结构体
    iounmap(gph0con);
    return 0;
}

/*第二步*/
struct platform_driver s5pc100_led_drv = {
    .probe = s5pc100_led_probe,
    .remove = s5pc100_led_remove,
    .driver = {
        .name = "s5pc100_led",
        .owner = THIS_MODULE,
    },
};
struct platform_driver s5pc100_buttons_drv = {
    .probe = s5pc100_buttons_probe,
    .remove = s5pc100_buttons_remove,
    .driver = {
        .name = "s5pc100_buttons",
        .owner = THIS_MODULE,
    },
};

static int __init s5pc100_led_drv_init(void)
{
    /*第一步*/
    platform_driver_register(&s5pc100_led_drv);
    platform_driver_register(&s5pc100_buttons_drv);
    return 0;
}

static void __exit s5pc100_led_drv_exit(void)
{
    platform_driver_unregister(&s5pc100_led_drv);    
    platform_driver_unregister(&s5pc100_buttons_drv);
}

module_init(s5pc100_led_drv_init);
module_exit(s5pc100_led_drv_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("allen");



posted on 2012-05-20 10:23  小风儿_xf  阅读(633)  评论(2编辑  收藏  举报

导航