TIBERGHIEN corentin 6ad8705650 rapport pdf
2026-02-24 14:23:20 +01:00
2026-02-17 15:22:20 +01:00
2026-02-17 15:23:16 +01:00
2026-02-17 15:11:25 +01:00
2026-02-17 15:22:20 +01:00
2026-02-24 14:23:20 +01:00
2026-02-24 14:23:20 +01:00
2026-02-24 14:20:07 +01:00
2026-02-17 15:10:34 +01:00

journal de bord

super document partage

etat initial du device : lorsqu'on le branche, lsmod retourne cette ligne :

usbnet                 61440  1 cdc_ether

qui est le driver charge nativement par le kernel.

il existe un moyen de "blacklist" ce-dit driver :

creer un fichier :

echo "blacklist cdc_ether" | sudo tee /etc/modprobe.d/blacklist.conf

puis mettre a jour le initramfs :

sudo update-initramfs -u

En l'etat (5/2/26) le driver s'installe, s'attache au device ch397 puis creer une interface reseau sur la machine. on peut alors recuperer le nom de l'interface grace a :

ip a

puis attribuer une IP a l'interface grace aux commandes suivantes :

sudo ip addr add 192.168.1.100/24 dev <nom_interface>
sudo ip link set <nom_interface> up

ce qui nous permet ensuite, depuis une autre machine d'envoyer des pings a l'ip (192.168.1.100) qui sont ensuite parses en hexadecimal et affiches sur l'interface usb (visibles en executant dmesg | grep ch397)

Todo

  • Enregistrer une interface réseau
  • Implémenter les opérations réseau
  • Gérer la réception de trames
    • Soumettre des URBs (USB Request Blocks) pour lire en continu sur l'endpt. IN
    • Parser les trames ethernet reçues
    • Les passer au network stack avec netif_rx(skb)
  • Gérer l'émission de trames
  • Récupérer l'adresse MAC
  • Gérer les contrôles CDC
    • Link up/down notifications via endpoint interrupt (0x81)
    • Vitesse de connexion (10/100 Mbps)
    • Statistiques réseau
  • Gestion d'énergie et erreurs
    • Gérer les déconnexions brutales
    • Suspend/Resume propres
    • Récupération d'erreurs USB

Utile

https://cdn.promelec.ru/upload/items/2025/09/18/CH397_.pdf

Introduction

Un driver (pilote) est un composant logiciel qui fait linterface entre le noyau du système dexploitation et un périphérique matériel ou une couche dabstraction. Il traduit les demandes génériques du système (lire/écrire, configurer, envoyer/recevoir paquets, etc.) en opérations spécifiques au matériel, et inversement expose létat et les événements matériels au système.

Principales responsabilités

  • Initialisation et énumération : détecter le matériel, allouer ressources et configurer le périphérique.
  • Traduction dappels : implémenter les callbacks et API attendus par le soussystème du noyau (ex. net_device ops, block ops, file ops) pour que le reste du système utilise le périphérique de façon standardisée.
  • Gestion des I/O : orchestrer transferts (DMA, URB, interruptions), mise en file dattente, copies de buffers et synchronisation.
  • Gestion derreurs et robustesse : détecter conditions derreur, reprendre, nettoyer proprement à la déconnexion ou en cas déchec.
  • Exposition des fonctionnalités avancées : support doptions matérielles (offloads, mise en veille, statistiques, configurations spécifiques).
  • Concurrence et sécurité : protéger les ressources partagées (mutex, spinlock), respecter les contextes dexécution (process/context IRQ/softirq).

Types et niveaux

  • Pilotes noyau (inkernel) : sexécutent au sein du noyau, offrent faibles latences et accès direct au matériel (ex. pilotes réseaux, disques, USB).
  • Pilotes en espace utilisateur : utilisent un mécanisme de médiation (ex. UIO, libusb) et conviennent pour prototypage ou usages moins critiques.
  • Pilotes de classe vs vendorspecific : les pilotes de classe implémentent une interface standard (ex. CDC, HID) interopérable ; les pilotes vendorspecific gèrent fonctionnalités propriétaires.

