Linux I/O port programmering mini-HOWTO
 Av: Riku Saikkonen <[email protected]> �vers�ttning till
 svenska: Sven Wilhelmsson, <[email protected]>
 v  ,28 December 1997 , �versatt: 10 Augusti 1998

 I detta HOWTO dokument beskrivs hur man programmerar I/O portar samt
 hur man f�rdr�jer eller m�ter korta tidsintervall i user-mode Linux
 program f�r Intel x86 arkitekturen.
 ______________________________________________________________________

 Inneh�llsf�rteckning


 1. Inledning

 2. Att anv�nda I/O portar i C-program

    2.1 Det vanliga s�ttet
    2.2 En alternativ metod:

 3. Avbrott (IRQs) och DMA

 4. H�guppl�sande timing

    4.1 F�rdr�jningar
       4.1.1 (TT
       4.1.2 nanosleep()
       4.1.3 F�rdr�jningar med port I/O
       4.1.4 Att f�rdr�ja med assemblerinstruktioner
       4.1.5 rdtsc() f�r Pentium
    4.2 Att m�ta tid

 5. Andra programmeringsspr�k

 6. N�gra anv�ndbara portar

    6.1 Parallellporten
    6.2 Spelporten (joystick)
    6.3 Serieporten

 7. Tips

 8. Fels�kning

 9. Kod exempel

 10. Erk�nnande



 ______________________________________________________________________

 1.  Inledning


 I detta HOWTO dokument beskrivs hur man n�r I/O-portar och hur man
 f�rdr�jer korta tidsintervall i user-mode Linux program som k�rs p�
 Intel x86 arkitekturen. Detta dokumentet �r en uppf�ljare till den
 mycket lilla IO-Port mini-HOWTO fr�n samma f�rfattare.

 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
 ([email protected])...
 �ndringar fr�n tidigare publicerad version (Mar 30 1997):

 �  F�rklaringar ang�ende inb_p/outb_p/ och port 0x80.

 �  Tagit bort information om  udelay(), eftersom nanosleep() medger
    ett renare s�tt att g�ra samma sak.

 �  Konverterat till Linuxdoc-SGML, och �ndrat om n�got.

 �  M�nga mindre till�gg och �ndringar.



 2.  Att anv�nda I/O portar i C-program

 2.1.  Det vanliga s�ttet

 Rutiner f�r 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 d�r �r inline makron, s� det r�cker att g�ra #include
 <asm/io.h>, inga ytterligare bibliotek beh�vs.

 Beroende p� brister i gcc (�tminstone i 2.7.2.3 och l�gre) och i egcs
 (alla versioner), m�ste du kompilera k�llkod som anv�nder dessa
 rutiner med optimeringsflaggan p� (gcc -O1 eller h�gre), eller
 alternativt #define extern till ingenting, (dvs. #define extern p� en
 i �vrigt blank rad) innan du g�r #include <asm/io.h>.

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

 Innan du anropar en port, m�ste du ge ditt program tillst�nd till
 detta.  Detta g�r man genom att anropa ioperm() funktionen (som finns
 deklarerad i unistd.h, och definierad i 'kernel') n�gonstans i b�rjan
 av ditt program, innan n�gon I/O-port anropas. Syntaxen �r
 ioperm(from, num, turn_on), d�r from �r den f�rsta portadressen som
 ska ges tillst�nd och num �r antalet konsekutiva adresser. Till
 exempel, ioperm(0x300, 5, 1) ger tillst�nd till portarna  0x300 till
 0x304 (totalt 5 portar). Det sista argumentet �r en bool som
 specificerar om du vill ge accesstillst�nd (true(1)) eller ta bort
 tillst�ndet (false(0)). Du kan anv�nda ioperm() upprepade g�nger f�r
 att ge tillst�nd till ickekonsekutiva portadresser. Se ioperm(2)
 manualen.

  ioperm() anropet kr�ver att ditt program har rootprivilegier. Det
 kr�vs att du antingen k�r som root, eller g�r setuid root.  Du kan
 sl�ppa rootprivilegierna s� snart du har anropat ioperm(). Det �r inte
 n�dv�ndigt att explicit sl�ppa dina accessr�ttigheter med ioperm(...,
 0) mot slutet av ditt program. Detta sker automatiskt n�r processen
 avslutas.

 Om du g�r setuid() till en non-root user f�rst�rs inte de
 accessr�ttigheter som �r redan givna av ioperm(), men fork() f�rst�r
 dem (child processen f�r inga r�ttigheter, men parent beh�ller dem).

 ioperm() kan endast ge access r�ttigheter till portarna 0x000 - 0x3ff.
 F�r att komma �t h�gre portadresser, kan man anv�nda iopl(), som ger
 access till alla portar p� en g�ng. Anv�nd niv� 3 (dvs iopl(3)) f�r
 att ge ditt program tillg�ng till alla portar. (Men var f�rsiktig -
 att skriva p� fel port kan orsaka allehanda otrevliga saker med din
 dator).  Du beh�ver rootprivilegier f�r att anropa  iopl().  Se
 iopl(2) manualen.

 Sedan, f�r att komma �t portarna... F�r att l�sa in en byte, (8 bitar)
 fr�n en port, call inb(port), den returnerar den byte den l�ser. F�r
 att st�lla ut, call outb(value,port) (notera parameterordningen).  F�r
 att l�sa in 16 bitar fr�n port x och x+1 ,en byte fr�n vardera, call
 inw(x) och f�r att st�lla ut, call outw(value,x). �r du os�ker p� om
 du skall anv�nda byte eller word instruktioner, �r det troligen inb()
 och outb() - flertalet apparater konstrueras f�r bytevis portaccess.
 Notera att alla portaccesser tar �tminstone cirka en mikrosekund att
 utf�ra.

 F�r �vrigt fungerar makroanropen inb_p(), outb_p(), inw_p(), och
 outw_p() p� samma s�tt som ovann�mnda, f�rutom att de l�gger till ca
 en mikrosekund efter varje portaccess. Du kan g�ra f�rdr�jningen �nnu
 l�ngre, ca 4 mikrosekunder, med #define REALLY_SLOW_IO innan du g�r
 #include <asm/io.h>. Dessa makron g�r normalt (s�vida du inte g�r
 #define SLOW_IO_BY_JUMPING, vilket blir mindre noggrant) access till
 port 0x80 f�r att skapa delay, s� du beh�ver f�rst ge accessr�tt till
 port 0x80 med ioperm(). (Skrivning p� port 0x80 p�verkar ingenting).
 F�r mer flexibla delay-metoder, l�s vidare.

 Det finns sidor till ioperm(2), iopl(2) och ovann�mnda makron i
 n�gorlunda f�rska utg�vor av Linux manual.



 2.2.  En alternativ metod: /dev/port


 Ett annat s�tt att komma �t I/O-portar �r open() /dev/port (en
 'character device', major number 1, minor 4) f�r l�sning och/eller
 skrivning (stdio f*() funktionerna har intern buffring, s� anv�nd inte
 dem). G�r 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 fr�n den.

 Naturligtvis beh�ver ditt program accessr�ttigheter till /dev/port f�r
 att metoden skall fungera. Denna metod �r sannolikt l�ngsammare �n den
 normala metoden enligt ovan, men beh�ver varken optimeringsflaggan vid
 kompilering eller ioperm(). Det beh�vs inte heller 'root access', bara
 du ger 'non-root user' eller 'group' access till /dev/port - l�t vara
 att detta �r dumt ur systems�kerhetssynpunkt, eftersom det �r m�jligt
 att skada systemet, kanske till och med vinna 'root access', genom att
 anv�nda /dev/port f�r att komma �t h�rddisk, n�tverkskort, etc.
 direkt.



 3.  Avbrott (IRQs) och DMA


 Man kan inte anv�nda  IRQ eller DMA direkt i en usermode process.  Man
 m�ste skriva en kernel driver; se The Linux Kernel Hacker's Guide
 <http://www.redhat.com:8080/HyperNews/get/khg.html> D�r finns detaljer
 och kernel k�llkod som exempel.  Man kan heller inte st�nga av ett
 avbrott fr�n ett user-mode program.



 4.  H�guppl�sande timing

 4.1.  F�rdr�jningar


 F�rst och fr�mst m�ste s�gas att det inte g�r 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 n�gra sekunder (om belastningen
 �r h�g).  Detta spelar emellertid ingen roll f�r flertalet program som
 anv�nder I/O-portar. F�r att reducera effekterna, kan du med hj�lp av
 kommandot nice ge din process h�g prioritet. Se nice(2) manualen eller
 anv�nd real-time scheduling enligt nedan.

 Om du beh�ver b�ttre tidsprecision �n vad normala user-mode processer
 kan ge, s� finns vissa f�rberedelser f�r 'user-mode real time'
 support.  Linux 2.x k�rnor har 'soft real time support', se manualen
 f�r sched_setscheduler(2). Det finns en speciell k�rna som st�der h�rd
 realtid, se  <http://luz.cs.nmt.edu/~rtlinux/> f�r ytterligare
 information om detta.




 4.1.1.  sleep()  och usleep()


 L�t oss b�rja med de l�tta funktionsanropen. F�r att f�rdr�ja flera
 sekunder, �r det troligtvis b�st att anv�nda sleep(). F�rdr�jningar p�
 10-tals millisekunder (ca 10 ms verkar vara minimum) g�rs med
 usleep().  Dessa funktioner frig�r CPU f�r andra processer, s� att
 ingen CPU-tid g�r f�rlorad. Se manualerna  sleep(3) och usleep(3).


 Om f�rdr�jningar �r p� mindre �n 50 ms ( beror p� din processor och
 dess belastning), tar det on�digt mycket tid att sl�ppa CPUn, d�rf�r
 att det f�r Linux scheduler (f�r x86 arkitekturen) vanligtvis tar
 minst 10-30 millisekunder innan den �terger din process kontrollen.
 Beroende p� detta f�rdr�jer usleep(3) n�got mer �n vad du specificerar
 i dina parametrar, och alltid minst ca 10 ms.





 4.1.2.  nanosleep()


 I 2.0.x serien av Linuxk�rnor finns ett nytt systemanrop: nanosleep()
 (se nanosleep(2) manualen), som m�jligg�r s� korta f�rdr�jningar som
 ett par mikrosekunder eller mer.

 Vid f�rdr�jningar p� mindre �n 2 ms, om (och endast om) din process �r
 satt till soft real time scheduling (med sched_setscheduler()),
 anv�nder nanosleep() en v�nteloop, i annat fall frig�rs CPU p� samma
 s�tt som med usleep().

 V�nteloopen anv�nder udelay() (en intern kernelfunktion som anv�nds av
 m�nga 'kernel drivers'), och loopens l�ngd ber�knas med hj�lp av
 BogoMips v�rdet (det �r bara denna sorts hastighet BogoMips v�rdet
 m�ter noggrant).  Se hur det fungerar i  /usr/include/asm/delay.h


 4.1.3.  F�rdr�jningar med port I/O


 Ett annat s�tt att f�rdr�ja ett f�tal mikrosekunder �r att anv�nda
 port I/O.  L�sning eller skrivning p� port 0x80 (se ovan hur man g�r)
 tar n�stan precis 1 mikrosekund oberoende av processortyp och
 hastighet. Du kan g�ra det upprepade g�nger om du vill v�nta ett antal
 mikrosekunder. Skrivning p� denna port torde inte ha n�gra skadliga
 sidoeffekter p� n�gon standardmaskin och vissa 'kerneldrivers'
 anv�nder denna metod.  det �r p� detta s�ttet {in|out}[bw]_p()
 normalt g�r sin f�rdr�jning.  (se asmio.h)/.
 Flertalet port I/O instruktioner i adressomr�det 0-0x3ff tar n�stan
 exakt 1 mikrosekund, s� om du t.ex. anv�nder parallellporten direkt,
 g�r bara n�gra extra inb() fr�n porten f�r att skapa f�rdr�jning.




 4.1.4.  Att f�rdr�ja med assemblerinstruktioner


 Om man k�nner till processortyp och klockhastighet, kan man h�rdkoda
 korta f�rdr�jningar med vissa assemblerinstruktioner (men kom ih�g,
 processen kan skyfflas ut n�r som helst, s� f�rdr�jningarna kan ibland
 bli l�ngre).  Tabellen nedan ger n�gra exempel. F�r 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




 tyv�rr k�nner jag inte till Pentium; f�rmodligen n�ra i486.  Jag
 hittar ingen instruktion som tar EN klockcykel i i386.  Anv�nd en-
 cykel instruktioner om du kan, annars kanske pipelinen i moderna
 processortyper f�rkortar tiden.


 Instruktionerna nop och xchg i tabellen b�r inte ha n�gra
 sidoeffekter. �vriga modifierar statusregistret, men det b�r inte
 betyda n�got eftersom gcc detekterar detta. nop �r ett bra val.

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

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

 Kortare f�rdr�jningar �n en klockcykel �r inte m�jligt med x86
 arkitekturen.



 4.1.5.  rdtsc() f�r Pentium

 Med Pentium kan du erh�lla antalet klockcykler som g�tt sedan senaste
 uppstart med hj�lp av f�ljande 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 v�rdet f�r hur m�nga cykler som helst.


 4.2.  Att m�ta tid


 F�r att m�ta tider med en sekunds uppl�sning, �r det nog enklast att
 anv�nda time(). Kr�vs b�ttre noggrannhet, ger gettimeofday() cirka en
 mikrosekunds uppl�sning (men se ovan ang�ende 'scheduling',
 utskyffling). F�r Pentium �r rdtsc kodfragmentet ovan noggrant till en
 klockcykel.

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


 5.  Andra programmeringsspr�k


 Beskrivningen ovan koncentrerar sig p� programmeringsspr�ket C.  Det
 b�r vara till�mpbart �ven p� C++ och Objective C. I assembler f�r man
 anropa  ioperm() eller iopl() som i C, och d�refter kan man anv�nda
 I/O-port read/write  instruktionerna direkt.

 I andra spr�k, s�vida inte du kan infoga inline assembler eller C kod
 i ditt program eller anv�nda ovann�mnda systemanrop, �r det nog
 enklast att skriva en C k�llkodsfil med funktionerna f�r I/O-
 portaccess och separatkompilera och l�nka den till �vriga delar av
 ditt program.  Eller anv�nda  /dev/port enligt ovan.



 6.  N�gra anv�ndbara portar

 H�r f�ljer programmeringsinformation om n�gra portar som direkt kan
 anv�ndas f�r TTL (eller CMOS) digitala kretsar.

 Om du vill anv�nda dessa eller andra g�ngse portar f�r det �ndam�l de
 �r �gnade (t.ex. f�r att styra en printer eller modem), skall du
 troligen anv�nda en befintlig drivrutin (vanligtvis inkluderad i
 k�rnan) i st�llet f�r att programmera dessa portar direkt som beskrivs
 i detta HOWTO. Denna sektion �r avsedd f�r 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), s�k efter en befintlig drivrutin.
 Hardware-HOWTO <http://sunsite.unc.edu/pub/Linux/docs/HOWTO/Hardware-
 HOWTO> �r ett bra st�lle att b�rja.

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


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


 F�rutom 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 allm�nt), se  <http://www.fapo.com/> och
 <http://www.senet.com.au/~cpeacock/parallel.htm>.  Kom ih�g att
 eftersom du inte kan anv�nda IRQs eller DMA i ett user-mode program,
 s� kommer du nog att beh�va skriva en 'kernel-driver' f�r att anv�nda
 ECP/EPP. Jag tror att n�gon h�ller p� att skriva en s�dan driver men
 jag k�nner inte till n�gra detaljer.


 Porten  BASE+0 (Data port) styr data signalerna (D0 till D7 f�r
 bitarna 0 to 7, respektive; tillst�nden: 0 = l�g (0 V), 1 = h�g (5
 V)). Skrivning p� denna port st�ller ut data till donet. En l�sning
 returnerar senast skrivna data i standard- eller extended-moden, eller
 data p� stiften fr�n en ansluten apparat i 'extended read mode'.


 Portarna BASE+1 ('Status port') �r 'read-only', och returnerar
 tillst�ndet p� f�ljande insignaler:

 �  Bits 0 och 1 �r reserverade.

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

 �  Bit 3 ERROR (1=h�g)

 �  Bit 4 SLCT (1=h�g)

 �  Bit 5 PE (1=h�g)

 �  Bit 6 ACK (1=h�g)

 �  Bit 7 -BUSY (0=h�g)

    (Vet inte vilka sp�nningar som motsvarar h�g respektive l�g.)

 Porten BASE+2 ('Control port') �r 'write-only' (l�sning returnerar
 senast inskrivna data), och styr f�ljande status signaler:

 �  Bit 0 -STROBE (0=h�g)

 �  Bit 1 AUTO_FD_XT (1=h�g)

 �  Bit 2 -INIT (0=h�g)

 �  Bit 3 SLCT_IN (1=h�g)

 �  Bit 4 aktiverar ('enables') parallell portens IRQ (vilket sker p�
    uppflanken hos ACK) n�r den s�tts till 1.

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

 �  Bits 6 och 7 �r reserverade.

    (�terigen, �r inte s�ker p� vad som �r h�g och l�g.)

 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 s�ger att stiften 1, 14, 16, och 17 ('control-
 outputs') har 'open-collektor' utg�ngar dragna till 5 V genom ett 4.7
 K motst�nd (s�nker 20 mA, ger 0.55 mA, h�gniv� utg�ng 5.0 V minus
 eventuellt sp�nningsfall). �vriga stift s�nker 24 mA och ger 15 mA,
 och deras h�gniv� sp�nning �r minst 2.4 V. L�gniv� sp�nningen �r i
 b�da fallen minst 0.5 V.  Icke-IBM parallell portar avviker troligen
 fr�n denna standard.  F�r ytterligare information om detta se
 <http://www.hut.fi/Misc/Electronics/circuits/lptpower.html>.


 Slutligen en varning: Var noga med jordningen. Jag har f�rst�rt flera
 parallellportar genom att ansluta dem  med datorn ig�ng. Det kan vara
 ett bra alternativ att anv�nda parallellportar som inte sitter p�
 moderkortet f�r s�dana h�r saker. (Du kan antagligen f� en andra
 parallellport med ett billigt standard 'multi-I/O' kort; St�ng bara av
 de portar du inte beh�ver, och s�tt parallellkortets I/O-adress till
 en ledig adress. Du beh�ver inte bekymra dig om parallellportens IRQ,
 eftersom den vanligtvis inte anv�nds.)



 6.2.  Spelporten (joystick)


 Spelporten finns p�  adresserna 0x200-0x207. F�r 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 ing�ngar BA1, BA2, BB1, och BB2, respektive

 �  3,6,11,13: ''Analoga'' ing�ngar AX, AY, BX, och BY, respektive

 +5 V stiften verkar ofta vara direkt anslutna till moderkortets
 kraftmatning, s� de b�r klara ganska mycket str�m, beroende p�
 moderkort, kraftaggregat och spelport.

 De digitala ing�ngarna anv�nds till de tv� joystickarna (joystick A
 och joystick B, med tv� knappar vardera) som du kan ansluta till
 porten. De torde vara normala TTL ing�ngar, och du kan l�sa deras
 status direkt p� statusporten (se nedan). En joystick ger l�g (0 V)
 status n�r knappen �r nedtryckt och eljest h�g (5 V fr�n matningen via
 ett 1K motst�nd).


 De s� kallade analoga ing�ngarna m�ter egentligen resistans.
 Spelportarna har en fyrfaldig one-shot multivibrator (ett 558 chip)
 anslutet till de fyra ing�ngarna. P� varje ing�ngsshylsa i
 kontaktdonet finns ett 2.2K motst�nd mellan ing�ngshylsan och
 multivibratorns 'open-collector' utg�ng, och en 0,01 uF 'timing'
 kondensator mellan multivibratorns utg�ng och jord.  En joystick har
 en potentiometer f�r varje axel (X och Y), dragen mellan +5 V och
 respektive ing�ngshylsa ( AX och AY f�r joystick A, eller BX och BY
 f�r joystick B).


 N�r multivibratorn aktiveras s�tts dess utg�ng h�g (5 V) och den
 inv�ntar att timing kondensatorn n�r 3.3 V innan den s�nker respektive
 utg�ng.  P� s� s�tt blir multivibratorns pulsl�ngd proportionell mot
 potentiometerns resistans (dvs. joystickens position f�r respektive
 axel) enligt f�ljande:

      R = (t - 24.2) / 0.011,


 d�r R �r potentiometerns resistans och  t  pulsens l�ngd i mikrosekun�
 der.


 S�ledes, f�r att l�sa dessa analoga ing�ngar, skall man f�rst aktivera
 multivibratorn (med en skrivning p� porten; se nedan), sedan polla
 (g�ra upprepade l�sningar) tillst�ndet f�r de fyra axlarna tills de
 g�r fr�n h�g till l�g, och p� s� s�tt m�ta pulstiden. Denna pollning
 tar mycket CPU tid och i ett ickerealtids multiprocess system som
 Linux blir inte resultatet s� tillf�rlitligt eftersom man inte kan
 polla kontinuerligt, s�vida du inte g�r en 'kernel-driver' och st�nger
 avbrottsing�ngar n�r du pollar (vilket tar �nnu mer CPU tid). Om du
 vet att signalen kommer dr�ja tiotals millisekunder s� kan du anropa
 usleep() innan du b�rjar polla f�r att ge CPU tid till andra
 processer.

 Den enda I/O-port som du beh�ver n� �r port 0x201 (de andra portarna
 beter sig precis likadant eller �r inaktiva). En skrivning till porten
 (spelar ingen roll vad) aktiverar multivibratorn. L�sning fr�n 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 st�der n�got som liknar
 RS-232 b�r du kunna anv�nda en serieport f�r att tala med den. Linux
 drivrutin f�r serieportar b�r r�cka f�r n�stan alla t�nkbara
 till�mpningar ( du ska inte beh�va programmera serieportarna direkt,
 och skulle s� vara m�ste du skriva en  'kernel driver'); den �r mycket
 flexibel, s� att anv�nda ickestandardiserade bithastigheter torde inte
 vara n�got problem.
 Se termios(3) manualen, eller seriedriverns k�llkod,
 (linux/drivers/char/serial.c), och
 <http://www.easysw.com/~mike/serial/index.html> f�r mer info om hur
 man programmerar serieportar p� Unix system.



 7.  Tips


 Om du beh�ver bra analog I/O kan du ansluta ett ADC- och/eller DAC-
 chip till parallellporten (tips: kraft kan du ta fr�n anslutningsdonet
 till spelporten eller fr�n ett don till en yttre diskenhet eller
 anv�nda ett separat kraftaggregat. Har du str�msn�la kretsar kan du ta
 kraftmatning fr�n parallellporten.  Du kan ocks� k�pa ett AD/DA-kort
 (de flesta �ldre/l�ngsammare typerna ansluts till I/O-portar. Eller,
 om det r�cker med 1 eller 2 kanaler och m�ttlig noggrannhet, k�p ett
 billigt ljudkort som har st�d fr�n Linux sound driver. Ett s�dant �r
 ocks� t�mligen snabbt.

 Noggranna analoga apparater st�rs l�tt om jordningen �r bristf�llig.
 Om du f�r problem av detta slag, kan du pr�va att isolera din
 utrustning fr�n datorn med hj�lp av optokopplare. (p�  alla signaler
 mellan datorn och din utrustning. F�rs�k att f� matning till
 optokopplarna fr�n datorn (lediga signaler fr�n porten kan ge
 tillr�ckligt med kraft) f�r b�sta isolation fr�n st�rning.

 Letar du efter Linux mjukvara f�r m�nsterkortframtagning, s� finns det
 en fri s�dan som kallas Pcb. Den torde g�ra ett bra jobb, �tminstone
 om inte du g�r n�got alltf�r komplicerat. Den finn med i m�nga Linux
 distributioner, och den finns tillg�nglig i
 <ftp://sunsite.unc.edu/pub/Linux/apps/circuits/> (filename pcb-*).



 8.  Fels�kning



    Q1.
       Jag f�r segmentation faults n�r jag adresserar portar.


    A1.
       Antingen har ditt program inte rootprivilegier, eller har
       ioperm()  falerat av n�gon annan orsak. Testa det returnerade
       v�rdet fr�n ioperm(). Testa ocks� att du verkligen adresserar de
       portar som du gett tillst�nd till med  ioperm() (se Q3).

       Om du anv�nder 'delaying macros' (inb_p(), outb_p(), osv.), kom
       ih�g att du d� m�ste anropa ioperm() f�r att ge accesstillst�nd
       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 h�gre),
       och d�rf�r kunde inte gcc l�sa upp de makron som finns i
       asm/io.h. Eller gl�mde du kanske #include <asm/io.h>.



    Q3.
       out*() g�r ingenting, eller g�r n�got konstigt.


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


    Q4.
       Jag vill k�ra en standard RS-232 device/parallel
       printer/joystick...



    A4.
       D� �r det nog b�st att anv�nda en befintlig driver (i Linux
       kernel eller en X-server eller n�gon annanstans) f�r detta.
       Drivrutinerna �r vanligtvis mycket flexibla, s� att �ven en
       ickestandard apparat fungerar vanligtvis med dem. Se info om
       standard portar ovan efter h�nvisningar till dokumentation.



 9.  Kod exempel

 H�r f�ljer ett enkelt exempel p� kod f�r 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.  Erk�nnande


 Alltf�r m�nga har bidragit till artikeln f�r att jag skall kunna r�kna
 upp alla, men tack allesammans. Jag har inte besvarat alla bidrag som
 jag f�tt; ledsen f�r det, men �terigen tack f�r all hj�lp.