Grunnleggende karakterdriver i Linux

Grunnleggende karakterdriver i Linux
Vi vil gå gjennom Linux -måten å implementere karakterdriveren. Vi vil først prøve å forstå hva karakterdriveren er og hvordan Linux -rammeverket gjør oss i stand til å legge til karakterdriveren. Etter det vil vi gjøre applikasjonen for eksemplet test for brukeren. Denne testapplikasjonen bruker enhetsnoden utsatt av driveren for å skrive og lese dataene fra kjerneminnet.

Beskrivelse

La oss starte diskusjonen med karakterføreren i Linux. Kernel kategoriserer driverne i tre kategorier:

Karakterdrivere - Dette er driverne som ikke har for mye data å håndtere. Få eksempler på karakterførere er driver med berøringsskjerm, UART -driver osv. Disse alle er karakterdriverne siden dataoverføringen gjøres gjennom karakter etter karakter.

Blokkerer drivere - Dette er driverne som omhandler for mye data. Dataoverføring gjøres blokkering av blokkering siden for mye av dataene må overføres. Eksempel på blokkeringsførere er SATA, NVME, etc.

Nettverksdrivere - Dette er driverne som fungerer i nettverksgruppen til drivere. Her gjøres dataoverføring i form av datapakker. Trådløse drivere som ateros kommer under denne kategorien.

I denne diskusjonen vil vi bare fokusere på karakterdriver.

Som et eksempel vil vi ta den enkle lese-/skriveoperasjonene for å forstå den grunnleggende karakterdriveren. Generelt har enhver enhetsdriver disse to minimumsoperasjonene. Ytterligere drift kan være åpen, nær, ioctl osv. I vårt eksempel har sjåføren vår minnet i kjerneområdet. Dette minnet tildeles av enhetsdriveren og kan betraktes som enhetsminnet siden det ikke er noen maskinvarekomponent involvert. Driveren oppretter enhetsgrensesnittet i /dev -katalogen som kan brukes av brukerromsprogrammene for å få tilgang til driveren og utføre operasjonene som støttes av driveren. For brukerpace -programmet er disse operasjonene akkurat som alle andre filoperasjoner. Brukerplassprogrammet må åpne enhetsfilen for å få forekomsten av enheten. Hvis brukeren ønsker å utføre leseoperasjonen, kan lesesystemanropet brukes til å gjøre det. Tilsvarende, hvis brukeren ønsker å utføre skriveoperasjonen, kan skrivesystemanropet brukes til å oppnå skriveoperasjonen.

Karakterdriver

La oss vurdere å implementere karakterdriveren med Read/Writ Data Operations.

Vi starter med å ta forekomsten av enhetsdataene. I vårt tilfelle er det “struct cdrv_device_data”.

Hvis vi ser feltene i denne strukturen, har vi CDEV, enhetsbuffer, størrelse på buffer, klasseforekomst og enhetsobjekt. Dette er minimumsfeltene der vi skal implementere karakterdriveren. Det avhenger av implementeren av hvilke tilleggsfelt vil han legge til for å forbedre driverens funksjon. Her prøver vi å oppnå minimumsfunksjonen.

Deretter bør vi lage objektet med enhetsdatastrukturen. Vi bruker instruksjonen for å tildele minnet på statisk måte.

struct cdrv_device_data char_device [cdrv_max_minors];

Dette minnet kan også tildeles dynamisk med “Kmalloc”. La oss holde implementeringen så enkel som mulig.

Vi bør ta implementeringen av lese- og skrivefunksjonene. Prototypen til disse to funksjonene er definert av enhetsdriverens rammeverk av Linux. Implementeringen av disse funksjonene må være brukerdefinert. I vårt tilfelle vurderte vi følgende:

Les: Operasjonen for å få dataene fra driverminnet til brukerområdet.

statisk ssize_t cdrv_read (struct file *fil, char __user *user_buffer, størrelse_t størrelse, LOFF_T *offset);

Skriv: Operasjonen for å lagre dataene til driverminnet fra brukerområdet.

statisk ssize_t cdrv_write (struct file *fil, const char __user *user_buffer, størrelse_t størrelse, LOFF_T *offset);

Begge operasjonene, lese og skrive, må registreres som en del av struct File_Operations CDRV_FOPS. Disse er registrert på Linux Device Driver Framework i INIT_CDRV () til driveren. Inne i init_cdrv () -funksjonen utføres alle oppsettoppgaver. Få oppgaver er som følger:

  • Lage klasse
  • Opprett enhetsforekomst
  • Tilordne større og mindre nummer for enhetsnoden

Den komplette eksempelkoden for den grunnleggende karakterenheten Driver er som følger:

