  Linux I/O port programmering mini-HOWTO
  Av: Riku Saikkonen <Riku.Saikkonen@hut.fi> versttning till
  svenska: Sven Wilhelmsson, <sven.wilhelmsson@swipnet.se>
  v  ,28 December 1997 , versatt: 10 Augusti 1998

  I detta HOWTO dokument beskrivs hur man programmerar I/O portar samt
  hur man frdrjer eller mter korta tidsintervall i user-mode Linux
  program fr Intel x86 arkitekturen.
  ______________________________________________________________________

  Innehllsfrteckning


  1. Inledning

  2. Att anvnda I/O portar i C-program

     2.1 Det vanliga sttet
     2.2 En alternativ metod:

  3. Avbrott (IRQs) och DMA

  4. Hgupplsande timing

     4.1 Frdrjningar
        4.1.1 (TT
        4.1.2 nanosleep()
        4.1.3 Frdrjningar med port I/O
        4.1.4 Att frdrja med assemblerinstruktioner
        4.1.5 rdtsc() fr Pentium
     4.2 Att mta tid

  5. Andra programmeringssprk

  6. Ngra anvndbara portar

     6.1 Parallellporten
     6.2 Spelporten (joystick)
     6.3 Serieporten

  7. Tips

  8. Felskning

  9. Kod exempel

  10. Erknnande



  ______________________________________________________________________

  1.  Inledning


  I detta HOWTO dokument beskrivs hur man nr I/O-portar och hur man
  frdrjer korta tidsintervall i user-mode Linux program som krs p
  Intel x86 arkitekturen. Detta dokumentet r en uppfljare till den
  mycket lilla IO-Port mini-HOWTO frn samma frfattare.

  This document is Copyright 1995-1997 Riku Saikkonen. See the Linux
  HOWTO copyright
  <http://sunsite.unc.edu/pub/Linux/docs/HOWTO/COPYRIGHT> for details.

  If you have corrections or something to add, feel free to e-mail me
  (Riku.Saikkonen@hut.fi)...
  ndringar frn tidigare publicerad version (Mar 30 1997):

    Frklaringar angende inb_p/outb_p/ och port 0x80.

    Tagit bort information om  udelay(), eftersom nanosleep() medger
     ett renare stt att gra samma sak.

    Konverterat till Linuxdoc-SGML, och ndrat om ngot.

    Mnga mindre tillgg och ndringar.



  2.  Att anvnda I/O portar i C-program

  2.1.  Det vanliga sttet

  Rutiner fr att n I/O-portar finns i/usr/include/asm/io.h (eller
  linux/include/asm-i386/io.h i 'the kernel source distribution').
  Rutinerna dr r inline makron, s det rcker att gra #include
  <asm/io.h>, inga ytterligare bibliotek behvs.

  Beroende p brister i gcc (tminstone i 2.7.2.3 och lgre) och i egcs
  (alla versioner), mste du kompilera kllkod som anvnder dessa
  rutiner med optimeringsflaggan p (gcc -O1 eller hgre), eller
  alternativt #define extern till ingenting, (dvs. #define extern p en
  i vrigt blank rad) innan du gr #include <asm/io.h>.

  Om du vill avlusa, 'debug', kan du anvnda gcc -g -O (tminstone med
  moderna versioner av gcc), ven om optimeringen ibland gr att
  debuggern beter sig lite underligt. Om detta besvrar dig, kan du
  lgga de rutiner som anropar I/O-portarna i separata filer och
  kompilera endast dem med optimeringsflaggan p.

  Innan du anropar en port, mste du ge ditt program tillstnd till
  detta.  Detta gr man genom att anropa ioperm() funktionen (som finns
  deklarerad i unistd.h, och definierad i 'kernel') ngonstans i brjan
  av ditt program, innan ngon I/O-port anropas. Syntaxen r
  ioperm(from, num, turn_on), dr from r den frsta portadressen som
  ska ges tillstnd och num r antalet konsekutiva adresser. Till
  exempel, ioperm(0x300, 5, 1) ger tillstnd till portarna  0x300 till
  0x304 (totalt 5 portar). Det sista argumentet r en bool som
  specificerar om du vill ge accesstillstnd (true(1)) eller ta bort
  tillstndet (false(0)). Du kan anvnda ioperm() upprepade gnger fr
  att ge tillstnd till ickekonsekutiva portadresser. Se ioperm(2)
  manualen.

   ioperm() anropet krver att ditt program har rootprivilegier. Det
  krvs att du antingen kr som root, eller gr setuid root.  Du kan
  slppa rootprivilegierna s snart du har anropat ioperm(). Det r inte
  ndvndigt att explicit slppa dina accessrttigheter med ioperm(...,
  0) mot slutet av ditt program. Detta sker automatiskt nr processen
  avslutas.

  Om du gr setuid() till en non-root user frstrs inte de
  accessrttigheter som r redan givna av ioperm(), men fork() frstr
  dem (child processen fr inga rttigheter, men parent behller dem).

  ioperm() kan endast ge access rttigheter till portarna 0x000 - 0x3ff.
  Fr att komma t hgre portadresser, kan man anvnda iopl(), som ger
  access till alla portar p en gng. Anvnd niv 3 (dvs iopl(3)) fr
  att ge ditt program tillgng till alla portar. (Men var frsiktig -
  att skriva p fel port kan orsaka allehanda otrevliga saker med din
  dator).  Du behver rootprivilegier fr att anropa  iopl().  Se
  iopl(2) manualen.

  Sedan, fr att komma t portarna... Fr att lsa in en byte, (8 bitar)
  frn en port, call inb(port), den returnerar den byte den lser. Fr
  att stlla ut, call outb(value,port) (notera parameterordningen).  Fr
  att lsa in 16 bitar frn port x och x+1 ,en byte frn vardera, call
  inw(x) och fr att stlla ut, call outw(value,x). r du osker p om
  du skall anvnda byte eller word instruktioner, r det troligen inb()
  och outb() - flertalet apparater konstrueras fr bytevis portaccess.
  Notera att alla portaccesser tar tminstone cirka en mikrosekund att
  utfra.

  Fr vrigt fungerar makroanropen inb_p(), outb_p(), inw_p(), och
  outw_p() p samma stt som ovannmnda, frutom att de lgger till ca
  en mikrosekund efter varje portaccess. Du kan gra frdrjningen nnu
  lngre, ca 4 mikrosekunder, med #define REALLY_SLOW_IO innan du gr
  #include <asm/io.h>. Dessa makron gr normalt (svida du inte gr
  #define SLOW_IO_BY_JUMPING, vilket blir mindre noggrant) access till
  port 0x80 fr att skapa delay, s du behver frst ge accessrtt till
  port 0x80 med ioperm(). (Skrivning p port 0x80 pverkar ingenting).
  Fr mer flexibla delay-metoder, ls vidare.

  Det finns sidor till ioperm(2), iopl(2) och ovannmnda makron i
  ngorlunda frska utgvor av Linux manual.



  2.2.  En alternativ metod: /dev/port


  Ett annat stt att komma t I/O-portar r open() /dev/port (en
  'character device', major number 1, minor 4) fr lsning och/eller
  skrivning (stdio f*() funktionerna har intern buffring, s anvnd inte
  dem). Gr sedan  lseek() till den aktuella byten i filen (fil position
  0 = port 0x00, fil position 1 = 0x01, och s vidare), och read() eller
  write()  en byte eller ett ord till eller frn den.

  Naturligtvis behver ditt program accessrttigheter till /dev/port fr
  att metoden skall fungera. Denna metod r sannolikt lngsammare n den
  normala metoden enligt ovan, men behver varken optimeringsflaggan vid
  kompilering eller ioperm(). Det behvs inte heller 'root access', bara
  du ger 'non-root user' eller 'group' access till /dev/port - lt vara
  att detta r dumt ur systemskerhetssynpunkt, eftersom det r mjligt
  att skada systemet, kanske till och med vinna 'root access', genom att
  anvnda /dev/port fr att komma t hrddisk, ntverkskort, etc.
  direkt.



  3.  Avbrott (IRQs) och DMA


  Man kan inte anvnda  IRQ eller DMA direkt i en usermode process.  Man
  mste skriva en kernel driver; se The Linux Kernel Hacker's Guide
  <http://www.redhat.com:8080/HyperNews/get/khg.html> Dr finns detaljer
  och kernel kllkod som exempel.  Man kan heller inte stnga av ett
  avbrott frn ett user-mode program.



  4.  Hgupplsande timing

  4.1.  Frdrjningar


  Frst och frmst mste sgas att det inte gr att garantera user mode
  processer exakt kontroll avseende timing eftersom Linux r ett
  multiprocess system. Din  process kan bli utskyfflad under vad som
  helst mellan 10 millisekunder upp till ngra sekunder (om belastningen
  r hg).  Detta spelar emellertid ingen roll fr flertalet program som
  anvnder I/O-portar. Fr att reducera effekterna, kan du med hjlp av
  kommandot nice ge din process hg prioritet. Se nice(2) manualen eller
  anvnd real-time scheduling enligt nedan.

  Om du behver bttre tidsprecision n vad normala user-mode processer
  kan ge, s finns vissa frberedelser fr 'user-mode real time'
  support.  Linux 2.x krnor har 'soft real time support', se manualen
  fr sched_setscheduler(2). Det finns en speciell krna som stder hrd
  realtid, se  <http://luz.cs.nmt.edu/~rtlinux/> fr ytterligare
  information om detta.




  4.1.1.  sleep()  och usleep()


  Lt oss brja med de ltta funktionsanropen. Fr att frdrja flera
  sekunder, r det troligtvis bst att anvnda sleep(). Frdrjningar p
  10-tals millisekunder (ca 10 ms verkar vara minimum) grs med
  usleep().  Dessa funktioner frigr CPU fr andra processer, s att
  ingen CPU-tid gr frlorad. Se manualerna  sleep(3) och usleep(3).


  Om frdrjningar r p mindre n 50 ms ( beror p din processor och
  dess belastning), tar det ondigt mycket tid att slppa CPUn, drfr
  att det fr Linux scheduler (fr x86 arkitekturen) vanligtvis tar
  minst 10-30 millisekunder innan den terger din process kontrollen.
  Beroende p detta frdrjer usleep(3) ngot mer n vad du specificerar
  i dina parametrar, och alltid minst ca 10 ms.





  4.1.2.  nanosleep()


  I 2.0.x serien av Linuxkrnor finns ett nytt systemanrop: nanosleep()
  (se nanosleep(2) manualen), som mjliggr s korta frdrjningar som
  ett par mikrosekunder eller mer.

  Vid frdrjningar p mindre n 2 ms, om (och endast om) din process r
  satt till soft real time scheduling (med sched_setscheduler()),
  anvnder nanosleep() en vnteloop, i annat fall frigrs CPU p samma
  stt som med usleep().

  Vnteloopen anvnder udelay() (en intern kernelfunktion som anvnds av
  mnga 'kernel drivers'), och loopens lngd berknas med hjlp av
  BogoMips vrdet (det r bara denna sorts hastighet BogoMips vrdet
  mter noggrant).  Se hur det fungerar i  /usr/include/asm/delay.h


  4.1.3.  Frdrjningar med port I/O


  Ett annat stt att frdrja ett ftal mikrosekunder r att anvnda
  port I/O.  Lsning eller skrivning p port 0x80 (se ovan hur man gr)
  tar nstan precis 1 mikrosekund oberoende av processortyp och
  hastighet. Du kan gra det upprepade gnger om du vill vnta ett antal
  mikrosekunder. Skrivning p denna port torde inte ha ngra skadliga
  sidoeffekter p ngon standardmaskin och vissa 'kerneldrivers'
  anvnder denna metod.  det r p detta sttet {in|out}[bw]_p()
  normalt gr sin frdrjning.  (se asmio.h)/.
  Flertalet port I/O instruktioner i adressomrdet 0-0x3ff tar nstan
  exakt 1 mikrosekund, s om du t.ex. anvnder parallellporten direkt,
  gr bara ngra extra inb() frn porten fr att skapa frdrjning.




  4.1.4.  Att frdrja med assemblerinstruktioner


  Om man knner till processortyp och klockhastighet, kan man hrdkoda
  korta frdrjningar med vissa assemblerinstruktioner (men kom ihg,
  processen kan skyfflas ut nr som helst, s frdrjningarna kan ibland
  bli lngre).  Tabellen nedan ger ngra exempel. Fr en 50MHz processor
  tar en klockcykel 20 ns.




       Instruktion   i386 klock cykler   i486 klock cykler
       nop                   3                   1
       xchg %ax,%ax          3                   3
       or %ax,%ax            2                   1
       mov %ax,%ax           2                   1
       add %ax,0             2                   1




  tyvrr knner jag inte till Pentium; frmodligen nra i486.  Jag
  hittar ingen instruktion som tar EN klockcykel i i386.  Anvnd en-
  cykel instruktioner om du kan, annars kanske pipelinen i moderna
  processortyper frkortar tiden.


  Instruktionerna nop och xchg i tabellen br inte ha ngra
  sidoeffekter. vriga modifierar statusregistret, men det br inte
  betyda ngot eftersom gcc detekterar detta. nop r ett bra val.

  Om du vill anvnda dem, skriv call asm("instruktion") i ditt program.
  Syntaxen ge i tabellen ovan. Vill du gra multipla instruktioner i en
  asm()-sats, s separera med semikolon. Till exempel exekveras i satsen
  asm(" nop; nop; nop; nop") fyra nop instruktioner, som frdrjer fyra
  klockcykler med i486 eller pentium (eller 12 cykler med i386).

  asm() verstts av gcc till inline assembler kod, s det blir inget
  overhead med funktionsanrop.

  Kortare frdrjningar n en klockcykel r inte mjligt med x86
  arkitekturen.



  4.1.5.  rdtsc() fr Pentium

  Med Pentium kan du erhlla antalet klockcykler som gtt sedan senaste
  uppstart med hjlp av fljande C kod:









  ______________________________________________________________________
     extern __inline__ unsigned long long int rdtsc()
     {
       unsigned long long int x;
       __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x));
       return x;
     }
  ______________________________________________________________________




  Du kan polla vrdet fr hur mnga cykler som helst.


  4.2.  Att mta tid


  Fr att mta tider med en sekunds upplsning, r det nog enklast att
  anvnda time(). Krvs bttre noggrannhet, ger gettimeofday() cirka en
  mikrosekunds upplsning (men se ovan angende 'scheduling',
  utskyffling). Fr Pentium r rdtsc kodfragmentet ovan noggrant till en
  klockcykel.

  Om din process skall ha en signal efter en viss tid, s anvnd
  setitimer() eller alarm(). Se manualsidorna.


  5.  Andra programmeringssprk


  Beskrivningen ovan koncentrerar sig p programmeringssprket C.  Det
  br vara tillmpbart ven p C++ och Objective C. I assembler fr man
  anropa  ioperm() eller iopl() som i C, och drefter kan man anvnda
  I/O-port read/write  instruktionerna direkt.

  I andra sprk, svida inte du kan infoga inline assembler eller C kod
  i ditt program eller anvnda ovannmnda systemanrop, r det nog
  enklast att skriva en C kllkodsfil med funktionerna fr I/O-
  portaccess och separatkompilera och lnka den till vriga delar av
  ditt program.  Eller anvnda  /dev/port enligt ovan.



  6.  Ngra anvndbara portar

  Hr fljer programmeringsinformation om ngra portar som direkt kan
  anvndas fr TTL (eller CMOS) digitala kretsar.

  Om du vill anvnda dessa eller andra gngse portar fr det ndaml de
  r gnade (t.ex. fr att styra en printer eller modem), skall du
  troligen anvnda en befintlig drivrutin (vanligtvis inkluderad i
  krnan) i stllet fr att programmera dessa portar direkt som beskrivs
  i detta HOWTO. Denna sektion r avsedd fr dem som vill ansluta LCD-
  displayer, stegmotorer, eller annan speciell elektronik till en PC's
  standardport.


  Ska du styra en massproducerad produkt som t.ex. scanner (som har
  funnits p marknaden ett tag), sk efter en befintlig drivrutin.
  Hardware-HOWTO <http://sunsite.unc.edu/pub/Linux/docs/HOWTO/Hardware-
  HOWTO> r ett bra stlle att brja.

  <http://www.hut.fi/Misc/Electronics/> r en annan bra klla till
  information om hur man ansluter utrustning till datorer, och om
  elektronik i allmnhet.
  6.1.  Parallellporten


  Parallellportens basadress (kallad ''BASE'' nedan) r 0x3bc fr
  /dev/lp0, 0x378 fr /dev/lp1, och 0x278 fr /dev/lp2. Ska du styra
  ngot som beter sig som en normal printer, se Printing-HOWTO
  <http://sunsite.unc.edu/pub/Linux/docs/HOWTO/Printing-HOWTO>.


  Frutom den vanliga output-only moden som beskrivs nedan, finns det en
  'extended' bidirektionell mod i flertalet parallellportar.
  Information om detta och om de nyare  ECP/EPP moderna (och om IEEE
  1284 standarden allmnt), se  <http://www.fapo.com/> och
  <http://www.senet.com.au/~cpeacock/parallel.htm>.  Kom ihg att
  eftersom du inte kan anvnda IRQs eller DMA i ett user-mode program,
  s kommer du nog att behva skriva en 'kernel-driver' fr att anvnda
  ECP/EPP. Jag tror att ngon hller p att skriva en sdan driver men
  jag knner inte till ngra detaljer.


  Porten  BASE+0 (Data port) styr data signalerna (D0 till D7 fr
  bitarna 0 to 7, respektive; tillstnden: 0 = lg (0 V), 1 = hg (5
  V)). Skrivning p denna port stller ut data till donet. En lsning
  returnerar senast skrivna data i standard- eller extended-moden, eller
  data p stiften frn en ansluten apparat i 'extended read mode'.


  Portarna BASE+1 ('Status port') r 'read-only', och returnerar
  tillstndet p fljande insignaler:

    Bits 0 och 1 r reserverade.

    Bit 2 IRQ status (inget stift, vet inte hur detta fungerar)

    Bit 3 ERROR (1=hg)

    Bit 4 SLCT (1=hg)

    Bit 5 PE (1=hg)

    Bit 6 ACK (1=hg)

    Bit 7 -BUSY (0=hg)

     (Vet inte vilka spnningar som motsvarar hg respektive lg.)

  Porten BASE+2 ('Control port') r 'write-only' (lsning returnerar
  senast inskrivna data), och styr fljande status signaler:

    Bit 0 -STROBE (0=hg)

    Bit 1 AUTO_FD_XT (1=hg)

    Bit 2 -INIT (0=hg)

    Bit 3 SLCT_IN (1=hg)

    Bit 4 aktiverar ('enables') parallell portens IRQ (vilket sker p
     uppflanken hos ACK) nr den stts till 1.

    Bit 5 styr 'extended mode direction' (0 = skriv, 1 = ls), den r
     'write-only' (lsning p denna bit returnerar ingenting
     meningsfullt).

    Bits 6 och 7 r reserverade.

     (terigen, r inte sker p vad som r hg och lg.)

  Pinout (ett 25-pin D-don , hona ) (i=input, o=output):


       1io -STROBE, 2io D0, 3io D1, 4io D2, 5io D3, 6io D4, 7io D5, 8io D6,
       9io D7, 10i ACK, 11i -BUSY, 12i PE, 13i SLCT, 14o AUTO_FD_XT,
       15i ERROR, 16o -INIT, 17o SLCT_IN, 18-25 Ground




  IBM specifikationen sger att stiften 1, 14, 16, och 17 ('control-
  outputs') har 'open-collektor' utgngar dragna till 5 V genom ett 4.7
  K motstnd (snker 20 mA, ger 0.55 mA, hgniv utgng 5.0 V minus
  eventuellt spnningsfall). vriga stift snker 24 mA och ger 15 mA,
  och deras hgniv spnning r minst 2.4 V. Lgniv spnningen r i
  bda fallen minst 0.5 V.  Icke-IBM parallell portar avviker troligen
  frn denna standard.  Fr ytterligare information om detta se
  <http://www.hut.fi/Misc/Electronics/circuits/lptpower.html>.


  Slutligen en varning: Var noga med jordningen. Jag har frstrt flera
  parallellportar genom att ansluta dem  med datorn igng. Det kan vara
  ett bra alternativ att anvnda parallellportar som inte sitter p
  moderkortet fr sdana hr saker. (Du kan antagligen f en andra
  parallellport med ett billigt standard 'multi-I/O' kort; Stng bara av
  de portar du inte behver, och stt parallellkortets I/O-adress till
  en ledig adress. Du behver inte bekymra dig om parallellportens IRQ,
  eftersom den vanligtvis inte anvnds.)



  6.2.  Spelporten (joystick)


  Spelporten finns p  adresserna 0x200-0x207. Fr att styra normala
  joystickar finns en kernel-level joystick driver, se
  <ftp://sunsite.unc.edu/pub/Linux/kernel/patches/>, filename
  joystick-*.

  Pinout (ett 25-pin D-don , hona ) (i=input, o=output):

    1,8,9,15: +5 V (kraftmatning)

    4,5,12: Ground

    2,7,10,14: Digitala ingngar BA1, BA2, BB1, och BB2, respektive

    3,6,11,13: ''Analoga'' ingngar AX, AY, BX, och BY, respektive

  +5 V stiften verkar ofta vara direkt anslutna till moderkortets
  kraftmatning, s de br klara ganska mycket strm, beroende p
  moderkort, kraftaggregat och spelport.

  De digitala ingngarna anvnds till de tv joystickarna (joystick A
  och joystick B, med tv knappar vardera) som du kan ansluta till
  porten. De torde vara normala TTL ingngar, och du kan lsa deras
  status direkt p statusporten (se nedan). En joystick ger lg (0 V)
  status nr knappen r nedtryckt och eljest hg (5 V frn matningen via
  ett 1K motstnd).


  De s kallade analoga ingngarna mter egentligen resistans.
  Spelportarna har en fyrfaldig one-shot multivibrator (ett 558 chip)
  anslutet till de fyra ingngarna. P varje ingngsshylsa i
  kontaktdonet finns ett 2.2K motstnd mellan ingngshylsan och
  multivibratorns 'open-collector' utgng, och en 0,01 uF 'timing'
  kondensator mellan multivibratorns utgng och jord.  En joystick har
  en potentiometer fr varje axel (X och Y), dragen mellan +5 V och
  respektive ingngshylsa ( AX och AY fr joystick A, eller BX och BY
  fr joystick B).


  Nr multivibratorn aktiveras stts dess utgng hg (5 V) och den
  invntar att timing kondensatorn nr 3.3 V innan den snker respektive
  utgng.  P s stt blir multivibratorns pulslngd proportionell mot
  potentiometerns resistans (dvs. joystickens position fr respektive
  axel) enligt fljande:

       R = (t - 24.2) / 0.011,


  dr R r potentiometerns resistans och  t  pulsens lngd i mikrosekun
  der.


  Sledes, fr att lsa dessa analoga ingngar, skall man frst aktivera
  multivibratorn (med en skrivning p porten; se nedan), sedan polla
  (gra upprepade lsningar) tillstndet fr de fyra axlarna tills de
  gr frn hg till lg, och p s stt mta pulstiden. Denna pollning
  tar mycket CPU tid och i ett ickerealtids multiprocess system som
  Linux blir inte resultatet s tillfrlitligt eftersom man inte kan
  polla kontinuerligt, svida du inte gr en 'kernel-driver' och stnger
  avbrottsingngar nr du pollar (vilket tar nnu mer CPU tid). Om du
  vet att signalen kommer drja tiotals millisekunder s kan du anropa
  usleep() innan du brjar polla fr att ge CPU tid till andra
  processer.

  Den enda I/O-port som du behver n r port 0x201 (de andra portarna
  beter sig precis likadant eller r inaktiva). En skrivning till porten
  (spelar ingen roll vad) aktiverar multivibratorn. Lsning frn porten
  returnerar signalernas status:


    Bit 0: AX (status (1=high) of the multivibrator output)

    Bit 1: AY (status (1=high) of the multivibrator output)

    Bit 2: BX (status (1=high) of the multivibrator output)

    Bit 3: BY (status (1=high) of the multivibrator output)

    Bit 4: BA1 (digital input, 1=high)

    Bit 5: BA2 (digital input, 1=high)

    Bit 6: BB1 (digital input, 1=high)

    Bit 7: BB2 (digital input, 1=high)


  6.3.  Serieporten


  Om den apparat som du vill kommunicera med stder ngot som liknar
  RS-232 br du kunna anvnda en serieport fr att tala med den. Linux
  drivrutin fr serieportar br rcka fr nstan alla tnkbara
  tillmpningar ( du ska inte behva programmera serieportarna direkt,
  och skulle s vara mste du skriva en  'kernel driver'); den r mycket
  flexibel, s att anvnda ickestandardiserade bithastigheter torde inte
  vara ngot problem.
  Se termios(3) manualen, eller seriedriverns kllkod,
  (linux/drivers/char/serial.c), och
  <http://www.easysw.com/~mike/serial/index.html> fr mer info om hur
  man programmerar serieportar p Unix system.



  7.  Tips


  Om du behver bra analog I/O kan du ansluta ett ADC- och/eller DAC-
  chip till parallellporten (tips: kraft kan du ta frn anslutningsdonet
  till spelporten eller frn ett don till en yttre diskenhet eller
  anvnda ett separat kraftaggregat. Har du strmsnla kretsar kan du ta
  kraftmatning frn parallellporten.  Du kan ocks kpa ett AD/DA-kort
  (de flesta ldre/lngsammare typerna ansluts till I/O-portar. Eller,
  om det rcker med 1 eller 2 kanaler och mttlig noggrannhet, kp ett
  billigt ljudkort som har std frn Linux sound driver. Ett sdant r
  ocks tmligen snabbt.

  Noggranna analoga apparater strs ltt om jordningen r bristfllig.
  Om du fr problem av detta slag, kan du prva att isolera din
  utrustning frn datorn med hjlp av optokopplare. (p  alla signaler
  mellan datorn och din utrustning. Frsk att f matning till
  optokopplarna frn datorn (lediga signaler frn porten kan ge
  tillrckligt med kraft) fr bsta isolation frn strning.

  Letar du efter Linux mjukvara fr mnsterkortframtagning, s finns det
  en fri sdan som kallas Pcb. Den torde gra ett bra jobb, tminstone
  om inte du gr ngot alltfr komplicerat. Den finn med i mnga Linux
  distributioner, och den finns tillgnglig i
  <ftp://sunsite.unc.edu/pub/Linux/apps/circuits/> (filename pcb-*).



  8.  Felskning



     Q1.
        Jag fr segmentation faults nr jag adresserar portar.


     A1.
        Antingen har ditt program inte rootprivilegier, eller har
        ioperm()  falerat av ngon annan orsak. Testa det returnerade
        vrdet frn ioperm(). Testa ocks att du verkligen adresserar de
        portar som du gett tillstnd till med  ioperm() (se Q3).

        Om du anvnder 'delaying macros' (inb_p(), outb_p(), osv.), kom
        ihg att du d mste anropa ioperm() fr att ge accesstillstnd
        till adress 0x80.


     Q2.
        Jag kan inte hitta var in*(), out*() funktionerna definieras,
        och gcc klagar ver odefinierade referenser.


     A2.
        Du kompilerade inte med optimeringsflaggan p (-O1 eller hgre),
        och drfr kunde inte gcc lsa upp de makron som finns i
        asm/io.h. Eller glmde du kanske #include <asm/io.h>.



     Q3.
        out*() gr ingenting, eller gr ngot konstigt.


     A3.
        Kolla ordningen p parametrarna; set skall vara outb(value,
        port), inte  outb(port, value) som frekommer i MS-DOS.


     Q4.
        Jag vill kra en standard RS-232 device/parallel
        printer/joystick...



     A4.
        D r det nog bst att anvnda en befintlig driver (i Linux
        kernel eller en X-server eller ngon annanstans) fr detta.
        Drivrutinerna r vanligtvis mycket flexibla, s att ven en
        ickestandard apparat fungerar vanligtvis med dem. Se info om
        standard portar ovan efter hnvisningar till dokumentation.



  9.  Kod exempel

  Hr fljer ett enkelt exempel p kod fr I/O-port access:







































  ______________________________________________________________________
  /*
   * example.c: very simple example of port I/O
   *
   * This code does nothing useful, just a port write, a pause,
   * and a port read. Compile with 'gcc -O2 -o example example.c',
   * and run as root with './example'.
   */

  #include <stdio.h>
  #include <unistd.h>
  #include <asm/io.h>

  #define BASEPORT 0x378 /* lp1 */

  int main()
  {
    /* Get access to the ports */
    if (ioperm(BASEPORT, 3, 1)) {perror("ioperm"); exit(1);}

    /* Set the data signals (D0-7) of the port to all low (0) */
    outb(0, BASEPORT);

    /* Sleep for a while (100 ms) */
    usleep(100000);

    /* Read from the status port (BASE+1) and display the result */
    printf("status: %d\n", inb(BASEPORT + 1));

    /* We don't need the ports anymore */
    if (ioperm(BASEPORT, 3, 0)) {perror("ioperm"); exit(1);}

    exit(0);
  }

  /* end of example.c */
  ______________________________________________________________________






  10.  Erknnande


  Alltfr mnga har bidragit till artikeln fr att jag skall kunna rkna
  upp alla, men tack allesammans. Jag har inte besvarat alla bidrag som
  jag ftt; ledsen fr det, men terigen tack fr all hjlp.

















