Você está na página 1de 201

EmbeddedLinuxdriverdevelopment

EmbeddedLinux kernelanddriver development


SebastienJan MichaelOpdenacker ThomasPetazzoni FreeElectrons
Copyright20042011,FreeElectrons. CreativeCommonsBYSA3.0license Latestupdate:Mar2,2011, Documentsources,updatesandtranslations: http://freeelectrons.com/docs/kernel Corrections,suggestions,contributionsandtranslationsarewelcome!

FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Contents
Driverdevelopment
Loadablekernelmodules Memorymanagement I/Omemoryandports Characterdrivers Processesandscheduling Sleeping,Interruptmanagement Handlingconcurrency Debugging mmap Deviceanddrivermodel

2
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

EmbeddedLinuxdriverdevelopment

Driverdevelopment
Loadablekernelmodules

3
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

hellomodule
/*hello.c*/ #include<linux/init.h> #include<linux/module.h> #include<linux/kernel.h> staticint__inithello_init(void) { printk(KERN_ALERT"Goodmorrow"); printk(KERN_ALERT"tothisfairassembly.\n"); return0; } staticvoid__exithello_exit(void) { printk(KERN_ALERT"Alas,poorworld,whattreasure"); printk(KERN_ALERT"hastthoulost!\n"); } module_init(hello_init); module_exit(hello_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Greetingmodule"); MODULE_AUTHOR("WilliamShakespeare");

__init: removedafterinitialization (statickernelormodule). __exit:discardedwhen modulecompiledstatically intothekernel.

Exampleavailableonhttp://freeelectrons.com/doc/c/hello.c

FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Hellomoduleexplanations
HeadersspecifictotheLinuxkernel:<linux/xxx.h>
NoaccesstotheusualClibrary,we'redoingkernelprogramming

Aninitializationfunction
Calledwhenthemoduleisloaded,returnsanerrorcode(0on success,negativevalueonfailure) Declaredbythemodule_init()macro:thenameofthefunction doesn'tmatter,eventhoughmodulename_init()isaconvention.

Acleanupfunction
Calledwhenthemoduleisunloaded Declaredbythemodule_exit()macro.

MetadatainformationsdeclaredusingMODULE_LICENSE(), MODULE_DESCRIPTION()andMODULE_AUTHOR()
5
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Symbolsexportedtomodules
Fromakernelmodule, onlyalimitednumberofkernelfunctionscanbecalled Functionsandvariableshavetobeexplicitlyexported bythekerneltobevisiblefromakernelmodule Twomacrosareusedinthekernel toexportfunctionsandvariables: EXPORT_SYMBOL(symbolname),whichexportsa functionorvariabletoallmodules EXPORT_SYMBOL_GPL(symbolname),whichexportsa functionorvariableonlytoGPLmodules Anormaldrivershouldnotneedanynonexportedfunction.

6
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Symbolsexportedtomodules(2)
kernel
voidfunc1(){} voidfunc2(){} EXPORT_SYMBOL(func2); voidfunc3(){} EXPORT_SYMBOL_GPL(func3);

GPLmoduleA
voidfunc4(){} EXPORT_SYMBOL_GPL(func4);

func1(); func2(); func3(); func4();

NOK OK OK OK

nonGPLmoduleB
func1(); func2(); func3(); func4(); NOK OK NOK NOK

func1(); func2(); func3(); func4();

OK OK OK NOK

GPLmoduleC
func1(); func2(); func3(); func4(); NOK OK OK OK
7

FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Modulelicense
Severalusages
Usedtorestrictthekernelfunctionsthatthemodulecanuseifit isn'taGPLlicensedmodule
DifferencebetweenEXPORT_SYMBOL()and EXPORT_SYMBOL_GPL()

Usedbykerneldeveloperstoidentifyissuescomingfrom proprietarydrivers,whichtheycan'tdoanythingabout (Taintedkernelnoticeinkernelcrashesandoopses). Usefulforuserstocheckthattheirsystemis100%free (check/proc/sys/kernel/tainted)

Values
GPL,GPLv2,GPLandadditionalrights,DualMIT/GPL,Dual BSD/GPL,DualMPL/GPL,Proprietary
8
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Compilingamodule
Twosolutions
Outoftree
Whenthecodeisoutsideofthekernelsourcetree,inadifferent directory Advantage:Mightbeeasiertohandlethanmodificationstothekernel itself Drawbacks:Notintegratedtothekernelconfiguration/compilation process,needstobebuiltseparately,thedrivercannotbebuilt statically

Insidethekerneltree
Wellintegratedintothekernelconfiguration/compilationprocess Drivercanbebuiltstaticallyifneeded

9
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Compilingaoutoftreemodule
ThebelowMakefileshouldbereusableforanysinglefile outoftreeLinux2.6module Thesourcefileishello.c Justrunmaketobuildthehello.kofile Caution:makesurethereisa[Tab]characteratthe beginningofthe$(MAKE)line(makesyntax) Either
ifneq($(KERNELRELEASE),) objm:=hello.o else KDIR:=/path/to/kernel/sources all: $(MAKE)C$(KDIR)M=`pwd`modules endif

[Tab]! (nospaces)

fullkernel sourcedirectory (configuredand compiled) orjustkernel headersdirectory (minimum needed)

10
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Compilinganoutoftreemodule(2)
Step1:themoduleMakefileisinterpretedwithKERNELRELEASEundefined, soitcallsthekernelMakefile,passingthemoduledirectoryintheMvariable

Modulesource
/path/to/module_source

Kernelsource
/path/to/kernel_source

hello.c hello.ko Makefile ...

drivers kernel include Makefile ...

Step2:thekernelMakefileknowshowtocompileamodule,andthankstothe Mvariable,knowswheretheMakefileforourmoduleis.ThemoduleMakefile isinterpretedwithKERNELRELEASEdefined,sothekernelseestheobjm definition.

11

FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Modulesandkernelversion
Tobecompiled,akernelmoduleneedsaccesstothekernel headers,containingthefunctions,typesandconstantsdefinitions Twosolutions
Fullkernelsources Onlykernelheaders(linuxheaders*packagesin Debian/Ubuntudistributions)

Thesourcesorheadersmustbeconfigured
Manymacrosorfunctionsdependontheconfiguration

AkernelmodulecompiledagainstversionXofkernelheaders willnotloadinkernelversionY
modprobe/insmodwillsayInvalidmoduleformat
12
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Newdriverinkernelsources(1)
Toaddanewdrivertothekernelsources: Addyournewsourcefiletotheappropriatesourcedirectory. Example:drivers/usb/serial/navman.c

Singlefiledriversinthecommoncase,evenifthefileisseveral thousandlinesofcode.Onlyreallybigdriversaresplitinseveral filesorhavetheirowndirectory.


Describetheconfigurationinterfaceforyournewdriver byaddingthefollowinglinestotheKconfigfileinthisdirectory:
configUSB_SERIAL_NAVMAN tristate"USBNavmanGPSdevice" dependsonUSB_SERIAL help Tocompilethisdriverasamodule,chooseMhere:the modulewillbecallednavman.
13
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Newdriverinkernelsources(2)
AddalineintheMakefilefilebasedontheKconfigsetting: obj$(CONFIG_USB_SERIAL_NAVMAN)+=navman.o Ittellsthekernelbuildsystemtobuildnavman.cwhenthe USB_SERIAL_NAVMANoptionisenabled.Itworksbothifcompiled staticallyorasamodule. Runmakexconfigandseeyournewoptions! Runmakeandyournewfilesarecompiled! SeeDocumentation/kbuild/fordetailsandmoreelaborate exampleslikedriverswithseveralsourcefiles,ordriversintheir ownsubdirectory,etc.

14
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

HowtocreateLinuxpatches
Theoldschoolway Beforemakingyourchanges,makesureyouhavetwokerneltrees cpalinux2.6.37/linux2.6.37patch/ Makeyourchangesinlinux2.6.37patch/ Runmakedistcleantokeeponlysourcefiles. Createapatchfile: diffNurlinux2.6.37/\ linux2.6.37patch/>patchfile Notpractical,doesnotscaletomultiplepatches Thenewschoolways Usequilt(tooltomanageastackofpatches) Usegit(revisioncontrolsystemusedbytheLinuxkerneldevelopers)
ThankstoNicolasRougier(Copyright2003, http://webloria.loria.fr/~rougier/)fortheTuximage 15

FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

hellomodulewithparameters
/*hello_param.c*/ #include<linux/init.h> #include<linux/module.h> #include<linux/moduleparam.h> MODULE_LICENSE("GPL"); /*Acoupleofparametersthatcanbepassedin:howmanytimeswesay hello,andtowhom*/ staticchar*whom="world"; module_param(whom,charp,0); staticinthowmany=1; module_param(howmany,int,0); staticint__inithello_init(void) { inti; for(i=0;i<howmany;i++) printk(KERN_ALERT"(%d)Hello,%s\n",i,whom); return0; } staticvoid__exithello_exit(void) { printk(KERN_ALERT"Goodbye,cruel%s\n",whom); } module_init(hello_init); module_exit(hello_exit);

Thanksto JonathanCorbet fortheexample!

Exampleavailableonhttp://freeelectrons.com/doc/c/hello_param.c

16

FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Declaringamoduleparameter
#include<linux/moduleparam.h> module_param( name, /*nameofanalreadydefinedvariable*/ type, /*eitherbyte,short,ushort,int,uint,long, ulong,charp,orbool. (checkedatcompiletime!)*/ perm /*for/sys/module/<module_name>/parameters/<param> 0:nosuchmoduleparametervaluefile*/ ); Example intirq=5; module_param(irq,int,S_IRUGO);

Modulesparameterarraysarealsopossiblewith module_param_array(),buttheyarelesscommon.
17
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

PracticallabWritingmodules
Writeakernelmodulewithseveral capabilities,includingmodule parameters. Accesskernelinternalsfromyour module. Setuptheenvironmenttocompileit

18
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

EmbeddedLinuxdriverdevelopment

Driverdevelopment
Memorymanagement

19
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Physicalandvirtualmemory
Physicaladdressspace
0xFFFFFFFF
0xFFFFFFFFF

Virtualaddressspaces
0xFFFFFFFF 0xC0000000

Kernel

I/Omemory3 I/Omemory2 I/Omemory1


Memory Management Unit

Process1

0x00000000

0x00000000

Flash

MMU

CPU
0xFFFFFFFF

RAM1 RAM0 Alltheprocesseshavetheir ownvirtualaddressspace,and runasiftheyhadaccesstothe wholeaddressspace.

Kernel

0xC0000000

Process2

0x00000000

0x00000000

20
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Virtualmemoryorganization:1GB/3GB
0xFFFFFFFF

1GBreservedforkernelspace Kernel Containskernelcodeandcoredatastructures, identicalinalladdressspaces Mostmemorycanbeadirectmappingofphysical memoryatafixedoffset Complete3GBexclusivemappingavailableforeach userspaceprocess Processcodeanddata(program,stack,) Processn Memorymappedfiles Notnecessarilymappedtophysicalmemory (demandfaultpagingusedfordynamicmappingto physicalmemorypages) Differsfromoneaddressspacetotheother

0xC0000000

0x00000000

21
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Physical/virtualmemorymapping
Physicaladdressspace
0xFFFFFFFF

Virtualaddressspace
0xFFFFFFFF

I/Omemory

Kernel
0xC0000000

ZONE_HIGHMEM

RAM

RAM
ZONE_NORMAL

Processn

ZONE_DMA

0x00000000

0x00000000 22

FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Accessingmorephysicalmemory
Onlylessthan1GBmemoryaddressabledirectlythroughkernel virtualaddressspace Ifmorephysicalmemoryispresentontheplatform:
Partofthememorywillnotbeaccessablebykernelspace,butcan beusedbyuserspace Toallowkerneltoaccesstomorephysicalmemory:
Change1GB/3GBmemorysplit(2GB/2GB)?=>butreducestotal memoryavailableforeachprocess Changefora64bitsarchitecture;) Activatethe'highmem'supportifavailableforyourarchitecture: Allowskerneltomappartsofitsnondirectlyaccessablememory Mappingmustberequestedexplicitly Limitedaddressesrangesreservedforthisusage
23
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Accessingevenmorephysicalmemory!
Ifyour32bitsplatformhostsmorethan4GB,theyjust cannotbemapped ThePAE(PhysicalAddressExpansion)maybesupported byyourarchitecture Addssomeaddressextensionbitsusedtoindexmemory areas Allowsaccessingupto64GBofphysicalmemoryby4GB pages Notethateachuserspaceprocessisstilllimitedtoa3GB memoryspace

24
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Notesonuserspacememory
Newuserspacememoryisallocatedeitherfromthealready allocatedprocessmemory,orusingthemmapsystemcall Notethatmemoryallocatedmaynotbephysicallyallocated:
Kernelusesdemandfaultpagingtoallocatethephysicalpage(the physicalpageisallocatedwhenaccesstothevirtualaddress generatesapagefault) ...ormayhavebeenswappedout,whichalsoinducesapagefault

