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

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

updates

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