source: trunk/src/kernel32/hmcomm.cpp@ 7524

Last change on this file since 7524 was 7524, checked in by sandervl, 24 years ago

removed logging

File size: 57.5 KB
Line 
1/* $Id: hmcomm.cpp,v 1.24 2001-12-02 12:00:50 sandervl Exp $ */
2
3/*
4 * Project Odin Software License can be found in LICENSE.TXT
5 *
6 * Win32 COM device access class
7 *
8 * 1999 Achim Hasenmueller <achimha@innotek.de>
9 * 2001 Sander van Leeuwen <sandervl@xs4all.nl>
10 *
11 * TODO: Overlapped IO only supports one request at a time
12 * TODO: Overlapped IO not thread safe
13 *
14 */
15
16
17
18#include <os2win.h>
19#include <string.h>
20#include <handlemanager.h>
21#include "handlenames.h"
22#include <heapstring.h>
23#include "hmdevice.h"
24#include "hmcomm.h"
25#include "oslibdos.h"
26
27#define DBG_LOCALLOG DBG_hmcomm
28#include "dbglocal.h"
29
30//#define TESTING_COMM
31#ifdef TESTING_COMM
32#undef dprintf
33#define dprintf(a) WriteLog a
34#undef dprintf2
35#define dprintf2(a) WriteLog a
36#endif
37
38BAUDTABLEENTRY BaudTable[] =
39{
40 {75,BAUD_075},
41 {110,BAUD_110},
42 {134,BAUD_134_5},
43 {150,BAUD_150},
44 {300,BAUD_300},
45 {600,BAUD_600},
46 {1200,BAUD_1200},
47 {1800,BAUD_1800},
48 {2400,BAUD_2400},
49 {4800,BAUD_4800},
50 {7200,BAUD_7200},
51 {9600,BAUD_9600},
52 {14400,BAUD_14400},
53 {19200,BAUD_19200},
54 {38400,BAUD_38400},
55 {56000,BAUD_56K},
56 {57600,BAUD_57600},
57 {115200,BAUD_115200},
58 {128000,BAUD_128K}
59};
60
61#define BaudTableSize (sizeof(BaudTable)/sizeof(BAUDTABLEENTRY))
62
63DWORD CALLBACK SerialCommThread(LPVOID lpThreadParam);
64
65//******************************************************************************
66//******************************************************************************
67static VOID *CreateDevData()
68{
69 PHMDEVCOMDATA pData;
70 pData = new HMDEVCOMDATA();
71 if(NULL!=pData)
72 {
73 memset(pData,0,sizeof(HMDEVCOMDATA));
74 pData->ulMagic = MAGIC_COM;
75 pData->CommCfg.dwSize = sizeof(COMMCONFIG);
76 pData->CommCfg.wVersion = 1;
77 pData->CommCfg.dwProviderSubType = PST_RS232;
78 pData->CommCfg.dcb.DCBlength = sizeof(DCB);
79 pData->CommCfg.dcb.BaudRate = CBR_1200;
80 pData->CommCfg.dcb.ByteSize = 8;
81 pData->CommCfg.dcb.Parity = NOPARITY;
82 pData->CommCfg.dcb.StopBits = ONESTOPBIT;
83 pData->dwInBuffer = 16;
84 pData->dwOutBuffer = 16;
85 }
86 return pData;
87}
88//******************************************************************************
89//******************************************************************************
90HMDeviceCommClass::HMDeviceCommClass(LPCSTR lpDeviceName) : HMDeviceHandler(lpDeviceName)
91{
92 VOID *pData;
93 dprintf(("HMDeviceCommClass: Register COM1 to COM8 with Handle Manager\n"));
94 pData = CreateDevData();
95 if(pData!= NULL)
96 HMDeviceRegisterEx("COM1", this, pData);
97
98 // add symbolic links to the "real name" of the device
99 {
100 // @@@PH what's the long device name: SerialPortx ?
101 // HandleNamesAddSymbolicLink("\\Device\\ParallelPort3", "COM3");
102 // Note: \\.\COMx: is invalid (NT4SP6)
103
104 PSZ pszCOM = strdup("\\\\.\\COMx");
105 for (char ch = '1'; ch <= '9'; ch++)
106 {
107 pszCOM[7] = ch;
108 HandleNamesAddSymbolicLink(pszCOM, pszCOM+4);
109 }
110 free(pszCOM);
111
112 // add "AUX" device
113 HandleNamesAddSymbolicLink("AUX", "COM1");
114 HandleNamesAddSymbolicLink("AUX:", "COM1");
115 HandleNamesAddSymbolicLink("\\\\.\\AUX", "COM1");
116 }
117}
118
119/*****************************************************************************
120 * Name : HMDeviceCommClass::FindDevice
121 * Purpose : Checks if lpDeviceName belongs to this device class
122 * Parameters: LPCSTR lpClassDevName
123 * LPCSTR lpDeviceName
124 * int namelength
125 * Variables :
126 * Result : checks if name is COMx or COMx: (x=1..8)
127 * Remark :
128 * Status :
129 *
130 * Author : SvL
131 *****************************************************************************/
132BOOL HMDeviceCommClass::FindDevice(LPCSTR lpClassDevName, LPCSTR lpDeviceName, int namelength)
133{
134 dprintf2(("HMDeviceCommClass::FindDevice %s %s", lpClassDevName, lpDeviceName));
135
136 //first 3 letters 'COM'?
137 if(lstrncmpiA(lpDeviceName, lpClassDevName, 3) != 0) {
138 return FALSE;
139 }
140
141 if(namelength == 5 && lpDeviceName[4] != ':') {
142 return FALSE;
143 }
144 switch(lpDeviceName[3]) {
145 case '1':
146 case '2':
147 case '3':
148 case '4':
149 case '5':
150 case '6':
151 case '7':
152 case '8':
153 return TRUE; //we support up to COM8
154 }
155 return FALSE;
156}
157//******************************************************************************
158//******************************************************************************
159DWORD HMDeviceCommClass::CreateFile(HANDLE hComm,
160 LPCSTR lpFileName,
161 PHMHANDLEDATA pHMHandleData,
162 PVOID lpSecurityAttributes,
163 PHMHANDLEDATA pHMHandleDataTemplate)
164{
165 char comname[6];
166
167 dprintf(("HMComm: Serial communication port %s open request\n", lpFileName));
168
169 if(strlen(lpFileName) > 5) {
170 lpFileName += 4; //skip prefix
171 }
172
173 pHMHandleData->hHMHandle = 0;
174
175 strcpy(comname, lpFileName);
176 comname[4] = 0; //get rid of : (if present) (eg COM1:)
177
178 //AH: TODO parse Win32 security handles
179 ULONG oldmode = ::SetErrorMode(SEM_FAILCRITICALERRORS);
180 pHMHandleData->hHMHandle = OSLibDosOpen(comname,
181 OSLIB_ACCESS_READWRITE |
182 OSLIB_ACCESS_SHAREDENYREAD |
183 OSLIB_ACCESS_SHAREDENYWRITE);
184 ::SetErrorMode(oldmode);
185 if (pHMHandleData->hHMHandle != 0)
186 {
187 ULONG ulLen;
188 APIRET rc;
189 pHMHandleData->lpHandlerData = new HMDEVCOMDATA();
190 // Init The handle instance with the default default device config
191 memcpy( pHMHandleData->lpHandlerData,
192 pHMHandleData->lpDeviceData,
193 sizeof(HMDEVCOMDATA));
194
195 ulLen = sizeof(DCBINFO);
196
197 rc = OSLibDosDevIOCtl( pHMHandleData->hHMHandle,
198 IOCTL_ASYNC,
199 ASYNC_GETDCBINFO,
200 0,0,0,
201 &((PHMDEVCOMDATA)pHMHandleData->lpHandlerData)->dcbOS2,ulLen,&ulLen);
202 dprintf(("DCB Of %s :\n"
203 " WriteTimeout : %d\n"
204 " ReadTimeout : %d\n"
205 " CtlHandshake : 0x%x\n"
206 " FlowReplace : 0x%x\n"
207 " Timeout : 0x%x\n"
208 " Error replacement Char : 0x%x\n"
209 " Break replacement Char : 0x%x\n"
210 " XON Char : 0x%x\n"
211 " XOFF Char : 0x%x\n",
212 comname,
213 ((PHMDEVCOMDATA)pHMHandleData->lpHandlerData)->dcbOS2.usWriteTimeout,
214 ((PHMDEVCOMDATA)pHMHandleData->lpHandlerData)->dcbOS2.usReadTimeout,
215 ((PHMDEVCOMDATA)pHMHandleData->lpHandlerData)->dcbOS2.fbCtlHndShake,
216 ((PHMDEVCOMDATA)pHMHandleData->lpHandlerData)->dcbOS2.fbFlowReplace,
217 ((PHMDEVCOMDATA)pHMHandleData->lpHandlerData)->dcbOS2.fbTimeOut,
218 ((PHMDEVCOMDATA)pHMHandleData->lpHandlerData)->dcbOS2.bErrorReplacementChar,
219 ((PHMDEVCOMDATA)pHMHandleData->lpHandlerData)->dcbOS2.bBreakReplacementChar,
220 ((PHMDEVCOMDATA)pHMHandleData->lpHandlerData)->dcbOS2.bXONChar,
221 ((PHMDEVCOMDATA)pHMHandleData->lpHandlerData)->dcbOS2.bXOFFChar));
222
223 if(rc)
224 {
225 delete pHMHandleData->lpHandlerData;
226 return rc;
227 }
228 rc = SetBaud(pHMHandleData,9600);
229 dprintf(("Init Baud to 9600 rc = %d",rc));
230 rc = SetLine(pHMHandleData,8,0,0);
231 dprintf(("Set Line to 8/N/1 rc = %d",rc));
232
233 if(pHMHandleData->dwFlags & FILE_FLAG_OVERLAPPED)
234 {
235 PHMDEVCOMDATA pDevData = (PHMDEVCOMDATA)pHMHandleData->lpHandlerData;
236 DWORD dwThreadId;
237
238 pDevData->hEventSem = ::CreateEventA(NULL, TRUE, FALSE, NULL);
239 pDevData->hThread = ::CreateThread(NULL, 32*1024, SerialCommThread, (LPVOID)hComm, 0, &dwThreadId);
240
241 if(!pDevData->hEventSem || !pDevData->hThread)
242 {
243 DebugInt3();
244 if(pDevData->hEventSem) ::CloseHandle(pDevData->hEventSem);
245 delete pHMHandleData->lpHandlerData;
246 return ERROR_NOT_ENOUGH_MEMORY;
247 }
248 }
249 return ERROR_SUCCESS;
250 }
251 else
252 return ERROR_ACCESS_DENIED;
253}
254//******************************************************************************
255//******************************************************************************
256BOOL HMDeviceCommClass::CloseHandle(PHMHANDLEDATA pHMHandleData)
257{
258 PHMDEVCOMDATA pDevData = (PHMDEVCOMDATA)pHMHandleData->lpHandlerData;
259 dprintf(("HMComm: Serial communication port close request"));
260
261 if(pDevData && pHMHandleData->dwFlags & FILE_FLAG_OVERLAPPED)
262 {
263 pDevData->fClosing = TRUE;
264 dprintf(("signalling serial thread"));
265 ::SetEvent(pDevData->hEventSem);
266 ::ResetEvent(pDevData->hEventSem);
267
268 //Wait for thread to clean up
269 dprintf(("waiting for serial thread"));
270 DWORD ret = ::WaitForSingleObject(pDevData->hEventSem, 200);
271 dprintf(("waiting for serial thread done -> %x", ret));
272 ::CloseHandle(pDevData->hEventSem);
273 }
274 delete pHMHandleData->lpHandlerData;
275 return OSLibDosClose(pHMHandleData->hHMHandle);
276}
277/*****************************************************************************
278 * Name : BOOL HMDeviceCommClass::WriteFile
279 * Purpose : write data to handle / device
280 * Parameters: PHMHANDLEDATA pHMHandleData,
281 * LPCVOID lpBuffer,
282 * DWORD nNumberOfBytesToWrite,
283 * LPDWORD lpNumberOfBytesWritten,
284 * LPOVERLAPPED lpOverlapped
285 * Variables :
286 * Result : Boolean
287 * Remark :
288 * Status :
289 *
290 * Author : SvL
291 *****************************************************************************/
292BOOL HMDeviceCommClass::WriteFile(PHMHANDLEDATA pHMHandleData,
293 LPCVOID lpBuffer,
294 DWORD nNumberOfBytesToWrite,
295 LPDWORD lpNumberOfBytesWritten,
296 LPOVERLAPPED lpOverlapped)
297{
298 dprintf(("KERNEL32:HMDeviceCommClass::WriteFile %s(%08x,%08x,%08x,%08x,%08x)",
299 lpHMDeviceName,
300 pHMHandleData->hHMHandle,
301 lpBuffer,
302 nNumberOfBytesToWrite,
303 lpNumberOfBytesWritten,
304 lpOverlapped));
305
306 BOOL ret;
307 ULONG ulBytesWritten;
308
309 if((pHMHandleData->dwFlags & FILE_FLAG_OVERLAPPED) && !lpOverlapped) {
310 dprintf(("FILE_FLAG_OVERLAPPED flag set, but lpOverlapped NULL!!"));
311 ::SetLastError(ERROR_INVALID_PARAMETER);
312 return FALSE;
313 }
314 if(!(pHMHandleData->dwFlags & FILE_FLAG_OVERLAPPED) && lpOverlapped) {
315 dprintf(("Warning: lpOverlapped != NULL & !FILE_FLAG_OVERLAPPED; sync operation"));
316 }
317//testestestest
318 dprintf(("Bytes to write:"));
319 for(int i=0;i<nNumberOfBytesToWrite;i++) {
320 dprintf(("%x %c", ((char *)lpBuffer)[i], ((char *)lpBuffer)[i]));
321 }
322//testestestset
323
324 ret = OSLibDosWrite(pHMHandleData->hHMHandle, (LPVOID)lpBuffer, nNumberOfBytesToWrite,
325 &ulBytesWritten);
326
327 if(lpNumberOfBytesWritten) {
328 *lpNumberOfBytesWritten = (ret) ? ulBytesWritten : 0;
329 dprintf2(("KERNEL32:HMDeviceCommClass::WriteFile %d byte(s) written", *lpNumberOfBytesWritten));
330 }
331 if(ret == FALSE) {
332 dprintf(("!ERROR!: WriteFile failed with rc %d", GetLastError()));
333 }
334
335 return ret;
336}
337/*****************************************************************************
338 * Name : BOOL WriteFileEx
339 * Purpose : The WriteFileEx function writes data to a file. It is designed
340 * solely for asynchronous operation, unlike WriteFile, which is
341 * designed for both synchronous and asynchronous operation.
342 * WriteFileEx reports its completion status asynchronously,
343 * calling a specified completion routine when writing is completed
344 * and the calling thread is in an alertable wait state.
345 * Parameters: HANDLE hFile handle of file to write
346 * LPVOID lpBuffer address of buffer
347 * DWORD nNumberOfBytesToRead number of bytes to write
348 * LPOVERLAPPED lpOverlapped address of offset
349 * LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine address of completion routine
350 * Variables :
351 * Result : TRUE / FALSE
352 * Remark :
353 * Status : UNTESTED STUB
354 *
355 * Author : SvL
356 *****************************************************************************/
357
358BOOL HMDeviceCommClass::WriteFileEx(PHMHANDLEDATA pHMHandleData,
359 LPVOID lpBuffer,
360 DWORD nNumberOfBytesToWrite,
361 LPOVERLAPPED lpOverlapped,
362 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
363{
364 dprintf(("!ERROR!: WriteFileEx %s (%08xh,%08xh,%08xh,%08xh,%08xh) not implemented.\n",
365 lpHMDeviceName,
366 pHMHandleData->hHMHandle,
367 lpBuffer,
368 nNumberOfBytesToWrite,
369 lpOverlapped,
370 lpCompletionRoutine));
371
372 if(!(pHMHandleData->dwFlags & FILE_FLAG_OVERLAPPED)) {
373 dprintf(("!WARNING!: Handle not created with FILE_FLAG_OVERLAPPED!"));
374 ::SetLastError(ERROR_ACCESS_DENIED); //todo: right error?
375 return FALSE;
376 }
377
378 ::SetLastError(ERROR_INVALID_FUNCTION);
379 return FALSE;
380}
381/*****************************************************************************
382 * Name : BOOL HMDeviceCommClass::ReadFile
383 * Purpose : read data from handle / device
384 * Parameters: PHMHANDLEDATA pHMHandleData,
385 * LPCVOID lpBuffer,
386 * DWORD nNumberOfBytesToRead,
387 * LPDWORD lpNumberOfBytesRead,
388 * LPOVERLAPPED lpOverlapped
389 * Variables :
390 * Result : Boolean
391 * Remark :
392 * Status :
393 *
394 * Author : SvL
395 *****************************************************************************/
396
397BOOL HMDeviceCommClass::ReadFile(PHMHANDLEDATA pHMHandleData,
398 LPCVOID lpBuffer,
399 DWORD nNumberOfBytesToRead,
400 LPDWORD lpNumberOfBytesRead,
401 LPOVERLAPPED lpOverlapped)
402{
403 dprintf(("KERNEL32:HMDeviceCommClass::ReadFile %s(%08x,%08x,%08x,%08x,%08x)",
404 lpHMDeviceName,
405 pHMHandleData->hHMHandle,
406 lpBuffer,
407 nNumberOfBytesToRead,
408 lpNumberOfBytesRead,
409 lpOverlapped));
410
411 BOOL ret;
412 ULONG ulBytesRead;
413
414 if((pHMHandleData->dwFlags & FILE_FLAG_OVERLAPPED) && !lpOverlapped) {
415 dprintf(("FILE_FLAG_OVERLAPPED flag set, but lpOverlapped NULL!!"));
416 ::SetLastError(ERROR_INVALID_PARAMETER);
417 return FALSE;
418 }
419 if(!(pHMHandleData->dwFlags & FILE_FLAG_OVERLAPPED) && lpOverlapped) {
420 dprintf(("!WARNING!: lpOverlapped != NULL & !FILE_FLAG_OVERLAPPED; sync operation"));
421 }
422
423 RXQUEUE qInfo;
424 ULONG ulLen = sizeof(qInfo);
425 ULONG rc = OSLibDosDevIOCtl( pHMHandleData->hHMHandle,
426 IOCTL_ASYNC,
427 ASYNC_GETINQUECOUNT,
428 0,0,0,
429 &qInfo,ulLen,&ulLen);
430 dprintf(("ASYNC_GETINQUECOUNT -> qInfo.cch %d (queue size %d) rc %d", qInfo.cch, qInfo.cb, rc));
431
432 ret = OSLibDosRead(pHMHandleData->hHMHandle, (LPVOID)lpBuffer, nNumberOfBytesToRead,
433 &ulBytesRead);
434
435 if(lpNumberOfBytesRead) {
436 *lpNumberOfBytesRead = (ret) ? ulBytesRead : 0;
437 dprintf2(("KERNEL32:HMDeviceCommClass::ReadFile %d bytes read", *lpNumberOfBytesRead));
438 }
439 if(ret == FALSE) {
440 dprintf(("!ERROR!: ReadFile failed with rc %d", GetLastError()));
441 }
442 else {
443//testestestest
444 dprintf(("Bytes read:"));
445 for(int i=0;i<ulBytesRead;i++) {
446 dprintf(("%x %c", ((char *)lpBuffer)[i], ((char *)lpBuffer)[i]));
447 }
448//testestestset
449 }
450 return ret;
451}
452
453/*****************************************************************************
454 * Name : BOOL ReadFileEx
455 * Purpose : The ReadFileEx function reads data from a file asynchronously.
456 * It is designed solely for asynchronous operation, unlike the
457 * ReadFile function, which is designed for both synchronous and
458 * asynchronous operation. ReadFileEx lets an application perform
459 * other processing during a file read operation.
460 * The ReadFileEx function reports its completion status asynchronously,
461 * calling a specified completion routine when reading is completed
462 * and the calling thread is in an alertable wait state.
463 * Parameters: HANDLE hFile handle of file to read
464 * LPVOID lpBuffer address of buffer
465 * DWORD nNumberOfBytesToRead number of bytes to read
466 * LPOVERLAPPED lpOverlapped address of offset
467 * LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine address of completion routine
468 * Variables :
469 * Result : TRUE / FALSE
470 * Remark :
471 * Status : UNTESTED STUB
472 *
473 * Author : SvL
474 *****************************************************************************/
475BOOL HMDeviceCommClass::ReadFileEx(PHMHANDLEDATA pHMHandleData,
476 LPVOID lpBuffer,
477 DWORD nNumberOfBytesToRead,
478 LPOVERLAPPED lpOverlapped,
479 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
480{
481 dprintf(("!ERROR!: ReadFileEx %s (%08xh,%08xh,%08xh,%08xh,%08xh) not implemented.\n",
482 lpHMDeviceName,
483 pHMHandleData->hHMHandle,
484 lpBuffer,
485 nNumberOfBytesToRead,
486 lpOverlapped,
487 lpCompletionRoutine));
488
489 if(!(pHMHandleData->dwFlags & FILE_FLAG_OVERLAPPED)) {
490 dprintf(("!WARNING!: Handle not created with FILE_FLAG_OVERLAPPED!"));
491 ::SetLastError(ERROR_ACCESS_DENIED); //todo: right error?
492 return FALSE;
493 }
494
495 ::SetLastError(ERROR_INVALID_FUNCTION);
496 return FALSE;
497}
498/*****************************************************************************
499 * Name : DWORD HMDeviceHandler::SetupComm
500 * Purpose : set com port parameters (queue)
501 * Variables :
502 * Result :
503 * Remark :
504 * Status :
505 *
506 * Author : Achim Hasenmueller
507 *****************************************************************************/
508
509BOOL HMDeviceCommClass::SetupComm( PHMHANDLEDATA pHMHandleData,
510 DWORD dwInQueue,
511 DWORD dwOutQueue)
512{
513 dprintf(("HMDeviceCommClass::SetupComm "));
514 PHMDEVCOMDATA pDevData = (PHMDEVCOMDATA)pHMHandleData->lpHandlerData;
515 if((NULL==pDevData) || (pDevData->ulMagic != MAGIC_COM) )
516 {
517 ::SetLastError(ERROR_INVALID_HANDLE);
518 return FALSE;
519 }
520 pDevData->dwInBuffer = dwInQueue;
521 pDevData->dwOutBuffer = dwOutQueue;
522
523 return(TRUE);
524}
525//******************************************************************************
526#define TIMEOUT_COMM 50
527//******************************************************************************
528DWORD CALLBACK SerialCommThread(LPVOID lpThreadParam)
529{
530 HANDLE hComm = (HANDLE)lpThreadParam;
531 PHMHANDLEDATA pHMHandleData;
532 PHMDEVCOMDATA pDevData;
533 DWORD ret;
534 APIRET rc;
535 ULONG ulLen;
536 USHORT COMEvt;
537 DWORD dwEvent,dwMask;
538
539 pHMHandleData = HMQueryHandleData(hComm);
540 if(!pHMHandleData) {
541 dprintf(("!ERROR!: Invalid handle -> aborting"));
542 return 0;
543 }
544
545 pDevData = (PHMDEVCOMDATA)pHMHandleData->lpHandlerData;
546 if(!pDevData) {
547 dprintf(("!ERROR! SerialCommThread !pDevData"));
548 DebugInt3();
549 return 0;
550 }
551 HANDLE hEvent = pDevData->hEventSem;
552 HANDLE hCommOS2 = pHMHandleData->hHMHandle;
553 if(!hCommOS2 || !hEvent) {
554 dprintf(("!ERROR! SerialCommThread !hCommOS2 || !hEvent"));
555 DebugInt3();
556 return 0;
557 }
558 dprintf(("SerialCommThread %x entered", hComm));
559
560 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
561 while(TRUE)
562 {
563 //validate handle
564 pHMHandleData = HMQueryHandleData(hComm);
565 if(!pHMHandleData) {
566 dprintf(("!ERROR!: Invalid handle -> aborting"));
567 return 0;
568 }
569 if(pDevData->fClosing) {
570 dprintf(("Cleaning up async comm thread"));
571 SetEvent(hEvent); //signal to CloseHandle that we're done
572 return 0;
573 }
574
575 //Wait for the app to call WaitCommEvent
576 dprintf(("SerialCommThread: wait for WaitCommEvent"));
577 ret = WaitForSingleObject(hEvent, INFINITE);
578 ResetEvent(hEvent);
579 dprintf(("SerialCommThread: wait for WaitCommEvent done %x", ret));
580
581 //validate handle first
582 pHMHandleData = HMQueryHandleData(hComm);
583 if(!pHMHandleData) {
584 dprintf(("!ERROR!: Invalid handle -> aborting"));
585 return 0;
586 }
587
588 if(pDevData->fClosing) {
589 dprintf(("Cleaning up async comm thread"));
590 SetEvent(hEvent); //signal to CloseHandle that we're done
591 return 0;
592 }
593
594 HANDLE hOverlappedEvent = pDevData->overlapped.hEvent;
595 if(!hOverlappedEvent) {
596 DebugInt3();
597 return 0;
598 }
599
600 ulLen = sizeof(CHAR);
601 dwEvent = 0;
602 rc = 0;
603 ulLen = sizeof(COMEvt);
604 dwMask = pDevData->dwEventMask;
605
606 while( (0==rc) &&
607 !(dwEvent & dwMask) &&
608 (dwMask == pDevData->dwEventMask) &&
609 !(pDevData->fCancelIo) && !(pDevData->fClosing) ) // Exit if the Mask gets changed
610 {
611 rc = OSLibDosDevIOCtl(hCommOS2,
612 IOCTL_ASYNC,
613 ASYNC_GETCOMMEVENT,
614 0,0,0,
615 &COMEvt,ulLen,&ulLen);
616 if(!rc)
617 {
618 dwEvent |= (COMEvt&0x0001)? EV_RXCHAR:0;
619 //dwEvent |= (COMEvt&0x0002)? 0:0;
620 dwEvent |= (COMEvt&0x0004)? EV_TXEMPTY:0;
621 dwEvent |= (COMEvt&0x0008)? EV_CTS:0;
622 dwEvent |= (COMEvt&0x0010)? EV_DSR:0;
623 //dwEvent |= (COMEvt&0x0020)? 0:0; DCS = RLSD?
624 dwEvent |= (COMEvt&0x0040)? EV_BREAK:0;
625 dwEvent |= (COMEvt&0x0080)? EV_ERR:0;
626 dwEvent |= (COMEvt&0x0100)? EV_RING:0;
627 if((dwEvent & dwMask)) break;
628 }
629 else break;
630
631 //validate handle first
632 pHMHandleData = HMQueryHandleData(hComm);
633 if(!pHMHandleData) {
634 dprintf(("!ERROR!: Invalid handle -> aborting"));
635 return 0;
636 }
637
638 if(pDevData->fClosing) {
639 dprintf(("Cleaning up async comm thread"));
640 SetEvent(hEvent); //signal to CloseHandle that we're done
641 return 0;
642 }
643
644 DosSleep(TIMEOUT_COMM);
645 }
646 if(pDevData->fClosing) {
647 dprintf(("Cleaning up async comm thread"));
648 SetEvent(hEvent); //signal to CloseHandle that we're done
649 return 0;
650 }
651 else
652 if(pDevData->fCancelIo) {
653 pDevData->overlapped.Internal = 0;
654 pDevData->dwLastError = ERROR_OPERATION_ABORTED;
655 if(pDevData->lpfdwEvtMask) *pDevData->lpfdwEvtMask = 0;
656 dprintf(("Overlapped: WaitCommEvent ERROR_OPERATION_ABORTED"));
657
658 //signal to app that a comm event has occurred
659 SetEvent(hOverlappedEvent);
660 }
661 else
662 if((dwEvent & dwMask) && (dwMask == pDevData->dwEventMask)) {
663 pDevData->overlapped.Internal |= (rc==0) ? (dwEvent & dwMask) : 0;
664 pDevData->dwLastError = rc;
665
666 //We're also supposed to write the result to the address supplied
667 //by the call to WaitCommEvent
668 if(pDevData->lpfdwEvtMask) *pDevData->lpfdwEvtMask = (rc==0) ? (dwEvent & dwMask) : 0;
669 dprintf(("Overlapped: WaitCommEvent returned %x", pDevData->overlapped.Internal));
670
671 //signal to app that a comm event has occurred
672 SetEvent(hOverlappedEvent);
673 }
674 }
675 return 0;
676}
677//******************************************************************************
678//******************************************************************************
679BOOL HMDeviceCommClass::WaitCommEvent( PHMHANDLEDATA pHMHandleData,
680 LPDWORD lpfdwEvtMask,
681 LPOVERLAPPED lpo)
682{
683 APIRET rc;
684 ULONG ulLen;
685 USHORT COMEvt;
686 DWORD dwEvent,dwMask;
687
688 PHMDEVCOMDATA pDevData = (PHMDEVCOMDATA)pHMHandleData->lpHandlerData;
689
690 dprintf(("HMDeviceCommClass::WaitCommEvent %x %x %x", pHMHandleData->hHMHandle, lpfdwEvtMask, lpo));
691
692 if((pHMHandleData->dwFlags & FILE_FLAG_OVERLAPPED) && !lpo) {
693 dprintf(("!WARNING! pHMHandleData->dwFlags & FILE_FLAG_OVERLAPPED) && !lpo"));
694 ::SetLastError(ERROR_INVALID_PARAMETER);
695 return FALSE;
696 }
697
698 ulLen = sizeof(CHAR);
699
700 dwEvent = 0;
701 rc = 0;
702 ulLen = sizeof(COMEvt);
703 dwMask = pDevData->dwEventMask;
704 while( (0==rc) &&
705 !(dwEvent & dwMask) &&
706 (dwMask ==pDevData->dwEventMask) ) // Exit if the Mask gets changed
707 {
708 rc = OSLibDosDevIOCtl(pHMHandleData->hHMHandle,
709 IOCTL_ASYNC,
710 ASYNC_GETCOMMEVENT,
711 0,0,0,
712 &COMEvt,ulLen,&ulLen);
713 if(!rc)
714 {
715 dwEvent |= (COMEvt&0x0001)? EV_RXCHAR:0;
716 //dwEvent |= (COMEvt&0x0002)? 0:0;
717 dwEvent |= (COMEvt&0x0004)? EV_TXEMPTY:0;
718 dwEvent |= (COMEvt&0x0008)? EV_CTS:0;
719 dwEvent |= (COMEvt&0x0010)? EV_DSR:0;
720 //dwEvent |= (COMEvt&0x0020)? 0:0; DCS = RLSD?
721 dwEvent |= (COMEvt&0x0040)? EV_BREAK:0;
722 dwEvent |= (COMEvt&0x0080)? EV_ERR:0;
723 dwEvent |= (COMEvt&0x0100)? EV_RING:0;
724 if((dwEvent & dwMask)) break;
725 }
726 else break;
727
728 if(pHMHandleData->dwFlags & FILE_FLAG_OVERLAPPED)
729 {
730 memcpy(&pDevData->overlapped, lpo, sizeof(pDevData->overlapped));
731 pDevData->overlapped.Internal = 0;
732 pDevData->overlapped.InternalHigh = 0;
733 pDevData->overlapped.Offset = 0;
734 pDevData->overlapped.OffsetHigh = 0;
735 //We're also supposed to write the result to the address supplied
736 //by this call
737 pDevData->lpfdwEvtMask = lpfdwEvtMask;
738 //Set app event semaphore to non-signalled state
739 ::ResetEvent(lpo->hEvent);
740
741 //signal async comm thread to start polling comm status
742 ::SetEvent(pDevData->hEventSem);
743 ::SetLastError(ERROR_IO_PENDING);
744 return FALSE;
745 }
746 DosSleep(TIMEOUT_COMM);
747 }
748 if(dwMask == pDevData->dwEventMask) {
749 *lpfdwEvtMask = (rc==0) ? (dwEvent & dwMask) : 0;
750 dprintf(("WaitCommEvent returned %x", *lpfdwEvtMask));
751 }
752 else *lpfdwEvtMask = 0;
753
754 ::SetLastError(rc);
755 return (rc==0);
756}
757/*****************************************************************************
758 * Name : DWORD HMDeviceCommClass::CancelIo
759 * Purpose : cancel pending IO operation
760 * Variables :
761 * Result :
762 * Remark :
763 * Status :
764 *
765 * Author : SvL
766 *****************************************************************************/
767BOOL HMDeviceCommClass::CancelIo(PHMHANDLEDATA pHMHandleData)
768{
769 PHMDEVCOMDATA pDevData = (PHMDEVCOMDATA)pHMHandleData->lpHandlerData;
770
771 dprintf(("HMDeviceCommClass::CancelIo"));
772 if(pDevData == NULL || !(pHMHandleData->dwFlags & FILE_FLAG_OVERLAPPED)) {
773 ::SetLastError(ERROR_ACCESS_DENIED); //todo: wrong error?
774 return FALSE;
775 }
776
777 //signal serial thread to cancel pending IO operation
778 pDevData->fCancelIo = TRUE;
779 ::SetEvent(pDevData->hEventSem);
780
781 ::SetLastError(ERROR_SUCCESS);
782 return(TRUE);
783}
784/*****************************************************************************
785 * Name : DWORD HMDeviceFileClass::GetOverlappedResult
786 * Purpose : asynchronus I/O
787 * Parameters: PHMHANDLEDATA pHMHandleData
788 * LPOVERLAPPED arg2
789 * LPDWORD arg3
790 * BOOL arg4
791 * Variables :
792 * Result : API returncode
793 * Remark :
794 * Status :
795 *
796 * Author : SvL
797 *****************************************************************************/
798BOOL HMDeviceCommClass::GetOverlappedResult(PHMHANDLEDATA pHMHandleData,
799 LPOVERLAPPED lpoOverlapped,
800 LPDWORD lpcbTransfer,
801 BOOL fWait)
802{
803 PHMDEVCOMDATA pDevData = (PHMDEVCOMDATA)pHMHandleData->lpHandlerData;
804
805 dprintf(("KERNEL32-WARNING: HMDeviceCommClass::GetOverlappedResult(%08xh,%08xh,%08xh,%08xh) partly implemented",
806 pHMHandleData->hHMHandle,
807 lpoOverlapped,
808 lpcbTransfer,
809 fWait));
810
811 if(pDevData == NULL || !(pHMHandleData->dwFlags & FILE_FLAG_OVERLAPPED)) {
812 ::SetLastError(ERROR_ACCESS_DENIED); //todo: wrong error?
813 return FALSE;
814 }
815 if(!lpoOverlapped) {
816 ::SetLastError(ERROR_INVALID_PARAMETER);
817 return FALSE;
818 }
819 if(lpoOverlapped->hEvent != pDevData->overlapped.hEvent) {
820 dprintf(("!WARNING!: GetOverlappedResult called for unknown operation"));
821 ::SetLastError(ERROR_ACCESS_DENIED); //todo: wrong error?
822 return FALSE;
823 }
824 if(pDevData->overlapped.Internal) {
825 lpoOverlapped->Internal = pDevData->overlapped.Internal;
826 pDevData->overlapped.Internal = 0; //not entirely safe
827 pDevData->dwLastError = 0;
828 ::SetLastError(pDevData->dwLastError);
829 return lpoOverlapped->Internal;
830 }
831 if(fWait) {
832 ::WaitForSingleObject(pDevData->overlapped.hEvent, INFINITE);
833 ::ResetEvent(pDevData->overlapped.hEvent);
834 lpoOverlapped->Internal = pDevData->overlapped.Internal;
835 pDevData->overlapped.Internal = 0; //not entirely safe
836 ::SetLastError(ERROR_SUCCESS);
837 return lpoOverlapped->Internal;
838 }
839 else {
840 ::SetLastError(ERROR_IO_PENDING);
841 return FALSE;
842 }
843}
844//******************************************************************************
845//******************************************************************************
846BOOL HMDeviceCommClass::GetCommProperties( PHMHANDLEDATA pHMHandleData,
847 LPCOMMPROP lpcmmp)
848{
849 EXTBAUDGET BaudInfo;
850 APIRET rc;
851 ULONG ulLen;
852 USHORT COMErr;
853 int i;
854 dprintf(("HMDeviceCommClass::GetCommProperties"));
855
856 ulLen = sizeof(EXTBAUDGET);
857 rc = OSLibDosDevIOCtl( pHMHandleData->hHMHandle,
858 IOCTL_ASYNC,
859 ASYNC_EXTGETBAUDRATE,
860 0,0,0,
861 &BaudInfo,ulLen,&ulLen);
862 memset(lpcmmp,0,sizeof(COMMPROP));
863 lpcmmp->wPacketLength = sizeof(COMMPROP);
864 lpcmmp->wPacketVersion = 1; //???
865 lpcmmp->dwServiceMask = SP_SERIALCOMM;
866 for(i=0;i<BaudTableSize && BaudInfo.ulMaxBaud <= BaudTable[i].dwBaudRate;i++);
867 lpcmmp->dwMaxBaud = BaudTable[i].dwBaudFlag;
868 lpcmmp->dwProvSubType = PST_RS232;
869 lpcmmp->dwProvCapabilities = PCF_DTRDSR | PCF_PARITY_CHECK |
870 PCF_RTSCTS | PCF_SETXCHAR |
871 PCF_XONXOFF;
872 lpcmmp->dwSettableParams = SP_BAUD | SP_DATABITS |
873 SP_HANDSHAKEING | SP_PARITY |
874 SP_PARITY_CHECK | SP_STOPBIT;
875 lpcmmp->dwSettableBaud = 0;
876 for(i=0;i<BaudTableSize;i++)
877 {
878 if ( (BaudTable[i].dwBaudRate>=BaudInfo.ulMinBaud) &&
879 (BaudTable[i].dwBaudRate<=BaudInfo.ulMaxBaud) )
880 lpcmmp->dwSettableBaud |= BaudTable[i].dwBaudFlag;
881 }
882 lpcmmp->dwSettableBaud |= BAUD_USER;
883 lpcmmp->wSettableData = DATABITS_5 | DATABITS_6 | DATABITS_7 | DATABITS_8;
884 lpcmmp->wSettableStopParity = STOPBITS_10 | STOPBITS_15 | STOPBITS_20 |
885 PARITY_NONE | PARITY_ODD | PARITY_EVEN |
886 PARITY_MARK | PARITY_SPACE;
887 return(rc==0);
888}
889//******************************************************************************
890//******************************************************************************
891BOOL HMDeviceCommClass::GetCommMask( PHMHANDLEDATA pHMHandleData,
892 LPDWORD lpfdwEvtMask)
893{
894 PHMDEVCOMDATA pDevData = (PHMDEVCOMDATA)pHMHandleData->lpHandlerData;
895
896 dprintf(("HMDeviceCommClass::GetCommMask"));
897
898 *lpfdwEvtMask = pDevData->dwEventMask;
899 return(TRUE);
900}
901//******************************************************************************
902//******************************************************************************
903BOOL HMDeviceCommClass::SetCommMask( PHMHANDLEDATA pHMHandleData,
904 DWORD fdwEvtMask)
905{
906 PHMDEVCOMDATA pDevData = (PHMDEVCOMDATA)pHMHandleData->lpHandlerData;
907 dprintf(("HMDeviceCommClass::SetCommMask %x", fdwEvtMask));
908
909 if(fdwEvtMask & (EV_RLSD|EV_RXFLAG)) {
910 dprintf(("!WARNING! SetCommMask: unsupported flags EV_RLSD and/or EV_RXFLAG!!"));
911 }
912
913 pDevData->dwEventMask = fdwEvtMask & ~(EV_RLSD|EV_RXFLAG); // Clear the 2 not supported Flags.
914 return(TRUE);
915}
916//******************************************************************************
917//******************************************************************************
918BOOL HMDeviceCommClass::PurgeComm( PHMHANDLEDATA pHMHandleData,
919 DWORD fdwAction)
920{
921 ULONG ulParLen, ulDataLen, rc = ERROR_SUCCESS;
922 BYTE par = 0;
923 WORD data = 0;
924
925 dprintf(("HMDeviceCommClass::PurgeComm (flags 0x%x) partly implemented",fdwAction));
926 // ToDo: find a way to stop the current transmision didn't find
927 // any clue how to in Control Program Guide and reference
928
929 ulParLen = sizeof(par);
930 ulDataLen = sizeof(data);
931 if(fdwAction & PURGE_TXCLEAR) {
932 rc = OSLibDosDevIOCtl( pHMHandleData->hHMHandle,
933 IOCTL_GENERAL,
934 DEV_FLUSHOUTPUT,
935 &par,ulParLen,&ulParLen,
936 &data,ulDataLen,&ulDataLen);
937 }
938 if(fdwAction & PURGE_RXCLEAR) {
939 rc = OSLibDosDevIOCtl( pHMHandleData->hHMHandle,
940 IOCTL_GENERAL,
941 DEV_FLUSHINPUT,
942 &par,ulParLen,&ulParLen,
943 &data,ulDataLen,&ulDataLen);
944 }
945 if(rc) {
946 dprintf(("!WARNING! OSLibDosDevIOCtl failed with rc %d", rc));
947 }
948 return (rc == ERROR_SUCCESS);
949}
950//******************************************************************************
951//******************************************************************************
952BOOL HMDeviceCommClass::ClearCommError( PHMHANDLEDATA pHMHandleData,
953 LPDWORD lpdwErrors,
954 LPCOMSTAT lpcst)
955{
956 APIRET rc;
957 ULONG ulLen;
958 USHORT COMErr;
959
960 dprintf(("HMDeviceCommClass::ClearCommError"));
961 ulLen = sizeof(USHORT);
962
963 rc = OSLibDosDevIOCtl( pHMHandleData->hHMHandle,
964 IOCTL_ASYNC,
965 ASYNC_GETCOMMERROR,
966 0,0,0,
967 &COMErr,2,&ulLen);
968 *lpdwErrors = 0;
969 *lpdwErrors |= (COMErr & 0x0001)?CE_OVERRUN:0;
970 *lpdwErrors |= (COMErr & 0x0002)?CE_RXOVER:0;
971 *lpdwErrors |= (COMErr & 0x0004)?CE_RXPARITY:0;
972 *lpdwErrors |= (COMErr & 0x0008)?CE_FRAME:0;
973
974 if(lpcst)
975 {
976 UCHAR ucStatus;
977 RXQUEUE qInfo;
978 ulLen = 1;
979 rc = OSLibDosDevIOCtl( pHMHandleData->hHMHandle,
980 IOCTL_ASYNC,
981 ASYNC_GETCOMMSTATUS,
982 0,0,0,
983 &ucStatus,ulLen,&ulLen);
984 if(!rc)
985 {
986 lpcst->fCtsHold = ((ucStatus & 0x01)>0);
987 lpcst->fDsrHold = ((ucStatus & 0x02)>0);
988 lpcst->fRlsdHold = FALSE;//(ucStatus & 0x04)>0);
989 lpcst->fXoffHold = ((ucStatus & 0x08)>0);
990 lpcst->fXoffSend = ((ucStatus & 0x10)>0);
991 lpcst->fEof = ((ucStatus & 0x20)>0);// Is break = Eof ??
992 lpcst->fTxim = ((ucStatus & 0x40)>0);
993
994 ulLen = sizeof(qInfo);
995 rc = OSLibDosDevIOCtl( pHMHandleData->hHMHandle,
996 IOCTL_ASYNC,
997 ASYNC_GETINQUECOUNT,
998 0,0,0,
999 &qInfo,ulLen,&ulLen);
1000 if(!rc)
1001 {
1002 lpcst->cbInQue = qInfo.cch;
1003 rc = OSLibDosDevIOCtl( pHMHandleData->hHMHandle,
1004 IOCTL_ASYNC,
1005 ASYNC_GETOUTQUECOUNT,
1006 0,0,0,
1007 &qInfo,ulLen,&ulLen);
1008 if(!rc)
1009 lpcst->cbOutQue = qInfo.cch;
1010 }
1011 }
1012 }
1013
1014 return(rc==0);
1015}
1016//******************************************************************************
1017//******************************************************************************
1018BOOL HMDeviceCommClass::SetCommState( PHMHANDLEDATA pHMHandleData,
1019 LPDCB lpDCB)
1020{
1021 APIRET rc;
1022 PHMDEVCOMDATA pDevData = (PHMDEVCOMDATA)pHMHandleData->lpHandlerData;
1023 DCB *pCurDCB = &pDevData->CommCfg.dcb;
1024 dprintf(("HMDeviceCommClass::SetCommState"));
1025
1026 rc = 0;
1027 if(pCurDCB->BaudRate != lpDCB->BaudRate) {
1028 dprintf(("SetCommState: change baud rate from %d to %d", pCurDCB->BaudRate, lpDCB->BaudRate));
1029 rc = SetBaud( pHMHandleData,
1030 lpDCB->BaudRate);
1031 }
1032
1033 if(!rc)
1034 {
1035 if( (pCurDCB->ByteSize != lpDCB->ByteSize) ||
1036 (pCurDCB->Parity != lpDCB->Parity) ||
1037 (pCurDCB->StopBits != lpDCB->StopBits))
1038 {
1039 dprintf(("SetCommState: change line %d %d %d", lpDCB->ByteSize, lpDCB->Parity, lpDCB->StopBits));
1040 rc = SetLine( pHMHandleData,
1041 lpDCB->ByteSize,
1042 lpDCB->Parity,
1043 lpDCB->StopBits);
1044 }
1045 }
1046
1047 if(!rc)
1048 {
1049 if( (pCurDCB->fOutxCtsFlow != lpDCB->fOutxCtsFlow) ||
1050 (pCurDCB->fOutxDsrFlow != lpDCB->fOutxDsrFlow) ||
1051 (pCurDCB->fDtrControl != lpDCB->fDtrControl) ||
1052 (pCurDCB->fDsrSensitivity != lpDCB->fDsrSensitivity) ||
1053 (pCurDCB->fTXContinueOnXoff != lpDCB->fTXContinueOnXoff) ||
1054 (pCurDCB->fOutX != lpDCB->fOutX) ||
1055 (pCurDCB->fInX != lpDCB->fInX) ||
1056 (pCurDCB->fErrorChar != lpDCB->fErrorChar) ||
1057 (pCurDCB->fNull != lpDCB->fNull) ||
1058 (pCurDCB->fRtsControl != lpDCB->fRtsControl) ||
1059 (pCurDCB->fAbortOnError != lpDCB->fAbortOnError) ||
1060 (pCurDCB->XonChar != lpDCB->XonChar) ||
1061 (pCurDCB->XoffChar != lpDCB->XoffChar) ||
1062 (pCurDCB->ErrorChar != lpDCB->ErrorChar))
1063 {
1064 dprintf(("SetCommState: change flags cts %d dsr %d dtr %d dsr %d tx %d out %d in %d ferror %d null %d rts %d abort %d xon %d xoff %d error %d", lpDCB->fOutxCtsFlow, lpDCB->fOutxDsrFlow,lpDCB->fDtrControl,lpDCB->fDsrSensitivity,lpDCB->fDsrSensitivity,lpDCB->fTXContinueOnXoff,lpDCB->fOutX, lpDCB->fInX,lpDCB->fErrorChar,lpDCB->fNull,lpDCB->fRtsControl,lpDCB->fAbortOnError,lpDCB->XonChar,lpDCB->XoffChar,lpDCB->ErrorChar));
1065 SetOS2DCB( pHMHandleData,
1066 lpDCB->fOutxCtsFlow, lpDCB->fOutxDsrFlow,
1067 lpDCB->fDtrControl, lpDCB->fDsrSensitivity,
1068 lpDCB->fTXContinueOnXoff, lpDCB->fOutX,
1069 lpDCB->fInX, lpDCB->fErrorChar,
1070 lpDCB->fNull, lpDCB->fRtsControl,
1071 lpDCB->fAbortOnError, lpDCB->XonChar,
1072 lpDCB->XoffChar,lpDCB->ErrorChar);
1073 }
1074 }
1075
1076 return(rc==0);
1077}
1078//******************************************************************************
1079//******************************************************************************
1080BOOL HMDeviceCommClass::GetCommState( PHMHANDLEDATA pHMHandleData,
1081 LPDCB lpdcb)
1082{
1083 PHMDEVCOMDATA pDevData = (PHMDEVCOMDATA)pHMHandleData->lpHandlerData;
1084
1085 dprintf(("HMDeviceCommClass::GetCommState %x", lpdcb));
1086
1087 if(lpdcb == NULL) {
1088 ::SetLastError(ERROR_INVALID_PARAMETER);
1089 return FALSE;
1090 }
1091
1092 memcpy(lpdcb,&pDevData->CommCfg.dcb,sizeof(DCB));
1093 return(TRUE);
1094}
1095//******************************************************************************
1096//******************************************************************************
1097BOOL HMDeviceCommClass::GetCommModemStatus( PHMHANDLEDATA pHMHandleData,
1098 LPDWORD lpModemStat )
1099{
1100 APIRET rc;
1101 ULONG ulLen;
1102 USHORT COMErr;
1103 UCHAR ucStatus;
1104
1105 dprintf(("HMDeviceCommClass::GetCommModemStatus %x", lpModemStat));
1106 if(lpModemStat == NULL) {
1107 ::SetLastError(ERROR_INVALID_PARAMETER);
1108 return FALSE;
1109 }
1110
1111 ulLen = sizeof(CHAR);
1112
1113 ulLen = 1;
1114 *lpModemStat = 0;
1115
1116 rc = OSLibDosDevIOCtl( pHMHandleData->hHMHandle,
1117 IOCTL_ASYNC,
1118 ASYNC_GETMODEMINPUT,
1119 0,0,0,
1120 &ucStatus,ulLen,&ulLen);
1121 if(!rc)
1122 {
1123 *lpModemStat |= (ucStatus & 0x10)? MS_CTS_ON:0;
1124 *lpModemStat |= (ucStatus & 0x20)? MS_DSR_ON:0;
1125 *lpModemStat |= (ucStatus & 0x40)? MS_RING_ON:0;
1126 //*lpModemStat |= (ucStatus & 0x80)? MS_RSLD_ON:0;
1127 }
1128
1129 dprintf2(("HMDeviceCommClass::GetCommModemStatus -> %x rc=%d", *lpModemStat, rc));
1130 return(rc==0);
1131}
1132//******************************************************************************
1133//******************************************************************************
1134BOOL HMDeviceCommClass::GetCommTimeouts( PHMHANDLEDATA pHMHandleData,
1135 LPCOMMTIMEOUTS lpctmo)
1136{
1137 PHMDEVCOMDATA pDevData = (PHMDEVCOMDATA)pHMHandleData->lpHandlerData;
1138
1139 dprintf(("HMDeviceCommClass::GetCommTimeouts %x stub", lpctmo));
1140
1141 if(lpctmo == NULL) {
1142 ::SetLastError(ERROR_INVALID_PARAMETER);
1143 return FALSE;
1144 }
1145
1146 memcpy( lpctmo,
1147 &pDevData->CommTOuts,
1148 sizeof(COMMTIMEOUTS));
1149 return(TRUE);
1150}
1151//******************************************************************************
1152//******************************************************************************
1153BOOL HMDeviceCommClass::SetCommTimeouts( PHMHANDLEDATA pHMHandleData,
1154 LPCOMMTIMEOUTS lpctmo)
1155{
1156 PHMDEVCOMDATA pDevData = (PHMDEVCOMDATA)pHMHandleData->lpHandlerData;
1157 DCBINFO os2dcb;
1158 ULONG ulLen;
1159 APIRET rc;
1160 UCHAR fbTimeOut;
1161
1162 if(lpctmo == NULL) {
1163 dprintf(("!WARNING! HMDeviceCommClass::SetCommTimeouts %x -> invalid parameter", lpctmo));
1164 ::SetLastError(ERROR_INVALID_PARAMETER);
1165 return FALSE;
1166 }
1167
1168 dprintf(("HMDeviceCommClass::SetCommTimeouts\n"
1169 " ReadIntervalTimeout : 0x%x\n"
1170 " ReadTotalTimeoutMultiplier : %d\n"
1171 " ReadTotalTimeoutConstant : %d\n"
1172 " WriteTotalTimeoutMultiplier : %d\n"
1173 " WriteTotalTimeoutConstant : %d\n",
1174 lpctmo->ReadIntervalTimeout,
1175 lpctmo->ReadTotalTimeoutMultiplier,
1176 lpctmo->ReadTotalTimeoutConstant,
1177 lpctmo->WriteTotalTimeoutMultiplier,
1178 lpctmo->WriteTotalTimeoutConstant
1179 ));
1180
1181 memcpy( &pDevData->CommTOuts,
1182 lpctmo,
1183 sizeof(COMMTIMEOUTS));
1184
1185 memcpy(&os2dcb,&pDevData->dcbOS2,sizeof(DCBINFO));
1186
1187 fbTimeOut = 0x02;
1188 if(MAXDWORD==pDevData->CommTOuts.ReadIntervalTimeout)
1189 {
1190 if( (0==pDevData->CommTOuts.ReadTotalTimeoutMultiplier) &&
1191 (0==pDevData->CommTOuts.ReadTotalTimeoutConstant))
1192 fbTimeOut = 0x05;
1193 else
1194 fbTimeOut = 0x04;
1195 }
1196 else
1197 {
1198 DWORD dwTimeout;
1199 dwTimeout = pDevData->CommTOuts.ReadIntervalTimeout/10;
1200#if 0
1201 if(dwTimeout)
1202 dwTimeout--; // 0=10 ms unit is 10ms or .01s
1203#endif
1204 os2dcb.usWriteTimeout = 0x0000FFFF & dwTimeout;
1205 os2dcb.usReadTimeout = 0x0000FFFF & dwTimeout;
1206 }
1207 os2dcb.fbTimeOut = (os2dcb.fbTimeOut & 0xF9) | fbTimeOut;
1208
1209 dprintf((" New DCB:\n"
1210 " WriteTimeout : %d\n"
1211 " ReadTimeout : %d\n"
1212 " CtlHandshake : 0x%x\n"
1213 " FlowReplace : 0x%x\n"
1214 " Timeout : 0x%x\n"
1215 " Error replacement Char : 0x%x\n"
1216 " Break replacement Char : 0x%x\n"
1217 " XON Char : 0x%x\n"
1218 " XOFF Char : 0x%x\n",
1219 os2dcb.usWriteTimeout,
1220 os2dcb.usReadTimeout,
1221 os2dcb.fbCtlHndShake,
1222 os2dcb.fbFlowReplace,
1223 os2dcb.fbTimeOut,
1224 os2dcb.bErrorReplacementChar,
1225 os2dcb.bBreakReplacementChar,
1226 os2dcb.bXONChar,
1227 os2dcb.bXOFFChar));
1228
1229 ulLen = sizeof(DCBINFO);
1230 rc = OSLibDosDevIOCtl( pHMHandleData->hHMHandle,
1231 IOCTL_ASYNC,
1232 ASYNC_SETDCBINFO,
1233 &os2dcb,ulLen,&ulLen,
1234 NULL,0,NULL);
1235 dprintf(("IOCRL returned %d",rc));
1236 return(0==rc);
1237}
1238//******************************************************************************
1239//******************************************************************************
1240BOOL HMDeviceCommClass::TransmitCommChar( PHMHANDLEDATA pHMHandleData,
1241 CHAR cChar )
1242{
1243 APIRET rc;
1244 ULONG ulLen;
1245 USHORT COMErr;
1246
1247 dprintf(("HMDeviceCommClass::TransmitCommChar"));
1248 ulLen = sizeof(CHAR);
1249
1250 rc = OSLibDosDevIOCtl( pHMHandleData->hHMHandle,
1251 IOCTL_ASYNC,
1252 ASYNC_TRANSMITIMM,
1253 &cChar,ulLen,&ulLen,
1254 NULL,0,NULL);
1255
1256 return(rc==0);
1257}
1258//******************************************************************************
1259//******************************************************************************
1260BOOL HMDeviceCommClass::SetCommBreak( PHMHANDLEDATA pHMHandleData )
1261{
1262 APIRET rc;
1263 ULONG ulLen;
1264 USHORT COMErr;
1265
1266 dprintf(("HMDeviceCommClass::SetCommBreak"));
1267 ulLen = sizeof(USHORT);
1268
1269 rc = OSLibDosDevIOCtl( pHMHandleData->hHMHandle,
1270 IOCTL_ASYNC,
1271 ASYNC_SETBREAKON,
1272 0,0,0,
1273 &COMErr,2,&ulLen);
1274
1275 return(rc==0);
1276}
1277//******************************************************************************
1278//******************************************************************************
1279BOOL HMDeviceCommClass::ClearCommBreak( PHMHANDLEDATA pHMHandleData)
1280{
1281 APIRET rc;
1282 ULONG ulLen;
1283 USHORT COMErr;
1284
1285 dprintf(("HMDeviceCommClass::ClearCommBreak"));
1286 ulLen = sizeof(USHORT);
1287
1288 rc = OSLibDosDevIOCtl( pHMHandleData->hHMHandle,
1289 IOCTL_ASYNC,
1290 ASYNC_SETBREAKOFF,
1291 0,0,0,
1292 &COMErr,2,&ulLen);
1293
1294 return(rc==0);
1295}
1296//******************************************************************************
1297//******************************************************************************
1298BOOL HMDeviceCommClass::SetCommConfig( PHMHANDLEDATA pHMHandleData,
1299 LPCOMMCONFIG lpCC,
1300 DWORD dwSize )
1301{
1302 dprintf(("HMDeviceCommClass::SetCommConfig NOT IMPLEMENTED"));
1303
1304 return(TRUE);
1305}
1306//******************************************************************************
1307//******************************************************************************
1308BOOL HMDeviceCommClass::GetCommConfig( PHMHANDLEDATA pHMHandleData,
1309 LPCOMMCONFIG lpCC,
1310 LPDWORD lpdwSize )
1311{
1312 PHMDEVCOMDATA pDevData = (PHMDEVCOMDATA)pHMHandleData->lpHandlerData;
1313
1314 dprintf(("HMDeviceCommClass::GetCommConfig"));
1315
1316 if( O32_IsBadWritePtr(lpCC,sizeof(COMMCONFIG)) ||
1317 *lpdwSize< sizeof(COMMCONFIG) )
1318 {
1319 ::SetLastError(ERROR_INSUFFICIENT_BUFFER);
1320 *lpdwSize= sizeof(COMMCONFIG);
1321 return FALSE;
1322 }
1323
1324 if((NULL==pDevData) || (pDevData->ulMagic != MAGIC_COM) )
1325 {
1326 ::SetLastError(ERROR_INVALID_HANDLE);
1327 return FALSE;
1328 }
1329
1330 memcpy(lpCC,&pDevData->CommCfg,sizeof(COMMCONFIG));
1331 *lpdwSize = sizeof(COMMCONFIG);
1332 return(TRUE);
1333}
1334//******************************************************************************
1335//******************************************************************************
1336BOOL HMDeviceCommClass::EscapeCommFunction( PHMHANDLEDATA pHMHandleData,
1337 UINT dwFunc )
1338{
1339 APIRET rc;
1340 ULONG ulDLen,ulPLen;
1341 USHORT COMErr;
1342 MODEMSTATUS mdm;
1343
1344 dprintf(("HMDeviceCommClass::EscapeCommFunction %x", dwFunc));
1345
1346 ulDLen = sizeof(USHORT);
1347 ulPLen = sizeof(MODEMSTATUS);
1348 switch(dwFunc)
1349 {
1350 case CLRDTR:
1351 mdm.fbModemOn = 0x00;
1352 mdm.fbModemOff = 0XFE;
1353 rc = OSLibDosDevIOCtl( pHMHandleData->hHMHandle,
1354 IOCTL_ASYNC,
1355 ASYNC_SETMODEMCTRL,
1356 &mdm,ulPLen,&ulPLen,
1357 &COMErr,ulDLen,&ulDLen);
1358 dprintf(("CLRDTR rc = %d Comerror = 0x%x",rc,COMErr));
1359 rc = COMErr;
1360 if(rc==0)
1361 {
1362 BYTE bModem;
1363 ulDLen = sizeof(BYTE);
1364 rc = OSLibDosDevIOCtl( pHMHandleData->hHMHandle,
1365 IOCTL_ASYNC,
1366 ASYNC_GETMODEMOUTPUT,
1367 NULL,0,NULL,
1368 &bModem,ulDLen,&ulDLen);
1369 dprintf(("Check DTR rc = %d Flags = 0x%x",rc,bModem));
1370 rc = bModem & 0x01;
1371 }
1372 break;
1373 case CLRRTS:
1374 mdm.fbModemOn = 0x00;
1375 mdm.fbModemOff = 0XFD;
1376 rc = OSLibDosDevIOCtl( pHMHandleData->hHMHandle,
1377 IOCTL_ASYNC,
1378 ASYNC_SETMODEMCTRL,
1379 &mdm,ulPLen,&ulPLen,
1380 &COMErr,ulDLen,&ulDLen);
1381 dprintf(("CLRRTS: rc = %d, Comm error %x", rc, COMErr));
1382 break;
1383 case SETDTR:
1384 mdm.fbModemOn = 0x01;
1385 mdm.fbModemOff = 0XFF;
1386 rc = OSLibDosDevIOCtl( pHMHandleData->hHMHandle,
1387 IOCTL_ASYNC,
1388 ASYNC_SETMODEMCTRL,
1389 &mdm,ulPLen,&ulPLen,
1390 &COMErr,ulDLen,&ulDLen);
1391 dprintf(("SETDTR: rc = %d, Comm error %x", rc, COMErr));
1392 break;
1393 case SETRTS:
1394 mdm.fbModemOn = 0x02;
1395 mdm.fbModemOff = 0XFF;
1396 rc = OSLibDosDevIOCtl( pHMHandleData->hHMHandle,
1397 IOCTL_ASYNC,
1398 ASYNC_SETMODEMCTRL,
1399 &mdm,ulPLen,&ulPLen,
1400 &COMErr,ulDLen,&ulDLen);
1401 dprintf(("SETRTS: rc = %d, Comm error %x", rc, COMErr));
1402 break;
1403 case SETXOFF:
1404 rc = OSLibDosDevIOCtl( pHMHandleData->hHMHandle,
1405 IOCTL_ASYNC,
1406 ASYNC_STOPTRANSMIT,
1407 0,0,0,
1408 0,0,0);
1409 dprintf(("SETXOFF: rc = %d", rc));
1410 break;
1411 case SETXON:
1412 rc = OSLibDosDevIOCtl( pHMHandleData->hHMHandle,
1413 IOCTL_ASYNC,
1414 ASYNC_STARTTRANSMIT,
1415 0,0,0,
1416 0,0,0);
1417 dprintf(("SETXON: rc = %d", rc));
1418 break;
1419 default:
1420 dprintf(("!ERROR!: EscapeCommFunction: unknown function"));
1421 ::SetLastError(ERROR_INVALID_PARAMETER);
1422 return(FALSE);
1423 }
1424
1425 return(rc==0);
1426}
1427//******************************************************************************
1428//******************************************************************************
1429BOOL HMDeviceCommClass::SetDefaultCommConfig( PHMHANDLEDATA pHMHandleData,
1430 LPCOMMCONFIG lpCC,
1431 DWORD dwSize)
1432{
1433 PHMDEVCOMDATA pDevData = (PHMDEVCOMDATA)pHMHandleData->lpDeviceData;
1434 if((NULL==pDevData) || (pDevData->ulMagic != MAGIC_COM) )
1435 {
1436 ::SetLastError(ERROR_INVALID_HANDLE);
1437 return FALSE;
1438 }
1439
1440 dprintf(("SetDefaultCommConfig %x %d", lpCC, dwSize));
1441 memset(&pDevData->CommCfg,0, sizeof(COMMCONFIG));
1442 memcpy(&pDevData->CommCfg,lpCC,dwSize>sizeof(COMMCONFIG)?sizeof(COMMCONFIG):dwSize);
1443
1444 return(TRUE);
1445}
1446//******************************************************************************
1447//******************************************************************************
1448BOOL HMDeviceCommClass::GetDefaultCommConfig( PHMHANDLEDATA pHMHandleData,
1449 LPCOMMCONFIG lpCC,
1450 LPDWORD lpdwSize)
1451{
1452 PHMDEVCOMDATA pDevData = (PHMDEVCOMDATA)pHMHandleData->lpDeviceData;
1453
1454 if( O32_IsBadWritePtr(lpCC,sizeof(COMMCONFIG)) ||
1455 *lpdwSize< sizeof(COMMCONFIG) )
1456 {
1457 ::SetLastError(ERROR_INSUFFICIENT_BUFFER);
1458 *lpdwSize= sizeof(COMMCONFIG);
1459 return FALSE;
1460 }
1461
1462 if((NULL==pDevData) || (pDevData->ulMagic != MAGIC_COM) )
1463 {
1464 ::SetLastError(ERROR_INVALID_HANDLE);
1465 return FALSE;
1466 }
1467 dprintf(("GetDefaultCommConfig %x %x", lpCC, lpdwSize));
1468
1469 memcpy(lpCC,&pDevData->CommCfg,sizeof(COMMCONFIG));
1470 *lpdwSize = sizeof(COMMCONFIG);
1471 return(TRUE);
1472}
1473//******************************************************************************
1474//******************************************************************************
1475APIRET HMDeviceCommClass::SetLine( PHMHANDLEDATA pHMHandleData,
1476 UCHAR ucSize,
1477 UCHAR ucParity,
1478 UCHAR ucStop)
1479{
1480 APIRET rc;
1481 ULONG ulLen;
1482 PHMDEVCOMDATA pDevData = (PHMDEVCOMDATA)pHMHandleData->lpHandlerData;
1483 DCB *pCurDCB = &pDevData->CommCfg.dcb;
1484 struct
1485 {
1486 UCHAR ucSize;
1487 UCHAR ucParity;
1488 UCHAR ucStop;
1489 UCHAR ucPadding;
1490 }Param;
1491
1492 ulLen = 3;
1493 Param.ucSize = ucSize;
1494 Param.ucParity = ucParity;
1495 Param.ucStop = ucStop;
1496
1497 rc = OSLibDosDevIOCtl( pHMHandleData->hHMHandle,
1498 IOCTL_ASYNC,
1499 ASYNC_SETLINECTRL,
1500 &Param,ulLen,&ulLen,
1501 NULL,0,NULL);
1502
1503 if(0==rc)
1504 {
1505 pCurDCB->ByteSize = ucSize;
1506 pCurDCB->Parity = ucParity;
1507 pCurDCB->StopBits = ucStop;
1508 }
1509 else {
1510 dprintf(("!ERROR! SetLine: OSLibDosDevIOCtl failed with rc %d", rc));
1511 }
1512 return rc;
1513}
1514//******************************************************************************
1515//******************************************************************************
1516APIRET HMDeviceCommClass::SetOS2DCB( PHMHANDLEDATA pHMHandleData,
1517 BOOL fOutxCtsFlow, BOOL fOutxDsrFlow,
1518 UCHAR ucDtrControl, BOOL fDsrSensitivity,
1519 BOOL fTXContinueOnXoff, BOOL fOutX,
1520 BOOL fInX, BOOL fErrorChar,
1521 BOOL fNull, UCHAR ucRtsControl,
1522 BOOL fAbortOnError, BYTE XonChar,
1523 BYTE XoffChar,BYTE ErrorChar)
1524{
1525 APIRET rc;
1526 ULONG ulLen;
1527 DCBINFO os2dcb;
1528 UCHAR fbTimeOut;
1529 PHMDEVCOMDATA pDevData = (PHMDEVCOMDATA)pHMHandleData->lpHandlerData;
1530 DCB *pCurDCB = &pDevData->CommCfg.dcb;
1531
1532 memcpy(&os2dcb,&pDevData->dcbOS2,sizeof(DCBINFO));
1533 os2dcb.fbCtlHndShake = (ucDtrControl & 0x03) |
1534 (fOutxCtsFlow?0x08:0x00) |
1535 (fOutxDsrFlow?0x10:0x00) |
1536 // No DCD support in Win32 ?!
1537 (fDsrSensitivity?0x40:0x00);
1538 os2dcb.fbFlowReplace = (fOutX?0x01:0x00) |
1539 (fInX?0x02:0x00) |
1540 (fErrorChar?0x04:0x00)|
1541 (fNull?0x08:0x00)|
1542 (fTXContinueOnXoff?0x02:0x00)| // Not sure if thats the right flag to test
1543 (ucRtsControl<<6);
1544
1545 fbTimeOut = 0x02;
1546 if(MAXDWORD==pDevData->CommTOuts.ReadIntervalTimeout)
1547 {
1548 if( (0==pDevData->CommTOuts.ReadTotalTimeoutMultiplier) &&
1549 (0==pDevData->CommTOuts.ReadTotalTimeoutConstant))
1550 fbTimeOut = 0x05;
1551 else
1552 fbTimeOut = 0x04;
1553 }
1554 else
1555 {
1556 DWORD dwTimeout;
1557 dwTimeout = pDevData->CommTOuts.ReadIntervalTimeout/10;
1558 if(dwTimeout)
1559 dwTimeout--; // 0=10 ms unit is 10ms or .01s
1560 os2dcb.usWriteTimeout = 0x0000FFFF & dwTimeout;
1561 os2dcb.usReadTimeout = 0x0000FFFF & dwTimeout;
1562 }
1563 os2dcb.fbTimeOut = (os2dcb.fbTimeOut & 0xF9) | fbTimeOut;
1564 os2dcb.bErrorReplacementChar = ErrorChar;
1565 os2dcb.bXONChar = XonChar;
1566 os2dcb.bXOFFChar = XoffChar;
1567 ulLen = sizeof(DCBINFO);
1568 rc = OSLibDosDevIOCtl( pHMHandleData->hHMHandle,
1569 IOCTL_ASYNC,
1570 ASYNC_SETDCBINFO,
1571 &os2dcb,ulLen,&ulLen,
1572 NULL,0,NULL);
1573
1574 if(0==rc)
1575 {
1576 memcpy(&pDevData->dcbOS2,&os2dcb,sizeof(DCBINFO));
1577 pCurDCB->fOutxCtsFlow = fOutxCtsFlow;
1578 pCurDCB->fOutxDsrFlow = fOutxDsrFlow;
1579 pCurDCB->fDtrControl = ucDtrControl;
1580 pCurDCB->fDsrSensitivity = fDsrSensitivity;
1581 pCurDCB->fTXContinueOnXoff = fTXContinueOnXoff;
1582 pCurDCB->fOutX = fOutX;
1583 pCurDCB->fInX = fInX;
1584 pCurDCB->fErrorChar = fErrorChar;
1585 pCurDCB->fNull = fNull;
1586 pCurDCB->fRtsControl = ucRtsControl;
1587 pCurDCB->fAbortOnError = fAbortOnError;
1588 pCurDCB->XonChar = XonChar;
1589 pCurDCB->XoffChar = XoffChar;
1590 pCurDCB->ErrorChar = ErrorChar;
1591 }
1592
1593 return rc;
1594
1595}
1596//******************************************************************************
1597//******************************************************************************
1598APIRET HMDeviceCommClass::SetBaud( PHMHANDLEDATA pHMHandleData,
1599 DWORD dwNewBaud)
1600{
1601 APIRET rc;
1602 ULONG ulLen;
1603 EXTBAUDSET SetBaud;
1604 EXTBAUDGET GetBaud;
1605 PHMDEVCOMDATA pDevData = (PHMDEVCOMDATA)pHMHandleData->lpHandlerData;
1606
1607 ulLen = sizeof(SetBaud);
1608 SetBaud.ulBaud = dwNewBaud;
1609 SetBaud.ucFrac = 0;
1610 rc = OSLibDosDevIOCtl( pHMHandleData->hHMHandle,
1611 IOCTL_ASYNC,
1612 ASYNC_EXTSETBAUDRATE,
1613 &SetBaud,ulLen,&ulLen,
1614 NULL,0,NULL);
1615 if(0==rc)
1616 {
1617 ulLen = sizeof(GetBaud);
1618 rc = OSLibDosDevIOCtl( pHMHandleData->hHMHandle,
1619 IOCTL_ASYNC,
1620 ASYNC_EXTGETBAUDRATE,
1621 NULL,0,NULL,
1622 &GetBaud,ulLen,&ulLen);
1623 if(0==rc)
1624 {
1625 if(dwNewBaud != GetBaud.ulCurrBaud) {
1626 dprintf(("!WARNING! dwNewBaud (%d) != GetBaud.ulCurrBaud (%d)", dwNewBaud, GetBaud.ulCurrBaud));
1627 rc = 1; // ToDo set a proper Errorhandling
1628 }
1629 else
1630 {
1631 pDevData->CommCfg.dcb.BaudRate = dwNewBaud;
1632 }
1633 }
1634 else {
1635 dprintf(("!WARNING! SetBaud: (get) OSLibDosDevIOCtl failed with rc %d", rc));
1636 }
1637 }
1638 else {
1639 dprintf(("!WARNING! SetBaud: (set) OSLibDosDevIOCtl failed with rc %d", rc));
1640 }
1641 return rc;
1642}
1643//******************************************************************************
1644//******************************************************************************
1645
1646
Note: See TracBrowser for help on using the repository browser.