Userspacememoryallocationisallowedtoovercommitmemory (morethanavailablephysicalmemory)=>canleadtooutof memory OOMkillerentersinactionandselectsaprocesstokilltoretrieve somememory


25
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Backtokernelmemory
Kernelmemoryallocators(seefollowingslides)allocatephysical pages,andkernelallocatedmemorycannotbeswappedout,so nofaulthandlingrequiredforkernelmemory Mostkernelmemoryallocationfunctionsalsoreturnakernel virtualaddresstobeusedwithinthekernelspace Kernelmemorylowlevelallocatormanagespages.Thisisthe finestgranularity(usually4kB,architecturedependent) However,thekernelmemorymanagementhandlessmaller memoryallocationsthroughitsallocator(seeslabs/SLUB allocatorusedbykmalloc)

26
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Allocatorsinthekernel
Somekernelcode

kmalloc()allocator
Usesasetofanonymous SLABcaches.

vmalloc()allocator
Nonphysicallycontiguous memory

SLABallocator
Allowstocreatecaches,eachcachestoringobjectsofthesame size.Sizecanbelowerorgreaterthanapagesize.

Pageallocator
Allowstoallocatecontiguousareasofphysicalpages(4k,8k,16k,32k,etc.) 27
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Pageallocator
Appropriateforlargeallocations Apageisusually4K,butcanbemadegreaterinsomearchitectures (sh,mips:4,8,16or64K,butnotconfigurableini386orarm). Buddyallocatorstrategy,soonlyallocationsofpoweroftwonumberof pagesarepossible:1page,2pages,4pages,8pages,16pages,etc. Typicalmaximumsizeis8192KB,butitmightdependonthekernel configuration. Theallocatedareaisvirtuallycontiguous(ofcourse),butalso physicallycontiguous.Itisallocatedintheidentitymappedpartofthe kernelmemoryspace. Thismeansthatlargeareasmaynotbeavailableorhardtoretrieve duetophysicalmemoryfragmentation.

28
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

PageallocatorAPI
unsignedlongget_zeroed_page(intflags); Returnsthevirtualaddressofafreepage,initializedtozero unsignedlong__get_free_page(intflags); Same,butdoesn'tinitializethecontents unsignedlong__get_free_pages(intflags, unsignedintorder); Returnsthestartingvirtualaddressofanareaofseveralcontiguous pagesinphysicalRAM,withorderbeing log2(<number_of_pages>).Canbecomputedfromthesizewith theget_order()function. voidfree_page(unsignedlongaddr); Freesonepage. voidfree_pages(unsignedlongaddr, unsignedintorder); Freesmultiplepages.Needtousethesameorderasinallocation.
29
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Pageallocatorflags
Themostcommononesare: GFP_KERNEL Standardkernelmemoryallocation.Theallocationmayblockinorder tofindenoughavailablememory.Fineformostneeds,exceptin interrupthandlercontext. GFP_ATOMIC RAMallocatedfromcodewhichisnotallowedtoblock(interrupt handlersorcriticalsections).Neverblocks,allowstoaccessemegency pools,butcanfailifnofreememoryisreadilyavailable. GFP_DMA AllocatesmemoryinanareaofthephysicalmemoryusableforDMA transfers. Othersaredefinedininclude/linux/gfp.h(GFP: __get_free_pages).
30
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

SLABallocator
TheSLABallocatorallowstocreatecaches,whichcontainsa setofobjectsofthesamesize Theobjectsizecanbesmallerorgreaterthanthepagesize TheSLABallocatortakescareofgrowingorreducingthesize ofthecacheasneeded,dependingonthenumberofallocated objects.Itusesthepageallocatortoallocateandfreepages. SLABcachesareusedfordatastructuresthatarepresentin manymanyinstancesinthekernel:directoryentries,file objects,networkpacketdescriptors,processdescriptors,etc. See/proc/slabinfo Theyarerarelyusedforindividualdrivers. Seeinclude/linux/slab.hfortheAPI
31
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

SLABallocator(2)
Cache1
Objectsof512bytes

4KBpage

Allocated512bytesobject

Cache2
Objectsof1024 bytes

Free1024bytesobject
32
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

DifferentSLABallocators
Therearethreedifferent,butAPIcompatible,implementationsofaSLAB allocatorintheLinuxkernel.Aparticularimplementationischoosenat configurationtime. SLAB:original,wellprovenallocatorinLinux2.6. SLOB:muchsimpler.Morespaceefficientbutdoesn'tscalewell.Saves afewhundredsofKBinsmallsystems(dependson CONFIG_EMBEDDED) SLUB:thenewdefaultallocatorsince2.6.23,simplerthanSLAB, scalingmuchbetter(inparticularforhugesystems)andcreatingless fragmentation.

33
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

kmallocallocator
Thekmallocallocatoristhegeneralpurposememoryallocatorin theLinuxkernel,forobjectsfrom8bytesto128KB Forsmallsizes,itreliesongenericSLABcaches,named kmallocXXXin/proc/slabinfo Forlargersizes,itreliesonthepageallocator Theallocatedareaisguaranteedtobephysicallycontiguous Theallocatedareasizeisroundeduptothenextpoweroftwo size(whileusingtheSLABallocatordirectlyallowstohavemore flexibility) Itusesthesameflagsasthepageallocator(GFP_KERNEL, GFP_ATOMIC,GFP_DMA,etc.)withthesamesemantics. Shouldbeusedastheprimaryallocatorunlessthereisastrong reasontouseanotherone.

34

FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

kmallocAPI
#include<linux/slab.h> void*kmalloc(size_tsize,intflags);

Allocatesizebytes,andreturnapointertothearea(virtual address) size:numberofbytestoallocate flags:sameflagsasthepageallocator


voidkfree(constvoid*objp);

Freeanallocatedarea
Example:(drivers/infiniband/core/cache.c) structib_update_work*work; work=kmalloc(sizeof*work,GFP_ATOMIC); ... kfree(work);
35
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

kmallocAPI(2)

void*kzalloc(size_tsize,gfp_tflags); Allocatesazeroinitializedbuffer void*kcalloc(size_tn,size_tsize, gfp_tflags); Allocatesmemoryforanarrayofnelementsofsizesize, andzeroesitscontents. void*krealloc(constvoid*p,size_tnew_size, gfp_tflags); Changesthesizeofthebufferpointedbyptonew_size,by reallocatinganewbufferandcopyingthedata,unlessthe new_sizefitswithinthealignmentoftheexistingbuffer.

36
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

vmallocallocator
Thevmallocallocatorcanbeusedtoobtainvirtually contiguousmemoryzones,butnotphysicallycontiguous. Therequestedmemorysizeisroundeduptothenextpage. Theallocatedareaisinthekernelspacepartoftheaddress space,butoutsideoftheidenticallymappedarea Allocationsoffairlylargeareasispossible,sincephysical memoryfragmentationisnotanissue,butareascannotbe usedforDMA,asDMAusuallyrequiresphysically contiguousbuffers. APIin<linux/vmalloc.h> void*vmalloc(unsignedlongsize);
Returnsavirtualaddress

voidvfree(void*addr);
37
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Kernelmemorydebugging
Debuggingfeaturesavailablesince2.6.31 Kmemcheck Dynamiccheckerforaccesstouninitializedmemory. Onlyavailableonx86sofar,butwillhelptoimprovearchitecture independentcodeanyway. SeeDocumentation/kmemcheck.txtfordetails. Kmemleak Dynamiccheckerformemoryleaks Thisfeatureisavailableforallarchitectures. SeeDocumentation/kmemleak.txtfordetails. Bothhaveasignificantoverhead.Onlyusethemindevelopment!

38
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

EmbeddedLinuxdriverdevelopment

Driverdevelopment
UsefulgeneralpurposekernelAPIs

39
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Memory/stringutilities
In<linux/string.h>
Memoryrelated:memset,memcpy,memmove,

memscan,memcmp,memchr
Stringrelated:strcpy,strcat,strcmp,strchr,

strrchr,strlenandvariants
Allocateandcopyastring:kstrdup,kstrndup Allocateandcopyamemoryarea:kmemdup

In<linux/kernel.h>
Stringtointconversion:simple_strtoul,

simple_strtol,simple_strtoull, simple_strtoll
Otherstringfunctions:sprintf,sscanf
40
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Linkedlists
Convenientlinkedlistfacilityin<linux/list.h> Usedinthousandsofplacesinthekernel Addastructlist_headmembertothestructurewhoseinstances willbepartofthelinkedlist.Itisusuallynamednodewheneach instanceneedstoonlybepartofasinglelist. DefinethelistwiththeLIST_HEADmacroforagloballist,ordefinea structlist_headelementandinitializeitwithINIT_LIST_HEAD forlistsembeddedinastructure. Thenusethelist_*()APItomanipulatethelist Addelements:list_add(),list_add_tail() Remove,moveorreplaceelements:list_del(), list_move(),list_move_tail(),list_replace() Testthelist:list_empty() Iterateoverthelist:list_for_each_*()familyofmacros
41

FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Linkedlistsexample
Frominclude/linux/atmel_tc.h structatmel_tc{ /*somemembers*/ structlist_headnode; }; Fromdrivers/misc/atmel_tclib.c staticLIST_HEAD(tc_list);

Definitionofalistelement,witha structlist_headmember

Thegloballist

structatmel_tc*atmel_tc_alloc(unsignedblock,constchar*name){ structatmel_tc*tc; list_for_each_entry(tc,&tc_list,node){ /*Dosomethingwithtc*/ Iterateoverthelistelements } [...] } staticint__inittc_probe(structplatform_device*pdev){ structatmel_tc*tc; tc=kzalloc(sizeof(structatmel_tc),GFP_KERNEL); list_add_tail(&tc>node,&tc_list); }

Addanelementtothelist
42

FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

EmbeddedLinuxdriverdevelopment

Driverdevelopment
I/Omemoryandports

43
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

PortI/Ovs.MemoryMappedI/O
MMIO Sameaddressbustoaddress memoryandI/Odevices AccesstotheI/Odevices usingregularinstructions MostwidelyusedI/Omethod acrossthedifferent architecturessupportedby Linux PIO Differentaddressspacesfor memoryandI/Odevices UsesaspecialclassofCPU instructionstoaccessI/O devices Exampleonx86:INandOUT instructions

44
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

MMIOvsPIO

MMIO registers

RAM PIO registers


Physicalmemory addressspace,accessedwithnormal load/storeinstructions SeparateI/Oaddressspace, accessedwithspecificCPU instructions
45
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

RequestingI/Oports
/proc/ioportsexample(x86) 0000001f:dma1 00200021:pic1 00400043:timer0 00500053:timer1 0060006f:keyboard 00700077:rtc 0080008f:dmapagereg 00a000a1:pic2 00c000df:dma2 00f000ff:fpu 0100013f:pcmcia_socket0 01700177:ide1 01f001f7:ide0 03760376:ide1 0378037a:parport0 03c003df:vga+ 03f603f6:ide0 03f803ff:serial 0800087f:0000:00:1f.0 08000803:PM1a_EVT_BLK 08040805:PM1a_CNT_BLK 0808080b:PM_TMR 08200820:PM2_CNT_BLK 0828082f:GPE0_BLK ...

Tellsthekernelwhichdriverisusingwhich I/Oports Allowstopreventotherdriversfromusingthe sameI/Oports,butispurelyvoluntary.


structresource*request_region( unsignedlongstart, unsignedlonglen, char*name); Triestoreservethegivenregionandreturns NULLifunsuccessful. request_region(0x0170,8,"ide1"); voidrelease_region( unsignedlongstart, unsignedlonglen);
46

FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

AccessingI/Oports
Functionstoread/writebytes(b),word(w)andlongs(l)toI/O ports:
unsignedin[bwl](unsignedlong*addr); voidout[bwl](unsignedport,unsignedlong*addr);

Andthestringsvariants:oftenmoreefficientthanthe correspondingCloop,iftheprocessorsupportssuchoperations!
voidins[bwl](unsignedport,void*addr, unsignedlongcount); voidouts[bwl](unsignedport,void*addr, unsignedlongcount);

Examples
read8bits
oldlcr=inb(baseio+UART_LCR);

write8bits
outb(MOXA_MUST_ENTER_ENCHANCE,baseio+UART_LCR);
47
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

RequestingI/Omemory
/proc/iomemexample 000000000009efff:SystemRAM 0009f0000009ffff:reserved 000a0000000bffff:VideoRAMarea 000c0000000cffff:VideoROM 000f0000000fffff:SystemROM 001000003ffadfff:SystemRAM 001000000030afff:Kernelcode 0030b000003b4bff:Kerneldata 3ffae0003fffffff:reserved 40000000400003ff:0000:00:1f.1 4000100040001fff:0000:02:01.0 4000100040001fff:yenta_socket 4000200040002fff:0000:02:01.1 4000200040002fff:yenta_socket 40400000407fffff:PCICardBus#03 4080000040bfffff:PCICardBus#03 40c0000040ffffff:PCICardBus#07 41000000413fffff:PCICardBus#07 a0000000a0000fff:pcmcia_socket0 a0001000a0001fff:pcmcia_socket1 e0000000e7ffffff:0000:00:00.0 e8000000efffffff:PCIBus#01 e8000000efffffff:0000:01:00.0 ...