Propriétés attendues

  • Stabilité et sécurité : ne pas corrompre la mémoire noyau, gérer correctement les erreurs et concurrents.
  • Performance : minimiser copies, utiliser offloads matériels, gérer pools/URB/queues pour hauts débits.
  • Portabilité et intégration : respecter les conventions du soussystème kernel concerné (APIs, structures, callbacks, sysfs/ethtool si applicable).

Présentation CH397

Le CH397 est une puce NIC USB hautement intégrée et basse consommation, destinée à étendre une interface Ethernet via USB pour ordinateurs de bureau, portables, tablettes, consoles de jeu, etc. Elle intègre un processeur RISCV QingKe, un contrôleur USB2.0/2.1 avec transceiver PHY conforme USB2.1, ainsi quun soussystème Ethernet complet (MAC + PHY) conforme IEEE 802.3, supportant 10/100 Mbps.

Architecture matérielle

  • SoC toutenun : processeur embarqué QingKe RISCV, contrôleur USB, transceiver PHY USB et contrôleur Ethernet MAC+PHY intégrés sur une unique puce (packages QFN24/QFN32).
  • USB 2.0/2.1 Full/HighSpeed : contrôleur et transceiver conformes à la spécification USB2.1, avec LDO intégré et composants périphériques réduits (résistance 50 Ω, condensateurs oscillateur).
  • Ethernet 10/100M : MAC et PHY conformes IEEE 802.3 (10BASET / 100BASETX) ; support de lautonégociation 10/100 Mbps, AutoMDIX et distances jusquà 120 m sur câbles CAT5/CAT6.
  • Mémoire tampon interne : buffers TX/RX intégrés pour stocker les trames avant transfert sur USB, réduisant la charge CPU de lhôte.
  • Fonctions matérielles supplémentaires : LDO interne, support ESD amélioré (6 kV), configuration LED matérielle, wakeup réseau et modes basse consommation.

Interfaces réseau disponibles

  • CDCECM, CDCNCM et RNDIS : support natif de CDCECM et CDCNCM (USB Ethernet classes) et RNDIS — possibilité dutilisation sans pilote propriétaire sur de nombreux hôtes, ou avec pilote vendorspecific si souhaité.
  • Endpoints USB standard : modes vendorspecific (bulk endpoints) et classes réseau standard (interfaces Communications/Data avec altsetting pour endpoints bulk IN/OUT).
  • Fonctionnalités réseau hardwareassist :
    • génération et vérification de checksums IPv4/IPv6 (TCP/UDP/HEAD),
    • support IEEE 802.3x flow control et fallback halfduplex,
    • prise en charge VLAN (802.3Q),
    • wakeonLAN (magic packet / wake packets).

Contraintes et exigences spécifiques

  • Choix de configuration USB : la puce expose plusieurs configurations (vendor, CDCECM, NCM, RNDIS) — le pilote doit détecter la configuration active et sélectionner linterface/altsetting offrant les endpoints bulk nécessaires (ex. altsetting 1 pour CDC Data).
  • Taille et gestion des buffers : présence de buffers internes signifie que le périphérique peut livrer des trames agrégées ou de taille > MTU standard ; prévoir côté pilote des buffers hôtes suffisamment grands (ex. ≥ 16002048 octets) et gérer lalignement skb.
  • Performances et flux : le CH397 prend en charge features hardwareassist (checksum offload, flow control, VLAN), le pilote peut en tirer parti pour réduire la charge CPU et améliorer le débit ; envisager gestion des URB/queues pour atteindre des débits proches du 100 Mbps.
  • Gestion basseconsommation et wakeup : la puce propose modes Sleep et wakeonLAN — le pilote doit exposer et coordonner ces capacités via PM (suspend/resume, autosuspend) et notifications réseau.
  • Robustesse physique et contraintes matérielles : 6 kV ESD, exigences doscillateur externe et simple filtrage passif — le design matériel autour du CH397 est simplifié, mais le firmware peut exposer ou non certaines fonctionnalités (NCM, paramètres LED).
  • Compatibilité multiOS : grâce au support CDCECM/NCM/RNDIS, le CH397 peut fonctionner sans pilote propriétaire sur de nombreux systèmes ; toutefois, un pilote dédié permet dexploiter au mieux les optimisations matérielles et les modes vendorspecific.

