Øvelse+5+-+GPIO+Linux+Device+Driver

=Lav en driver som kan sætte værdien af en gpio (hvis den er output) og læse værdien fra en gpio (hvis den er et input).= Grundlaget for at lave denne øvelse at er:
 * hente zip filen indeholde --> mygpio.c og den tilhørende makefi

mygpio.c, som er en driver, er der en række funktioner hvor koden mangler at blive implementeret. Dette er vores opgave at få gjort.

Implementering af init og exit funktionerne
Der opgives en struct indeholdende gpio fra 130 - 137. Fra 130 til 133 er input og 134 til 137 er outputs. code format="c" struct gpioPort{ unsigned int num; enum direnu { in, out } dir; const char label[10]; // Very important to specify a size. Just [] causes havoc to gpio indexing } gpio[] = { {130, in, "gpio0_0"}, {131, in, "gpio0_1"}, {132, in, "gpio0_2"}, {133, in, "gpio0_3"}, {134, out, "gpio0_4"}, {135, out, "gpio0_5"}, {136, out, "gpio0_6"}, {137, out, "gpio0_7"}, {139, out, "gpio0_8"} }; code Vi har tilføjet en extra gpio, for at kunne tænde og slukke en lysdiode som vi kalder gpio_8 liggende på pin 139. code format="c" if ( (err = gpio_request(gpio[i].num, gpio[i].label)) < 0) return err; code Her tjekkes om et resource nummer + label er fri, før vi vil bruge dem. Hvis dette ikke er tilfældet bliver der returneret en fejlmedelse som "err sørger for code format="c"   if ( gpio[i].dir == in)        gpio_direction_input(gpio[i].num);    else        gpio_direction_output(gpio[i].num, 0);    } code Vi benytter en forløkke til at gennemløbe en struct med 9 gpio som er input og output(vi har tilføjet et ekstra output label: gpio_8) Her sættes GPIO direction. Sættes til enten input eller output.

I exit-funktionen skal vi vi ikke gøre andet end at sætte alle GPIO til input. code format="c" if ( gpio[i].dir == out ) gpio_direction_input(gpio[i].num); gpio_free(gpio[i].num); code Hvis en gpio er output, bliver det sat til input her Dernæst frigøres GPIO resourcer

Implementering af open og release funktionerne
Dette kodeudsnit optræder i både open og release funktionen. code format="c" major = MAJOR(inode->i_rdev); minor = MINOR(inode->i_rdev); if ( major != MYGPIO_MAJOR ) return -ENODEV; if ( minor < MYGPIO_MINOR || minor > gpio_len ) return -ENODEV; code Der lagres i variablerne major og minor og tjekkes på disse to variabler. MYGPIO_MAJOR er defineret til 62 i starten at koden, hvilket svare til vores character device. MGPIO_MINOR er defineret til 0. Hvis -ENODEV returneres, betyder dette at der returneres en fejlkode som ligger i biblioteket "enodev.h". Denne fejlkode kender linux kender, og dette udskrives i terminal.

Implementering af write funktionen
I write funktionen bliver der igen tjekket på om minor holder sig inden for intervallet fra første til sidste gpio. Hvis dette ikke er tilfældet returneres -ENODEV. code format="c" len = count < MAXLEN ? count : MAXLEN; // set len < MAXLEN

/**** Use copy_from_user to get data ****/ copy_from_user(kbuf, ubuf,len);

kbuf[len] = '\0';  // Pad null termination to string code I ovenstående kode skal der kopieres data fra user space til kernel space. Til dette bruger vi funktione copy_to_user som modtager 3 argumenter. Første validers på count, og lægges ind i variablen len, som sener benyttes. Her ses funktionen som den er: unsinged long copy_from_user(void *to, const void __user *from, unsigned long count) Første argument er en void pointer til det objekt der skal kopiers til, der næst en const pointer som peger der hvor der skal kopires fra, og tilsidst en længde på det der skal kopires.

code format="c" gpio_set_value(gpio[minor].num,value); code Her srkives/sættes der en værdi til en bestemet minor.

=Implementering af read= code format="c" /*    * Read GPIO port (if an input port) */   if (gpio[minor].dir == in) result = gpio_get_value(gpio[minor].num);
 * Read aflæser en værdi.

/*    * Copy string result to User Space */   copy_to_user(buf, readBuf, len);
 * værdien konverteres til en streng og skrives via copy_to_user til en ekstern buffer.

code

Test vores program på Devkit 8000
Vi starter med at indsætte kernemodulet af driver ved hjælp af følgende kode code format="c" insmod mygpio.ko code Vi starter med at lave en node således code format="c" mknod /dev/gpio4 c 62 4 code Her laves en node med navnet gpio4, c fortæller at vi laver en character driver. Character driver har major nummert 62, og bliver bundet til minor 4, som svare til 134 hvilket er et output. code format="c" cat /dev/gpio4 code Denne kode linje viser hvad gpio4 er, hvilket gerne skulle være 0, da det er output som standard. code format="c" echo 1 > /dev/gpio4 code Med echo kan skrives en værdi til gpio4. Det kunne enten være 0 eller 1, alt efter hvad man vil sætte gpio4 til input eller output.