Aquí es un simple controlador de dispositivo de caracteres.
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
static unsigned int simple_dev_major_num = 222;
module_param(simple_dev_major_num, uint, S_IRUGO);
struct simple_cdev{
struct cdev scdev;
unsigned char data;
};
static struct simple_cdev *psimle_cdev = NULL;
int simple_cdev_open(struct inode *pinode, struct file *pfile)
{
return 0;
}
int simple_cdev_close(struct inode *pinode, struct file *pfile)
{
return 0;
}
static const struct file_operations simple_cdev_fopt = {
.owner = THIS_MODULE,
.open = simple_cdev_open,
.release =simple_cdev_close,
};
static int __init simple_cdev_init(void)
{
int ret;
dev_t devno = MKDEV(simple_dev_major_num, 0);
//申请/注册设备号
if ( 0 == simple_dev_major_num )
{
ret = register_chrdev_region(devno, 1, "simple cdev");
}
else
{
ret = alloc_chrdev_region(&devno, 0, 1, "simple cdev");
simple_dev_major_num = devno;
}
if ( ret < 0 )
{
printk(KERN_ERR "simple cdev get device num error\n");
return ret;
}
psimle_cdev = kzalloc(sizeof(struct simple_cdev), GFP_KERNEL);
if ( !psimle_cdev )
{
printk(KERN_ERR "simple cdev get memory failed\n");
unregister_chrdev_region(devno, 1);
return -ENOMEM;
}
//初始化字符设备
cdev_init(&psimle_cdev->scdev, &simple_cdev_fopt);
psimle_cdev->scdev.owner = THIS_MODULE;
//添加设备
ret = cdev_add(&psimle_cdev->scdev, devno, 1);
if ( ret < 0 )
{
printk(KERN_ERR "add cdev failed\n");
unregister_chrdev_region(devno, 1);
return ret;
}
printk(KERN_INFO "simple cdev enter\n");
return 0;
}
module_init(simple_cdev_init);
static void __exit simple_cdev_exit(void)
{
printk(KERN_INFO "simple cdev exit\n ");
if ( NULL != psimle_cdev )
{
cdev_del(&psimle_cdev->scdev);
kfree(psimle_cdev);
}
unregister_chrdev_region(simple_dev_major_num, 1);
}
module_exit(simple_cdev_exit);
MODULE_AUTHOR("[email protected]");
MODULE_LICENSE("GPL v2");
Que contiene varios estructura clave struct file
, struct inode
, struct cdev
, struct file_operations
. La estructura de estos capa de aplicación del archivo abierto del dispositivo, leer, escribir y otras operaciones asociadas controlador de dispositivo real. La siguiente figura muestra la relación entre los controladores de dispositivo de caracteres y sistemas de archivos.
Típicamente un carácter específico del dispositivo se describirá en la siguiente forma:
struct simple_cdev{
struct cdev scdev;
unsigned char data;
...
...
};
Struct cdev simple_cdev struct equivalente es la clase base, si se describe en C ++:
class cdev{
};
class simple_cdev::cdev{
unsigned char data;
...
...
};
Struct cdev varias funciones clave de la operación contenidos en el fichero linux / fs / char_dev.c archivo
int register_chrdev_region(dev_t from, unsigned count, const char *name);
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,
const char *name);
void unregister_chrdev_region(dev_t from, unsigned count);
void cdev_init(struct cdev *cdev, const struct file_operations *fops);
int cdev_add(struct cdev *p, dev_t dev, unsigned count);
void cdev_del(struct cdev *p);
Exportan el enlace simbólico por SYMBOL_EXPORT, para usos distintos LKM:
EXPORT_SYMBOL(register_chrdev_region);
EXPORT_SYMBOL(unregister_chrdev_region);
EXPORT_SYMBOL(alloc_chrdev_region);
EXPORT_SYMBOL(cdev_init);
EXPORT_SYMBOL(cdev_alloc);
EXPORT_SYMBOL(cdev_del);
EXPORT_SYMBOL(cdev_add);
Las tres primeras x__chrdev_region
funciones son la aplicación y el número de dispositivo, en función de la liberación de las operaciones relacionadas. cdev_init
Los file_operations struct struct cdev y definido en el interior del controlador de dispositivo está asociado. De hecho, los miembros de las operaciones de asignación struct cdev para los petimetres especificados. cdev_add, cdev_del
A / desde los dispositivos de sistema de Añadir / Quitar, debe ser estructuras de datos relacionados kobject específicos organizados temporalmente para kobject no saben, no hacen análisis.
struct cdev {
struct kobject kobj;
struct module *owner;
const struct file_operations *ops;
struct list_head list;
dev_t dev;
unsigned int count;
};