12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506 |
- /*++
- Copyright (c) 2014 Minoca Corp. All Rights Reserved
- Module Name:
- ser16550.c
- Abstract:
- This module implements a kernel driver for 16550-like UARTs.
- Author:
- Evan Green 21-Nov-2014
- Environment:
- Kernel
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include <minoca/kernel/driver.h>
- #include <minoca/fw/acpitabs.h>
- #include <minoca/kernel/kdebug.h>
- //
- // --------------------------------------------------------------------- Macros
- //
- //
- // Macros to read from and write to 16550 registers.
- //
- #define SER16550_READ8(_Device, _Register) \
- (_Device)->Read8((_Device), (_Register))
- #define SER16550_WRITE8(_Device, _Register, _Value) \
- (_Device)->Write8((_Device), (_Register), (_Value))
- //
- // This macro returns the offset of a given register from its base.
- //
- #define SER16550_REGISTER_OFFSET(_Device, _Register) \
- ((_Device)->RegisterOffset + ((_Register) << (_Device)->RegisterShift))
- //
- // This macro evaluates to non-zero if the given Oxford device ID has two
- // UARTs. This matches against the Mode[2:0] bits being 101 and the UART_EN bit
- // being set.
- //
- #define SER16550_OXFORD_DUAL_UARTS(_DeviceId) \
- (((_DeviceId) & 0x0078) == 0x0058)
- //
- // ---------------------------------------------------------------- Definitions
- //
- #define SER16550_ALLOCATION_TAG 0x36317253
- #define SER16550_DEFAULT_BUFFER_SIZE 2048
- #define SER16550_DEFAULT_BASE_BAUD 115200
- #define SER16550A_FIFO_SIZE 16
- #define SER16550_MAX_FIFO 256
- #define SERIAL_PORT_DEVICE_ID_FORMAT "Serial%d"
- #define SERIAL_PORT_DEVICE_ID_SIZE 50
- //
- // Standard 16x50 register definitions.
- //
- #define SER16550_LINE_CONTROL_5_DATA_BITS 0x00
- #define SER16550_LINE_CONTROL_6_DATA_BITS 0x01
- #define SER16550_LINE_CONTROL_7_DATA_BITS 0x02
- #define SER16550_LINE_CONTROL_8_DATA_BITS 0x03
- #define SER16550_LINE_CONTROL_2_STOP_BITS 0x04
- #define SER16550_LINE_CONTROL_PARITY_ENABLE 0x08
- #define SER16550_LINE_CONTROL_EVEN_PARITY 0x10
- #define SER16550_LINE_CONTROL_SET_PARITY 0x20
- #define SER16550_LINE_CONTROL_SET_BREAK 0x40
- #define SER16550_LINE_CONTROL_DIVISOR_LATCH 0x80
- #define SER16550_FIFO_CONTROL_ENABLE 0x01
- #define SER16550_FIFO_CONTROL_CLEAR_RECEIVE 0x02
- #define SER16550_FIFO_CONTROL_CLEAR_TRANSMIT 0x04
- #define SER16550_FIFO_CONTROL_MULTI_DMA 0x08
- #define SER16550_FIFO_CONTROL_64_BYTE_FIFO 0x20
- #define SER16550_FIFO_CONTROL_RX_TRIGGER_1 (0 << 6)
- #define SER16550_FIFO_CONTROL_RX_TRIGGER_4 (1 << 6)
- #define SER16550_FIFO_CONTROL_RX_TRIGGER_8 (2 << 6)
- #define SER16550_FIFO_CONTROL_RX_TRIGGER_14 (3 << 6)
- #define SER16550_MODEM_CONTROL_DTR 0x01
- #define SER16550_MODEM_CONTROL_RTS 0x02
- #define SER16550_MODEM_CONTROL_OP1 0x04
- #define SER16550_MODEM_CONTROL_ENABLE_INTERRUPT 0x08
- #define SER16550_MODEM_CONTROL_LOOPBACK 0x10
- #define SER16550_MODEM_CONTROL_ENABLE_FLOW_CONTROL 0x20
- #define SER16550_INTERRUPT_ENABLE_RX_DATA 0x01
- #define SER16550_INTERRUPT_ENABLE_TX_EMPTY 0x02
- #define SER16550_INTERRUPT_ENABLE_RX_STATUS 0x04
- #define SER16550_INTERRUPT_ENABLE_MODEM_STATUS 0x08
- #define SER16550_INTERRUPT_STATUS_NONE_PENDING 0x01
- #define SER16550_INTERRUPT_STATUS_RX_DATA_ERROR 0x06
- #define SER16550_INTERRUPT_STATUS_RX_DATA_READY 0x04
- #define SER16550_INTERRUPT_STATUS_RX_TIMEOUT 0x0C
- #define SER16550_INTERRUPT_STATUS_TX_EMPTY 0x02
- #define SER16550_INTERRUPT_STATUS_MODEM_STATUS 0x00
- #define SER16550_INTERRUPT_STATUS_MASK 0x0E
- #define SER16550_LINE_STATUS_RX_READY 0x01
- #define SER16550_LINE_STATUS_OVERRUN_ERROR 0x02
- #define SER16550_LINE_STATUS_PARITY_ERROR 0x04
- #define SER16550_LINE_STATUS_FRAMING_ERROR 0x08
- #define SER16550_LINE_STATUS_BREAK 0x10
- #define SER16550_LINE_STATUS_TX_HOLDING_EMPTY 0x20
- #define SER16550_LINE_STATUS_TX_EMPTY 0x40
- #define SER16550_LINE_STATUS_FIFO_ERROR 0x80
- #define SER16550_LINE_STATUS_ERROR_MASK \
- (SER16550_LINE_STATUS_OVERRUN_ERROR | SER16550_LINE_STATUS_PARITY_ERROR | \
- SER16550_LINE_STATUS_FRAMING_ERROR | SER16550_LINE_STATUS_FIFO_ERROR)
- #define SER16550_LINE_STATUS_RX_MASK \
- (SER16550_LINE_STATUS_RX_READY | SER16550_LINE_STATUS_BREAK)
- //
- // Known vendors and devices.
- //
- #define SER16550_PCI_DEVICE_ID_FORMAT "VEN_%x&DEV_%x"
- #define SER16550_VENDOR_INTEL 0x8086
- #define SER16550_INTEL_QUARK 0x0936
- #define SER16550_VENDOR_OXFORD 0x1415
- #define SER16550_OXFORD_UART_OFFSET 0x1000
- #define SER16550_OXFORD_UART_STRIDE 0x200
- #define SER16550_OXFORD_BASE_BAUD 3916800
- //
- // Intel Quark UART information.
- //
- #define SER16550_INTEL_QUARK_UART_BASE_BAUD 2764800
- #define SER16550_INTEL_QUARK_UART_REGISTER_SHIFT 2
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- typedef enum _SER16550_OBJECT_TYPE {
- Ser16550ObjectInvalid,
- Ser16550ObjectParent,
- Ser16550ObjectChild
- } SER16550_OBJECT_TYPE, *PSER16550_OBJECT_TYPE;
- typedef enum _SER16550_VARIANT {
- Ser16550VariantInvalid,
- Ser16550VariantGeneric,
- Ser16550VariantQuark,
- Ser16550VariantOxford,
- } SER16550_VARIANT, *PSER16550_VARIANT;
- typedef enum _SER16550_REGISTER {
- Ser16550Data = 0,
- Ser16550DivisorLow = 0,
- Ser16550InterruptEnable = 1,
- Ser16550DivisorHigh = 1,
- Ser16550InterruptStatus = 2,
- Ser16550FifoControl = 2,
- Ser16550LineControl = 3,
- Ser16550ModemControl = 4,
- Ser16550LineStatus = 5,
- Ser16550ModemStatus = 6,
- Ser16550Scratch = 7
- } SER16550_REGISTER, *PSER16550_REGISTER;
- typedef struct _SER16550_CHILD SER16550_CHILD, *PSER16550_CHILD;
- typedef
- UCHAR
- (*PSER16550_READ8) (
- PSER16550_CHILD Device,
- SER16550_REGISTER Register
- );
- /*++
- Routine Description:
- This routine reads a 16550 register.
- Arguments:
- Device - Supplies a pointer to the device context.
- Register - Supplies the register to read.
- Return Value:
- Returns the value at the register.
- --*/
- typedef
- VOID
- (*PSER16550_WRITE8) (
- PSER16550_CHILD Device,
- SER16550_REGISTER Register,
- UCHAR Value
- );
- /*++
- Routine Description:
- This routine writes to a 16550 register.
- Arguments:
- Device - Supplies a pointer to the device context.
- Register - Supplies the register to write to.
- Value - Supplies the value to write.
- Return Value:
- None.
- --*/
- /*++
- Structure Description:
- This structure stores the common header for a 16550 object.
- Members:
- Type - Stores the serial object type.
- ReferenceCount - Stores the reference count on the object.
- --*/
- typedef struct _SER16550_OBJECT {
- SER16550_OBJECT_TYPE Type;
- ULONG ReferenceCount;
- } SER16550_OBJECT, *PSER16550_OBJECT;
- /*++
- Structure Description:
- This structure stores information about a 16550 parent context.
- Members:
- Header - Store the common 16550 object header.
- Device - Stores the OS device this device belongs to.
- InterruptLine - Stores the interrupt line that this controller's interrupt
- comes in on.
- InterruptVector - Stores the interrupt vector that this controller's
- interrupt comes in on.
- InterruptResourcesFound - Stores a boolean indicating whether or not the
- interrupt line and interrupt vector fields are valid.
- InterruptHandle - Stores a pointer to the handle received when the
- interrupt was connected.
- InterruptLock - Stores the spin lock synchronizing access to the pending
- status bits.
- Variant - Stores the variant type of 16550 controller.
- VendorId - Stores the PCI vendor ID of the device, or 0 if this was not a
- PCI device.
- DeviceId - Stores the PCI device ID of thd device.
- ChildObjects - Stores an array of child objects.
- ChildDevices - Stores an array of child devices.
- ChildCount - Stores the count of the number of children.
- RegisterShift - Stores the number of bits to shift left to get from a 16550
- register to an actual device register. By default this is applied to
- all children.
- BaseBaud - Stores the baud rate when the divisor is set to 1.
- Removed - Stores a boolean indicating that the device has been removed.
- --*/
- typedef struct _SER16550_PARENT {
- SER16550_OBJECT Header;
- PDEVICE Device;
- ULONGLONG InterruptLine;
- ULONGLONG InterruptVector;
- BOOL InterruptResourcesFound;
- HANDLE InterruptHandle;
- KSPIN_LOCK InterruptLock;
- SER16550_VARIANT Variant;
- USHORT VendorId;
- USHORT DeviceId;
- PSER16550_CHILD ChildObjects;
- PDEVICE *ChildDevices;
- UINTN ChildCount;
- ULONG RegisterShift;
- ULONG BaseBaud;
- BOOL Removed;
- } SER16550_PARENT, *PSER16550_PARENT;
- /*++
- Structure Description:
- This structure stores information about a 16550 port.
- Members:
- Header - Store the common 16550 object header.
- Parent - Stores a pointer to the parent structure.
- Read8 - Stores a pointer to a function used to perform an 8-bit register
- read.
- Write8 - Stores a pointer to a function used to perform an 8-bit register
- write.
- Index - Stores the index of this child into the parent.
- PhysicalAddress - Stores the base physical address of the register region,
- if the UART is memory mapped.
- MappedAddress - Stores the virtual address of the register region, if the
- UART is memory mapped.
- MappedSize - Stores the size of the mapping.
- IoPortAddress - Stores the I/O port address of the registers if the region
- is I/O port based.
- Terminal - Stores a pointer to the terminal device.
- TransmitBuffer - Stores the ring buffer of bytes waiting to be sent.
- TransmitStart - Stores the index of the next byte the hardware will send
- out.
- TransmitEnd - Stores the index of the next byte to be added to the buffer.
- TransmitSize - Stores the size of the transmit buffer in bytes.
- TransmitFifoSize - Stores the size of the hardware transmit FIFO in bytes.
- ReceiveBuffer - Stores the buffer of received bytes.
- ReceiveStart - Stores the index of the next byte software should read.
- ReceiveEnd - Stores the index of the next byte the hardware will add.
- ReceiveSize - Stores the size of the receive buffer in bytes.
- ControlFlags - Stores the currently set control flags. See
- TERMINAL_CONTROL_* definitions.
- BaudRate - Stores the currently set baud rate. This may be zero if the
- device is not configured.
- RegisterOffset - Stores the offset in bytes from the begining of the
- register region to the 16550ish registers.
- RegisterShift - Stores the number of bits to shift left to get from a 16550
- register to an actual device register.
- TransmitLock - Stores a pointer to the lock serializing access to the
- transmit buffer.
- ReceiveLock - Stores a pointer to the lock serializing access to the
- receive buffer.
- TransmitReady - Stores an event that is signaled when the UART can accept
- more outgoing data.
- ReceiveReady - Stores an event that is signaled when this receive buffer
- has data.
- InterruptWorkPending - Stores a boolean indicating that the interrupt
- worker needs to process this child.
- ShouldUnmap - Stores a boolean indicating that this child owns the mapping
- and should unmap it to clean up.
- InterruptEnable - Stores a shadow copy of the interrupt enable register.
- --*/
- struct _SER16550_CHILD {
- SER16550_OBJECT Header;
- PSER16550_PARENT Parent;
- PSER16550_READ8 Read8;
- PSER16550_WRITE8 Write8;
- UINTN Index;
- PRESOURCE_ALLOCATION Resource;
- PHYSICAL_ADDRESS PhysicalAddress;
- PVOID MappedAddress;
- UINTN MappedSize;
- USHORT IoPortAddress;
- PIO_HANDLE Terminal;
- PUCHAR TransmitBuffer;
- UINTN TransmitStart;
- UINTN TransmitEnd;
- UINTN TransmitSize;
- UINTN TransmitFifoSize;
- PUCHAR ReceiveBuffer;
- UINTN ReceiveStart;
- UINTN ReceiveEnd;
- UINTN ReceiveSize;
- LONG ControlFlags;
- ULONG BaudRate;
- ULONG RegisterOffset;
- ULONG RegisterShift;
- PQUEUED_LOCK TransmitLock;
- PQUEUED_LOCK ReceiveLock;
- PKEVENT TransmitReady;
- PKEVENT ReceiveReady;
- BOOL InterruptWorkPending;
- BOOL ShouldUnmap;
- UCHAR InterruptEnable;
- };
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- KSTATUS
- Ser16550AddDevice (
- PVOID Driver,
- PSTR DeviceId,
- PSTR ClassId,
- PSTR CompatibleIds,
- PVOID DeviceToken
- );
- VOID
- Ser16550DispatchStateChange (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- );
- VOID
- Ser16550DispatchOpen (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- );
- VOID
- Ser16550DispatchClose (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- );
- VOID
- Ser16550DispatchIo (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- );
- VOID
- Ser16550DispatchSystemControl (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- );
- VOID
- Ser16550DispatchUserControl (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- );
- INTERRUPT_STATUS
- Ser16550InterruptService (
- PVOID Context
- );
- INTERRUPT_STATUS
- Ser16550InterruptServiceWorker (
- PVOID Context
- );
- KSTATUS
- Ser16550pParentProcessResourceRequirements (
- PIRP Irp,
- PSER16550_PARENT Device
- );
- KSTATUS
- Ser16550pParentStartDevice (
- PIRP Irp,
- PSER16550_PARENT Device
- );
- KSTATUS
- Ser16550pInitializeChildrenGeneric (
- PSER16550_PARENT Parent,
- PRESOURCE_ALLOCATION_LIST AllocationList
- );
- KSTATUS
- Ser16550pInitializeChildrenOxford (
- PSER16550_PARENT Parent,
- PRESOURCE_ALLOCATION_LIST AllocationList
- );
- KSTATUS
- Ser16550pInitializeChild (
- PSER16550_PARENT Parent,
- UINTN Index
- );
- VOID
- Ser16550pParentEnumerateChildren (
- PIRP Irp,
- PSER16550_PARENT Device
- );
- VOID
- Ser16550pChildStartDevice (
- PIRP Irp,
- PSER16550_CHILD Device
- );
- VOID
- Ser16550pChildDispatchSystemControl (
- PIRP Irp,
- PSER16550_CHILD Device
- );
- VOID
- Ser16550pChildDispatchUserControl (
- PIRP Irp,
- PSER16550_CHILD Device
- );
- VOID
- Ser16550pStartTransmit (
- PSER16550_CHILD Device
- );
- VOID
- Ser16550pStopTransmit (
- PSER16550_CHILD Device
- );
- KSTATUS
- Ser16550pConfigureDevice (
- PSER16550_CHILD Device,
- ULONG TerminalControlFlags,
- ULONG BaudRate
- );
- ULONG
- Ser16550pGetFifoSize (
- PSER16550_CHILD Device
- );
- VOID
- Ser16550pAddReference (
- PSER16550_OBJECT Object
- );
- VOID
- Ser16550pReleaseReference (
- PSER16550_OBJECT Object
- );
- VOID
- Ser16550pDestroyDevice (
- PSER16550_OBJECT Object
- );
- UCHAR
- Ser16550pReadIo8 (
- PSER16550_CHILD Device,
- SER16550_REGISTER Register
- );
- VOID
- Ser16550pWriteIo8 (
- PSER16550_CHILD Device,
- SER16550_REGISTER Register,
- UCHAR Value
- );
- UCHAR
- Ser16550pReadMemory8 (
- PSER16550_CHILD Device,
- SER16550_REGISTER Register
- );
- VOID
- Ser16550pWriteMemory8 (
- PSER16550_CHILD Device,
- SER16550_REGISTER Register,
- UCHAR Value
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- PDRIVER Ser16550Driver = NULL;
- //
- // ------------------------------------------------------------------ Functions
- //
- KSTATUS
- DriverEntry (
- PDRIVER Driver
- )
- /*++
- Routine Description:
- This routine is the entry point for the 16550 driver. It registers its
- other dispatch functions, and performs driver-wide initialization.
- Arguments:
- Driver - Supplies a pointer to the driver object.
- Return Value:
- STATUS_SUCCESS on success.
- Failure code on error.
- --*/
- {
- DRIVER_FUNCTION_TABLE FunctionTable;
- KSTATUS Status;
- Ser16550Driver = Driver;
- RtlZeroMemory(&FunctionTable, sizeof(DRIVER_FUNCTION_TABLE));
- FunctionTable.Version = DRIVER_FUNCTION_TABLE_VERSION;
- FunctionTable.AddDevice = Ser16550AddDevice;
- FunctionTable.DispatchStateChange = Ser16550DispatchStateChange;
- FunctionTable.DispatchOpen = Ser16550DispatchOpen;
- FunctionTable.DispatchClose = Ser16550DispatchClose;
- FunctionTable.DispatchIo = Ser16550DispatchIo;
- FunctionTable.DispatchSystemControl = Ser16550DispatchSystemControl;
- FunctionTable.DispatchUserControl = Ser16550DispatchUserControl;
- Status = IoRegisterDriverFunctions(Driver, &FunctionTable);
- return Status;
- }
- KSTATUS
- Ser16550AddDevice (
- PVOID Driver,
- PSTR DeviceId,
- PSTR ClassId,
- PSTR CompatibleIds,
- PVOID DeviceToken
- )
- /*++
- Routine Description:
- This routine is called when a device is detected for which the 16550 device
- acts as the function driver. The driver will attach itself to the stack.
- Arguments:
- Driver - Supplies a pointer to the driver being called.
- DeviceId - Supplies a pointer to a string with the device ID.
- ClassId - Supplies a pointer to a string containing the device's class ID.
- CompatibleIds - Supplies a pointer to a string containing device IDs
- that would be compatible with this device.
- DeviceToken - Supplies an opaque token that the driver can use to identify
- the device in the system. This token should be used when attaching to
- the stack.
- Return Value:
- STATUS_SUCCESS on success.
- Failure code if the driver was unsuccessful in attaching itself.
- --*/
- {
- ULONG ItemsScanned;
- PSER16550_PARENT Parent;
- ULONG PciDeviceId;
- ULONG PciVendorId;
- KSTATUS Status;
- Parent = MmAllocateNonPagedPool(sizeof(SER16550_PARENT),
- SER16550_ALLOCATION_TAG);
- if (Parent == NULL) {
- return STATUS_INSUFFICIENT_RESOURCES;
- }
- RtlZeroMemory(Parent, sizeof(SER16550_PARENT));
- Parent->Header.Type = Ser16550ObjectParent;
- Parent->Device = DeviceToken;
- Parent->BaseBaud = SER16550_DEFAULT_BASE_BAUD;
- Parent->Variant = Ser16550VariantGeneric;
- Parent->InterruptHandle = INVALID_HANDLE;
- KeInitializeSpinLock(&(Parent->InterruptLock));
- //
- // Detect variants by PCI vendor and device ID.
- //
- Status = RtlStringScan(DeviceId,
- -1,
- SER16550_PCI_DEVICE_ID_FORMAT,
- sizeof(SER16550_PCI_DEVICE_ID_FORMAT),
- CharacterEncodingDefault,
- &ItemsScanned,
- &PciVendorId,
- &PciDeviceId);
- if ((KSUCCESS(Status)) && (ItemsScanned == 2)) {
- Parent->VendorId = PciVendorId;
- Parent->DeviceId = PciDeviceId;
- switch (PciVendorId) {
- case SER16550_VENDOR_INTEL:
- if (PciDeviceId == SER16550_INTEL_QUARK) {
- Parent->Variant = Ser16550VariantQuark;
- Parent->RegisterShift =
- SER16550_INTEL_QUARK_UART_REGISTER_SHIFT;
- Parent->BaseBaud = SER16550_INTEL_QUARK_UART_BASE_BAUD;
- }
- break;
- case SER16550_VENDOR_OXFORD:
- Parent->Variant = Ser16550VariantOxford;
- break;
- default:
- break;
- }
- }
- Status = IoAttachDriverToDevice(Driver, DeviceToken, Parent);
- if (!KSUCCESS(Status)) {
- goto AddDeviceEnd;
- }
- AddDeviceEnd:
- if (!KSUCCESS(Status)) {
- if (Parent != NULL) {
- MmFreePagedPool(Parent);
- }
- }
- return Status;
- }
- VOID
- Ser16550DispatchStateChange (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- )
- /*++
- Routine Description:
- This routine handles State Change IRPs.
- Arguments:
- Irp - Supplies a pointer to the I/O request packet.
- DeviceContext - Supplies the context pointer supplied by the driver when it
- attached itself to the driver stack. Presumably this pointer contains
- driver-specific device context.
- IrpContext - Supplies the context pointer supplied by the driver when
- the IRP was created.
- Return Value:
- None.
- --*/
- {
- PSER16550_CHILD Child;
- PSER16550_OBJECT Object;
- PSER16550_PARENT Parent;
- KSTATUS Status;
- ASSERT(Irp->MajorCode == IrpMajorStateChange);
- if ((Irp->Direction == IrpUp) && (!KSUCCESS(IoGetIrpStatus(Irp)))) {
- return;
- }
- Object = DeviceContext;
- switch (Object->Type) {
- //
- // In this case the driver is the functional driver for the controller.
- //
- case Ser16550ObjectParent:
- Parent = PARENT_STRUCTURE(Object, SER16550_PARENT, Header);
- switch (Irp->MinorCode) {
- case IrpMinorQueryResources:
- //
- // On the way up, filter the resource requirements to add interrupt
- // vectors to any lines.
- //
- if (Irp->Direction == IrpUp) {
- Status = Ser16550pParentProcessResourceRequirements(Irp,
- Parent);
- if (!KSUCCESS(Status)) {
- IoCompleteIrp(Ser16550Driver, Irp, Status);
- }
- }
- break;
- case IrpMinorStartDevice:
- //
- // Attempt to fire the thing up if the bus has already started it.
- //
- if (Irp->Direction == IrpUp) {
- Status = Ser16550pParentStartDevice(Irp, Parent);
- if (!KSUCCESS(Status)) {
- IoCompleteIrp(Ser16550Driver, Irp, Status);
- }
- }
- break;
- case IrpMinorQueryChildren:
- if (Irp->Direction == IrpUp) {
- Ser16550pParentEnumerateChildren(Irp, Parent);
- }
- break;
- case IrpMinorRemoveDevice:
- Ser16550pReleaseReference(Object);
- IoCompleteIrp(Ser16550Driver, Irp, STATUS_SUCCESS);
- break;
- default:
- break;
- }
- break;
- //
- // In this case the object is the bus driver for an individual port.
- //
- case Ser16550ObjectChild:
- Child = PARENT_STRUCTURE(Object, SER16550_CHILD, Header);
- switch (Irp->MinorCode) {
- case IrpMinorQueryResources:
- IoCompleteIrp(Ser16550Driver, Irp, STATUS_SUCCESS);
- break;
- case IrpMinorStartDevice:
- Ser16550pChildStartDevice(Irp, Child);
- break;
- case IrpMinorQueryChildren:
- IoCompleteIrp(Ser16550Driver, Irp, STATUS_SUCCESS);
- break;
- case IrpMinorRemoveDevice:
- ASSERT(Child->Parent->Removed != FALSE);
- KeAcquireQueuedLock(Child->ReceiveLock);
- KeAcquireQueuedLock(Child->TransmitLock);
- if (Child->Terminal != NULL) {
- IoTerminalSetDevice(Child->Terminal, NULL);
- IoClose(Child->Terminal);
- Child->Terminal = NULL;
- }
- if (Child->TransmitReady != NULL) {
- KeSignalEvent(Child->TransmitReady, SignalOptionSignalAll);
- }
- if (Child->ReceiveReady != NULL) {
- KeSignalEvent(Child->ReceiveReady, SignalOptionSignalAll);
- }
- KeReleaseQueuedLock(Child->ReceiveLock);
- KeReleaseQueuedLock(Child->TransmitLock);
- Ser16550pReleaseReference(Object);
- IoCompleteIrp(Ser16550Driver, Irp, STATUS_SUCCESS);
- break;
- default:
- break;
- }
- break;
- default:
- ASSERT(FALSE);
- break;
- }
- return;
- }
- VOID
- Ser16550DispatchOpen (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- )
- /*++
- Routine Description:
- This routine handles Open IRPs.
- Arguments:
- Irp - Supplies a pointer to the I/O request packet.
- DeviceContext - Supplies the context pointer supplied by the driver when it
- attached itself to the driver stack. Presumably this pointer contains
- driver-specific device context.
- IrpContext - Supplies the context pointer supplied by the driver when
- the IRP was created.
- Return Value:
- None.
- --*/
- {
- PSER16550_OBJECT Object;
- Object = DeviceContext;
- if (Object->Type == Ser16550ObjectChild) {
- Ser16550pAddReference(Object);
- Irp->U.Open.DeviceContext =
- PARENT_STRUCTURE(Object, SER16550_CHILD, Header);
- IoCompleteIrp(Ser16550Driver, Irp, STATUS_SUCCESS);
- }
- return;
- }
- VOID
- Ser16550DispatchClose (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- )
- /*++
- Routine Description:
- This routine handles Close IRPs.
- Arguments:
- Irp - Supplies a pointer to the I/O request packet.
- DeviceContext - Supplies the context pointer supplied by the driver when it
- attached itself to the driver stack. Presumably this pointer contains
- driver-specific device context.
- IrpContext - Supplies the context pointer supplied by the driver when
- the IRP was created.
- Return Value:
- None.
- --*/
- {
- PSER16550_CHILD Child;
- Child = Irp->U.Close.DeviceContext;
- ASSERT(Child->Header.Type == Ser16550ObjectChild);
- Ser16550pReleaseReference(&(Child->Header));
- IoCompleteIrp(Ser16550Driver, Irp, STATUS_SUCCESS);
- return;
- }
- VOID
- Ser16550DispatchIo (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- )
- /*++
- Routine Description:
- This routine handles I/O IRPs.
- Arguments:
- Irp - Supplies a pointer to the I/O request packet.
- DeviceContext - Supplies the context pointer supplied by the driver when it
- attached itself to the driver stack. Presumably this pointer contains
- driver-specific device context.
- IrpContext - Supplies the context pointer supplied by the driver when
- the IRP was created.
- Return Value:
- None.
- --*/
- {
- UINTN BytesRemaining;
- PSER16550_CHILD Child;
- UINTN CopySize;
- UINTN CopyStart;
- PIO_BUFFER IoBuffer;
- UINTN IoBufferOffset;
- PQUEUED_LOCK Lock;
- UINTN Next;
- RUNLEVEL OldRunLevel;
- PSER16550_PARENT Parent;
- UINTN ReceiveEnd;
- UINTN ReceiveStart;
- KSTATUS Status;
- UINTN TransmitEnd;
- UINTN TransmitStart;
- ASSERT(Irp->Direction == IrpDown);
- Child = Irp->U.ReadWrite.DeviceContext;
- IoBuffer = Irp->U.ReadWrite.IoBuffer;
- IoBufferOffset = 0;
- BytesRemaining = Irp->U.ReadWrite.IoSizeInBytes;
- Parent = Child->Parent;
- ASSERT(Child->Header.Type == Ser16550ObjectChild);
- if (Irp->MinorCode == IrpMinorIoRead) {
- Lock = Child->ReceiveLock;
- } else {
- ASSERT(Irp->MinorCode == IrpMinorIoWrite);
- Lock = Child->TransmitLock;
- }
- KeAcquireQueuedLock(Lock);
- if (Irp->MinorCode == IrpMinorIoWrite) {
- while (BytesRemaining != 0) {
- if (Parent->Removed != FALSE) {
- Status = STATUS_DEVICE_NOT_CONNECTED;
- goto DispatchIoEnd;
- }
- TransmitEnd = Child->TransmitEnd;
- TransmitStart = Child->TransmitStart;
- if (TransmitEnd >= TransmitStart) {
- CopySize = Child->TransmitSize - TransmitEnd;
- } else {
- CopySize = TransmitStart - TransmitEnd;
- }
- //
- // If the transmit buffer is full, then wait until a byte can be
- // added.
- //
- if (CopySize == 0) {
- //
- // If the transmitter isn't working at all, kick off the
- // process.
- //
- OldRunLevel = IoRaiseToInterruptRunLevel(
- Parent->InterruptHandle);
- KeAcquireSpinLock(&(Parent->InterruptLock));
- Ser16550pStartTransmit(Child);
- KeReleaseSpinLock(&(Parent->InterruptLock));
- KeLowerRunLevel(OldRunLevel);
- KeSignalEvent(Child->TransmitReady, SignalOptionUnsignal);
- KeReleaseQueuedLock(Lock);
- KeWaitForEvent(Child->TransmitReady,
- FALSE,
- WAIT_TIME_INDEFINITE);
- KeAcquireQueuedLock(Lock);
- continue;
- }
- if (CopySize > BytesRemaining) {
- CopySize = BytesRemaining;
- }
- CopyStart = TransmitEnd;
- Next = CopyStart + CopySize;
- ASSERT(Next <= Child->TransmitSize);
- if (Next == Child->TransmitSize) {
- Next = 0;
- }
- if (Next == TransmitStart) {
- CopySize -= 1;
- if (Next == 0) {
- Next = Child->TransmitSize - 1;
- } else {
- Next -= 1;
- }
- }
- Status = MmCopyIoBufferData(IoBuffer,
- &(Child->TransmitBuffer[CopyStart]),
- IoBufferOffset,
- CopySize,
- FALSE);
- if (!KSUCCESS(Status)) {
- goto DispatchIoEnd;
- }
- IoBufferOffset += CopySize;
- BytesRemaining -= CopySize;
- Child->TransmitEnd = Next;
- }
- //
- // Kick off the transfer if needed.
- //
- OldRunLevel = IoRaiseToInterruptRunLevel(Parent->InterruptHandle);
- KeAcquireSpinLock(&(Parent->InterruptLock));
- Ser16550pStartTransmit(Child);
- KeReleaseSpinLock(&(Parent->InterruptLock));
- KeLowerRunLevel(OldRunLevel);
- } else {
- ASSERT(Irp->MinorCode == IrpMinorIoRead);
- while (BytesRemaining != 0) {
- if (Child->Parent->Removed != FALSE) {
- Status = STATUS_DEVICE_NOT_CONNECTED;
- goto DispatchIoEnd;
- }
- ReceiveEnd = Child->ReceiveEnd;
- ReceiveStart = Child->ReceiveStart;
- if (ReceiveEnd > ReceiveStart) {
- CopySize = ReceiveEnd - ReceiveStart;
- } else {
- CopySize = Child->ReceiveSize - ReceiveStart;
- }
- //
- // Handle an empty receive buffer.
- //
- if (CopySize == 0) {
- //
- // If some bytes were read in, then return them now.
- //
- if (BytesRemaining != Irp->U.ReadWrite.IoSizeInBytes) {
- break;
- }
- //
- // Block waiting for more bytes to come in.
- //
- KeSignalEvent(Child->ReceiveReady, SignalOptionUnsignal);
- KeReleaseQueuedLock(Lock);
- KeWaitForEvent(Child->ReceiveReady,
- FALSE,
- WAIT_TIME_INDEFINITE);
- KeAcquireQueuedLock(Lock);
- continue;
- }
- CopyStart = ReceiveStart;
- if (CopySize > BytesRemaining) {
- CopySize = BytesRemaining;
- }
- ASSERT((CopySize < Child->ReceiveSize) &&
- (CopyStart + CopySize <= Child->ReceiveSize));
- Status = MmCopyIoBufferData(IoBuffer,
- &(Child->ReceiveBuffer[CopyStart]),
- IoBufferOffset,
- CopySize,
- TRUE);
- if (!KSUCCESS(Status)) {
- goto DispatchIoEnd;
- }
- IoBufferOffset += CopySize;
- BytesRemaining -= CopySize;
- CopyStart += CopySize;
- if (CopyStart == Child->ReceiveSize) {
- CopyStart = 0;
- }
- Child->ReceiveStart = CopyStart;
- }
- }
- Status = STATUS_SUCCESS;
- DispatchIoEnd:
- KeReleaseQueuedLock(Lock);
- Irp->U.ReadWrite.IoBytesCompleted = Irp->U.ReadWrite.IoSizeInBytes -
- BytesRemaining;
- IoCompleteIrp(Ser16550Driver, Irp, Status);
- return;
- }
- VOID
- Ser16550DispatchSystemControl (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- )
- /*++
- Routine Description:
- This routine handles System Control IRPs.
- Arguments:
- Irp - Supplies a pointer to the I/O request packet.
- DeviceContext - Supplies the context pointer supplied by the driver when it
- attached itself to the driver stack. Presumably this pointer contains
- driver-specific device context.
- IrpContext - Supplies the context pointer supplied by the driver when
- the IRP was created.
- Return Value:
- None.
- --*/
- {
- PSER16550_CHILD Child;
- ASSERT(Irp->MajorCode == IrpMajorSystemControl);
- Child = DeviceContext;
- switch (Child->Header.Type) {
- case Ser16550ObjectParent:
- break;
- case Ser16550ObjectChild:
- Ser16550pChildDispatchSystemControl(Irp, Child);
- break;
- default:
- ASSERT(FALSE);
- break;
- }
- return;
- }
- VOID
- Ser16550DispatchUserControl (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- )
- /*++
- Routine Description:
- This routine handles User Control IRPs.
- Arguments:
- Irp - Supplies a pointer to the I/O request packet.
- DeviceContext - Supplies the context pointer supplied by the driver when it
- attached itself to the driver stack. Presumably this pointer contains
- driver-specific device context.
- IrpContext - Supplies the context pointer supplied by the driver when
- the IRP was created.
- Return Value:
- None.
- --*/
- {
- PSER16550_CHILD Child;
- ASSERT(Irp->MajorCode == IrpMajorUserControl);
- Child = DeviceContext;
- switch (Child->Header.Type) {
- case Ser16550ObjectParent:
- break;
- case Ser16550ObjectChild:
- Ser16550pChildDispatchUserControl(Irp, Child);
- break;
- default:
- ASSERT(FALSE);
- break;
- }
- return;
- }
- INTERRUPT_STATUS
- Ser16550InterruptService (
- PVOID Context
- )
- /*++
- Routine Description:
- This routine implements the EHCI interrupt service routine.
- Arguments:
- Context - Supplies the context pointer given to the system when the
- interrupt was connected. In this case, this points to the EHCI
- controller.
- Return Value:
- Interrupt status.
- --*/
- {
- UCHAR Byte;
- PSER16550_CHILD Child;
- UINTN ChildIndex;
- ULONG Count;
- BOOL DidSomething;
- UCHAR InterruptRegister;
- INTERRUPT_STATUS InterruptStatus;
- UCHAR LineStatus;
- UINTN Next;
- PSER16550_PARENT Parent;
- InterruptStatus = InterruptStatusNotClaimed;
- Parent = Context;
- //
- // Loop over every serial port this interrupt services.
- //
- for (ChildIndex = 0; ChildIndex < Parent->ChildCount; ChildIndex += 1) {
- Child = &(Parent->ChildObjects[ChildIndex]);
- //
- // Skip invalid children.
- //
- if (Child->Header.Type != Ser16550ObjectChild) {
- continue;
- }
- //
- // Quickly exit if the UART is not interrupting.
- //
- InterruptRegister = SER16550_READ8(Child, Ser16550InterruptStatus);
- if ((InterruptRegister & SER16550_INTERRUPT_STATUS_NONE_PENDING) != 0) {
- continue;
- }
- InterruptStatus = InterruptStatusClaimed;
- do {
- DidSomething = FALSE;
- LineStatus = SER16550_READ8(Child, Ser16550LineStatus);
- if ((LineStatus & SER16550_LINE_STATUS_ERROR_MASK) != 0) {
- DidSomething = TRUE;
- //
- // TODO: Actually handle 16550 line status errors.
- //
- if ((LineStatus & SER16550_LINE_STATUS_OVERRUN_ERROR) != 0) {
- RtlDebugPrint("16550: Overrun Error.\n");
- } else if ((LineStatus &
- SER16550_LINE_STATUS_PARITY_ERROR) != 0) {
- RtlDebugPrint("16550: Parity Error.\n");
- } else if ((LineStatus &
- SER16550_LINE_STATUS_FRAMING_ERROR) != 0) {
- RtlDebugPrint("16550: Framing Error.\n");
- } else if ((LineStatus &
- SER16550_LINE_STATUS_FIFO_ERROR) != 0) {
- RtlDebugPrint("16550: Fifo Error.\n");
- }
- }
- //
- // Transmit more stuff if possible.
- //
- if ((LineStatus & SER16550_LINE_STATUS_TX_HOLDING_EMPTY) != 0) {
- KeAcquireSpinLock(&(Child->Parent->InterruptLock));
- for (Count = 0; Count < Child->TransmitFifoSize; Count += 1) {
- if (Child->TransmitStart == Child->TransmitEnd) {
- Ser16550pStopTransmit(Child);
- break;
- } else {
- Byte = Child->TransmitBuffer[Child->TransmitStart];
- SER16550_WRITE8(Child, Ser16550Data, Byte);
- Next = Child->TransmitStart + 1;
- if (Next == Child->TransmitSize) {
- Next = 0;
- }
- Child->TransmitStart = Next;
- DidSomething = TRUE;
- }
- }
- KeReleaseSpinLock(&(Child->Parent->InterruptLock));
- Child->InterruptWorkPending = TRUE;
- }
- //
- // Receive a byte data if possible.
- //
- if ((LineStatus & SER16550_LINE_STATUS_RX_MASK) != 0) {
- DidSomething = TRUE;
- //
- // TODO: Actually handle a 16550 break.
- //
- if ((LineStatus & SER16550_LINE_STATUS_BREAK) != 0) {
- RtlDebugPrint("16550: Break\n");
- } else if ((LineStatus & SER16550_LINE_STATUS_RX_READY) != 0) {
- Byte = SER16550_READ8(Child, Ser16550Data);
- Next = Child->ReceiveEnd + 1;
- if (Next == Child->ReceiveSize) {
- Next = 0;
- }
- if (Next == Child->ReceiveStart) {
- RtlDebugPrint("Uart RX Overflow\n");
- } else {
- Child->ReceiveBuffer[Child->ReceiveEnd] = Byte;
- Child->ReceiveEnd = Next;
- }
- }
- }
- } while (DidSomething != FALSE);
- }
- return InterruptStatus;
- }
- INTERRUPT_STATUS
- Ser16550InterruptServiceWorker (
- PVOID Context
- )
- /*++
- Routine Description:
- This routine processes interrupts for the 16550 UART at low level.
- Arguments:
- Context - Supplies a context pointer, which in this case points to the
- parent controller.
- Return Value:
- Interrupt status.
- --*/
- {
- UINTN BytesCompleted;
- PSER16550_CHILD Child;
- UINTN ChildIndex;
- INTERRUPT_STATUS InterruptStatus;
- PIO_BUFFER IoBuffer;
- UINTN Next;
- PSER16550_PARENT Parent;
- UINTN ReceiveEnd;
- UINTN ReceiveStart;
- UINTN Size;
- KSTATUS Status;
- Parent = Context;
- ASSERT(KeGetRunLevel() == RunLevelLow);
- InterruptStatus = InterruptStatusNotClaimed;
- //
- // Loop over every serial port this interrupt services.
- //
- for (ChildIndex = 0; ChildIndex < Parent->ChildCount; ChildIndex += 1) {
- Child = &(Parent->ChildObjects[ChildIndex]);
- if (Child->InterruptWorkPending == FALSE) {
- continue;
- }
- Child->InterruptWorkPending = FALSE;
- InterruptStatus = InterruptStatusClaimed;
- //
- // Signal the transmit ready event if some data was processed by now.
- //
- KeAcquireQueuedLock(Child->TransmitLock);
- Next = Child->TransmitEnd + 1;
- if (Next == Child->TransmitSize) {
- Next = 0;
- }
- if (Next != Child->TransmitStart) {
- KeSignalEvent(Child->TransmitReady, SignalOptionSignalAll);
- }
- KeReleaseQueuedLock(Child->TransmitLock);
- //
- // If there's a terminal, feed the terminal. Otherwise, maintain the
- // event.
- //
- KeAcquireQueuedLock(Child->ReceiveLock);
- ReceiveEnd = Child->ReceiveEnd;
- ReceiveStart = Child->ReceiveStart;
- while (ReceiveStart != ReceiveEnd) {
- if (ReceiveEnd >= ReceiveStart) {
- Size = ReceiveEnd - ReceiveStart;
- } else {
- Size = Child->ReceiveSize - ReceiveStart;
- }
- Status = MmCreateIoBuffer(Child->ReceiveBuffer + ReceiveStart,
- Size,
- IO_BUFFER_FLAG_KERNEL_MODE_DATA,
- &IoBuffer);
- BytesCompleted = 0;
- if (KSUCCESS(Status)) {
- if (Child->Terminal != NULL) {
- Status = IoWrite(Child->Terminal,
- IoBuffer,
- Size,
- 0,
- 0,
- &BytesCompleted);
- } else {
- KeSignalEvent(Child->ReceiveReady, SignalOptionSignalAll);
- }
- MmFreeIoBuffer(IoBuffer);
- if (!KSUCCESS(Status)) {
- RtlDebugPrint("Ser16550: Failed terminal write: %x\n",
- Status);
- }
- }
- ASSERT(ReceiveStart + BytesCompleted <= Child->ReceiveSize);
- ReceiveStart += BytesCompleted;
- if (ReceiveStart == Child->ReceiveSize) {
- ReceiveStart = 0;
- }
- Child->ReceiveStart = ReceiveStart;
- if (BytesCompleted == 0) {
- break;
- }
- ReceiveEnd = Child->ReceiveEnd;
- ReceiveStart = Child->ReceiveStart;
- }
- KeReleaseQueuedLock(Child->ReceiveLock);
- }
- return InterruptStatus;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- KSTATUS
- Ser16550pParentProcessResourceRequirements (
- PIRP Irp,
- PSER16550_PARENT Device
- )
- /*++
- Routine Description:
- This routine filters through the resource requirements presented by the
- bus for a 16550 parent device. It adds an interrupt vector requirement for
- any interrupt line requested.
- Arguments:
- Irp - Supplies a pointer to the I/O request packet.
- Device - Supplies a pointer to this parent device.
- Return Value:
- Status code.
- --*/
- {
- PRESOURCE_CONFIGURATION_LIST Requirements;
- KSTATUS Status;
- RESOURCE_REQUIREMENT VectorRequirement;
- ASSERT((Irp->MajorCode == IrpMajorStateChange) &&
- (Irp->MinorCode == IrpMinorQueryResources));
- //
- // Initialize a nice interrupt vector requirement in preparation.
- //
- RtlZeroMemory(&VectorRequirement, sizeof(RESOURCE_REQUIREMENT));
- VectorRequirement.Type = ResourceTypeInterruptVector;
- VectorRequirement.Minimum = 0;
- VectorRequirement.Maximum = -1;
- VectorRequirement.Length = 1;
- Requirements = Irp->U.QueryResources.ResourceRequirements;
- Status = IoCreateAndAddInterruptVectorsForLines(Requirements,
- &VectorRequirement);
- if (!KSUCCESS(Status)) {
- goto ParentProcessResourceRequirementsEnd;
- }
- ParentProcessResourceRequirementsEnd:
- return Status;
- }
- KSTATUS
- Ser16550pParentStartDevice (
- PIRP Irp,
- PSER16550_PARENT Device
- )
- /*++
- Routine Description:
- This routine starts up the 16550 controller.
- Arguments:
- Irp - Supplies a pointer to the I/O request packet.
- Device - Supplies a pointer to this 16550 device.
- Return Value:
- Status code.
- --*/
- {
- PRESOURCE_ALLOCATION Allocation;
- PRESOURCE_ALLOCATION_LIST AllocationList;
- UINTN ChildCount;
- IO_CONNECT_INTERRUPT_PARAMETERS Connect;
- PRESOURCE_ALLOCATION LineAllocation;
- KSTATUS Status;
- ChildCount = 0;
- //
- // Loop through the allocated resources to get the interrupt and count the
- // number of BARs.
- //
- AllocationList = Irp->U.StartDevice.ProcessorLocalResources;
- Allocation = IoGetNextResourceAllocation(AllocationList, NULL);
- while (Allocation != NULL) {
- //
- // If the resource is an interrupt vector, then it should have an
- // owning interrupt line allocation.
- //
- if (Allocation->Type == ResourceTypeInterruptVector) {
- //
- // Currently only one interrupt resource is expected.
- //
- ASSERT(Device->InterruptResourcesFound == FALSE);
- ASSERT(Allocation->OwningAllocation != NULL);
- //
- // Save the line and vector number.
- //
- LineAllocation = Allocation->OwningAllocation;
- Device->InterruptLine = LineAllocation->Allocation;
- Device->InterruptVector = Allocation->Allocation;
- Device->InterruptResourcesFound = TRUE;
- } else if (Allocation->Type == ResourceTypePhysicalAddressSpace) {
- ChildCount += 1;
- } else if (Allocation->Type == ResourceTypeIoPort) {
- ChildCount += 1;
- }
- //
- // Get the next allocation in the list.
- //
- Allocation = IoGetNextResourceAllocation(AllocationList, Allocation);
- }
- //
- // Some variants override the child count.
- //
- switch (Device->Variant) {
- case Ser16550VariantQuark:
- ChildCount = 1;
- break;
- case Ser16550VariantOxford:
- //
- // Oxford devices just have a single UART, except for a couple
- // (specified by the mode bits encoded in the device ID) that have two.
- //
- ASSERT(Device->VendorId == SER16550_VENDOR_OXFORD);
- ChildCount = 1;
- if (SER16550_OXFORD_DUAL_UARTS(Device->DeviceId) != FALSE) {
- ChildCount = 2;
- }
- break;
- default:
- break;
- }
- if (ChildCount == 0) {
- Status = STATUS_NOT_CONFIGURED;
- goto ParentStartDeviceEnd;
- }
- //
- // Allocate the child arrays.
- //
- if (ChildCount != Device->ChildCount) {
- ASSERT(Device->ChildCount == 0);
- Device->ChildDevices = MmAllocatePagedPool(ChildCount * sizeof(PDEVICE),
- SER16550_ALLOCATION_TAG);
- if (Device->ChildDevices == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto ParentStartDeviceEnd;
- }
- RtlZeroMemory(Device->ChildDevices, ChildCount * sizeof(PDEVICE));
- Device->ChildObjects = MmAllocatePagedPool(
- ChildCount * sizeof(SER16550_CHILD),
- SER16550_ALLOCATION_TAG);
- if (Device->ChildObjects == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto ParentStartDeviceEnd;
- }
- RtlZeroMemory(Device->ChildObjects,
- ChildCount * sizeof(SER16550_CHILD));
- Device->ChildCount = ChildCount;
- }
- //
- // Initialize the child devices with their correct resources.
- //
- switch (Device->Variant) {
- case Ser16550VariantOxford:
- Status = Ser16550pInitializeChildrenOxford(Device, AllocationList);
- break;
- case Ser16550VariantQuark:
- case Ser16550VariantGeneric:
- Status = Ser16550pInitializeChildrenGeneric(Device, AllocationList);
- break;
- default:
- ASSERT(FALSE);
- Status = STATUS_INVALID_CONFIGURATION;
- }
- if (!KSUCCESS(Status)) {
- goto ParentStartDeviceEnd;
- }
- //
- // Attempt to connect the interrupt.
- //
- if ((Device->InterruptResourcesFound != FALSE) &&
- (Device->InterruptHandle == INVALID_HANDLE)) {
- RtlZeroMemory(&Connect, sizeof(IO_CONNECT_INTERRUPT_PARAMETERS));
- Connect.Version = IO_CONNECT_INTERRUPT_PARAMETERS_VERSION;
- Connect.Device = Irp->Device;
- Connect.LineNumber = Device->InterruptLine;
- Connect.Vector = Device->InterruptVector;
- Connect.InterruptServiceRoutine = Ser16550InterruptService;
- Connect.LowLevelServiceRoutine = Ser16550InterruptServiceWorker;
- Connect.Context = Device;
- Connect.Interrupt = &(Device->InterruptHandle);
- Status = IoConnectInterrupt(&Connect);
- if (!KSUCCESS(Status)) {
- goto ParentStartDeviceEnd;
- }
- }
- Status = STATUS_SUCCESS;
- ParentStartDeviceEnd:
- if (!KSUCCESS(Status)) {
- if (Device->InterruptHandle != INVALID_HANDLE) {
- IoDisconnectInterrupt(Device->InterruptHandle);
- Device->InterruptHandle = INVALID_HANDLE;
- }
- }
- return Status;
- }
- KSTATUS
- Ser16550pInitializeChildrenGeneric (
- PSER16550_PARENT Parent,
- PRESOURCE_ALLOCATION_LIST AllocationList
- )
- /*++
- Routine Description:
- This routine initializes the child device structures for a standard 16550
- UART device. In a standard device, each BAR is assumed to correspond to
- a UART, up to the number of children.
- Arguments:
- Parent - Supplies a pointer to the parent.
- AllocationList - Supplies a pointer to the resource allocation list.
- Return Value:
- Status code.
- --*/
- {
- PRESOURCE_ALLOCATION Allocation;
- UINTN ChildIndex;
- PSER16550_CHILD ChildObject;
- UINTN ReleaseCount;
- KSTATUS Status;
- Allocation = IoGetNextResourceAllocation(AllocationList, NULL);
- ChildIndex = 0;
- while (ChildIndex < Parent->ChildCount) {
- ASSERT(Allocation != NULL);
- //
- // For each BAR found, initialize a child device.
- //
- if ((Allocation->Type == ResourceTypePhysicalAddressSpace) ||
- (Allocation->Type == ResourceTypeIoPort)) {
- ChildObject = &(Parent->ChildObjects[ChildIndex]);
- Status = Ser16550pInitializeChild(Parent, ChildIndex);
- if (!KSUCCESS(Status)) {
- goto InitializeChildrenGenericEnd;
- }
- if (Allocation->Type == ResourceTypePhysicalAddressSpace) {
- ChildObject->MappedSize = Allocation->Length;
- ChildObject->PhysicalAddress = Allocation->Allocation;
- ChildObject->MappedAddress = MmMapPhysicalAddress(
- Allocation->Allocation,
- Allocation->Length,
- TRUE,
- FALSE,
- TRUE);
- if (ChildObject->MappedAddress == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto InitializeChildrenGenericEnd;
- }
- ChildObject->Read8 = Ser16550pReadMemory8;
- ChildObject->Write8 = Ser16550pWriteMemory8;
- ChildObject->ShouldUnmap = TRUE;
- } else {
- ChildObject->IoPortAddress = (USHORT)(Allocation->Allocation);
- ChildObject->Read8 = Ser16550pReadIo8;
- ChildObject->Write8 = Ser16550pWriteIo8;
- }
- ChildIndex += 1;
- }
- //
- // Get the next allocation in the list.
- //
- Allocation = IoGetNextResourceAllocation(AllocationList, Allocation);
- }
- Status = STATUS_SUCCESS;
- InitializeChildrenGenericEnd:
- if (!KSUCCESS(Status)) {
- ASSERT(ChildIndex != Parent->ChildCount);
- ReleaseCount = ChildIndex;
- for (ChildIndex = 0; ChildIndex <= ReleaseCount; ChildIndex += 1) {
- ASSERT(Parent->ChildObjects[ChildIndex].Header.ReferenceCount == 1);
- Ser16550pReleaseReference(
- &(Parent->ChildObjects[ChildIndex].Header));
- }
- }
- return Status;
- }
- KSTATUS
- Ser16550pInitializeChildrenOxford (
- PSER16550_PARENT Parent,
- PRESOURCE_ALLOCATION_LIST AllocationList
- )
- /*++
- Routine Description:
- This routine initializes the child device structures for an Oxford UART.
- Arguments:
- Parent - Supplies a pointer to the parent.
- AllocationList - Supplies a pointer to the resource allocation list.
- Return Value:
- Status code.
- --*/
- {
- PRESOURCE_ALLOCATION Allocation;
- UINTN ChildIndex;
- PSER16550_CHILD ChildObject;
- UINTN ReleaseCount;
- KSTATUS Status;
- //
- // Find the first BAR, which is where the single or dual UART resides.
- //
- Allocation = IoGetNextResourceAllocation(AllocationList, NULL);
- while (Allocation != NULL) {
- if ((Allocation->Type == ResourceTypePhysicalAddressSpace) ||
- (Allocation->Type == ResourceTypeIoPort)) {
- break;
- }
- //
- // Get the next allocation in the list.
- //
- Allocation = IoGetNextResourceAllocation(AllocationList, Allocation);
- }
- if (Allocation == NULL) {
- return STATUS_NOT_CONFIGURED;
- }
- //
- // If the BAR is an I/O port, then this is a legacy compatible controller.
- //
- if (Allocation->Type == ResourceTypeIoPort) {
- ChildIndex = 0;
- ChildObject = &(Parent->ChildObjects[0]);
- Status = Ser16550pInitializeChild(Parent, 0);
- if (!KSUCCESS(Status)) {
- goto InitializeChildrenGenericEnd;
- }
- ChildObject->IoPortAddress = (USHORT)(Allocation->Allocation);
- ChildObject->Read8 = Ser16550pReadIo8;
- ChildObject->Write8 = Ser16550pWriteIo8;
- //
- // This is a native UART.
- //
- } else {
- Parent->BaseBaud = SER16550_OXFORD_BASE_BAUD;
- for (ChildIndex = 0; ChildIndex < Parent->ChildCount; ChildIndex += 1) {
- ChildObject = &(Parent->ChildObjects[ChildIndex]);
- Status = Ser16550pInitializeChild(Parent, ChildIndex);
- if (!KSUCCESS(Status)) {
- goto InitializeChildrenGenericEnd;
- }
- ChildObject->MappedSize = Allocation->Length;
- ChildObject->PhysicalAddress = Allocation->Allocation;
- if (ChildIndex == 0) {
- ChildObject->MappedAddress = MmMapPhysicalAddress(
- Allocation->Allocation,
- Allocation->Length,
- TRUE,
- FALSE,
- TRUE);
- if (ChildObject->MappedAddress == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto InitializeChildrenGenericEnd;
- }
- ChildObject->ShouldUnmap = TRUE;
- } else {
- ChildObject->MappedAddress =
- Parent->ChildObjects[0].MappedAddress;
- }
- ChildObject->RegisterOffset = SER16550_OXFORD_UART_OFFSET +
- (ChildIndex *
- SER16550_OXFORD_UART_STRIDE);
- ChildObject->Read8 = Ser16550pReadMemory8;
- ChildObject->Write8 = Ser16550pWriteMemory8;
- }
- }
- Status = STATUS_SUCCESS;
- InitializeChildrenGenericEnd:
- if (!KSUCCESS(Status)) {
- ASSERT(ChildIndex != Parent->ChildCount);
- ReleaseCount = ChildIndex;
- for (ChildIndex = 0; ChildIndex <= ReleaseCount; ChildIndex += 1) {
- ASSERT(Parent->ChildObjects[ChildIndex].Header.ReferenceCount == 1);
- Ser16550pReleaseReference(
- &(Parent->ChildObjects[ChildIndex].Header));
- }
- }
- return Status;
- }
- KSTATUS
- Ser16550pInitializeChild (
- PSER16550_PARENT Parent,
- UINTN Index
- )
- /*++
- Routine Description:
- This routine creates the resources associated with a 16550 UART child.
- Arguments:
- Parent - Supplies a pointer to the parent.
- Index - Supplies the child index within the parent.
- Return Value:
- Status code.
- --*/
- {
- PSER16550_CHILD ChildObject;
- KSTATUS Status;
- ChildObject = &(Parent->ChildObjects[Index]);
- ChildObject->Header.Type = Ser16550ObjectChild;
- ChildObject->Header.ReferenceCount = 1;
- ChildObject->Parent = Parent;
- ChildObject->Index = Index;
- ChildObject->RegisterOffset = 0;
- ChildObject->RegisterShift = Parent->RegisterShift;
- if (ChildObject->TransmitBuffer == NULL) {
- ChildObject->TransmitBuffer = MmAllocateNonPagedPool(
- SER16550_DEFAULT_BUFFER_SIZE,
- SER16550_ALLOCATION_TAG);
- if (ChildObject->TransmitBuffer == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto InitializeChildEnd;
- }
- ChildObject->TransmitSize = SER16550_DEFAULT_BUFFER_SIZE;
- ChildObject->TransmitStart = 0;
- ChildObject->TransmitEnd = 0;
- }
- if (ChildObject->ReceiveBuffer == NULL) {
- ChildObject->ReceiveBuffer = MmAllocateNonPagedPool(
- SER16550_DEFAULT_BUFFER_SIZE,
- SER16550_ALLOCATION_TAG);
- if (ChildObject->ReceiveBuffer == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto InitializeChildEnd;
- }
- ChildObject->ReceiveSize = SER16550_DEFAULT_BUFFER_SIZE;
- ChildObject->ReceiveStart = 0;
- ChildObject->ReceiveEnd = 0;
- }
- if (ChildObject->TransmitLock == NULL) {
- ChildObject->TransmitLock = KeCreateQueuedLock();
- if (ChildObject->TransmitLock == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto InitializeChildEnd;
- }
- }
- if (ChildObject->ReceiveLock == NULL) {
- ChildObject->ReceiveLock = KeCreateQueuedLock();
- if (ChildObject->ReceiveLock == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto InitializeChildEnd;
- }
- }
- if (ChildObject->TransmitReady == NULL) {
- ChildObject->TransmitReady = KeCreateEvent(NULL);
- if (ChildObject->TransmitReady == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto InitializeChildEnd;
- }
- KeSignalEvent(ChildObject->TransmitReady,
- SignalOptionSignalAll);
- }
- if (ChildObject->ReceiveReady == NULL) {
- ChildObject->ReceiveReady = KeCreateEvent(NULL);
- if (ChildObject->ReceiveReady == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto InitializeChildEnd;
- }
- }
- Status = STATUS_SUCCESS;
- InitializeChildEnd:
- return Status;
- }
- VOID
- Ser16550pParentEnumerateChildren (
- PIRP Irp,
- PSER16550_PARENT Device
- )
- /*++
- Routine Description:
- This routine enumerates all ports in the serial controller.
- Arguments:
- Irp - Supplies a pointer to the I/O request packet.
- Device - Supplies a pointer to this 16550 device.
- Return Value:
- None.
- --*/
- {
- UINTN ChildIndex;
- CHAR DeviceId[SERIAL_PORT_DEVICE_ID_SIZE];
- KSTATUS Status;
- //
- // Create child devices for each child.
- //
- for (ChildIndex = 0; ChildIndex < Device->ChildCount; ChildIndex += 1) {
- ASSERT(Device->ChildObjects[ChildIndex].Header.Type ==
- Ser16550ObjectChild);
- if (Device->ChildDevices[ChildIndex] == NULL) {
- RtlPrintToString(DeviceId,
- SERIAL_PORT_DEVICE_ID_SIZE,
- CharacterEncodingDefault,
- SERIAL_PORT_DEVICE_ID_FORMAT,
- ChildIndex);
- Status = IoCreateDevice(Ser16550Driver,
- &(Device->ChildObjects[ChildIndex]),
- Device->Device,
- DeviceId,
- CHARACTER_CLASS_ID,
- NULL,
- &(Device->ChildDevices[ChildIndex]));
- if (!KSUCCESS(Status)) {
- goto ParentEnumerateChildrenEnd;
- }
- }
- }
- Status = IoMergeChildArrays(Irp,
- Device->ChildDevices,
- Device->ChildCount,
- SER16550_ALLOCATION_TAG);
- if (!KSUCCESS(Status)) {
- goto ParentEnumerateChildrenEnd;
- }
- ParentEnumerateChildrenEnd:
- IoCompleteIrp(Ser16550Driver, Irp, Status);
- return;
- }
- VOID
- Ser16550pChildStartDevice (
- PIRP Irp,
- PSER16550_CHILD Device
- )
- /*++
- Routine Description:
- This routine starts an individual 16550serial port.
- Arguments:
- Irp - Supplies a pointer to the I/O request packet.
- Device - Supplies a pointer to this 16550 device.
- Return Value:
- None.
- --*/
- {
- PIO_HANDLE DeviceHandle;
- PDEBUG_HANDOFF_DATA HandoffData;
- KSTATUS Status;
- DeviceHandle = NULL;
- //
- // Determine if this UART is being used by the kernel debug transport, and
- // fail to start up if it is (as the kernel debugger owns it).
- //
- Status = KdGetDeviceInformation(&HandoffData);
- if ((KSUCCESS(Status)) &&
- (HandoffData != NULL) &&
- (HandoffData->PortType == DEBUG_PORT_TYPE_SERIAL) &&
- ((HandoffData->PortSubType == DEBUG_PORT_SERIAL_16550) ||
- (HandoffData->PortSubType == DEBUG_PORT_SERIAL_16550_COMPATIBLE))) {
- if (HandoffData->Identifier == Device->PhysicalAddress) {
- Status = STATUS_RESOURCE_IN_USE;
- goto ChildStartDeviceEnd;
- }
- }
- //
- // Create the terminal object.
- //
- if (Device->Terminal == NULL) {
- Status = IoCreateTerminal(TRUE,
- NULL,
- NULL,
- NULL,
- 0,
- NULL,
- 0,
- IO_ACCESS_READ | IO_ACCESS_WRITE,
- OPEN_FLAG_NO_CONTROLLING_TERMINAL,
- TERMINAL_DEFAULT_PERMISSIONS,
- TERMINAL_DEFAULT_PERMISSIONS,
- &(Device->Terminal));
- if (!KSUCCESS(Status)) {
- goto ChildStartDeviceEnd;
- }
- //
- // Open a handle to this very device.
- //
- Status = IoOpenDevice(Irp->Device,
- IO_ACCESS_READ | IO_ACCESS_WRITE,
- 0,
- &DeviceHandle,
- NULL,
- NULL,
- NULL);
- if (!KSUCCESS(Status)) {
- goto ChildStartDeviceEnd;
- }
- //
- // Associate the hardware device with the terminal. The terminal now
- // owns the handle.
- //
- Status = IoTerminalSetDevice(Device->Terminal, DeviceHandle);
- if (!KSUCCESS(Status)) {
- goto ChildStartDeviceEnd;
- }
- DeviceHandle = NULL;
- }
- Status = STATUS_SUCCESS;
- ChildStartDeviceEnd:
- if (DeviceHandle != NULL) {
- IoClose(DeviceHandle);
- }
- if (!KSUCCESS(Status)) {
- if (Device->Terminal != NULL) {
- IoClose(Device->Terminal);
- Device->Terminal = NULL;
- }
- }
- IoCompleteIrp(Ser16550Driver, Irp, Status);
- return;
- }
- VOID
- Ser16550pChildDispatchSystemControl (
- PIRP Irp,
- PSER16550_CHILD Device
- )
- /*++
- Routine Description:
- This routine handles system control IRPs for the 16550 child device.
- Arguments:
- Irp - Supplies a pointer to the I/O request packet.
- Device - Supplies a pointer to this 16550 device.
- Return Value:
- None. The IRP will be completed appropriately.
- --*/
- {
- PVOID Context;
- PSYSTEM_CONTROL_FILE_OPERATION FileOperation;
- PSYSTEM_CONTROL_LOOKUP Lookup;
- PFILE_PROPERTIES Properties;
- ULONGLONG PropertiesFileSize;
- KSTATUS Status;
- Context = Irp->U.SystemControl.SystemContext;
- switch (Irp->MinorCode) {
- case IrpMinorSystemControlLookup:
- Lookup = (PSYSTEM_CONTROL_LOOKUP)Context;
- Status = STATUS_PATH_NOT_FOUND;
- if (Lookup->Root != FALSE) {
- //
- // Enable opening of the root as a character device.
- //
- Properties = &(Lookup->Properties);
- Properties->FileId = 0;
- Properties->Type = IoObjectCharacterDevice;
- Properties->HardLinkCount = 1;
- Properties->BlockSize = 0;
- Properties->BlockCount = 0;
- WRITE_INT64_SYNC(&(Properties->FileSize), 0);
- Status = STATUS_SUCCESS;
- }
- IoCompleteIrp(Ser16550Driver, Irp, Status);
- break;
- //
- // Fail if the properties being written are different.
- //
- case IrpMinorSystemControlWriteFileProperties:
- FileOperation = (PSYSTEM_CONTROL_FILE_OPERATION)Context;
- Properties = FileOperation->FileProperties;
- READ_INT64_SYNC(&(Properties->FileSize), &PropertiesFileSize);
- if ((Properties->FileId != 0) ||
- (Properties->Type != IoObjectCharacterDevice) ||
- (Properties->HardLinkCount != 1) ||
- (Properties->BlockSize != 0) ||
- (Properties->BlockCount != 0) ||
- (PropertiesFileSize != 0)) {
- Status = STATUS_NOT_SUPPORTED;
- } else {
- Status = STATUS_SUCCESS;
- }
- IoCompleteIrp(Ser16550Driver, Irp, Status);
- break;
- //
- // Do not support hard disk device truncation.
- //
- case IrpMinorSystemControlTruncate:
- IoCompleteIrp(Ser16550Driver, Irp, STATUS_NOT_SUPPORTED);
- break;
- //
- // Gather and return device information.
- //
- case IrpMinorSystemControlDeviceInformation:
- break;
- //
- // Send all pending output data.
- // TODO: Wait for all pending output data to be complete.
- //
- case IrpMinorSystemControlSynchronize:
- Status = STATUS_SUCCESS;
- IoCompleteIrp(Ser16550Driver, Irp, Status);
- break;
- //
- // Ignore everything unrecognized.
- //
- default:
- break;
- }
- return;
- }
- VOID
- Ser16550pChildDispatchUserControl (
- PIRP Irp,
- PSER16550_CHILD Device
- )
- /*++
- Routine Description:
- This routine handles user control IRPs for the 16550 child device.
- Arguments:
- Irp - Supplies a pointer to the I/O request packet.
- Device - Supplies a pointer to this 16550 device.
- Return Value:
- None. The IRP will be completed appropriately.
- --*/
- {
- TERMINAL_USER_CONTROL_CODE ControlCode;
- KSTATUS Status;
- TERMINAL_SETTINGS TerminalSettings;
- TERMINAL_SETTINGS_OLD TerminalSettingsOld;
- Status = STATUS_NOT_HANDLED;
- ControlCode = Irp->MinorCode;
- switch (ControlCode) {
- case TerminalControlSetAttributesFlush:
- //
- // Flush the input.
- //
- Device->ReceiveStart = Device->ReceiveEnd;
- //
- // Fall through.
- //
- case TerminalControlSetAttributesDrain:
- //
- // TODO: Flush the output.
- //
- //
- // Fall through.
- //
- case TerminalControlSetAttributes:
- if (Irp->U.UserControl.FromKernelMode != FALSE) {
- RtlCopyMemory(&TerminalSettings,
- Irp->U.UserControl.UserBuffer,
- sizeof(TERMINAL_SETTINGS));
- Status = STATUS_SUCCESS;
- } else {
- Status = MmCopyFromUserMode(&TerminalSettings,
- Irp->U.UserControl.UserBuffer,
- sizeof(TERMINAL_SETTINGS));
- if (!KSUCCESS(Status)) {
- break;
- }
- }
- if (TerminalSettings.InputSpeed != TerminalSettings.OutputSpeed) {
- Status = STATUS_NOT_SUPPORTED;
- break;
- }
- if ((TerminalSettings.ControlFlags != Device->ControlFlags) ||
- (TerminalSettings.OutputSpeed != Device->BaudRate)) {
- Status = Ser16550pConfigureDevice(Device,
- TerminalSettings.ControlFlags,
- TerminalSettings.OutputSpeed);
- if (!KSUCCESS(Status)) {
- break;
- }
- Device->ControlFlags = TerminalSettings.ControlFlags;
- Device->BaudRate = TerminalSettings.OutputSpeed;
- }
- break;
- case TerminalControlSetAttributesFlushOld:
- //
- // Flush the input.
- //
- Device->ReceiveStart = Device->ReceiveEnd;
- //
- // Fall through.
- //
- case TerminalControlSetAttributesDrainOld:
- //
- // TODO: Flush the output.
- //
- //
- // Fall through.
- //
- case TerminalControlSetAttributesOld:
- if (Irp->U.UserControl.FromKernelMode != FALSE) {
- RtlCopyMemory(&TerminalSettingsOld,
- Irp->U.UserControl.UserBuffer,
- sizeof(TERMINAL_SETTINGS_OLD));
- Status = STATUS_SUCCESS;
- } else {
- Status = MmCopyFromUserMode(&TerminalSettingsOld,
- Irp->U.UserControl.UserBuffer,
- sizeof(TERMINAL_SETTINGS_OLD));
- if (!KSUCCESS(Status)) {
- break;
- }
- }
- if (TerminalSettingsOld.ControlFlags != Device->ControlFlags) {
- Status = Ser16550pConfigureDevice(Device,
- TerminalSettingsOld.ControlFlags,
- Device->BaudRate);
- if (!KSUCCESS(Status)) {
- break;
- }
- Device->ControlFlags = TerminalSettingsOld.ControlFlags;
- }
- break;
- case TerminalControlSendBreak:
- //
- // TODO: Send a serial break.
- //
- break;
- case TerminalControlFlowControl:
- //
- // TODO: Handle serial flow control.
- //
- break;
- case TerminalControlFlush:
- //
- // TODO: Handle serial flush.
- //
- break;
- case TerminalControlGetModemStatus:
- //
- // TODO: Get serial modem status.
- //
- break;
- case TerminalControlOrModemStatus:
- //
- // TODO: Get serial control/modem status.
- //
- break;
- case TerminalControlClearModemStatus:
- //
- // TODO: Clear serial modem status.
- //
- break;
- case TerminalControlSetModemStatus:
- //
- // TODO: Set serial modem status.
- //
- break;
- case TerminalControlGetSoftCarrier:
- case TerminalControlSetSoftCarrier:
- //
- // TODO: Get/set serial soft carrier status.
- //
- break;
- case TerminalControlSendBreakPosix:
- case TerminalControlStartBreak:
- case TerminalControlStopBreak:
- //
- // TODO: Send a serial break.
- //
- Status = STATUS_SUCCESS;
- break;
- case TerminalControlGetAttributes:
- case TerminalControlGetAttributesOld:
- case TerminalControlSetExclusive:
- case TerminalControlClearExclusive:
- case TerminalControlGetOutputQueueSize:
- case TerminalControlGetInputQueueSize:
- case TerminalControlInsertInInputQueue:
- case TerminalControlGetWindowSize:
- case TerminalControlSetWindowSize:
- case TerminalControlRedirectLocalConsole:
- case TerminalControlSetPacketMode:
- case TerminalControlGiveUpControllingTerminal:
- case TerminalControlSetControllingTerminal:
- case TerminalControlGetProcessGroup:
- case TerminalControlSetProcessGroup:
- case TerminalControlGetCurrentSessionId:
- default:
- break;
- }
- if (Status != STATUS_NOT_HANDLED) {
- IoCompleteIrp(Ser16550Driver, Irp, Status);
- }
- return;
- }
- VOID
- Ser16550pStartTransmit (
- PSER16550_CHILD Device
- )
- /*++
- Routine Description:
- This routine starts transmission on the 16550 device.
- Arguments:
- Device - Supplies a pointer to the device.
- Return Value:
- None.
- --*/
- {
- if ((Device->InterruptEnable & SER16550_INTERRUPT_ENABLE_TX_EMPTY) == 0) {
- Device->InterruptEnable |= SER16550_INTERRUPT_ENABLE_TX_EMPTY;
- SER16550_WRITE8(Device,
- Ser16550InterruptEnable,
- Device->InterruptEnable);
- }
- return;
- }
- VOID
- Ser16550pStopTransmit (
- PSER16550_CHILD Device
- )
- /*++
- Routine Description:
- This routine stops transmission on the 16550 device.
- Arguments:
- Device - Supplies a pointer to the device.
- Return Value:
- None.
- --*/
- {
- if ((Device->InterruptEnable & SER16550_INTERRUPT_ENABLE_TX_EMPTY) != 0) {
- Device->InterruptEnable &= ~SER16550_INTERRUPT_ENABLE_TX_EMPTY;
- SER16550_WRITE8(Device,
- Ser16550InterruptEnable,
- Device->InterruptEnable);
- }
- return;
- }
- KSTATUS
- Ser16550pConfigureDevice (
- PSER16550_CHILD Device,
- ULONG TerminalControlFlags,
- ULONG BaudRate
- )
- /*++
- Routine Description:
- This routine configures the serial device, including baud rate, data bits,
- stop bits, and parity.
- Arguments:
- Device - Supplies a pointer to the device.
- TerminalControlFlags - Supplies the bitfield of terminal control flags
- governing parity, data width, and stop bits. See TERMINAL_CONTROL_*
- definitions.
- BaudRate - Supplies the requested baud rate.
- Return Value:
- Status code.
- --*/
- {
- ULONG CurrentBaud;
- ULONG Divisor;
- UCHAR Value;
- //
- // Compute the appropriate divisor.
- //
- Divisor = 1;
- if (BaudRate > Device->Parent->BaseBaud) {
- return STATUS_NOT_SUPPORTED;
- }
- Divisor = 1;
- while (TRUE) {
- CurrentBaud = Device->Parent->BaseBaud / Divisor;
- if ((CurrentBaud <= BaudRate) || (CurrentBaud == 0)) {
- break;
- }
- Divisor += 1;
- }
- if ((CurrentBaud == 0) || (Divisor > MAX_USHORT)) {
- return STATUS_NOT_SUPPORTED;
- }
- //
- // Disable all interrupts.
- //
- Device->InterruptEnable = 0;
- SER16550_WRITE8(Device, Ser16550InterruptEnable, Device->InterruptEnable);
- //
- // Set the divisor latch enable bit to get at the divisor registers.
- //
- Value = SER16550_LINE_CONTROL_DIVISOR_LATCH;
- SER16550_WRITE8(Device, Ser16550LineControl, Value);
- //
- // Write the computed divisor value.
- //
- SER16550_WRITE8(Device, Ser16550DivisorLow, (UCHAR)(Divisor & 0x00FF));
- SER16550_WRITE8(Device,
- Ser16550DivisorHigh,
- (UCHAR)((Divisor >> 8) & 0x00FF));
- //
- // Enable the FIFOs.
- //
- SER16550_WRITE8(Device, Ser16550LineControl, 0);
- Value = SER16550_FIFO_CONTROL_ENABLE;
- SER16550_WRITE8(Device, Ser16550FifoControl, Value);
- //
- // Figure out the appropriate line control register value.
- //
- Value = 0;
- switch (TerminalControlFlags & TERMINAL_CONTROL_CHARACTER_SIZE_MASK) {
- case TERMINAL_CONTROL_5_BITS_PER_CHARACTER:
- Value |= SER16550_LINE_CONTROL_5_DATA_BITS;
- break;
- case TERMINAL_CONTROL_6_BITS_PER_CHARACTER:
- Value |= SER16550_LINE_CONTROL_6_DATA_BITS;
- break;
- case TERMINAL_CONTROL_7_BITS_PER_CHARACTER:
- Value |= SER16550_LINE_CONTROL_7_DATA_BITS;
- break;
- case TERMINAL_CONTROL_8_BITS_PER_CHARACTER:
- Value |= SER16550_LINE_CONTROL_8_DATA_BITS;
- break;
- default:
- return STATUS_NOT_SUPPORTED;
- }
- if ((TerminalControlFlags & TERMINAL_CONTROL_2_STOP_BITS) != 0) {
- Value |= SER16550_LINE_CONTROL_2_STOP_BITS;
- }
- if ((TerminalControlFlags & TERMINAL_CONTROL_ENABLE_PARITY) != 0) {
- Value |= SER16550_LINE_CONTROL_PARITY_ENABLE |
- SER16550_LINE_CONTROL_SET_PARITY;
- if ((TerminalControlFlags & TERMINAL_CONTROL_ODD_PARITY) == 0) {
- Value |= SER16550_LINE_CONTROL_EVEN_PARITY;
- }
- }
- //
- // Write the line control, which also flips the divisor registers back to
- // their normal registers.
- //
- SER16550_WRITE8(Device, Ser16550LineControl, Value);
- //
- // Initialize the modem control register, which includes flow control
- // (currently disabled).
- //
- Value = 0;
- SER16550_WRITE8(Device, Ser16550ModemControl, Value);
- //
- // Initialize the FIFO size.
- //
- Device->TransmitFifoSize = Ser16550pGetFifoSize(Device);
- //
- // Enable interrupts.
- //
- Device->InterruptEnable = SER16550_INTERRUPT_ENABLE_RX_DATA |
- SER16550_INTERRUPT_ENABLE_RX_STATUS;
- SER16550_WRITE8(Device, Ser16550InterruptEnable, Device->InterruptEnable);
- return STATUS_SUCCESS;
- }
- ULONG
- Ser16550pGetFifoSize (
- PSER16550_CHILD Device
- )
- /*++
- Routine Description:
- This routine determines the size of the serial port FIFO.
- Arguments:
- Device - Supplies a pointer to the device.
- Return Value:
- Returns the FIFO size.
- --*/
- {
- UCHAR DivisorHigh;
- UCHAR DivisorLow;
- ULONG Index;
- UCHAR LineControl;
- UCHAR ModemControl;
- UCHAR Value;
- LineControl = SER16550_READ8(Device, Ser16550LineControl);
- SER16550_WRITE8(Device, Ser16550LineControl, 0);
- ModemControl = SER16550_READ8(Device, Ser16550ModemControl);
- Value = SER16550_FIFO_CONTROL_ENABLE |
- SER16550_FIFO_CONTROL_CLEAR_TRANSMIT |
- SER16550_FIFO_CONTROL_CLEAR_RECEIVE;
- SER16550_WRITE8(Device, Ser16550FifoControl, Value);
- SER16550_WRITE8(Device,
- Ser16550ModemControl,
- SER16550_MODEM_CONTROL_LOOPBACK);
- Value = SER16550_LINE_CONTROL_DIVISOR_LATCH;
- SER16550_WRITE8(Device, Ser16550LineControl, Value);
- DivisorLow = SER16550_READ8(Device, Ser16550DivisorLow);
- DivisorHigh = SER16550_READ8(Device, Ser16550DivisorHigh);
- SER16550_WRITE8(Device, Ser16550DivisorLow, 1);
- SER16550_WRITE8(Device, Ser16550DivisorHigh, 0);
- Value = SER16550_LINE_CONTROL_8_DATA_BITS;
- SER16550_WRITE8(Device, Ser16550LineControl, Value);
- for (Index = 0; Index < SER16550_MAX_FIFO; Index += 1) {
- SER16550_WRITE8(Device, Ser16550Data, Index);
- }
- KeDelayExecution(FALSE, FALSE, 10 * MICROSECONDS_PER_MILLISECOND);
- for (Index = 0; Index < SER16550_MAX_FIFO; Index += 1) {
- if ((SER16550_READ8(Device, Ser16550LineStatus) &
- SER16550_LINE_STATUS_RX_READY) == 0) {
- break;
- }
- SER16550_READ8(Device, Ser16550Data);
- }
- SER16550_WRITE8(Device, Ser16550ModemControl, ModemControl);
- Value = SER16550_LINE_CONTROL_DIVISOR_LATCH;
- SER16550_WRITE8(Device, Ser16550LineControl, Value);
- SER16550_WRITE8(Device, Ser16550DivisorLow, DivisorLow);
- SER16550_WRITE8(Device, Ser16550DivisorHigh, DivisorHigh);
- SER16550_WRITE8(Device, Ser16550LineControl, LineControl);
- return Index;
- }
- VOID
- Ser16550pAddReference (
- PSER16550_OBJECT Object
- )
- /*++
- Routine Description:
- This routine adds a reference on the given 16550 context.
- Arguments:
- Object - Supplies a pointer to the 16550 object.
- Return Value:
- None.
- --*/
- {
- ULONG OldReferenceCount;
- OldReferenceCount = RtlAtomicAdd32(&(Object->ReferenceCount), 1);
- ASSERT(OldReferenceCount < 0x10000000);
- return;
- }
- VOID
- Ser16550pReleaseReference (
- PSER16550_OBJECT Object
- )
- /*++
- Routine Description:
- This routine releases a reference on a 16550 object.
- Arguments:
- Object - Supplies a pointer to the 16550 object.
- Return Value:
- None.
- --*/
- {
- ULONG OldReferenceCount;
- OldReferenceCount = RtlAtomicAdd32(&(Object->ReferenceCount), (ULONG)-1);
- ASSERT((OldReferenceCount != 0) && (OldReferenceCount < 0x10000000));
- if (OldReferenceCount == 1) {
- Ser16550pDestroyDevice(Object);
- }
- return;
- }
- VOID
- Ser16550pDestroyDevice (
- PSER16550_OBJECT Object
- )
- /*++
- Routine Description:
- This routine destroys a 16550 object.
- Arguments:
- Object - Supplies a pointer to the 16550 object.
- Return Value:
- None.
- --*/
- {
- PSER16550_CHILD Child;
- PSER16550_PARENT Parent;
- switch (Object->Type) {
- case Ser16550ObjectParent:
- Parent = PARENT_STRUCTURE(Object, SER16550_PARENT, Header);
- if (Parent->ChildDevices != NULL) {
- MmFreePagedPool(Parent->ChildDevices);
- Parent->ChildDevices = NULL;
- }
- if (Parent->ChildObjects != NULL) {
- MmFreePagedPool(Parent->ChildObjects);
- Parent->ChildObjects = NULL;
- }
- Parent->Header.Type = Ser16550ObjectInvalid;
- MmFreeNonPagedPool(Parent);
- break;
- case Ser16550ObjectChild:
- Child = PARENT_STRUCTURE(Object, SER16550_CHILD, Header);
- Child->Header.Type = Ser16550ObjectInvalid;
- if (Child->Terminal != NULL) {
- IoTerminalSetDevice(Child->Terminal, NULL);
- IoClose(Child->Terminal);
- Child->Terminal = NULL;
- }
- if ((Child->MappedAddress != NULL) && (Child->ShouldUnmap != FALSE)) {
- ASSERT(Child->MappedSize != 0);
- MmUnmapAddress(Child->MappedAddress, Child->MappedSize);
- Child->MappedAddress = NULL;
- Child->MappedSize = 0;
- }
- if (Child->TransmitBuffer != NULL) {
- MmFreeNonPagedPool(Child->TransmitBuffer);
- Child->TransmitBuffer = NULL;
- Child->TransmitSize = 0;
- Child->TransmitStart = 0;
- Child->TransmitEnd = 0;
- }
- if (Child->ReceiveBuffer != NULL) {
- MmFreeNonPagedPool(Child->ReceiveBuffer);
- Child->ReceiveBuffer = NULL;
- Child->ReceiveSize = 0;
- Child->ReceiveStart = 0;
- Child->ReceiveEnd = 0;
- }
- if (Child->TransmitLock != NULL) {
- KeDestroyQueuedLock(Child->TransmitLock);
- Child->TransmitLock = NULL;
- }
- if (Child->ReceiveLock != NULL) {
- KeDestroyQueuedLock(Child->ReceiveLock);
- Child->ReceiveLock = NULL;
- }
- if (Child->TransmitReady == NULL) {
- KeDestroyEvent(Child->TransmitReady);
- Child->TransmitReady = NULL;
- }
- if (Child->ReceiveReady == NULL) {
- KeDestroyEvent(Child->ReceiveReady);
- Child->ReceiveReady = NULL;
- }
- break;
- default:
- ASSERT(FALSE);
- return;
- }
- return;
- }
- UCHAR
- Ser16550pReadIo8 (
- PSER16550_CHILD Device,
- SER16550_REGISTER Register
- )
- /*++
- Routine Description:
- This routine reads an I/O port based 16550 register.
- Arguments:
- Device - Supplies a pointer to the device context.
- Register - Supplies the register to read.
- Return Value:
- Returns the value at the register.
- --*/
- {
- USHORT Port;
- Port = Device->IoPortAddress + SER16550_REGISTER_OFFSET(Device, Register);
- return HlIoPortInByte(Port);
- }
- VOID
- Ser16550pWriteIo8 (
- PSER16550_CHILD Device,
- SER16550_REGISTER Register,
- UCHAR Value
- )
- /*++
- Routine Description:
- This routine writes to an I/O port based 16550 register.
- Arguments:
- Device - Supplies a pointer to the device context.
- Register - Supplies the register to write to.
- Value - Supplies the value to write.
- Return Value:
- None.
- --*/
- {
- USHORT Port;
- Port = Device->IoPortAddress + SER16550_REGISTER_OFFSET(Device, Register);
- HlIoPortOutByte(Port, Value);
- return;
- }
- UCHAR
- Ser16550pReadMemory8 (
- PSER16550_CHILD Device,
- SER16550_REGISTER Register
- )
- /*++
- Routine Description:
- This routine reads a memory-based 16550 register.
- Arguments:
- Device - Supplies a pointer to the device context.
- Register - Supplies the register to read.
- Return Value:
- Returns the value at the register.
- --*/
- {
- PVOID Address;
- Address = Device->MappedAddress +
- SER16550_REGISTER_OFFSET(Device, Register);
- return HlReadRegister8(Address);
- }
- VOID
- Ser16550pWriteMemory8 (
- PSER16550_CHILD Device,
- SER16550_REGISTER Register,
- UCHAR Value
- )
- /*++
- Routine Description:
- This routine writes to a memory-based 16550 register.
- Arguments:
- Device - Supplies a pointer to the device context.
- Register - Supplies the register to write to.
- Value - Supplies the value to write.
- Return Value:
- None.
- --*/
- {
- PVOID Address;
- Address = Device->MappedAddress +
- SER16550_REGISTER_OFFSET(Device, Register);
- HlWriteRegister8(Address, Value);
- return;
- }
|