En synthèse, le CH397 fournit une solution USB→Ethernet complète et optimisée, offrant à la fois compatibilité plugandplay via classes USB standard et options avancées (offloads, VLAN, wakeup, basse consommation) pour une intégration performante sur hôte via un pilote USBEthernet adapté.

Environnement de dev

compilateur make gcc arborescence du projet dependances etherdevice et kernel

4. Conception

4.1 Architecture logicielle (modules et interfaces)

  • Composants principaux
    • Module USB driver linux : probe, disconnect, suspend, resume.
    • Couche réseau (net_device): instance net_device créée via alloc_etherdev, opérateurs netdev (open, stop, start_xmit, validate_addr, set_mac).
    • Gestion des transferts USB: URB pour RX (dev->rx_urb) et URB temporaires pour TX.
    • Buffering utilisateurs: dev->bulk_in_buffer pour réception, skb pour transmission/réception vers/depuis la pile réseau.
  • Interactions
    • usb core <-> driver : probe/ disconnect, usb_submit_urb / usb_kill_urb.
    • driver <-> network stack : netif_rx, netdev_ops callbacks, register_netdev/unregister_netdev.
    • Synchronisation locale : mutex io_mutex pour protéger opérations I/O critiques (prise/relâche autour dopérations longues).

4.2 API exposée au noyau (structures, callbacks)

  • Structures principales :
    • struct ch397_device : état du périphérique, pointeurs usb/netdev, endpoints, buffer et URB.
    • struct net_device : structure standard exposée au stack réseau, initialisée via alloc_etherdev.
  • Callbacks et points dentrée :
    • usb driver callbacks : ch397_probe, ch397_disconnect, ch397_suspend, ch397_resume.
    • net_device ops : ch397_net_open (ndo_open), ch397_net_stop (ndo_stop), ch397_start_xmit (ndo_start_xmit), eth_validate_addr (ndo_validate_addr), eth_mac_addr (ndo_set_mac_address).
    • URB callbacks : ch397_read_callback (RX), ch397_write_callback (TX).
  • Comportement attendu :
    • Lors de probe : allouer netdev, initialiser ch397_device, trouver endpoints, récupérer MAC, register_netdev.
    • Lors de open : lancer réception (soumettre URB RX), mettre la carrier on et démarrer la queue.
    • Lors de start_xmit : encapsuler skb dans URB bulk-out, soumettre, gérer compteurs et erreurs.
    • Lors de disconnect : arrêter RX, unregister_netdev, libérer ressources.

4.3 Intégration avec etherdevice.h

  • Utilisation :
    • alloc_etherdev(sizeof(struct ch397_device)) pour allocation et initialisation dun net_device avec espace privé.
    • eth_random_addr/mac helpers : eth_random_addr utilisé comme fallback si lecture MAC échoue ; eth_hw_addr_set pour positionner ladresse MAC.
    • eth_validate_addr/eth_mac_addr fournis comme ndo_validate_addr/ndo_set_mac_address, ce qui délègue la validation et le réglage standard dadresse MAC.
  • Conséquences :
    • Le driver sappuie sur les helpers pour respecter les conventions Ethernet sans réimplémenter la validation/gestion MAC.
    • Lalignement des sk_buffs est fait via skb_reserve(skb, 2) pour correspondre aux exigences de la pile Ethernet/IP.

4.4 Rôle de kernel.h et interactions avec le noyau

  • Inclusion de <linux/kernel.h> pour :
    • Fonctions dimpression et de logging et macros comme KERN_INFO (utilisées dans le code).
    • Types et API kernel de base (HZ, GFP_KERNEL/GFP_ATOMIC, etc.).
  • Interactions principales :
    • Allocation mémoire: kmalloc/kfree, netdev/skb allocation.
    • Gestion des URB: usb_alloc_urb/usb_free_urb, usb_submit_urb, usb_kill_urb.
    • Enregistrement/espace didentification: MODULE_DEVICE_TABLE, module_usb_driver.
  • Impact : le driver utilise les primitives noyau pour mémoire, synchronisation (mutex), temporisation (watchdog_timeo), et communication inter-sous-systèmes (network/usb).

