add task 6

This commit is contained in:
rick 2023-01-30 02:00:23 +01:00
parent ed31555471
commit 2fca35a3d5
Signed by: Rick
GPG key ID: 4A6223D66294EB20
3 changed files with 190 additions and 0 deletions

View file

@ -135,6 +135,44 @@ Il faut le décharger à la main avec `rmmod`.
* [usb-skeleton.c (Code Kernel)](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/usb/usb-skeleton.c)
* [Nihaal - Eudyptula Challenge Task 5](https://nihaal.me/post/ec5/)
## Tache 6
Il existe plusieurs façons pour créer un nouveau fichier dans `/dev`. J'ai
cependant décidé d'implémenter qu'une seule manière pour l'instant.
Pour pouvoir créer un fichier dans `/dev`, il faut créer le périphérique à la
main. Il faut connaitre le numéro majeur du driver, ce qui se fait ou en
regardant dans le fichier `/proc/devices` ou en regardant le journal du kernel.
Il suffit de taper la commande suivante pour créer le fichier :
`mknod /dev/eudyptula c <majeur> 0`. N'oubliez pas de changer les droits si
vous souhaitez écrire dedans !
**Je n'ai pas suivi les consignes à la lettre, en effet je n'utilise pas un
*misc char device* mais un *char device*.** C'est pour ça qu'il faut créer à
la main le device. Je l'ai codé directement comme ça, ne trouvant pas beaucoup
d'informations sur les *misc char devices*. En lisant des codes sources ainsi
que la documentation, je comprends mieux comment en faire mais j'ai décidé de
ne pas changer tout le code que j'avais fait. Cepedant, je le modifierai si
l'on doit faire un *char device* plus tard.
Lorsqu'on ouvre le device, on reçoit la chaine `coucou c'est rick`. Si l'on
souhaite écrire dans le fichier, il faut taper `congruent`, sinon un message
d'erreur est retourné.
```bash
cat /dev/eudyptula
# coucou c'est rick
echo "congruent" > /dev/eudyptula
# aucune réponse, $? vaut 0
echo "bonjour12" > /dev/eudyptula
-bash: echo: erreur d'écriture : Argument invalide
# $? vaut 1
```
* [Chapitre 3, Linux Device Drivers, 3rd Edition](https://lwn.net/Kernel/LDD3/)
* [Linux Kernel Labs - Character device drivers](https://linux-kernel-labs.github.io/refs/heads/master/labs/device_drivers.html#read-and-write)
* [Nihall - Misc character devices](https://nihaal.me/post/misc_char_devices/)
## Informations diverses
Je liste dans cette section quelques informations que j'ai pu découvrir en

9
task_6/Makefile Normal file
View file

@ -0,0 +1,9 @@
obj-m += misc-device.o
PWD := $(CURDIR)
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

143
task_6/misc-device.c Normal file
View file

@ -0,0 +1,143 @@
// SPDX-License-Identifier: GPL-2.0
/* TODO
* créer char device avec un mineur dynamique
* appeler le device eudyptula
*/
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/string.h>
#define BUFFER_LENGTH 10
#define NUMBER_MINORS 1
static char *msg;
static int major;
static ssize_t my_read(struct file *, char __user *buffer, size_t length,
loff_t *offset)
{
/* le nombre de bytes qu'on va lire */
int bytes = 0;
/* le pointeur qui va parcourir notre message pour le mettre dans le buffer
* du userspace
*/
const char *msg_tmp = msg;
/* si on essaie de lire plus que le message */
if (!*(msg + *offset)) {
*offset = 0; /* on reset l'offset */
return 0; /* on a rien lu */
}
/* on commence à l'offset */
msg_tmp += *offset;
while (*msg_tmp && bytes < length) {
/* on va copier char par char le message dans le userspace */
put_user(*(msg_tmp), (buffer + bytes));
bytes++;
msg_tmp++;
}
/* on déplace l'offset du nombre de bytes qu'on a lu */
*offset += bytes;
return bytes;
}
static ssize_t my_write(struct file *, const char __user *buffer,
size_t size, loff_t *)
{
int ret;
/* là où on stocke l'entrée utilisateur */
char *tmp_buffer;
/* on peut pas écrire dans un buffer sans place */
if (size == 0)
return 0;
/* on alloue BUFFER_LENGTH qui vaut exactement la taille de "congruent", le
* mot qu'on souhaite détecter
*/
tmp_buffer = kzalloc(BUFFER_LENGTH, GFP_KERNEL);
/* si on arrive pas à copier les données utilisateurs, on retourne une
* erreur
*/
if (copy_from_user(tmp_buffer, buffer, BUFFER_LENGTH)) {
kfree(tmp_buffer);
return -EINVAL;
}
/* comme on copie des bytes et non une string, il faut mettre le byte de fin
* de string manuellement, à la fin du buffer.
*/
*(tmp_buffer + BUFFER_LENGTH - 1) = '\0';
pr_info("Test %s-\n", tmp_buffer);
if (!strcmp(tmp_buffer, "congruent"))
/* on retourne la longueur du buffer écrit pour dire que tout est OK */
ret = BUFFER_LENGTH;
else
ret = -EINVAL;
kfree(tmp_buffer);
return ret;
}
static const struct file_operations fops = {
.owner = THIS_MODULE,
.read = my_read,
.write = my_write,
};
static struct cdev *my_cdev;
static int __init my_init(void)
{
dev_t dev;
int ret;
msg = kmalloc(19, GFP_KERNEL);
strcpy(msg, "coucou c'est rick\n");
/* on demande un numéro majeur dynamiquement avec uniquement un seul numéro
* mineur
*/
ret = alloc_chrdev_region(&dev, 0, NUMBER_MINORS, "eudyptula");
if (ret)
pr_err("Erreur lors de l'initialisation du device : %d\n", ret);
major = MAJOR(dev); /* on récupère le numéro majeur alloué */
/* on initialise notre chardevice */
my_cdev = cdev_alloc();
my_cdev->ops = &fops;
my_cdev->owner = THIS_MODULE;
ret = cdev_add(my_cdev, dev, NUMBER_MINORS);
if (ret)
pr_err("Erreur lors de la création du device : %d\n", ret);
pr_info("Initialisation terminée, majeur: %d\n", major);
return 0;
}
static void __exit my_exit(void)
{
dev_t dev;
pr_info("Suppression du device avec pour majeur: %d\n", major);
kfree(msg);
cdev_del(my_cdev);
dev = MKDEV(major, 0);
unregister_chrdev_region(dev, NUMBER_MINORS);
}
module_init(my_init);
module_exit(my_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("rick <rick@gnous.eu>");
MODULE_DESCRIPTION("Création d'un device accessible en lecture et écriture.");