Skip to content

Instantly share code, notes, and snippets.

@icarofreire
Last active August 29, 2015 14:20
Show Gist options
  • Save icarofreire/8ce0a8b0f8168420e08f to your computer and use it in GitHub Desktop.
Save icarofreire/8ce0a8b0f8168420e08f to your computer and use it in GitHub Desktop.
comunicação com espaço de usuário e espaço de kernel.
#include <linux/module.h>
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/slab.h>
#include <linux/err.h>
#define DEVICE_NAME_1 "mod_1"
#define DEVICE_NAME_2 "mod_2"
#define NUM_DISPOSITIVOS 1 /* números de arquivos do dispositivo */
#define TAM_MSG 100//1024
static char msg[TAM_MSG];
#define ERRO(P)\
if(IS_ERR_OR_NULL(P)){\
printk(KERN_ERR "Erro ou Nulo");\
return PTR_ERR(P);\
}
/* prototypes */
static int modulo_open(struct inode *inode, struct file *file);
static ssize_t modulo_read(struct file *file, char *buf, size_t count, loff_t *ppos);
static ssize_t modulo_write(struct file *file, const char *buf, size_t count, loff_t *ppos);
static int modulo_release(struct inode *inode, struct file *file);
/* file operations structure */
static struct file_operations modulo_fops = {
.owner = THIS_MODULE,
.open = modulo_open,
.release = modulo_release,
.read = modulo_read,
.write = modulo_write,
};
struct cdev c_dev;
/* leds driver major number */
/* dev_t estrutura para criar o major e minor number */
static dev_t modulo_dev_number;
/* class for the sysfs entry */
struct class *modulo_class;
/* driver initialization */
static int __init modulo_init(void)
{
int ret;
struct device *dev_ret;
/* request device major number */
if ((ret = alloc_chrdev_region(&modulo_dev_number, 0, NUM_DISPOSITIVOS, DEVICE_NAME_1) < 0)) {
printk(KERN_DEBUG "Erro ao registrar device!\n");
return ret;
}
/* create /sys entry */
modulo_class = class_create(THIS_MODULE, DEVICE_NAME_2);
if( IS_ERR(modulo_class) )
{
printk(KERN_ERR "Erro em /sys entry.");
unregister_chrdev_region(modulo_dev_number, 1);
return PTR_ERR(modulo_class);
}
/* connect file operations to this device */
cdev_init(&c_dev, &modulo_fops);
c_dev.owner = THIS_MODULE;
/* connect major/minor numbers */
if ( (ret = cdev_add(&c_dev, modulo_dev_number, 1)) < 0)
{
printk(KERN_DEBUG "Erro ao adicionar o dispositivo!\n");
device_destroy(modulo_class, modulo_dev_number);
class_destroy(modulo_class);
unregister_chrdev_region(modulo_dev_number, 1);
return ret;
}
// dev_t corresponding <major, minor>
/* send uevent to udev to create /dev node */
dev_ret = device_create(modulo_class, NULL, modulo_dev_number, NULL, "modulo_dev");
if( IS_ERR(dev_ret) )
{
printk(KERN_ERR "Erro ao criar o device em /dev.");
class_destroy(modulo_class);
unregister_chrdev_region(modulo_dev_number, 1);
return PTR_ERR(dev_ret);
}
printk(KERN_INFO "Driver inicializado.\n");
/* ... */
return 0;
}
/* driver exit */
static void __exit modulo_exit(void)
{
cdev_del(&c_dev);
device_destroy(modulo_class, modulo_dev_number );
/* destroy class */
class_destroy(modulo_class);
/* release major number */
unregister_chrdev_region(modulo_dev_number, NUM_DISPOSITIVOS);
printk(KERN_INFO "Exiting leds driver.\n");
}
/* open file */
static int modulo_open(struct inode *inode, struct file *file)
{
printk(KERN_INFO "Driver: open()\n");
/* return OK */
return 0;
}
/* close file */
static int modulo_release(struct inode *inode, struct file *file)
{
/* return OK */
return 0;
}
/* read status */
static ssize_t modulo_read(struct file *file, char *buf, size_t count, loff_t *ppos)
{
printk(KERN_INFO "Driver: read()\n");
printk(KERN_INFO "In chardrv read routine.\n");
printk(KERN_INFO "O tamanho é: %lu.\n", count);
printk(KERN_INFO "Offset é: %lu.\n", *ppos);
int maxbytes; // máximo de bytes que podem ser lidos a partir de *ppos para TAM_MSG;
int bytes_p_ler; // indica o número de bytes a ser lido;
int bytes_lidos; // número de bytes realmente lidos;
/*
maxbytes = TAM_MSG - *ppos;
if( maxbytes > count ){
bytes_p_ler = count; // se o resto dos bytes para ler do buffer, for maior que count, então não há mais bytes para ler; count será igual a zero;
}else{
bytes_p_ler = maxbytes; // mais bytes para ler, existe mais bytes no buffer;
}
*/
maxbytes = TAM_MSG - *ppos;
bytes_p_ler = maxbytes;
if( maxbytes == 0 ){
return bytes_lidos;
}
if( bytes_p_ler == 0 ){ // Atingido o final do dispositivo.
printk(KERN_INFO "Atingido o final do dispositivo\n");
}
/* copy_to_user:
Retorna o número de bytes que não puderam ser copiados.
Em caso de sucesso, esta será zero.
* */
bytes_lidos = bytes_p_ler - copy_to_user(buf, msg, bytes_p_ler);
printk(KERN_INFO "dispositivo foi lido: %d\n",bytes_lidos);
*ppos += bytes_lidos;
printk(KERN_INFO "dispositivo foi lido.\n");
return bytes_lidos;
}
/* write status */
static ssize_t modulo_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
{
printk(KERN_INFO "Driver: write()\n");
printk(KERN_INFO "MODULO WRITE: Offset é: %lu.\n", *ppos);
memset(msg,0,TAM_MSG);
int length = count;
if (length > TAM_MSG - 1){
length = TAM_MSG - 1;
}
if (length < 0){
return -EINVAL; /* Invalid argument */
}
/* copy_from_user:
Retorna o número de bytes que não puderam ser copiados.
Em caso de sucesso, esta será zero.
Se alguns dados não puderam ser copiados, esta função irá preencher os copiados
dados para o tamanho solicitado usando zero bytes.
* */
if (copy_from_user(msg, buf, length)){
return -EFAULT; /* Bad address */
}
return count;
}
module_init(modulo_init);
module_exit(modulo_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Icaro Freire Martins");
MODULE_DESCRIPTION("Treinamento de Character Driver");
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment