kf701_dev->timer_char = 'A';
init_timer( &kf701_dev->timer );
kf701_dev->timer_interval = HZ * TIMER_INTERVAL;
kf701_dev->timer.function = timer_function;
kf701_dev->timer.expires = jiffies + kf701_dev->timer_interval;
kf701_dev->timer.data = (unsigned long)kf701_dev;
add_timer( &kf701_dev->timer );
printk(KERN_DEBUG "%s:init timer OK\n",DEVICE);
return SUCCESS;
}
static void __exit chardev_exit(void)
{
dev_t devno = MKDEV( major, minor );
// 以相反的顺序清除
del_timer_sync( &kf701_dev->timer );
printk(KERN_DEBUG "%s:del timer OK\n",DEVICE);
kfree( kf701_dev->buf );
cdev_del( &kf701_dev->cdev );
kfree( kf701_dev );
printk(KERN_DEBUG "%s:kfree OK\n",DEVICE);
unregister_chrdev_region( devno, 1 );
printk(KERN_DEBUG "%s:unregister device OK\n",DEVICE);
}
int chardev_open(struct inode *inode, struct file *file)
{
struct my_dev *dev = container_of(inode->i_cdev, struct my_dev, cdev);
file->private_data = dev;
printk(KERN_DEBUG "%s:open OK\n",DEVICE);
return SUCCESS;
}
int chardev_release(struct inode *inode, struct file *file)
{
printk(KERN_DEBUG "%s:release OK\n",DEVICE);
return SUCCESS;
}
ssize_t chardev_read(struct file *file, char __user *buf, size_t count,loff_t *offset)
{
struct my_dev *dev = file->private_data;
ssize_t retval = 0;
if( down_interruptible(&dev->sem) )
return -ERESTARTSYS;
// 增加了对NONBLOCK的支持
while( 0 == dev->index )
{
up(&dev->sem);
if( file->f_flags & O_NONBLOCK )
return -EAGAIN;
// 在这里准备睡眠,等待条件为真
if( wait_event_interruptible(dev->rq, (0 != dev->index)) )
return -ERESTARTSYS; // 返回非0表示被信号中断
if( down_interruptible(&dev->sem) )
return -ERESTARTSYS; // 先取得锁再检查条件
}
if( *offset >= dev->index )
goto out;
if( (*offset+count) > dev->index )
count = dev->index - *offset;
if( copy_to_user(buf, dev->buf + *offset, count) )
{
retval = -EFAULT;
goto out;
}
*offset += count;
retval = count;
out:
up(&dev->sem);
return retval;
}
// omit offset argument for write
ssize_t chardev_write(struct file *file, const char __user *buf, size_t count, loff_t *offset)
{
struct my_dev *dev = file->private_data;
ssize_t retval = -ENOMEM;
if( down_interruptible(&dev->sem) )
return -ERESTARTSYS;
if( count > dev->size )
count = dev->size - 1;
if( copy_from_user(dev->buf, buf, count) )
{
retval = -EFAULT;
goto out;
}
dev->index = count;
retval = count;
out:
up(&dev->sem);
// 唤醒阻塞在 read 和 select 上的进程
if( retval > 0 )
wake_up_interruptible(&dev->rq);
return retval;
}
阅读(1192) | 评论(0) | 转发(0) |