📄 chardev.c
字号:
/*
* chardev.c kf701 2006/12/05
* /dev/kf701_chardev0 /proc/devices
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/cdev.h>
static int chardev_open(struct inode *, struct file *);
static int chardev_release(struct inode *, struct file *);
static ssize_t chardev_read(struct file *, char __user *, size_t, loff_t *);
static ssize_t chardev_write(struct file *, const char __user *, size_t, loff_t *);
#define SUCCESS 0
#define DEVICE "kf701_chardev"
int major = 233;
int minor = 0;
struct file_operations fops = {
.owner = THIS_MODULE,
.read = chardev_read,
.write = chardev_write,
.open = chardev_open,
.release = chardev_release,
};
struct my_dev{
uint8_t *buf;
uint32_t size;
uint32_t index;
struct semaphore sem;
struct cdev cdev;
} 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. 注册设备
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 = 1024;
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);
// 初始化信号量
init_MUTEX( &(kf701_dev.sem) );
printk(KERN_DEBUG "%s:init semaphore OK\n",DEVICE);
return SUCCESS;
}
static void __exit chardev_exit(void)
{
dev_t devno = MKDEV( major, minor );
cdev_del( &kf701_dev.cdev );
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;
printk(KERN_DEBUG "%s:read down sem OK\n",DEVICE);
if( 0 == dev->index )
goto out;
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);
printk(KERN_DEBUG "%s:read up sem OK\n",DEVICE);
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;
printk(KERN_DEBUG "%s:write down sem OK\n",DEVICE);
if( count > dev->size )
goto out;
if( copy_from_user(dev->buf, buf, count) )
{
retval = -EFAULT;
goto out;
}
dev->index = count;
retval = count;
out:
up(&dev->sem);
printk(KERN_DEBUG "%s:write up sem OK\n",DEVICE);
return retval;
}
module_init(chardev_init);
module_exit(chardev_exit);
MODULE_AUTHOR("kf701.ye at gmail.com");
MODULE_DESCRIPTION("Study for kf701");
MODULE_SUPPORTED_DEVICE(DEVICE);
MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -