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

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

implemented PurgeComm

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