全部博文(404)
分类: LINUX
2008-09-26 10:59:11
/* * kf701_chardev.c
* 2006-12-06 13:22:22
* Contact me: kf701.ye AT gmail.com
* 2.6内核字符驱动示例程序,供学习。
* /dev/kf701_chardev0
* /proc/devices
* 分配1024个字节的buffer,对/dev/kf701_chardev0的读写将
* 作用到buffer上。目前的写操作会覆盖先前的buffer。
* 内核定时器每次向buffer里追加一个字符和一个回车。
*
* 测试方法:
* $> echo "only for test" > /dev/kf701_chardev0
* $> cat /dev/kf701_chardev0
*
* 2006-12-18 09:19:44 修改
* 加入对 NONBLOCK 和 poll 的支持。
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/cdev.h>
#include <linux/timer.h>
#include <linux/jiffies.h>
#include <linux/ioctl.h>
#include <linux/poll.h>
#include <linux/wait.h>
int chardev_open(struct inode *, struct file *);
int chardev_release(struct inode *, struct file *);
ssize_t chardev_read(struct file *, char __user *, size_t, loff_t *);
ssize_t chardev_write(struct file *, const char __user *, size_t, loff_t *);
int chardev_ioctl(struct inode *,struct file *,unsigned int,unsigned long);
unsigned int chardev_poll(struct file* file, poll_table *wait);
void timer_function(unsigned long);
#define DEVICE "kf701_chardev"
#define SUCCESS 0
#define BUF_SIZE 1024
#define TIMER_INTERVAL 20 // 每20秒运行一次定时器函数
int major = 233;
int minor = 0;
// define ioctl command
#define KF701_IOC_MAGIC 'K'
#define KF701_IO_RESET _IO(KF701_IOC_MAGIC,0)
#define KF701_IO_R _IOR(KF701_IOC_MAGIC,1,int)
#define KF701_IO_W _IOW(KF701_IOC_MAGIC,2,int)
#define KF701_IO_RW _IOWR(KF701_IOC_MAGIC,3,int)
#define KF701_IOC_MAXNR 4
struct file_operations fops = {
.owner = THIS_MODULE,
.read = chardev_read,
.write = chardev_write,
.open = chardev_open,
.release = chardev_release,
.ioctl = chardev_ioctl,
.poll = chardev_poll,
};
struct my_dev{
wait_queue_head_t rq; // 读取等待队列
uint8_t *buf;
uint32_t size;
uint32_t index;
struct semaphore sem;
struct cdev cdev;
struct timer_list timer;
char timer_char;
uint32_t timer_interval;
};
struct my_dev *kf701_dev;
static int __init chardev_init(void)
{
// 1. 分配主设备号
dev_t devno = MKDEV( major, minor );
int ret = register_chrdev_region( devno, 1, DEVICE );
if( ret < 0 )
{
printk(KERN_DEBUG "register major number failed with %d\n", ret);
return ret;
}
printk(KERN_DEBUG "%s:register major number OK\n",DEVICE);
// 2. 注册设备
kf701_dev = kmalloc(sizeof(struct my_dev), GFP_KERNEL);//分配内存
memset( kf701_dev, 0, sizeof(struct my_dev) );//内存管理
cdev_init( &kf701_dev->cdev, &fops );//初始化
kf701_dev->cdev.ops = &fops;
kf701_dev->cdev.owner = THIS_MODULE;
ret = cdev_add( &kf701_dev->cdev, devno, 1 );//设备注册函数
if( ret < 0 )
{
printk(KERN_DEBUG "register device failed with %d\n", ret);
return ret;
}
printk(KERN_DEBUG "%s:register device OK\n",DEVICE);
// 3. 分配本驱动要使用的内存
kf701_dev->index = 0; //起始地址
kf701_dev->size = BUF_SIZE;//空间大小
kf701_dev->buf = kmalloc( kf701_dev->size, GFP_KERNEL );//分配空间
if( NULL == kf701_dev->buf ) //空间分配失败
{
printk(KERN_DEBUG "kmalloc failed\n");
return -ENOMEM;
}
printk(KERN_DEBUG "%s:kmalloc buffer OK\n",DEVICE);
// 4. 初始化信号量
init_MUTEX( &(kf701_dev->sem) );
printk(KERN_DEBUG "%s:init semaphore OK\n",DEVICE);
// 5. 初始化等待队列头
init_waitqueue_head(&kf701_dev->rq);
// 6. 初始化并启动定时器