一、开发环境
1、硬件平台:FS2410
2、主机:Ubuntu 10.10
3、内核版本:linux-2.6.35
4、交叉编译工具链:arm-none-linux-gnueabi-
二、详细代码
1、驱动代码:(beep_drv.c)
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/time.h>
#include <linux/irq.h>
#include <asm/delay.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
#include <linux/poll.h>
#include <asm/irq.h>
#include <mach/regs-gpio.h>
#define TCFG0 0x51000000
#define TCFG1 0x51000004
#define TCON 0x51000008
#define TCNTB0 0x5100000C
#define TCMPB0 0x51000010
#define GPBCON 0x56000010
static volatile unsigned int *tcfg0;
static volatile unsigned int *tcfg1;
static volatile unsigned int *tcon;
static volatile unsigned int *tcntb0;
static volatile unsigned int *tcmpb0;
static volatile unsigned int *gpbcon;
static int beep_major = 249;
struct beep_dev
{
struct cdev cdev;
};
struct beep_dev dev;
void ioremap_gpio(void)
{
tcfg0 = ioremap(TCFG0, 0x4);
tcfg1 = ioremap(TCFG1, 0x4);
tcon = ioremap(TCON, 0x4);
tcntb0 = ioremap(TCNTB0, 0x4);
tcmpb0 = ioremap(TCMPB0, 0x4);
gpbcon = ioremap(GPBCON, 0x4);
return ;
}
void init_gpio(void)
{
ioremap_gpio();
writel(readl(gpbcon) & ~(3 << 0), gpbcon);
writel(readl(gpbcon) | (2 << 0), gpbcon);
writel(readl(tcfg0) | (254 << 0), tcfg0);
writel(readl(tcfg1) & ~(0xf << 0), tcfg1);
writel(10000, tcntb0);
writel(800, tcmpb0);
writel(readl(tcon) | (0xf << 0), tcon);
writel(readl(tcon) & ~(1 << 1), tcon);
return ;
}
static int beep_open(struct inode *inode, struct file *filp)
{
init_gpio();
return 0;
}
static int beep_release(struct inode *inode, struct file *filp)
{
return 0;
}
static ssize_t beep_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos)
{
return 0;
}
static ssize_t beep_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos)
{
return 0;
}
static int beep_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
{
return 0;
}
static struct file_operations beep_fops = {
.owner = THIS_MODULE,
.open = beep_open,
.release = beep_release,
.read = beep_read,
.write = beep_write,
.ioctl = beep_ioctl,
};
static void beep_setup_cdev(struct cdev *dev, int index)
{
int err;
int devno = MKDEV(beep_major, index);
cdev_init(dev, &beep_fops);
dev->owner = THIS_MODULE;
err = cdev_add(dev, devno, 1);
if(err)
printk("Error %d adding beep %d\n", err, index);
return ;
}
static int __init beep_init(void)
{
int result;
int devno = MKDEV(beep_major, 0);
if(beep_major)
result = register_chrdev_region(devno, 1, "beep");
else
{
result = alloc_chrdev_region(&devno, 0, 1, "beep");
beep_major = MAJOR(devno);
}
if(result < 0)
return result;
beep_setup_cdev(&dev.cdev, 0);
printk("beep_major : %d\n", beep_major);
return 0;
}
static void __exit beep_exit(void)
{
cdev_del(&dev.cdev);
unregister_chrdev_region(MKDEV(beep_major, 0), 1);
return ;
}
module_init(beep_init);
module_exit(beep_exit);
MODULE_AUTHOR("yhr");
MODULE_LICENSE("GPL");
2、测试程序(beep_test.c):
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
int main()
{
int dev_fd;
if((dev_fd = open("/dev/beep", O_RDONLY)) < 0)
{
perror("failed to open beep");
exit(-1);
}
while(1);
return 0;
}
3、Makefile
ifeq ($(KERNELRELEASE),)
#KERNELDIR ?= /your/target/source/directory/
KERNELDIR ?= /home/linux/linux-2.6.35/
PWD := $(shell pwd)
modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
modules_install:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions Module* modules*
.PHONY: modules modules_install clean
else
obj-m := beep_drv.o
endif