文章来源:http://blog.csdn.net/zqixiao_09/article/details/50888795
采用设备模型的概念,总线,设备,驱动。先将设备(驱动)挂载到总线上,等待另一个同名的驱动(设备),用match函数进行匹配。如果找到了就调用driver的probe函数将设备和驱动绑定在一起;当设备拔出时,driver调用remove函数清除一些相关的操作
device.c:
<span style="font-size:18px;">
#include <linux/module.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/ioport.h>
static struct resource beep_resource[] =
{
[0] ={
.start = 0x114000a0,
.end = 0x114000a0 + 0x4,
.flags = IORESOURCE_MEM,
},
[1] ={
.start = 0x139D0000,
.end = 0x139D0000 + 0x14,
.flags = IORESOURCE_MEM,
}
};
static void hello_release(struct device *dev)
{
printk("hello_release\n");
return ;
}
/*定义设备结构体*/
static struct platform_device hello_device=
{
.name = "bigbang",
.id = -1,
.dev.release = hello_release,
.num_resources = ARRAY_SIZE(beep_resource),
.resource = beep_resource,
};
static int hello_init(void)
{
printk("hello_init");
return platform_device_register(&hello_device);/*将设备挂到platform总线上*/
}
static void hello_exit(void)
{
printk("hello_exit");
platform_device_unregister(&hello_device);/*从platform总线上撤销*/
return;
}
MODULE_LICENSE("GPL");
module_init(hello_init);
module_exit(hello_exit); </span>
driver.c
<span style="font-size:18px;">
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <asm/io.h>
static int major = 250;
static int minor=0;
static dev_t devno;
static struct class *cls;
static struct device *test_device;
#define TCFG0 0x0000
#define TCFG1 0x0004
#define TCON 0x0008
#define TCNTB0 0x000C
#define TCMPB0 0x0010
static unsigned int *gpd0con;
static void *timer_base;
#define MAGIC_NUMBER 'k'
#define BEEP_ON _IO(MAGIC_NUMBER ,0)
#define BEEP_OFF _IO(MAGIC_NUMBER ,1)
#define BEEP_FREQ _IO(MAGIC_NUMBER ,2)
static void fs4412_beep_init(void)
{
writel ((readl(gpd0con)&~(0xf<<0)) | (0x2<<0),gpd0con);
writel ((readl(timer_base +TCFG0 )&~(0xff<<0)) | (0xff <<0),timer_base +TCFG0);
writel ((readl(timer_base +TCFG1 )&~(0xf<<0)) | (0x2 <<0),timer_base +TCFG1 );
writel (500, timer_base +TCNTB0 );
writel (250, timer_base +TCMPB0 );
writel ((readl(timer_base +TCON )&~(0xf<<0)) | (0x2 <<0),timer_base +TCON );
}
void fs4412_beep_on(void)
{
writel ((readl(timer_base +TCON )&~(0xf<<0)) | (0x9 <<0),timer_base +TCON );
}
void fs4412_beep_off(void)
{
writel ((readl(timer_base +TCON )&~(0xf<<0)) | (0x0 <<0),timer_base +TCON );
}
static void beep_unmap(void)
{
iounmap(gpd0con);
iounmap(timer_base);
}
static int beep_open (struct inode *inode, struct file *filep)
{
fs4412_beep_on();
return 0;
}
static int beep_release(struct inode *inode, struct file *filep)
{
fs4412_beep_off();
return 0;
}
#define BEPP_IN_FREQ 100000
static void beep_freq(unsigned long arg)
{
writel(BEPP_IN_FREQ/arg, timer_base +TCNTB0 );
writel(BEPP_IN_FREQ/(2*arg), timer_base +TCMPB0 );
}
static long beep_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
{
switch(cmd)
{
case BEEP_ON:
fs4412_beep_on();
break;
case BEEP_OFF:
fs4412_beep_off();
break;
case BEEP_FREQ:
beep_freq( arg );
break;
default :
return -EINVAL;
}
return 0;
}
/*操作*/
static struct file_operations beep_ops=
{
.open = beep_open,
.release = beep_release,
.unlocked_ioctl = beep_ioctl,
};
/*在platform总线上找到同名的设备,调用该函数
*对设备资源进行初始化以及注册驱动生成设备文件
*/
static int beep_probe(struct platform_device *pdev)
{
int ret;
printk("match ok!");
gpd0con = ioremap(pdev->resource[0].start,pdev->resource[0].end - pdev->resource[0].start);
timer_base = ioremap(pdev->resource[1].start, pdev->resource[1].end - pdev->resource[1].start);
devno = MKDEV(major,minor);
ret = register_chrdev(major,"beep",&beep_ops);
cls = class_create(THIS_MODULE, "myclass");
if(IS_ERR(cls))
{
unregister_chrdev(major,"beep");
return -EBUSY;
}
test_device = device_create(cls,NULL,devno,NULL,"beep");
if(IS_ERR(test_device))
{
class_destroy(cls);
unregister_chrdev(major,"beep");
return -EBUSY;
}
fs4412_beep_init();
return 0;
}
/*设备拔出时调用该函数*/
static int beep_remove(struct platform_device *pdev)
{
beep_unmap();
device_destroy(cls,devno);
class_destroy(cls);
unregister_chrdev(major,"beep");
return 0;
}
/*定义驱动结构体
*probe和remove函数的入口
*/
static struct platform_driver beep_driver=
{
.driver.name = "bigbang",
.probe = beep_probe,
.remove = beep_remove,
};
static int beep_init(void)
{
printk("beep_init");
/*将驱动挂到platform总线上*/
return platform_driver_register(&beep_driver);
}
static void beep_exit(void)
{
printk("beep_exit");
/*从platform总线上撤销*/
platform_driver_unregister(&beep_driver);
return;
}
MODULE_LICENSE("GPL");
module_init(beep_init);
module_exit(beep_exit); </span>
test.c
<span style="font-size:18px;">
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<stdio.h>
#include<sys/ioctl.h>
#define MAGIC_NUMBER 'k'
#define BEEP_ON _IO(MAGIC_NUMBER ,0)
#define BEEP_OFF _IO(MAGIC_NUMBER ,1)
#define BEEP_FREQ _IO(MAGIC_NUMBER ,2)
int main(void)
{
int fd;
fd=open("/dev/beep",O_RDWR);
if(fd<0)
{
perror("open fail\n");
return 0;
}
ioctl(fd,BEEP_ON);
sleep(6);
ioctl(fd,BEEP_OFF);
close(fd);
return 0;
}
</span>
Makefile:
<span style="font-size:18px;">
ifneq ($(KERNELRELEASE),)
obj-m:=driver.o device.o
else
KDIR:=/lib/modules/$(shell uname -r)/build
PWD:=$(shell pwd)
all:
make -C $(KDIR) M=$(PWD) modules
gcc -Wall -o test test.c
clean:
make -C $(KDIR) M=$(PWD) clean
endif</span>