4.5 Gestion des buffers et des descriptors

  • Buffers RX :
    • Buffer statique alloué kmalloc(dev->bulk_in_size) (2048 octets) pour réception.
    • RX URB configuré pour pointer sur dev->bulk_in_buffer ; urb->actual_length indique la taille reçue.
    • Après réception, données copiées dans un skb via netdev_alloc_skb + skb_put_data, puis remises au stack réseau.
  • Buffers TX :
    • Pas de buffer de copie : lURB de transmission référence directement skb->data (risque si le stack modifie ou libère le skb) — dans ce code, le skb est passé comme contexte de lURB et libéré dans write_callback.
    • URB allouées par transmission et libérées dans ch397_write_callback.
  • Descriptors / URB lifecycle :
    • RX : un URB long-vie (dev->rx_urb) est alloué lors de ch397_start_rx, soumis, et resoumis par le callback. En stop, usb_kill_urb + usb_free_urb.
    • TX : URB allouées par start_xmit, soumises, et libérées dans le callback de fin.
  • Statistiques et erreurs :
    • netdev->stats.{rx_packets, rx_bytes, tx_packets, tx_bytes, rx_errors, tx_errors, rx_dropped, tx_dropped} mis à jour aux emplacements appropriés.
  • Remarques sur robustesse :
    • Vérifier et gérer le cas où usb_submit_urb échoue (déjà partiellement géré).
    • Potentiel reusage / pool dURB pour haute performance non implémenté ; actuellement allocation à la volée.
    • Attention à lutilisation de skb->data directement : garantir que le skb nest pas modifié tant que lURB est en vol (ici le skb est conservé comme contexte et libéré dans le callback, ce qui est acceptable).

5. Implémentation

  • Le code fournit une base fonctionnelle pour un driver USB Ethernet CDC-like : découverte endpoints, RX continu via URB ré-submis, TX via URB à la demande, intégration basique avec la stack réseau.

5.1 Stratégie dinitialisation et dargs parsing

  • Initialisation principale dans ch397_probe :
    • Vérifier configuration/interface USB et ignorer linterface CDC Comm quand nécessaire.
    • Allouer net_device via alloc_etherdev et récupérer ch397_device avec netdev_priv.
    • Initialiser mutex, obtenir référence usb_get_dev, définir altsetting si nécessaire (usb_set_interface pour CDC Data).
    • Parcourir endpoints de laltsetting courant pour découvrir bulk-in et bulk-out ; allouer bulk_in_buffer (kmalloc).
    • Récupérer ladresse MAC via ch397_get_mac_address (usb_string) et lappliquer via eth_hw_addr_set.
    • Initialiser netdev->netdev_ops, watchdog_timeo, et appeler register_netdev.
    • En cas derreur, faire cleanup (usb_put_dev, kfree buffer, free_netdev).
  • Pas dargs parsing via module_param dans ce code — stratégie : valeurs par défaut et auto-détection depuis lUSB device string/config.

5.2 Routine dattach/detach

  • Attach (probe) : allouer structures, configurer endpoints, set MAC, register_netdev, netif_carrier_off (attente de lopen).
  • Detach (disconnect) :
    • Récupérer dev via usb_get_intfdata, retirer association usb_set_intfdata(NULL).
    • unregister_netdev (qui arrêtera la queue si nécessaire).
    • Arrêter RX via ch397_stop_rx (usb_kill_urb + usb_free_urb).
    • Libérer bulk_in_buffer, usb_put_dev, free_netdev.
    • Logging de déconnexion.
  • Robustesse :
    • Garantir que disconnect peut être appelé même si probe a échoué partiellement (vérifier NULLs avant free).
    • Utiliser usb_kill_urb pour attendre la fin des callbacks avant de free les ressources partagées.

5.3 Transmissions (TX) : file dattente et gestion

  • Flux denvoi :
    • ch397_start_xmit est appelé avec un skb.
    • Allouer une URB (usb_alloc_urb) ; si échec, libérer skb et incrémenter tx_dropped.
    • Préparer URB avec usb_fill_bulk_urb en pointant sur skb->data et en passant skb comme contexte.
    • Soumettre URB (usb_submit_urb). En cas déchec : libérer urb et skb, incrémenter tx_errors.
    • Si succès : skb conservé jusquau ch397_write_callback qui libère le skb et lURB.
  • Gestion de la queue :
    • Implémentation actuelle ne stoppe pas la queue quand trop dURB en vol (commentaire présent). Pour production : ajouter compteur dURB en vol et netif_stop_queue/netif_wake_queue.
  • Sécurité mémoire :
    • Le skb est référencé via urb->context et libéré dans le callback ; sassurer que rien ne libère ou modifie skb avant callback.
  • Erreurs et métriques :
    • Incrémenter netdev->stats.tx_errors sur échec de submit, tx_packets/tx_bytes sur succès (dans callback).

