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

Last change on this file since 4924 was 4924, checked in by sandervl, 25 years ago

WriteFile/ReadFile bugfixes for COM

File size: 36.3 KB
Line 
1/* $Id: hmcomm.cpp,v 1.8 2001-01-10 20:38:51 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 *
10 */
11
12
13
14#include <os2win.h>
15#include <string.h>
16#include <handlemanager.h>
17#include <heapstring.h>
18#include "hmdevice.h"
19#include "hmcomm.h"
20#include "oslibdos.h"
21
22#define DBG_LOCALLOG DBG_hmcomm
23#include "dbglocal.h"
24
25#define MAGIC_COM 0x12abcd34
26
27#define IOCTL_ASYNC 0x01
28#define ASYNC_GETDCBINFO 0x73
29#define ASYNC_SETDCBINFO 0x53
30#define ASYNC_SETLINECTRL 0x42
31#define ASYNC_GETCOMMEVENT 0x72
32#define ASYNC_EXTGETBAUDRATE 0x63
33#define ASYNC_EXTSETBAUDRATE 0x43
34#define ASYNC_GETCOMMERROR 0x6D
35#define ASYNC_GETCOMMSTATUS 0x65
36#define ASYNC_GETINQUECOUNT 0x68
37#define ASYNC_GETOUTQUECOUNT 0x69
38#define ASYNC_GETMODEMINPUT 0x67
39#define ASYNC_TRANSMITIMM 0x44
40#define ASYNC_SETBREAKON 0x4B
41#define ASYNC_SETBREAKOFF 0x45
42#define ASYNC_SETMODEMCTRL 0x46
43#define ASYNC_STARTTRANSMIT 0x48
44#define ASYNC_STOPTRANSMIT 0x47
45
46
47
48#pragma pack(1)
49typedef struct _DCBINFO
50{
51 USHORT usWriteTimeout; /* Time period used for Write Timeout processing. */
52 USHORT usReadTimeout; /* Time period used for Read Timeout processing. */
53 BYTE fbCtlHndShake; /* HandShake Control flag. */
54 BYTE fbFlowReplace; /* Flow Control flag. */
55 BYTE fbTimeOut; /* Timeout flag. */
56 BYTE bErrorReplacementChar; /* Error Replacement Character. */
57 BYTE bBreakReplacementChar; /* Break Replacement Character. */
58 BYTE bXONChar; /* Character XON. */
59 BYTE bXOFFChar; /* Character XOFF. */
60} DCBINFO;
61typedef DCBINFO *PDCBINFO;
62
63
64typedef struct _RXQUEUE
65{
66 USHORT cch; /* Number of characters in the queue. */
67 USHORT cb; /* Size of receive/transmit queue. */
68} RXQUEUE;
69
70typedef RXQUEUE *PRXQUEUE;
71
72
73typedef struct _MODEMSTATUS
74{
75 BYTE fbModemOn; /* Modem Control Signals ON Mask. */
76 BYTE fbModemOff; /* Modem Control Signals OFF Mask. */
77} MODEMSTATUS;
78
79typedef MODEMSTATUS *PMODEMSTATUS;
80
81
82#pragma pack()
83
84
85
86
87
88typedef struct _HMDEVCOMDATA
89{
90 ULONG ulMagic;
91 // Win32 Device Control Block
92 COMMCONFIG CommCfg;
93 COMMTIMEOUTS CommTOuts;
94 DWORD dwInBuffer, dwOutBuffer;
95 DWORD dwEventMask;
96 //OS/2 Device Control Block
97 DCBINFO dcbOS2;
98} HMDEVCOMDATA, *PHMDEVCOMDATA;
99
100VOID *CreateDevData()
101{
102 PHMDEVCOMDATA pData;
103 pData = new HMDEVCOMDATA();
104 if(NULL!=pData)
105 {
106 memset(pData,0,sizeof(HMDEVCOMDATA));
107 pData->ulMagic = MAGIC_COM;
108 pData->CommCfg.dwSize = sizeof(COMMCONFIG);
109 pData->CommCfg.wVersion = 1;
110 pData->CommCfg.dwProviderSubType = PST_RS232;
111 pData->CommCfg.dcb.DCBlength = sizeof(DCB);
112 pData->CommCfg.dcb.BaudRate = CBR_1200;
113 pData->CommCfg.dcb.ByteSize = 8;
114 pData->CommCfg.dcb.Parity = NOPARITY;
115 pData->CommCfg.dcb.StopBits = ONESTOPBIT;
116 pData->dwInBuffer = 16;
117 pData->dwOutBuffer = 16;
118 }
119 return pData;
120}
121
122HMDeviceCommClass::HMDeviceCommClass(LPCSTR lpDeviceName) : HMDeviceHandler(lpDeviceName)
123{
124 VOID *pData;
125 dprintf(("HMDeviceCommClass: Register COM1 to COM8 with Handle Manager\n"));
126 pData = CreateDevData();
127 if(pData!= NULL)
128 HMDeviceRegisterEx("COM1", this, pData);
129}
130
131/*****************************************************************************
132 * Name : HMDeviceCommClass::FindDevice
133 * Purpose : Checks if lpDeviceName belongs to this device class
134 * Parameters: LPCSTR lpClassDevName
135 * LPCSTR lpDeviceName
136 * int namelength
137 * Variables :
138 * Result : checks if name is COMx or COMx: (x=1..8)
139 * Remark :
140 * Status :
141 *
142 * Author : SvL
143 *****************************************************************************/
144BOOL HMDeviceCommClass::FindDevice(LPCSTR lpClassDevName, LPCSTR lpDeviceName, int namelength)
145{
146 if(namelength > 5)
147 return FALSE; //can't be com name
148
149 //first 3 letters 'COM'?
150 if(lstrncmpiA(lpDeviceName, lpClassDevName, 3) != 0) {
151 return FALSE;
152 }
153
154 if(namelength == 5 && lpDeviceName[4] != ':') {
155 return FALSE;
156 }
157 switch(lpDeviceName[3]) {
158 case '1':
159 case '2':
160 case '3':
161 case '4':
162 case '5':
163 case '6':
164 case '7':
165 case '8':
166 return TRUE; //we support up to COM8
167 }
168 return FALSE;
169}
170
171DWORD HMDeviceCommClass::CreateFile(LPCSTR lpFileName,
172 PHMHANDLEDATA pHMHandleData,
173 PVOID lpSecurityAttributes,
174 PHMHANDLEDATA pHMHandleDataTemplate)
175{
176 char comname[6];
177
178 dprintf(("HMComm: Serial communication port %s open request\n", lpFileName));
179
180 if(strlen(lpFileName) > 5) {
181 return -1; //safety check (unnecessary..)
182 }
183 pHMHandleData->hHMHandle = 0;
184
185 strcpy(comname, lpFileName);
186 comname[4] = 0; //get rid of : (if present) (eg COM1:)
187
188 //AH: TODO parse Win32 security handles
189 OSLibDosDisableHardError(TRUE);
190 pHMHandleData->hHMHandle = OSLibDosOpen(comname,
191 OSLIB_ACCESS_READWRITE |
192 OSLIB_ACCESS_SHAREDENYREAD |
193 OSLIB_ACCESS_SHAREDENYWRITE);
194 OSLibDosDisableHardError(FALSE);
195 if (pHMHandleData->hHMHandle != 0)
196 {
197 ULONG ulLen;
198 APIRET rc;
199
200 pHMHandleData->lpHandlerData = new HMDEVCOMDATA();
201 // Init The handle instance with the default default device config
202 memcpy( pHMHandleData->lpHandlerData,
203 pHMHandleData->lpDeviceData,
204 sizeof(HMDEVCOMDATA));
205
206 ulLen = sizeof(DCBINFO);
207
208 rc = OSLibDosDevIOCtl( pHMHandleData->hHMHandle,
209 IOCTL_ASYNC,
210 ASYNC_GETDCBINFO,
211 0,0,0,
212 &((PHMDEVCOMDATA)pHMHandleData->lpHandlerData)->dcbOS2,ulLen,&ulLen);
213
214 if(rc)
215 {
216 return -1;
217 }
218 return 0;
219 }
220 else
221 return -1;
222}
223
224
225 /* this is a handler method for calls to CloseHandle() */
226DWORD HMDeviceCommClass::CloseHandle(PHMHANDLEDATA pHMHandleData)
227{
228 dprintf(("HMComm: Serial communication port close request\n"));
229 delete pHMHandleData->lpHandlerData;
230 return OSLibDosClose(pHMHandleData->hHMHandle);
231}
232
233/*****************************************************************************
234 * Name : DWORD HMDeviceHandler::SetupComm
235 * Purpose : set com port parameters (queue)
236 * Variables :
237 * Result :
238 * Remark :
239 * Status :
240 *
241 * Author : Achim Hasenmueller
242 *****************************************************************************/
243
244BOOL HMDeviceCommClass::SetupComm( PHMHANDLEDATA pHMHandleData,
245 DWORD dwInQueue,
246 DWORD dwOutQueue)
247{
248 dprintf(("HMDeviceCommClass::SetupComm "));
249 PHMDEVCOMDATA pDevData = (PHMDEVCOMDATA)pHMHandleData->lpHandlerData;
250 if((NULL==pDevData) || (pDevData->ulMagic != MAGIC_COM) )
251 {
252 SetLastError(ERROR_INVALID_HANDLE);
253 return FALSE;
254 }
255 pDevData->dwInBuffer = dwInQueue;
256 pDevData->dwOutBuffer = dwOutQueue;
257
258 return(TRUE);
259}
260
261BOOL HMDeviceCommClass::WaitCommEvent( PHMHANDLEDATA pHMHandleData,
262 LPDWORD lpfdwEvtMask,
263 LPOVERLAPPED lpo)
264{
265 APIRET rc;
266 ULONG ulLen;
267 USHORT COMEvt;
268 DWORD dwEvent,dwMask;
269
270 PHMDEVCOMDATA pDevData = (PHMDEVCOMDATA)pHMHandleData->lpHandlerData;
271
272 dprintf(("HMDeviceCommClass::WaitCommEvent"));
273 ulLen = sizeof(CHAR);
274
275 dwEvent = 0;
276 rc = 0;
277 ulLen = sizeof(COMEvt);
278 dwMask = pDevData->dwEventMask;
279 while( (0==rc) &&
280 !(dwEvent & dwMask) &&
281 (dwMask ==pDevData->dwEventMask) ) // Exit if the Mask gets changed
282 {
283 rc = OSLibDosDevIOCtl( pHMHandleData->hHMHandle,
284 IOCTL_ASYNC,
285 ASYNC_GETCOMMEVENT,
286 0,0,0,
287 &COMEvt,ulLen,&ulLen);
288 if(!rc)
289 {
290 dwEvent |= (COMEvt&0x0001)? EV_RXCHAR:0;
291 //dwEvent |= (COMEvt&0x0002)? 0:0;
292 dwEvent |= (COMEvt&0x0004)? EV_TXEMPTY:0;
293 dwEvent |= (COMEvt&0x0008)? EV_CTS:0;
294 dwEvent |= (COMEvt&0x0010)? EV_DSR:0;
295 //dwEvent |= (COMEvt&0x0020)? 0:0; DCS = RLSD?
296 dwEvent |= (COMEvt&0x0040)? EV_BREAK:0;
297 dwEvent |= (COMEvt&0x0080)? EV_ERR:0;
298 dwEvent |= (COMEvt&0x0100)? EV_RING:0;
299 }
300 DosSleep(100);
301 }
302 *lpfdwEvtMask = rc==0?dwEvent:0;
303 return(rc==0);
304}
305
306
307#pragma pack(1)
308typedef struct
309{
310 ULONG ulCurrBaud;
311 UCHAR ucCurrFrac;
312 ULONG ulMinBaud;
313 UCHAR ucMinFrac;
314 ULONG ulMaxBaud;
315 UCHAR ucMaxFrac;
316} EXTBAUDGET, *PEXTBAUDGET;
317
318typedef struct
319{
320 ULONG ulBaud;
321 UCHAR ucFrac;
322} EXTBAUDSET, *PEXTBAUDSET;
323#pragma pack()
324
325BAUDTABLEENTRY BaudTable[] =
326{
327 {75,BAUD_075},
328 {110,BAUD_110},
329 {134,BAUD_134_5},
330 {150,BAUD_150},
331 {300,BAUD_300},
332 {600,BAUD_600},
333 {1200,BAUD_1200},
334 {1800,BAUD_1800},
335 {2400,BAUD_2400},
336 {4800,BAUD_4800},
337 {7200,BAUD_7200},
338 {9600,BAUD_9600},
339 {14400,BAUD_14400},
340 {19200,BAUD_19200},
341 {38400,BAUD_38400},
342 {56000,BAUD_56K},
343 {57600,BAUD_57600},
344 {115200,BAUD_115200},
345 {128000,BAUD_128K}
346};
347
348#define BaudTableSize (sizeof(BaudTable)/sizeof(BAUDTABLEENTRY))
349
350BOOL HMDeviceCommClass::GetCommProperties( PHMHANDLEDATA pHMHandleData,
351 LPCOMMPROP lpcmmp)
352{
353 EXTBAUDGET BaudInfo;
354 APIRET rc;
355 ULONG ulLen;
356 USHORT COMErr;
357 int i;
358 dprintf(("HMDeviceCommClass::GetCommProperties"));
359
360 ulLen = sizeof(EXTBAUDGET);
361 rc = OSLibDosDevIOCtl( pHMHandleData->hHMHandle,
362 IOCTL_ASYNC,
363 ASYNC_EXTGETBAUDRATE,
364 0,0,0,
365 &BaudInfo,ulLen,&ulLen);
366 memset(lpcmmp,0,sizeof(COMMPROP));
367 lpcmmp->wPacketLength = sizeof(COMMPROP);
368 lpcmmp->wPacketVersion = 1; //???
369 lpcmmp->dwServiceMask = SP_SERIALCOMM;
370 for(i=0;i<BaudTableSize && BaudInfo.ulMaxBaud <= BaudTable[i].dwBaudRate;i++);
371 lpcmmp->dwMaxBaud = BaudTable[i].dwBaudFlag;
372 lpcmmp->dwProvSubType = PST_RS232;
373 lpcmmp->dwProvCapabilities = PCF_DTRDSR | PCF_PARITY_CHECK |
374 PCF_RTSCTS | PCF_SETXCHAR |
375 PCF_XONXOFF;
376 lpcmmp->dwSettableParams = SP_BAUD | SP_DATABITS |
377 SP_HANDSHAKEING | SP_PARITY |
378 SP_PARITY_CHECK | SP_STOPBIT;
379 lpcmmp->dwSettableBaud = 0;
380 for(i=0;i<BaudTableSize;i++)
381 {
382 if ( (BaudTable[i].dwBaudRate>=BaudInfo.ulMinBaud) &&
383 (BaudTable[i].dwBaudRate<=BaudInfo.ulMaxBaud) )
384 lpcmmp->dwSettableBaud |= BaudTable[i].dwBaudFlag;
385 }
386 lpcmmp->dwSettableBaud |= BAUD_USER;
387 lpcmmp->wSettableData = DATABITS_5 | DATABITS_6 | DATABITS_7 | DATABITS_8;
388 lpcmmp->wSettableStopParity = STOPBITS_10 | STOPBITS_15 | STOPBITS_20 |
389 PARITY_NONE | PARITY_ODD | PARITY_EVEN |
390 PARITY_MARK | PARITY_SPACE;
391 return(rc==0);
392}
393
394BOOL HMDeviceCommClass::GetCommMask( PHMHANDLEDATA pHMHandleData,
395 LPDWORD lpfdwEvtMask)
396{
397 PHMDEVCOMDATA pDevData = (PHMDEVCOMDATA)pHMHandleData->lpHandlerData;
398
399 dprintf(("HMDeviceCommClass::GetCommMask"));
400
401 *lpfdwEvtMask = pDevData->dwEventMask;
402 return(TRUE);
403}
404
405BOOL HMDeviceCommClass::SetCommMask( PHMHANDLEDATA pHMHandleData,
406 DWORD fdwEvtMask)
407{
408 PHMDEVCOMDATA pDevData = (PHMDEVCOMDATA)pHMHandleData->lpHandlerData;
409 dprintf(("HMDeviceCommClass::SetCommMask"));
410
411 pDevData->dwEventMask = fdwEvtMask & ~(EV_RLSD|EV_RXFLAG); // Clear the 2 not supported Flags.
412 return(TRUE);
413}
414
415BOOL HMDeviceCommClass::PurgeComm( PHMHANDLEDATA pHMHandleData,
416 DWORD fdwAction)
417{
418 dprintf(("HMDeviceCommClass::PurgeComm unimplemented stub!"));
419 // ToDo: find a way to stop the current transmision didn't find
420 // any clue how to in Control Program Guide and reference
421
422 return(TRUE);
423}
424BOOL HMDeviceCommClass::ClearCommError( PHMHANDLEDATA pHMHandleData,
425 LPDWORD lpdwErrors,
426 LPCOMSTAT lpcst)
427{
428 APIRET rc;
429 ULONG ulLen;
430 USHORT COMErr;
431
432 dprintf(("HMDeviceCommClass::ClearCommError"));
433 ulLen = sizeof(USHORT);
434
435 rc = OSLibDosDevIOCtl( pHMHandleData->hHMHandle,
436 IOCTL_ASYNC,
437 ASYNC_GETCOMMERROR,
438 0,0,0,
439 &COMErr,2,&ulLen);
440 *lpdwErrors = 0;
441 *lpdwErrors |= (COMErr & 0x0001)?CE_OVERRUN:0;
442 *lpdwErrors |= (COMErr & 0x0002)?CE_RXOVER:0;
443 *lpdwErrors |= (COMErr & 0x0004)?CE_RXPARITY:0;
444 *lpdwErrors |= (COMErr & 0x0008)?CE_FRAME:0;
445
446 if(lpcst)
447 {
448 UCHAR ucStatus;
449 RXQUEUE qInfo;
450 ulLen = 1;
451 rc = OSLibDosDevIOCtl( pHMHandleData->hHMHandle,
452 IOCTL_ASYNC,
453 ASYNC_GETCOMMSTATUS,
454 0,0,0,
455 &ucStatus,ulLen,&ulLen);
456 if(!rc)
457 {
458 lpcst->fCtsHold = ((ucStatus & 0x01)>0);
459 lpcst->fDsrHold = ((ucStatus & 0x02)>0);
460 lpcst->fRlsdHold = FALSE;//(ucStatus & 0x04)>0);
461 lpcst->fXoffHold = ((ucStatus & 0x08)>0);
462 lpcst->fXoffSend = ((ucStatus & 0x10)>0);
463 lpcst->fEof = ((ucStatus & 0x20)>0);// Is break = Eof ??
464 lpcst->fTxim = ((ucStatus & 0x40)>0);
465
466 ulLen = sizeof(qInfo);
467 rc = OSLibDosDevIOCtl( pHMHandleData->hHMHandle,
468 IOCTL_ASYNC,
469 ASYNC_GETINQUECOUNT,
470 0,0,0,
471 &qInfo,ulLen,&ulLen);
472 if(!rc)
473 {
474 lpcst->cbInQue = qInfo.cch;
475 rc = OSLibDosDevIOCtl( pHMHandleData->hHMHandle,
476 IOCTL_ASYNC,
477 ASYNC_GETOUTQUECOUNT,
478 0,0,0,
479 &qInfo,ulLen,&ulLen);
480 if(!rc)
481 lpcst->cbOutQue = qInfo.cch;
482 }
483 }
484 }
485
486 return(rc==0);
487}
488BOOL HMDeviceCommClass::SetCommState( PHMHANDLEDATA pHMHandleData,
489 LPDCB lpDCB)
490{
491 APIRET rc;
492 PHMDEVCOMDATA pDevData = (PHMDEVCOMDATA)pHMHandleData->lpHandlerData;
493 DCB *pCurDCB = &pDevData->CommCfg.dcb;
494 dprintf(("HMDeviceCommClass::SetCommState"));
495
496 rc = 0;
497 if(pCurDCB->BaudRate != lpDCB->BaudRate)
498 rc = SetBaud( pHMHandleData,
499 lpDCB->BaudRate);
500
501 if(!rc)
502 {
503 if( (pCurDCB->ByteSize != lpDCB->ByteSize) ||
504 (pCurDCB->Parity != lpDCB->Parity) ||
505 (pCurDCB->StopBits != lpDCB->StopBits))
506 rc = SetLine( pHMHandleData,
507 lpDCB->ByteSize,
508 lpDCB->Parity,
509 lpDCB->StopBits);
510 }
511
512 if(!rc)
513 {
514 if( (pCurDCB->fOutxCtsFlow != lpDCB->fOutxCtsFlow) ||
515 (pCurDCB->fOutxDsrFlow != lpDCB->fOutxDsrFlow) ||
516 (pCurDCB->fDtrControl != lpDCB->fDtrControl) ||
517 (pCurDCB->fDsrSensitivity != lpDCB->fDsrSensitivity) ||
518 (pCurDCB->fTXContinueOnXoff != lpDCB->fTXContinueOnXoff) ||
519 (pCurDCB->fOutX != lpDCB->fOutX) ||
520 (pCurDCB->fInX != lpDCB->fInX) ||
521 (pCurDCB->fErrorChar != lpDCB->fErrorChar) ||
522 (pCurDCB->fNull != lpDCB->fNull) ||
523 (pCurDCB->fRtsControl != lpDCB->fRtsControl) ||
524 (pCurDCB->fAbortOnError != lpDCB->fAbortOnError) ||
525 (pCurDCB->XonChar != lpDCB->XonChar) ||
526 (pCurDCB->XoffChar != lpDCB->XoffChar) ||
527 (pCurDCB->ErrorChar != lpDCB->ErrorChar))
528 SetOS2DCB( pHMHandleData,
529 lpDCB->fOutxCtsFlow, lpDCB->fOutxDsrFlow,
530 lpDCB->fDtrControl, lpDCB->fDsrSensitivity,
531 lpDCB->fTXContinueOnXoff, lpDCB->fOutX,
532 lpDCB->fInX, lpDCB->fErrorChar,
533 lpDCB->fNull, lpDCB->fRtsControl,
534 lpDCB->fAbortOnError, lpDCB->XonChar,
535 lpDCB->XoffChar,lpDCB->ErrorChar);
536 }
537
538 return(rc==0);
539}
540BOOL HMDeviceCommClass::GetCommState( PHMHANDLEDATA pHMHandleData,
541 LPDCB lpdcb)
542{
543 PHMDEVCOMDATA pDevData = (PHMDEVCOMDATA)pHMHandleData->lpHandlerData;
544
545 dprintf(("HMDeviceCommClass::GetCommState"));
546 memcpy(lpdcb,&pDevData->CommCfg.dcb,sizeof(DCB));
547
548 return(TRUE);
549}
550BOOL HMDeviceCommClass::GetCommModemStatus( PHMHANDLEDATA pHMHandleData,
551 LPDWORD lpModemStat )
552{
553 APIRET rc;
554 ULONG ulLen;
555 USHORT COMErr;
556 UCHAR ucStatus;
557
558 dprintf(("HMDeviceCommClass::TransmitCommChar partly implemented"));
559 ulLen = sizeof(CHAR);
560
561 ulLen = 1;
562 *lpModemStat = 0;
563
564 rc = OSLibDosDevIOCtl( pHMHandleData->hHMHandle,
565 IOCTL_ASYNC,
566 ASYNC_GETMODEMINPUT,
567 0,0,0,
568 &ucStatus,ulLen,&ulLen);
569 if(!rc)
570 {
571 *lpModemStat |= (ucStatus & 0x10)? MS_CTS_ON:0;
572 *lpModemStat |= (ucStatus & 0x20)? MS_DSR_ON:0;
573 *lpModemStat |= (ucStatus & 0x40)? MS_RING_ON:0;
574 //*lpModemStat |= (ucStatus & 0x80)? MS_RSLD_ON:0;
575 }
576
577 return(rc==0);
578}
579
580BOOL HMDeviceCommClass::GetCommTimeouts( PHMHANDLEDATA pHMHandleData,
581 LPCOMMTIMEOUTS lpctmo)
582{
583 PHMDEVCOMDATA pDevData = (PHMDEVCOMDATA)pHMHandleData->lpHandlerData;
584
585 dprintf(("HMDeviceCommClass::GetCommTimeouts stub"));
586 memcpy( lpctmo,
587 &pDevData->CommTOuts,
588 sizeof(COMMTIMEOUTS));
589 return(TRUE);
590}
591BOOL HMDeviceCommClass::SetCommTimeouts( PHMHANDLEDATA pHMHandleData,
592 LPCOMMTIMEOUTS lpctmo)
593{
594 PHMDEVCOMDATA pDevData = (PHMDEVCOMDATA)pHMHandleData->lpHandlerData;
595 DCBINFO os2dcb;
596 ULONG ulLen;
597 APIRET rc;
598
599 memcpy( &pDevData->CommTOuts,
600 lpctmo,
601 sizeof(COMMTIMEOUTS));
602
603 memcpy(&os2dcb,&pDevData->dcbOS2,sizeof(DCBINFO));
604
605 os2dcb.fbTimeOut = 0x01;
606 if(MAXDWORD==pDevData->CommTOuts.ReadIntervalTimeout)
607 {
608 if( (0==pDevData->CommTOuts.ReadTotalTimeoutMultiplier) &&
609 (0==pDevData->CommTOuts.ReadTotalTimeoutConstant))
610 os2dcb.fbTimeOut = 0x03;
611 else
612 os2dcb.fbTimeOut = 0x02;
613 }
614 else
615 {
616 DWORD dwTimeout;
617 dwTimeout = pDevData->CommTOuts.ReadIntervalTimeout/10;
618 if(dwTimeout)
619 dwTimeout--; // 0=10 ms unit is 10ms or .01s
620 os2dcb.usWriteTimeout = 0x0000FFFF & dwTimeout;
621 os2dcb.usReadTimeout = 0x0000FFFF & dwTimeout;
622 }
623 ulLen = sizeof(DCBINFO);
624 rc = OSLibDosDevIOCtl( pHMHandleData->hHMHandle,
625 IOCTL_ASYNC,
626 ASYNC_SETDCBINFO,
627 &os2dcb,ulLen,&ulLen,
628 NULL,0,NULL);
629
630 return(0==rc);
631}
632BOOL HMDeviceCommClass::TransmitCommChar( PHMHANDLEDATA pHMHandleData,
633 CHAR cChar )
634{
635 APIRET rc;
636 ULONG ulLen;
637 USHORT COMErr;
638
639 dprintf(("HMDeviceCommClass::TransmitCommChar"));
640 ulLen = sizeof(CHAR);
641
642 rc = OSLibDosDevIOCtl( pHMHandleData->hHMHandle,
643 IOCTL_ASYNC,
644 ASYNC_TRANSMITIMM,
645 &cChar,ulLen,&ulLen,
646 NULL,0,NULL);
647
648 return(rc==0);
649}
650
651/*****************************************************************************
652 * Name : BOOL HMDeviceCommClass::WriteFile
653 * Purpose : write data to handle / device
654 * Parameters: PHMHANDLEDATA pHMHandleData,
655 * LPCVOID lpBuffer,
656 * DWORD nNumberOfBytesToWrite,
657 * LPDWORD lpNumberOfBytesWritten,
658 * LPOVERLAPPED lpOverlapped
659 * Variables :
660 * Result : Boolean
661 * Remark :
662 * Status :
663 *
664 * Author : SvL
665 *****************************************************************************/
666
667BOOL HMDeviceCommClass::WriteFile(PHMHANDLEDATA pHMHandleData,
668 LPCVOID lpBuffer,
669 DWORD nNumberOfBytesToWrite,
670 LPDWORD lpNumberOfBytesWritten,
671 LPOVERLAPPED lpOverlapped)
672{
673 dprintf(("KERNEL32:HMDeviceCommClass::WriteFile %s(%08x,%08x,%08x,%08x,%08x)",
674 lpHMDeviceName,
675 pHMHandleData->hHMHandle,
676 lpBuffer,
677 nNumberOfBytesToWrite,
678 lpNumberOfBytesWritten,
679 lpOverlapped));
680
681 BOOL ret;
682 ULONG ulBytesWritten;
683
684 if((pHMHandleData->dwFlags & FILE_FLAG_OVERLAPPED) && !lpOverlapped) {
685 dprintf(("FILE_FLAG_OVERLAPPED flag set, but lpOverlapped NULL!!"));
686 SetLastError(ERROR_INVALID_PARAMETER);
687 return FALSE;
688 }
689 if(!(pHMHandleData->dwFlags & FILE_FLAG_OVERLAPPED) && lpOverlapped) {
690 dprintf(("Warning: lpOverlapped != NULL & !FILE_FLAG_OVERLAPPED; sync operation"));
691 }
692
693 ret = OSLibDosWrite(pHMHandleData->hHMHandle, (LPVOID)lpBuffer, nNumberOfBytesToWrite,
694 &ulBytesWritten);
695
696 if(lpNumberOfBytesWritten) {
697 *lpNumberOfBytesWritten = (ret) ? ulBytesWritten : 0;
698 }
699 if(ret == FALSE) {
700 dprintf(("ERROR: WriteFile failed with rc %d", GetLastError()));
701 }
702
703 return ret;
704}
705
706/*****************************************************************************
707 * Name : BOOL WriteFileEx
708 * Purpose : The WriteFileEx function writes data to a file. It is designed
709 * solely for asynchronous operation, unlike WriteFile, which is
710 * designed for both synchronous and asynchronous operation.
711 * WriteFileEx reports its completion status asynchronously,
712 * calling a specified completion routine when writing is completed
713 * and the calling thread is in an alertable wait state.
714 * Parameters: HANDLE hFile handle of file to write
715 * LPVOID lpBuffer address of buffer
716 * DWORD nNumberOfBytesToRead number of bytes to write
717 * LPOVERLAPPED lpOverlapped address of offset
718 * LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine address of completion routine
719 * Variables :
720 * Result : TRUE / FALSE
721 * Remark :
722 * Status : UNTESTED STUB
723 *
724 * Author : Patrick Haller [Mon, 1998/06/15 08:00]
725 *****************************************************************************/
726
727BOOL HMDeviceCommClass::WriteFileEx(PHMHANDLEDATA pHMHandleData,
728 LPVOID lpBuffer,
729 DWORD nNumberOfBytesToWrite,
730 LPOVERLAPPED lpOverlapped,
731 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
732{
733 dprintf(("ERROR: WriteFileEx %s (%08xh,%08xh,%08xh,%08xh,%08xh) not implemented.\n",
734 lpHMDeviceName,
735 pHMHandleData->hHMHandle,
736 lpBuffer,
737 nNumberOfBytesToWrite,
738 lpOverlapped,
739 lpCompletionRoutine));
740
741 SetLastError(ERROR_INVALID_FUNCTION);
742 return FALSE;
743}
744
745/*****************************************************************************
746 * Name : BOOL HMDeviceCommClass::ReadFile
747 * Purpose : read data from handle / device
748 * Parameters: PHMHANDLEDATA pHMHandleData,
749 * LPCVOID lpBuffer,
750 * DWORD nNumberOfBytesToRead,
751 * LPDWORD lpNumberOfBytesRead,
752 * LPOVERLAPPED lpOverlapped
753 * Variables :
754 * Result : Boolean
755 * Remark :
756 * Status :
757 *
758 * Author : SvL
759 *****************************************************************************/
760
761BOOL HMDeviceCommClass::ReadFile(PHMHANDLEDATA pHMHandleData,
762 LPCVOID lpBuffer,
763 DWORD nNumberOfBytesToRead,
764 LPDWORD lpNumberOfBytesRead,
765 LPOVERLAPPED lpOverlapped)
766{
767 dprintf(("KERNEL32:HMDeviceCommClass::ReadFile %s(%08x,%08x,%08x,%08x,%08x)",
768 lpHMDeviceName,
769 pHMHandleData->hHMHandle,
770 lpBuffer,
771 nNumberOfBytesToRead,
772 lpNumberOfBytesRead,
773 lpOverlapped));
774
775 BOOL ret;
776 ULONG ulBytesRead;
777
778 if((pHMHandleData->dwFlags & FILE_FLAG_OVERLAPPED) && !lpOverlapped) {
779 dprintf(("FILE_FLAG_OVERLAPPED flag set, but lpOverlapped NULL!!"));
780 SetLastError(ERROR_INVALID_PARAMETER);
781 return FALSE;
782 }
783 if(!(pHMHandleData->dwFlags & FILE_FLAG_OVERLAPPED) && lpOverlapped) {
784 dprintf(("Warning: lpOverlapped != NULL & !FILE_FLAG_OVERLAPPED; sync operation"));
785 }
786
787 ret = OSLibDosRead(pHMHandleData->hHMHandle, (LPVOID)lpBuffer, nNumberOfBytesToRead,
788 &ulBytesRead);
789
790 if(lpNumberOfBytesRead) {
791 *lpNumberOfBytesRead = (ret) ? ulBytesRead : 0;
792 }
793 if(ret == FALSE) {
794 dprintf(("ERROR: ReadFile failed with rc %d", GetLastError()));
795 }
796 return ret;
797}
798
799/*****************************************************************************
800 * Name : BOOL ReadFileEx
801 * Purpose : The ReadFileEx function reads data from a file asynchronously.
802 * It is designed solely for asynchronous operation, unlike the
803 * ReadFile function, which is designed for both synchronous and
804 * asynchronous operation. ReadFileEx lets an application perform
805 * other processing during a file read operation.
806 * The ReadFileEx function reports its completion status asynchronously,
807 * calling a specified completion routine when reading is completed
808 * and the calling thread is in an alertable wait state.
809 * Parameters: HANDLE hFile handle of file to read
810 * LPVOID lpBuffer address of buffer
811 * DWORD nNumberOfBytesToRead number of bytes to read
812 * LPOVERLAPPED lpOverlapped address of offset
813 * LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine address of completion routine
814 * Variables :
815 * Result : TRUE / FALSE
816 * Remark :
817 * Status : UNTESTED STUB
818 *
819 * Author : Patrick Haller [Mon, 1998/06/15 08:00]
820 *****************************************************************************/
821BOOL HMDeviceCommClass::ReadFileEx(PHMHANDLEDATA pHMHandleData,
822 LPVOID lpBuffer,
823 DWORD nNumberOfBytesToRead,
824 LPOVERLAPPED lpOverlapped,
825 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
826{
827 dprintf(("ERROR: ReadFileEx %s (%08xh,%08xh,%08xh,%08xh,%08xh) not implemented.\n",
828 lpHMDeviceName,
829 pHMHandleData->hHMHandle,
830 lpBuffer,
831 nNumberOfBytesToRead,
832 lpOverlapped,
833 lpCompletionRoutine));
834
835 SetLastError(ERROR_INVALID_FUNCTION);
836 return FALSE;
837}
838
839BOOL HMDeviceCommClass::SetCommBreak( PHMHANDLEDATA pHMHandleData )
840{
841 APIRET rc;
842 ULONG ulLen;
843 USHORT COMErr;
844
845 dprintf(("HMDeviceCommClass::SetCommBreak"));
846 ulLen = sizeof(USHORT);
847
848 rc = OSLibDosDevIOCtl( pHMHandleData->hHMHandle,
849 IOCTL_ASYNC,
850 ASYNC_SETBREAKON,
851 0,0,0,
852 &COMErr,2,&ulLen);
853
854 return(rc==0);
855}
856
857BOOL HMDeviceCommClass::ClearCommBreak( PHMHANDLEDATA pHMHandleData)
858{
859 APIRET rc;
860 ULONG ulLen;
861 USHORT COMErr;
862
863 dprintf(("HMDeviceCommClass::ClearCommBreak"));
864 ulLen = sizeof(USHORT);
865
866 rc = OSLibDosDevIOCtl( pHMHandleData->hHMHandle,
867 IOCTL_ASYNC,
868 ASYNC_SETBREAKOFF,
869 0,0,0,
870 &COMErr,2,&ulLen);
871
872 return(rc==0);
873}
874
875BOOL HMDeviceCommClass::SetCommConfig( PHMHANDLEDATA pHMHandleData,
876 LPCOMMCONFIG lpCC,
877 DWORD dwSize )
878{
879 dprintf(("HMDeviceCommClass::SetCommConfig"));
880
881
882 return(TRUE);
883}
884
885BOOL HMDeviceCommClass::GetCommConfig( PHMHANDLEDATA pHMHandleData,
886 LPCOMMCONFIG lpCC,
887 LPDWORD lpdwSize )
888{
889 PHMDEVCOMDATA pDevData = (PHMDEVCOMDATA)pHMHandleData->lpHandlerData;
890
891 dprintf(("HMDeviceCommClass::GetCommConfig"));
892
893 if( O32_IsBadWritePtr(lpCC,sizeof(COMMCONFIG)) ||
894 *lpdwSize< sizeof(COMMCONFIG) )
895 {
896 SetLastError(ERROR_INSUFFICIENT_BUFFER);
897 *lpdwSize= sizeof(COMMCONFIG);
898 return FALSE;
899 }
900
901 if((NULL==pDevData) || (pDevData->ulMagic != MAGIC_COM) )
902 {
903 SetLastError(ERROR_INVALID_HANDLE);
904 return FALSE;
905 }
906
907 memcpy(lpCC,&pDevData->CommCfg,sizeof(COMMCONFIG));
908 *lpdwSize = sizeof(COMMCONFIG);
909 return(TRUE);
910
911
912 return(TRUE);
913}
914
915BOOL HMDeviceCommClass::EscapeCommFunction( PHMHANDLEDATA pHMHandleData,
916 UINT dwFunc )
917{
918 APIRET rc;
919 ULONG ulDLen,ulPLen;
920 USHORT COMErr;
921 MODEMSTATUS mdm;
922
923 dprintf(("HMDeviceCommClass::EscapeCommFunction"));
924
925 ulDLen = sizeof(USHORT);
926 ulPLen = sizeof(MODEMSTATUS);
927 switch(dwFunc)
928 {
929 case CLRDTR:
930 mdm.fbModemOn = 0x00;
931 mdm.fbModemOff = 0XFE;
932 rc = OSLibDosDevIOCtl( pHMHandleData->hHMHandle,
933 IOCTL_ASYNC,
934 ASYNC_SETMODEMCTRL,
935 &mdm,ulPLen,&ulPLen,
936 &COMErr,ulDLen,&ulDLen);
937 break;
938 case CLRRTS:
939 mdm.fbModemOn = 0x00;
940 mdm.fbModemOff = 0XFD;
941 rc = OSLibDosDevIOCtl( pHMHandleData->hHMHandle,
942 IOCTL_ASYNC,
943 ASYNC_SETMODEMCTRL,
944 &mdm,ulPLen,&ulPLen,
945 &COMErr,ulDLen,&ulDLen);
946 break;
947 case SETDTR:
948 mdm.fbModemOn = 0x01;
949 mdm.fbModemOff = 0XFF;
950 rc = OSLibDosDevIOCtl( pHMHandleData->hHMHandle,
951 IOCTL_ASYNC,
952 ASYNC_SETMODEMCTRL,
953 &mdm,ulPLen,&ulPLen,
954 &COMErr,ulDLen,&ulDLen);
955 break;
956 case SETRTS:
957 mdm.fbModemOn = 0x02;
958 mdm.fbModemOff = 0XFF;
959 rc = OSLibDosDevIOCtl( pHMHandleData->hHMHandle,
960 IOCTL_ASYNC,
961 ASYNC_SETMODEMCTRL,
962 &mdm,ulPLen,&ulPLen,
963 &COMErr,ulDLen,&ulDLen);
964 break;
965 case SETXOFF:
966 rc = OSLibDosDevIOCtl( pHMHandleData->hHMHandle,
967 IOCTL_ASYNC,
968 ASYNC_STOPTRANSMIT,
969 0,0,0,
970 0,0,0);
971 break;
972 case SETXON:
973 rc = OSLibDosDevIOCtl( pHMHandleData->hHMHandle,
974 IOCTL_ASYNC,
975 ASYNC_STARTTRANSMIT,
976 0,0,0,
977 0,0,0);
978 break;
979 default:
980 SetLastError(ERROR_INVALID_PARAMETER);
981 return(FALSE);
982 }
983
984 return(rc==0);
985}
986
987BOOL HMDeviceCommClass::SetDefaultCommConfig( PHMHANDLEDATA pHMHandleData,
988 LPCOMMCONFIG lpCC,
989 DWORD dwSize)
990{
991 PHMDEVCOMDATA pDevData = (PHMDEVCOMDATA)pHMHandleData->lpDeviceData;
992 if((NULL==pDevData) || (pDevData->ulMagic != MAGIC_COM) )
993 {
994 SetLastError(ERROR_INVALID_HANDLE);
995 return FALSE;
996 }
997 memset(&pDevData->CommCfg,0, sizeof(COMMCONFIG));
998 memcpy(&pDevData->CommCfg,lpCC,dwSize>sizeof(COMMCONFIG)?sizeof(COMMCONFIG):dwSize);
999
1000 return(TRUE);
1001}
1002BOOL HMDeviceCommClass::GetDefaultCommConfig( PHMHANDLEDATA pHMHandleData,
1003 LPCOMMCONFIG lpCC,
1004 LPDWORD lpdwSize)
1005{
1006 PHMDEVCOMDATA pDevData = (PHMDEVCOMDATA)pHMHandleData->lpDeviceData;
1007
1008 if( O32_IsBadWritePtr(lpCC,sizeof(COMMCONFIG)) ||
1009 *lpdwSize< sizeof(COMMCONFIG) )
1010 {
1011 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1012 *lpdwSize= sizeof(COMMCONFIG);
1013 return FALSE;
1014 }
1015
1016 if((NULL==pDevData) || (pDevData->ulMagic != MAGIC_COM) )
1017 {
1018 SetLastError(ERROR_INVALID_HANDLE);
1019 return FALSE;
1020 }
1021
1022 memcpy(lpCC,&pDevData->CommCfg,sizeof(COMMCONFIG));
1023 *lpdwSize = sizeof(COMMCONFIG);
1024 return(TRUE);
1025}
1026APIRET HMDeviceCommClass::SetLine( PHMHANDLEDATA pHMHandleData,
1027 UCHAR ucSize,
1028 UCHAR ucParity,
1029 UCHAR ucStop)
1030{
1031 APIRET rc;
1032 ULONG ulLen;
1033 PHMDEVCOMDATA pDevData = (PHMDEVCOMDATA)pHMHandleData->lpHandlerData;
1034 DCB *pCurDCB = &pDevData->CommCfg.dcb;
1035 struct
1036 {
1037 UCHAR ucSize;
1038 UCHAR ucParity;
1039 UCHAR ucStop;
1040 UCHAR ucPadding;
1041 }Param;
1042
1043 ulLen = 3;
1044 Param.ucSize = ucSize;
1045 Param.ucParity = ucParity;
1046 Param.ucStop = ucStop;
1047
1048 rc = OSLibDosDevIOCtl( pHMHandleData->hHMHandle,
1049 IOCTL_ASYNC,
1050 ASYNC_SETLINECTRL,
1051 &Param,ulLen,&ulLen,
1052 NULL,0,NULL);
1053
1054 if(0==rc)
1055 {
1056 pCurDCB->ByteSize = ucSize;
1057 pCurDCB->Parity = ucParity;
1058 pCurDCB->StopBits = ucStop;
1059 }
1060
1061 return rc;
1062}
1063
1064APIRET HMDeviceCommClass::SetOS2DCB( PHMHANDLEDATA pHMHandleData,
1065 BOOL fOutxCtsFlow, BOOL fOutxDsrFlow,
1066 UCHAR ucDtrControl, BOOL fDsrSensitivity,
1067 BOOL fTXContinueOnXoff, BOOL fOutX,
1068 BOOL fInX, BOOL fErrorChar,
1069 BOOL fNull, UCHAR ucRtsControl,
1070 BOOL fAbortOnError, BYTE XonChar,
1071 BYTE XoffChar,BYTE ErrorChar)
1072{
1073 APIRET rc;
1074 ULONG ulLen;
1075 DCBINFO os2dcb;
1076
1077 PHMDEVCOMDATA pDevData = (PHMDEVCOMDATA)pHMHandleData->lpHandlerData;
1078 DCB *pCurDCB = &pDevData->CommCfg.dcb;
1079
1080 memcpy(&os2dcb,&pDevData->dcbOS2,sizeof(DCBINFO));
1081 os2dcb.fbCtlHndShake = (ucDtrControl & 0x03) |
1082 (fOutxCtsFlow?0x08:0x00) |
1083 (fOutxDsrFlow?0x10:0x00) |
1084 // No DCD support in Win32 ?!
1085 (fDsrSensitivity?0x40:0x00);
1086 os2dcb.fbFlowReplace = (fOutX?0x01:0x00) |
1087 (fInX?0x02:0x00) |
1088 (fErrorChar?0x04:0x00)|
1089 (fNull?0x08:0x00)|
1090 (fTXContinueOnXoff?0x02:0x00)| // Not sure if thats the right flag to test
1091 (ucRtsControl<<6);
1092
1093 os2dcb.fbTimeOut = 0x01;
1094 if(MAXDWORD==pDevData->CommTOuts.ReadIntervalTimeout)
1095 {
1096 if( (0==pDevData->CommTOuts.ReadTotalTimeoutMultiplier) &&
1097 (0==pDevData->CommTOuts.ReadTotalTimeoutConstant))
1098 os2dcb.fbTimeOut = 0x03;
1099 else
1100 os2dcb.fbTimeOut = 0x02;
1101 }
1102 else
1103 {
1104 DWORD dwTimeout;
1105 dwTimeout = pDevData->CommTOuts.ReadIntervalTimeout/10;
1106 if(dwTimeout)
1107 dwTimeout--; // 0=10 ms unit is 10ms or .01s
1108 os2dcb.usWriteTimeout = 0x0000FFFF & dwTimeout;
1109 os2dcb.usReadTimeout = 0x0000FFFF & dwTimeout;
1110 }
1111 os2dcb.bErrorReplacementChar = ErrorChar;
1112 os2dcb.bXONChar = XonChar;
1113 os2dcb.bXOFFChar = XoffChar;
1114 ulLen = sizeof(DCBINFO);
1115 rc = OSLibDosDevIOCtl( pHMHandleData->hHMHandle,
1116 IOCTL_ASYNC,
1117 ASYNC_SETDCBINFO,
1118 &os2dcb,ulLen,&ulLen,
1119 NULL,0,NULL);
1120
1121 if(0==rc)
1122 {
1123 memcpy(&pDevData->dcbOS2,&os2dcb,sizeof(DCBINFO));
1124 pCurDCB->fOutxCtsFlow = fOutxCtsFlow;
1125 pCurDCB->fOutxDsrFlow = fOutxDsrFlow;
1126 pCurDCB->fDtrControl = ucDtrControl;
1127 pCurDCB->fDsrSensitivity = fDsrSensitivity;
1128 pCurDCB->fTXContinueOnXoff = fTXContinueOnXoff;
1129 pCurDCB->fOutX = fOutX;
1130 pCurDCB->fInX = fInX;
1131 pCurDCB->fErrorChar = fErrorChar;
1132 pCurDCB->fNull = fNull;
1133 pCurDCB->fRtsControl = ucRtsControl;
1134 pCurDCB->fAbortOnError = fAbortOnError;
1135 pCurDCB->XonChar = XonChar;
1136 pCurDCB->XoffChar = XoffChar;
1137 pCurDCB->ErrorChar = ErrorChar;
1138 }
1139
1140 return rc;
1141
1142}
1143
1144APIRET HMDeviceCommClass::SetBaud( PHMHANDLEDATA pHMHandleData,
1145 DWORD dwNewBaud)
1146{
1147 APIRET rc;
1148 ULONG ulLen;
1149 EXTBAUDSET SetBaud;
1150 EXTBAUDGET GetBaud;
1151 ulLen = sizeof(SetBaud);
1152 SetBaud.ulBaud = dwNewBaud;
1153 rc = OSLibDosDevIOCtl( pHMHandleData->hHMHandle,
1154 IOCTL_ASYNC,
1155 ASYNC_EXTSETBAUDRATE,
1156 &SetBaud,ulLen,&ulLen,
1157 NULL,0,NULL);
1158 if(0==rc)
1159 {
1160 ulLen = sizeof(GetBaud);
1161 rc = OSLibDosDevIOCtl( pHMHandleData->hHMHandle,
1162 IOCTL_ASYNC,
1163 ASYNC_EXTGETBAUDRATE,
1164 NULL,0,NULL,
1165 &GetBaud,ulLen,&ulLen);
1166 if(0==rc)
1167 {
1168 if(dwNewBaud !=GetBaud.ulCurrBaud)
1169 rc = 1; // ToDo set a proper Errorhandling
1170 else
1171 {
1172 ((PHMDEVCOMDATA)pHMHandleData->lpDeviceData)->CommCfg.dcb.BaudRate = dwNewBaud;
1173 ((PHMDEVCOMDATA)pHMHandleData->lpDeviceData)->CommCfg.dcb.BaudRate = dwNewBaud;
1174 }
1175 }
1176 }
1177 return rc;
1178}
1179
Note: See TracBrowser for help on using the repository browser.