Escolar Documentos
Profissional Documentos
Cultura Documentos
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");
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);
NOK OK OK OK
nonGPLmoduleB
func1(); func2(); func3(); func4(); NOK OK NOK NOK
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()
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)
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
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
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);
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
Process1
0x00000000
0x00000000
Flash
MMU
CPU
0xFFFFFFFF
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
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);
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
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 ...
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 ...
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
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)
62
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com
write()
ssize_tfoo_write( structfile*f, __userconstchar*buf, size_tsz,loff_t*off)
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
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,®); 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()
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
88
FreeElectrons.Kernel,driversandembeddedLinuxdevelopment,consulting,trainingandsupport.http://freeelectrons.com
Executionofsystemcalls
Theexecutionofsystemcallstakesplaceinthe contextofthethreadrequestingthem.
Processcontinuinginuserspace... (orreplacedbyahigherpriorityprocess) (canbepreempted)
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.
...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
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
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)
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
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
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?
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!
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);
//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
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
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
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
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; [...] }
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
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)
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
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
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
System
PCIctrl Sounddevice USBctrl
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.
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
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
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