5.4 Réception (RX) : traitement des paquets

  • Setup :
    • ch397_start_rx alloue dev->rx_urb, le configure via usb_fill_bulk_urb sur bulk_in_buffer et soumet.
  • Traitement dans ch397_read_callback :
    • Vérifier urb->status ; si success et actual_length > 0 :
      • hexdump pour debug.
      • Allouer skb via netdev_alloc_skb, réserver 2 octets pour alignement, copier données avec skb_put_data.
      • Déterminer protocole via eth_type_trans et injecter via netif_rx.
      • Mettre à jour stats rx_packets/rx_bytes.
    • Sur erreurs terminales (-ENOENT, -ECONNRESET, -ESHUTDOWN) : retourner (pas de resubmit).
    • Sur autres erreurs : incrémenter rx_errors.
    • Resoumettre lURB via usb_submit_urb(urb, GFP_ATOMIC) pour continuer la réception.
  • Robustesse :
    • Gestion dallocation skb échouée : incrémenter rx_dropped.
    • Toujours resoumettre URB tant que linterface reste active ; gérer échecs de resubmit (logger, incrémenter erreur).
    • Sassurer que le buffer dev->bulk_in_buffer reste alloué pendant la durée de vie de lURB (libéré seulement à disconnect).

5.5 Gestion des erreurs et reprise

  • Erreurs USB :
    • Dans read/write callbacks, vérifier urb->status et traiter codes connus.
    • Echec de usb_submit_urb lors dinitialisation : nettoyage et retour derreur dans probe/start_rx.
  • Reprise :
    • Probe refuse config non supportées (config 3, interface 0 en config 2) évitant états incohérents.
    • On peut améliorer la reprise en ajoutant tentatives limitées de resubmit et backoff si submit échoue.
  • Nettoyage : toujours free les URB (usb_free_urb) et buffers si submit échoue.
  • Consistance :
    • Utiliser usb_kill_urb dans disconnect pour garantir callbacks terminés avant free.
    • mutex io_mutex disponible pour séquencer opérations critiques sur lUSB (bien que son usage soit minimal actuellement).

5.6 Synchronisation et verrouillage

  • Mutex :
    • mutex_init(&dev->io_mutex) lors du probe.
    • mutex utilisé dans suspend pour verrouiller les opérations I/O (exemple minimal présent). Recommandation : entourer submit/kill URB et manipulations dev->rx_urb/dev->bulk_in_buffer par la mutex si nécessaire.
  • Contexte dexécution :
    • Callbacks URB sexécutent en contexte interruption ou softirq ; utiliser GFP_ATOMIC pour allocations faites dans callbacks si nécessaire.
    • Les fonctions net_device ops (ndo_start_xmit, ndo_open/stop) sexécutent en context process ; utiliser GFP_KERNEL pour allocations là.
  • Protection des ressources :
    • Accès concurrent à rx_urb, bulk_in_buffer et autres champs doivent être protégés lors de modification (start/stop Rx, disconnect).
    • Lors du disconnect, utiliser usb_set_intfdata(interface, NULL) avant de libérer afin déviter race avec callbacks.

5.7 Extraits de code clés (fonctions importantes)

  • ch397_probe : allocation netdev, découverte endpoints, set_interface altsetting, récupération MAC, register_netdev, gestion derreurs.
  • ch397_start_rx / ch397_stop_rx : allocation/soumission et arrêt/libération de RX URB.
  • ch397_read_callback : traitement packet -> skb -> netif_rx, resubmit URB.
  • ch397_start_xmit / ch397_write_callback : envoi via URB, statistiques, libération skb/urb.
  • ch397_disconnect : cleanup complet — unregister_netdev, usb_kill_urb, free buffers/structures.
Description
No description provided
Readme 355 KiB
Languages
C 89.4%
Makefile 10.6%