Functionsequivalentto request_region()and release_region(),butforI/Omemory.


structresource*request_mem_region( unsignedlongstart, unsignedlonglen, char*name); voidrelease_mem_region( unsignedlongstart, unsignedlonglen);

48
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

MappingI/Omemoryinvirtualmemory
Load/storeinstructionsworkwithvirtualaddresses ToaccessI/Omemory,driversneedtohaveavirtual addressthattheprocessorcanhandle,becauseI/O memoryisnotmappedbydefaultinvirtualmemory. Theioremapfunctionssatisfythisneed: #include<asm/io.h>; void*ioremap(unsignedlongphys_addr, unsignedlongsize); voidiounmap(void*address); Caution:checkthatioremapdoesn'treturnaNULL address!
49
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

ioremap()
ioremap(0xFFEBC00,4096)=0xCDEFA000

MMIO registers
0xFFEBC000

0xCDEFA000

RAM

RAM

Physicalmemory addressspace

Virtual addressspace
50

FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

User

Kernel

AccessingMMIOdevices
Directlyreadingfromorwritingtoaddressesreturnedby ioremap(pointerdereferencing)maynotworkonsome architectures. TodoPCIstyle,littleendianaccesses,conversionbeingdone automatically
unsignedread[bwl](void*addr); voidwrite[bwl](unsignedval,void*addr);

Todorawaccess,withoutendianessconversion
unsigned__raw_read[bwl](void*addr); void__raw_write[bwl](unsignedval,void*addr);

Example
32bitswrite
__raw_writel(1<<KS8695_IRQ_UART_TX, membase+KS8695_INTST);
51
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

NewAPIformixedaccesses
AnewAPIallowstowritedriversthatcanworkoneitherdevices accessedoverPIOorMMIO.Afewdriversuseit,buttheredoesn't seemtobeaconsensusinthekernelcommunityaroundit. Mapping
ForPIO:ioport_map()andioport_unmap().Theydon'treally map,buttheyreturnaspecialcookie. ForMMIO:ioremap()andiounmap().Asusual.

Access,worksbothonaddressesreturnedbyioport_map()and
ioremap()
ioread[8/16/32]()andiowrite[8/16/32]forsingleaccess ioread_rep[8/16/32]()andiowrite_rep[8/16/32]()for

repeatedaccesses
52
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

AvoidingI/Oaccessissues
CachingonI/Oportsormemoryalreadydisabled Usethemacros,theydotherightthingforyourarchitecture Thecompilerand/orCPUcanreordermemoryaccesses,which mightcausetroublesforyourdevicesistheyexpectoneregister toberead/writtenbeforeanotherone. Memorybarriersareavailabletopreventthisreordering rmb()isareadmemorybarrier,preventsreadstocrossthe barrier wmb()isawritememorybarrier mb()isareadwritememorybarrier StartstobeaproblemwithCPUthatreorderinstructionsand SMP. SeeDocumentation/memorybarriers.txtfordetails
53
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

/dev/mem
Usedtoprovideuserspaceapplications withdirectaccesstophysicaladdresses. Usage:open/dev/memandreadorwriteatgivenoffset. Whatyoureadorwriteisthevalue atthecorrespondingphysicaladdress. UsedbyapplicationssuchastheXserver towritedirectlytodevicememory. Onx86,armandtile:CONFIG_STRICT_DEVMEMoption torestrict/dev/memnonRAMaddresses,forsecurity reasons(2.6.37rc2status).

54
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

PracticallabI/Omemoryandports
Makearemoteconnectiontoyour boardthroughssh. Accessthesystemconsolethrough thenetwork. ReservetheI/Omemoryaddresses usedbytheserialport. Readdeviceregistersandwritedata tothem,tosendcharactersonthe serialport.

55
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

EmbeddedLinuxdriverdevelopment

Driverdevelopment
Characterdrivers

56
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Usefulnessofcharacterdrivers
Exceptforstoragedevicedrivers,mostdriversfordeviceswith inputandoutputflowsareimplementedascharacterdrivers. So,mostdriversyouwillfacewillbecharacterdrivers Youwillregretifyousleepduringthispart!

57
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Creatingacharacterdriver
Userspaceneeds Thenameofadevicefilein/devto interactwiththedevicedriverthrough regularfileoperations(open,read,write, close...) Thekernelneeds
Copytouser

Userspace
Read buffer read /dev/foo major/minor Copyfromuser 58 Write string write

Toknowwhichdriverisinchargeofdevice fileswithagivenmajor/minornumberpair Foragivendriver,tohavehandlers(file operations)toexecutewhenuserspace opens,reads,writesorclosesthedevice file.

Read handler

Write handler

Devicedriver Kernelspace

FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Implementingacharacterdriver
Fourmajorsteps
Implementoperationscorrespondingtothesystemcallsan applicationcanapplytoafile:fileoperations Defineafile_operationsstructureassociatingfunctionpointers totheirimplementationinyourdriver Reserveasetofmajorandminorsforyourdriver Tellthekerneltoassociatethereservedmajorandminortoyour fileoperations

ThisisaverycommondesignschemeintheLinuxkernel
Acommonkernelinfrastructuredefinesasetofoperationstobe implementedbyadriverandfunctionstoregisteryourdriver Yourdriveronlyneedstoimplementthissetofwelldefined operations
59
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Fileoperations
Beforeregisteringcharacterdevices,youhavetodefine file_operations(calledfops)forthedevicefiles. Thefile_operationsstructureisgenerictoallfileshandledbytheLinux kernel.Itcontainsmanyoperationsthataren'tneededforcharacter drivers. Herearethemostimportantoperationsforacharacterdriver.Allof themareoptional.
structfile_operations{ [...] ssize_t(*read)(structfile*,char__user*,size_t,loff_t*); ssize_t(*write)(structfile*,constchar__user*,size_t,loff_t*); long(*unlocked_ioctl)(structfile*,unsignedint,unsignedlong); int(*mmap)(structfile*,structvm_area_struct*); int(*open)(structinode*,structfile*); int(*release)(structinode*,structfile*); [...] };

60
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

open()andrelease()
intfoo_open(structinode*i,structfile*f) Calledwhenuserspaceopensthedevicefile. inodeisastructurethatuniquelyrepresentafileinthesystem(be itaregularfile,adirectory,asymboliclink,acharacterorblock device) fileisastructurecreatedeverytimeafileisopened.Severalfile structurescanpointtothesameinodestructure. Containsinformationslikethecurrentposition,theopening mode,etc. Hasavoid*private_datapointerthatonecanfreelyuse. Apointertothefilestructureispassedtoallotheroperations intfoo_release(structinode*i, structfile*f) Calledwhenuserspaceclosesthefile.
61
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

read()
ssize_tfoo_read ( structfile*f, __userchar*buf, size_tsz,loff_t*off)

Calledwhenuserspaceusestheread()systemcallonthe device. Mustreaddatafromthedevice,writeatmostszbytesinthe userspacebufferbuf,andupdatethecurrentpositioninthefile off.fisapointertothesamefilestructurethatwaspassedin theopen()operation Mustreturnthenumberofbytesread. OnUnix,read()operationstypicallyblockwhenthereisn't enoughdatatoreadfromthedevice

62
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

write()
ssize_tfoo_write( structfile*f, __userconstchar*buf, size_tsz,loff_t*off)

Calledwhenuserspaceusesthewrite()systemcallonthe device Theoppositeofread,mustreadatmostszbytesfrombuf, writeittothedevice,updateoffandreturnthenumberof byteswritten.

63
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Exchangingdatawithuserspace(1)
Kernelcodeisn'tallowedtodirectlyaccess userspacememory,usingmemcpyor directpointerdereferencing Doingsodoesnotworkonsome architectures Iftheaddresspassedbytheapplication wasinvalid,theapplicationwould segfault Tokeepthekernelcodeportableandhave propererrorhandling,yourdrivermustuse specialkernelfunctionstoexchangedata withuserspace
64
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Exchangingdatawithuserspace(2)
Asinglevalue
get_user(v,p);

Thekernelvariablevgetsthevaluepointerbytheuserspace pointerp
put_user(v,p);

Thevaluepointedbytheuserspacepointerpissettothecontents ofthekernelvariablev.

Abuffer
unsignedlongcopy_to_user(void__user*to, constvoid*from, unsignedlongn); unsignedlongcopy_from_user(void*to, constvoid__user*from,unsignedlongn);

Thereturnvaluemustbechecked.Zeroonsuccess,nonzeroon failure.Ifnonzero,theconventionistoreturnEFAULT.
65
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Exchangingdatawithuserspace(3)
void*to void*from

copy_from_user()

copy_to_user()

void__user*from

void__user*to

Bufferofdatainthe userspaceapplication Bufferofdatainthe kernelspacedriver Kernel User 66

FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

