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, >b); // 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