ODCom.c 108 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705
  1. /* OpenDoors Online Software Programming Toolkit
  2. * (C) Copyright 1991 - 1999 by Brian Pirie.
  3. *
  4. * Oct-2001 door32.sys/socket modifications by Rob Swindell (www.synchro.net)
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 2 of the License, or (at your option) any later version.
  10. *
  11. * This library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with this library; if not, write to the Free Software
  18. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  19. *
  20. *
  21. * File: ODCom.c
  22. *
  23. * Description: Generic serial I/O routines, provide a single interface to
  24. * serial ports on any platform.
  25. *
  26. * Revisions: Date Ver Who Change
  27. * ---------------------------------------------------------------
  28. * Oct 13, 1994 6.00 BP New file header format.
  29. * Oct 20, 1994 6.00 BP Handle BIOS missing port addrs.
  30. * Oct 20, 1994 6.00 BP Standardized coding style.
  31. * Oct 21, 1994 6.00 BP Further isolated com routines.
  32. * Dec 07, 1994 6.00 BP Support for RTS/CTS flow control.
  33. * Dec 10, 1994 6.00 BP Allow word frmt setting for intern I/O
  34. * Dec 13, 1994 6.00 BP Remove include of dir.h.
  35. * Dec 31, 1994 6.00 BP Remove #ifndef USEINLINE DOS code.
  36. * Jan 01, 1995 6.00 BP Integrate in Win32 code.
  37. * Jan 01, 1995 6.00 BP Add FLOW_DEFAULT setting.
  38. * Jan 01, 1995 6.00 BP Added ODComWaitEvent().
  39. * Nov 16, 1995 6.00 BP Removed oddoor.h, added odcore.h.
  40. * Nov 21, 1995 6.00 BP Ported to Win32.
  41. * Dec 21, 1995 6.00 BP Add ability to use already open port.
  42. * Jan 09, 1996 6.00 BP Supply actual in/out buffer size used.
  43. * Feb 19, 1996 6.00 BP Changed version number to 6.00.
  44. * Mar 03, 1996 6.10 BP Begin version 6.10.
  45. * Mar 06, 1996 6.10 BP Initial support for Door32 interface.
  46. * Mar 19, 1996 6.10 BP MSVC15 source-level compatibility.
  47. * Jan 13, 1997 6.10 BP Fixes for Door32 support.
  48. * Oct 19, 2001 6.20 RS Added TCP/IP socket (telnet) support.
  49. * Oct 22, 2001 6.21 RS Fixed disconnected socket detection.
  50. * Aug 22, 2002 6.22 RS Fixed bugs in ODComCarrier and ODComWaitEvent
  51. * Aug 22, 2002 6.22 MD Modified socket functions for non-blocking use.
  52. * Sep 18, 2002 6.22 MD Fixed bugs in ODComWaitEvent for non-blocking sockets.
  53. * Aug 10, 2003 6.23 SH *nix support
  54. */
  55. #define BUILDING_OPENDOORS
  56. #include <stdio.h>
  57. #include <stdlib.h>
  58. #include <stdarg.h>
  59. #include <string.h>
  60. #include <ctype.h>
  61. #include <time.h>
  62. #include "OpenDoor.h"
  63. #ifdef ODPLAT_NIX
  64. #include <sys/ioctl.h>
  65. #include <signal.h>
  66. #include <termios.h>
  67. #include <errno.h>
  68. #include <unistd.h>
  69. #include <sys/socket.h>
  70. #include <netinet/in.h>
  71. #include <netinet/tcp.h>
  72. #ifdef __sun
  73. #include <sys/filio.h>
  74. #endif
  75. #endif
  76. #include "ODCore.h"
  77. #include "ODGen.h"
  78. #include "ODPlat.h"
  79. #include "ODCom.h"
  80. #include "ODUtil.h"
  81. /* The following define determines whether serial port function should */
  82. /* ASSERT or return an error code on programmer erorrs (e.g. invalid */
  83. /* parameters. */
  84. #define ASSERT_ON_INVALID_CALLS
  85. /* The following code defines the VERIFY_CALL() macro, which maps to an */
  86. /* ASSERT if ASSERT_ON_INVALID_CALLS is defined. Otherwise, this macro */
  87. /* maps to a test which will return an error code to the caller. */
  88. #ifdef ASSERT_ON_INVALID_CALLS
  89. #define VERIFY_CALL(x) ASSERT(x)
  90. #else /* !ASSERT_ON_INVALID_CALLS */
  91. #define VERIFY_CALL(x) if(x) return(kODRCInvalidCall)
  92. #endif /* !ASSERT_ON_INVALID_CALLS */
  93. /* The following defines determine which serial I/O mechanisms should be */
  94. /* supported. */
  95. /* Serial I/O mechanisms supported under MS-DOS version. */
  96. #ifdef ODPLAT_DOS
  97. #define INCLUDE_FOSSIL_COM /* INT 14h FOSSIL-based I/O. */
  98. #define INCLUDE_UART_COM /* Internal interrupt driven I/O. */
  99. #endif /* ODPLAT_DOS */
  100. /* Serial I/O mechanisms supported under Win32 version. */
  101. #ifdef ODPLAT_WIN32
  102. #define INCLUDE_WIN32_COM /* Win32 API serial I/O. */
  103. #define INCLUDE_DOOR32_COM /* Door32 I/O interface. */
  104. #define INCLUDE_SOCKET_COM /* TCP/IP socket I/O. */
  105. #endif /* ODPLAT_WIN32 */
  106. /* Serial I/O mechanisms supported inder *nix version */
  107. #ifdef ODPLAT_NIX
  108. #define INCLUDE_STDIO_COM
  109. #define INCLUDE_SOCKET_COM /* TCP/IP socket I/O. */
  110. /* Win32 Compat. Stuff */
  111. #define SOCKET int
  112. #define WSAEWOULDBLOCK EAGAIN
  113. #define SOCKET_ERROR -1
  114. #define WSAGetLastError() errno
  115. #define ioctlsocket ioctl
  116. #define closesocket close
  117. #endif /* ODPLAT_NIX */
  118. /* Include "windows.h" for Win32-API based serial I/O. */
  119. #ifdef INCLUDE_WIN32_COM
  120. #include "windows.h"
  121. #endif /* INCLUDE_WIN32_COM */
  122. /* terminal variables */
  123. #ifdef INCLUDE_STDIO_COM
  124. struct termios tio_default; /* Initial term settings */
  125. #endif
  126. #if defined(_WIN32) && defined(INCLUDE_SOCKET_COM)
  127. #include <winsock.h>
  128. static WSADATA WSAData; /* WinSock data */
  129. #endif
  130. /* ========================================================================= */
  131. /* Serial port object structure. */
  132. /* ========================================================================= */
  133. /* Win32-API serial I/O implementation requires current timeout setting */
  134. /* status variable in serial port object structure. */
  135. #ifdef INCLUDE_WIN32_COM
  136. typedef enum
  137. {
  138. kNotSet,
  139. kBlocking,
  140. kNonBlocking
  141. } tReadTimeoutState;
  142. #endif /* INCLUDE_WIN32_COM */
  143. /* Structure associated with each serial port handle. */
  144. typedef struct
  145. {
  146. BOOL bIsOpen;
  147. BOOL bUsingClientsHandle;
  148. BYTE btFlowControlSetting;
  149. long lSpeed;
  150. BYTE btPort;
  151. int nPortAddress;
  152. BYTE btIRQLevel;
  153. BYTE btWordFormat;
  154. int nReceiveBufferSize;
  155. int nTransmitBufferSize;
  156. BYTE btFIFOSetting;
  157. tComMethod Method;
  158. void (*pfIdleCallback)(void);
  159. #ifdef INCLUDE_WIN32_COM
  160. HANDLE hCommDev;
  161. tReadTimeoutState ReadTimeoutState;
  162. #endif /* INCLUDE_WIN32_COM */
  163. #ifdef INCLUDE_DOOR32_COM
  164. HINSTANCE hinstDoor32DLL;
  165. BOOL (WINAPI *pfDoorInitialize)(void);
  166. BOOL (WINAPI *pfDoorShutdown)(void);
  167. BOOL (WINAPI *pfDoorWrite)(const BYTE *pbData, DWORD dwSize);
  168. DWORD (WINAPI *pfDoorRead)(BYTE *pbData, DWORD dwSize);
  169. HANDLE (WINAPI *pfDoorGetAvailableEventHandle)(void);
  170. HANDLE (WINAPI *pfDoorGetOfflineEventHandle)(void);
  171. #endif /* INCLUDE_DOOR32_COM */
  172. #ifdef INCLUDE_SOCKET_COM
  173. SOCKET socket;
  174. int old_delay;
  175. #endif
  176. } tPortInfo;
  177. /* ========================================================================= */
  178. /* Internal interrupt-driven serial I/O specific defintions & functions. */
  179. /* ========================================================================= */
  180. #ifdef INCLUDE_UART_COM
  181. /* Private function prototypes, used by internal UART async serial I/O. */
  182. static void ODComSetVect(BYTE btVector, void (INTERRUPT far *pfISR)(void));
  183. static void (INTERRUPT far *ODComGetVect(BYTE btVector))(void);
  184. static void INTERRUPT ODComInternalISR();
  185. static BOOL ODComInternalTXReady(void);
  186. static void ODComInternalResetRX(void);
  187. static void ODComInternalResetTX(void);
  188. /* Offsets of UART registers. */
  189. #define TXBUFF 0 /* Transmit buffer register. */
  190. #define RXBUFF 0 /* Receive buffer register. */
  191. #define DLLSB 0 /* Divisor latch LS byte. */
  192. #define DLMSB 1 /* Divisor latch MS byte. */
  193. #define IER 1 /* Interrupt enable register. */
  194. #define IIR 2 /* Interrupt ID register. */
  195. #define LCR 3 /* Line control register. */
  196. #define MCR 4 /* Modem control register. */
  197. #define LSR 5 /* Line status register. */
  198. #define MSR 6 /* Modem status register. */
  199. /* FIFO control register bits. */
  200. #define FE 0x01 /* FIFO enable. */
  201. #define RR 0x02 /* FIFO receive buffer reset. */
  202. #define TR 0x04 /* FIFO transmit buffer reset. */
  203. #define FTS_1 0x00 /* FIFO trigger size 1 byte. */
  204. #define FTS_4 0x40 /* FIFO trigger size 4 bytes. */
  205. #define FTS_8 0x80 /* FIFO trigger size 8 bytes. */
  206. #define FTS_14 0xc0 /* FIFO trigger size 14 bytes. */
  207. /* Modem control register (MCR) bits. */
  208. #define DTR 0x01 /* Data terminal ready. */
  209. #define NOT_DTR 0xfe /* All bits other than DTR. */
  210. #define RTS 0x02 /* Request to send. */
  211. #define NOT_RTS 0xfd /* All bits other than RTS. */
  212. #define OUT1 0x04 /* Output #1. */
  213. #define OUT2 0x08 /* Output #2. */
  214. #define LPBK 0x10 /* Loopback mode bit. */
  215. /* Modem status register (MSR) bits. */
  216. #define DCTS 0x01 /* Delta clear to send. */
  217. #define DDSR 0x02 /* Delta data set ready. */
  218. #define TERI 0x04 /* Trailing edge ring indicator. */
  219. #define DRLSD 0x08 /* Delta Rx line signal detect. */
  220. #define CTS 0x10 /* Clear to send. */
  221. #define DSR 0x20 /* Data set ready. */
  222. #define RI 0x40 /* Ring indicator. */
  223. #define RLSD 0x80 /* Receive line signal detect. */
  224. /* Line control register (LCR) bits. */
  225. #define DATA5 0x00 /* 5 Data bits. */
  226. #define DATA6 0x01 /* 6 Data bits. */
  227. #define DATA7 0x02 /* 7 Data bits. */
  228. #define DATA8 0x03 /* 8 Data bits. */
  229. #define STOP1 0x00 /* 1 Stop bit. */
  230. #define STOP2 0x04 /* 2 Stop bits. */
  231. #define NOPAR 0x00 /* No parity. */
  232. #define ODDPAR 0x08 /* Odd parity. */
  233. #define EVNPAR 0x18 /* Even parity. */
  234. #define STKPAR 0x28 /* Sticky parity. */
  235. #define ZROPAR 0x38 /* Zero parity. */
  236. #define DLATCH 0x80 /* Baud rate divisor latch. */
  237. #define NOT_DL 0x7f /* Turns off divisor latch. */
  238. /* Line status register (LSR) bits. */
  239. #define RDR 0x01 /* Receive data ready. */
  240. #define ERRS 0x1E /* All the error bits. */
  241. #define TXR 0x20 /* Transmitter ready. */
  242. /* Interrupt enable register (IER) bits. */
  243. #define DR 0x01 /* Data ready. */
  244. #define THRE 0x02 /* Transmit holding register empty. */
  245. #define RLS 0x04 /* Receive line status. */
  246. #define MS 0x08 /* Modem status. */
  247. /* Flow control receive buffer limits. */
  248. #define RECEIVE_LOW_NUM 1 /* Numerator for low water mark. */
  249. #define RECEIVE_LOW_DENOM 4 /* Denominator for low water mark. */
  250. #define RECEIVE_HIGH_NUM 3 /* Numerator for high water mark. */
  251. #define RECEIVE_HIGH_DENOM 4 /* Denominator for high water mark. */
  252. /* Built-in async serial I/O global variables. */
  253. /* These variabes are shared throughout the functions that handle the */
  254. /* built-in UART-base serial I/O, including the interrupt service routine. */
  255. /* Since only one copy of these variables exist, the built-in serial I/O */
  256. /* routines may only be used to access one port at a time. */
  257. /* Default port addresses. */
  258. /* First 4 addresses are standard addresses used for PC/AT COM1 thru COM4. */
  259. /* Second 4 addresses are PS/2 standard addresses used for COM5 thru COM8. */
  260. static int anDefaultPortAddr[] = {0x3f8, 0x2f8, 0x3e8, 0x2e8,
  261. 0x4220, 0x4228, 0x5220, 0x5228};
  262. /* UART address variables. */
  263. static int nDataRegAddr; /* Data register address. */
  264. static int nIntEnableRegAddr; /* Interrupt enable register. */
  265. static int nIntIDRegAddr; /* Interrupt ID register address. */
  266. static int nLineCtrlRegAddr; /* Line control register address. */
  267. static int nModemCtrlRegAddr; /* Modem control register address. */
  268. static int nLineStatusRegAddr; /* Line status register address. */
  269. static int nModemStatusRegAddr; /* Modem status register address. */
  270. /* General variables. */
  271. static BYTE btIntVector; /* Interrupt vector number for port. */
  272. static char btI8259Bit; /* 8259 bit mask. */
  273. static char btI8259Mask; /* Copy as it was before open. */
  274. static int nI8259MaskRegAddr; /* Address of i8259 mask register. */
  275. static int nI8259EndOfIntRegAddr; /* Address of i8259 EOI register. */
  276. static int nI8259MasterEndOfIntRegAddr; /* Address of master PIC EOI reg. */
  277. static char btOldIntEnableReg; /* Original IER contents. */
  278. static char btOldModemCtrlReg; /* Original MCR contents. */
  279. static void (INTERRUPT far *pfOldISR)();/* Original ISR routine for IRQ. */
  280. static char bUsingFIFO = FALSE; /* Are we using 16550 FIFOs? */
  281. static unsigned char btBaseFIFOCtrl; /* FIFO control register byte. */
  282. /* Transmit queue variables. */
  283. static int nTXQueueSize; /* Actual size of transmit queue. */
  284. static char *pbtTXQueue; /* Pointer to transmit queue. */
  285. static int nTXInIndex; /* Location to store next byte. */
  286. static int nTXOutIndex; /* Location to get next byte. */
  287. static int nTXChars; /* Count of characters in queue. */
  288. /* Receive queue variables. */
  289. static int nRXQueueSize; /* Actual size of receive queue. */
  290. static char *pbtRXQueue; /* Pointer to receive queue. */
  291. static int nRXInIndex; /* Location to store next byte. */
  292. static int nRXOutIndex; /* Location to retrieve next byte. */
  293. static int nRXChars; /* Count of characters in queue. */
  294. /* Flow control variables. */
  295. static int nRXHighWaterMark; /* High water mark for queue size. */
  296. static int nRXLowWaterMark; /* Low water mark for queue size. */
  297. static BYTE btFlowControl; /* Flow control method. */
  298. static BOOL bStopTrans; /* Flag set to stop transmitting. */
  299. /* ----------------------------------------------------------------------------
  300. * ODComSetVect() *** PRIVATE FUNCTION ***
  301. *
  302. * Sets the function to be called for the specified interrupt level.
  303. *
  304. * Parameters: btVector - Interrupt vector level, a value from 0 to 255.
  305. *
  306. * pfISR - Pointer to the ISR function to be called.
  307. *
  308. * Return: void
  309. */
  310. static void ODComSetVect(BYTE btVector, void (INTERRUPT far *pfISR)(void))
  311. {
  312. ASM push ds
  313. ASM mov ah, 0x25
  314. ASM mov al, btVector
  315. ASM lds dx, pfISR
  316. ASM int 0x21
  317. ASM pop ds
  318. }
  319. /* ----------------------------------------------------------------------------
  320. * ODComGetVect() *** PRIVATE FUNCTION ***
  321. *
  322. * Returns the address of the function that is currently called for the
  323. * specified interrupt level.
  324. *
  325. * Parameters: btVector - Interrupt vector level, a value from 0 to 255.
  326. *
  327. * Return: A pointer to the code that is currently executed on an interrupt
  328. * of the speceified level.
  329. */
  330. static void (INTERRUPT far *ODComGetVect(BYTE btVector))(void)
  331. {
  332. void (INTERRUPT far *pfISR)(void);
  333. ASM push es
  334. ASM mov ah, 0x35
  335. ASM mov al, btVector
  336. ASM int 0x21
  337. ASM mov word ptr pfISR, bx
  338. ASM mov word ptr [pfISR+2], bx
  339. ASM pop es
  340. return(pfISR);
  341. }
  342. /* ----------------------------------------------------------------------------
  343. * ODComInternalTXReady() *** PRIVATE FUNCTION ***
  344. *
  345. * Returns TRUE if the internal serial I/O transmit buffer is not full.
  346. *
  347. * Parameters: none
  348. *
  349. * Return: void
  350. */
  351. static BOOL ODComInternalTXReady(void)
  352. {
  353. /* Return TRUE if tx_chars is less than total tx buffer size. */
  354. return(nTXChars < nTXQueueSize);
  355. }
  356. /* ----------------------------------------------------------------------------
  357. * ODComInternalResetTX() *** PRIVATE FUNCTION ***
  358. *
  359. * Clears transmit buffer used by internal serial I/O routines.
  360. *
  361. * Parameters: none
  362. *
  363. * Return: void
  364. */
  365. static void ODComInternalResetTX(void)
  366. {
  367. /* Disable interrupts. */
  368. ASM cli
  369. /* If we are using 16550A FIFO buffers, then clear the FIFO transmit */
  370. /* buffer. */
  371. if(bUsingFIFO)
  372. {
  373. ASM mov al, btBaseFIFOCtrl
  374. ASM or al, TR
  375. ASM mov dx, nIntIDRegAddr
  376. ASM out dx, al
  377. }
  378. /* Reset start, end and total count of characters in buffer */
  379. /* If buffer is still empty on next transmit interrupt, transmit */
  380. /* interrupts will be turned off. */
  381. nTXChars = nTXInIndex = nTXOutIndex = 0;
  382. /* Re-enable interrupts. */
  383. ASM sti
  384. }
  385. /* ----------------------------------------------------------------------------
  386. * ODComInternalResetRX() *** PRIVATE FUNCTION ***
  387. *
  388. * Clears receive buffer used by internal serial I/O routines.
  389. *
  390. * Parameters: none
  391. *
  392. * Return: void
  393. */
  394. static void ODComInternalResetRX(void)
  395. {
  396. /* Disable interrupts. */
  397. ASM cli
  398. /* If we are using 16550A FIFO buffers, then clear the FIFO receive */
  399. /* buffer. */
  400. if(bUsingFIFO)
  401. {
  402. ASM mov al, btBaseFIFOCtrl
  403. ASM or al, RR
  404. ASM mov dx, nIntIDRegAddr
  405. ASM out dx, al
  406. }
  407. /* Reset start, end and total count of characters in buffer */
  408. /* On the next receive interrupt, data will be added at the beginning */
  409. /* of the buffer. */
  410. nRXChars = nRXInIndex = nRXOutIndex = 0;
  411. /* Re-enable interrupts. */
  412. ASM sti
  413. }
  414. /* ----------------------------------------------------------------------------
  415. * ODComInternalISR() *** PRIVATE FUNCTION ***
  416. *
  417. * Interrupt service routine for internal UART-based serial I/O.
  418. *
  419. * Parameters: none
  420. *
  421. * Return: void
  422. */
  423. static void INTERRUPT ODComInternalISR()
  424. {
  425. char btIIR;
  426. BYTE btTemp;
  427. /* Loop until there are no more pending operations to perform with the */
  428. /* UART. */
  429. for(;;)
  430. {
  431. /* While bit 0 of the UART IIR is 0, there remains pending operations. */
  432. /* Read IIR. */
  433. ASM mov dx, nIntIDRegAddr
  434. ASM in al, dx
  435. ASM mov btIIR, al
  436. /* If IIR bit 0 is set, then UART processing is finished. */
  437. if(btIIR & 0x01) break;
  438. /* Bits 1 and 2 of the IIR register identify the type of operation */
  439. /* to be performed with the UART. */
  440. /* Switch on bits 1 and 2 of IIR register. */
  441. switch(btIIR & 0x06)
  442. {
  443. case 0x00:
  444. /* Operation: modem status has changed. */
  445. /* Read modem status register. */
  446. ASM mov dx, nModemStatusRegAddr
  447. ASM in al, dx
  448. ASM mov btTemp, al
  449. /* We only care about the modem status register if we are */
  450. /* using RTS/CTS flow control, and the CTS register has */
  451. /* changed. */
  452. if((btFlowControl & FLOW_RTSCTS) && (btTemp & DCTS))
  453. {
  454. if(btTemp & CTS)
  455. {
  456. /* If CTS has gone high, then re-enable transmission. */
  457. bStopTrans = FALSE;
  458. /* Restart transmission if there is anything in the */
  459. /* transmit buffer. */
  460. if(nTXChars > 0)
  461. {
  462. /* Enable transmit interrupt. */
  463. ASM mov dx, nIntEnableRegAddr
  464. ASM in al, dx
  465. ASM or al, THRE
  466. ASM out dx, al
  467. }
  468. }
  469. else
  470. {
  471. /* If CTS has gone low, then stop transmitting. */
  472. bStopTrans = TRUE;
  473. }
  474. }
  475. break;
  476. case 0x02:
  477. /* Operation: room in transmit register/FIFO. */
  478. /* Check whether we can send further characters to transmit. */
  479. if(nTXChars <= 0 || bStopTrans)
  480. {
  481. /* If we cannot send more characters, then turn off */
  482. /* transmit interrupts. */
  483. ASM mov dx, nIntEnableRegAddr
  484. ASM in al, dx
  485. ASM and al, 0xfd
  486. ASM out dx, al
  487. }
  488. else
  489. {
  490. /* If we still have characters to transmit ... */
  491. /* Check line status register to determine whether transmit */
  492. /* register/FIFO truly has room. Some UARTs trigger transmit */
  493. /* interrupts before the character has been tranmistted, */
  494. /* causing transmitted characters to be lost. */
  495. ASM mov dx, nLineStatusRegAddr
  496. ASM in al, dx
  497. ASM mov btTemp, al
  498. if(btTemp & TXR)
  499. {
  500. /* There is room in the transmit register/FIFO. */
  501. /* Get next character to transmit. */
  502. btTemp = pbtTXQueue[nTXOutIndex++];
  503. /* Write character to UART data register. */
  504. ASM mov dx, nDataRegAddr
  505. ASM mov al, btTemp
  506. ASM out dx, al
  507. /* Wrap-around transmit buffer pointer, if needed. */
  508. if (nTXOutIndex == nTXQueueSize)
  509. {
  510. nTXOutIndex = 0;
  511. }
  512. /* Decrease count of characters in transmit buffer. */
  513. nTXChars--;
  514. }
  515. }
  516. break;
  517. case 0x04:
  518. /* Operation: Receive Data. */
  519. /* Get character from receive buffer ASAP. */
  520. ASM mov dx, nDataRegAddr
  521. ASM in al, dx
  522. ASM mov btTemp, al
  523. /* If receive buffer is above high water mark. */
  524. if(nRXChars >= nRXHighWaterMark)
  525. {
  526. /* If we are using flow control, then stop sender from */
  527. /* sending. */
  528. if(btFlowControl & FLOW_RTSCTS)
  529. {
  530. /* If using RTS/CTS flow control, then lower RTS line. */
  531. ASM mov dx, nModemCtrlRegAddr
  532. ASM in al, dx
  533. ASM and al, NOT_RTS
  534. ASM out dx, al
  535. }
  536. }
  537. /* If there is room in receive buffer. */
  538. if(nRXChars < nRXQueueSize)
  539. {
  540. /* Store the new character in the receive buffer. */
  541. pbtRXQueue[nRXInIndex++] = btTemp;
  542. /* Wrap-around buffer index, if needed. */
  543. if (nRXInIndex == nRXQueueSize)
  544. nRXInIndex = 0;
  545. /* Increment count of characters in the buffer. */
  546. nRXChars++;
  547. }
  548. break;
  549. case 0x06:
  550. /* Operation: Change in line status register. */
  551. /* We just read the register to move on to further operations. */
  552. ASM mov dx, nLineStatusRegAddr
  553. ASM in al, dx
  554. break;
  555. }
  556. }
  557. /* Send end of interrupt to interrupt controller(s). */
  558. ASM mov dx, nI8259EndOfIntRegAddr
  559. ASM mov al, 0x20
  560. ASM out dx, al
  561. if(nI8259MasterEndOfIntRegAddr != 0)
  562. {
  563. ASM mov dx, nI8259MasterEndOfIntRegAddr
  564. ASM mov al, 0x20
  565. ASM out dx, al
  566. }
  567. }
  568. #endif /* INCLUDE_UART_COM */
  569. /* ========================================================================= */
  570. /* Win32-API base serial I/O specific functions. */
  571. /* ========================================================================= */
  572. #ifdef INCLUDE_WIN32_COM
  573. /* Function prototypes. */
  574. static tODResult ODComWin32SetReadTimeouts(tPortInfo *pPortInfo,
  575. tReadTimeoutState RequiredTimeoutState);
  576. /* ----------------------------------------------------------------------------
  577. * ODComWin32SetReadTimeouts() *** PRIVATE FUNCTION ***
  578. *
  579. * Ensures that read timeout state is set appropriately.
  580. *
  581. * Parameters: pPortInfo - Pointer to serial port handle structure.
  582. *
  583. * RequiredTimeoutState - Timeout state that should be set.
  584. *
  585. * Return: kODRCSuccess on success, or an error code on failure.
  586. */
  587. static tODResult ODComWin32SetReadTimeouts(tPortInfo *pPortInfo,
  588. tReadTimeoutState RequiredTimeoutState)
  589. {
  590. ASSERT(pPortInfo != NULL);
  591. /* If timeout state must be changed ... */
  592. if(RequiredTimeoutState != pPortInfo->ReadTimeoutState)
  593. {
  594. COMMTIMEOUTS CommTimeouts;
  595. /* Obtain current timeout settings. */
  596. if(!GetCommTimeouts(pPortInfo->hCommDev, &CommTimeouts))
  597. {
  598. return(kODRCGeneralFailure);
  599. }
  600. /* Setup timeout setting structure appropriately. */
  601. switch(RequiredTimeoutState)
  602. {
  603. case kBlocking:
  604. CommTimeouts.ReadIntervalTimeout = 0;
  605. CommTimeouts.ReadTotalTimeoutMultiplier = 0;
  606. CommTimeouts.ReadTotalTimeoutConstant = 0;
  607. break;
  608. case kNonBlocking:
  609. CommTimeouts.ReadIntervalTimeout = INFINITE;
  610. CommTimeouts.ReadTotalTimeoutMultiplier = 0;
  611. CommTimeouts.ReadTotalTimeoutConstant = 0;
  612. break;
  613. default:
  614. ASSERT(FALSE);
  615. }
  616. /* Write settings. */
  617. if(!SetCommTimeouts(pPortInfo->hCommDev, &CommTimeouts))
  618. {
  619. return(kODRCGeneralFailure);
  620. }
  621. /* Record current read timeout setting state for subsequent */
  622. /* calls to this function. */
  623. pPortInfo->ReadTimeoutState = RequiredTimeoutState;
  624. }
  625. return(kODRCSuccess);
  626. }
  627. #endif /* INCLUDE_WIN32_COM */
  628. /* ========================================================================= */
  629. /* Implementation of generic serial I/O functions. */
  630. /* ========================================================================= */
  631. /* ----------------------------------------------------------------------------
  632. * ODComAlloc()
  633. *
  634. * Allocates a serial port handle, which can be passed to other ODCom...()
  635. * functions.
  636. *
  637. * Parameters: phPort - Pointer to serial port handle.
  638. *
  639. * Return: kODRCSuccess on success, or an error code on failure.
  640. */
  641. tODResult ODComAlloc(tPortHandle *phPort)
  642. {
  643. tPortInfo *pPortInfo;
  644. VERIFY_CALL(phPort != NULL);
  645. /* Attempt to allocate a serial port information structure. */
  646. pPortInfo = malloc(sizeof(tPortInfo));
  647. /* If memory allocation failed, return with failure. */
  648. if(pPortInfo == NULL)
  649. {
  650. *phPort = ODPTR2HANDLE(NULL, tPortInfo);
  651. return(kODRCNoMemory);
  652. }
  653. /* Initialize serial port information structure. */
  654. pPortInfo->bIsOpen = FALSE;
  655. pPortInfo->bUsingClientsHandle = FALSE;
  656. pPortInfo->btFlowControlSetting = FLOW_DEFAULT;
  657. pPortInfo->lSpeed = SPEED_UNSPECIFIED;
  658. pPortInfo->btWordFormat = ODPARITY_NONE | DATABITS_EIGHT | STOP_ONE;
  659. pPortInfo->nReceiveBufferSize = 1024;
  660. pPortInfo->nTransmitBufferSize = 1024;
  661. pPortInfo->btFIFOSetting = FIFO_ENABLE | FIFO_TRIGGER_8;
  662. pPortInfo->Method = kComMethodUnspecified;
  663. pPortInfo->pfIdleCallback = NULL;
  664. /* Convert serial port information structure pointer to a handle. */
  665. *phPort = ODPTR2HANDLE(pPortInfo, tPortInfo);
  666. /* Set default port number. */
  667. ODComSetPort(*phPort, 0);
  668. #if defined(INCLUDE_SOCKET_COM) && defined(_WINSOCKAPI_)
  669. WSAStartup(MAKEWORD(1,1), &WSAData);
  670. #endif
  671. /* Return with success. */
  672. return(kODRCSuccess);
  673. }
  674. /* ----------------------------------------------------------------------------
  675. * ODComFree()
  676. *
  677. * Deallocates a serial port handle that is no longer required.
  678. *
  679. * Parameters: hPort - Handle to a serial port object.
  680. *
  681. * Return: kODRCSuccess on success, or an error code on failure.
  682. */
  683. tODResult ODComFree(tPortHandle hPort)
  684. {
  685. tPortInfo *pPortInfo = ODHANDLE2PTR(hPort, tPortInfo);
  686. VERIFY_CALL(pPortInfo != NULL);
  687. VERIFY_CALL(!pPortInfo->bIsOpen);
  688. /* Deallocate port information structure. */
  689. free(pPortInfo);
  690. /* Return with success. */
  691. return(kODRCSuccess);
  692. }
  693. /* ----------------------------------------------------------------------------
  694. * ODComSetIdleFunction()
  695. *
  696. * Sets function to call when serial I/O module is idle, or NULL for none.
  697. *
  698. * Parameters: hPort - Handle to a serial port object.
  699. *
  700. * pfCallback - Pointer to function to call when idle.
  701. *
  702. * Return: kODRCSuccess on success, or an error code on failure.
  703. */
  704. tODResult ODComSetIdleFunction(tPortHandle hPort,
  705. void (*pfCallback)(void))
  706. {
  707. tPortInfo *pPortInfo = ODHANDLE2PTR(hPort, tPortInfo);
  708. VERIFY_CALL(pPortInfo != NULL);
  709. VERIFY_CALL(!pPortInfo->bIsOpen);
  710. pPortInfo->pfIdleCallback = pfCallback;
  711. /* Return with success. */
  712. return(kODRCSuccess);
  713. }
  714. /* ----------------------------------------------------------------------------
  715. * ODComSetFlowControl()
  716. *
  717. * Sets the flow control method(s) to use. If this function is not called,
  718. * RTS/CTS flow control is used by default. This function should not be
  719. * called while the port is open.
  720. *
  721. * Parameters: hPort - Handle to a serial port object.
  722. *
  723. * btFlowControlSetting - One or more FLOW_* settings, joined
  724. * by bitwise-or (|) operators. If
  725. * FLOW_DEFAULT is included, all other
  726. * settings are ignored, and the default
  727. * settings for this serial I/O method
  728. * are used.
  729. *
  730. * Return: kODRCSuccess on success, or an error code on failure.
  731. */
  732. tODResult ODComSetFlowControl(tPortHandle hPort, BYTE btFlowControlSetting)
  733. {
  734. tPortInfo *pPortInfo = ODHANDLE2PTR(hPort, tPortInfo);
  735. VERIFY_CALL(pPortInfo != NULL);
  736. VERIFY_CALL(!pPortInfo->bIsOpen);
  737. pPortInfo->btFlowControlSetting = btFlowControlSetting;
  738. /* Return with success. */
  739. return(kODRCSuccess);
  740. }
  741. /* ----------------------------------------------------------------------------
  742. * ODComSetSpeed()
  743. *
  744. * Sets the serial port BPS (baud) rate to use. Depending upon the serial I/O
  745. * method being used, this setting may be controlled by the user's system
  746. * configuration, in which case the value passed to this function wil have
  747. * no effect. A setting of SPEED_UNSPECIFIED, indicates that the serial port
  748. * speed should not be changed, if it is possible not to do so with the serial
  749. * I/O method being used. This function cannot be called while the port is
  750. * open.
  751. *
  752. * Parameters: hPort - Handle to a serial port object.
  753. *
  754. * lSpeed - A valid BPS rate, or SPEED_UNSPECIFIED.
  755. *
  756. * Return: kODRCSuccess on success, or an error code on failure.
  757. */
  758. tODResult ODComSetSpeed(tPortHandle hPort, long lSpeed)
  759. {
  760. tPortInfo *pPortInfo = ODHANDLE2PTR(hPort, tPortInfo);
  761. VERIFY_CALL(pPortInfo != NULL);
  762. VERIFY_CALL(!pPortInfo->bIsOpen);
  763. pPortInfo->lSpeed = lSpeed;
  764. /* Return with success. */
  765. return(kODRCSuccess);
  766. }
  767. /* ----------------------------------------------------------------------------
  768. * ODComSetPort()
  769. *
  770. * Sets the serial port number to be associated with this port handle. This
  771. * function cannot be called while the port is open. Calling this function
  772. * also sets the IRQ line number and serial port address to their defaults
  773. * for this port number, if this values can be set for the serial I/O method
  774. * being used.
  775. *
  776. * Parameters: hPort - Handle to a serial port object.
  777. *
  778. * btPort - Serial port identification, where 0 typically
  779. * corresponds to COM1, 1 to COM2, and so on.
  780. *
  781. * Return: kODRCSuccess on success, or an error code on failure.
  782. */
  783. tODResult ODComSetPort(tPortHandle hPort, BYTE btPort)
  784. {
  785. tPortInfo *pPortInfo = ODHANDLE2PTR(hPort, tPortInfo);
  786. VERIFY_CALL(pPortInfo != NULL);
  787. VERIFY_CALL(!pPortInfo->bIsOpen);
  788. /* Store port number in port information structure. */
  789. pPortInfo->btPort = btPort;
  790. #ifdef INCLUDE_UART_COM
  791. /* Get default address for this port number, if possible. */
  792. pPortInfo->nPortAddress = 0;
  793. if(btPort < 4)
  794. {
  795. /* Get port address from BIOS data area. */
  796. pPortInfo->nPortAddress = *(((int far *)0x400) + btPort);
  797. }
  798. /* If port address is still unknown, and we know the default */
  799. /* address, then use that address. */
  800. if(pPortInfo->nPortAddress == 0
  801. && btPort < DIM(anDefaultPortAddr))
  802. {
  803. pPortInfo->nPortAddress = anDefaultPortAddr[btPort];
  804. }
  805. /* Set default IRQ number for this port number. */
  806. /* Ports 0 and 2 (COM1:, COM3:) default to IRQ 4, all others */
  807. /* default to IRQ 3. */
  808. if(btPort == 0 || btPort == 2)
  809. {
  810. pPortInfo->btIRQLevel = 4;
  811. }
  812. else
  813. {
  814. pPortInfo->btIRQLevel = 3;
  815. }
  816. #endif /* INCLUDE_UART_COM */
  817. /* Return with success. */
  818. return(kODRCSuccess);
  819. }
  820. /* ----------------------------------------------------------------------------
  821. * ODComSetPortAddress()
  822. *
  823. * Sets address of the serial port, if it can be set for the serial I/O method
  824. * being used. This function cannot be called when the port is open.
  825. *
  826. * Parameters: hPort - Handle to a serial port object.
  827. *
  828. * nPortAddress - Address of serial port.
  829. *
  830. * Return: kODRCSuccess on success, or an error code on failure.
  831. */
  832. tODResult ODComSetPortAddress(tPortHandle hPort, int nPortAddress)
  833. {
  834. tPortInfo *pPortInfo = ODHANDLE2PTR(hPort, tPortInfo);
  835. VERIFY_CALL(pPortInfo != NULL);
  836. VERIFY_CALL(!pPortInfo->bIsOpen);
  837. pPortInfo->nPortAddress = nPortAddress;
  838. /* Return with success. */
  839. return(kODRCSuccess);
  840. }
  841. /* ----------------------------------------------------------------------------
  842. * ODComSetIRQ()
  843. *
  844. * Sets the IRQ line associated with this serial port, if applicable for the
  845. * serial I/O method being used. This function cannot be called while the port
  846. * is open.
  847. *
  848. * Parameters: hPort - Handle to a serial port object.
  849. *
  850. * btIRQLevel - A number from 1 to 15, specifying the IRQ line that
  851. * the serial port is wired to.
  852. *
  853. * Return: kODRCSuccess on success, or an error code on failure.
  854. */
  855. tODResult ODComSetIRQ(tPortHandle hPort, BYTE btIRQLevel)
  856. {
  857. tPortInfo *pPortInfo = ODHANDLE2PTR(hPort, tPortInfo);
  858. VERIFY_CALL(pPortInfo != NULL);
  859. VERIFY_CALL(!pPortInfo->bIsOpen);
  860. pPortInfo->btIRQLevel = btIRQLevel;
  861. /* Return with success. */
  862. return(kODRCSuccess);
  863. }
  864. /* ----------------------------------------------------------------------------
  865. * ODComSetWordFormat()
  866. *
  867. * Determine the word format (number of data bits, stop bits and parity bits)
  868. * to use, if it can be set for the serial I/O method being used. If this
  869. * function is not called, N81 word format is used. This function can only
  870. * be called when the port is not open.
  871. *
  872. * Parameters: hPort - Handle to a serial port object.
  873. *
  874. * btWordFormat - Bitwise-or (|) of PARITY_*, STOP_* and DATABITS_*
  875. * settings which determine the word format to use.
  876. *
  877. * Return: kODRCSuccess on success, or an error code on failure.
  878. */
  879. tODResult ODComSetWordFormat(tPortHandle hPort, BYTE btWordFormat)
  880. {
  881. tPortInfo *pPortInfo = ODHANDLE2PTR(hPort, tPortInfo);
  882. VERIFY_CALL(pPortInfo != NULL);
  883. VERIFY_CALL(!pPortInfo->bIsOpen);
  884. pPortInfo->btWordFormat = btWordFormat;
  885. /* Return with success. */
  886. return(kODRCSuccess);
  887. }
  888. /* ----------------------------------------------------------------------------
  889. * ODComSetRXBuf()
  890. *
  891. * Sets the desired size of the receive buffer, if possible for the
  892. * serial I/O method being used. Note that for some serial I/O methods, this
  893. * buffer size is fixed, controlled by the user's system configuration.
  894. * No error is generated when this function is called when such serial I/O
  895. * methods will be used - in this case this setting will simply have no effect.
  896. * This function cannot be called while the port is open.
  897. *
  898. * Parameters: hPort - Handle to a serial port object.
  899. *
  900. * nReceiveBufferSize - Number of bytes in the receive buffer.
  901. *
  902. * Return: kODRCSuccess on success, or an error code on failure.
  903. */
  904. tODResult ODComSetRXBuf(tPortHandle hPort, int nReceiveBufferSize)
  905. {
  906. tPortInfo *pPortInfo = ODHANDLE2PTR(hPort, tPortInfo);
  907. VERIFY_CALL(pPortInfo != NULL);
  908. VERIFY_CALL(!pPortInfo->bIsOpen);
  909. pPortInfo->nReceiveBufferSize = nReceiveBufferSize;
  910. /* Return with success. */
  911. return(kODRCSuccess);
  912. }
  913. /* ----------------------------------------------------------------------------
  914. * ODComSetTXBuf()
  915. *
  916. * Sets the desired size of the transmit buffer, if possible for the
  917. * serial I/O method being used. Note that for some serial I/O methods, this
  918. * buffer size is fixed, controlled by the user's system configuration.
  919. * No error is generated when this function is called when such serial I/O
  920. * methods will be used - in this case this setting will simply have no effect.
  921. * This function cannot be called while the port is open.
  922. *
  923. * Parameters: hPort - Handle to a serial port object.
  924. *
  925. * nTransmitBufferSize - Number of bytes in the transmit buffer.
  926. *
  927. * Return: kODRCSuccess on success, or an error code on failure.
  928. */
  929. tODResult ODComSetTXBuf(tPortHandle hPort, int nTransmitBufferSize)
  930. {
  931. tPortInfo *pPortInfo = ODHANDLE2PTR(hPort, tPortInfo);
  932. VERIFY_CALL(pPortInfo != NULL);
  933. VERIFY_CALL(!pPortInfo->bIsOpen);
  934. pPortInfo->nTransmitBufferSize = nTransmitBufferSize;
  935. /* Return with success. */
  936. return(kODRCSuccess);
  937. }
  938. /* ----------------------------------------------------------------------------
  939. * ODComSetFIFO()
  940. *
  941. * Enables or disables use of the UART FIFO buffers (if applicable), and also
  942. * sets the FIFO trigger level. This function cannot be called while the port
  943. * is open.
  944. *
  945. * Parameters: hPort - Handle to a serial port object.
  946. *
  947. * btFIFOSetting - UART FIFO setting, including FIFO_ENABLE or
  948. * FIDO_DISABLE, and a FIFO_TRIGGER_* setting,
  949. * joined by bitwise-or (|) operators.
  950. *
  951. * Return: kODRCSuccess on success, or an error code on failure.
  952. */
  953. tODResult ODComSetFIFO(tPortHandle hPort, BYTE btFIFOSetting)
  954. {
  955. tPortInfo *pPortInfo = ODHANDLE2PTR(hPort, tPortInfo);
  956. VERIFY_CALL(pPortInfo != NULL);
  957. VERIFY_CALL(!pPortInfo->bIsOpen);
  958. pPortInfo->btFIFOSetting = btFIFOSetting;
  959. /* Return with success. */
  960. return(kODRCSuccess);
  961. }
  962. /* ----------------------------------------------------------------------------
  963. * ODComSetPreferredMethod()
  964. *
  965. * Sets the method to be used to perform serial I/O.
  966. *
  967. * Parameters: hPort - Handle to a serial port object.
  968. *
  969. * Method - The method to be used for peforming serial I/O,
  970. * or kComMethodUnspecified to have the serial I/O
  971. * routines to automatically choose the method to use.
  972. *
  973. * Return: kODRCSuccess on success, or an error code on failure.
  974. */
  975. tODResult ODComSetPreferredMethod(tPortHandle hPort, tComMethod Method)
  976. {
  977. tPortInfo *pPortInfo = ODHANDLE2PTR(hPort, tPortInfo);
  978. VERIFY_CALL(pPortInfo != NULL);
  979. VERIFY_CALL(!pPortInfo->bIsOpen);
  980. pPortInfo->Method = Method;
  981. /* Return with success. */
  982. return(kODRCSuccess);
  983. }
  984. /* ----------------------------------------------------------------------------
  985. * ODComGetMethod()
  986. *
  987. * Returns the method being used to perform serial I/O, if this has been
  988. * determined. You can only assume that this value will be set after
  989. * ODComOpen() has been called.
  990. *
  991. * Parameters: hPort - Handle to a serial port object.
  992. *
  993. * pMethod - Pointer to a tComMethod, in which function will
  994. * store the method of serial I/O being used, if this
  995. * has been determined.
  996. *
  997. * Return: kODRCSuccess on success, or an error code on failure.
  998. */
  999. tODResult ODComGetMethod(tPortHandle hPort, tComMethod *pMethod)
  1000. {
  1001. tPortInfo *pPortInfo = ODHANDLE2PTR(hPort, tPortInfo);
  1002. VERIFY_CALL(pPortInfo != NULL);
  1003. VERIFY_CALL(pMethod != NULL);
  1004. *pMethod = pPortInfo->Method;
  1005. return(kODRCSuccess);
  1006. }
  1007. /* ----------------------------------------------------------------------------
  1008. * ODComOpen()
  1009. *
  1010. * Initializes serial I/O for appropriate serial I/O mechanism (e.g. FOSSIL
  1011. * driver, internal async I/O, etc.)
  1012. *
  1013. * Parameters: hPort - Handle to a serial port object.
  1014. *
  1015. * Return: kODRCSuccess on success, or an error code on failure.
  1016. */
  1017. tODResult ODComOpen(tPortHandle hPort)
  1018. {
  1019. #if defined(INCLUDE_FOSSIL_COM) || defined(INCLUDE_UART_COM)
  1020. unsigned int uDivisor;
  1021. unsigned long ulQuotient, ulRemainder;
  1022. BYTE btTemp;
  1023. #endif /* INCLUDE_FOSSIL_COM || INCLUDE_UART_COM */
  1024. #ifdef INCLUDE_STDIO_COM
  1025. struct termios tio_raw;
  1026. #endif
  1027. tPortInfo *pPortInfo = ODHANDLE2PTR(hPort, tPortInfo);
  1028. int nPort;
  1029. VERIFY_CALL(pPortInfo != NULL);
  1030. nPort = (int)pPortInfo->btPort;
  1031. /* Ensure that port is not already open. */
  1032. VERIFY_CALL(!pPortInfo->bIsOpen);
  1033. /* The following code is used to handle FOSSIL-based serial I/O open */
  1034. /* operations. */
  1035. #ifdef INCLUDE_FOSSIL_COM
  1036. /* If use of FOSSIL driver has not been disabled, then first attempt to */
  1037. /* use it. */
  1038. if(pPortInfo->Method == kComMethodFOSSIL ||
  1039. pPortInfo->Method == kComMethodUnspecified)
  1040. {
  1041. /* Attempt to open port with FOSSIL DRIVER. */
  1042. ASM push si
  1043. ASM push di
  1044. ASM mov ah, 4
  1045. ASM mov dx, nPort
  1046. ASM mov bx, 0
  1047. ASM int 20
  1048. ASM pop di
  1049. ASM pop si
  1050. ASM cmp ax, 6484
  1051. ASM je fossil
  1052. goto no_fossil;
  1053. fossil:
  1054. pPortInfo->Method = kComMethodFOSSIL;
  1055. /* Enable flow control, if applicable. */
  1056. /* Generate flow control setting. All bits in high nibble of flow */
  1057. /* control are set to 1, because some FOSSIL driver implementations */
  1058. /* use the high nibble as a control mask. */
  1059. if(pPortInfo->btFlowControlSetting & FLOW_DEFAULT)
  1060. {
  1061. btTemp = FLOW_RTSCTS | 0xf0;
  1062. }
  1063. else
  1064. {
  1065. btTemp = pPortInfo->btFlowControlSetting | 0xf0;
  1066. }
  1067. ASM push si
  1068. ASM push di
  1069. ASM mov ah, 0x0f
  1070. ASM mov al, btTemp
  1071. ASM mov dx, nPort
  1072. ASM int 20
  1073. ASM pop di
  1074. ASM pop si
  1075. /* If serial port speed is not to be set, then return now. */
  1076. if(pPortInfo->lSpeed == SPEED_UNSPECIFIED)
  1077. {
  1078. /* Set port state to open. */
  1079. pPortInfo->bIsOpen = TRUE;
  1080. /* Return with success. */
  1081. return(kODRCSuccess);
  1082. }
  1083. /* Set to current baud rate. */
  1084. switch(pPortInfo->lSpeed)
  1085. {
  1086. case 300L:
  1087. btTemp = 0x40;
  1088. break;
  1089. case 600L:
  1090. btTemp = 0x60;
  1091. break;
  1092. case 1200L:
  1093. btTemp = 0x80;
  1094. break;
  1095. case 2400L:
  1096. btTemp = 0xa0;
  1097. break;
  1098. case 4800L:
  1099. btTemp = 0xc0;
  1100. break;
  1101. case 9600L:
  1102. btTemp = 0xe0;
  1103. break;
  1104. case 19200L:
  1105. btTemp = 0x00;
  1106. break;
  1107. case 38400L:
  1108. btTemp = 0x20;
  1109. break;
  1110. default:
  1111. /* If invalid bps rate, don't change current bps setting. */
  1112. /* Set port state to open. */
  1113. pPortInfo->bIsOpen = TRUE;
  1114. /* Return with success. */
  1115. return(kODRCSuccess);
  1116. }
  1117. /* Add desired word format parameters to data to be passed to fossil. */
  1118. btTemp |= pPortInfo->btWordFormat;
  1119. /* Initialize fossil driver. */
  1120. ASM push si
  1121. ASM push di
  1122. ASM mov al, btTemp
  1123. ASM mov ah, 0
  1124. ASM mov dx, nPort
  1125. ASM int 20
  1126. ASM pop di
  1127. ASM pop si
  1128. /* Set port state to open. */
  1129. pPortInfo->bIsOpen = TRUE;
  1130. /* Return with success. */
  1131. return(kODRCSuccess);
  1132. }
  1133. no_fossil:
  1134. #endif /* INCLUDE_FOSSIL_COM */
  1135. /* The following code is used to carry out the serial port I/O open */
  1136. /* operations if built-in UART-based serial I/O is being used. */
  1137. #ifdef INCLUDE_UART_COM
  1138. if(pPortInfo->Method == kComMethodUART ||
  1139. pPortInfo->Method == kComMethodUnspecified)
  1140. {
  1141. /* Set internal serial I/O flow control variable from pre-set */
  1142. /* flow control options. */
  1143. if(pPortInfo->btFlowControlSetting & FLOW_DEFAULT)
  1144. {
  1145. btFlowControl = FLOW_RTSCTS;
  1146. }
  1147. else
  1148. {
  1149. btFlowControl = pPortInfo->btFlowControlSetting;
  1150. }
  1151. /* Store serial I/O method being used. */
  1152. pPortInfo->Method = kComMethodUART;
  1153. /* Calculate receive buffer high and low water marks for use with */
  1154. /* flow control. */
  1155. nRXHighWaterMark = (pPortInfo->nReceiveBufferSize * RECEIVE_HIGH_NUM)
  1156. / RECEIVE_HIGH_DENOM;
  1157. nRXLowWaterMark = (pPortInfo->nReceiveBufferSize * RECEIVE_LOW_NUM)
  1158. / RECEIVE_LOW_DENOM;
  1159. /* Allocate transmit and receive buffers */
  1160. pbtTXQueue = malloc(nTXQueueSize = pPortInfo->nTransmitBufferSize);
  1161. pbtRXQueue = malloc(nRXQueueSize = pPortInfo->nReceiveBufferSize);
  1162. if(pbtTXQueue == NULL || pbtRXQueue == NULL)
  1163. {
  1164. return(kODRCNoMemory);
  1165. }
  1166. /* If serial port address is unknown. */
  1167. if(pPortInfo->nPortAddress == 0)
  1168. {
  1169. return(kODRCNoPortAddress);
  1170. }
  1171. /* Initialize table of UART register port addresses. */
  1172. nDataRegAddr = pPortInfo->nPortAddress;
  1173. nIntEnableRegAddr = nDataRegAddr + IER;
  1174. nIntIDRegAddr = nDataRegAddr + IIR;
  1175. nLineCtrlRegAddr = nDataRegAddr + LCR;
  1176. nModemCtrlRegAddr = nDataRegAddr + MCR;
  1177. nLineStatusRegAddr = nDataRegAddr + LSR;
  1178. nModemStatusRegAddr = nDataRegAddr + MSR;
  1179. /* Store interrupt vector number and PIC interrupt information for */
  1180. /* the specified IRQ line. */
  1181. if(pPortInfo->btIRQLevel <= 7)
  1182. {
  1183. btIntVector = 0x08 + (pPortInfo->btIRQLevel);
  1184. btI8259Bit = 1 << (pPortInfo->btIRQLevel);
  1185. nI8259MaskRegAddr = 0x21;
  1186. nI8259EndOfIntRegAddr = 0x20;
  1187. nI8259MasterEndOfIntRegAddr = 0x00;
  1188. }
  1189. else
  1190. {
  1191. btIntVector = 0x68 + (pPortInfo->btIRQLevel);
  1192. btI8259Bit = 1 << (pPortInfo->btIRQLevel - 8);
  1193. nI8259MaskRegAddr = 0xA1;
  1194. nI8259EndOfIntRegAddr = 0xA0;
  1195. nI8259MasterEndOfIntRegAddr = 0x20;
  1196. }
  1197. /* Save original state of UART IER register. */
  1198. ASM mov dx, nIntEnableRegAddr
  1199. ASM in al, dx
  1200. ASM mov btOldIntEnableReg, al
  1201. /* Test that a UART is indeed installed at this port address. */
  1202. ASM mov dx, nIntEnableRegAddr
  1203. ASM mov al, 0
  1204. ASM out dx, al
  1205. ASM mov dx, nIntEnableRegAddr
  1206. ASM in al, dx
  1207. ASM mov btTemp, al
  1208. if (btTemp != 0)
  1209. {
  1210. return(kODRCNoUART);
  1211. }
  1212. /* Setup for RTS/CTS flow control, if it is to be used. */
  1213. if(btFlowControl & FLOW_RTSCTS)
  1214. {
  1215. /* Read modem status register. */
  1216. ASM mov dx, nModemStatusRegAddr
  1217. ASM in al, dx
  1218. ASM mov btTemp, al
  1219. /* Enable transmission only if CTS is high. */
  1220. bStopTrans = !(btTemp & CTS);
  1221. }
  1222. /* Save original PIC interrupt settings, and temporarily disable */
  1223. /* interrupts on this IRQ line while we perform initialization. */
  1224. ASM cli
  1225. ASM mov dx, nI8259MaskRegAddr
  1226. ASM in al, dx
  1227. ASM mov btI8259Mask, al
  1228. ASM or al, btI8259Bit
  1229. ASM out dx, al
  1230. /* Initialize transmit and recieve buffers. */
  1231. ODComInternalResetTX();
  1232. ODComInternalResetRX();
  1233. /* Re-enable interrupts. */
  1234. ASM sti
  1235. /* Save original interrupt vector. */
  1236. pfOldISR = ODComGetVect(btIntVector);
  1237. /* Set interrupt vector to point to our ISR. */
  1238. #ifdef _MSC_VER
  1239. ODComSetVect(btIntVector, (void far *)ODComInternalISR);
  1240. #else /* !_MSC_VER */
  1241. ODComSetVect(btIntVector, ODComInternalISR);
  1242. #endif /* !_MSC_VER */
  1243. /* Set line control register to 8 data bits, no parity bits, 1 stop */
  1244. /* bit. */
  1245. btTemp = pPortInfo->btWordFormat;
  1246. ASM mov dx, nLineCtrlRegAddr
  1247. ASM mov al, btTemp
  1248. ASM out dx, al
  1249. /* Save original modem control register. */
  1250. ASM cli
  1251. ASM mov dx, nModemCtrlRegAddr
  1252. ASM in al, dx
  1253. ASM mov btOldModemCtrlReg, al
  1254. /* Keep current DTR setting, and activate RTS. */
  1255. btTemp = (btOldModemCtrlReg & DTR) | (OUT2 + RTS);
  1256. ASM mov dx, nModemCtrlRegAddr
  1257. ASM mov al, btTemp
  1258. ASM out dx, al
  1259. /* Enable use of 16550A FIFOs, if available. */
  1260. if(pPortInfo->btFIFOSetting & FIFO_ENABLE)
  1261. {
  1262. /* Set FIFO enable bit and trigger size. */
  1263. btBaseFIFOCtrl = pPortInfo->btFIFOSetting;
  1264. /* Attempt to enable use of FIFO buffers. */
  1265. ASM mov al, btBaseFIFOCtrl
  1266. ASM mov dx, nIntIDRegAddr
  1267. ASM out dx, al
  1268. /* Check whether a 16550A UART is actually present by reading */
  1269. /* state of FIFO buffer. */
  1270. ASM mov dx, nIntIDRegAddr
  1271. ASM in al, dx
  1272. ASM mov btTemp, al
  1273. bUsingFIFO = btTemp & 0xc0;
  1274. }
  1275. ASM sti
  1276. /* Enable receive and modem status interrupts on the UART. */
  1277. ASM mov dx, nIntEnableRegAddr
  1278. ASM mov al, DR + MS
  1279. ASM out dx, al
  1280. ASM cli
  1281. ASM mov dx, nI8259MaskRegAddr
  1282. ASM in al, dx
  1283. ASM mov ah, btI8259Bit
  1284. ASM not ah
  1285. ASM and al, ah
  1286. ASM out dx, al
  1287. ASM sti
  1288. /* Set baud rate, if possible. */
  1289. /* Calculate baud rate divisor. */
  1290. if(pPortInfo->lSpeed != SPEED_UNSPECIFIED)
  1291. {
  1292. ODDWordDivide(&ulQuotient, &ulRemainder, 115200UL, pPortInfo->lSpeed);
  1293. /* If division results in a remainder, then this is an invalid */
  1294. /* baud rate. We only change the UART baud rate if we have a valid */
  1295. /* rate to set it to. Otherwise, we cross our fingers and proceed */
  1296. /* with the currently set UART baud rate. */
  1297. if(ulRemainder == 0L)
  1298. {
  1299. uDivisor = (unsigned int)ulQuotient;
  1300. /* Disable interrupts. */
  1301. ASM cli
  1302. /* Set baud rate divisor latch. */
  1303. /* The data register now becomes the lower byte of the baud rate */
  1304. /* divisor, and the interrupt enable register becomes the upper */
  1305. /* byte of the divisor. */
  1306. ASM mov dx, nLineCtrlRegAddr
  1307. ASM in al, dx
  1308. ASM or al, DLATCH
  1309. ASM out dx, al
  1310. /* Write lower byte of baud rate divisor. */
  1311. ASM mov dx, nDataRegAddr
  1312. ASM mov ax, uDivisor
  1313. ASM out dx, al
  1314. /* Write upper byte of baud rate divisor. */
  1315. ASM mov dx, nIntEnableRegAddr
  1316. ASM mov al, ah
  1317. ASM out dx, al
  1318. /* Reset baud rate divisor latch. */
  1319. ASM mov dx, nLineCtrlRegAddr
  1320. ASM in al, dx
  1321. ASM and al, NOT_DL
  1322. ASM out dx, al
  1323. /* Re-enable interrupts. */
  1324. ASM sti
  1325. }
  1326. }
  1327. /* Remember the serial I/O method that we are using. */
  1328. pPortInfo->Method = kComMethodUART;
  1329. /* Store port state as open. */
  1330. pPortInfo->bIsOpen = TRUE;
  1331. /* Return with success. */
  1332. return(kODRCSuccess);
  1333. }
  1334. #endif /* INCLUDE_UART_COM */
  1335. /* The following code is used to handle I/O using the Door32 interface. */
  1336. #ifdef INCLUDE_DOOR32_COM
  1337. if(pPortInfo->Method == kComMethodDoor32 ||
  1338. pPortInfo->Method == kComMethodUnspecified)
  1339. {
  1340. /* Attempt to load the Door32 DLL. */
  1341. pPortInfo->hinstDoor32DLL = LoadLibrary("DOOR32.DLL");
  1342. if(pPortInfo->hinstDoor32DLL != NULL)
  1343. {
  1344. /* Obtain pointers to required Door32 API function entry points. */
  1345. pPortInfo->pfDoorInitialize = (BOOL (WINAPI *)(void))
  1346. GetProcAddress(pPortInfo->hinstDoor32DLL, "DoorInitialize");
  1347. pPortInfo->pfDoorShutdown = (BOOL (WINAPI *)(void))
  1348. GetProcAddress(pPortInfo->hinstDoor32DLL, "DoorShutdown");
  1349. pPortInfo->pfDoorWrite = (BOOL (WINAPI *)(const BYTE *, DWORD))
  1350. GetProcAddress(pPortInfo->hinstDoor32DLL, "DoorWrite");
  1351. pPortInfo->pfDoorRead = (DWORD (WINAPI *)(BYTE *, DWORD))
  1352. GetProcAddress(pPortInfo->hinstDoor32DLL, "DoorRead");
  1353. pPortInfo->pfDoorGetAvailableEventHandle = (HANDLE (WINAPI *)(void))
  1354. GetProcAddress(pPortInfo->hinstDoor32DLL,
  1355. "DoorGetAvailableEventHandle");
  1356. pPortInfo->pfDoorGetOfflineEventHandle = (HANDLE (WINAPI *)(void))
  1357. GetProcAddress(pPortInfo->hinstDoor32DLL,
  1358. "DoorGetOfflineEventHandle");
  1359. /* Check whether we have successfully been able to obtain all the */
  1360. /* required function entry points. */
  1361. if(pPortInfo->pfDoorInitialize != NULL
  1362. && pPortInfo->pfDoorShutdown != NULL
  1363. && pPortInfo->pfDoorWrite != NULL
  1364. && pPortInfo->pfDoorRead != NULL
  1365. && pPortInfo->pfDoorGetAvailableEventHandle != NULL
  1366. && pPortInfo->pfDoorGetOfflineEventHandle != NULL)
  1367. {
  1368. if((*pPortInfo->pfDoorInitialize)())
  1369. {
  1370. /* Set port state as open. */
  1371. pPortInfo->bIsOpen = TRUE;
  1372. /* Set serial I/O method. */
  1373. pPortInfo->Method = kComMethodDoor32;
  1374. /* Return with success. */
  1375. return(kODRCSuccess);
  1376. }
  1377. }
  1378. /* On failure to obtain all Door32 function entry points, unload */
  1379. /* the Door32 DLL. */
  1380. FreeLibrary(pPortInfo->hinstDoor32DLL);
  1381. }
  1382. /* If our attempt to use the Door32 interface failed for any reason, */
  1383. /* then proceed, attempting to use the Win32 serial I/O interface. */
  1384. }
  1385. #endif /* INCLUDE_DOOR32_COM */
  1386. /* The following code is used to handle Win32 API-base serial I/O */
  1387. /* open operations. */
  1388. #ifdef INCLUDE_WIN32_COM
  1389. if(pPortInfo->Method == kComMethodWin32 ||
  1390. pPortInfo->Method == kComMethodUnspecified)
  1391. {
  1392. char szDevName[7];
  1393. DCB dcb;
  1394. /* Generate device name. */
  1395. sprintf(szDevName, "COM%u", (unsigned)pPortInfo->btPort + 1);
  1396. /* Attempt to create handle for device. */
  1397. pPortInfo->hCommDev = CreateFile(szDevName, GENERIC_READ | GENERIC_WRITE,
  1398. 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  1399. /* On open failure, return with an error code. */
  1400. if(pPortInfo->hCommDev == INVALID_HANDLE_VALUE)
  1401. {
  1402. return(kODRCGeneralFailure);
  1403. }
  1404. /* Note that read timeout settings have not been set. */
  1405. pPortInfo->ReadTimeoutState = kNotSet;
  1406. /* Call SetupComm() to set queue sizes. */
  1407. if(!SetupComm(pPortInfo->hCommDev, pPortInfo->nReceiveBufferSize,
  1408. pPortInfo->nTransmitBufferSize))
  1409. {
  1410. CloseHandle(pPortInfo->hCommDev);
  1411. return(kODRCGeneralFailure);
  1412. }
  1413. /* Get current port state. */
  1414. if(!GetCommState(pPortInfo->hCommDev, &dcb))
  1415. {
  1416. CloseHandle(pPortInfo->hCommDev);
  1417. return(kODRCGeneralFailure);
  1418. }
  1419. /* Fill device control block. */
  1420. /* Set bps rate, if appropriate. */
  1421. if(pPortInfo->lSpeed != SPEED_UNSPECIFIED)
  1422. {
  1423. dcb.BaudRate = pPortInfo->lSpeed;
  1424. }
  1425. /* Set flow control, if appropriate. */
  1426. if(!(pPortInfo->btFlowControlSetting & FLOW_DEFAULT))
  1427. {
  1428. if(pPortInfo->btFlowControlSetting & FLOW_RTSCTS)
  1429. {
  1430. dcb.fOutxCtsFlow = 1;
  1431. dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
  1432. }
  1433. else
  1434. {
  1435. dcb.fOutxCtsFlow = 0;
  1436. dcb.fRtsControl = RTS_CONTROL_ENABLE;
  1437. }
  1438. }
  1439. /* Set word size. */
  1440. if((pPortInfo->btWordFormat & DATABITS_MASK) == DATABITS_FIVE)
  1441. {
  1442. dcb.ByteSize = 5;
  1443. }
  1444. else if((pPortInfo->btWordFormat & DATABITS_MASK) == DATABITS_SIX)
  1445. {
  1446. dcb.ByteSize = 6;
  1447. }
  1448. else if((pPortInfo->btWordFormat & DATABITS_MASK) == DATABITS_SEVEN)
  1449. {
  1450. dcb.ByteSize = 7;
  1451. }
  1452. else if((pPortInfo->btWordFormat & DATABITS_MASK) == DATABITS_EIGHT)
  1453. {
  1454. dcb.ByteSize = 8;
  1455. }
  1456. /* Set parity. */
  1457. if((pPortInfo->btWordFormat & ODPARITY_MASK) == ODPARITY_NONE)
  1458. {
  1459. dcb.Parity = NOPARITY;
  1460. }
  1461. else if((pPortInfo->btWordFormat & ODPARITY_MASK) == ODPARITY_ODD)
  1462. {
  1463. dcb.Parity = ODDPARITY;
  1464. }
  1465. else if((pPortInfo->btWordFormat & ODPARITY_MASK) == ODPARITY_EVEN)
  1466. {
  1467. dcb.Parity = EVENPARITY;
  1468. }
  1469. /* Enable DTR control. */
  1470. dcb.fDtrControl = DTR_CONTROL_ENABLE;
  1471. /* Set number of stop bits. */
  1472. if((pPortInfo->btWordFormat & STOP_MASK) == STOP_ONE)
  1473. {
  1474. dcb.StopBits = ONESTOPBIT;
  1475. }
  1476. else if((pPortInfo->btWordFormat & STOP_MASK) == STOP_ONE_POINT_FIVE)
  1477. {
  1478. dcb.StopBits = ONE5STOPBITS;
  1479. }
  1480. else if((pPortInfo->btWordFormat & STOP_MASK) == STOP_TWO)
  1481. {
  1482. dcb.StopBits = TWOSTOPBITS;
  1483. }
  1484. /* Set comm state from device control block. */
  1485. if(!SetCommState(pPortInfo->hCommDev, &dcb))
  1486. {
  1487. CloseHandle(pPortInfo->hCommDev);
  1488. return(kODRCGeneralFailure);
  1489. }
  1490. /* Store port state as open. */
  1491. pPortInfo->bIsOpen = TRUE;
  1492. /* Set serial I/O method. */
  1493. pPortInfo->Method = kComMethodWin32;
  1494. /* Return with success. */
  1495. return(kODRCSuccess);
  1496. }
  1497. #endif /* INCLUDE_WIN32_COM */
  1498. #ifdef INCLUDE_STDIO_COM
  1499. if(pPortInfo->Method == kComMethodStdIO ||
  1500. pPortInfo->Method == kComMethodUnspecified)
  1501. {
  1502. if (isatty(STDIN_FILENO)) {
  1503. tcgetattr(STDIN_FILENO,&tio_default);
  1504. tio_raw = tio_default;
  1505. #ifdef __sun
  1506. tio_raw.c_iflag &= ~(IMAXBEL|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
  1507. tio_raw.c_oflag &= ~OPOST;
  1508. tio_raw.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
  1509. tio_raw.c_cflag &= ~(CSIZE|PARENB);
  1510. tio_raw.c_cflag |= CS8;
  1511. tio_raw.c_cc[VMIN] = 1;
  1512. tio_raw.c_cc[VTIME] = 0;
  1513. #else
  1514. cfmakeraw(&tio_raw);
  1515. #endif
  1516. tcsetattr(STDIN_FILENO,TCSANOW,&tio_raw);
  1517. setvbuf(stdout, NULL, _IONBF, 0);
  1518. } else {
  1519. setvbuf(stdout, NULL, _IONBF, 0);
  1520. }
  1521. /* Set port state as open. */
  1522. pPortInfo->bIsOpen = TRUE;
  1523. /* Set serial I/O method. */
  1524. pPortInfo->Method = kComMethodStdIO;
  1525. /* Return with success. */
  1526. return(kODRCSuccess);
  1527. }
  1528. #endif /* INCLUDE_STDIO_COM */
  1529. /* If we get to this point, then no form of serial I/O could be */
  1530. /* initialized. */
  1531. return(kODRCGeneralFailure);
  1532. }
  1533. /* ----------------------------------------------------------------------------
  1534. * ODComOpenFromExistingHandle()
  1535. *
  1536. * Initializes serial I/O using a serial port handle natvie to the current
  1537. * operating system, which has already been opened by another application.
  1538. *
  1539. * Parameters: hPort - Handle to a serial port object.
  1540. *
  1541. * dwExistingHandle - Native operating system's handle to an
  1542. * already open serial port.
  1543. *
  1544. * Return: kODRCSuccess on success, or an error code on failure.
  1545. */
  1546. tODResult ODComOpenFromExistingHandle(tPortHandle hPort,
  1547. DWORD dwExistingHandle)
  1548. {
  1549. tPortInfo *pPortInfo = ODHANDLE2PTR(hPort, tPortInfo);
  1550. VERIFY_CALL(pPortInfo != NULL);
  1551. VERIFY_CALL(!pPortInfo->bIsOpen);
  1552. #ifdef INCLUDE_SOCKET_COM
  1553. if(pPortInfo->Method == kComMethodSocket) {
  1554. socklen_t delay=FALSE;
  1555. pPortInfo->socket = dwExistingHandle;
  1556. getsockopt(pPortInfo->socket, IPPROTO_TCP, TCP_NODELAY, &(pPortInfo->old_delay), &delay);
  1557. delay=FALSE;
  1558. setsockopt(pPortInfo->socket, IPPROTO_TCP, TCP_NODELAY, &delay, sizeof(delay));
  1559. pPortInfo->bIsOpen = TRUE;
  1560. return(kODRCSuccess);
  1561. }
  1562. #endif /* INCLUDE_SOCKET_COM */
  1563. #ifdef INCLUDE_WIN32_COM
  1564. /* Store handle to the Win32 handle to the serial port. */
  1565. pPortInfo->hCommDev = (HANDLE)dwExistingHandle;
  1566. /* Remember that read timeout settings have not been set. */
  1567. pPortInfo->ReadTimeoutState = kNotSet;
  1568. /* Remember that we are using a handle provided by the client, rather */
  1569. /* than one that we opened ourself. This flag prevents the handle from */
  1570. /* being closed by a call to ODComClose(). */
  1571. pPortInfo->bUsingClientsHandle = TRUE;
  1572. /* Remember that the serial port is now open. */
  1573. pPortInfo->bIsOpen = TRUE;
  1574. return(kODRCSuccess);
  1575. #else /* !INCLUDE_WIN32_COM */
  1576. UNUSED(dwExistingHandle);
  1577. UNUSED(pPortInfo);
  1578. /* If no form of serial I/O included in this build can use this handle, */
  1579. /* then return with a failure. */
  1580. return(kODRCInvalidCall);
  1581. #endif /* !INCLUDE_WIN32_COM */
  1582. }
  1583. /* ----------------------------------------------------------------------------
  1584. * ODComClose()
  1585. *
  1586. * Closes currently open serial port.
  1587. *
  1588. * Parameters: hPort - Handle to a serial port object.
  1589. *
  1590. * Return: kODRCSuccess on success, or an error code on failure.
  1591. */
  1592. tODResult ODComClose(tPortHandle hPort)
  1593. {
  1594. #ifdef INCLUDE_UART_COM
  1595. BYTE btTemp;
  1596. #endif /* INCLUDE_UART_COM */
  1597. tPortInfo *pPortInfo = ODHANDLE2PTR(hPort, tPortInfo);
  1598. int nPort;
  1599. VERIFY_CALL(pPortInfo != NULL);
  1600. VERIFY_CALL(pPortInfo->bIsOpen);
  1601. /* If we are using the client's handle, then we should not close it. */
  1602. if(pPortInfo->bUsingClientsHandle)
  1603. {
  1604. pPortInfo->bIsOpen = FALSE;
  1605. return(kODRCSuccess);
  1606. }
  1607. nPort = (int)pPortInfo->btPort;
  1608. switch(pPortInfo->Method)
  1609. {
  1610. #ifdef INCLUDE_FOSSIL_COM
  1611. case kComMethodFOSSIL:
  1612. ASM mov ah, 5
  1613. ASM mov dx, nPort
  1614. ASM int 20
  1615. break;
  1616. #endif /* INCLUDE_FOSSIL_COM */
  1617. #ifdef INCLUDE_UART_COM
  1618. case kComMethodUART:
  1619. /* Reset UART registers to their original values. */
  1620. ASM mov dx, nModemCtrlRegAddr
  1621. ASM mov al, btOldModemCtrlReg
  1622. ASM out dx, al
  1623. ASM mov dx, nIntEnableRegAddr
  1624. ASM mov al, btOldIntEnableReg
  1625. ASM out dx, al
  1626. /* Disable interrupts. */
  1627. ASM cli
  1628. /* Reset this line's interrupt enable status on the PIC to its */
  1629. /* original state. */
  1630. ASM mov dx, nI8259MaskRegAddr
  1631. ASM in al, dx
  1632. ASM mov btTemp, al
  1633. btTemp = (btTemp & ~btI8259Bit) | (btI8259Mask & btI8259Bit);
  1634. ASM mov dx, nI8259MaskRegAddr
  1635. ASM mov al, btTemp
  1636. ASM out dx, al
  1637. /* Re-enable interrupts. */
  1638. ASM sti
  1639. /* Reset vector to original interrupt handler. */
  1640. #ifdef _MSC_VER
  1641. ODComSetVect(btIntVector, (void far *)pfOldISR);
  1642. #else /* !_MSC_VER */
  1643. ODComSetVect(btIntVector, pfOldISR);
  1644. #endif /* !_MSC_VER */
  1645. break;
  1646. #endif /* INCLUDE_UART_COM */
  1647. #ifdef INCLUDE_WIN32_COM
  1648. case kComMethodWin32:
  1649. CloseHandle(pPortInfo->hCommDev);
  1650. break;
  1651. #endif /* INCLUDE_WIN32_COM */
  1652. #ifdef INCLUDE_DOOR32_COM
  1653. case kComMethodDoor32:
  1654. ASSERT(pPortInfo->pfDoorShutdown != NULL);
  1655. (*pPortInfo->pfDoorShutdown)();
  1656. ASSERT(pPortInfo->hinstDoor32DLL != NULL);
  1657. FreeLibrary(pPortInfo->hinstDoor32DLL);
  1658. break;
  1659. #endif /* INCLUDE_DOOR32_COM */
  1660. #ifdef INCLUDE_SOCKET_COM
  1661. case kComMethodSocket:
  1662. setsockopt(pPortInfo->socket, IPPROTO_TCP, TCP_NODELAY, &(pPortInfo->old_delay), sizeof(pPortInfo->old_delay));
  1663. closesocket(pPortInfo->socket);
  1664. break;
  1665. #endif /* INCLUDE_SOCKET_COM */
  1666. #ifdef INCLUDE_STDIO_COM
  1667. case kComMethodStdIO:
  1668. if(isatty(STDIN_FILENO))
  1669. tcsetattr(STDIN_FILENO,TCSANOW,&tio_default);
  1670. break;
  1671. #endif
  1672. default:
  1673. /* If we get here, then the current serial I/O method is not */
  1674. /* handled by this function. */
  1675. ASSERT(FALSE);
  1676. }
  1677. /* Store the fact that the port is now closed. */
  1678. pPortInfo->bIsOpen = FALSE;
  1679. /* Return with success. */
  1680. return(kODRCSuccess);
  1681. }
  1682. /* ----------------------------------------------------------------------------
  1683. * ODComCarrier()
  1684. *
  1685. * Determines whether or not the carrier detect signal is present.
  1686. *
  1687. * Parameters: hPort - Handle to a serial port object.
  1688. *
  1689. * pbIsCarrier - Location to store result. Set to TRUE if carrier
  1690. * detect signal is high, FALSE if it is low.
  1691. *
  1692. * Return: kODRCSuccess on success, or an error code on failure.
  1693. */
  1694. tODResult ODComCarrier(tPortHandle hPort, BOOL *pbIsCarrier)
  1695. {
  1696. #ifdef ODPLAT_NIX
  1697. sigset_t sigs;
  1698. #endif
  1699. tPortInfo *pPortInfo = ODHANDLE2PTR(hPort, tPortInfo);
  1700. int nPort;
  1701. VERIFY_CALL(pPortInfo != NULL);
  1702. VERIFY_CALL(pbIsCarrier != NULL);
  1703. VERIFY_CALL(pPortInfo->bIsOpen);
  1704. nPort = pPortInfo->btPort;
  1705. switch(pPortInfo->Method)
  1706. {
  1707. #ifdef INCLUDE_FOSSIL_COM
  1708. case kComMethodFOSSIL:
  1709. {
  1710. int to_return;
  1711. ASM mov ah, 3
  1712. ASM mov dx, nPort
  1713. ASM int 20
  1714. ASM and ax, 128
  1715. ASM mov to_return, ax
  1716. *pbIsCarrier = to_return;
  1717. break;
  1718. }
  1719. #endif /* INCLUDE_FOSSIL_COM */
  1720. #ifdef INCLUDE_UART_COM
  1721. case kComMethodUART:
  1722. {
  1723. BYTE btMSR;
  1724. ASM mov dx, nModemStatusRegAddr
  1725. ASM in al, dx
  1726. ASM mov btMSR, al
  1727. *pbIsCarrier = btMSR & RLSD;
  1728. break;
  1729. }
  1730. #endif /* INCLUDE_UART_COM */
  1731. #ifdef INCLUDE_WIN32_COM
  1732. case kComMethodWin32:
  1733. {
  1734. DWORD dwModemStats;
  1735. /* Get modem status settings. */
  1736. if(!GetCommModemStatus(pPortInfo->hCommDev, &dwModemStats))
  1737. {
  1738. return(kODRCGeneralFailure);
  1739. }
  1740. *pbIsCarrier = (dwModemStats & MS_RLSD_ON) ? TRUE : FALSE;
  1741. break;
  1742. }
  1743. #endif /* INCLUDE_WIN32_COM */
  1744. #ifdef INCLUDE_DOOR32_COM
  1745. case kComMethodDoor32:
  1746. ASSERT(pPortInfo->pfDoorGetOfflineEventHandle != NULL);
  1747. *pbIsCarrier = (WaitForSingleObject(
  1748. (*pPortInfo->pfDoorGetOfflineEventHandle)(),
  1749. 0) != WAIT_OBJECT_0);
  1750. break;
  1751. #endif /* INCLUDE_DOOR32_COM */
  1752. #ifdef INCLUDE_SOCKET_COM
  1753. case kComMethodSocket:
  1754. {
  1755. int i;
  1756. char ch;
  1757. fd_set socket_set;
  1758. struct timeval tv;
  1759. FD_ZERO(&socket_set);
  1760. FD_SET(pPortInfo->socket,&socket_set);
  1761. tv.tv_sec=0;
  1762. tv.tv_usec=0;
  1763. i=select(pPortInfo->socket+1,&socket_set,NULL,NULL,&tv);
  1764. if(i==0
  1765. || (i==1 && recv(pPortInfo->socket,&ch,1,MSG_PEEK)==1))
  1766. *pbIsCarrier = TRUE;
  1767. else
  1768. *pbIsCarrier = FALSE;
  1769. break;
  1770. }
  1771. #endif
  1772. #ifdef INCLUDE_STDIO_COM
  1773. case kComMethodStdIO:
  1774. {
  1775. sigpending(&sigs);
  1776. if(sigismember(&sigs,SIGHUP))
  1777. *pbIsCarrier = FALSE;
  1778. else
  1779. *pbIsCarrier = TRUE;
  1780. break;
  1781. }
  1782. #endif
  1783. default:
  1784. /* If we get here, then the current serial I/O method is not */
  1785. /* handled by this function. */
  1786. ASSERT(FALSE);
  1787. }
  1788. return(kODRCSuccess);
  1789. }
  1790. /* ----------------------------------------------------------------------------
  1791. * ODComSetDTR()
  1792. *
  1793. * Raises or lowers the DTR signal on the port.
  1794. *
  1795. * Parameters: hPort - Handle to a serial port object.
  1796. *
  1797. * bHigh - TRUE to raise DTR, FALSE to lower it.
  1798. *
  1799. * Return: kODRCSuccess on success, or an error code on failure.
  1800. */
  1801. tODResult ODComSetDTR(tPortHandle hPort, BOOL bHigh)
  1802. {
  1803. tPortInfo *pPortInfo = ODHANDLE2PTR(hPort, tPortInfo);
  1804. int nPort;
  1805. VERIFY_CALL(pPortInfo != NULL);
  1806. VERIFY_CALL(pPortInfo->bIsOpen);
  1807. nPort = pPortInfo->btPort;
  1808. switch(pPortInfo->Method)
  1809. {
  1810. #ifdef INCLUDE_FOSSIL_COM
  1811. case kComMethodFOSSIL:
  1812. ASM cmp byte ptr bHigh, 0
  1813. ASM je lower
  1814. ASM mov al, 1
  1815. ASM jmp set_dtr
  1816. lower:
  1817. ASM xor al, al
  1818. set_dtr:
  1819. ASM mov ah, 6
  1820. ASM mov dx, nPort
  1821. ASM int 20
  1822. #endif /* INCLUDE_FOSSIL_COM */
  1823. #ifdef INCLUDE_UART_COM
  1824. case kComMethodUART:
  1825. if(bHigh)
  1826. {
  1827. ASM cli
  1828. ASM mov dx, nModemCtrlRegAddr
  1829. ASM in al, dx
  1830. ASM or al, DTR
  1831. ASM out dx, al
  1832. ASM sti
  1833. }
  1834. else
  1835. {
  1836. ASM cli
  1837. ASM mov dx, nModemCtrlRegAddr
  1838. ASM in al, dx
  1839. ASM and al, NOT_DTR
  1840. ASM out dx, al
  1841. ASM sti
  1842. }
  1843. break;
  1844. #endif /* INCLUDE_UART_COM */
  1845. #ifdef INCLUDE_WIN32_COM
  1846. case kComMethodWin32:
  1847. /* Set DTR line appropriately. */
  1848. if(!EscapeCommFunction(pPortInfo->hCommDev, bHigh ? SETDTR : CLRDTR))
  1849. {
  1850. return(kODRCGeneralFailure);
  1851. }
  1852. break;
  1853. #endif /* INCLUDE_WIN32_COM */
  1854. #ifdef INCLUDE_DOOR32_COM
  1855. case kComMethodDoor32:
  1856. return(kODRCUnsupported);
  1857. #endif /* INCLUDE_DOOR32_COM */
  1858. #ifdef INCLUDE_SOCKET_COM
  1859. case kComMethodSocket:
  1860. if(bHigh)
  1861. return(kODRCUnsupported);
  1862. closesocket(pPortInfo->socket);
  1863. break;
  1864. #endif /* INCLUDE_SOCKET_CO */
  1865. #ifdef INCLUDE_STDIO_COM
  1866. case kComMethodStdIO:
  1867. return(kODRCUnsupported);
  1868. #endif
  1869. default:
  1870. /* If we get here, then the current serial I/O method is not */
  1871. /* handled by this function. */
  1872. ASSERT(FALSE);
  1873. }
  1874. return(kODRCSuccess);
  1875. }
  1876. /* ----------------------------------------------------------------------------
  1877. * ODComOutbound()
  1878. *
  1879. * Determines the number of bytes waiting in the serial port outbound buffer.
  1880. *
  1881. * Parameters: hPort - Handle to a serial port object.
  1882. *
  1883. * pnOutboundWaiting - Location where result the number of bytes
  1884. * waiting in the outbound buffer should be
  1885. * stored. Under some I/O methods we can
  1886. * determine whether data is still in the
  1887. * buffer, but not the number of bytes in the
  1888. * buffer. In this situation, this may be set
  1889. * to SIZE_NON_ZERO.
  1890. *
  1891. * Return: kODRCSuccess on success, or an error code on failure.
  1892. */
  1893. tODResult ODComOutbound(tPortHandle hPort, int *pnOutboundWaiting)
  1894. {
  1895. tPortInfo *pPortInfo = ODHANDLE2PTR(hPort, tPortInfo);
  1896. int nPort;
  1897. VERIFY_CALL(pPortInfo != NULL);
  1898. VERIFY_CALL(pnOutboundWaiting != NULL);
  1899. VERIFY_CALL(pPortInfo->bIsOpen);
  1900. nPort = pPortInfo->btPort;
  1901. switch(pPortInfo->Method)
  1902. {
  1903. #ifdef INCLUDE_FOSSIL_COM
  1904. case kComMethodFOSSIL:
  1905. ASM mov ah, 0x03
  1906. ASM mov dx, nPort
  1907. ASM int 20
  1908. ASM and ah, 0x40
  1909. ASM jz still_sending
  1910. *pnOutboundWaiting = 0;
  1911. break;
  1912. still_sending:
  1913. *pnOutboundWaiting = SIZE_NON_ZERO;
  1914. break;
  1915. #endif /* INCLUDE_FOSSIL_COM */
  1916. #ifdef INCLUDE_UART_COM
  1917. case kComMethodUART:
  1918. *pnOutboundWaiting = (int)nTXChars;
  1919. break;
  1920. #endif /* INCLUDE_UART_COM */
  1921. #ifdef INCLUDE_WIN32_COM
  1922. case kComMethodWin32:
  1923. {
  1924. DWORD dwErrors;
  1925. COMSTAT ComStat;
  1926. /* Use ClearCommError() to obtain device status. */
  1927. if(!ClearCommError(pPortInfo->hCommDev, &dwErrors, &ComStat))
  1928. {
  1929. return(kODRCGeneralFailure);
  1930. }
  1931. /* Set pbIsInbound to TRUE if any bytes are in outbound queue. */
  1932. *pnOutboundWaiting = (int)ComStat.cbOutQue;
  1933. break;
  1934. }
  1935. #endif /* INCLUDE_WIN32_COM */
  1936. #ifdef INCLUDE_DOOR32_COM
  1937. case kComMethodDoor32:
  1938. /* Door32 doesn't currently support this functionality, so we */
  1939. /* assume that all sent data is transmitted immediately. */
  1940. *pnOutboundWaiting = 0;
  1941. return(kODRCUnsupported);
  1942. #endif /* INCLUDE_DOOR32_COM */
  1943. #ifdef INCLUDE_SOCKET_COM
  1944. case kComMethodSocket:
  1945. *pnOutboundWaiting = 0;
  1946. return(kODRCUnsupported);
  1947. #endif /* INCLUDE_SOCKET_COM */
  1948. #ifdef INCLUDE_STDIO_COM
  1949. case kComMethodStdIO:
  1950. *pnOutboundWaiting = 0;
  1951. return(kODRCUnsupported);
  1952. #endif
  1953. default:
  1954. /* If we get here, then the current serial I/O method is not */
  1955. /* handled by this function. */
  1956. ASSERT(FALSE);
  1957. }
  1958. return(kODRCSuccess);
  1959. }
  1960. /* ----------------------------------------------------------------------------
  1961. * ODComClearOutbound()
  1962. *
  1963. * Removes the current contents of the serial port outbound buffer.
  1964. *
  1965. * Parameters: hPort - Handle to a serial port object.
  1966. *
  1967. * Return: kODRCSuccess on success, or an error code on failure.
  1968. */
  1969. tODResult ODComClearOutbound(tPortHandle hPort)
  1970. {
  1971. tPortInfo *pPortInfo = ODHANDLE2PTR(hPort, tPortInfo);
  1972. int nPort;
  1973. VERIFY_CALL(pPortInfo != NULL);
  1974. VERIFY_CALL(pPortInfo->bIsOpen);
  1975. nPort = pPortInfo->btPort;
  1976. switch(pPortInfo->Method)
  1977. {
  1978. #ifdef INCLUDE_FOSSIL_COM
  1979. case kComMethodFOSSIL:
  1980. ASM mov ah, 9
  1981. ASM mov dx, nPort
  1982. ASM int 20
  1983. #endif /* INCLUDE_FOSSIL_COM */
  1984. #ifdef INCLUDE_UART_COM
  1985. case kComMethodUART:
  1986. ODComInternalResetTX();
  1987. break;
  1988. #endif /* INCLUDE_UART_COM */
  1989. #ifdef INCLUDE_WIN32_COM
  1990. case kComMethodWin32:
  1991. if(!PurgeComm(pPortInfo->hCommDev, PURGE_TXCLEAR))
  1992. {
  1993. return(kODRCGeneralFailure);
  1994. }
  1995. break;
  1996. #endif /* INCLUDE_WIN32_COM */
  1997. #ifdef INCLUDE_DOOR32_COM
  1998. case kComMethodDoor32:
  1999. return(kODRCUnsupported);
  2000. #endif /* INCLUDE_DOOR32_COM */
  2001. #ifdef INCLUDE_SOCKET_COM
  2002. case kComMethodSocket:
  2003. return(kODRCUnsupported);
  2004. #endif /* INCLUDE_SOCKET_COM */
  2005. #ifdef INCLUDE_STDIO_COM
  2006. case kComMethodStdIO:
  2007. return(kODRCUnsupported);
  2008. #endif
  2009. default:
  2010. /* If we get here, then the current serial I/O method is not */
  2011. /* handled by this function. */
  2012. ASSERT(FALSE);
  2013. }
  2014. /* Return with success. */
  2015. return(kODRCSuccess);
  2016. }
  2017. /* ----------------------------------------------------------------------------
  2018. * ODComClearInbound()
  2019. *
  2020. * Removes the current contents of the serial port inbound buffer.
  2021. *
  2022. * Parameters: hPort - Handle to a serial port object.
  2023. *
  2024. * Return: kODRCSuccess on success, or an error code on failure.
  2025. */
  2026. tODResult ODComClearInbound(tPortHandle hPort)
  2027. {
  2028. tPortInfo *pPortInfo = ODHANDLE2PTR(hPort, tPortInfo);
  2029. int nPort;
  2030. VERIFY_CALL(pPortInfo != NULL);
  2031. VERIFY_CALL(pPortInfo->bIsOpen);
  2032. nPort = pPortInfo->btPort;
  2033. switch(pPortInfo->Method)
  2034. {
  2035. #ifdef INCLUDE_FOSSIL_COM
  2036. case kComMethodFOSSIL:
  2037. ASM mov ah, 10
  2038. ASM mov dx, nPort
  2039. ASM int 20
  2040. #endif /* INCLUDE_FOSSIL_COM */
  2041. #ifdef INCLUDE_UART_COM
  2042. case kComMethodUART:
  2043. ODComInternalResetRX();
  2044. break;
  2045. #endif /* INCLUDE_UART_COM */
  2046. #ifdef INCLUDE_WIN32_COM
  2047. case kComMethodWin32:
  2048. if(!PurgeComm(pPortInfo->hCommDev, PURGE_RXCLEAR))
  2049. {
  2050. return(kODRCGeneralFailure);
  2051. }
  2052. break;
  2053. #endif /* INCLUDE_WIN32_COM */
  2054. #ifdef INCLUDE_DOOR32_COM
  2055. case kComMethodDoor32:
  2056. return(kODRCUnsupported);
  2057. #endif /* INCLUDE_DOOR32_COM */
  2058. #ifdef INCLUDE_SOCKET_COM
  2059. case kComMethodSocket:
  2060. return(kODRCUnsupported);
  2061. #endif /* INCLUDE_SOCKET_COM */
  2062. #ifdef INCLUDE_STDIO_COM
  2063. case kComMethodStdIO:
  2064. return(kODRCUnsupported);
  2065. #endif
  2066. default:
  2067. /* If we get here, then the current serial I/O method is not */
  2068. /* handled by this function. */
  2069. ASSERT(FALSE);
  2070. }
  2071. /* Return with success. */
  2072. return(kODRCSuccess);
  2073. }
  2074. /* ----------------------------------------------------------------------------
  2075. * ODComInbound()
  2076. *
  2077. * Determines the number of bytes waiting in the serial port inbound buffer.
  2078. *
  2079. * Parameters: hPort - Handle to a serial port object.
  2080. *
  2081. * pnInboundWaiting - Location in which to store number of bytes
  2082. * waiting in the inbound buffer. Under some
  2083. * I/O methods (e.g. FOSSIL driver), we can
  2084. * determine whether data is still in the
  2085. * buffer, but not the number of bytes in the
  2086. * buffer. In this situation, this may be set
  2087. * to SIZE_NON_ZERO.
  2088. *
  2089. * Return: kODRCSuccess on success, or an error code on failure.
  2090. */
  2091. tODResult ODComInbound(tPortHandle hPort, int *pnInboundWaiting)
  2092. {
  2093. tPortInfo *pPortInfo = ODHANDLE2PTR(hPort, tPortInfo);
  2094. int nPort;
  2095. VERIFY_CALL(pPortInfo != NULL);
  2096. VERIFY_CALL(pnInboundWaiting != NULL);
  2097. VERIFY_CALL(pPortInfo->bIsOpen);
  2098. nPort = pPortInfo->btPort;
  2099. switch(pPortInfo->Method)
  2100. {
  2101. #ifdef INCLUDE_FOSSIL_COM
  2102. case kComMethodFOSSIL:
  2103. {
  2104. BOOL bDataInBuffer = FALSE;
  2105. ASM mov ah, 3
  2106. ASM mov dx, nPort
  2107. ASM push si
  2108. ASM push di
  2109. ASM int 20
  2110. ASM pop di
  2111. ASM pop si
  2112. ASM and ah, 1
  2113. ASM mov bDataInBuffer, ah
  2114. *pnInboundWaiting = bDataInBuffer ? SIZE_NON_ZERO : 0;
  2115. break;
  2116. }
  2117. #endif /* INCLUDE_FOSSIL_COM */
  2118. #ifdef INCLUDE_UART_COM
  2119. case kComMethodUART:
  2120. *pnInboundWaiting = (int)nRXChars;
  2121. break;
  2122. #endif /* INCLUDE_UART_COM */
  2123. #ifdef INCLUDE_WIN32_COM
  2124. case kComMethodWin32:
  2125. {
  2126. DWORD dwErrors;
  2127. COMSTAT ComStat;
  2128. /* Use ClearCommError() to obtain device status. */
  2129. if(!ClearCommError(pPortInfo->hCommDev, &dwErrors, &ComStat))
  2130. {
  2131. return(kODRCGeneralFailure);
  2132. }
  2133. /* Set pbIsInbound to TRUE if there are any bytes in inbound queue. */
  2134. *pnInboundWaiting = (int)ComStat.cbInQue;
  2135. break;
  2136. }
  2137. #endif /* INCLUDE_WIN32_COM */
  2138. #ifdef INCLUDE_DOOR32_COM
  2139. case kComMethodDoor32:
  2140. ASSERT(pPortInfo->pfDoorGetAvailableEventHandle != NULL);
  2141. if(WaitForSingleObject(
  2142. (*pPortInfo->pfDoorGetAvailableEventHandle)(),
  2143. 0) == WAIT_OBJECT_0)
  2144. {
  2145. *pnInboundWaiting = SIZE_NON_ZERO;
  2146. }
  2147. else
  2148. {
  2149. *pnInboundWaiting = 0;
  2150. }
  2151. break;
  2152. #endif /* INCLUDE_DOOR32_COM */
  2153. #ifdef INCLUDE_SOCKET_COM
  2154. case kComMethodSocket:
  2155. if(ioctlsocket(pPortInfo->socket,FIONREAD,pnInboundWaiting) != 0)
  2156. *pnInboundWaiting = 0;
  2157. break;
  2158. #endif /* INCLUDE_SOCKET_COM */
  2159. #ifdef INCLUDE_STDIO_COM
  2160. case kComMethodStdIO:
  2161. if(ioctl(0,FIONREAD,pnInboundWaiting) == -1)
  2162. *pnInboundWaiting = 0;
  2163. break;
  2164. #endif
  2165. default:
  2166. /* If we get here, then the current serial I/O method is not */
  2167. /* handled by this function. */
  2168. ASSERT(FALSE);
  2169. }
  2170. return(kODRCSuccess);
  2171. }
  2172. /* ----------------------------------------------------------------------------
  2173. * ODComGetByte()
  2174. *
  2175. * Returns a single inbound byte. If there are characters waiting in the
  2176. * inbound buffer, the next character is returned immediately. If bWait is TRUE
  2177. * and no characters are waiting, this function will wait until a character is
  2178. * received (possibly forever, if no characters are ever received).
  2179. *
  2180. * Parameters: hPort - Handle to a serial port object.
  2181. *
  2182. * pbtNext - Location to store retrieved byte.
  2183. *
  2184. * bWait - If TRUE, function will only return after a character
  2185. * has been received. If FALSE, this function will return
  2186. * kODRCNothingWaiting if no characters are waiting.
  2187. *
  2188. * Return: kODRCSuccess on success, or an error code on failure.
  2189. */
  2190. tODResult ODComGetByte(tPortHandle hPort, char *pbtNext, BOOL bWait)
  2191. {
  2192. tPortInfo *pPortInfo = ODHANDLE2PTR(hPort, tPortInfo);
  2193. int nPort;
  2194. VERIFY_CALL(pPortInfo != NULL);
  2195. VERIFY_CALL(pbtNext != NULL);
  2196. VERIFY_CALL(pPortInfo->bIsOpen);
  2197. nPort = pPortInfo->btPort;
  2198. switch(pPortInfo->Method)
  2199. {
  2200. #ifdef INCLUDE_FOSSIL_COM
  2201. case kComMethodFOSSIL:
  2202. {
  2203. BYTE btToReturn;
  2204. int nInboundSize;
  2205. /* If we should not wait for characters if inbound queue is empty. */
  2206. if(!bWait)
  2207. {
  2208. /* Determine whether there are any inbound characterse waiting. */
  2209. ODComInbound(hPort, &nInboundSize);
  2210. /* If there are no inbound characters waiting, then return */
  2211. /* without obtaining any characters. */
  2212. if(nInboundSize == 0) return(kODRCNothingWaiting);
  2213. }
  2214. ASM mov ah, 2
  2215. ASM mov dx, nPort
  2216. ASM push si
  2217. ASM push di
  2218. ASM int 20
  2219. ASM pop di
  2220. ASM pop si
  2221. ASM mov btToReturn, al
  2222. *pbtNext = btToReturn;
  2223. break;
  2224. }
  2225. #endif /* INCLUDE_FOSSIL_COM */
  2226. #ifdef INCLUDE_UART_COM
  2227. case kComMethodUART:
  2228. /* If we should not wait for characters if inbound queue is empty. */
  2229. if(!bWait)
  2230. {
  2231. /* If there are no inbound characters waiting, then return */
  2232. /* without obtaining any characters. */
  2233. if(!nRXChars) return(kODRCNothingWaiting);
  2234. }
  2235. /* Loop, calling idle function, until next character arrives. */
  2236. while(!nRXChars)
  2237. {
  2238. if(pPortInfo->pfIdleCallback != NULL)
  2239. {
  2240. (*pPortInfo->pfIdleCallback)();
  2241. }
  2242. }
  2243. /* Disable interrupts. */
  2244. ASM cli
  2245. /* Get next character from receive queue. */
  2246. *pbtNext = pbtRXQueue[nRXOutIndex++];
  2247. /* Wrap queue index if needed. */
  2248. if (nRXOutIndex == nRXQueueSize)
  2249. {
  2250. nRXOutIndex = 0;
  2251. }
  2252. /* Decrement count of total character in the receive queue. */
  2253. nRXChars--;
  2254. /* Re-enable interrupts. */
  2255. ASM sti
  2256. /* If receive buffer is below low water mark. */
  2257. if(nRXChars <= nRXLowWaterMark)
  2258. {
  2259. /* If we are using flow control, then stop sender from */
  2260. /* sending. */
  2261. if(btFlowControl & FLOW_RTSCTS)
  2262. {
  2263. /* If using RTS/CTS flow control, then raise RTS line. */
  2264. ASM mov dx, nModemCtrlRegAddr
  2265. ASM in al, dx
  2266. ASM or al, RTS
  2267. ASM out dx, al
  2268. }
  2269. }
  2270. break;
  2271. #endif /* INCLUDE_UART_COM */
  2272. #ifdef INCLUDE_WIN32_COM
  2273. case kComMethodWin32:
  2274. {
  2275. DWORD dwBytesRead;
  2276. DWORD dwErrors;
  2277. /* Ensure read timeout state is set appropriately for bWait value. */
  2278. if(bWait)
  2279. {
  2280. ODComWin32SetReadTimeouts(pPortInfo, kBlocking);
  2281. }
  2282. else
  2283. {
  2284. ODComWin32SetReadTimeouts(pPortInfo, kNonBlocking);
  2285. }
  2286. /* Perform read operation. */
  2287. if(!ReadFile(pPortInfo->hCommDev, pbtNext, 1, &dwBytesRead, NULL))
  2288. {
  2289. ClearCommError(pPortInfo->hCommDev, &dwErrors, NULL);
  2290. return(kODRCGeneralFailure);
  2291. }
  2292. /* Determine whether or not a byte was read. */
  2293. if(dwBytesRead == 0)
  2294. {
  2295. /* If no bytes where read, then this is a general error if bWait */
  2296. /* is TRUE. If bWait is FALSE, then we should return */
  2297. /* waiting kODRCNothingWaiting. */
  2298. return(bWait ? kODRCGeneralFailure : kODRCNothingWaiting);
  2299. }
  2300. break;
  2301. }
  2302. #endif /* INCLUDE_WIN32_COM */
  2303. #ifdef INCLUDE_DOOR32_COM
  2304. case kComMethodDoor32:
  2305. if(WaitForSingleObject((*pPortInfo->pfDoorGetAvailableEventHandle)(),
  2306. bWait ? INFINITE : 0) == WAIT_OBJECT_0)
  2307. {
  2308. (*pPortInfo->pfDoorRead)(pbtNext, 1);
  2309. break;
  2310. }
  2311. return(bWait ? kODRCGeneralFailure : kODRCNothingWaiting);
  2312. break;
  2313. #endif /* INCLUDE_DOOR32_COM */
  2314. #ifdef INCLUDE_SOCKET_COM
  2315. case kComMethodSocket:
  2316. {
  2317. fd_set socket_set;
  2318. struct timeval tv;
  2319. int select_ret, recv_ret;
  2320. FD_ZERO(&socket_set);
  2321. FD_SET(pPortInfo->socket,&socket_set);
  2322. tv.tv_sec=0;
  2323. tv.tv_usec=100;
  2324. select_ret = select(pPortInfo->socket+1, &socket_set, NULL, NULL, bWait ? NULL : &tv);
  2325. if (select_ret == SOCKET_ERROR)
  2326. return (kODRCGeneralFailure);
  2327. if (select_ret == 0)
  2328. return (kODRCNothingWaiting);
  2329. do {
  2330. recv_ret = recv(pPortInfo->socket, pbtNext, 1, 0);
  2331. if(recv_ret != SOCKET_ERROR)
  2332. break;
  2333. if(WSAGetLastError() != WSAEWOULDBLOCK)
  2334. return (kODRCGeneralFailure);
  2335. od_sleep(50);
  2336. } while (bWait);
  2337. if (recv_ret == 0)
  2338. return (kODRCNothingWaiting);
  2339. break;
  2340. }
  2341. #endif /* INCLUDE_SOCKET_COM */
  2342. #ifdef INCLUDE_STDIO_COM
  2343. case kComMethodStdIO:
  2344. {
  2345. fd_set socket_set;
  2346. struct timeval tv;
  2347. int select_ret=-1;
  2348. int recv_ret;
  2349. while(select_ret==-1) {
  2350. FD_ZERO(&socket_set);
  2351. FD_SET(STDIN_FILENO,&socket_set);
  2352. tv.tv_sec=0;
  2353. tv.tv_usec=100;
  2354. select_ret = select(STDIN_FILENO+1, &socket_set, NULL, NULL, bWait ? NULL : &tv);
  2355. if (select_ret == -1) {
  2356. if(errno==EINTR)
  2357. continue;
  2358. return (kODRCGeneralFailure);
  2359. }
  2360. if (select_ret == 0)
  2361. return (kODRCNothingWaiting);
  2362. }
  2363. recv_ret = read(STDIN_FILENO, pbtNext, 1);
  2364. if(recv_ret == 1)
  2365. break;
  2366. return (kODRCGeneralFailure);
  2367. break;
  2368. }
  2369. #endif
  2370. default:
  2371. /* If we get here, then the current serial I/O method is not */
  2372. /* handled by this function. */
  2373. ASSERT(FALSE);
  2374. }
  2375. return(0);
  2376. }
  2377. /* ----------------------------------------------------------------------------
  2378. * ODComSendByte()
  2379. *
  2380. * Sends a single byte to the serial port outbound buffer.
  2381. *
  2382. * Parameters: hPort - Handle to a serial port object.
  2383. *
  2384. * btToSend - The byte to transmit.
  2385. *
  2386. * Return: kODRCSuccess on success, or an error code on failure.
  2387. */
  2388. tODResult ODComSendByte(tPortHandle hPort, BYTE btToSend)
  2389. {
  2390. tPortInfo *pPortInfo = ODHANDLE2PTR(hPort, tPortInfo);
  2391. int nPort;
  2392. VERIFY_CALL(pPortInfo != NULL);
  2393. VERIFY_CALL(pPortInfo->bIsOpen);
  2394. nPort = pPortInfo->btPort;
  2395. switch(pPortInfo->Method)
  2396. {
  2397. #ifdef INCLUDE_FOSSIL_COM
  2398. case kComMethodFOSSIL:
  2399. try_again:
  2400. ASM mov ah, 0x0b
  2401. ASM mov dx, nPort
  2402. ASM mov al, btToSend
  2403. ASM int 20
  2404. ASM cmp ax, 0
  2405. ASM jne keep_going
  2406. /* Call idle function, if any. */
  2407. if(pPortInfo->pfIdleCallback != NULL)
  2408. {
  2409. (*pPortInfo->pfIdleCallback)();
  2410. }
  2411. goto try_again;
  2412. keep_going:
  2413. break;
  2414. #endif /* INCLUDE_FOSSIL_COM */
  2415. #ifdef INCLUDE_UART_COM
  2416. case kComMethodUART:
  2417. /* Loop, calling idle function, until characters are waiting in */
  2418. /* the transmit buffer. */
  2419. while(!ODComInternalTXReady())
  2420. {
  2421. /* Call idle function, if any. */
  2422. if(pPortInfo->pfIdleCallback != NULL)
  2423. {
  2424. (*pPortInfo->pfIdleCallback)();
  2425. }
  2426. }
  2427. /* Disable interrupts. */
  2428. ASM cli
  2429. /* Place the character in the queue. */
  2430. pbtTXQueue[nTXInIndex++] = btToSend;
  2431. /* Wrap transmit queue index, if needed. */
  2432. if (nTXInIndex == nTXQueueSize)
  2433. {
  2434. nTXInIndex = 0;
  2435. }
  2436. /* Increment count of total characters in the queue. */
  2437. nTXChars++;
  2438. /* Enable transmit interrupt on the UART. */
  2439. ASM mov dx, nIntEnableRegAddr
  2440. ASM in al, dx
  2441. ASM or al, THRE
  2442. ASM out dx, al
  2443. ASM sti
  2444. break;
  2445. #endif /* INCLUDE_UART_COM */
  2446. #ifdef INCLUDE_WIN32_COM
  2447. case kComMethodWin32:
  2448. {
  2449. DWORD dwErrors;
  2450. DWORD dwBytesWritten;
  2451. /* Attempt to perform write operation. */
  2452. if(!WriteFile(pPortInfo->hCommDev, &btToSend, 1, &dwBytesWritten,
  2453. NULL) || dwBytesWritten != 1)
  2454. {
  2455. ClearCommError(pPortInfo->hCommDev, &dwErrors, NULL);
  2456. return(kODRCGeneralFailure);
  2457. }
  2458. break;
  2459. }
  2460. #endif /* INCLUDE_WIN32_COM */
  2461. #ifdef INCLUDE_DOOR32_COM
  2462. case kComMethodDoor32:
  2463. ASSERT(pPortInfo->pfDoorWrite != NULL);
  2464. if(!(*pPortInfo->pfDoorWrite)(&btToSend, 1))
  2465. {
  2466. return(kODRCGeneralFailure);
  2467. }
  2468. break;
  2469. #endif /* INCLUDE_DOOR32_COM */
  2470. #ifdef INCLUDE_SOCKET_COM
  2471. case kComMethodSocket:
  2472. {
  2473. fd_set socket_set;
  2474. struct timeval tv;
  2475. int send_ret;
  2476. FD_ZERO(&socket_set);
  2477. FD_SET(pPortInfo->socket,&socket_set);
  2478. tv.tv_sec=1;
  2479. tv.tv_usec=0;
  2480. if(select(pPortInfo->socket+1,NULL,&socket_set,NULL,&tv) != 1)
  2481. return(kODRCGeneralFailure);
  2482. do {
  2483. send_ret = send(pPortInfo->socket, &btToSend, 1, 0);
  2484. if (send_ret != 1)
  2485. od_sleep(50);
  2486. } while ((send_ret == SOCKET_ERROR) && (WSAGetLastError() == WSAEWOULDBLOCK));
  2487. if (send_ret == SOCKET_ERROR)
  2488. return (kODRCGeneralFailure);
  2489. break;
  2490. }
  2491. #endif /* INCLUDE_SOCKET_COM */
  2492. #ifdef INCLUDE_STDIO_COM
  2493. case kComMethodStdIO:
  2494. {
  2495. fd_set fdset;
  2496. struct timeval tv;
  2497. int retval=-1;
  2498. int loopcount=0;
  2499. while(retval==-1 && loopcount < 10) {
  2500. FD_ZERO(&fdset);
  2501. FD_SET(STDOUT_FILENO,&fdset);
  2502. tv.tv_sec=1;
  2503. tv.tv_usec=0;
  2504. retval=select(STDOUT_FILENO+1,NULL,&fdset,NULL,&tv);
  2505. if(retval!=1) {
  2506. if(retval==0) {
  2507. retval=-1;
  2508. loopcount++;
  2509. continue;
  2510. }
  2511. if(retval==-1 && errno==EINTR)
  2512. continue;
  2513. return(kODRCGeneralFailure);
  2514. }
  2515. }
  2516. if(fwrite(&btToSend,1,1,stdout)!=1)
  2517. return(kODRCGeneralFailure);
  2518. break;
  2519. }
  2520. #endif
  2521. default:
  2522. /* If we get here, then the current serial I/O method is not */
  2523. /* handled by this function. */
  2524. ASSERT(FALSE);
  2525. }
  2526. /* Return with success. */
  2527. return(kODRCSuccess);
  2528. }
  2529. /* ----------------------------------------------------------------------------
  2530. * ODComGetBuffer()
  2531. *
  2532. * Retreives received data into a buffer, filling the buffer with as much data
  2533. * as possible that has been received, returning immediately.
  2534. *
  2535. * Parameters: hPort - Handle to a serial port object.
  2536. *
  2537. * pbtBuffer - Pointer to a contiguous array of bytes.
  2538. *
  2539. * nSize - Size of buffer, in bytes. This is the maximum
  2540. * number of characters that will be returned.
  2541. *
  2542. * pnBytesRead - Pointer to an int where function will store the
  2543. * number of bytes actually read.
  2544. *
  2545. * Return: kODRCSuccess on success, or an error code on failure.
  2546. */
  2547. tODResult ODComGetBuffer(tPortHandle hPort, BYTE *pbtBuffer, int nSize,
  2548. int *pnBytesRead)
  2549. {
  2550. tPortInfo *pPortInfo = ODHANDLE2PTR(hPort, tPortInfo);
  2551. int nPort;
  2552. VERIFY_CALL(pPortInfo != NULL);
  2553. VERIFY_CALL(pbtBuffer != NULL);
  2554. VERIFY_CALL(nSize > 0);
  2555. VERIFY_CALL(pnBytesRead != NULL);
  2556. VERIFY_CALL(pPortInfo->bIsOpen);
  2557. nPort = pPortInfo->btPort;
  2558. switch(pPortInfo->Method)
  2559. {
  2560. #ifdef INCLUDE_FOSSIL_COM
  2561. case kComMethodFOSSIL:
  2562. {
  2563. int nReceived;
  2564. ASM push di
  2565. ASM mov cx, nSize
  2566. ASM mov dx, nPort
  2567. #ifdef LARGEDATA
  2568. ASM les di, pbtBuffer
  2569. #else
  2570. ASM mov ax, ds
  2571. ASM mov es, ax
  2572. ASM mov di, pbtBuffer
  2573. #endif
  2574. ASM mov ah, 0x18
  2575. ASM int 20
  2576. ASM pop di
  2577. ASM mov nReceived, ax
  2578. *pnBytesRead = nReceived;
  2579. break;
  2580. }
  2581. #endif /* INCLUDE_FOSSIL_COM */
  2582. #ifdef INCLUDE_UART_COM
  2583. case kComMethodUART:
  2584. {
  2585. int nTransferSize;
  2586. int nFirstHalfSize;
  2587. int nSecondHalfSize;
  2588. char *pbtSource;
  2589. /* Disable interrupts. */
  2590. ASM cli
  2591. /* Number of bytes to transfer is minimum of buffer size, and */
  2592. /* number of bytes in receive queue. */
  2593. nTransferSize = MIN(nRXChars, nSize);
  2594. /* First half of transfer is minimum of number of bytes from here */
  2595. /* to the end of the buffer, and the total transfer size. */
  2596. nFirstHalfSize = nRXQueueSize - nRXOutIndex;
  2597. nFirstHalfSize = MIN(nFirstHalfSize, nTransferSize);
  2598. /* Second half of transfer is remaining bytes, if any. */
  2599. nSecondHalfSize = nTransferSize - nFirstHalfSize;
  2600. /* Perform first half of transfer. */
  2601. pbtSource = pbtRXQueue + nRXOutIndex;
  2602. while(nFirstHalfSize--)
  2603. {
  2604. *pbtBuffer++ = *pbtSource++;
  2605. }
  2606. /* If there is a second half to transfer. */
  2607. if(nSecondHalfSize)
  2608. {
  2609. /* Copy source will begin at beginning of queue. */
  2610. pbtSource = pbtRXQueue;
  2611. /* Set final queue out index. */
  2612. nRXOutIndex = nSecondHalfSize;
  2613. /* Perform second half of transfer. */
  2614. while(nSecondHalfSize--)
  2615. {
  2616. *pbtBuffer++ = *pbtSource++;
  2617. }
  2618. }
  2619. /* If entire transfer was performed in first half. */
  2620. else
  2621. {
  2622. /* Set final queue out index. */
  2623. nRXOutIndex += nTransferSize;
  2624. /* Wrap queue out index, if needed. */
  2625. if(nRXOutIndex == nRXQueueSize) nRXOutIndex = 0;
  2626. }
  2627. /* Subtract number of bytes retrieved from number of bytes in */
  2628. /* receive queue. */
  2629. nRXChars -= nTransferSize;
  2630. /* Return number of bytes copied into buffer. */
  2631. *pnBytesRead = nTransferSize;
  2632. /* Re-enable interrupts. */
  2633. ASM sti
  2634. break;
  2635. }
  2636. #endif /* INCLUDE_UART_COM */
  2637. #ifdef INCLUDE_WIN32_COM
  2638. case kComMethodWin32:
  2639. {
  2640. DWORD dwBytesRead;
  2641. DWORD dwErrors;
  2642. /* Ensure read timeout state is set for non-blocking read */
  2643. ODComWin32SetReadTimeouts(pPortInfo, kNonBlocking);
  2644. /* Perform read operation. */
  2645. if(!ReadFile(pPortInfo->hCommDev, pbtBuffer, nSize, &dwBytesRead,
  2646. NULL))
  2647. {
  2648. ClearCommError(pPortInfo->hCommDev, &dwErrors, NULL);
  2649. return(kODRCGeneralFailure);
  2650. }
  2651. /* Pass number of bytes read back to caller. */
  2652. *pnBytesRead = (int)dwBytesRead;
  2653. break;
  2654. }
  2655. #endif /* INCLUDE_WIN32_COM */
  2656. #ifdef INCLUDE_DOOR32_COM
  2657. case kComMethodDoor32:
  2658. ASSERT(pPortInfo->pfDoorRead != NULL);
  2659. *pnBytesRead = (int)((*pPortInfo->pfDoorRead)(pbtBuffer, nSize));
  2660. break;
  2661. #endif /* INCLUDE_DOOR32_COM */
  2662. #ifdef INCLUDE_SOCKET_COM
  2663. case kComMethodSocket:
  2664. {
  2665. fd_set socket_set;
  2666. struct timeval tv;
  2667. FD_ZERO(&socket_set);
  2668. FD_SET(pPortInfo->socket,&socket_set);
  2669. tv.tv_sec=0;
  2670. tv.tv_usec=100;
  2671. if(select(pPortInfo->socket+1,&socket_set,NULL,NULL,&tv) != 1) {
  2672. *pnBytesRead = 0;
  2673. break;
  2674. }
  2675. *pnBytesRead = recv(pPortInfo->socket,pbtBuffer,nSize,0);
  2676. break;
  2677. }
  2678. #endif /* INCLUDE_SOCKET_COM */
  2679. #ifdef INCLUDE_STDIO_COM
  2680. case kComMethodStdIO:
  2681. {
  2682. for(*pnBytesRead=0;
  2683. *pnBytesRead<nSize && (ODComGetByte(hPort, (pbtBuffer+*pnBytesRead), FALSE)==kODRCSuccess);
  2684. *pnBytesRead++);
  2685. }
  2686. #endif
  2687. default:
  2688. /* If we get here, then the current serial I/O method is not */
  2689. /* handled by this function. */
  2690. ASSERT(FALSE);
  2691. }
  2692. /* Return with success. */
  2693. return(kODRCSuccess);
  2694. }
  2695. /* ----------------------------------------------------------------------------
  2696. * ODComSendBuffer()
  2697. *
  2698. * Sends the contents of an entire buffer to the serial port, waiting until
  2699. * there is enough room in the serial port outbound buffer.
  2700. *
  2701. * Parameters: hPort - Handle to a serial port object.
  2702. *
  2703. * pbtBuffer - Pointer to the first byte in the buffer to transmit.
  2704. *
  2705. * nSize - Number of bytes to transmit from the buffer.
  2706. *
  2707. * Return: kODRCSuccess on success, or an error code on failure.
  2708. */
  2709. tODResult ODComSendBuffer(tPortHandle hPort, BYTE *pbtBuffer, int nSize)
  2710. {
  2711. tPortInfo *pPortInfo = ODHANDLE2PTR(hPort, tPortInfo);
  2712. int nPort;
  2713. VERIFY_CALL(pPortInfo != NULL);
  2714. VERIFY_CALL(pbtBuffer != NULL);
  2715. VERIFY_CALL(nSize >= 0);
  2716. VERIFY_CALL(pPortInfo->bIsOpen);
  2717. nPort = pPortInfo->btPort;
  2718. /* If there are no characters to transmit, then there is no need to */
  2719. /* proceed further. */
  2720. if(nSize == 0)
  2721. {
  2722. return(kODRCSuccess);
  2723. }
  2724. switch(pPortInfo->Method)
  2725. {
  2726. #ifdef INCLUDE_FOSSIL_COM
  2727. case kComMethodFOSSIL:
  2728. {
  2729. int nCount;
  2730. try_again:
  2731. ASM push di
  2732. ASM mov cx, nSize
  2733. ASM mov dx, nPort
  2734. #ifdef LARGEDATA
  2735. ASM les di, pbtBuffer
  2736. #else
  2737. ASM mov ax, ds
  2738. ASM mov es, ax
  2739. ASM mov di, pbtBuffer
  2740. #endif
  2741. ASM mov ah, 0x19
  2742. ASM int 20
  2743. ASM pop di
  2744. ASM mov nCount, ax
  2745. if(nCount<nSize)
  2746. {
  2747. /* Call idle function, if any. */
  2748. if(pPortInfo->pfIdleCallback != NULL)
  2749. {
  2750. (*pPortInfo->pfIdleCallback)();
  2751. }
  2752. nSize-=nCount;
  2753. pbtBuffer+=nCount;
  2754. goto try_again;
  2755. }
  2756. break;
  2757. }
  2758. #endif /* INCLUDE_FOSSIL_COM */
  2759. #ifdef INCLUDE_UART_COM
  2760. case kComMethodUART:
  2761. {
  2762. int nTransferSize;
  2763. int nFirstHalfSize;
  2764. int nSecondHalfSize;
  2765. char *pbtDest;
  2766. /* Loop, copying as much of buffer to transmit queue as possible, */
  2767. /* then waiting for some characters to be transmitted, and copy */
  2768. /* more of buffer to transmit queue, until entire buffer has been */
  2769. /* transferred. */
  2770. for(;;)
  2771. {
  2772. /* Disable interrupts. */
  2773. ASM cli
  2774. /* Try to transfer all of buffer if possible. */
  2775. nTransferSize = nSize;
  2776. /* Adjust number of character to transfer down if there isn't */
  2777. /* enough space in transmit queue. */
  2778. if(nTransferSize > (nTXQueueSize - nTXChars))
  2779. {
  2780. nTransferSize = (nTXQueueSize - nTXChars);
  2781. }
  2782. /* Block transfer is divided into two segments - everything from */
  2783. /* current in index to end of queue, and everything from */
  2784. /* beginning of queue to end of free space in queue. */
  2785. /* Calculate size of first half of transfer. */
  2786. nFirstHalfSize = nTXQueueSize - nTXInIndex;
  2787. if(nFirstHalfSize > nTransferSize) nFirstHalfSize = nTransferSize;
  2788. /* Calculate size of second half of transfer. */
  2789. nSecondHalfSize = nTransferSize - nFirstHalfSize;
  2790. /* Transfer characters at current queue in index. */
  2791. pbtDest = pbtTXQueue + nTXInIndex;
  2792. while(nFirstHalfSize--)
  2793. {
  2794. *pbtDest++ = *pbtBuffer++;
  2795. }
  2796. /* If there is a second half to transfer. */
  2797. if(nSecondHalfSize)
  2798. {
  2799. /* Copy destination will begin at beginning of queue. */
  2800. pbtDest = pbtTXQueue;
  2801. /* Set final queue in index. */
  2802. nTXInIndex = nSecondHalfSize;
  2803. /* Perform second half of transfer. */
  2804. while(nSecondHalfSize--)
  2805. {
  2806. *pbtDest++ = *pbtBuffer++;
  2807. }
  2808. }
  2809. /* If entire transfer was performed in first half. */
  2810. else
  2811. {
  2812. /* Set final queue in index. */
  2813. nTXInIndex += nTransferSize;
  2814. /* Wrap queue in index if we just happened to fill characters */
  2815. /* up to end of physical queue. If there was one less */
  2816. /* character transferred, no wrap would be necessary, and if */
  2817. /* there was one more character to be transferred, transfer */
  2818. /* would have to be performed in two halves. */
  2819. if(nTXInIndex == nTXQueueSize) nTXInIndex = 0;
  2820. }
  2821. /* Update count of total characters in the queue. */
  2822. nTXChars += nTransferSize;
  2823. /* Enable transmit interrupt on the UART. */
  2824. ASM mov dx, nIntEnableRegAddr
  2825. ASM in al, dx
  2826. ASM or al, THRE
  2827. ASM out dx, al
  2828. /* Re-enable interrupts. */
  2829. ASM sti
  2830. /* Adjust count of characters left to transfer down by number of */
  2831. /* characters transferred. */
  2832. nSize -= nTransferSize;
  2833. /* If there are no characters left to transfer, then we are */
  2834. /* done. */
  2835. if(nSize == 0) break;
  2836. /* Call idle function, if any. */
  2837. if(pPortInfo->pfIdleCallback != NULL)
  2838. {
  2839. (*pPortInfo->pfIdleCallback)();
  2840. }
  2841. }
  2842. break;
  2843. }
  2844. #endif /* INCLUDE_UART_COM */
  2845. #ifdef INCLUDE_WIN32_COM
  2846. case kComMethodWin32:
  2847. {
  2848. DWORD dwErrors;
  2849. DWORD dwBytesWritten;
  2850. /* Attempt to perform write operation. */
  2851. if(!WriteFile(pPortInfo->hCommDev, pbtBuffer, nSize, &dwBytesWritten,
  2852. NULL) || dwBytesWritten != (DWORD)nSize)
  2853. {
  2854. ClearCommError(pPortInfo->hCommDev, &dwErrors, NULL);
  2855. return(kODRCGeneralFailure);
  2856. }
  2857. break;
  2858. }
  2859. #endif /* INCLUDE_WIN32_COM */
  2860. #ifdef INCLUDE_DOOR32_COM
  2861. case kComMethodDoor32:
  2862. ASSERT(pPortInfo->pfDoorWrite != NULL);
  2863. if(!(*pPortInfo->pfDoorWrite)(pbtBuffer, nSize))
  2864. {
  2865. return(kODRCGeneralFailure);
  2866. }
  2867. break;
  2868. return(kODRCUnsupported);
  2869. #endif /* INCLUDE_DOOR32_COM */
  2870. #ifdef INCLUDE_SOCKET_COM
  2871. case kComMethodSocket:
  2872. {
  2873. fd_set socket_set;
  2874. struct timeval tv;
  2875. int send_ret;
  2876. FD_ZERO(&socket_set);
  2877. FD_SET(pPortInfo->socket,&socket_set);
  2878. tv.tv_sec=1;
  2879. tv.tv_usec=0;
  2880. if(select(pPortInfo->socket+1,NULL,&socket_set,NULL,&tv) != 1)
  2881. return(kODRCGeneralFailure);
  2882. do {
  2883. send_ret = send(pPortInfo->socket, pbtBuffer, nSize, 0);
  2884. if (send_ret != SOCKET_ERROR)
  2885. break;
  2886. od_sleep(25);
  2887. } while (WSAGetLastError() == WSAEWOULDBLOCK);
  2888. if (send_ret != nSize)
  2889. return (kODRCGeneralFailure);
  2890. break;
  2891. }
  2892. #endif /* INCLUDE_SOCKET_COM */
  2893. #ifdef INCLUDE_STDIO_COM
  2894. case kComMethodStdIO:
  2895. {
  2896. int pos=0;
  2897. fd_set fdset;
  2898. struct timeval tv;
  2899. int retval;
  2900. int loopcount=0;
  2901. while(pos<nSize) {
  2902. FD_ZERO(&fdset);
  2903. FD_SET(STDOUT_FILENO,&fdset);
  2904. tv.tv_sec=1;
  2905. tv.tv_usec=0;
  2906. retval=select(STDOUT_FILENO+1,NULL,&fdset,NULL,&tv);
  2907. if(retval!=1) {
  2908. if(retval==0) {
  2909. if(++loopcount>10)
  2910. return(kODRCGeneralFailure);
  2911. continue;
  2912. }
  2913. if(retval==-1 && errno==EINTR)
  2914. continue;
  2915. return(kODRCGeneralFailure);
  2916. }
  2917. retval=fwrite(pbtBuffer+pos,1,nSize-pos,stdout);
  2918. if(retval!=nSize-pos) {
  2919. od_sleep(1);
  2920. }
  2921. pos+=retval;
  2922. }
  2923. break;
  2924. }
  2925. #endif
  2926. default:
  2927. /* If we get here, then the current serial I/O method is not */
  2928. /* handled by this function. */
  2929. ASSERT(FALSE);
  2930. }
  2931. /* Return with success. */
  2932. return(kODRCSuccess);
  2933. }
  2934. /* ----------------------------------------------------------------------------
  2935. * ODComWaitEvent()
  2936. *
  2937. * Blocks until the specified serial I/O event occurs, or an error condition
  2938. * is encountered.
  2939. *
  2940. * Parameters: hPort - Handle to an open port.
  2941. *
  2942. * Event - Event type to wait for.
  2943. *
  2944. * Return: kODRCSuccess on success, or an error code on failure.
  2945. */
  2946. tODResult ODComWaitEvent(tPortHandle hPort, tComEvent Event)
  2947. {
  2948. tPortInfo *pPortInfo = ODHANDLE2PTR(hPort, tPortInfo);
  2949. VERIFY_CALL(pPortInfo != NULL);
  2950. VERIFY_CALL(pPortInfo->bIsOpen);
  2951. switch(pPortInfo->Method)
  2952. {
  2953. #if defined(INCLUDE_UART_COM) || defined(INCLUDE_FOSSIL_COM) || defined(INCLUDE_STDIO_COM)
  2954. case kComMethodFOSSIL:
  2955. case kComMethodUART:
  2956. case kComMethodStdIO:
  2957. switch(Event)
  2958. {
  2959. case kNoCarrier:
  2960. {
  2961. BOOL bCarrier;
  2962. for(;;)
  2963. {
  2964. ODComCarrier(hPort, &bCarrier);
  2965. if(!bCarrier) break;
  2966. if(pPortInfo->pfIdleCallback != NULL)
  2967. {
  2968. (*pPortInfo->pfIdleCallback)();
  2969. }
  2970. }
  2971. break;
  2972. }
  2973. default:
  2974. VERIFY_CALL(FALSE);
  2975. }
  2976. break;
  2977. #endif /* INCLUDE_UART_COM || INCLUDE_FOSSIL_COM */
  2978. #ifdef INCLUDE_WIN32_COM
  2979. case kComMethodWin32:
  2980. {
  2981. DWORD dwEvtMask;
  2982. /* Obtain current event mask. */
  2983. if(!GetCommMask(pPortInfo->hCommDev, &dwEvtMask))
  2984. {
  2985. return(kODRCGeneralFailure);
  2986. }
  2987. /* Turn on event to be waited for. */
  2988. switch(Event)
  2989. {
  2990. case kNoCarrier:
  2991. dwEvtMask |= EV_RLSD;
  2992. break;
  2993. default:
  2994. VERIFY_CALL(FALSE);
  2995. }
  2996. /* Write new event mask. */
  2997. if(!SetCommMask(pPortInfo->hCommDev, dwEvtMask))
  2998. {
  2999. return(kODRCGeneralFailure);
  3000. }
  3001. /* Wait until event occurs. */
  3002. for(;;)
  3003. {
  3004. /* Block until some event occurs. */
  3005. if(!WaitCommEvent(pPortInfo->hCommDev, &dwEvtMask, NULL))
  3006. {
  3007. return(kODRCGeneralFailure);
  3008. }
  3009. /* Determine whether this is what we are waiting for. */
  3010. switch(Event)
  3011. {
  3012. case kNoCarrier:
  3013. if(dwEvtMask | EV_RLSD)
  3014. {
  3015. BOOL bCarrier;
  3016. ODComCarrier(hPort, &bCarrier);
  3017. if(!bCarrier)
  3018. {
  3019. return(kODRCSuccess);
  3020. }
  3021. }
  3022. break;
  3023. }
  3024. /* If we get here, the event we are waiting for hasn't occurred */
  3025. /* yet, so loop and block waiting for next event. */
  3026. }
  3027. break;
  3028. }
  3029. #endif /* INCLUDE_WIN32_COM */
  3030. #ifdef INCLUDE_DOOR32_COM
  3031. case kComMethodDoor32:
  3032. switch(Event)
  3033. {
  3034. case kNoCarrier:
  3035. ASSERT(pPortInfo->pfDoorGetOfflineEventHandle != NULL);
  3036. WaitForSingleObject(
  3037. (*pPortInfo->pfDoorGetOfflineEventHandle)(), INFINITE);
  3038. break;
  3039. default:
  3040. VERIFY_CALL(FALSE);
  3041. }
  3042. break;
  3043. #endif /* INCLUDE_DOOR32_COM */
  3044. #ifdef INCLUDE_SOCKET_COM
  3045. case kComMethodSocket:
  3046. {
  3047. if(Event == kNoCarrier)
  3048. {
  3049. /* Wait for socket disconnect */
  3050. fd_set socket_set;
  3051. char ch;
  3052. int recv_ret;
  3053. while(1)
  3054. {
  3055. FD_ZERO(&socket_set);
  3056. FD_SET(pPortInfo->socket,&socket_set);
  3057. if(select(pPortInfo->socket+1,&socket_set,NULL,NULL,NULL)
  3058. ==SOCKET_ERROR)
  3059. break;
  3060. recv_ret = recv(pPortInfo->socket, &ch, 1, MSG_PEEK);
  3061. if(recv_ret == SOCKET_ERROR && WSAGetLastError() == WSAEWOULDBLOCK)
  3062. continue;
  3063. if (recv_ret != 1)
  3064. break;
  3065. }
  3066. }
  3067. else
  3068. {
  3069. VERIFY_CALL(FALSE);
  3070. }
  3071. break;
  3072. }
  3073. #endif /* INCLUDE_SOCKET_COM */
  3074. default:
  3075. /* If we get here, then the current serial I/O method is not */
  3076. /* handled by this function. */
  3077. ASSERT(FALSE);
  3078. }
  3079. /* Return with success. */
  3080. return(kODRCSuccess);
  3081. }