#inkludere
#inkludere
#inkludere
#inkludere
#inkludere
#inkludere
#inkludere
#Define CDRV_MAJOR 42
#Define CDRV_MAX_Minors 1
#Define BUF_LEN 256
#Define CDRV_DEVICE_NAME "CDRV_DEV"
#Define CDRV_CLASS_NAME "CDRV_CLASS"
struct cdrv_device_data
struct cdev cdev;
char buffer [buf_len];
størrelse_t størrelse;
struct Class* CDRV_CLASS;
Struct Device* CDRV_DEV;
;
struct cdrv_device_data char_device [cdrv_max_minors];
statisk ssize_t cdrv_write (struct file *fil, const char __user *user_buffer,
størrelse_t størrelse, loff_t * offset)

struct cdrv_device_data *cdrv_data = & char_device [0];
ssize_t len ​​= min (cdrv_data-> størrelse - *offset, størrelse);
printk ("skriving: byte =%d \ n", størrelse);
if (len buffer + *offset, user_buffer, len))
return -efault;
*Offset += Len;
return len;

statisk ssize_t cdrv_read (struct file *fil, char __user *user_buffer,
størrelse_t størrelse, loff_t *offset)

struct cdrv_device_data *cdrv_data = & char_device [0];
ssize_t len ​​= min (cdrv_data-> størrelse - *offset, størrelse);
if (len buffer + *offset, len))
return -efault;
*Offset += Len;
printk ("Les: byte =%d \ n", størrelse);
return len;

statisk int cdrv_open (struct inode *inode, struct file *file)
printk (kern_info "CDRV: enhet åpen \ n");
retur 0;

statisk int cdrv_release (struct inode *inode, struct file *file)
printk (kern_info "CDRV: enhet stengt \ n");
retur 0;

const struct file_operations cdrv_fops =
.Eier = denne_modulen,
.ÅPEN = CDRV_OPEN,
.LES = CDRV_READ,
.Skriv = CDRV_WRITE,
.Utgivelse = CDRV_Release,
;
int init_cdrv (tomrom)

int count, ret_val;
printk ("init the Basic Character Driver ... start \ n");
ret_val = register_chrdev_region (mkdev (cdrv_major, 0), cdrv_max_minors,
"CDRV_Device_driver");
if (ret_val != 0)
printk ("register_chrdev_region (): mislyktes med feilkode:%d \ n", ret_val);
return ret_val;

for (count = 0; count < CDRV_MAX_MINORS; count++)
CDEV_INIT (& Char_Device [Count].CDEV, & CDRV_FOPS);
CDEV_ADD (& Char_Device [Count].CDEV, MKDEV (CDRV_MAJOR, COUNT), 1);
char_device [count].cdrv_class = class_create (this_module, cdrv_class_name);
if (is_err (char_device [count].cdrv_class))
Printk (Kern_Allert "CDRV: Register Device Class Failed \ n");
Returner PTR_ERR (Char_Device [Count].cdrv_class);

char_device [count].størrelse = buf_len;
printk (Kern_info "CDRV Device Class Registrert vellykket \ n");
char_device [count].CDRV_DEV = DEVICE_CREATE (Char_Device [Count].CDRV_CLASS, NULL, MKDEV (CDRV_MAJOR, COUNT), NULL, CDRV_DEVICE_NAME);

retur 0;

void cleanup_cdrv (void)

int count;
for (count = 0; count < CDRV_MAX_MINORS; count++)
enhet_destroy (char_device [count].CDRV_CLASS, & CHAR_DEVICE [Count].CDRV_DEV);
class_destroy (char_device [count].cdrv_class);
CDEV_DEL (& Char_Device [Count].cdev);

UNREGISTER_CHRDEV_REGION (MKDEV (CDRV_MAJOR, 0), CDRV_MAX_MINORS);
printk ("Utgang av den grunnleggende karakterdriveren ... \ n");

module_init (init_cdrv);
module_exit (cleanup_cdrv);
Module_license ("gpl");
Module_author ("Sushil Rathore");
Module_description ("Eksempel på karakterdriver");
Module_version ("1.0 ");

Vi lager et eksempel på makefile for å kompilere den grunnleggende karakterdriveren og testappen. Driverkoden vår er til stede i CRDV.C og testappkoden er til stede i CDRV_APP.c.

OBJ-M+= CDRV.o
alle:
lage -c/lib/modules/$ (shell uname -r)/build/m = $ (pwd) moduler
$ (CC) CDRV_APP.C -O CDRV_APP
ren:
lage -c/lib/modules/$ (shell uname -r)/build/m = $ (pwd) ren
RM CDRV_APP
~

Etter at utstedelsen er gjort til makefilen, bør vi få følgende logger. Vi får også CDRV.KO og kjørbar (CDRV_APP) for testappen vår:

root@haxv-srathore-2:/home/cienauser/kjerne_artikler# lage
lage -c/lib/modules/4.15.0-197-generisk/build/m =/home/cienauser/kjerne_artikler moduler
lage [1]: legge inn katalog '/usr/src/linux-headers-4.15.0-197-generisk '
CC [M]/Home/Cienauser/Kernel_Articles/CDRV.o
Bygningsmoduler, trinn 2.
Modpost 1 -moduler
CC/Home/Cienauser/Kernel_Articles/CDRV.mod.o
LD [M]/Home/Cienauser/Kernel_Articles/CDRV.ko
Make [1]: Leaving Directory '/usr/src/Linux-headers-4.15.0-197-generisk '
CC CDRV_APP.C -O CDRV_APP

Her er prøvekoden for testappen. Denne koden implementerer testappen som åpner enhetsfilen som er opprettet av CDRV -driveren og skriver “testdata” for den. Deretter leser den dataene fra driveren og skriver dem ut etter å ha lest dataene som skal skrives ut som "Testdata".

#inkludere
#inkludere
#define enhet_file "/dev/cdrv_dev"
char *data = "testdata";
char read_buff [256];
int main ()

int fd;
int rc;
fd = åpen (enhet_file, o_wronly, 0644);
if (fd<0)

Perror ("Åpningsfil: \ n");
return -1;

RC = skriv (FD, data, strlen (data) +1);
if (rc<0)

Perror ("skrivefil: \ n");
return -1;

printf ("skrevet byte =%d, data =%s \ n", rc, data);
Lukk (FD);
fd = åpen (enhet_file, o_rdonly);
if (fd<0)

Perror ("Åpningsfil: \ n");
return -1;

RC = Read (FD, Read_Buff, Strlen (data) +1);
if (rc<0)

Perror ("Lesefil: \ n");
return -1;

printf ("Les byte =%d, data =%s \ n", rc, read_buff);
Lukk (FD);
retur 0;

Når vi har alle tingene på plass, kan vi bruke følgende kommando for å sette inn den grunnleggende karakterdriveren til Linux -kjernen:

root@haxv-srathore-2:/home/cienauser/kernel_articles# insmod cdrv.ko
root@haxv-srathore-2:/home/cienauser/kjerne_artikler#

Etter å ha satt inn modulen, får vi følgende meldinger med DMESG og få enhetsfilen opprettet i /dev as /dev /cdrv_dev:

root@haxv-srathore-2:/home/cienauser/kjerne_artikler# dmesg
[160.015595] CDRV: Lasting av ut-av-tre-modul Taints-kjerne.
[160.015688] CDRV: Modulverifisering mislyktes: signatur og/eller påkrevd nøkkel mangler - Tainting -kjernen
[160.016173] init the Basic Character Driver ... Start
[160.016225] CDRV -enhetsklasse registrert vellykket
root@haxv-srathore-2:/home/cienauser/kjerne_artikler#

Utfør nå testappen med følgende kommando i Linux -skallet. Den endelige meldingen skriver ut lesedataene fra driveren som er nøyaktig det samme som det vi skrev i skriveoperasjonen:

root@haxv-srathore-2:/home/cienauser/kjerne_artikler# ./cdrv_app
Skrevet byte = 10, data = testdata
Les byte = 10, data = testdata
root@haxv-srathore-2:/home/cienauser/kjerne_artikler#

Vi har få ekstra utskrifter i skrive- og lesestien som kan sees ved hjelp av DMESG -kommandoen. Når vi utsteder DMESG -kommandoen, får vi følgende utdata:

root@haxv-srathore-2:/home/cienauser/kjerne_artikler# dmesg
[160.015595] CDRV: Lasting av ut-av-tre-modul Taints-kjerne.
[160.015688] CDRV: Modulverifisering mislyktes: signatur og/eller påkrevd nøkkel mangler - Tainting -kjernen
[160.016173] init the Basic Character Driver ... Start
[160.016225] CDRV -enhetsklasse registrert vellykket
[228.533614] CDRV: enhet åpen
[228.533620] Skriving: byte = 10
[228.533771] CDRV: Stengt enhet
[228.533776] CDRV: enhet åpen
[228.533779] Les: byte = 10
[228.533792] CDRV: Stengt enhet
root@haxv-srathore-2:/home/cienauser/kjerne_artikler#

Konklusjon

Vi har gått gjennom den grunnleggende karakterdriveren som implementerer de grunnleggende skrive- og leseoperasjonene. Vi diskuterte også eksemplet Makefile for å kompilere modulen sammen med testappen. Testappen ble skrevet og diskutert for å utføre skrive- og leseoperasjonene fra brukerområdet. Vi demonstrerte også samlingen og utførelsen av modulen og testappen med logger. Test -appen skriver få byte av testdata og leser den tilbake. Brukeren kan sammenligne både dataene for å bekrefte riktig funksjon av driver- og testappen.