• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /****************************************************************************
2 ** use1401.c
3 ** Copyright (C) Cambridge Electronic Design Ltd, 1992-2010
4 **
5 ** This program is free software; you can redistribute it and/or
6 ** modify it under the terms of the GNU General Public License
7 ** as published by the Free Software Foundation; either version 2
8 ** of the License, or (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18 **
19 ** Contact CED: Cambridge Electronic Design Limited, Science Park, Milton Road
20 **              Cambridge, CB6 0FE.
21 **              www.ced.co.uk
22 **              greg@ced.co.uk
23 **
24 **  Title:      USE1401.C
25 **  Version:    4.00
26 **  Author:     Paul Cox, Tim Bergel, Greg Smith
27 **
28 ** The code was vigorously pruned in DEC 2010 to remove the macintosh options
29 ** and to get rid of the 16-bit support. It has also been aligned with the
30 ** Linux version. See CVS for revisions. This will work for Win 9x onwards.
31 ****************************************************************************
32 **
33 ** Notes on Windows interface to driver
34 ** ************************************
35 **
36 ** Under Windows 9x and NT, Use1401 uses DeviceIoControl to get access to
37 ** the 1401 driver. This has parameters for the device handle, the function
38 ** code, an input pointer and byte count, an output pointer and byte count
39 ** and a pointer to a DWORD to hold the output byte count. Note that input
40 ** and output are from the point-of-view of the driver, so the output stuff
41 ** is used to read values from the 1401, not send to the 1401. The use of
42 ** these parameters varies with the function in use and the operating
43 ** system; there are five separate DIOC calls SendString, GetString and
44 ** SetTransferArea all have their own specialised calls, the rest use the
45 ** Status1401 or Control1401 functions.
46 **
47 ** There are two basic styles of DIOC call used, one for Win9x VxD drivers
48 ** and one for NT Kernel-mode and WDM drivers (see below for tables showing
49 ** the different parameters used. The array bUseNTDIOC[] selects between
50 ** these two calling styles.
51 **
52 ** Function codes
53 ** In Win3.x, simple function codes from 0 to 40 were used, shifted left 8
54 ** bits with a sub-function code in the lower 8 bits. These were also used
55 ** in the Windows 95 driver, though we had to add 1 to the code value to
56 ** avoid problems (Open from CreateFile is zero), and the sub-function code
57 ** is now unused. We found that this gave some problems with Windows 98
58 ** as the function code values are reserved by microsoft, so we switched to
59 ** using the NT function codes instead. The NT codes are generated using the
60 ** CTL_CODE macro, essentially this gives 0x80012000 | (func << 2), where
61 ** func is the original 0 to 34 value. The driver will handle both types of
62 ** code and Use1432 only uses the NT codes if it knows the driver is new
63 ** enough. The array bUseNTCodes[] holds flags on the type of codes required.
64 ** GPS/TDB Dec 2010: we removed the bUseNTCodes array as this is always true
65 ** as we no longer support ancient versions.
66 **
67 ** The CreateFile and CloseFile function calls are also handled
68 ** by DIOC, using the special function codes 0 and -1 respectively.
69 **
70 ** Input pointer and buffer size
71 ** These are intended for data sent to the device driver. In nearly all cases
72 ** they are unused in calls to the Win95 driver, the NT driver uses them
73 ** for all information sent to the driver. The table below shows the pointer
74 ** and byte count used for the various calls:
75 **
76 **                      Win 95                  Win NT
77 ** SendString           NULL, 0                 pStr, nStr
78 ** GetString            NULL, 0                 NULL, 0
79 ** SetTransferArea      pBuf, nBuf (unused?)    pDesc, nDesc
80 ** GetTransfer          NULL, 0                 NULL, 0
81 ** Status1401           NULL, 0                 NULL, 0
82 ** Control1401          NULL, 0                 pBlk, nBlk
83 **
84 ** pStr and nStr are pointers to a char buffer and the buffer length for
85 ** string I/O, note that these are temporary buffers owned by the DLL, not
86 ** application memory, pBuf and nBuf are the transfer area buffer (I think
87 ** these are unused), pDesc and nDesc are the TRANSFERDESC structure, pBlk
88 ** and nBlk are the TCSBLOCK structure.
89 **
90 **
91 ** Output pointer and buffer size
92 ** These are intended for data read from the device driver. These are used
93 ** for almost all information sent to the Win95 driver, the NT driver uses
94 ** them for information read from the driver, chiefly the error code. The
95 ** table below shows the pointer and byte count used for the various calls:
96 **
97 **                      Win 95                  Win NT
98 ** SendString           pStr, nStr              pPar, nPar
99 ** GetString            pStr, nStr+2            pStr, nStr+2
100 ** SetTransferArea      pDesc, nDesc            pPar, nPar
101 ** GetTransfer          pGet, nGet              pGet, nGet
102 ** Status1401           pBlk, nBlk              pPar, nPar
103 ** Control1401          pBlk, nBlk              pPar, nPar
104 **
105 ** pStr and nStr are pointers to a char buffer and the buffer length for
106 ** string I/O, the +2 for GetString refers to two spare bytes at the start
107 ** used to hold the string length and returning an error code for NT. Note
108 ** again that these are (and must be) DLL-owned temporary buffers. pPar
109 ** and nPar are a PARAM structure used in NT (it holds an error code and a
110 ** TCSBLOCK structure). pDesc and nDesc are the VXTRANSFERDESC structure,
111 ** pBlk and nBlk are the TCSBLOCK structure. pGet and nGet indicate the
112 ** TGET_TX_BLOCK structure used for GetTransfer.
113 **
114 **
115 ** The output byte count
116 ** Both drivers return the output buffer size here, regardless of the actual
117 ** bytes output. This is used to check that we did get through to the driver.
118 **
119 ** Multiple 1401s
120 ** **************
121 **
122 ** We have code that tries to support the use of multiple 1401s, but there
123 ** are problems: The lDriverVersion and lDriverType variables are global, not
124 ** per-1401 (a particular problem as the U14 functions that use them don't
125 ** have a hand parameter). In addition, the mechansim for finding a free
126 ** 1401 depends upon the 1401 device driver open operation failing if it's
127 ** already in use, which doesn't always happen, particularly with the VxDs.
128 ** The code in TryToOpen tries to fix this by relying on TYPEOF1401 to detect
129 ** the 1401-in-use state - the VxDs contain special code to help this. This is
130 ** working OK but multiple 1401 support works better with the Win2000 drivers.
131 **
132 ** USB driver
133 ** **********
134 **
135 ** The USB driver, which runs on both Win98 and NT2000, uses the NT-style
136 ** calling convention, both for the DIOC codes and the DIOC parameters. The
137 ** TryToOpen function has been altered to look for an NT driver first in
138 ** the appropriate circumstances, and to set the driver DIOC flags up in
139 ** the correct state.
140 **
141 ** Adding a new 1401 type - now almost nothing to do
142 ** *************************************************
143 **
144 ** The 1401 types are defined by a set of U14TYPExxxx codes in USE1401.H.
145 ** You should add a new one of these to keep things tidy for applications.
146 **
147 ** DRIVERET_MAX (below) specifies the maximum allowed type code from the
148 ** 1401 driver; I have set this high to accommodate as yet undesigned 1401
149 ** types. Similarly, as long as the command file names follow the ARM,
150 ** ARN, ARO sequence, these are calculated by the ExtForType function, so
151 ** you don't need to do anything here either.
152 **
153 ** Version number
154 ** **************
155 ** The new U14InitLib() function returns 0 if the OS is incapable of use,
156 ** otherwise is returns the version of the USE1401 library. This is done
157 ** in three parts: Major(31-24).Minor(23-16).Revision.(15-0) (brackets are
158 ** the bits used). The Major number starts at 2 for the first revision with
159 ** the U14InitLib() function. Changes to the Major version means that we
160 ** have broken backwards compatibility. Minor number changes mean that we
161 ** have added new functionality that does not break backwards compatibility.
162 ** we starts at 0. Revision changes mean we have fixed something. Each index
163 ** returns to 0 when a higher one changes.
164 */
165 #define U14LIB_MAJOR 4
166 #define U14LIB_MINOR 0
167 #define U14LIB_REVISION 0
168 #define U14LIB_VERSION ((U14LIB_MAJOR<<24) | (U14LIB_MINOR<<16) | U14LIB_REVISION)
169 
170 #include <stdlib.h>
171 #include <string.h>
172 #include <stdio.h>
173 
174 #include "USE1401.H"
175 
176 #ifdef _IS_WINDOWS_
177 #include <io.h>
178 #include <windows.h>
179 #pragma warning(disable: 4100) /* Disable "Unused formal parameter" warning */
180 #include <assert.h>
181 #include "process.h"
182 
183 
184 #define sprintf wsprintf
185 #define PATHSEP '\\'
186 #define PATHSEPSTR "\\"
187 #define DEFCMDPATH "\\1401\\"   // default command path if all else fails
188 #define MINDRIVERMAJREV 1       // minimum driver revision level we need
189 #define __packed                // does nothing in Windows
190 
191 #include "use14_ioc.h"          // links to device driver stuff
192 #endif
193 
194 #ifdef LINUX
195 #include <fcntl.h>
196 #include <unistd.h>
197 #include <sys/ioctl.h>
198 #include <errno.h>
199 #include <sys/time.h>
200 #include <sched.h>
201 #include <libgen.h>
202 #define PATHSEP '/'
203 #define PATHSEPSTR "/"
204 #define DEFCMDPATH "/var/1401/" // default command path if all else fails
205 #define MINDRIVERMAJREV 2       // minimum driver revision level we need
206 
207 #include "ced_ioctl.h"          // links to device driver stuff
208 #endif
209 
210 #define MAX1401         8       // The number of 1401s that can be supported
211 
212 /*
213 ** These are the 1401 type codes returned by the driver, they are a slightly
214 ** odd sequence & start for reasons of compatibility with the DOS driver.
215 ** The maximum code value is the upper limit of 1401 device types.
216 */
217 #define DRIVRET_STD     4       // Codes for 1401 types matching driver values
218 #define DRIVRET_U1401   5       // This table does not need extending, as
219 #define DRIVRET_PLUS    6       // we can calculate values now.
220 #define DRIVRET_POWER   7       // but we need all of these values still
221 #define DRIVRET_MAX     26      // Maximum tolerated code - future designs
222 
223 /*
224 ** These variables store data that will be used to generate the last
225 ** error string. For now, a string will hold the 1401 command file name.
226 */
227 static char szLastName[20];     // additional text information
228 
229 /*
230 ** Information stored per handle. NBNB, driverType and DriverVersion used to be
231 ** only stored once for all handles... i.e. nonsensical. This change means that
232 ** three U14...() calls now include handles that were previously void. We have
233 ** set a constructor and a destructor call for the library (see the end) to
234 ** initialise important structures, or call use1401_load().
235 */
236 static short asDriverType[MAX1401] = {0};
237 static int lLastDriverVersion = U14ERR_NO1401DRIV;
238 static int lLastDriverType = U14TYPEUNKNOWN;
239 static int alDriverVersion[MAX1401];            // version/type of each driver
240 static int alTimeOutPeriod[MAX1401];            // timeout time in milliseconds
241 static short asLastRetCode[MAX1401];            // last code from a fn call
242 static short asType1401[MAX1401] = {0};         // The type of the 1401
243 static BOOL abGrabbed[MAX1401] = {0};           // Flag for grabbed, set true by grab1401
244 static int iAttached = 0;                       // counts process attaches so can let go
245 
246 #ifdef _IS_WINDOWS_
247 /****************************************************************************
248 ** Windows NT Specific Variables and internal types
249 ****************************************************************************/
250 static HANDLE aHand1401[MAX1401] = {0};         // handles for 1401s
251 static HANDLE aXferEvent[MAX1401] = {0};        // transfer events for the 1401s
252 static LPVOID apAreas[MAX1401][MAX_TRANSAREAS]; // Locked areas
253 static DWORD  auAreas[MAX1401][MAX_TRANSAREAS]; // Size of locked areas
254 static BOOL   bWindows9x = FALSE;               // if we are Windows 95 or better
255 #ifdef _WIN64
256 #define USE_NT_DIOC(ind) TRUE
257 #else
258 static BOOL   abUseNTDIOC[MAX1401];             // Use NT-style DIOC parameters */
259 #define USE_NT_DIOC(ind) abUseNTDIOC[ind]
260 #endif
261 
262 #endif
263 
264 #ifdef LINUX
265 static int aHand1401[MAX1401] = {0};    // handles for 1401s
266 #define INVALID_HANDLE_VALUE 0          // to avoid code differences
267 #endif
268 
269 
270 /*
271 ** The CmdHead relates to backwards compatibility with ancient Microsoft (and Sperry!)
272 ** versions of BASIC, where this header was needed so we could load a command into
273 ** memory.
274 */
275 #pragma pack(1)                 // pack our structure
276 typedef struct CmdHead          // defines header block on command
277 {                               // for PC commands
278    char   acBasic[5];           // BASIC information - needed to align things
279    WORD   wBasicSz;             // size as seen by BASIC
280    WORD   wCmdSize;             // size of the following info
281 } __packed CMDHEAD;
282 #pragma pack()                  // back to normal
283 
284 /*
285 ** The rest of the header looks like this...
286 **  int    iRelPnt;             relocation pointer... actual start
287 **  char   acName[8];           string holding the command name
288 **  BYTE   bMonRev;             monitor revision level
289 **  BYTE   bCmdRev;             command revision level
290 */
291 
292 typedef CMDHEAD *LPCMDHEAD;     // pointer to a command header
293 
294 #define  MAXSTRLEN   255        // maximum string length we use
295 #define  TOHOST      FALSE
296 #define  TO1401      TRUE
297 
CheckHandle(short h)298 static short CheckHandle(short h)
299 {
300     if ((h < 0) || (h >= MAX1401))  // must be legal range...
301         return U14ERR_BADHAND;
302     if (aHand1401[h] <= 0)          // must be open
303         return U14ERR_BADHAND;
304     return U14ERR_NOERROR;
305 }
306 
307 #ifdef _IS_WINDOWS_
308 /****************************************************************************
309 ** U14Status1401    Used for functions which do not pass any data in but
310 **                  get data back
311 ****************************************************************************/
U14Status1401(short sHand,LONG lCode,TCSBLOCK * pBlk)312 static short U14Status1401(short sHand, LONG lCode, TCSBLOCK* pBlk)
313 {
314     DWORD dwBytes = 0;
315 
316     if ((sHand < 0) || (sHand >= MAX1401))  /* Check parameters */
317         return U14ERR_BADHAND;
318 #ifndef _WIN64
319     if (!USE_NT_DIOC(sHand))
320     {   /* Windows 9x DIOC methods? */
321         if (DeviceIoControl(aHand1401[sHand], lCode, NULL, 0, pBlk,sizeof(TCSBLOCK),&dwBytes,NULL))
322             return (short)((dwBytes>=sizeof(TCSBLOCK)) ? U14ERR_NOERROR : U14ERR_DRIVCOMMS);
323         else
324             return (short)GetLastError();
325     }
326     else
327 #endif
328     {                                       /* Windows NT or USB driver */
329         PARAMBLK rWork;
330         rWork.sState = U14ERR_DRIVCOMMS;
331         if (DeviceIoControl(aHand1401[sHand], lCode, NULL, 0, &rWork,sizeof(PARAMBLK),&dwBytes,NULL) &&
332             (dwBytes >= sizeof(PARAMBLK)))
333         {
334             *pBlk = rWork.csBlock;
335             return rWork.sState;
336         }
337     }
338 
339     return U14ERR_DRIVCOMMS;
340 }
341 
342 /****************************************************************************
343 ** U14Control1401   Used for functions which pass data in and only expect
344 **                  an error code back
345 ****************************************************************************/
U14Control1401(short sHand,LONG lCode,TCSBLOCK * pBlk)346 static short U14Control1401(short sHand, LONG lCode, TCSBLOCK* pBlk)
347 {
348     DWORD dwBytes = 0;
349 
350     if ((sHand < 0) || (sHand >= MAX1401))              /* Check parameters */
351         return U14ERR_BADHAND;
352 
353 #ifndef _WIN64
354     if (!USE_NT_DIOC(sHand))
355     {                            /* Windows 9x DIOC methods */
356         if (DeviceIoControl(aHand1401[sHand], lCode, NULL, 0, pBlk, sizeof(TCSBLOCK), &dwBytes, NULL))
357             return (short)(dwBytes >= sizeof(TCSBLOCK) ? U14ERR_NOERROR : U14ERR_DRIVCOMMS);
358         else
359             return (short)GetLastError();
360     }
361     else
362 #endif
363     {                            /* Windows NT or later */
364         PARAMBLK rWork;
365         rWork.sState = U14ERR_DRIVCOMMS;
366         if (DeviceIoControl(aHand1401[sHand], lCode, pBlk, sizeof(TCSBLOCK), &rWork, sizeof(PARAMBLK), &dwBytes, NULL) &&
367             (dwBytes >= sizeof(PARAMBLK)))
368             return rWork.sState;
369     }
370 
371     return U14ERR_DRIVCOMMS;
372 }
373 #endif
374 
375 /****************************************************************************
376 ** SafeTickCount
377 ** Gets time in approximately units of a millisecond.
378 *****************************************************************************/
SafeTickCount()379 static long SafeTickCount()
380 {
381 #ifdef _IS_WINDOWS_
382     return GetTickCount();
383 #endif
384 #ifdef LINUX
385     struct timeval tv;
386     gettimeofday(&tv, NULL);
387     return (tv.tv_sec*1000 + tv.tv_usec/1000);
388 #endif
389 }
390 
391 /****************************************************************************
392 ** A utility routine to get the command file extension for a given type
393 ** of 1401. We assume the type code is vaguely legal.
394 ****************************************************************************/
ExtForType(short sType,char * szExt)395 static int ExtForType(short sType, char* szExt)
396 {
397     szExt[0] = 0;                       /* Default return is a blank string */
398     switch (sType)
399     {
400     case U14TYPE1401: strcpy(szExt, ".CMD");  break;    // Standard 1401
401     case U14TYPEPLUS: strcpy(szExt, ".GXC");  break;    // 1401 plus
402     default:               // All others are in a predictable sequence
403         strcpy(szExt, ".ARM");
404             szExt[3] = (char)('M' + sType - U14TYPEU1401);
405         if (szExt[3] > 'Z')             // Wrap round to ARA after ARZ
406                 szExt[3] = (char)(szExt[3] - 26);
407     }
408     return 0;
409 }
410 
411 /****************************************************************************
412 **   U14WhenToTimeOut
413 **       Returns the time to time out in time units suitable for the machine
414 ** we are running on  ie millsecs for pc/linux, or Mac/
415 ****************************************************************************/
U14WhenToTimeOut(short hand)416 U14API(int) U14WhenToTimeOut(short hand)
417 {
418     int iNow = SafeTickCount();
419     if ((hand >= 0) && (hand < MAX1401))
420         iNow += alTimeOutPeriod[hand];
421     return iNow;
422 }
423 
424 /****************************************************************************
425 ** U14PassedTime
426 ** Returns non zero if the timed passed in has been passed 0 if not
427 ****************************************************************************/
U14PassedTime(int lCheckTime)428 U14API(short) U14PassedTime(int lCheckTime)
429 {
430     return (short)((SafeTickCount()-lCheckTime) > 0);
431 }
432 
433 /****************************************************************************
434 ** TranslateString
435 ** Tidies up string that U14GetString returns. Converts all the commas in a
436 ** string to spaces. Removes terminating CR character. May do more in future.
437 ****************************************************************************/
TranslateString(char * pStr)438 static void TranslateString(char* pStr)
439 {
440     int i = 0;
441     while (pStr[i])
442     {
443         if (pStr[i] == ',')
444             pStr[i] = ' ';              /* convert comma to space */
445         ++i;
446     }
447 
448     if ((i > 0) && (pStr[i-1] == '\n'))  /* kill terminating LF */
449         pStr[i-1] = (char)0;
450 }
451 
452 /****************************************************************************
453 ** U14StrToLongs
454 ** Converts a string to an array of longs and returns the number of values
455 ****************************************************************************/
U14StrToLongs(const char * pszBuff,U14LONG * palNums,short sMaxLongs)456 U14API(short) U14StrToLongs(const char* pszBuff, U14LONG *palNums, short sMaxLongs)
457 {
458     WORD wChInd = 0;                // index into source
459     short sLgInd = 0;               // index into result longs
460 
461     while (pszBuff[wChInd] &&       // until we get to end of string...
462            (sLgInd < sMaxLongs))    // ...or filled the buffer
463     {
464         // Why not use a C Library converter?
465         switch (pszBuff[wChInd])
466         {
467         case '-':
468         case '0': case '1':   case '2': case '3':   case '4':
469         case '5': case '6':   case '7': case '8':   case '9':
470             {
471                 BOOL bDone = FALSE; // true at end of number
472                 int iSign = 1;      // sign of number
473                 long lValue = 0;
474 
475                 while ((!bDone) && pszBuff[wChInd])
476                 {
477                     switch (pszBuff[wChInd])
478                     {
479                     case '-':
480                         iSign = -1; // swap sign
481                         break;
482 
483                     case '0': case '1':   case '2': case '3':   case '4':
484                     case '5': case '6':   case '7': case '8':   case '9':
485                         lValue *= 10;   // move to next digit base 10
486                         lValue += ((int)pszBuff[wChInd]-(int)'0');
487                         break;
488 
489                     default:        // end of number
490                         bDone = TRUE;
491                         break;
492                     }
493                     wChInd++;       // move onto next character
494                 }
495                 palNums[sLgInd] = lValue * iSign;
496                 sLgInd++;
497             }
498             break;
499 
500         default:
501             wChInd++;               // look at next char
502             break;
503         }
504     }
505     return (sLgInd);
506 }
507 
508 
509 /****************************************************************************
510 ** U14LongsFrom1401
511 ** Gets the next waiting line from the 1401 and converts it longs
512 ** Returns the number of numbers read or an error.
513 ****************************************************************************/
U14LongsFrom1401(short hand,U14LONG * palBuff,short sMaxLongs)514 U14API(short) U14LongsFrom1401(short hand, U14LONG *palBuff, short sMaxLongs)
515 {
516     char szWork[MAXSTRLEN];
517     short sResult = U14GetString(hand, szWork, MAXSTRLEN);/* get reply from 1401   */
518     if (sResult == U14ERR_NOERROR)                  /* if no error convert   */
519         sResult = U14StrToLongs(szWork, palBuff, sMaxLongs);
520     return sResult;
521 }
522 
523 /****************************************************************************
524 **   U14CheckErr
525 **   Sends the ERR command to the 1401 and gets the result. Returns 0, a
526 **   negative error code, or the first error value.
527 ****************************************************************************/
U14CheckErr(short hand)528 U14API(short) U14CheckErr(short hand)
529 {
530     short sResult = U14SendString(hand, ";ERR;");
531     if (sResult == U14ERR_NOERROR)
532     {
533         U14LONG er[3];
534         sResult = U14LongsFrom1401(hand, er, 3);
535         if (sResult > 0)
536         {
537             sResult = (short)er[0];        /* Either zero or an error value */
538 #ifdef _DEBUG
539             if (er[0] != 0)
540             {
541                 char szMsg[50];
542                 sprintf(szMsg, "U14CheckErr returned %d,%d\n", er[0], er[1]);
543                 OutputDebugString(szMsg);
544             }
545 #endif
546         }
547         else
548         {
549             if (sResult == 0)
550                 sResult = U14ERR_TIMEOUT;      /* No numbers equals timeout */
551         }
552     }
553 
554     return sResult;
555 }
556 
557 /****************************************************************************
558 ** U14LastErrCode
559 ** Returns the last code from the driver. This is for Windows where all calls
560 ** go through the Control and Status routines, so we can save any error.
561 ****************************************************************************/
U14LastErrCode(short hand)562 U14API(short) U14LastErrCode(short hand)
563 {
564     if ((hand < 0) || (hand >= MAX1401))
565         return U14ERR_BADHAND;
566     return asLastRetCode[hand];
567 }
568 
569 /****************************************************************************
570 ** U14SetTimeout
571 ** Set the timeout period for 1401 comms in milliseconds
572 ****************************************************************************/
U14SetTimeout(short hand,int lTimeOut)573 U14API(void) U14SetTimeout(short hand, int lTimeOut)
574 {
575     if ((hand < 0) || (hand >= MAX1401))
576         return;
577     alTimeOutPeriod[hand] = lTimeOut;
578 }
579 
580 /****************************************************************************
581 ** U14GetTimeout
582 ** Get the timeout period for 1401 comms in milliseconds
583 ****************************************************************************/
U14GetTimeout(short hand)584 U14API(int) U14GetTimeout(short hand)
585 {
586     if ((hand < 0) || (hand >= MAX1401))
587         return U14ERR_BADHAND;
588     return alTimeOutPeriod[hand];
589 }
590 
591 /****************************************************************************
592 ** U14OutBufSpace
593 ** Return the space in the output buffer, or an error.
594 ****************************************************************************/
U14OutBufSpace(short hand)595 U14API(short) U14OutBufSpace(short hand)
596 {
597 #ifdef _IS_WINDOWS_
598     TCSBLOCK csBlock;
599     short sErr = U14Status1401(hand, U14_GETOUTBUFSPACE,&csBlock);
600     if (sErr == U14ERR_NOERROR)
601         sErr = csBlock.ints[0];
602     return sErr;
603 #endif
604 #ifdef LINUX
605     short sErr = CheckHandle(hand);
606     return (sErr == U14ERR_NOERROR) ? CED_GetOutBufSpace(aHand1401[hand]) : sErr;
607 #endif
608 }
609 
610 
611 /****************************************************************************
612 ** U14BaseAddr1401
613 ** Returns the 1401 base address or an error code. Meaningless nowadays
614 ****************************************************************************/
U14BaseAddr1401(short hand)615 U14API(int) U14BaseAddr1401(short hand)
616 {
617 #ifdef _IS_WINDOWS_
618     TCSBLOCK csBlock;
619     int iError = U14Status1401(hand, U14_GETBASEADDRESS,&csBlock);
620     if (iError == U14ERR_NOERROR)
621         iError = csBlock.longs[0];
622     return iError;
623 #endif
624 #ifdef LINUX
625     short sErr = CheckHandle(hand);
626     return (sErr == U14ERR_NOERROR) ? CED_GetBaseAddress(aHand1401[hand]) : sErr;
627 #endif
628 }
629 
630 /****************************************************************************
631 ** U14StateOf1401
632 ** Return error state, either NOERROR or a negative code.
633 ****************************************************************************/
U14StateOf1401(short hand)634 U14API(short) U14StateOf1401(short hand)
635 {
636 #ifdef _IS_WINDOWS_
637     TCSBLOCK csBlock;
638     short sErr = U14Status1401(hand, U14_STATEOF1401, &csBlock);
639     if (sErr == U14ERR_NOERROR)
640     {
641         sErr = csBlock.ints[0];      // returned 1401 state
642         if ((sErr >= DRIVRET_STD) && (sErr <= DRIVRET_MAX))
643             sErr = U14ERR_NOERROR;
644     }
645 #endif
646 #ifdef LINUX
647     short sErr = CheckHandle(hand);
648     if (sErr == U14ERR_NOERROR)
649     {
650         sErr = (short)CED_StateOf1401(aHand1401[hand]);
651         if ((sErr >= DRIVRET_STD) && (sErr <= DRIVRET_MAX))
652             sErr = U14ERR_NOERROR;
653     }
654 #endif
655     return sErr;
656 }
657 
658 /****************************************************************************
659 ** U14DriverVersion
660 ** Returns the driver version. Hi word is major revision, low word is minor.
661 ** If you pass in a silly handle (like -1), we return the version of the last
662 ** driver we know of (to cope with PCI and no 1401 attached).
663 ****************************************************************************/
U14DriverVersion(short hand)664 U14API(int) U14DriverVersion(short hand)
665 {
666     return CheckHandle(hand) != U14ERR_NOERROR ? lLastDriverVersion : alDriverVersion[hand];
667 }
668 
669 /****************************************************************************
670 ** U14DriverType
671 ** Returns the driver type. The type, 0=ISA/NU-Bus, 1=PCI, 2=USB, 3=HSS
672 ** If you pass in a silly handle (like -1), we return the type of the last
673 ** driver we know of (to cope with PCI and no 1401 attached).
674 ****************************************************************************/
U14DriverType(short hand)675 U14API(int) U14DriverType(short hand)
676 {
677     return CheckHandle(hand) != U14ERR_NOERROR ? lLastDriverType : asDriverType[hand];
678 }
679 
680 /****************************************************************************
681 ** U14DriverName
682 ** Returns the driver type as 3 character (ISA, PCI, USB or HSS))
683 ****************************************************************************/
U14DriverName(short hand,char * pBuf,WORD wMax)684 U14API(short) U14DriverName(short hand, char* pBuf, WORD wMax)
685 {
686     char* pName;
687     *pBuf = 0;                             // Start off with a blank string
688     switch (U14DriverType(hand))           // Results according to type
689     {
690     case 0:  pName = "ISA"; break;
691     case 1:  pName = "PCI"; break;
692     case 2:  pName = "USB"; break;
693     case 3:  pName = "HSS"; break;
694     default: pName = "???"; break;
695     }
696     strncpy(pBuf, pName, wMax);            // Copy the correct name to return
697 
698     return U14ERR_NOERROR;
699 }
700 
701 /****************************************************************************
702 ** U14BlkTransState
703 ** Returns 0 no transfer in progress, 1 transfer in progress or an error code
704 ****************************************************************************/
U14BlkTransState(short hand)705 U14API(short) U14BlkTransState(short hand)
706 {
707 #ifdef _IS_WINDOWS_
708     TCSBLOCK csBlock;
709     short sErr = U14Status1401(hand, U14_BLKTRANSSTATE, &csBlock);
710     if (sErr == U14ERR_NOERROR)
711         sErr = csBlock.ints[0];
712     return sErr;
713 #endif
714 #ifdef LINUX
715     short sErr = CheckHandle(hand);
716     return (sErr == U14ERR_NOERROR) ? CED_BlkTransState(aHand1401[hand]) : sErr;
717 #endif
718 }
719 
720 /****************************************************************************
721 ** U14Grab1401
722 ** Take control of the 1401 for diagnostics purposes. USB does nothing.
723 ****************************************************************************/
U14Grab1401(short hand)724 U14API(short) U14Grab1401(short hand)
725 {
726     short sErr = CheckHandle(hand);
727     if (sErr == U14ERR_NOERROR)
728     {
729 #ifdef _IS_WINDOWS_
730         if (abGrabbed[hand])            // 1401 should not have been grabbed
731             sErr = U14ERR_ALREADYSET;   // Error code defined for this
732         else
733         {
734             TCSBLOCK csBlock;
735             sErr = U14Control1401(hand, U14_GRAB1401, &csBlock);
736         }
737 #endif
738 #ifdef LINUX
739         // 1401 should not have been grabbed
740         sErr = abGrabbed[hand] ? U14ERR_ALREADYSET : CED_Grab1401(aHand1401[hand]);
741 #endif
742         if (sErr == U14ERR_NOERROR)
743             abGrabbed[hand] = TRUE;
744     }
745     return sErr;
746 }
747 
748 /****************************************************************************
749 ** U14Free1401
750 ****************************************************************************/
U14Free1401(short hand)751 U14API(short)  U14Free1401(short hand)
752 {
753     short sErr = CheckHandle(hand);
754     if (sErr == U14ERR_NOERROR)
755     {
756 #ifdef _IS_WINDOWS_
757         if (abGrabbed[hand])    // 1401 should have been grabbed
758         {
759             TCSBLOCK csBlock;
760             sErr = U14Control1401(hand, U14_FREE1401, &csBlock);
761         }
762         else
763             sErr = U14ERR_NOTSET;
764 #endif
765 #ifdef LINUX
766         // 1401 should not have been grabbed
767         sErr = abGrabbed[hand] ? CED_Free1401(aHand1401[hand]) : U14ERR_NOTSET;
768 #endif
769         if (sErr == U14ERR_NOERROR)
770             abGrabbed[hand] = FALSE;
771     }
772     return sErr;
773 }
774 
775 /****************************************************************************
776 ** U14Peek1401
777 ** DESCRIPTION  Cause the 1401 to do one or more peek operations.
778 ** If lRepeats is zero, the loop will continue until U14StopDebugLoop
779 ** is called. After the peek is done, use U14GetDebugData to retrieve
780 ** the results of the peek.
781 ****************************************************************************/
U14Peek1401(short hand,DWORD dwAddr,int nSize,int nRepeats)782 U14API(short) U14Peek1401(short hand, DWORD dwAddr, int nSize, int nRepeats)
783 {
784     short sErr = CheckHandle(hand);
785     if (sErr == U14ERR_NOERROR)
786     {
787         if (abGrabbed[hand])    // 1401 should have been grabbed
788         {
789 #ifdef _IS_WINDOWS_
790             TCSBLOCK csBlock;
791             csBlock.longs[0] = (long)dwAddr;
792             csBlock.longs[1] = nSize;
793             csBlock.longs[2] = nRepeats;
794             sErr = U14Control1401(hand, U14_DBGPEEK, &csBlock);
795 #endif
796 #ifdef LINUX
797             TDBGBLOCK dbb;
798             dbb.iAddr = (int)dwAddr;
799             dbb.iWidth = nSize;
800             dbb.iRepeats = nRepeats;
801             sErr = CED_DbgPeek(aHand1401[hand], &dbb);
802 #endif
803         }
804         else
805             sErr = U14ERR_NOTSET;
806     }
807     return sErr;
808 }
809 
810 /****************************************************************************
811 ** U14Poke1401
812 ** DESCRIPTION  Cause the 1401 to do one or more poke operations.
813 ** If lRepeats is zero, the loop will continue until U14StopDebugLoop
814 ** is called.
815 ****************************************************************************/
U14Poke1401(short hand,DWORD dwAddr,DWORD dwValue,int nSize,int nRepeats)816 U14API(short) U14Poke1401(short hand, DWORD dwAddr, DWORD dwValue,
817                                       int nSize, int nRepeats)
818 {
819     short sErr = CheckHandle(hand);
820     if (sErr == U14ERR_NOERROR)
821     {
822         if (abGrabbed[hand])    // 1401 should have been grabbed
823         {
824 #ifdef _IS_WINDOWS_
825             TCSBLOCK csBlock;
826             csBlock.longs[0] = (long)dwAddr;
827             csBlock.longs[1] = nSize;
828             csBlock.longs[2] = nRepeats;
829             csBlock.longs[3] = (long)dwValue;
830             sErr = U14Control1401(hand, U14_DBGPOKE, &csBlock);
831 #endif
832 #ifdef LINUX
833             TDBGBLOCK dbb;
834             dbb.iAddr = (int)dwAddr;
835             dbb.iWidth = nSize;
836             dbb.iRepeats= nRepeats;
837             dbb.iData = (int)dwValue;
838             sErr = CED_DbgPoke(aHand1401[hand], &dbb);
839 #endif
840         }
841         else
842             sErr = U14ERR_NOTSET;
843     }
844     return sErr;
845 }
846 
847 /****************************************************************************
848 ** U14Ramp1401
849 ** DESCRIPTION  Cause the 1401 to loop, writing a ramp to a location.
850 ** If lRepeats is zero, the loop will continue until U14StopDebugLoop.
851 ****************************************************************************/
U14Ramp1401(short hand,DWORD dwAddr,DWORD dwDef,DWORD dwEnable,int nSize,int nRepeats)852 U14API(short) U14Ramp1401(short hand, DWORD dwAddr, DWORD dwDef, DWORD dwEnable,
853                                       int nSize, int nRepeats)
854 {
855     short sErr = CheckHandle(hand);
856     if (sErr == U14ERR_NOERROR)
857     {
858         if (abGrabbed[hand])    // 1401 should have been grabbed
859         {
860 #ifdef _IS_WINDOWS_
861             TCSBLOCK csBlock;
862             csBlock.longs[0] = (long)dwAddr;
863             csBlock.longs[1] = (long)dwDef;
864             csBlock.longs[2] = (long)dwEnable;
865             csBlock.longs[3] = nSize;
866             csBlock.longs[4] = nRepeats;
867             sErr = U14Control1401(hand, U14_DBGRAMPDATA, &csBlock);
868 #endif
869 #ifdef LINUX
870             TDBGBLOCK dbb;
871             dbb.iAddr = (int)dwAddr;
872             dbb.iDefault = (int)dwDef;
873             dbb.iMask = (int)dwEnable;
874             dbb.iWidth = nSize;
875             dbb.iRepeats = nRepeats;
876             sErr = CED_DbgRampAddr(aHand1401[hand], &dbb);
877 #endif
878         }
879         else
880             sErr = U14ERR_NOTSET;
881     }
882     return sErr;
883 }
884 
885 /****************************************************************************
886 ** U14RampAddr
887 ** DESCRIPTION  Cause the 1401 to loop, reading from a ramping location.
888 ** If lRepeats is zero, the loop will continue until U14StopDebugLoop
889 ****************************************************************************/
U14RampAddr(short hand,DWORD dwDef,DWORD dwEnable,int nSize,int nRepeats)890 U14API(short) U14RampAddr(short hand, DWORD dwDef, DWORD dwEnable,
891                                       int nSize, int nRepeats)
892 {
893     short sErr = CheckHandle(hand);
894     if (sErr == U14ERR_NOERROR)
895     {
896         if (abGrabbed[hand])    // 1401 should have been grabbed
897         {
898 #ifdef _IS_WINDOWS_
899             TCSBLOCK csBlock;
900             csBlock.longs[0] = (long)dwDef;
901             csBlock.longs[1] = (long)dwEnable;
902             csBlock.longs[2] = nSize;
903             csBlock.longs[3] = nRepeats;
904             sErr = U14Control1401(hand, U14_DBGRAMPADDR, &csBlock);
905 #endif
906 #ifdef LINUX
907             TDBGBLOCK dbb;
908             dbb.iDefault = (int)dwDef;
909             dbb.iMask = (int)dwEnable;
910             dbb.iWidth = nSize;
911             dbb.iRepeats = nRepeats;
912             sErr = CED_DbgRampAddr(aHand1401[hand], &dbb);
913 #endif
914         }
915         else
916             sErr = U14ERR_NOTSET;
917     }
918     return sErr;
919 }
920 
921 /****************************************************************************
922 **    U14StopDebugLoop
923 **    DESCRIPTION Stops a peek\poke\ramp that, with repeats set to zero,
924 **    will otherwise continue forever.
925 ****************************************************************************/
U14StopDebugLoop(short hand)926 U14API(short) U14StopDebugLoop(short hand)
927 {
928     short sErr = CheckHandle(hand);
929     if (sErr == U14ERR_NOERROR)
930 #ifdef _IS_WINDOWS_
931     {
932         if (abGrabbed[hand])    // 1401 should have been grabbed
933         {
934             TCSBLOCK csBlock;
935             sErr = U14Control1401(hand, U14_DBGSTOPLOOP, &csBlock);
936         }
937         else
938             sErr = U14ERR_NOTSET;
939     }
940 #endif
941 #ifdef LINUX
942         sErr = abGrabbed[hand] ? CED_DbgStopLoop(aHand1401[hand]) : U14ERR_NOTSET;
943 #endif
944     return sErr;
945 }
946 
947 /****************************************************************************
948 ** U14GetDebugData
949 ** DESCRIPTION Returns the result from a previous peek operation.
950 ****************************************************************************/
U14GetDebugData(short hand,U14LONG * plValue)951 U14API(short) U14GetDebugData(short hand, U14LONG* plValue)
952 {
953     short sErr = CheckHandle(hand);
954     if (sErr == U14ERR_NOERROR)
955     {
956         if (abGrabbed[hand])    // 1401 should have been grabbed
957         {
958 #ifdef _IS_WINDOWS_
959             TCSBLOCK csBlock;
960             sErr = U14Status1401(hand, U14_DBGGETDATA, &csBlock);
961             if (sErr == U14ERR_NOERROR)
962                 *plValue = csBlock.longs[0];    // Return the data
963 #endif
964 #ifdef LINUX
965             TDBGBLOCK dbb;
966             sErr = CED_DbgGetData(aHand1401[hand], &dbb);
967             if (sErr == U14ERR_NOERROR)
968                 *plValue = dbb.iData;                     /* Return the data */
969 #endif
970         }
971         else
972             sErr = U14ERR_NOTSET;
973     }
974     return sErr;
975 }
976 
977 /****************************************************************************
978 ** U14StartSelfTest
979 ****************************************************************************/
U14StartSelfTest(short hand)980 U14API(short) U14StartSelfTest(short hand)
981 {
982 #ifdef _IS_WINDOWS_
983     TCSBLOCK csBlock;
984     return U14Control1401(hand, U14_STARTSELFTEST, &csBlock);
985 #endif
986 #ifdef LINUX
987     short sErr = CheckHandle(hand);
988     return (sErr == U14ERR_NOERROR) ? CED_StartSelfTest(aHand1401[hand]) : sErr;
989 #endif
990 }
991 
992 /****************************************************************************
993 ** U14CheckSelfTest
994 ****************************************************************************/
U14CheckSelfTest(short hand,U14LONG * pData)995 U14API(short) U14CheckSelfTest(short hand, U14LONG *pData)
996 {
997 #ifdef _IS_WINDOWS_
998     TCSBLOCK csBlock;
999     short sErr = U14Status1401(hand, U14_CHECKSELFTEST, &csBlock);
1000     if (sErr == U14ERR_NOERROR)
1001     {
1002         pData[0] = csBlock.longs[0];        /* Return the results to user */
1003         pData[1] = csBlock.longs[1];
1004         pData[2] = csBlock.longs[2];
1005     }
1006 #endif
1007 #ifdef LINUX
1008     short sErr = CheckHandle(hand);
1009     if (sErr == U14ERR_NOERROR)                /* Check parameters */
1010     {
1011         TGET_SELFTEST gst;
1012         sErr = CED_CheckSelfTest(aHand1401[hand], &gst);
1013         if (sErr == U14ERR_NOERROR)
1014         {
1015             pData[0] = gst.code;        /* Return the results to user */
1016             pData[1] = gst.x;
1017             pData[2] = gst.y;
1018         }
1019     }
1020 #endif
1021     return sErr;
1022 }
1023 
1024 /****************************************************************************
1025 ** U14GetUserMemorySize
1026 ****************************************************************************/
U14GetUserMemorySize(short hand,DWORD * pMemorySize)1027 U14API(short) U14GetUserMemorySize(short hand, DWORD *pMemorySize)
1028 {
1029     // The original 1401 used a different command for getting the size
1030     short sErr = U14SendString(hand, (asType1401[hand] == U14TYPE1401) ? "MEMTOP;" : "MEMTOP,?;");
1031     *pMemorySize = 0;         /* if we get error then leave size set at 0  */
1032     if (sErr == U14ERR_NOERROR)
1033     {
1034         U14LONG alLimits[4];
1035         sErr = U14LongsFrom1401(hand, alLimits, 4);
1036         if (sErr > 0)              /* +ve sErr is the number of values read */
1037         {
1038             sErr = U14ERR_NOERROR;                  /* All OK, flag success */
1039             if (asType1401[hand] == U14TYPE1401)    /* result for standard  */
1040                 *pMemorySize = alLimits[0] - alLimits[1]; /* memtop-membot */
1041             else
1042                 *pMemorySize = alLimits[0];   /* result for plus or u1401  */
1043         }
1044     }
1045     return sErr;
1046 }
1047 
1048 /****************************************************************************
1049 ** U14TypeOf1401
1050 ** Returns the type of the 1401, maybe unknown
1051 ****************************************************************************/
U14TypeOf1401(short hand)1052 U14API(short) U14TypeOf1401(short hand)
1053 {
1054     if ((hand < 0) || (hand >= MAX1401))                /* Check parameters */
1055         return U14ERR_BADHAND;
1056     else
1057         return asType1401[hand];
1058 }
1059 
1060 /****************************************************************************
1061 ** U14NameOf1401
1062 ** Returns the type of the 1401 as a string, blank if unknown
1063 ****************************************************************************/
U14NameOf1401(short hand,char * pBuf,WORD wMax)1064 U14API(short) U14NameOf1401(short hand, char* pBuf, WORD wMax)
1065 {
1066     short sErr = CheckHandle(hand);
1067     if (sErr == U14ERR_NOERROR)
1068     {
1069     char* pName;
1070     switch (asType1401[hand])               // Results according to type
1071     {
1072     case U14TYPE1401:  pName = "Std 1401"; break;
1073     case U14TYPEPLUS:  pName = "1401plus"; break;
1074     case U14TYPEU1401: pName = "micro1401"; break;
1075     case U14TYPEPOWER: pName = "Power1401"; break;
1076     case U14TYPEU14012:pName = "Micro1401 mk II"; break;
1077     case U14TYPEPOWER2:pName = "Power1401 mk II"; break;
1078     case U14TYPEU14013:pName = "Micro1401-3"; break;
1079     case U14TYPEPOWER3:pName = "Power1401-3"; break;
1080     default:           pName = "Unknown";
1081     }
1082         strncpy(pBuf, pName, wMax);
1083     }
1084     return sErr;
1085 }
1086 
1087 /****************************************************************************
1088 ** U14TransferFlags
1089 **  Returns the driver block transfer flags.
1090 **  Bits can be set - see U14TF_ constants in use1401.h
1091 *****************************************************************************/
U14TransferFlags(short hand)1092 U14API(short) U14TransferFlags(short hand)
1093 {
1094 #ifdef _IS_WINDOWS_
1095     TCSBLOCK csBlock;
1096     short sErr = U14Status1401(hand, U14_TRANSFERFLAGS, &csBlock);
1097     return (sErr == U14ERR_NOERROR) ? (short)csBlock.ints[0] : sErr;
1098 #endif
1099 #ifdef LINUX
1100     short sErr = CheckHandle(hand);
1101     return (sErr == U14ERR_NOERROR) ? CED_TransferFlags(aHand1401[hand]) : sErr;
1102 #endif
1103 }
1104 
1105 /****************************************************************************
1106 ** GetDriverVersion
1107 ** Actually reads driver version from the device driver.
1108 ** Hi word is major revision, low word is minor revision.
1109 ** Assumes that hand has been checked. Also codes driver type in bits 24 up.
1110 *****************************************************************************/
GetDriverVersion(short hand)1111 static int GetDriverVersion(short hand)
1112 {
1113 #ifdef _IS_WINDOWS_
1114     TCSBLOCK csBlock;
1115     int iErr = U14Status1401(hand, U14_GETDRIVERREVISION, &csBlock);
1116     if (iErr == U14ERR_NOERROR)
1117         iErr = csBlock.longs[0];
1118     return iErr;
1119 #endif
1120 #ifdef LINUX
1121     return CED_GetDriverRevision(aHand1401[hand]);
1122 #endif
1123 }
1124 
1125 /****************************************************************************
1126 ** U14MonitorRev
1127 ** Returns the 1401 monitor revision number.
1128 ** The number returned is the minor revision - the part after the
1129 ** decimal point - plus the major revision times 1000.
1130 *****************************************************************************/
U14MonitorRev(short hand)1131 U14API(int) U14MonitorRev(short hand)
1132 {
1133     int iRev = 0;
1134     int iErr = CheckHandle(hand);
1135     if (iErr != U14ERR_NOERROR)                 // Check open and in use
1136         return iErr;
1137 
1138     if (asType1401[hand] >= U14TYPEPOWER2)      // The Power2 onwards can give us the monitor
1139     {                                           //  revision directly for all versions
1140         iErr = U14SendString(hand, "INFO,S,28;");
1141         if (iErr == U14ERR_NOERROR)
1142         {
1143             U14LONG lVals[2];                   // Read a single number being the revision
1144             iErr = U14LongsFrom1401(hand, lVals, 1);
1145             if (iErr > 0)
1146             {
1147                 iErr = U14ERR_NOERROR;
1148                 iRev = lVals[0];                // This is the minor part of the revision
1149                 iRev += asType1401[hand] * 10000;
1150             }
1151         }
1152     }
1153     else
1154     {                                           /* Do it the hard way for older hardware */
1155         iErr = U14SendString(hand, ";CLIST;");     /* ask for command levels */
1156         if (iErr == U14ERR_NOERROR)
1157         {
1158             while (iErr == U14ERR_NOERROR)
1159             {
1160                 char wstr[50];
1161                 iErr = U14GetString(hand, wstr, 45);
1162                 if (iErr == U14ERR_NOERROR)
1163                 {
1164                     char *pstr = strstr(wstr,"RESET");  /* Is this the RESET command? */
1165                     if ((pstr == wstr) && (wstr[5] == ' '))
1166                     {
1167                         char *pstr2;
1168                         size_t l;
1169                         pstr += 6;       /* Move past RESET and followinmg char */
1170                         l = strlen(pstr);       /* The length of text remaining */
1171                         while (((pstr[l-1] == ' ') || (pstr[l-1] == 13)) && (l > 0))
1172                         {
1173                             pstr[l-1] = 0;         /* Tidy up string at the end */
1174                             l--;                  /* by removing spaces and CRs */
1175                         }
1176                         pstr2 = strchr(pstr, '.');    /* Find the decimal point */
1177                         if (pstr2 != NULL)                /* If we found the DP */
1178                         {
1179                             *pstr2 = 0;                /* End pstr string at DP */
1180                             pstr2++;              /* Now past the decimal point */
1181                             iRev = atoi(pstr2);   /* Get the number after point */
1182                         }
1183                         iRev += (atoi(pstr) * 1000);    /* Add first bit * 1000 */
1184                     }
1185                     if ((strlen(wstr) < 3) && (wstr[0] == ' '))
1186                         break;              /* Spot the last line of results */
1187                 }
1188             }
1189         }
1190     }
1191     if (iErr == U14ERR_NOERROR)            /* Return revision if no error */
1192         iErr = iRev;
1193 
1194     return iErr;
1195 }
1196 
1197 /****************************************************************************
1198 ** U14TryToOpen     Tries to open the 1401 number passed
1199 **  Note : This will succeed with NT driver even if no I/F card or
1200 **         1401 switched off, so we check state and close the driver
1201 **         if the state is unsatisfactory in U14Open1401.
1202 ****************************************************************************/
1203 #ifdef _IS_WINDOWS_
1204 #define U14NAMEOLD "\\\\.\\CED_140%d"
1205 #define U14NAMENEW "\\\\.\\CED%d"
U14TryToOpen(int n1401,long * plRetVal,short * psHandle)1206 static short U14TryToOpen(int n1401, long* plRetVal, short* psHandle)
1207 {
1208     short sErr = U14ERR_NOERROR;
1209     HANDLE hDevice = INVALID_HANDLE_VALUE;
1210     DWORD dwErr = 0;
1211     int nFirst, nLast, nDev = 0;        /* Used for the search for a 1401 */
1212     BOOL bOldName = FALSE;               /* start by looking for a modern driver */
1213 
1214     if (n1401 == 0)                             /* If we need to look for a 1401 */
1215     {
1216         nFirst = 1;                             /* Set the search range */
1217         nLast = MAX1401;                        /* through all the possible 1401s */
1218     }
1219     else
1220         nFirst = nLast = n1401;                 /* Otherwise just one 1401 */
1221 
1222     while (hDevice == INVALID_HANDLE_VALUE)     /* Loop to try for a 1401 */
1223     {
1224         for (nDev = nFirst; nDev <= nLast; nDev++)
1225         {
1226             char szDevName[40];                 /* name of the device to open */
1227             sprintf(szDevName, bOldName ? U14NAMEOLD : U14NAMENEW, nDev);
1228             hDevice = CreateFile(szDevName, GENERIC_WRITE | GENERIC_READ,
1229                                  0, 0,          /* Unshared mode does nothing as this is a device */
1230                                  OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
1231 
1232             if (hDevice != INVALID_HANDLE_VALUE)/* Check 1401 if opened */
1233             {
1234                 TCSBLOCK csBlock;
1235                 assert(aHand1401[nDev-1] == INVALID_HANDLE_VALUE);  // assert if already open
1236                 aHand1401[nDev-1] = hDevice;    /* Save handle for now */
1237 
1238 #ifndef _WIN64
1239                 // Use DIOC method if not windows 9x or if using new device name
1240                 abUseNTDIOC[nDev-1] = (BOOL)(!bWindows9x || !bOldName);
1241 #endif
1242                 sErr = U14Status1401((short)(nDev-1), U14_TYPEOF1401, &csBlock);
1243                 if (sErr == U14ERR_NOERROR)
1244                 {
1245                     *plRetVal = csBlock.ints[0];
1246                     if (csBlock.ints[0] == U14ERR_INUSE)/* Prevent multi opens */
1247                     {
1248                         CloseHandle(hDevice);   /* treat as open failure */
1249                         hDevice = INVALID_HANDLE_VALUE;
1250                         aHand1401[nDev-1] = INVALID_HANDLE_VALUE;
1251                         sErr = U14ERR_INUSE;
1252                     }
1253                     else
1254                         break;                  /* Exit from for loop on success */
1255                 }
1256                 else
1257                 {
1258                     CloseHandle(hDevice);       /* Give up if func fails */
1259                     hDevice = INVALID_HANDLE_VALUE;
1260                     aHand1401[nDev-1] = INVALID_HANDLE_VALUE;
1261                 }
1262             }
1263             else
1264             {
1265                 DWORD dwe = GetLastError();     /* Get error code otherwise */
1266                 if ((dwe != ERROR_FILE_NOT_FOUND) || (dwErr == 0))
1267                     dwErr = dwe;                /* Ignore repeats of 'not found' */
1268             }
1269         }
1270 
1271         if ((hDevice == INVALID_HANDLE_VALUE) &&/* No device found, and... */
1272             (bWindows9x) &&                     /* ...old names are allowed, and... */
1273             (bOldName == FALSE))                /* ...not tried old names yet */
1274             bOldName = TRUE;                    /* Set flag and go round again */
1275         else
1276             break;                              /* otherwise that's all folks */
1277     }
1278 
1279     if (hDevice != INVALID_HANDLE_VALUE)        /* If we got our device open */
1280         *psHandle = (short)(nDev-1);            /* return 1401 number opened */
1281     else
1282     {
1283         if (dwErr == ERROR_FILE_NOT_FOUND)      /* Sort out the error codes */
1284             sErr = U14ERR_NO1401DRIV;           /* if file not found */
1285         else if (dwErr == ERROR_NOT_SUPPORTED)
1286             sErr = U14ERR_DRIVTOOOLD;           /* if DIOC not supported */
1287         else if (dwErr == ERROR_ACCESS_DENIED)
1288             sErr = U14ERR_INUSE;
1289         else
1290             sErr = U14ERR_DRIVCOMMS;            /* otherwise assume comms problem */
1291     }
1292     return sErr;
1293 }
1294 #endif
1295 #ifdef LINUX
U14TryToOpen(int n1401,long * plRetVal,short * psHandle)1296 static short U14TryToOpen(int n1401, long* plRetVal, short* psHandle)
1297 {
1298     short sErr = U14ERR_NOERROR;
1299     int fh = 0;                             // will be 1401 handle
1300     int iErr = 0;
1301     int nFirst, nLast, nDev = 0;            // Used for the search for a 1401
1302 
1303     if (n1401 == 0)                         // If we need to look for a 1401
1304     {
1305         nFirst = 1;                             /* Set the search range */
1306         nLast = MAX1401;                        /* through all the possible 1401s */
1307     }
1308     else
1309         nFirst = nLast = n1401;                 /* Otherwise just one 1401 */
1310 
1311     for (nDev = nFirst; nDev <= nLast; nDev++)
1312     {
1313         char szDevName[40];                 // name of the device to open
1314         sprintf(szDevName,"/dev/cedusb/%d", nDev-1);
1315         fh = open(szDevName, O_RDWR);       // can only be opened once at a time
1316         if (fh > 0)                         // Check 1401 if opened
1317         {
1318             int iType1401 = CED_TypeOf1401(fh); // get 1401 type
1319             aHand1401[nDev-1] = fh;         // Save handle for now
1320             if (iType1401 >= 0)
1321             {
1322                 *plRetVal = iType1401;
1323                  break;                     // Exit from for loop on success
1324             }
1325             else
1326             {
1327                 close(fh);                  // Give up if func fails
1328                 fh = 0;
1329                 aHand1401[nDev-1] = 0;
1330             }
1331         }
1332         else
1333         {
1334             if (((errno != ENODEV) && (errno != ENOENT)) || (iErr == 0))
1335                 iErr = errno;                // Ignore repeats of 'not found'
1336         }
1337     }
1338 
1339 
1340     if (fh)                                 // If we got our device open
1341         *psHandle = (short)(nDev-1);        // return 1401 number opened
1342     else
1343     {
1344         if ((iErr == ENODEV) || (iErr == ENOENT)) // Sort out the error codes
1345             sErr = U14ERR_NO1401DRIV;       // if file not found
1346         else if (iErr == EBUSY)
1347             sErr = U14ERR_INUSE;
1348         else
1349             sErr = U14ERR_DRIVCOMMS;        // otherwise assume comms problem
1350     }
1351 
1352     return sErr;
1353 }
1354 #endif
1355 /****************************************************************************
1356 ** U14Open1401
1357 ** Tries to get the 1401 for use by this application
1358 *****************************************************************************/
U14Open1401(short n1401)1359 U14API(short) U14Open1401(short n1401)
1360 {
1361     long     lRetVal = -1;
1362     short    sErr;
1363     short    hand = 0;
1364 
1365     if ((n1401 < 0) || (n1401 > MAX1401))       // must check the 1401 number
1366         return U14ERR_BAD1401NUM;
1367 
1368     szLastName[0] = 0;          /* initialise the error info string */
1369 
1370     sErr = U14TryToOpen(n1401, &lRetVal, &hand);
1371     if (sErr == U14ERR_NOERROR)
1372     {
1373         long lDriverVersion = GetDriverVersion(hand);   /* get driver revision */
1374         long lDriverRev = -1;
1375 		if (lDriverVersion >= 0)                    /* can use it if all OK */
1376         {
1377             lLastDriverType = (lDriverVersion >> 24) & 0x000000FF;
1378             asDriverType[hand] = (short)lLastDriverType;    /* Drv type */
1379             lLastDriverVersion = lDriverVersion & 0x00FFFFFF;
1380             alDriverVersion[hand] = lLastDriverVersion;     /* Actual version */
1381             lDriverRev = ((lDriverVersion>>16) & 0x00FF);    /* use hi word */
1382         }
1383         else
1384         {
1385             U14Close1401(hand);    /* If there is a problem we should close */
1386             return (short)lDriverVersion;      /* and return the error code */
1387         }
1388 
1389         if (lDriverRev < MINDRIVERMAJREV)       /* late enough version?     */
1390         {
1391             U14Close1401(hand);    /* If there is a problem we should close */
1392             return U14ERR_DRIVTOOOLD;           /* too old                  */
1393         }
1394 
1395         asLastRetCode[hand] = U14ERR_NOERROR; /* Initialise this 1401s info */
1396         abGrabbed[hand] = FALSE;          /* we are not in single step mode */
1397         U14SetTimeout(hand, 3000);      /* set 3 seconds as default timeout */
1398 
1399         switch (lRetVal)
1400         {
1401         case DRIVRET_STD:  asType1401[hand] = U14TYPE1401; break;      /* Some we do by hand */
1402         case DRIVRET_U1401:asType1401[hand] = U14TYPEU1401; break;
1403         case DRIVRET_PLUS: asType1401[hand] = U14TYPEPLUS; break;
1404         default:  // For the power upwards, we can calculate the codes
1405                 if ((lRetVal >= DRIVRET_POWER) && (lRetVal <= DRIVRET_MAX))
1406                     asType1401[hand] = (short)(lRetVal - (DRIVRET_POWER - U14TYPEPOWER));
1407                 else
1408                     asType1401[hand] = U14TYPEUNKNOWN;
1409                 break;
1410             }
1411         U14KillIO1401(hand);                     /* resets the 1401 buffers */
1412 
1413         if (asType1401[hand] != U14TYPEUNKNOWN)   /* If all seems OK so far */
1414         {
1415             sErr = U14CheckErr(hand);        /* we can check 1401 comms now */
1416             if (sErr != 0)                       /* If this failed to go OK */
1417                 U14Reset1401(hand); /* Reset the 1401 to try to sort it out */
1418         }
1419 
1420         sErr = U14StateOf1401(hand);/* Get the state of the 1401 for return */
1421         if (sErr == U14ERR_NOERROR)
1422             sErr = hand;                 /* return the handle if no problem */
1423         else
1424             U14Close1401(hand);    /* If there is a problem we should close */
1425     }
1426 
1427     return sErr;
1428 }
1429 
1430 
1431 /****************************************************************************
1432 ** U14Close1401
1433 ** Closes the 1401 so someone else can use it.
1434 ****************************************************************************/
U14Close1401(short hand)1435 U14API(short) U14Close1401(short hand)
1436 {
1437     int j;
1438     int iAreaMask = 0;                          // Mask for active areas
1439     short sErr = CheckHandle(hand);
1440     if (sErr != U14ERR_NOERROR)                 // Check open and in use
1441         return sErr;
1442 
1443     for (j = 0; j<MAX_TRANSAREAS; ++j)
1444     {
1445         TGET_TX_BLOCK gtb;
1446         int iReturn = U14GetTransfer(hand, &gtb);   // get area information
1447         if (iReturn == U14ERR_NOERROR)          // ignore if any problem
1448             if (gtb.used)
1449                 iAreaMask |= (1 << j);          // set a bit for each used area
1450     }
1451 
1452     if (iAreaMask)                              // if any areas are in use
1453     {
1454         U14Reset1401(hand);                     // in case an active transfer running
1455         for (j = 0; j < MAX_TRANSAREAS; ++j)    // Locate locked areas
1456             if (iAreaMask & (1 << j))           // And kill off any transfers
1457                 U14UnSetTransfer(hand, (WORD)j);
1458     }
1459 
1460 #ifdef _IS_WINDOWS_
1461     if (aXferEvent[hand])                       // if this 1401 has an open event handle
1462     {
1463         CloseHandle(aXferEvent[hand]);          // close down the handle
1464         aXferEvent[hand] = NULL;                // and mark it as gone
1465     }
1466 
1467     if (CloseHandle(aHand1401[hand]))
1468 #endif
1469 #ifdef LINUX
1470     if (close(aHand1401[hand]) == 0)            // make sure that close works
1471 #endif
1472     {
1473         aHand1401[hand] = INVALID_HANDLE_VALUE;
1474         asType1401[hand] = U14TYPEUNKNOWN;
1475         return U14ERR_NOERROR;
1476     }
1477     else
1478         return U14ERR_BADHAND;     /* BUGBUG GetLastError() ? */
1479 }
1480 
1481 /**************************************************************************
1482 **
1483 ** Look for open 1401s and attempt to close them down. 32-bit windows only.
1484 **************************************************************************/
U14CloseAll(void)1485 U14API(void) U14CloseAll(void)
1486 {
1487     int i;
1488     for (i = 0; i < MAX1401; i++)       // Tidy up and make safe
1489         if (aHand1401[i] != INVALID_HANDLE_VALUE)
1490             U14Close1401((short)i);     // Last ditch close 1401
1491 }
1492 
1493 /****************************************************************************
1494 ** U14Reset1401
1495 ** Resets the 1401
1496 ****************************************************************************/
U14Reset1401(short hand)1497 U14API(short) U14Reset1401(short hand)
1498 {
1499 #ifdef _IS_WINDOWS_
1500     TCSBLOCK csBlock;
1501     return U14Control1401(hand, U14_RESET1401, &csBlock);
1502 #endif
1503 #ifdef LINUX
1504     short sErr = CheckHandle(hand);
1505     return (sErr == U14ERR_NOERROR) ? CED_Reset1401(aHand1401[hand]) : sErr;
1506 #endif
1507 }
1508 
1509 /****************************************************************************
1510 ** U14ForceReset
1511 **    Sets the 1401 full reset flag, so that next call to Reset1401 will
1512 **     always cause a genuine reset.
1513 *****************************************************************************/
U14ForceReset(short hand)1514 U14API(short) U14ForceReset(short hand)
1515 {
1516 #ifdef _IS_WINDOWS_
1517     TCSBLOCK csBlock;
1518     return U14Control1401(hand, U14_FULLRESET, &csBlock);
1519 #endif
1520 #ifdef LINUX
1521     short sErr = CheckHandle(hand);
1522     return (sErr == U14ERR_NOERROR) ? CED_FullReset(aHand1401[hand]) : sErr;
1523 #endif
1524 }
1525 
1526 /****************************************************************************
1527 ** U14KillIO1401
1528 **    Removes any pending IO from the buffers.
1529 *****************************************************************************/
U14KillIO1401(short hand)1530 U14API(short) U14KillIO1401(short hand)
1531 {
1532 #ifdef _IS_WINDOWS_
1533     TCSBLOCK csBlock;
1534     return U14Control1401(hand, U14_KILLIO1401, &csBlock);
1535 #endif
1536 #ifdef LINUX
1537     short sErr = CheckHandle(hand);
1538     return (sErr == U14ERR_NOERROR) ? CED_KillIO1401(aHand1401[hand]) : sErr;
1539 #endif
1540 }
1541 
1542 
1543 /****************************************************************************
1544 ** U14SendString
1545 ** Send characters to the 1401
1546 *****************************************************************************/
U14SendString(short hand,const char * pString)1547 U14API(short) U14SendString(short hand, const char* pString)
1548 {
1549     int nChars;                     // length we are sending
1550     long lTimeOutTicks;             // when to time out
1551     BOOL bSpaceToSend;              // space to send yet
1552     short sErr = CheckHandle(hand);
1553     if (sErr != U14ERR_NOERROR)
1554         return sErr;
1555 
1556     nChars = (int)strlen(pString);  // get string length we want to send
1557     if (nChars > MAXSTRLEN)
1558         return U14ERR_STRLEN;       // String too long
1559 
1560 #ifdef _IS_WINDOWS_
1561     // To get here we must wait for the buffer to have some space
1562     lTimeOutTicks = U14WhenToTimeOut(hand);
1563     do
1564     {
1565         bSpaceToSend = (BOOL)((long)U14OutBufSpace(hand) >= nChars);
1566     }
1567     while (!bSpaceToSend && !U14PassedTime(lTimeOutTicks));
1568 
1569     if (!bSpaceToSend)             /* Last-ditch attempt to avoid timeout */
1570     {           /* This can happen with anti-virus or network activity! */
1571         int i;
1572         for (i = 0; (i < 4) && (!bSpaceToSend); ++i)
1573         {
1574             Sleep(25);       /* Give other threads a chance for a while */
1575             bSpaceToSend = (BOOL)((long)U14OutBufSpace(hand) >= nChars);
1576         }
1577     }
1578 
1579     if (asLastRetCode[hand] == U14ERR_NOERROR)      /* no errors? */
1580     {
1581         if (bSpaceToSend)
1582         {
1583             PARAMBLK    rData;
1584             DWORD       dwBytes;
1585             char        tstr[MAXSTRLEN+5];          /* Buffer for chars */
1586 
1587             if ((hand < 0) || (hand >= MAX1401))
1588                 sErr = U14ERR_BADHAND;
1589             else
1590             {
1591                 strcpy(tstr, pString);              /* Into local buf */
1592 #ifndef _WIN64
1593                 if (!USE_NT_DIOC(hand))             /* Using WIN 95 driver access? */
1594                 {
1595                     int iOK = DeviceIoControl(aHand1401[hand], (DWORD)U14_SENDSTRING,
1596                                     NULL, 0, tstr, nChars,
1597                                     &dwBytes, NULL);
1598                     if (iOK)
1599                         sErr = (dwBytes >= (DWORD)nChars) ? U14ERR_NOERROR : U14ERR_DRIVCOMMS;
1600                     else
1601                         sErr = (short)GetLastError();
1602                 }
1603                 else
1604 #endif
1605                 {
1606                     int iOK = DeviceIoControl(aHand1401[hand],(DWORD)U14_SENDSTRING,
1607                                     tstr, nChars,
1608                                     &rData,sizeof(PARAMBLK),&dwBytes,NULL);
1609                     if (iOK && (dwBytes >= sizeof(PARAMBLK)))
1610                         sErr = rData.sState;
1611                     else
1612                         sErr = U14ERR_DRIVCOMMS;
1613                 }
1614 
1615                 if (sErr != U14ERR_NOERROR) // If we have had a comms error
1616                     U14ForceReset(hand);    //  make sure we get real reset
1617             }
1618 
1619             return sErr;
1620 
1621         }
1622         else
1623         {
1624             U14ForceReset(hand);                //  make sure we get real reset
1625             return U14ERR_TIMEOUT;
1626         }
1627     }
1628     else
1629         return asLastRetCode[hand];
1630 #endif
1631 #ifdef LINUX
1632     // Just try to send it and see what happens!
1633     sErr = CED_SendString(aHand1401[hand], pString, nChars);
1634     if (sErr != U14ERR_NOOUT)       // if any result except "no room in output"...
1635     {
1636         if (sErr != U14ERR_NOERROR) // if a problem...
1637              U14ForceReset(hand);   // ...make sure we get real reset next time
1638         return sErr;                // ... we are done as nothing we can do
1639     }
1640 
1641     // To get here we must wait for the buffer to have some space
1642     lTimeOutTicks = U14WhenToTimeOut(hand);
1643     do
1644     {
1645         bSpaceToSend = (BOOL)((long)U14OutBufSpace(hand) >= nChars);
1646         if (!bSpaceToSend)
1647             sched_yield();          // let others have fun while we wait
1648     }
1649     while (!bSpaceToSend && !U14PassedTime(lTimeOutTicks));
1650 
1651     if (asLastRetCode[hand] == U14ERR_NOERROR)                /* no errors? */
1652     {
1653         if (bSpaceToSend)
1654         {
1655             sErr = CED_SendString(aHand1401[hand], pString, nChars);
1656             if (sErr != U14ERR_NOERROR) // If we have had a comms error
1657                 U14ForceReset(hand);    //  make sure we get real reset
1658             return sErr;
1659         }
1660         else
1661         {
1662             U14ForceReset(hand);                //  make sure we get real reset
1663             return U14ERR_TIMEOUT;
1664         }
1665     }
1666     else
1667         return asLastRetCode[hand];
1668 #endif
1669 }
1670 
1671 /****************************************************************************
1672 ** U14SendChar
1673 ** Send character to the 1401
1674 *****************************************************************************/
U14SendChar(short hand,char cChar)1675 U14API(short) U14SendChar(short hand, char cChar)
1676 {
1677 #ifdef _IS_WINDOWS_
1678     char sz[2]=" ";                         // convert to a string and send
1679     sz[0] = cChar;
1680     sz[1] = 0;
1681     return(U14SendString(hand, sz));        // String routines are better
1682 #endif
1683 #ifdef LINUX
1684     short sErr = CheckHandle(hand);
1685     return (sErr == U14ERR_NOERROR) ? CED_SendChar(aHand1401[hand], cChar) : sErr;
1686 #endif
1687 }
1688 
1689 /****************************************************************************
1690 ** U14GetString
1691 ** Get a string from the 1401. Returns a null terminated string.
1692 ** The string is all the characters up to the next CR in the buffer
1693 ** or the end of the buffer if that comes first. This only returns text
1694 ** if there is a CR in the buffer. The terminating CR character is removed.
1695 ** wMaxLen  Is the size of the buffer and must be at least 2 or an error.
1696 ** Returns  U14ERR_NOERR if OK with the result in the string or a negative
1697 **          error code. Any error from the device causes us to set up for
1698 **          a full reset.
1699 ****************************************************************************/
U14GetString(short hand,char * pBuffer,WORD wMaxLen)1700 U14API(short) U14GetString(short hand, char* pBuffer, WORD wMaxLen)
1701 {
1702     short sErr = CheckHandle(hand);
1703     if (sErr != U14ERR_NOERROR)             // If an error...
1704         return sErr;                        // ...bail out!
1705 
1706 #ifdef _IS_WINDOWS_
1707     if (wMaxLen>1)                          // we need space for terminating 0
1708     {
1709         BOOL bLineToGet;                    // true when a line to get
1710         long lTimeOutTicks = U14WhenToTimeOut(hand);
1711         do
1712             bLineToGet = (BOOL)(U14LineCount(hand) != 0);
1713         while (!bLineToGet && !U14PassedTime(lTimeOutTicks));
1714 
1715         if (!bLineToGet)             /* Last-ditch attempt to avoid timeout */
1716         {           /* This can happen with anti-virus or network activity! */
1717             int i;
1718             for (i = 0; (i < 4) && (!bLineToGet); ++i)
1719             {
1720                 Sleep(25);       /* Give other threads a chance for a while */
1721                 bLineToGet = (BOOL)(U14LineCount(hand) != 0);
1722             }
1723         }
1724 
1725         if (bLineToGet)
1726         {
1727             if (asLastRetCode[hand] == U14ERR_NOERROR)     /* all ok so far */
1728             {
1729                 DWORD       dwBytes = 0;
1730                 *((WORD *)pBuffer) = wMaxLen;       /* set up length */
1731 #ifndef _WIN64
1732                 if (!USE_NT_DIOC(hand))             /* Win 95 DIOC here ? */
1733                 {
1734                     char tstr[MAXSTRLEN+5];         /* Buffer for Win95 chars */
1735                     int iOK;
1736 
1737                     if (wMaxLen > MAXSTRLEN)        /* Truncate length */
1738                         wMaxLen = MAXSTRLEN;
1739 
1740                     *((WORD *)tstr) = wMaxLen;      /* set len */
1741 
1742                     iOK = DeviceIoControl(aHand1401[hand],(DWORD)U14_GETSTRING,
1743                                     NULL, 0, tstr, wMaxLen+sizeof(short),
1744                                     &dwBytes, NULL);
1745                     if (iOK)                        /* Device IO control OK ? */
1746                     {
1747                         if (dwBytes >= 0)           /* If driver OK */
1748                         {
1749                             strcpy(pBuffer, tstr);
1750                             sErr = U14ERR_NOERROR;
1751                         }
1752                         else
1753                             sErr = U14ERR_DRIVCOMMS;
1754                     }
1755                     else
1756                     {
1757                         sErr = (short)GetLastError();
1758                         if (sErr > 0)               /* Errors are -ve */
1759                             sErr = (short)-sErr;
1760                     }
1761                 }
1762                 else
1763 #endif
1764                 {       /* Here for NT, the DLL must own the buffer */
1765                     HANDLE hMem = GlobalAlloc(GMEM_MOVEABLE,wMaxLen+sizeof(short));
1766                     if (hMem)
1767                     {
1768                         char* pMem = (char*)GlobalLock(hMem);
1769                         if (pMem)
1770                         {
1771                             int iOK = DeviceIoControl(aHand1401[hand],(DWORD)U14_GETSTRING,
1772                                             NULL, 0, pMem, wMaxLen+sizeof(short),
1773                                             &dwBytes, NULL);
1774                             if (iOK)                /* Device IO control OK ? */
1775                             {
1776                                 if (dwBytes >= wMaxLen)
1777                                 {
1778                                     strcpy(pBuffer, pMem+sizeof(short));
1779                                     sErr = *((SHORT*)pMem);
1780                                 }
1781                                 else
1782                                     sErr = U14ERR_DRIVCOMMS;
1783                             }
1784                             else
1785                                 sErr = U14ERR_DRIVCOMMS;
1786 
1787                             GlobalUnlock(hMem);
1788                         }
1789                         else
1790                             sErr = U14ERR_OUTOFMEMORY;
1791 
1792                         GlobalFree(hMem);
1793                     }
1794                     else
1795                         sErr = U14ERR_OUTOFMEMORY;
1796                 }
1797 
1798                 if (sErr == U14ERR_NOERROR)     // If all OK...
1799                     TranslateString(pBuffer);   // ...convert any commas to spaces
1800                 else                            // If we have had a comms error...
1801                     U14ForceReset(hand);        // ...make sure we get real reset
1802 
1803             }
1804             else
1805                 sErr = asLastRetCode[hand];
1806         }
1807         else
1808         {
1809             sErr = U14ERR_TIMEOUT;
1810             U14ForceReset(hand);            //  make sure we get real reset
1811         }
1812     }
1813     else
1814         sErr = U14ERR_BUFF_SMALL;
1815     return sErr;
1816 #endif
1817 #ifdef LINUX
1818     if (wMaxLen>1)                          // we need space for terminating 0
1819     {
1820         BOOL bLineToGet;                    // true when a line to get
1821         long lTimeOutTicks = U14WhenToTimeOut(hand);
1822         do
1823         {
1824             bLineToGet = (BOOL)(U14LineCount(hand) != 0);
1825             if (!bLineToGet)
1826                 sched_yield();
1827 
1828         }
1829         while (!bLineToGet && !U14PassedTime(lTimeOutTicks));
1830 
1831         if (bLineToGet)
1832         {
1833             sErr = CED_GetString(aHand1401[hand], pBuffer, wMaxLen-1);   // space for terminator
1834             if (sErr >=0)                    // if we were OK...
1835             {
1836                 if (sErr >= wMaxLen)         // this should NOT happen unless
1837                     sErr = U14ERR_DRIVCOMMS; // ...driver Comms are very bad
1838                 else
1839                 {
1840                     pBuffer[sErr] = 0;      // OK, so terminate the string...
1841                     TranslateString(pBuffer);  // ...and convert commas to spaces.
1842                 }
1843             }
1844 
1845             if (sErr < U14ERR_NOERROR)       // If we have had a comms error
1846                 U14ForceReset(hand);            //  make sure we get real reset
1847         }
1848         else
1849         {
1850             sErr = U14ERR_TIMEOUT;
1851             U14ForceReset(hand);            //  make sure we get real reset
1852         }
1853     }
1854     else
1855         sErr = U14ERR_BUFF_SMALL;
1856 
1857     return sErr >= U14ERR_NOERROR ? U14ERR_NOERROR : sErr;
1858 #endif
1859 }
1860 
1861 /****************************************************************************
1862 ** U14GetChar
1863 ** Get a character from the 1401. CR returned as CR.
1864 *****************************************************************************/
U14GetChar(short hand,char * pcChar)1865 U14API(short) U14GetChar(short hand, char* pcChar)
1866 {
1867 #ifdef _IS_WINDOWS_
1868     char sz[2];                             // read a very short string
1869     short sErr = U14GetString(hand, sz, 2); // read one char and nul terminate it
1870     *pcChar = sz[0];    // copy to result, NB char translate done by GetString
1871     if (sErr == U14ERR_NOERROR)
1872     {                                       // undo translate of CR to zero
1873         if (*pcChar == '\0')                // by converting back
1874             *pcChar = '\n';                 // What a nasty thing to have to do
1875     }
1876     return sErr;
1877 #endif
1878 #ifdef LINUX
1879     short sErr = CheckHandle(hand);
1880     if (sErr != U14ERR_NOERROR)             // Check parameters
1881         return sErr;
1882     sErr = CED_GetChar(aHand1401[hand]);    // get one char, if available
1883     if (sErr >= 0)
1884     {
1885         *pcChar = (char)sErr;              // return if it we have one
1886         return U14ERR_NOERROR;              // say all OK
1887     }
1888     else
1889         return sErr;
1890 #endif
1891 }
1892 
1893 /****************************************************************************
1894 ** U14Stat1401
1895 ** Returns 0 for no lines or error or non zero for something waiting
1896 ****************************************************************************/
U14Stat1401(short hand)1897 U14API(short) U14Stat1401(short hand)
1898 {
1899     return ((short)(U14LineCount(hand) > 0));
1900 }
1901 
1902 /****************************************************************************
1903 ** U14CharCount
1904 ** Returns the number of characters in the input buffer
1905 *****************************************************************************/
U14CharCount(short hand)1906 U14API(short) U14CharCount(short hand)
1907 {
1908 #ifdef _IS_WINDOWS_
1909     TCSBLOCK csBlock;
1910     short sErr = U14Status1401(hand, U14_STAT1401, &csBlock);
1911     if (sErr == U14ERR_NOERROR)
1912         sErr = csBlock.ints[0];
1913     return sErr;
1914 #endif
1915 #ifdef LINUX
1916     short sErr = CheckHandle(hand);
1917     return (sErr == U14ERR_NOERROR) ? CED_Stat1401(aHand1401[hand]) : sErr;
1918 #endif
1919 }
1920 
1921 /****************************************************************************
1922 ** U14LineCount
1923 ** Returns the number of CR characters in the input buffer
1924 *****************************************************************************/
U14LineCount(short hand)1925 U14API(short) U14LineCount(short hand)
1926 {
1927 #ifdef _IS_WINDOWS_
1928     TCSBLOCK csBlock;
1929     short sErr = U14Status1401(hand, U14_LINECOUNT, &csBlock);
1930     if (sErr == U14ERR_NOERROR)
1931         sErr = csBlock.ints[0];
1932     return sErr;
1933 #endif
1934 #ifdef LINUX
1935     short sErr = CheckHandle(hand);
1936     return (sErr == U14ERR_NOERROR) ? CED_LineCount(aHand1401[hand]) : sErr;
1937 #endif
1938 }
1939 
1940 /****************************************************************************
1941 ** U14GetErrorString
1942 ** Converts error code supplied to a decent descriptive string.
1943 ** NOTE: This function may use some extra information stored
1944 **       internally in the DLL. This information is stored on a
1945 **       per-process basis, but it might be altered if you call
1946 **       other functions after getting an error and before using
1947 **       this function.
1948 ****************************************************************************/
U14GetErrorString(short nErr,char * pStr,WORD wMax)1949 U14API(void)  U14GetErrorString(short nErr, char* pStr, WORD wMax)
1950 {
1951     char    wstr[150];
1952 
1953     switch (nErr)              /* Basically, we do this with a switch block */
1954     {
1955     case U14ERR_OFF:
1956         sprintf(wstr, "The 1401 is apparently switched off (code %d)", nErr);
1957         break;
1958 
1959     case U14ERR_NC:
1960         sprintf(wstr, "The 1401 is not connected to the interface card (code %d)", nErr);
1961         break;
1962 
1963     case U14ERR_ILL:
1964         sprintf(wstr, "The 1401 is not working correctly (code %d)", nErr);
1965         break;
1966 
1967     case U14ERR_NOIF:
1968         sprintf(wstr, "The 1401 interface card was not detected (code %d)", nErr);
1969         break;
1970 
1971     case U14ERR_TIME:
1972         sprintf(wstr, "The 1401 fails to become ready for use (code %d)", nErr);
1973         break;
1974 
1975     case U14ERR_BADSW:
1976         sprintf(wstr, "The 1401 interface card jumpers are incorrect (code %d)", nErr);
1977         break;
1978 
1979     case U14ERR_NOINT:
1980         sprintf(wstr, "The 1401 interrupt is not available for use (code %d)", nErr);
1981         break;
1982 
1983     case U14ERR_INUSE:
1984         sprintf(wstr, "The 1401 is already in use by another program (code %d)", nErr);
1985         break;
1986 
1987     case U14ERR_NODMA:
1988         sprintf(wstr, "The 1401 DMA channel is not available for use (code %d)", nErr);
1989         break;
1990 
1991     case U14ERR_BADHAND:
1992         sprintf(wstr, "The application supplied an incorrect 1401 handle (code %d)", nErr);
1993         break;
1994 
1995     case U14ERR_BAD1401NUM:
1996         sprintf(wstr, "The application used an incorrect 1401 number (code %d)", nErr);
1997         break;
1998 
1999     case U14ERR_NO_SUCH_FN:
2000         sprintf(wstr, "The code passed to the 1401 driver is invalid (code %d)", nErr);
2001         break;
2002 
2003     case U14ERR_NO_SUCH_SUBFN:
2004         sprintf(wstr, "The sub-code passed to the 1401 driver is invalid (code %d)", nErr);
2005         break;
2006 
2007     case U14ERR_NOOUT:
2008         sprintf(wstr, "No room in buffer for characters for the 1401 (code %d)", nErr);
2009         break;
2010 
2011     case U14ERR_NOIN:
2012         sprintf(wstr, "No characters from the 1401 are available (code %d)", nErr);
2013         break;
2014 
2015     case U14ERR_STRLEN:
2016         sprintf(wstr, "A string sent to or read from the 1401 was too long (code %d)", nErr);
2017         break;
2018 
2019     case U14ERR_LOCKFAIL:
2020         sprintf(wstr, "Failed to lock host memory for data transfer (code %d)", nErr);
2021         break;
2022 
2023     case U14ERR_UNLOCKFAIL:
2024         sprintf(wstr, "Failed to unlock host memory after data transfer (code %d)", nErr);
2025         break;
2026 
2027     case U14ERR_ALREADYSET:
2028         sprintf(wstr, "The transfer area used is already set up (code %d)", nErr);
2029         break;
2030 
2031     case U14ERR_NOTSET:
2032         sprintf(wstr, "The transfer area used has not been set up (code %d)", nErr);
2033         break;
2034 
2035     case U14ERR_BADAREA:
2036         sprintf(wstr, "The transfer area number is incorrect (code %d)", nErr);
2037         break;
2038 
2039     case U14ERR_NOFILE:
2040         sprintf(wstr, "The command file %s could not be opened (code %d)", szLastName, nErr);
2041         break;
2042 
2043     case U14ERR_READERR:
2044         sprintf(wstr, "The command file %s could not be read (code %d)", szLastName, nErr);
2045         break;
2046 
2047     case U14ERR_UNKNOWN:
2048         sprintf(wstr, "The %s command resource could not be found (code %d)", szLastName, nErr);
2049         break;
2050 
2051     case U14ERR_HOSTSPACE:
2052         sprintf(wstr, "Unable to allocate memory for loading command %s (code %d)", szLastName, nErr);
2053         break;
2054 
2055     case U14ERR_LOCKERR:
2056         sprintf(wstr, "Unable to lock memory for loading command %s (code %d)", szLastName, nErr);
2057         break;
2058 
2059     case U14ERR_CLOADERR:
2060         sprintf(wstr, "Error in loading command %s, bad command format (code %d)", szLastName, nErr);
2061         break;
2062 
2063     case U14ERR_TOXXXERR:
2064         sprintf(wstr, "Error detected after data transfer to or from the 1401 (code %d)", nErr);
2065         break;
2066 
2067     case U14ERR_NO386ENH:
2068         sprintf(wstr, "Windows 3.1 is not running in 386 enhanced mode (code %d)", nErr);
2069         break;
2070 
2071     case U14ERR_NO1401DRIV:
2072         sprintf(wstr, "The 1401 device driver cannot be found (code %d)\nUSB:   check plugged in and powered\nOther: not installed?", nErr);
2073         break;
2074 
2075     case U14ERR_DRIVTOOOLD:
2076         sprintf(wstr, "The 1401 device driver is too old for use (code %d)", nErr);
2077         break;
2078 
2079     case U14ERR_TIMEOUT:
2080         sprintf(wstr, "Character transmissions to the 1401 timed-out (code %d)", nErr);
2081         break;
2082 
2083     case U14ERR_BUFF_SMALL:
2084         sprintf(wstr, "Buffer for text from the 1401 was too small (code %d)", nErr);
2085         break;
2086 
2087     case U14ERR_CBALREADY:
2088         sprintf(wstr, "1401 monitor callback already set up (code %d)", nErr);
2089         break;
2090 
2091     case U14ERR_BADDEREG:
2092         sprintf(wstr, "1401 monitor callback deregister invalid (code %d)", nErr);
2093         break;
2094 
2095     case U14ERR_DRIVCOMMS:
2096         sprintf(wstr, "1401 device driver communications failed (code %d)", nErr);
2097         break;
2098 
2099     case U14ERR_OUTOFMEMORY:
2100         sprintf(wstr, "Failed to allocate or lock memory for text from the 1401 (code %d)", nErr);
2101         break;
2102 
2103     default:
2104         sprintf(wstr, "1401 error code %d returned; this code is unknown", nErr);
2105         break;
2106 
2107     }
2108     if ((WORD)strlen(wstr) >= wMax-1)  /* Check for string being too long */
2109         wstr[wMax-1] = 0;                          /* and truncate it if so */
2110     strcpy(pStr, wstr);                       /* Return the error string */
2111 }
2112 
2113 /***************************************************************************
2114 ** U14GetTransfer
2115 ** Get a TGET_TX_BLOCK describing a transfer area (held in the block)
2116 ***************************************************************************/
U14GetTransfer(short hand,TGET_TX_BLOCK * pTransBlock)2117 U14API(short) U14GetTransfer(short hand, TGET_TX_BLOCK *pTransBlock)
2118 {
2119     short sErr = CheckHandle(hand);
2120 #ifdef _IS_WINDOWS_
2121     if (sErr == U14ERR_NOERROR)
2122     {
2123         DWORD dwBytes = 0;
2124         BOOL bOK = DeviceIoControl(aHand1401[hand], (DWORD)U14_GETTRANSFER, NULL, 0, pTransBlock,
2125                               sizeof(TGET_TX_BLOCK), &dwBytes, NULL);
2126 
2127         if (bOK && (dwBytes >= sizeof(TGET_TX_BLOCK)))
2128             sErr = U14ERR_NOERROR;
2129         else
2130             sErr = U14ERR_DRIVCOMMS;
2131     }
2132     return sErr;
2133 #endif
2134 #ifdef LINUX
2135     return (sErr == U14ERR_NOERROR) ? CED_GetTransfer(aHand1401[hand], pTransBlock) : sErr;
2136 #endif
2137 }
2138 /////////////////////////////////////////////////////////////////////////////
2139 // U14WorkingSet
2140 // For Win32 only, adjusts process working set so that minimum is at least
2141 //  dwMinKb and maximum is at least dwMaxKb.
2142 // Return value is zero if all went OK, or a code from 1 to 3 indicating the
2143 //  cause of the failure:
2144 //
2145 //     1 unable to access process (insufficient rights?)
2146 //     2 unable to read process working set
2147 //     3 unable to set process working set - bad parameters?
U14WorkingSet(DWORD dwMinKb,DWORD dwMaxKb)2148 U14API(short) U14WorkingSet(DWORD dwMinKb, DWORD dwMaxKb)
2149 {
2150 #ifdef _IS_WINDOWS_
2151     short sRetVal = 0;                      // 0 means all is OK
2152     HANDLE hProcess;
2153     DWORD dwVer = GetVersion();
2154 	if (dwVer & 0x80000000)                 // is this not NT?
2155         return 0;                           // then give up right now
2156 
2157     // Now attempt to get information on working set size
2158     hProcess = OpenProcess(STANDARD_RIGHTS_REQUIRED |
2159                                   PROCESS_QUERY_INFORMATION |
2160                                   PROCESS_SET_QUOTA,
2161                                   FALSE, _getpid());
2162     if (hProcess)
2163     {
2164         SIZE_T dwMinSize,dwMaxSize;
2165         if (GetProcessWorkingSetSize(hProcess, &dwMinSize, &dwMaxSize))
2166         {
2167             DWORD dwMin = dwMinKb << 10;    // convert from kb to bytes
2168             DWORD dwMax = dwMaxKb << 10;
2169 
2170             // if we get here, we have managed to read the current size
2171             if (dwMin > dwMinSize)          // need to change sizes?
2172                 dwMinSize = dwMin;
2173 
2174             if (dwMax > dwMaxSize)
2175                 dwMaxSize = dwMax;
2176 
2177             if (!SetProcessWorkingSetSize(hProcess, dwMinSize, dwMaxSize))
2178                 sRetVal = 3;                // failed to change size
2179         }
2180         else
2181             sRetVal = 2;                    // failed to read original size
2182 
2183         CloseHandle(hProcess);
2184     }
2185     else
2186         sRetVal = 1;            // failed to get handle
2187 
2188     return sRetVal;
2189 #endif
2190 #ifdef LINUX
2191     if (dwMinKb | dwMaxKb)
2192     {
2193         // to stop compiler moaning
2194     }
2195     return U14ERR_NOERROR;
2196 #endif
2197 }
2198 
2199 /****************************************************************************
2200 ** U14UnSetTransfer  Cancels a transfer area
2201 ** wArea    The index of a block previously used in by SetTransfer
2202 *****************************************************************************/
U14UnSetTransfer(short hand,WORD wArea)2203 U14API(short) U14UnSetTransfer(short hand, WORD wArea)
2204 {
2205     short sErr = CheckHandle(hand);
2206 #ifdef _IS_WINDOWS_
2207     if (sErr == U14ERR_NOERROR)
2208     {
2209        TCSBLOCK csBlock;
2210        csBlock.ints[0] = (short)wArea;       /* Area number into control block */
2211        sErr = U14Control1401(hand, U14_UNSETTRANSFER, &csBlock);  /* Free area */
2212 
2213        VirtualUnlock(apAreas[hand][wArea], auAreas[hand][wArea]);/* Unlock */
2214        apAreas[hand][wArea] = NULL;                         /* Clear locations */
2215        auAreas[hand][wArea] = 0;
2216     }
2217     return sErr;
2218 #endif
2219 #ifdef LINUX
2220     return (sErr == U14ERR_NOERROR) ? CED_UnsetTransfer(aHand1401[hand], wArea) : sErr;
2221 #endif
2222 }
2223 
2224 /****************************************************************************
2225 ** U14SetTransArea      Sets an area up to be used for transfers
2226 ** WORD  wArea     The area number to set up
2227 ** void *pvBuff    The address of the buffer for the data.
2228 ** DWORD dwLength  The length of the buffer for the data
2229 ** short eSz       The element size (used for byte swapping on the Mac)
2230 ****************************************************************************/
U14SetTransArea(short hand,WORD wArea,void * pvBuff,DWORD dwLength,short eSz)2231 U14API(short) U14SetTransArea(short hand, WORD wArea, void *pvBuff,
2232                                           DWORD dwLength, short eSz)
2233 {
2234     TRANSFERDESC td;
2235     short sErr = CheckHandle(hand);
2236     if (sErr != U14ERR_NOERROR)
2237         return sErr;
2238     if (wArea >= MAX_TRANSAREAS)                    // Is this a valid area number
2239         return U14ERR_BADAREA;
2240 
2241 #ifdef _IS_WINDOWS_
2242     assert(apAreas[hand][wArea] == NULL);
2243     assert(auAreas[hand][wArea] == 0);
2244 
2245     apAreas[hand][wArea] = pvBuff;                  /* Save data for later */
2246     auAreas[hand][wArea] = dwLength;
2247 
2248     if (!VirtualLock(pvBuff, dwLength))             /* Lock using WIN32 calls */
2249     {
2250         apAreas[hand][wArea] = NULL;                /* Clear locations */
2251         auAreas[hand][wArea] = 0;
2252         return U14ERR_LOCKERR;                      /* VirtualLock failed */
2253     }
2254 #ifndef _WIN64
2255     if (!USE_NT_DIOC(hand))                         /* Use Win 9x DIOC? */
2256     {
2257         DWORD dwBytes;
2258         VXTRANSFERDESC vxDesc;                      /* Structure to pass to VXD */
2259         vxDesc.wArea = wArea;                       /* Copy across simple params */
2260         vxDesc.dwLength = dwLength;
2261 
2262         // Check we are not asking an old driver for more than area 0
2263         if ((wArea != 0) && (U14DriverVersion(hand) < 0x00010002L))
2264             sErr = U14ERR_DRIVTOOOLD;
2265         else
2266         {
2267             vxDesc.dwAddrOfs = (DWORD)pvBuff;       /* 32 bit offset */
2268             vxDesc.wAddrSel  = 0;
2269 
2270             if (DeviceIoControl(aHand1401[hand], (DWORD)U14_SETTRANSFER,
2271                                 pvBuff,dwLength,    /* Will translate pointer */
2272                                 &vxDesc,sizeof(VXTRANSFERDESC),
2273                                 &dwBytes,NULL))
2274             {
2275                 if (dwBytes >= sizeof(VXTRANSFERDESC)) /* Driver OK ? */
2276                     sErr = U14ERR_NOERROR;
2277                 else
2278                     sErr = U14ERR_DRIVCOMMS;        /* Else never got there */
2279             }
2280             else
2281                 sErr = (short)GetLastError();
2282         }
2283     }
2284     else
2285 #endif
2286     {
2287         PARAMBLK rWork;
2288         DWORD dwBytes;
2289         td.wArea = wArea;     /* Pure NT - put data into struct */
2290         td.lpvBuff = pvBuff;
2291         td.dwLength = dwLength;
2292         td.eSize = 0;                // Dummy element size
2293 
2294         if (DeviceIoControl(aHand1401[hand],(DWORD)U14_SETTRANSFER,
2295                             &td,sizeof(TRANSFERDESC),
2296                             &rWork,sizeof(PARAMBLK),&dwBytes,NULL))
2297         {
2298             if (dwBytes >= sizeof(PARAMBLK))    // maybe error from driver?
2299                 sErr = rWork.sState;            // will report any error
2300             else
2301                 sErr = U14ERR_DRIVCOMMS;        // Else never got there
2302         }
2303         else
2304             sErr = U14ERR_DRIVCOMMS;
2305     }
2306 
2307     if (sErr != U14ERR_NOERROR)
2308     {
2309         if (sErr != U14ERR_LOCKERR)             // unless lock failed...
2310             VirtualUnlock(pvBuff, dwLength);    // ...release the lock
2311         apAreas[hand][wArea] = NULL;            // Clear locations
2312         auAreas[hand][wArea] = 0;
2313     }
2314 
2315     return sErr;
2316 #endif
2317 #ifdef LINUX
2318     // The strange cast is so that it works in 64 and 32-bit linux as long is 64-bits
2319     // in the 64 bit version.
2320     td.lpvBuff = (long long)((unsigned long)pvBuff);
2321     td.wAreaNum = wArea;
2322     td.dwLength = dwLength;
2323     td.eSize = eSz;                // Dummy element size
2324     return CED_SetTransfer(aHand1401[hand], &td);
2325 #endif
2326 }
2327 
2328 /****************************************************************************
2329 ** U14SetTransferEvent  Sets an event for notification of application
2330 ** wArea       The transfer area index, from 0 to MAXAREAS-1
2331 **    bEvent      True to create an event, false to remove it
2332 **    bToHost     Set 0 for notification on to1401 tranfers, 1 for
2333 **                notification of transfers to the host PC
2334 **    dwStart     The offset of the sub-area of interest
2335 **    dwLength    The size of the sub-area of interest
2336 **
2337 ** The device driver will set the event supplied to the signalled state
2338 ** whenever a DMA transfer to/from the specified area is completed. The
2339 ** transfer has to be in the direction specified by bToHost, and overlap
2340 ** that part of the whole transfer area specified by dwStart and dwLength.
2341 ** It is important that this function is called with bEvent false to release
2342 ** the event once 1401 activity is finished.
2343 **
2344 ** Returns 1 if an event handle exists, 0 if all OK and no event handle or
2345 ** a negative code for an error.
2346 ****************************************************************************/
U14SetTransferEvent(short hand,WORD wArea,BOOL bEvent,BOOL bToHost,DWORD dwStart,DWORD dwLength)2347 U14API(short) U14SetTransferEvent(short hand, WORD wArea, BOOL bEvent,
2348                                   BOOL bToHost, DWORD dwStart, DWORD dwLength)
2349 {
2350 #ifdef _IS_WINDOWS_
2351     TCSBLOCK csBlock;
2352     short sErr = U14TransferFlags(hand);        // see if we can handle events
2353     if (sErr >= U14ERR_NOERROR)                 // check handle is OK
2354     {
2355         bEvent = bEvent && ((sErr & U14TF_NOTIFY) != 0); // remove request if we cannot do events
2356         if (wArea >= MAX_TRANSAREAS)            // Check a valid area...
2357             return U14ERR_BADAREA;              // ...and bail of not
2358 
2359         // We can hold an event for each area, so see if we need to change the
2360         // state of the event.
2361         if ((bEvent != 0) != (aXferEvent[hand] != 0))    // change of event state?
2362         {
2363             if (bEvent)                         // want one and none present
2364                 aXferEvent[hand] = CreateEvent(NULL, FALSE, FALSE, NULL);
2365             else
2366             {
2367                 CloseHandle(aXferEvent[hand]);  // clear the existing event
2368                 aXferEvent[hand] = NULL;        // and clear handle
2369             }
2370         }
2371 
2372         // We have to store the parameters differently for 64-bit operations
2373         //  because a handle is 64 bits long. The drivers know of this and
2374         //  handle the information appropriately.
2375 #ifdef _WIN64
2376         csBlock.longs[0] = wArea;               // Pass paramaters into the driver...
2377         if (bToHost != 0)                       // The direction flag is held in the
2378             csBlock.longs[0] |= 0x10000;        //  upper word of the transfer area value
2379         *((HANDLE*)&csBlock.longs[1]) = aXferEvent[hand];  // The event handle is 64-bits
2380         csBlock.longs[3] = dwStart;             // Thankfully these two remain
2381         csBlock.longs[4] = dwLength;            //  as unsigned 32-bit values
2382 #else
2383         csBlock.longs[0] = wArea;               // pass paramaters into the driver...
2384         csBlock.longs[1] = (long)aXferEvent[hand];    // ...especially the event handle
2385         csBlock.longs[2] = bToHost;
2386         csBlock.longs[3] = dwStart;
2387         csBlock.longs[4] = dwLength;
2388 #endif
2389         sErr = U14Control1401(hand, U14_SETTRANSEVENT, &csBlock);
2390         if (sErr == U14ERR_NOERROR)
2391             sErr = (short)(aXferEvent[hand] != NULL);    // report if we have a flag
2392     }
2393 
2394     return sErr;
2395 #endif
2396 #ifdef LINUX
2397     TRANSFEREVENT te;
2398     short sErr = CheckHandle(hand);
2399     if (sErr != U14ERR_NOERROR)
2400         return sErr;
2401 
2402     if (wArea >= MAX_TRANSAREAS)            // Is this a valid area number
2403         return U14ERR_BADAREA;
2404 
2405     te.wAreaNum = wArea;                    // copy parameters to the control block
2406     te.wFlags = bToHost ? 1 : 0;            // bit 0 sets the direction
2407     te.dwStart = dwStart;                   // start offset of the event area
2408     te.dwLength = dwLength;                 // size of the event area
2409     te.iSetEvent = bEvent;                  // in Windows, this creates/destroys the event
2410     return CED_SetEvent(aHand1401[hand], &te);
2411 #endif
2412 }
2413 
2414 /****************************************************************************
2415 ** U14TestTransferEvent
2416 ** Would a U14WaitTransferEvent() call return immediately? return 1 if so,
2417 ** 0 if not or a negative code if a problem.
2418 ****************************************************************************/
U14TestTransferEvent(short hand,WORD wArea)2419 U14API(int) U14TestTransferEvent(short hand, WORD wArea)
2420 {
2421 #ifdef _IS_WINDOWS_
2422     int iErr = CheckHandle(hand);
2423     if (iErr == U14ERR_NOERROR)
2424     {
2425         if (aXferEvent[hand])           // if a handle is set...
2426             iErr = WaitForSingleObject(aXferEvent[hand], 0) == WAIT_OBJECT_0;
2427     }
2428     return iErr;
2429 #endif
2430 #ifdef LINUX
2431     short sErr = CheckHandle(hand);
2432     return (sErr == U14ERR_NOERROR) ? CED_TestEvent(aHand1401[hand], wArea) : sErr;
2433 #endif
2434 }
2435 
2436 /****************************************************************************
2437 ** U14WaitTransferEvent
2438 ** Wait for a transfer event with a timeout.
2439 ** msTimeOut is 0 for an infinite wait, else it is the maximum time to wait
2440 **           in milliseconds in range 0-0x00ffffff.
2441 ** Returns   If no event handle then return immediately. Else return 1 if
2442 **           timed out or 0=event, and a negative code if a problem.
2443 ****************************************************************************/
U14WaitTransferEvent(short hand,WORD wArea,int msTimeOut)2444 U14API(int) U14WaitTransferEvent(short hand, WORD wArea, int msTimeOut)
2445 {
2446 #ifdef _IS_WINDOWS_
2447     int iErr = CheckHandle(hand);
2448     if (iErr == U14ERR_NOERROR)
2449     {
2450         if (aXferEvent[hand])
2451         {
2452             if (msTimeOut == 0)
2453                 msTimeOut = INFINITE;
2454             iErr = WaitForSingleObject(aXferEvent[hand], msTimeOut) != WAIT_OBJECT_0;
2455         }
2456         else
2457             iErr = TRUE;                // say we timed out if no event
2458     }
2459     return iErr;
2460 #endif
2461 #ifdef LINUX
2462     short sErr = CheckHandle(hand);
2463     return (sErr == U14ERR_NOERROR) ? CED_WaitEvent(aHand1401[hand], wArea, msTimeOut) : sErr;
2464 #endif
2465 }
2466 
2467 /****************************************************************************
2468 ** U14SetCircular    Sets an area up for circular DMA transfers
2469 ** WORD  wArea          The area number to set up
2470 ** BOOL  bToHost        Sets the direction of data transfer
2471 ** void *pvBuff        The address of the buffer for the data
2472 ** DWORD dwLength       The length of the buffer for the data
2473 ****************************************************************************/
U14SetCircular(short hand,WORD wArea,BOOL bToHost,void * pvBuff,DWORD dwLength)2474 U14API(short) U14SetCircular(short hand, WORD wArea, BOOL bToHost,
2475 									void *pvBuff, DWORD dwLength)
2476 {
2477     short sErr = CheckHandle(hand);
2478     if (sErr != U14ERR_NOERROR)
2479         return sErr;
2480 
2481     if (wArea >= MAX_TRANSAREAS)         /* Is this a valid area number */
2482         return U14ERR_BADAREA;
2483 
2484 	if (!bToHost)             /* For now, support tohost transfers only */
2485         return U14ERR_BADAREA;            /* best error code I can find */
2486 #ifdef _IS_WINDOWS_
2487     assert(apAreas[hand][wArea] == NULL);
2488     assert(auAreas[hand][wArea] == 0);
2489 
2490     apAreas[hand][wArea] = pvBuff;              /* Save data for later */
2491     auAreas[hand][wArea] = dwLength;
2492 
2493     if (!VirtualLock(pvBuff, dwLength))      /* Lock using WIN32 calls */
2494         sErr = U14ERR_LOCKERR;                    /* VirtualLock failed */
2495     else
2496     {
2497         PARAMBLK rWork;
2498         DWORD dwBytes;
2499         TRANSFERDESC txDesc;
2500         txDesc.wArea = wArea;             /* Pure NT - put data into struct */
2501         txDesc.lpvBuff = pvBuff;
2502         txDesc.dwLength = dwLength;
2503         txDesc.eSize = (short)bToHost;       /* Use this for direction flag */
2504 
2505         if (DeviceIoControl(aHand1401[hand],(DWORD)U14_SETCIRCULAR,
2506                            &txDesc, sizeof(TRANSFERDESC),
2507                            &rWork, sizeof(PARAMBLK),&dwBytes,NULL))
2508         {
2509            if (dwBytes >= sizeof(PARAMBLK))          /* error from driver? */
2510                sErr = rWork.sState;         /* No, just return driver data */
2511            else
2512                sErr = U14ERR_DRIVCOMMS;            /* Else never got there */
2513         }
2514         else
2515             sErr = U14ERR_DRIVCOMMS;
2516     }
2517 
2518     if (sErr != U14ERR_NOERROR)
2519     {
2520         if (sErr != U14ERR_LOCKERR)
2521             VirtualUnlock(pvBuff, dwLength);         /* Release NT lock */
2522         apAreas[hand][wArea] = NULL;                 /* Clear locations */
2523         auAreas[hand][wArea] = 0;
2524     }
2525 
2526     return sErr;
2527 #endif
2528 #ifdef LINUX
2529     else
2530     {
2531         TRANSFERDESC td;
2532         td.lpvBuff = (long long)((unsigned long)pvBuff);
2533         td.wAreaNum = wArea;
2534         td.dwLength = dwLength;
2535         td.eSize = (short)bToHost;       /* Use this for direction flag */
2536         return CED_SetCircular(aHand1401[hand], &td);
2537     }
2538 #endif
2539 }
2540 
2541 /****************************************************************************
2542 ** Function  GetCircBlk returns the size (& start offset) of the next
2543 **           available block of circular data.
2544 ****************************************************************************/
U14GetCircBlk(short hand,WORD wArea,DWORD * pdwOffs)2545 U14API(int) U14GetCircBlk(short hand, WORD wArea, DWORD *pdwOffs)
2546 {
2547     int lErr = CheckHandle(hand);
2548     if (lErr != U14ERR_NOERROR)
2549         return lErr;
2550 
2551     if (wArea >= MAX_TRANSAREAS)            // Is this a valid area number?
2552         return U14ERR_BADAREA;
2553     else
2554     {
2555 #ifdef _IS_WINDOWS_
2556         PARAMBLK rWork;
2557         TCSBLOCK csBlock;
2558         DWORD dwBytes;
2559         csBlock.longs[0] = wArea;               // Area number into control block
2560         rWork.sState = U14ERR_DRIVCOMMS;
2561         if (DeviceIoControl(aHand1401[hand], (DWORD)U14_GETCIRCBLK, &csBlock, sizeof(TCSBLOCK), &rWork, sizeof(PARAMBLK), &dwBytes, NULL) &&
2562            (dwBytes >= sizeof(PARAMBLK)))
2563             lErr = rWork.sState;
2564         else
2565             lErr = U14ERR_DRIVCOMMS;
2566 
2567         if (lErr == U14ERR_NOERROR)             // Did everything go OK?
2568         {                                       // Yes, we can pass the results back
2569             lErr = rWork.csBlock.longs[1];      // Return the block information
2570             *pdwOffs = rWork.csBlock.longs[0];  // Offset is first in array
2571         }
2572 #endif
2573 #ifdef LINUX
2574         TCIRCBLOCK cb;
2575         cb.nArea = wArea;                       // Area number into control block
2576         cb.dwOffset = 0;
2577         cb.dwSize = 0;
2578         lErr = CED_GetCircBlock(aHand1401[hand], &cb);
2579         if (lErr == U14ERR_NOERROR)             // Did everything go OK?
2580         {                                       // Yes, we can pass the results back
2581             lErr = cb.dwSize;                   // return the size
2582             *pdwOffs = cb.dwOffset;             // and the offset
2583         }
2584 #endif
2585     }
2586     return lErr;
2587 }
2588 
2589 /****************************************************************************
2590 ** Function  FreeCircBlk marks the specified area of memory as free for
2591 **           resuse for circular transfers and returns the size (& start
2592 **           offset) of the next available block of circular data.
2593 ****************************************************************************/
U14FreeCircBlk(short hand,WORD wArea,DWORD dwOffs,DWORD dwSize,DWORD * pdwOffs)2594 U14API(int) U14FreeCircBlk(short hand, WORD wArea, DWORD dwOffs, DWORD dwSize,
2595                                         DWORD *pdwOffs)
2596 {
2597     int lErr = CheckHandle(hand);
2598     if (lErr != U14ERR_NOERROR)
2599         return lErr;
2600 
2601     if (wArea < MAX_TRANSAREAS)                 // Is this a valid area number
2602     {
2603 #ifdef _IS_WINDOWS_
2604         PARAMBLK rWork;
2605         TCSBLOCK csBlock;
2606         DWORD dwBytes;
2607         csBlock.longs[0] = wArea;               // Area number into control block
2608         csBlock.longs[1] = dwOffs;
2609         csBlock.longs[2] = dwSize;
2610         rWork.sState = U14ERR_DRIVCOMMS;
2611         if (DeviceIoControl(aHand1401[hand], (DWORD)U14_FREECIRCBLK, &csBlock, sizeof(TCSBLOCK),
2612                            &rWork, sizeof(PARAMBLK), &dwBytes, NULL) &&
2613            (dwBytes >= sizeof(PARAMBLK)))
2614            lErr = rWork.sState;
2615         else
2616            lErr = U14ERR_DRIVCOMMS;
2617        if (lErr == U14ERR_NOERROR)             // Did everything work OK?
2618        {                                       // Yes, we can pass the results back
2619            lErr = rWork.csBlock.longs[1];      // Return the block information
2620            *pdwOffs = rWork.csBlock.longs[0];  // Offset is first in array
2621        }
2622 #endif
2623 #ifdef LINUX
2624         TCIRCBLOCK cb;
2625         cb.nArea = wArea;                       // Area number into control block
2626         cb.dwOffset = dwOffs;
2627         cb.dwSize = dwSize;
2628 
2629         lErr = CED_FreeCircBlock(aHand1401[hand], &cb);
2630         if (lErr == U14ERR_NOERROR)             // Did everything work OK?
2631         {                                       // Yes, we can pass the results back
2632             lErr = cb.dwSize;                   // Return the block information
2633             *pdwOffs = cb.dwOffset;             // Offset is first in array
2634         }
2635 #endif
2636     }
2637     else
2638         lErr = U14ERR_BADAREA;
2639 
2640     return lErr;
2641 }
2642 
2643 /****************************************************************************
2644 ** Transfer
2645 ** Transfer moves data to 1401 or to host
2646 ** Assumes memory is allocated and locked,
2647 ** which it should be to get a pointer
2648 *****************************************************************************/
Transfer(short hand,BOOL bTo1401,char * pData,DWORD dwSize,DWORD dw1401,short eSz)2649 static short Transfer(short hand, BOOL bTo1401, char* pData,
2650                        DWORD dwSize, DWORD dw1401, short eSz)
2651 {
2652     char strcopy[MAXSTRLEN+1];          // to hold copy of work string
2653     short sResult = U14SetTransArea(hand, 0, (void *)pData, dwSize, eSz);
2654     if (sResult == U14ERR_NOERROR)      // no error
2655     {
2656         sprintf(strcopy,                // data offset is always 0
2657                 "TO%s,$%X,$%X,0;", bTo1401 ? "1401" : "HOST", dw1401, dwSize);
2658 
2659         U14SendString(hand, strcopy);   // send transfer string
2660 
2661         sResult = U14CheckErr(hand);    // Use ERR command to check for done
2662         if (sResult > 0)
2663             sResult = U14ERR_TOXXXERR;  // If a 1401 error, use this code
2664 
2665         U14UnSetTransfer(hand, 0);
2666     }
2667     return sResult;
2668 }
2669 
2670 /****************************************************************************
2671 ** Function  ToHost transfers data into the host from the 1401
2672 ****************************************************************************/
U14ToHost(short hand,char * pAddrHost,DWORD dwSize,DWORD dw1401,short eSz)2673 U14API(short) U14ToHost(short hand, char* pAddrHost, DWORD dwSize,
2674                                             DWORD dw1401, short eSz)
2675 {
2676     short sErr = CheckHandle(hand);
2677     if ((sErr == U14ERR_NOERROR) && dwSize) // TOHOST is a constant
2678         sErr = Transfer(hand, TOHOST, pAddrHost, dwSize, dw1401, eSz);
2679     return sErr;
2680 }
2681 
2682 /****************************************************************************
2683 ** Function  To1401 transfers data into the 1401 from the host
2684 ****************************************************************************/
U14To1401(short hand,const char * pAddrHost,DWORD dwSize,DWORD dw1401,short eSz)2685 U14API(short) U14To1401(short hand, const char* pAddrHost,DWORD dwSize,
2686                                     DWORD dw1401, short eSz)
2687 {
2688     short sErr = CheckHandle(hand);
2689     if ((sErr == U14ERR_NOERROR) && dwSize) // TO1401 is a constant
2690         sErr = Transfer(hand, TO1401, (char*)pAddrHost, dwSize, dw1401, eSz);
2691     return sErr;
2692 }
2693 
2694 /****************************************************************************
2695 ** Function  LdCmd    Loads a command from a full path or just a file
2696 *****************************************************************************/
2697 #ifdef _IS_WINDOWS_
2698 #define file_exist(name) (_access(name, 0) != -1)
2699 #define file_open(name) _lopen(name, OF_READ)
2700 #define file_close(h)   _lclose(h)
2701 #define file_seek(h, pos) _llseek(h, pos, FILE_BEGIN)
2702 #define file_read(h, buffer, size) (_lread(h, buffer, size) == size)
2703 #endif
2704 #ifdef LINUX
2705 #define file_exist(name) (access(name, F_OK) != -1)
2706 #define file_open(name) open(name, O_RDONLY)
2707 #define file_close(h)   close(h)
2708 #define file_seek(h, pos) lseek(h, pos, SEEK_SET)
2709 #define file_read(h, buffer, size) (read(h, buffer, size) == (ssize_t)size)
GetModuleFileName(void * dummy,char * buffer,int max)2710 static DWORD GetModuleFileName(void* dummy, char* buffer, int max)
2711 {
2712     // The following works for Linux systems with a /proc file system.
2713     char szProcPath[32];
2714     sprintf(szProcPath, "/proc/%d/exe", getpid());  // attempt to read link
2715     if (readlink(szProcPath, buffer, max) != -1)
2716     {
2717         dirname (buffer);
2718         strcat  (buffer, "/");
2719         return strlen(buffer);
2720     }
2721     return 0;
2722 }
2723 #endif
2724 
U14LdCmd(short hand,const char * command)2725 U14API(short) U14LdCmd(short hand, const char* command)
2726 {
2727     char strcopy[MAXSTRLEN+1];      // to hold copy of work string
2728     BOOL bGotIt = FALSE;            // have we found the command file?
2729     int iFHandle;                   // file handle of command
2730 #define FNSZ 260
2731     char filnam[FNSZ];              // space to build name in
2732     char szCmd[25];                 // just the command name with extension
2733 
2734     short sErr = CheckHandle(hand);
2735     if (sErr != U14ERR_NOERROR)
2736         return sErr;
2737 
2738     if (strchr(command, '.') != NULL)       // see if we have full name
2739     {
2740         if (file_exist(command))            // If the file exists
2741         {
2742             strcpy(filnam, command);        // use name as is
2743             bGotIt = TRUE;                  // Flag no more searching
2744         }
2745         else                                // not found, get file name for search
2746         {
2747             char* pStr = strrchr(command, PATHSEP);  // Point to last separator
2748             if (pStr != NULL)               // Check we got it
2749             {
2750                 pStr++;                     // move past the backslash
2751                 strcpy(szCmd, pStr);        // copy file name as is
2752             }
2753             else
2754                 strcpy(szCmd, command);     // use as is
2755         }
2756     }
2757     else    // File extension not supplied, so build the command file name
2758     {
2759         char szExt[8];
2760         strcpy(szCmd, command);             // Build command file name
2761         ExtForType(asType1401[hand], szExt);// File extension string
2762         strcat(szCmd, szExt);               // add it to the end
2763     }
2764 
2765     // Next place to look is in the 1401 folder in the same place as the
2766     // application was run from.
2767     if (!bGotIt)                            // Still not got it?
2768     {
2769         DWORD dwLen = GetModuleFileName(NULL, filnam, FNSZ); // Get app path
2770         if (dwLen > 0)                      // and use it as path if found
2771         {
2772             char* pStr = strrchr(filnam, PATHSEP);    // Point to last separator
2773             if (pStr != NULL)
2774             {
2775                 *(++pStr) = 0;                  // Terminate string there
2776                 if (strlen(filnam) < FNSZ-6)    // make sure we have space
2777                 {
2778                     strcat(filnam, "1401" PATHSEPSTR);  // add in 1401 subdir
2779                     strcat(filnam,szCmd);
2780                     bGotIt = (BOOL)file_exist(filnam);  // See if file exists
2781                 }
2782             }
2783         }
2784     }
2785 
2786     // Next place to look is in whatever path is set by the 1401DIR environment
2787     // variable, if it exists.
2788     if (!bGotIt)                            // Need to do more searches?/
2789     {
2790         char* pStr = getenv("1401DIR");     // Try to find environment var
2791         if (pStr != NULL)                   // and use it as path if found
2792         {
2793             strcpy(filnam, pStr);                   // Use path in environment
2794             if (filnam[strlen(filnam)-1] != PATHSEP)// We need separator
2795                 strcat(filnam, PATHSEPSTR);
2796             strcat(filnam, szCmd);
2797             bGotIt = (BOOL)file_exist(filnam); // Got this one?
2798         }
2799     }
2800 
2801     // Last place to look is the default location.
2802     if (!bGotIt)                        // Need to do more searches?
2803     {
2804         strcpy(filnam, DEFCMDPATH);     // Use default path
2805         strcat(filnam, szCmd);
2806         bGotIt = file_exist(filnam);    // Got this one?
2807     }
2808 
2809     iFHandle = file_open(filnam);
2810     if (iFHandle == -1)
2811         sErr = U14ERR_NOFILE;
2812     else
2813     {                                   // first read in the header block
2814         CMDHEAD rCmdHead;               // to hold the command header
2815         if (file_read(iFHandle, &rCmdHead, sizeof(CMDHEAD)))
2816         {
2817             size_t nComSize = rCmdHead.wCmdSize;
2818             char* pMem = malloc(nComSize);
2819             if (pMem != NULL)
2820             {
2821                 file_seek(iFHandle, sizeof(CMDHEAD));
2822                 if (file_read(iFHandle, pMem, (UINT)nComSize))
2823                 {
2824                     sErr = U14SetTransArea(hand, 0, (void *)pMem, (DWORD)nComSize, ESZBYTES);
2825                     if (sErr == U14ERR_NOERROR)
2826                     {
2827                         sprintf(strcopy, "CLOAD,0,$%X;", (int)nComSize);
2828                         sErr = U14SendString(hand, strcopy);
2829                         if (sErr == U14ERR_NOERROR)
2830                         {
2831                             sErr = U14CheckErr(hand);     // Use ERR to check for done
2832                             if (sErr > 0)
2833                                 sErr = U14ERR_CLOADERR;   // If an error, this code
2834                         }
2835                         U14UnSetTransfer(hand, 0);  // release transfer area
2836                     }
2837                 }
2838                 else
2839                     sErr = U14ERR_READERR;
2840                 free(pMem);
2841             }
2842             else
2843                 sErr = U14ERR_HOSTSPACE;    // memory allocate failed
2844         }
2845         else
2846             sErr = U14ERR_READERR;
2847 
2848         file_close(iFHandle);               // close the file
2849     }
2850 
2851     return sErr;
2852 }
2853 
2854 
2855 /****************************************************************************
2856 ** Ld
2857 ** Loads a command into the 1401
2858 ** Returns NOERROR code or a long with error in lo word and index of
2859 ** command that failed in high word
2860 ****************************************************************************/
U14Ld(short hand,const char * vl,const char * str)2861 U14API(DWORD) U14Ld(short hand, const char* vl, const char* str)
2862 {
2863     DWORD dwIndex = 0;              // index to current command
2864     long lErr = U14ERR_NOERROR;     // what the error was that went wrong
2865     char strcopy[MAXSTRLEN+1];      // stores unmodified str parameter
2866     char szFExt[8];                 // The command file extension
2867     short sErr = CheckHandle(hand);
2868     if (sErr != U14ERR_NOERROR)
2869         return sErr;
2870 
2871     ExtForType(asType1401[hand], szFExt);   // File extension string
2872     strcpy(strcopy, str);               // to avoid changing original
2873 
2874     // now break out one command at a time and see if loaded
2875     if (*str)                           // if anything there
2876     {
2877         BOOL bDone = FALSE;             // true when finished all commands
2878         int iLoop1 = 0;                 // Point at start of string for command name
2879         int iLoop2 = 0;                 // and at start of str parameter
2880         do                              // repeat until end of str
2881         {
2882             char filnam[MAXSTRLEN+1];   // filename to use
2883             char szFName[MAXSTRLEN+1];  // filename work string
2884 
2885             if (!strcopy[iLoop1])       // at the end of the string?
2886                 bDone = TRUE;           // set the finish flag
2887 
2888             if (bDone || (strcopy[iLoop1] == ','))  // end of cmd?
2889             {
2890                 U14LONG er[5];                  // Used to read back error results
2891                 ++dwIndex;                      // Keep count of command number, first is 1
2892                 szFName[iLoop2]=(char)0;        // null terminate name of command
2893 
2894                 strncpy(szLastName, szFName, sizeof(szLastName));    // Save for error info
2895                 szLastName[sizeof(szLastName)-1] = 0;
2896                 strncat(szLastName, szFExt, sizeof(szLastName));     // with extension included
2897                 szLastName[sizeof(szLastName)-1] = 0;
2898 
2899                 U14SendString(hand, szFName);   // ask if loaded
2900                 U14SendString(hand, ";ERR;");   // add err return
2901 
2902                 lErr = U14LongsFrom1401(hand, er, 5);
2903                 if (lErr > 0)
2904                 {
2905                     lErr = U14ERR_NOERROR;
2906                     if (er[0] == 255)           // if command not loaded at all
2907                     {
2908                         if (vl && *vl)          // if we have a path name
2909                         {
2910                             strcpy(filnam, vl);
2911                             if (strchr("\\/:", filnam[strlen(filnam)-1]) == NULL)
2912                                 strcat(filnam, PATHSEPSTR); // add separator if none found
2913                             strcat(filnam, szFName);    // add the file name
2914                             strcat(filnam, szFExt);     // and extension
2915                         }
2916                         else
2917                             strcpy(filnam, szFName);    // simple name
2918 
2919                         lErr = U14LdCmd(hand, filnam);  // load cmd
2920                         if (lErr != U14ERR_NOERROR)     // spot any errors
2921                             bDone = TRUE;               // give up if an error
2922                     }
2923                 }
2924                 else
2925                     bDone = TRUE;       // give up if an error
2926 
2927                 iLoop2 = 0;             // Reset pointer to command name string
2928                 ++iLoop1;               // and move on through str parameter
2929             }
2930             else
2931                 szFName[iLoop2++] = strcopy[iLoop1++];  // no command end, so copy 1 char
2932         }
2933         while (!bDone);
2934     }
2935 
2936     if (lErr == U14ERR_NOERROR)
2937     {
2938         szLastName[0] = 0;      // No error, so clean out command name here
2939         return lErr;
2940     }
2941     else
2942         return ((dwIndex<<16) | ((DWORD)lErr & 0x0000FFFF));
2943 }
2944 
2945 // Initialise the library (if not initialised) and return the library version
U14InitLib(void)2946 U14API(int) U14InitLib(void)
2947 {
2948     int iRetVal = U14LIB_VERSION;
2949     if (iAttached == 0)         // only do this the first time please
2950     {
2951         int i;
2952 #ifdef _IS_WINDOWS_
2953         int j;
2954         DWORD   dwVersion = GetVersion();
2955         bWindows9x = FALSE;                  // Assume not Win9x
2956 
2957         if (dwVersion & 0x80000000)                 // if not windows NT
2958         {
2959             if ((LOBYTE(LOWORD(dwVersion)) < 4) &&  // if Win32s or...
2960                  (HIBYTE(LOWORD(dwVersion)) < 95))  // ...below Windows 95
2961             iRetVal = 0;                            // We do not support this
2962         else
2963             bWindows9x = TRUE;                      // Flag we have Win9x
2964         }
2965 #endif
2966 
2967         for (i = 0; i < MAX1401; i++)               // initialise the device area
2968         {
2969             aHand1401[i] = INVALID_HANDLE_VALUE;    // Clear handle values
2970             asType1401[i] = U14TYPEUNKNOWN;         // and 1401 type codes
2971             alTimeOutPeriod[i] = 3000;              // 3 second timeouts
2972 #ifdef _IS_WINDOWS_
2973 #ifndef _WIN64
2974             abUseNTDIOC[i] = (BOOL)!bWindows9x;
2975 #endif
2976             aXferEvent[i] = NULL;                   // there are no Xfer events
2977             for (j = 0; j < MAX_TRANSAREAS; j++)    // Clear out locked area info
2978             {
2979                 apAreas[i][j] = NULL;
2980                 auAreas[i][j] = 0;
2981             }
2982 #endif
2983         }
2984     }
2985     return iRetVal;
2986 }
2987 
2988 ///--------------------------------------------------------------------------------
2989 /// Functions called when the library is loaded and unloaded to give us a chance to
2990 /// setup the library.
2991 
2992 
2993 #ifdef _IS_WINDOWS_
2994 #ifndef U14_NOT_DLL
2995 /****************************************************************************
2996 ** FUNCTION: DllMain(HANDLE, DWORD, LPVOID)
2997 ** LibMain is called by Windows when the DLL is initialized, Thread Attached,
2998 ** and other times. Refer to SDK documentation, as to the different ways this
2999 ** may be called.
3000 ****************************************************************************/
DllMain(HANDLE hInst,DWORD ul_reason_being_called,LPVOID lpReserved)3001 INT APIENTRY DllMain(HANDLE hInst, DWORD ul_reason_being_called, LPVOID lpReserved)
3002 {
3003     int iRetVal = 1;
3004 
3005     switch (ul_reason_being_called)
3006     {
3007     case DLL_PROCESS_ATTACH:
3008         iRetVal = U14InitLib() > 0;         // does nothing if iAttached != 0
3009         ++iAttached;                        // count times attached
3010         break;
3011 
3012     case DLL_PROCESS_DETACH:
3013         if (--iAttached == 0)               // last man out?
3014             U14CloseAll();                  // release all open handles
3015         break;
3016     }
3017     return iRetVal;
3018 
3019     UNREFERENCED_PARAMETER(lpReserved);
3020 }
3021 #endif
3022 #endif
3023 #ifdef LINUX
use1401_load(void)3024 void __attribute__((constructor)) use1401_load(void)
3025 {
3026     U14InitLib();
3027     ++iAttached;
3028 }
3029 
use1401_unload(void)3030 void __attribute__((destructor)) use1401_unload(void)
3031 {
3032         if (--iAttached == 0)               // last man out?
3033             U14CloseAll();                  // release all open handles
3034 }
3035 #endif
3036