readoperationexample
staticssize_t acme_read(structfile*file,char__user*buf,size_tcount,loff_t*ppos) { /*Theacme_bufaddresscorrespondstoadeviceI/Omemoryarea*/ /*ofsizeacme_bufsize,obtainedwithioremap()*/ intremaining_size,transfer_size; remaining_size=acme_bufsize(int)(*ppos);//byteslefttotransfer if(remaining_size==0){/*Allread,returning0(EndOfFile)*/ return0; } /*Sizeofthistransfer*/ transfer_size=min(remaining_size,(int)count); if(copy_to_user(buf/*to*/,acme_buf+*ppos/*from*/,transfer_size)){ returnEFAULT; }else{/*Increasethepositionintheopenfile*/ *ppos+=transfer_size; returntransfer_size; } }

Readmethod

Pieceofcodeavailablein http://freeelectrons.com/doc/c/acme.c

67
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

writeoperationexample
staticssize_t acme_write(structfile*file,constchar__user*buf,size_tcount,loff_t*ppos) { intremaining_bytes; /*Numberofbytesnotwrittenyetinthedevice*/ remaining_bytes=acme_bufsize(*ppos); if(count>remaining_bytes){ /*Can'twritebeyondtheendofthedevice*/ returnEIO; } if(copy_from_user(acme_buf+*ppos/*to*/,buf/*from*/,count)){ returnEFAULT; }else{ /*Increasethepositionintheopenfile*/ *ppos+=count; returncount; } }

Writemethod

Pieceofcodeavailablein http://freeelectrons.com/doc/c/acme.c

68
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

unlocked_ioctl()
longunlocked_ioctl(structfile*f, unsignedintcmd,unsignedlongarg) Associatedtotheioctl()systemcall Calledunlockedbecauseitdoesn'tholdtheBigKernelLock. Allowstoextendthedrivercapabilitiesbeyondthelimited read/writeAPI Forexample:changingthespeedofaserialport,settingvideo outputformat,queryingadeviceserialnumber... cmdisanumberidentifyingtheoperationtoperform argistheoptionalargumentpassedasthirdargumentofthe ioctl()systemcall.Canbeaninteger,anaddress,etc. Thesemanticofcmdandargisdriverspecific.
69
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

ioctl()example:kernelside
staticlongphantom_ioctl(structfile*file,unsignedintcmd, unsignedlongarg) { structphm_regr; void__user*argp=(void__user*)arg; switch(cmd){ casePHN_SET_REG: if(copy_from_user(&r,argp,sizeof(r))) returnEFAULT; /*Dosomething*/ break; casePHN_GET_REG: if(copy_to_user(argp,&r,sizeof(r))) returnEFAULT; /*Dosomething*/ break; default: returnENOTTY; } return0; }

Selectedexcerptfromdrivers/misc/phantom.c

70

FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Ioctl()example:applicationside
intmain(void) { intfd,ret; structphm_regreg; fd=open(/dev/phantom); assert(fd>0); reg.field1=42; reg.field2=67; ret=ioctl(fd,PHN_SET_REG,&reg); assert(ret==0); return0; }
71
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

fileoperationsdefinitionexample(3)
Definingafile_operationsstructure: #include<linux/fs.h> staticstructfile_operationsacme_fops= { .owner=THIS_MODULE, .read=acme_read, .write=acme_write, }; Youjustneedtosupplythefunctionsyouimplemented!Defaultsfor otherfunctions(suchasopen,release...)arefineifyoudonot implementanythingspecial.

72
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

dev_tdatatype
Kerneldatatypetorepresentamajor/minornumberpair Alsocalledadevicenumber. Definedin<linux/kdev_t.h> Linux2.6:32bitsize(major:12bits,minor:20bits) Macrotocomposethedevicenumber: MKDEV(intmajor,intminor); Macrotoextracttheminorandmajornumbers: MAJOR(dev_tdev); MINOR(dev_tdev);

73
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Registeringdevicenumbers(1)
#include<linux/fs.h> intregister_chrdev_region( dev_tfrom, /*Startingdevicenumber*/ unsignedcount, /*Numberofdevicenumbers*/ constchar*name); /*Registeredname*/ Returns0iftheallocationwassuccessful. Example
staticdev_tacme_dev=MKDEV(202,128); if(register_chrdev_region(acme_dev,acme_count,acme)){ printk(KERN_ERRFailedtoallocatedevicenumber\n); ...

74
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Registeringdevicenumbers(2)
Ifyoudon'thavefixeddevicenumbersassignedtoyourdriver Betternottochoosearbitraryones. Therecouldbeconflictswithotherdrivers. ThekernelAPIoffersaalloc_chrdev_regionfunction tohavethekernelallocatefreeonesforyou.Youcanfindthe allocatedmajornumberin/proc/devices.

75
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Informationonregistereddevices
Registereddevicesarevisiblein/proc/devices:
Characterdevices: 1mem 4/dev/vc/0 4tty 4ttyS 5/dev/tty 5/dev/console 5/dev/ptmx 6lp 10misc 13input 14sound ... Blockdevices: 1ramdisk 3ide0 8sd 9md 22ide1 65sd 66sd 67sd 68sd

Major number

Registered name
76

FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Characterdeviceregistration(1)
Thekernelrepresentscharacterdriverswithacdevstructure Declarethisstructureglobally(withinyourmodule): #include<linux/cdev.h> staticstructcdevacme_cdev; Intheinitfunction,initializethestructure: cdev_init(&acme_cdev,&acme_fops);

77
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Characterdeviceregistration(2)
Then,nowthatyourstructureisready,addittothesystem: intcdev_add( structcdev*p, /*Characterdevicestructure*/ dev_tdev, /*Startingdevicemajor/minornumber*/ unsignedcount); /*Numberofdevices*/ Afterthisfunctioncall,thekernelknowstheassociationbetween themajor/minornumbersandthefileoperations.Yourdeviceis readytobeused! Example(continued):
if(cdev_add(&acme_cdev,acme_dev,acme_count)){ printk(KERN_ERRChardriverregistrationfailed\n);

...

78
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Characterdeviceunregistration
Firstdeleteyourcharacterdevice: voidcdev_del(structcdev*p); Then,andonlythen,freethedevicenumber: voidunregister_chrdev_region(dev_tfrom, unsignedcount); Example(continued): cdev_del(&acme_cdev); unregister_chrdev_region(acme_dev,acme_count);

79
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Linuxerrorcodes
Thekernelconventionforerrormanagementis Return0onsuccess return0; Returnanegativeerrorcodeonfailure returnEFAULT; Errorcodes include/asmgeneric/errnobase.h include/asmgeneric/errno.h

80
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Chardriverexamplesummary(1)
staticvoid*acme_buf; staticintacme_bufsize=8192; staticintacme_count=1; staticdev_tacme_dev=MKDEV(202,128); staticstructcdevacme_cdev; staticssize_tacme_write(...){...} staticssize_tacme_read(...){...} staticstructfile_operationsacme_fops= { .owner=THIS_MODULE, .read=acme_read, .write=acme_write };

81
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Chardriverexamplesummary(2)
Showshowtohandleerrorsanddeallocateresourcesintherightorder!
staticint__initacme_init(void) { interr; acme_buf=ioremap(ACME_PHYS, acme_bufsize); if(!acme_buf){ err=ENOMEM; gotoerr_exit; } if(register_chrdev_region(acme_dev, acme_count,acme)){ err=ENODEV; gotoerr_free_buf; } cdev_init(&acme_cdev,&acme_fops); if(cdev_add(&acme_cdev,acme_dev, acme_count)){ err=ENODEV; gotoerr_dev_unregister; }

return0; err_dev_unregister: unregister_chrdev_region( acme_dev,acme_count); err_free_buf: iounmap(acme_buf); err_exit: returnerr; } staticvoid__exitacme_exit(void) { cdev_del(&acme_cdev); unregister_chrdev_region(acme_dev, acme_count); iounmap(acme_buf); }

Completeexamplecodeavailableonhttp://freeelectrons.com/doc/c/acme.c
82
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Characterdriversummary
Definethefileoperationscallbacksforthedevicefile:read,write,ioctl... Inthemoduleinitfunction,reservemajorandminornumberswith register_chrdev_region(),initacdevstructurewithyourfileoperationsandadditto thesystemwithcdev_add(). Inthemoduleexitfunction,callcdev_del()andunregister_chrdev_region()

Loadthecharacterdrivermodule Createdevicefileswithmatchingmajorandminornumbersifneeded Thedevicefileisreadytouse!

Systemuser Kernel

Openthedevicefile,read,write,orsendioctl'stoit. Executesthecorrespondingfileoperations

Kernel
83

FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Userspace

Systemadministration

Kernel

Characterdriverwriter

PracticallabCharacterdrivers
Writingasimplecharacterdriver,to writedatatotheserialport. Onyourworkstation,checkingthat transmitteddataisreceivedcorrectly. Exchangingdatabetweenuserspace andkernelspace. Practicingwiththecharacterdevice driverAPI. Usingkernelstandarderrorcodes.

84
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

EmbeddedLinuxDriverDevelopment

Driverdevelopment
Processesandscheduling

85
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Process,thread?
Confusionaboutthetermsprocess,threadandtask InUnix,aprocessiscreatedusingfork()andiscomposedof
Anaddressspace,whichcontainstheprogramcode,data,stack, sharedlibraries,etc. Onethread,thatstartsexecutingthemain()function. Uponcreation,aprocesscontainsonethread

Additionalthreadscanbecreatedinsideanexistingprocess, usingpthread_create()
Theyruninthesameaddressspaceastheinitialthreadofthe process Theystartexecutingafunctionpassedasargumentto pthread_create()
86
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Process,thread:kernelpointofview
Thekernelrepresentseachthreadrunninginthesystembya structureoftypetask_struct Fromaschedulingpointofview,itmakesnodifferencebetween theinitialthreadofaprocessandalladditionalthreadscreated dynamicallyusingpthread_create()

Thread A Addressspace
Processafterfork()

Thread A

Thread B

Addressspace
Sameprocessafterpthread_create() 87

FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Athreadlife
Threadcreated
Taskterminatedbutits resourcesarenotfreedyet. Waitingforitsparent toacknowledgeitsdeath.

EXIT_ZOMBIE

byfork()or pthread_create()

Thethreadiselected bythescheduler

TASK_RUNNING
Readybut notrunning Thethreadispreempted bytheschedulertorun ahigherprioritytask

TASK_RUNNING
Actuallyrunning

Theeventoccurs ortheprocessreceives asignal.Threadbecomes runnableagain

TASK_INTERRUPTIBLE TASK_UNINTERRUPTIBLE orTASK_KILLABLE


Waiting

Decidestosleep onawaitqueue foraspecificevent

88
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Executionofsystemcalls
Theexecutionofsystemcallstakesplaceinthe contextofthethreadrequestingthem.
Processcontinuinginuserspace... (orreplacedbyahigherpriorityprocess) (canbepreempted)

Processexecutinginuserspace... (canbepreempted) Systemcall orexception

Kernelcodeexecuted onbehalfofuserspace (canbepreemptedtoo!)

Stillhasaccesstoprocess data(openfiles...)

89
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

EmbeddedLinuxdriverdevelopment

Driverdevelopment
Sleeping

90
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Sleeping
Sleepingisneededwhenaprocess(userspaceorkernelspace) iswaitingfordata.

Userspaceprocess... readdevicefile Systemcall... askfor data sleep

Other processes are scheduled ...Systemcall wakeup Interrupt handler datareadynotification

...Userspace return

91
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Howtosleep(1)
Mustdeclareawaitqueue Awaitqueuewillbeusedtostorethelistofthreadswaiting foranevent. Staticqueuedeclaration usefultodeclareasaglobalvariable DECLARE_WAIT_QUEUE_HEAD(module_queue); Ordynamicqueuedeclaration usefultoembedthewaitqueueinsideanotherdata structure wait_queue_head_tqueue; init_waitqueue_head(&queue);
92
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Howtosleep(2)
Severalwaystomakeakernelprocesssleep wait_event(queue,condition); SleepsuntilthetaskiswokenupandthegivenCexpressionistrue. Caution:can'tbeinterrupted(can'tkilltheuserspaceprocess!) intwait_event_killable(queue,condition);(SinceLinux2.6.25) Canbeinterrupted,butonlybyafatalsignal(SIGKILL).Returns ERESTARSYSifinterrupted. intwait_event_interruptible(queue,condition); Canbeinterruptedbyanysignal.ReturnsERESTARTSYSifinterrupted. intwait_event_timeout(queue,condition,timeout); Alsostopssleepingwhenthetaskiswokenupandthetimeoutexpired.Returns0 ifthetimeoutelapsed,nonzeroiftheconditionwasmet. intwait_event_interruptible_timeout(queue,condition, timeout); Sameasabove,interruptible.Returns0ifthetimeoutelapsed,ERESTARTSYS ifinterrupted,positivevalueiftheconditionwasmet
93
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

HowtosleepExample

ret=wait_event_interruptible (sonypi_device.fifo_proc_list, kfifo_len(sonypi_device.fifo)!=0); if(ret) returnret;

94
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Wakingup!
Typicallydonebyinterrupthandlerswhendatasleepingprocesses arewaitingforbecomesavailable. wake_up(&queue); Wakesupallprocessesinthewaitqueue wake_up_interruptible(&queue); Wakesupallprocesseswaitinginaninterruptiblesleeponthe givenqueue

95
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Exclusivevs.nonexclusive
wait_event_interruptible()putsataskinanonexclusive wait
Allnonexclusivetasksarewokenupbywake_up()/ wake_up_interruptible()

wait_event_interruptible_exclusive()putsataskin anexclusivewait
wake_up()/wake_up_interruptible()wakesupallnon exclusivetasksandonlyoneexclusivetask wake_up_all()/wake_up_interruptible_all()wakes upallnonexclusiveandallexclusivetasks

Exclusivesleepsareusefultoavoidwakingupmultipletasks whenonlyonewillbeabletoconsumetheevent Nonexclusivesleepsareusefulwhentheeventcanbenefitto multipletasks


96
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Sleepingandwakingupimplementation
Theschedulerdoesn'tkeepevaluatingthesleepingcondition!
#define__wait_event(wq,condition)\ do{\ DEFINE_WAIT(__wait);\ \ for(;;){\ prepare_to_wait(&wq,&__wait,TASK_UNINTERRUPTIBLE);\ if(condition)\ break;\ schedule();\ }\ finish_wait(&wq,&__wait);\ }while(0)

wait_event_interruptible(&queue,condition); TheprocessisputintheTASK_INTERRUPTIBLEstate. wake_up_interruptible(&queue); Allprocesseswaitinginqueuearewokenup,sotheyget scheduledlaterandhavetheopportunitytoreavalutethe condition.

97

FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

EmbeddedLinuxdriverdevelopment

Driverdevelopment
Interruptmanagement

98
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Registeringaninterrupthandler(1)
Definedininclude/linux/interrupt.h intrequest_irq( Returns0ifsuccessful unsignedintirq, Requestedirqchannel irq_handler_thandler, Interrupthandler unsignedlongirq_flags, Optionmask(seenextpage) constchar*devname, Registeredname void*dev_id); Pointertosomehandlerdata CannotbeNULLandmustbeuniqueforsharedirqs! voidfree_irq(unsignedintirq,void*dev_id); dev_idcannotbeNULLandmustbeuniqueforsharedirqs. Otherwise,onasharedinterruptline, free_irqwouldn'tknowwhichhandlertofree.

99
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Registeringaninterrupthandler(2)
irq_flagsbitvalues(canbecombined,noneisfinetoo) IRQF_DISABLED "Quick"interrupthandler.Runwithallinterruptsdisabledonthecurrentcpu (insteadofjustthecurrentline).Forlatencyreasons,shouldonlybeused whenneeded! IRQF_SHARED Runwithinterruptsdisabledonlyonthecurrentirqlineandonthelocalcpu. Theinterruptchannelcanbesharedbyseveraldevices.Requiresa hardwarestatusregistertellingwhetheranIRQwasraisedornot.

100
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Interrupthandlerconstraints
Noguaranteeonwhichaddressspacethesystemwill beinwhentheinterruptoccurs:can'ttransferdatato andfromuserspace InterrupthandlerexecutionismanagedbytheCPU,not bythescheduler.Handlerscan'trunactionsthatmay sleep,becausethereisnothingtoresumetheir execution.Inparticular,needtoallocatememorywith GFP_ATOMIC.
Havetocompletetheirjobquicklyenough: theyshouldn'tblocktheirinterruptlinefortoolong.

101
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Informationoninstalledhandlers
/proc/interrupts IGEPv2(OMAP3ARM) exampleonLinux2.6.33
CPU0 7:2INTCTWL4030PIH Registeredname 11:0INTCprcm 12:6946564INTCDMA 25:2INTCOMAPDSS 37:50993360INTCgptimer 56:598INTCi2c_omap 61:0INTCi2c_omap 72:1INTCserialidle 73:1INTCserialidle 74:35INTCserialidle,serial 77:8792082INTCehci_hcd:usb1 83:5421922INTCmmc0 86:126INTCmmc1 92:1INTCmusb_hdrc 93:0INTCmusb_hdrc 336:11781580GPIOeth0 376:0twl4030twl4030_pwrbutton 378:2twl4030twl4030_usb 379:0twl4030rtc0 384:0twl4030mmc0 Err:0 Spuriousinterruptcount 102
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Interrupthandlerprototype
irqreturn_tfoo_interrupt (intirq,void*dev_id) Arguments irq,theIRQnumber dev_id,theopaquepointerpassedatrequest_irq() Returnvalue IRQ_HANDLED:recognizedandhandledinterrupt IRQ_NONE:notonadevicemanagedbythemodule.Usefulto shareinterruptchannelsand/orreportspuriousinterruptsto thekernel.

103
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Theinterrupthandler'sjob
Acknowledgetheinterrupttothedevice (otherwisenomoreinterruptswillbegenerated,orthe interruptwillkeepfiringoverandoveragain) Read/writedatafrom/tothedevice Wakeupanywaitingprocesswaitingforthecompletion ofthisread/writeoperation: wake_up_interruptible(&module_queue);

104
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Tophalfandbottomhalfprocessing(1)
Splittingtheexecutionofinterrupthandlersin2parts Tophalf:theinterrupthandlermustcompleteasquickly aspossible.Onceitacknowledgedtheinterrupt,itjust schedulesthelengthyrestofthejobtakingcareofthe data,foralaterexecution. Bottomhalf:completingtherestoftheinterrupthandler job.Handlesdata,andthenwakesupanywaitinguser process. Canbeimplementedusingtaskletsorworkqueues.

105
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Tasklets
Declarethetaskletinthemodulesourcefile: DECLARE_TASKLET(module_tasklet,/*name*/ module_do_tasklet,/*function*/ data/*params*/ ); Schedulethetaskletinthetophalfpart(interrupthandler): tasklet_schedule(&module_tasklet); Notethatatasklet_hi_schedulefunctionisavailableto definehighprioritytaskletstorunbeforeordinaryones. Taskletsareexecutedwithallinterruptsenabled,butin interruptcontext,sosleepingisnotallowed.

106
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Interruptmanagementsummary
Devicedriver Whenthedevicefileisfirst opened,registeraninterrupt handlerforthedevice's interruptchannel. Interrupthandler Calledwhenaninterruptis raised. Acknowledgetheinterrupt Ifneeded,scheduleatasklet takingcareofhandlingdata. Otherwise,wakeupprocesses waitingforthedata.
107
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Tasklet Processthedata Wakeupprocesseswaiting forthedata Devicedriver Whenthedeviceisnolonger openedbyanyprocess, unregistertheinterrupt handler.

PracticallabInterrupts
Addingreadcapabilitytothe characterdriverdevelopedearlier. Registeraninterrupthandler. Waitingfordatatobeavailableinthe readfileoperation. Wakingupthecodewhendatais availablefromthedevice.

108
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

EmbeddedLinuxdriverdevelopment

Driverdevelopment
Concurrentaccesstoresources

109
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Sourcesofconcurrencyissues
Thesameresourcescanbeaccessedbyseveralkernel processesinparallel,causingpotentialconcurrencyissues Severaluserspaceprogramsaccessingthesamedevicedata orhardware.Severalkernelprocessescouldexecutethesame codeonbehalfofuserprocessesrunninginparallel. Multiprocessing:thesamedrivercodecanberunningon anotherprocessor.ThiscanalsohappenwithsingleCPUswith hyperthreading. Kernelpreemption,interrupts:kernelcodecanbeinterruptedat anytime(justafewexceptions),andthesamedatamaybe accessbyanotherprocessbeforetheexecutioncontinues.

110
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Avoidingconcurrencyissues
Avoidusingglobalvariablesandshareddatawhenever possible (cannotbedonewithhardwareresources). Usetechniquestomanageconcurrentaccessto resources. SeeRustyRussell'sUnreliableGuideToLocking Documentation/DocBook/kernellocking/ inthekernelsources.

111
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Concurrencyprotectionwithlocks
Process1
Acquirelock Success Criticalcodesection

Failed Tryagain Success

Process2
Waitlockrelease

Sharedresource

Releaselock

112
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Linuxmutexes
ThemainlockingprimitivesinceLinux2.6.16. Betterthancountingsemaphoreswhenbinaryonesare enough. Theprocessrequestingthelockblockswhenthelockis alreadyheld.Mutexescanthereforeonlybeusedin contextswheresleepingisallowed. Mutexdefinition: #include<linux/mutex.h> Initializingamutexstatically: DEFINE_MUTEX(name); Orinitializingamutexdynamically: voidmutex_init(structmutex*lock);
113
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

lockingandunlockingmutexes
voidmutex_lock(structmutex*lock); Triestolockthemutex,sleepsotherwise. Caution:can'tbeinterrupted,resultinginprocessesyoucannotkill! intmutex_lock_killable(structmutex*lock); Same,butcanbeinterruptedbyafatal(SIGKILL)signal.Ifinterrupted,returns anonzerovalueanddoesn'tholdthelock.Testthereturnvalue!!! intmutex_lock_interruptible(structmutex*lock); Same,butcanbeinterruptedbyanysignal. intmutex_trylock(structmutex*lock); Neverwaits.Returnsanonzerovalueifthemutexisnotavailable. intmutex_is_locked(structmutex*lock); Justtellswhetherthemutexislockedornot. voidmutex_unlock(structmutex*lock); Releasesthelock.Doitassoonasyouleavethecriticalsection.

114
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Spinlocks
Lockstobeusedforcodethatisnotallowedtosleep (interrupthandlers),orthatdoesn'twanttosleep(critical sections).Beverycarefulnottocallfunctionswhichcan sleep! Originallyintendedformultiprocessorsystems Spinlocksneversleepandkeepspinning inaloopuntilthelockisavailable.
Spinlock Stilllocked?

Spinlockscausekernelpreemptiontobedisabled ontheCPUexecutingthem. Thecriticalsectionprotectedbyaspinlockisnotallowedto sleep.

115
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Initializingspinlocks
Static spinlock_tmy_lock=SPIN_LOCK_UNLOCKED; Dynamic voidspin_lock_init(spinlock_t*lock);

116
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Usingspinlocks
Severalvariants,dependingonwherethespinlockiscalled: voidspin_[un]lock(spinlock_t*lock); Doesn'tdisableinterrupts.Usedforlockinginprocesscontext (criticalsectionsinwhichyoudonotwanttosleep). voidspin_lock_irqsave/spin_unlock_irqrestore (spinlock_t*lock,unsignedlongflags); Disables/restoresIRQsonthelocalCPU. Typicallyusedwhenthelockcanbeaccessedinbothprocess andinterruptcontext,topreventpreemptionbyinterrupts. voidspin_[un]lock_bh(spinlock_t*lock); Disablessoftwareinterrupts,butnothardwareones. Usefultoprotectshareddataaccessedinprocesscontext andinasoftinterrupt(bottomhalf).Noneedtodisable hardwareinterruptsinthiscase. Notethatreader/writerspinlocksalsoexist.
117
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Spinlockexample
Spinlockstructureembeddedintouart_port
structuart_port{ spinlock_tlock; /*Otherfields*/ };

Spinlocktaken/releasedwithprotectionagainstinterrupts
staticunsignedintulite_tx_empty(structuart_port*port) { unsignedlongflags; spin_lock_irqsave(&port>lock,flags); /*Dosomething*/ spin_unlock_irqrestore(&port>lock,flags); [] }
118
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Deadlocksituations
Theycanlockupyoursystem.Makesuretheyneverhappen! Don'tcallafunctionthatcan trytogetaccesstothesame lock Holdingmultiplelocksisrisky!

Getlock1 Getlock1 call Getlock2 Waitforlock1


Dead Lock! Dead Lock!

Getlock2

Getlock1

119
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Kernellockvalidator
FromIngoMolnarandArjanvandeVen Addsinstrumentationtokernellockingcode Detectviolationsoflockingrulesduringsystemlife,suchas: Locksacquiredindifferentorder (keepstrackoflockingsequencesandcomparesthem). Spinlocksacquiredininterrupthandlersandalsoinprocess contextwheninterruptsareenabled. Notsuitableforproductionsystemsbutacceptableoverheadin development. SeeDocumentation/lockdepdesign.txtfordetails

120
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Alternativestolocking
Aswehavejustseen,lockingcanhaveastrongnegative impactonsystemperformance.Insomesituations,youcould dowithoutit. ByusinglockfreealgorithmslikeReadCopyUpdate(RCU). RCUAPIavailableinthekernel (Seehttp://en.wikipedia.org/wiki/RCU). Whenavailable,useatomicoperations.

121
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Atomicvariables
Usefulwhenthesharedresourceisan integervalue Evenaninstructionliken++isnot guaranteedtobeatomiconall processors! Header #include<asm/atomic.h> Type atomic_t containsasignedinteger(atleast24 bits)

Operationswithoutreturnvalue:
voidatomic_inc(atomic_t*v); voidatomic_dec(atomic_t*v); voidatomic_add(inti,atomic_t*v); voidatomic_sub(inti,atomic_t*v);

Simularfunctionstestingtheresult:
intatomic_inc_and_test(...); intatomic_dec_and_test(...); intatomic_sub_and_test(...);

Functionsreturningthenewvalue:
intatomic_inc_and_return(...); intatomic_dec_and_return(...); intatomic_add_and_return(...); intatomic_sub_and_return(...);

Atomicoperations(mainones) Setorreadthecounter:
atomic_set(atomic_t*v,inti); intatomic_read(atomic_t*v);

122
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Atomicbitoperations
Supplyveryfast,atomicoperations Onmostplatforms,applytoanunsignedlongtype. Applytoavoidtypeonafewothers. Set,clear,toggleagivenbit: voidset_bit(intnr,unsignedlong*addr); voidclear_bit(intnr,unsignedlong*addr); voidchange_bit(intnr,unsignedlong*addr); Testbitvalue: inttest_bit(intnr,unsignedlong*addr); Testandmodify(returnthepreviousvalue): inttest_and_set_bit(...); inttest_and_clear_bit(...); inttest_and_change_bit(...);

123
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

PracticallabLocking
Addlockingtothedrivertoprevent concurrentaccessestoshared ressources

124
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

EmbeddedLinuxdriverdevelopment

Driverdevelopment
Debuggingandtracing

125
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Debuggingwithprintk
Universaldebuggingtechniqueusedsincethebeginningof programming(firstfoundincavemendrawings) Printedornotintheconsoleaccordingtothepriority. Thisiscontrolledbytheloglevelkernelparameter,or through/proc/sys/kernel/printk (seeDocumentation/sysctl/kernel.txt) Availablepriorities(include/linux/kernel.h):
#defineKERN_EMERG"<0>"/*systemisunusable*/ #defineKERN_ALERT"<1>"/*actionmustbetakenimmediately*/ #defineKERN_CRIT"<2>"/*criticalconditions*/ #defineKERN_ERR"<3>"/*errorconditions*/ #defineKERN_WARNING"<4>"/*warningconditions*/ #defineKERN_NOTICE"<5>"/*normalbutsignificantcondition*/ #defineKERN_INFO"<6>"/*informational*/ #defineKERN_DEBUG"<7>"/*debuglevelmessages*/

126
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Debuggingwith/procor/sys
Insteadofdumpingmessagesinthekernellog,youcanhaveyour driversmakeinformationavailabletouserspace Throughafilein/procor/sys,whichcontentsarehandledby callbacksdefinedandregisteredbyyourdriver. Canbeusedtoshowanypieceofinformation aboutyourdeviceordriver. Canalsobeusedtosenddatatothedriverortocontrolit. Caution:anybodycanusethesefiles. Youshouldremoveyourdebugginginterfaceinproduction! Sincethearrivalofdebugfs,nolongerthepreferreddebugging mechanism

127
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Debugfs
Avirtualfilesystemtoexportdebugginginformationtouserspace. Kernelconfiguration:DEBUG_FS Kernelhacking>DebugFilesystem Muchsimplertocodethananinterfacein/procor/sys. ThedebugginginterfacedisappearswhenDebugfsisconfigured out. Youcanmountitasfollows: sudomounttdebugfsnone/mnt/debugfs Firstdescribedonhttp://lwn.net/Articles/115405/ APIdocumentedintheLinuxKernelFilesystemAPI:
http://freeelectrons.com/kerneldoc/latest/DocBook/filesystems/index.html

128
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Simpledebugfsexample
#include<linux/debugfs.h> staticchar*acme_buf; staticunsignedlongacme_bufsize; staticstructdebugfs_blob_wrapperacme_blob; staticstructdentry*acme_buf_dentry; staticu32acme_state; staticstructdentry*acme_state_dentry; //modulebuffer

//modulevariable

/*Moduleinit*/ acme_blob.data=acme_buf; acme_blob.size=acme_bufsize; acme_buf_dentry=debugfs_create_blob("acme_buf",S_IRUGO, NULL,&acme_blob); acme_state_dentry=debugfs_create_bool("acme_state",S_IRUGO, NULL,&acme_state); /*Moduleexit*/ debugfs_remove(acme_buf_dentry); debugfs_remove(acme_state_dentry);

//Create //newfiles //indebugfs

//removingthefilesfromdebugfs

129
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Debuggingwithioctl
Canusetheioctl()systemcalltoqueryinformation aboutyourdriver(ordevice)orsendcommandstoit. Thiscallstheunlocked_ioctlfileoperationthatyoucan registerinyourdriver. Advantage:yourdebugginginterfaceisnotpublic. Youcouldevenleaveitwhenyoursystem(oritsdriver)isin thehandsofitsusers.

130
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

UsingMagicSysRq
Allowstorunmultipledebug/rescuecommandsevenwhenthe kernelseemstobeindeeptrouble OnPC:Alt+SysRq+<character> Onembedded:breakcharacterontheserialline+<character> .Examplecommands: n:makesRTprocessesniceable. t:showsthekernelstackofallsleepingprocesses w:showsthekernelstackofallrunningprocesses b:rebootthesystem Youcanevenregisteryourown! DetailedinDocumentation/sysrq.txt
131
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

kgdbAkerneldebugger
Theexecutionofthekernelisfullycontrolledbygdbfrom anothermachine,connectedthroughaserialline. Candoalmosteverything,includinginsertingbreakpointsin interrupthandlers. FeatureincludedinstandardLinuxsince2.6.26(x86and sparc).arm,mipsandppcsupportmergedin2.6.27.

132
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Usingkgdb
Detailsavailableinthekerneldocumentation: http://freeelectrons.com/kerneldoc/latest/DocBook/kgdb/ RecommendedtoturnonCONFIG_FRAME_POINTERtoaid inproducingmorereliablestackbacktracesingdb. YoumustincludeakgdbI/Odriver.Oneofthemiskgdb overserialconsole(kgdboc:kgdboverconsole,enabled byCONFIG_KGDB_SERIAL_CONSOLE) Configurekgdbocatboottimebypassingtothekernel: kgdboc=<ttydevice>,[baud].Forexample: kgdboc=ttyS0,115200

133
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Usingkgdb(2)
Thenalsopasskgdbwaittothekernel: itmakeskgdbwaitforadebuggerconnection. Bootyourkernel,andwhentheconsoleisinitialized,interruptthe kernelwith[Alt][SyrRq][g]. Onyourworkstation,startgdbasfollows: %gdb./vmlinux (gdb)setremotebaud115200 (gdb)targetremote/dev/ttyS0 Onceconnected,youcandebugakernelthewayyouwould debuganapplicationprogram.

134
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

DebuggingwithaJTAGinterface
TwotypesofJTAGdongles Thoseofferingagdbcompatibleinterface,overaserialportoranEthernet connexion.Gdbcandirectlyconnecttothem. Thosenotofferingagdbcompatibleinterfacearegenerallysupportedby OpenOCD(OpenOnChipDebugger) OpenOCDisthebridgebetweenthegdbdebugginglanguageandthe JTAGdonglespecificlanguage http://openocd.berlios.de/web/ Seetheverycompletedocumentation:http://openocd.berlios.de/doc/ Foreachboard,you'llneedanOpenOCDconfigurationfile(askyour supplier) SeeveryusefuldetailsonusingEclipse/gcc/gdb/OpenOCDonWindows: http://www2.amontec.com/sdk4arm/ext/jlynchtutorial20061124.pdfand http://www.yagarto.de/howto/yagarto2/
135
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Morekerneldebuggingtips
EnableCONFIG_KALLSYMS_ALL (GeneralSetup>Configurestandardkernelfeatures) togetoopsmessageswithsymbolnamesinsteadofrawaddresses (thisobsoletestheksymoopstool). Ifyourkerneldoesn'tbootyetorhangswithoutanymessage,youcan activateLowLeveldebugging(KernelHackingsection,onlyavailableon arm): CONFIG_DEBUG_LL=y TechniquestolocatetheCinstructionwhichcausedanoops: http://kerneltrap.org/node/3648 MoreaboutkerneldebugginginthefreeLinuxDeviceDriversbook: http://lwn.net/images/pdf/LDD3/ch04.pdf

136
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

TracingwithSystemTap
http://sourceware.org/systemtap/ Infrastructuretoaddinstrumentationtoarunningkernel: tracefunctions,readandwritevariables,followpointers,gatherstatistics... Eliminatestheneedtomodifythekernelsourcestoaddone'sown instrumentationtoinvestigatedafunctionalorperformanceproblem. Usesasimplescriptinglanguage. Severalexamplescriptsandprobepointsareavailable. BasedontheKprobesinstrumentationinfrastructure. SeeDocumentation/kprobes.txtinkernelsources. Linux2.6.26:supportedonmostpopularCPUs(armincludedin2.6.25). However,lackofrecentsupportformips(2.6.16only!).

137
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

SystemTapscriptexample(1)
#!/usr/bin/envstap #Usingstatisticsandmapstoexaminekernelmemoryallocations globalkmalloc probekernel.function("__kmalloc"){ kmalloc[execname()]<<<$size } #Exitafter10seconds probetimer.ms(10000){exit()} probeend{ foreach([name]inkmalloc){ printf("Allocationsfor%s\n",name) printf("Count:%dallocations\n",@count(kmalloc[name])) printf("Sum:%dKbytes\n",@sum(kmalloc[name])/1024) printf("Average:%dbytes\n",@avg(kmalloc[name])) printf("Min:%dbytes\n",@min(kmalloc[name])) printf("Max:%dbytes\n",@max(kmalloc[name])) print("\nAllocationsbysizeinbytes\n") print(@hist_log(kmalloc[name])) printf("\n\n"); } }

138
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

SystemTapscriptexample(2)
#!/usr/bin/envstap #Logseachfilereadperformedbyeachprocess probekernel.function("vfs_read") { dev_nr=$file>f_dentry>d_inode>i_sb>s_dev inode_nr=$file>f_dentry>d_inode>i_ino printf("%s(%d)%s0x%x/%d\n", execname(),pid(),probefunc(),dev_nr,inode_nr) }

Nicetutorialonhttp://sources.redhat.com/systemtap/tutorial.pdf

139
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Kernelcrashanalysiswithkexec/kdump
kexecsystemcall:makesitpossibleto callanewkernel,withoutrebootingand goingthroughtheBIOS/firmware. Idea:afterakernelpanic,makethe kernelautomaticallyexecuteanew, cleankernelfromareservedlocationin RAM,toperformpostmortemanalysis ofthememoryofthecrashedkernel. SeeDocumentation/kdump/kdump.txt inthekernelsourcesfordetails.
RegularRAM 1.Copydebug kernelto reserved RAM 3.Analyze crashed kernelRAM Standardkernel 2.kernel panic,kexec debugkernel Debugkernel

140
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Kernelmarkers
Capabilitytoaddstaticmarkerstokernelcode, mergedinLinux2.6.24byMatthieuDesnoyers. Almostnoimpactonperformance,untilthemarkerisdynamically enabled,byinsertingaprobekernelmodule. Usefultoinserttracepointsthatwon'tbeimpactedbychangesin theLinuxkernelsources. Seemarkerandprobeexample insamples/markersinthekernelsources. Seehttp://en.wikipedia.org/wiki/Kernel_marker

141
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

LTTng
http://lttng.org ThesuccessoroftheLinuxTraceToolkit(LTT) Toolkitallowingtocollectandanalyzetracinginformationfrom thekernel,basedonkernelmarkersandkerneltracepoints. Sofar,basedonkernelpatches,butdoingitsbesttouseintree solutions,andtobemergedinthefuture. Veryprecisetimestamps,verylittleoverhead. Usefuldocumentationonhttp://lttng.org/?q=node/2#manuals

142
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

LTTV
ViewerforLTTngtraces Supportforhugetraces(testedwith15GBones) Cancombinemultipletracefilesinasingleview. Graphicalortextinterface Seehttp://lttng.org/files/lttvdoc/user_guide/

143
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

PracticallabKerneldebugging
Loadabrokendriverandseeitcrash Analyzetheerrorinformation dumpedbythekernel. Disassemblethecodeandlocate theexactCinstructionwhichcaused thefailure. UsetheJTAGandOpenOCDto remotelycontrolthekernelexecution

144
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

EmbeddedLinuxdriverdevelopment

Driverdevelopment mmap

145
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

mmap(1)
Possibilitytohavepartsofthevirtualaddressspaceofaprogram mappedtothecontentsofafile!
>cat/proc/1/maps(initprocess) startend permoffsetmajor:minorinodemappedfilename 007710000077f000rxp0000000003:051165839/lib/libselinux.so.1 0077f00000781000rwp0000d00003:051165839/lib/libselinux.so.1 0097d00000992000rxp0000000003:051158767/lib/ld2.3.3.so 0099200000993000rp0001400003:051158767/lib/ld2.3.3.so 0099300000994000rwp0001500003:051158767/lib/ld2.3.3.so 0099600000aac000rxp0000000003:051158770/lib/tls/libc2.3.3.so 00aac00000aad000rp0011600003:051158770/lib/tls/libc2.3.3.so 00aad00000ab0000rwp0011700003:051158770/lib/tls/libc2.3.3.so 00ab000000ab2000rwp00ab000000:000 0804800008050000rxp0000000003:05571452/sbin/init(text) 0805000008051000rwp0000800003:05571452/sbin/init(data,stack) 08b4300008b64000rwp08b4300000:000 f6fdf000f6fe0000rwpf6fdf00000:000 fefd4000ff000000rwpfefd400000:000 ffffe000fffff000p0000000000:000

146
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

mmap(2)
Particularlyusefulwhenthefileisadevicefile! AllowstoaccessdeviceI/Omemoryandportswithouthavingto gothrough(expensive)read,writeorioctlcalls! Xserverexample(mapsexcerpt)
startend permoffsetmajor:minorinodemappedfilename 08047000081be000rxp0000000003:05310295/usr/X11R6/bin/Xorg 081be000081f0000rwp0017600003:05310295/usr/X11R6/bin/Xorg ... f4e08000f4f09000rwse000000003:05655295/dev/dri/card0 f4f09000f4f0b000rws4281a00003:05655295/dev/dri/card0 f4f0b000f6f0b000rwse800000003:05652822/dev/mem f6f0b000f6f8b000rwsfcff000003:05652822/dev/mem

Amoreuserfriendlywaytogetsuchinformation:pmap<pid>

147
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

mmapoverview
mmap system call(once)

Process
access virtual address

Devicedriver
mmapfopcalled initializesthemapping

MMU

access physical address

Processvirtualaddressspace

Physicaladdressspace

148
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

HowtoimplementmmapUserspace
Openthedevicefile Callthemmapsystemcall(seemanmmapfordetails): void*mmap( void*start, /*Often0,preferredstartingaddress*/ size_tlength, /*Lengthofthemappedarea*/ intprot, /*Permissions:read,write,execute*/ intflags, /*Options:sharedmapping,privatecopy... */ intfd, /*Openfiledescriptor*/ off_toffset /*Offsetinthefile*/ ); Yougetavirtualaddressyoucanwritetoorreadfrom.

149
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

HowtoimplementmmapKernelspace
Characterdriver:implementammapfileoperation andaddittothedriverfileoperations: int(*mmap)( structfile*, /*Openfilestructure*/ structvm_area_struct* /*KernelVMAstructure*/ ); Initializethemapping. Canbedoneinmostcaseswiththeremap_pfn_range() function,whichtakescareofmostofthejob.

150
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

remap_pfn_range()
pfn:pageframenumber Themostsignificantbitsofthepageaddress (withoutthebitscorrespondingtothepagesize). #include<linux/mm.h> intremap_pfn_range( structvm_area_struct*, /*VMAstruct*/ unsignedlongvirt_addr, /*Startinguservirtualaddress*/ unsignedlongpfn, /*pfnofthestartingphysicaladdress*/ unsignedlongsize, /*Mappingsize*/ pgprot_t /*Pagepermissions*/ );

151
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Simplemmapimplementation
staticintacme_mmap( structfile*file,structvm_area_struct*vma) { size=vma>vm_endvma>vm_start; if(size>ACME_SIZE) returnEINVAL; if(remap_pfn_range(vma, vma>vm_start, ACME_PHYS>>PAGE_SHIFT, size, vma>vm_page_prot)) returnEAGAIN; return0; }
152
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

devmem2
http://freeelectrons.com/pub/mirror/devmem2.c,byJanDerkBakker Veryusefultooltodirectlypeek(read)orpoke(write)I/Oaddresses mappedinphysicaladdressspacefromashellcommandline! Veryusefulforearlyinteractionexperimentswithadevice,without havingtocodeandcompileadriver. Usesmmapto/dev/mem. Examples(b:byte,h:half,w:word) devmem20x000c0004h(reading) devmem20x000c0008w0xffffffff(writing) devmemisnowavailableinBusyBox,makingiteveneasiertouse.

153
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

mmapsummary
Thedevicedriverisloaded. Itdefinesanmmapfileoperation. Auserspaceprocesscallsthemmapsystemcall. Themmapfileoperationiscalled. Itinitializesthemappingusingthedevicephysicaladdress. Theprocessgetsastartingaddresstoreadfromandwriteto (dependingonpermissions). TheMMUautomaticallytakescareofconvertingtheprocess virtualaddressesintophysicalones. Directaccesstothehardware! Noexpensivereadorwritesystemcalls!

154
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

EmbeddedLinuxdriverdevelopment

Driverdevelopment
Kernelarchitecturefordevicedrivers

155
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Kernelanddevicedrivers
Userspace Application

Systemcallinterface

Framework Kernel Driver

Businfrastructure

Hardware

156

FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Kernelanddevicedrivers
Manydevicedriversarenotimplementeddirectlyascharacter drivers Theyareimplementedunderaframework,specifictoagiven devicetype(framebuffer,V4L,serial,etc.)
Theframeworkallowstofactorizethecommonpartsofdriversfor thesametypeofdevices Fromuserspace,theyarestillseenascharacterdevicesbythe applications Theframeworkallowstoprovideacoherentuserspaceinterface (ioctl,etc.)foreverytypeofdevice,regardlessofthedriver

Thedevicedriversrelyonthebusinfrastructuretoenumerate thedevicesandcommunicatewiththem.
157
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

EmbeddedLinuxdriverdevelopment

Kernelframeworks

158
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Frameworks
Application Application Application

Systemcallinterface
Character driver Framebuffer core V4L core TTY core Block core

Framebuffer driver

V4L driver

TTY driver

Serial core

IDE core

SCSI core

Serial driver

IDE driver

USBstorage driver 159

FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Example:framebufferframework
KerneloptionCONFIG_FB
menuconfigFB tristate"Supportforframebufferdevices"

Implementedindrivers/video/
fb.c,fbmem.c,fbmon.c,fbcmap.c,fbsysfs.c, modedb.c,fbcvt.c

Implementsasinglecharacterdriveranddefinestheuser/kernel API
Firstpartofinclude/linux/fb.h

Definesthesetofoperationsaframebufferdrivermustimplement andhelperfunctionsforthedrivers
structfb_ops Secondpartofinclude/linux/fb.h (in#ifdef__KERNEL__)

160

FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Framebufferdriverskeleton
Skeletondriverindrivers/video/skeletonfb.c Implementsthesetofframebufferspecificoperationsdefined bythestructfb_opsstructure
xxxfb_open() xxxfb_read() xxxfb_write() xxxfb_release() xxxfb_checkvar() xxxfb_setpar() xxxfb_setcolreg() xxxfb_blank() xxxfb_pan_display()
161
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

xxxfb_fillrect() xxxfb_copyarea() xxxfb_imageblit() xxxfb_cursor() xxxfb_rotate() xxxfb_sync() xxxfb_ioctl() xxxfb_mmap()

Framebufferdriverskeleton
Aftertheimplementationoftheoperations,definitionofastruct fb_opsstructure
staticstructfb_opsxxxfb_ops={ .owner=THIS_MODULE, .fb_open=xxxfb_open, .fb_read=xxxfb_read, .fb_write=xxxfb_write, .fb_release=xxxfb_release, .fb_check_var=xxxfb_check_var, .fb_set_par=xxxfb_set_par, .fb_setcolreg=xxxfb_setcolreg, .fb_blank=xxxfb_blank, .fb_pan_display=xxxfb_pan_display, .fb_fillrect=xxxfb_fillrect,/*Needed!!!*/ .fb_copyarea=xxxfb_copyarea,/*Needed!!!*/ .fb_imageblit=xxxfb_imageblit,/*Needed!!!*/ .fb_cursor=xxxfb_cursor,/*Optional!!!*/ .fb_rotate=xxxfb_rotate, .fb_sync=xxxfb_sync, .fb_ioctl=xxxfb_ioctl, .fb_mmap=xxxfb_mmap, };

162
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Framebufferdriverskeleton
Intheprobe()function,registrationoftheframebufferdevice andoperations
staticint__devinitxxxfb_probe (structpci_dev*dev, conststructpci_device_id*ent) { structfb_info*info; [...] info=framebuffer_alloc(sizeof(structxxx_par),device); [...] info>fbops=&xxxfb_ops; [...] if(register_framebuffer(info)<0) returnEINVAL; [...] }

register_framebuffer()willcreatethecharacterdevice thatcanbeusedbyuserspaceapplicationwiththegeneric framebufferAPI


163
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

EmbeddedLinuxdriverdevelopment

DeviceModelandBusInfrastructure

164
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Unifieddevicemodel
Th2.6kernelincludedasignificantnewfeature:aunifieddevice model Insteadofhavingdifferentadhocmechanismsinthevarious subsystems,thedevicemodelunifiesthedescriptionofthe devicesandtheirtopology
Minimizationofcodeduplication Commonfacilities(referencecounting,eventnotification,power management,etc.) Enumeratethedevicesviewtheirinterconnections,linkthedevices totheirbusesanddrivers,etc.

Understandthedevicemodelisnecessarytounderstandhow devicedriversfitintotheLinuxkernelarchitecture.
165
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Busdrivers
Thefirstcomponentofthedevicemodelisthebusdriver
Onebusdriverforeachtypeofbus:USB,PCI,SPI,MMC,I2C,etc.

Itisresponsiblefor
Registeringthebustype(structbus_type) Allowingtheregistrationofadapterdrivers(USBcontrollers,I2C adapters,etc.),ableofdetectingtheconnecteddevices,and providingacommunicationmechanismwiththedevices Allowingtheregistrationofdevicedrivers(USBdevices,I2C devices,PCIdevices,etc.),managingthedevices Matchingthedevicedriversagainstthedevicesdetectedbythe adapterdrivers. ProvidesanAPItobothadapterdriversanddevicedrivers Definingdriveranddevicespecificstructure,typicallyxxx_driver andxxx_device 166
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Example:USBbus
USBcore
Registersthebus_typestructure

USBadapter driverA

USBadapter driverB

USBdevice driver1

USBdevice driver2

USBdevice driver3

DEV1 USB1 System USB2 DEV3 DEV4

DEV2

DEV5

167
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Example:USBbus(2)
Coreinfrastructure(busdriver)
drivers/usb/core Thebus_typeisdefinedindrivers/usb/core/driver.cand registeredindrivers/usb/core/usb.c

Adapterdrivers
drivers/usb/host ForEHCI,UHCI,OHCI,XHCI,andtheirimplementationsonvarious systems(Atmel,IXP,Xilinx,OMAP,Samsung,PXA,etc.)

Devicedrivers
Everywhereinthekerneltree,classifiedbytheirtype

168
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Exampleofdevicedriver
Toillustratehowdriversareimplementedtoworkwiththedevice model,wewillstudythesourcecodeofadriverforaUSB networkcard
ItisUSBdevice,soithastobeaUSBdevicedriver Itisanetworkdevice,soithastobeanetworkdevice Mostdriversrelyonabusinfrastructure(here,USB)andregister themselvesinaframework(here,network)

Wewillonlylookatthedevicedriverside,andnottheadapter driverside Thedriverwewilllookatisdrivers/net/usb/rtl8150.c

169
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Deviceidentifiers
Definesthesetofdevicesthatthisdrivercanmanage,sothatthe USBcoreknowsforwhichdevicesthisdrivershouldbeused TheMODULE_DEVICE_TABLEmacroallowsdepmodtoextractat compiletimetherelationbetweendeviceidentifiersanddrivers, sothatdriverscanbeloadedautomaticallybyudev.See /lib/modules/$(unamer)/modules.{alias,usbmap}
staticstructusb_device_idrtl8150_table[]={ {USB_DEVICE(VENDOR_ID_REALTEK,PRODUCT_ID_RTL8150) {USB_DEVICE(VENDOR_ID_MELCO,PRODUCT_ID_LUAKTX) {USB_DEVICE(VENDOR_ID_MICRONET,PRODUCT_ID_SP128AR) {USB_DEVICE(VENDOR_ID_LONGSHINE,PRODUCT_ID_LCS8138TX) {USB_DEVICE(VENDOR_ID_OQO,PRODUCT_ID_RTL8150) {USB_DEVICE(VENDOR_ID_ZYXEL,PRODUCT_ID_PRESTIGE) {} }; MODULE_DEVICE_TABLE(usb,rtl8150_table); 170
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

}, }, }, }, }, },

Instanciationofusb_driver
structusb_driverisastructuredefinedbytheUSBcore. EachUSBdevicedrivermustinstantiateit,andregisteritselfto theUSBcoreusingthisstructure Thisstructureinheritsfromstructdriver,whichisdefinedby thedevicemodel.
staticstructusb_driverrtl8150_driver={ .name ="rtl8150", .probe =rtl8150_probe, .disconnect =rtl8150_disconnect, .id_table =rtl8150_table, .suspend =rtl8150_suspend, .resume =rtl8150_resume };

171
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Driver(un)registration
Whenthedriverisloadedorunloaded,itmustregisteror unregisteritselffromtheUSBcore Doneusingusb_register()andusb_deregister(), providedbytheUSBcore.
staticint__initusb_rtl8150_init(void) { returnusb_register(&rtl8150_driver); } staticvoid__exitusb_rtl8150_exit(void) { usb_deregister(&rtl8150_driver); } module_init(usb_rtl8150_init); module_exit(usb_rtl8150_exit);

172
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Atinitialization
TheUSBadapterdriverthatcorrespondstotheUSBcontrollerof thesystemregistersitselftotheUSBcore Thertl8150USBdevicedriverregistersitselftotheUSBcore USBcore
usb_add_hcd() usb_register()

ohciat91

rtl8150

TheUSBcorenowknowstheassociationbetweenthe vendor/productIDsofrtl8150andtheusb_driverstructureof thisdriver

173

FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Whenadeviceisdetected
USBcore
Step2 IknowdevicesofIDX:Y, theycanbehandledby rtl8150 Step3 TheUSBcorecallsthe >probe()methodof theusb_driver structureregisteredby rtl8150
rtl8150

Step1 Ihavedetectedanew USBdeviceofIDX:Y

ohciat91

174
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Probemethod
Theprobe()methodreceivesasargumentastructure describingthedevice,usuallyspecializedbythebus infrastructure(pci_dev,usb_interface,etc.) Thisfunctionisresponsiblefor
Initializingthedevice,mappingI/Omemory,registeringthe interrupthandlers.Thebusinfrastructureprovidesmethodsto gettheaddresses,interruptsnumbersandotherdevice specificinformation. Registeringthedevicetotheproperkernelframework,for examplethenetworkinfrastructure.

175
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Probemethodexample
staticintrtl8150_probe( structusb_interface*intf, conststructusb_device_id*id) { rtl8150_t*dev; structnet_device*netdev; netdev=alloc_etherdev(sizeof(rtl8150_t)); [...] dev=netdev_priv(netdev); tasklet_init(&dev>tl,rx_fixup,(unsignedlong)dev); spin_lock_init(&dev>rx_pool_lock); [...] netdev>netdev_ops=&rtl8150_netdev_ops; alloc_all_urbs(dev); [...] usb_set_intfdata(intf,dev); SET_NETDEV_DEV(netdev,&intf>dev); register_netdev(netdev); return0; }
176
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Themodelisrecursive
ALSA Network stack
Chardriver infrastructure

Chardriver I2Cdevicedriver I2Ccore Networkdriver USBdevicedriver I2Cadapterdriver USBdevicedriver

System
PCIctrl Sounddevice USBctrl

USBcore ALSAdriver PCIdevicedriver USBadapterdriver PCIdevicedriver

I2Cctrl I2C thermometer

USB Netdevice

PCIcore PCIadapterdriver

177

FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

sysfs
Thebus,device,drivers,etc.structuresareinternaltothe kernel Thesysfsvirtualfilesystemoffersamechanismtoexportsuch informationtouserspace Usedforexamplebyudevtoprovideautomaticmoduleloading, firmwareloading,devicefilecreation,etc.
sysfsisusuallymountedin/sys /sys/bus/containsthelistofbuses /sys/devices/containsthelistofdevices
/sys/classenumeratesdevicesbyclass(net,input, block...),whateverthebustheyareconnectedto.Veryuseful!

Takeyourtimetoexplore/sysonyourworkstation.
178
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Platformdevices
Onembeddedsystems,devicesareoftennotconnected throughabusallowingenumeration,hotplugging,andproviding uniqueidentifiersfordevices. However,westillwantthedevicestobepartofthedevice model. Thesolutiontothisistheplatformdriver/platformdevice infrastructure. Theplatformdevicesarethedevicesthataredirectlyconnected totheCPU,withoutanykindofbus.

179
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Implementationoftheplatformdriver
Thedriverimplementsaplatform_driverstructure (exampletakenfromdrivers/serial/imx.c)
staticstructplatform_driverserial_imx_driver={ .probe=serial_imx_probe, .remove=serial_imx_remove, .driver={ .name="imxuart", .owner=THIS_MODULE, }, };

Andregistersitsdrivertotheplatformdriverinfrastructure
staticint__initimx_serial_init(void) { ret=platform_driver_register(&serial_imx_driver); } staticvoid__exitimx_serial_cleanup(void) { platform_driver_unregister(&serial_imx_driver); } 180
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Platformdeviceinstantiation(1)
Asplatformdevicescannotbedetecteddynamically,theyare definedstatically
Bydirectinstantiationofplatform_devicestructures,asdoneon ARM.DefinitiondoneintheboardspecificorSoCspecificcode. Byusingadevicetree,asdoneonPowerPC,fromwhich platform_devicestructuresarecreated

ExampleonARM,wheretheinstantiationisdonein arch/arm/machimx/mx1ads.c
staticstructplatform_deviceimx_uart1_device={ .name="imxuart", .id=0, .num_resources=ARRAY_SIZE(imx_uart1_resources), .resource=imx_uart1_resources, .dev={ .platform_data=&uart_pdata, } }; 181
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Platformdeviceinstantiation(2)
Thedeviceispartofalist
staticstructplatform_device*devices[]__initdata={ &cs89x0_device, &imx_uart1_device, &imx_uart2_device, };

Andthelistofdevicesisaddedtothesystem duringboardinitialization
staticvoid__initmx1ads_init(void) { [...] platform_add_devices(devices,ARRAY_SIZE(devices)); } MACHINE_START(MX1ADS,"FreescaleMX1ADS") [...] .init_machine=mx1ads_init, MACHINE_END 182
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Theresourcemechanism
Eachdevicemanagedbyaparticulardrivertypicallyuses differenthardwareresources:addressesfortheI/Oregisters, DMAchannels,IRQlines,etc. Theseinformationscanberepresentedusingthestruct resource,andanarrayofstructresourceisassociatedto aplatform_device Allowsadrivertobeinstantiatedformultipledevicesfunctioning similarly,butwithdifferentaddresses,IRQs,etc.
staticstructresourceimx_uart1_resources[]={ [0]={ .start=0x00206000, .end=0x002060FF, .flags=IORESOURCE_MEM, }, [1]={ .start=(UART1_MINT_RX), .end=(UART1_MINT_RX), .flags=IORESOURCE_IRQ, }, };

183

FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Usingresources
Whenaplatform_deviceisaddedtothesystemusing platform_add_device(),theprobe()methodoftheplatform drivergetscalled Thismethodisresponsibleforinitializingthehardware, registeringthedevicetotheproperframework(inourcase,the serialdriverframework) TheplatformdriverhasaccesstotheI/Oresources:
res=platform_get_resource(pdev,IORESOURCE_MEM,0); base=ioremap(res>start,PAGE_SIZE); sport>rxirq=platform_get_irq(pdev,0);

184
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

platform_datamechanism
Inadditiontothewelldefinedresources,manydriversrequire driverspecificinformationsforeachplatformdevice Theseinformationscanbepassedusingtheplatform_data fieldofthestructdevice(fromwhichstruct platform_deviceinherits) Asitisavoid*pointer,itcanbeusedtopassanytypeof information.
Typically,eachdriverdefinesastructuretopassinformation throughplatform_data

185
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

platform_dataexample(1)
Thei.MXserialportdriverdefinesthefollowingstructuretobe passedthroughplatform_data
structimxuart_platform_data{ int(*init)(structplatform_device*pdev); void(*exit)(structplatform_device*pdev); unsignedintflags; void(*irda_enable)(intenable); unsignedintirda_inv_rx:1; unsignedintirda_inv_tx:1; unsignedshorttransceiver_delay; };

TheMX1ADSboardcodeinstantiatessuchastructure
staticstructimxuart_platform_datauart1_pdata={ .flags=IMXUART_HAVE_RTSCTS, };

186
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

platform_dataexample(2)
Theuart_pdatastructureisassociatedtotheplatform_devicein theMX1ADSboardfile(therealcodeisslightlymore complicated)
structplatform_devicemx1ads_uart1={ .name=imxuart, .dev{ .platform_data=&uart1_pdata, }, .resource=imx_uart1_resources,
[]

};

Thedrivercanaccesstheplatformdata:
staticintserial_imx_probe(structplatform_device*pdev) { structimxuart_platform_data*pdata; pdata=pdev>dev.platform_data; if(pdata&&(pdata>flags&IMXUART_HAVE_RTSCTS)) sport>have_rtscts=1; [] } 187
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Driverspecificdatastructure
Eachframeworkdefinesastructurethatadevicedrivermust registertoberecognizedasadeviceinthisframework
uart_portforserialport,netdevfornetworkdevices,fb_infofor framebuffers,etc.

Inadditiontothisstructure,thedriverusuallyneedstostore additionalinformationsaboutitsdevice Thisistypicallydone


Bysubclassingtheframeworkstructure Orbystoringareferencetotheframeworkstructure

188
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Driverspecificdatastructureexamples
i.MXserialdriver:imx_portisasubclassofuart_port
structimx_port{ structuart_portport; structtimer_listtimer; unsignedintold_status; inttxirq,rxirq,rtsirq; unsignedinthave_rtscts:1; [] };

rtl8150networkdriver:rtl8150hasareferencetonet_device
structrtl8150{ unsignedlong flags; structusb_device *udev; structtasklet_structtl; structnet_device *netdev; [] };

189
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Linkbetweenstructures(1)
Theframeworktypicallycontainsastructdevice* pointerthatthedrivermustpointtothecorrespondingstruct device
It'stherelationbetweenthelogicaldevice(forexampleanetwork interface)andthephysicaldevice(forexampletheUSBnetwork adapter)

Thedevicestructurealsocontainsavoid*pointerthatthe drivercanfreelyuse.
It'softenusetolinkbackthedevicetothehigherlevelstructure fromtheframework. Itallows,forexample,fromtheplatform_devicestructure,to findthestructuredescribingthelogicaldevice

190
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Linkbetweenstructures(2)
staticintserial_imx_probe(structplatform_device*pdev) { structimx_port*sport; [] /*setupthelinkbetweenuart_portandthestruct deviceinsidetheplatform_device*/ sport>port.dev=&pdev>dev; [] /*setupthelinkbetweenthestructdeviceinside theplatformdevicetotheimx_portstructure*/ platform_set_drvdata(pdev,&sport>port); [] uart_add_one_port(&imx_reg,&sport>port); } staticintserial_imx_remove(structplatform_device*pdev) { /*retrivetheimx_portfromtheplatform_device*/ structimx_port*sport=platform_get_drvdata(pdev); [] uart_remove_one_port(&imx_reg,&sport>port); [] }

imx_port uart_port
structdevice*

platform_device device
void*driver_data

191
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Linkbetweenstructures(3)
staticintrtl8150_probe(structusb_interface*intf, conststructusb_device_id*id) { rtl8150_t*dev; structnet_device*netdev; netdev=alloc_etherdev(sizeof(rtl8150_t)); dev=netdev_priv(netdev); usb_set_intfdata(intf,dev); SET_NETDEV_DEV(netdev,&intf>dev); [] } staticvoidrtl8150_disconnect(structusb_interface*intf) { rtl8150_t*dev=usb_get_intfdata(intf); [] }

rtl8150_t
netdev

netdev
dev

usb_interface device
void*driver_data

192
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Exampleofanothernondynamicbus:SPI
SPIiscallednondynamicasitdoesn'tsupportruntimeenumerationof devices:thesystemneedstoknowwhichdevicesareonwhichSPI bus,andatwhichlocation TheSPIinfrastructureinthekernelisindrivers/spi
drivers/spi/spi.cisthecore,whichimplementsthestruct bus_typeforspi
Itallowsregistrationofadapterdriversusingspi_register_master(),and registrationofdevicedriversusingspi_register_driver()

drivers/spi/containsmanyadapterdrivers,forvarious platforms:Atmel,OMAP,Xilinx,Samsung,etc.
Mostofthemareplatform_driversorof_platform_drivers,one pci_driver,oneamba_driver,onepartport_driver

drivers/spi/spidev.cprovidesaninfrastructuretoaccessSPI busfromuserspace SPIdevicedriversarepresentalloverthekerneltree


193
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

SPIcomponents
RTC framework MTD framework GPIO framework CAN framework chardriver framework

Kernelframeworks
rtcds1305.c m25p80.c drivers/rtc drivers/mtd/devices MTDdriver RTCdriver spi_driver spi_driver mc33880.c drivers/gpio GPIOdriver spi_driver mcp251x.c drivers/net/can CANdriver spi_driver spidev.c drivers/spi chardriver spi_driver

SPIdevicedrivers

SPIcore drivers/spi/spi.c
atmel_spi.c drivers/spi SPIadapterdriver platform_driver ambapl022.c drivers/spi SPIadapterdriver amba_driver mpc52xx_spi.c drivers/spi SPIadapterdriver of_platform_driver spi_imx.c drivers/spi SPIadapterdriver platform_driver

SPIadapterdrivers
194
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

SPIAT91SoCcode
staticstructresourcespi0_resources[]={ [0]={ .start=AT91SAM9260_BASE_SPI0, .end=AT91SAM9260_BASE_SPI0+SZ_16K1, .flags=IORESOURCE_MEM, }, [1]={ .start=AT91SAM9260_ID_SPI0, .end=AT91SAM9260_ID_SPI0, .flags=IORESOURCE_IRQ, }, }; staticstructplatform_deviceat91sam9260_spi0_device={ .name="atmel_spi", .id=0, .dev={ .dma_mask=&spi_dmamask, .coherent_dma_mask=DMA_BIT_MASK(32), }, .resource=spi0_resources, .num_resources=ARRAY_SIZE(spi0_resources), };

arch/arm/machat91/at91sam9260_devices.c
195
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

SPIAT91SoCcode(2)
RegistrationofSPIdeviceswithspi_register_board_info(),registrationofSPI adapterwithplatform_device_register()
void__initat91_add_device_spi(structspi_board_info*devices, intnr_devices) { [] spi_register_board_info(devices,nr_devices); /*ConfigureSPIbus(es)*/ if(enable_spi0){ at91_set_A_periph(AT91_PIN_PA0,0);/*SPI0_MISO*/ at91_set_A_periph(AT91_PIN_PA1,0);/*SPI0_MOSI*/ at91_set_A_periph(AT91_PIN_PA2,0);/*SPI1_SPCK*/ at91_clock_associate("spi0_clk",&at91sam9260_spi0_device.dev, "spi_clk"); platform_device_register(&at91sam9260_spi0_device); } [] }

arch/arm/machat91/at91sam9260_devices.c
196
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

AT91RM9200DKboardcodeforSPI
Onespi_board_infostructureforeachSPIdeviceconnectedtothesystem.
staticstructspi_board_infodk_spi_devices[]={ {/*DataFlashchip*/ .modalias="mtd_dataflash", .chip_select=0, .max_speed_hz=15*1000*1000, }, {/*UR6HCPS2SP40PS2toSPIadapter*/ .modalias="ur6hcps2", .chip_select=1, .max_speed_hz=250*1000, }, [] }; staticvoid__initdk_board_init(void) { [] at91_add_device_spi(dk_spi_devices,ARRAY_SIZE(dk_spi_devices)); [] }

arch/arm/machat91/boarddk.c
197
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

References
Kerneldocumentation Documentation/drivermodel/ Documentation/filesystems/sysfs.txt Linux2.6DeviceModel http://www.bravegnu.org/devicemodel/devicemodel.html LinuxDeviceDrivers,chapter14TheLinuxDeviceModel http://lwn.net/images/pdf/LDD3/ch14.pdf Thekernelsourcecode Fullofexamplesofotherdrivers!

198
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com

Relateddocuments

Allourtechnicalpresentations onhttp://freeelectrons.com/docs Linuxkernel Devicedrivers Architecturespecifics EmbeddedLinuxsystemdevelopment


FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http//freeelectrons.com

Howtohelp
Youcanhelpustoimproveandmaintainthisdocument... Bysendingcorrections,suggestions,contributionsand translations Byaskingyourorganizationtoorderdevelopment,consulting andtrainingservicesperformedbytheauthorsofthese documents(seehttp://freeelectrons.com/). Bysharingthisdocumentwithyourfriends,colleagues andwiththelocalFreeSoftwarecommunity. Byaddinglinksonyourwebsitetoouronlinematerials, toincreasetheirvisibilityinsearchengineresults.

FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http//freeelectrons.com

Linuxkernel Linuxdevicedrivers Boardsupportcode Mainstreamingkernelcode Kerneldebugging EmbeddedLinuxTraining Allmaterialsreleasedwithafreelicense! UnixandGNU/Linuxbasics Linuxkernelanddriversdevelopment RealtimeLinux,uClinux Developmentandprofilingtools Lightweighttoolsforembeddedsystems Rootfilesystemcreation Audioandmultimedia Systemoptimization

FreeElectrons
Ourservices
CustomDevelopment Systemintegration EmbeddedLinuxdemosandprototypes Systemoptimization Applicationandinterfacedevelopment Consultingandtechnicalsupport Helpindecisionmaking Systemarchitecture Systemdesignandperformancereview Developmenttoolandapplicationsupport Investigatingissuesandfixingtoolbugs

Você também pode gostar