1 /*
2 * DEC 93 Erik Bos <erik@xs4all.nl>
3 *
4 * Copyright 1996 Marcus Meissner
5 *
6 * Copyright 2001 Mike McCormack
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 *
22 * History:
23 *
24 * Mar 31, 1999. Ove Kåven <ovek@arcticnet.no>
25 * - Implemented buffers and EnableCommNotification.
26 *
27 * Apr 3, 1999. Lawson Whitney <lawson_whitney@juno.com>
28 * - Fixed the modem control part of EscapeCommFunction16.
29 *
30 * Mar 3, 1999. Ove Kåven <ovek@arcticnet.no>
31 * - Use port indices instead of unixfds for win16
32 * - Moved things around (separated win16 and win32 routines)
33 * - Added some hints on how to implement buffers and EnableCommNotification.
34 *
35 * May 26, 1997. Fixes and comments by Rick Richardson <rick@dgii.com> [RER]
36 * - ptr->fd wasn't getting cleared on close.
37 * - GetCommEventMask() and GetCommError() didn't do much of anything.
38 * IMHO, they are still wrong, but they at least implement the RXCHAR
39 * event and return I/O queue sizes, which makes the app I'm interested
40 * in (analog devices EZKIT DSP development system) work.
41 *
42 * August 12, 1997. Take a bash at SetCommEventMask - Lawson Whitney
43 * <lawson_whitney@juno.com>
44 * July 6, 1998. Fixes and comments by Valentijn Sessink
45 * <vsessink@ic.uva.nl> [V]
46 * Oktober 98, Rein Klazes [RHK]
47 * A program that wants to monitor the modem status line (RLSD/DCD) may
48 * poll the modem status register in the commMask structure. I update the bit
49 * in GetCommError, waiting for an implementation of communication events.
50 *
51 */
52
53 #include "config.h"
54 #include "wine/port.h"
55
56 #include <stdlib.h>
57 #include <stdarg.h>
58 #include <stdio.h>
59 #include <string.h>
60 #include <errno.h>
61 #include <ctype.h>
62
63 #include "windef.h"
64 #include "winbase.h"
65 #include "wine/winuser16.h"
66 #include "win.h"
67 #include "user_private.h"
68
69 #include "wine/debug.h"
70
71 WINE_DEFAULT_DEBUG_CHANNEL(comm);
72
73 /* window's semi documented modem status register */
74 #define COMM_MSR_OFFSET 35
75 #define MSR_CTS 0x10
76 #define MSR_DSR 0x20
77 #define MSR_RI 0x40
78 #define MSR_RLSD 0x80
79 #define MSR_MASK (MSR_CTS|MSR_DSR|MSR_RI|MSR_RLSD)
80
81 #define FLAG_LPT 0x80
82
83 #define MAX_PORTS 9
84
85 struct DosDeviceStruct {
86 HANDLE handle;
87 int suspended;
88 int unget,xmit;
89 int evtchar;
90 /* events */
91 int commerror, eventmask;
92 /* buffers */
93 char *inbuf,*outbuf;
94 unsigned ibuf_size,ibuf_head,ibuf_tail;
95 unsigned obuf_size,obuf_head,obuf_tail;
96 /* notifications */
97 HWND wnd;
98 int n_read, n_write;
99 OVERLAPPED read_ov, write_ov;
100 /* save terminal states */
101 DCB16 dcb;
102 /* pointer to unknown(==undocumented) comm structure */
103 SEGPTR seg_unknown;
104 BYTE unknown[40];
105 };
106
107 static struct DosDeviceStruct COM[MAX_PORTS];
108 static struct DosDeviceStruct LPT[MAX_PORTS];
109
110 /* update window's semi documented modem status register */
111 /* see knowledge base Q101417 */
112 static void COMM_MSRUpdate( HANDLE handle, UCHAR * pMsr )
113 {
114 UCHAR tmpmsr=0;
115 DWORD mstat=0;
116
117 if(!GetCommModemStatus(handle,&mstat))
118 return;
119
120 if(mstat & MS_CTS_ON) tmpmsr |= MSR_CTS;
121 if(mstat & MS_DSR_ON) tmpmsr |= MSR_DSR;
122 if(mstat & MS_RING_ON) tmpmsr |= MSR_RI;
123 if(mstat & MS_RLSD_ON) tmpmsr |= MSR_RLSD;
124 *pMsr = (*pMsr & ~MSR_MASK) | tmpmsr;
125 }
126
127 static struct DosDeviceStruct *GetDeviceStruct(int index)
128 {
129 if ((index&0x7F)<=MAX_PORTS) {
130 if (!(index&FLAG_LPT)) {
131 if (COM[index].handle)
132 return &COM[index];
133 } else {
134 index &= 0x7f;
135 if (LPT[index].handle)
136 return &LPT[index];
137 }
138 }
139
140 return NULL;
141 }
142
143 static int GetCommPort_ov(const OVERLAPPED *ov, int write)
144 {
145 int x;
146
147 for (x=0; x<MAX_PORTS; x++) {
148 if (ov == (write?&COM[x].write_ov:&COM[x].read_ov))
149 return x;
150 }
151
152 return -1;
153 }
154
155 static int WinError(void)
156 {
157 TRACE("errno = %d\n", errno);
158 switch (errno) {
159 default:
160 return CE_IOE;
161 }
162 }
163
164 static unsigned comm_inbuf(const struct DosDeviceStruct *ptr)
165 {
166 return ((ptr->ibuf_tail > ptr->ibuf_head) ? ptr->ibuf_size : 0)
167 + ptr->ibuf_head - ptr->ibuf_tail;
168 }
169
170 static unsigned comm_outbuf(const struct DosDeviceStruct *ptr)
171 {
172 return ((ptr->obuf_tail > ptr->obuf_head) ? ptr->obuf_size : 0)
173 + ptr->obuf_head - ptr->obuf_tail;
174 }
175
176 static void comm_waitread(struct DosDeviceStruct *ptr);
177 static void comm_waitwrite(struct DosDeviceStruct *ptr);
178
179 static VOID WINAPI COMM16_ReadComplete(DWORD dwErrorCode, DWORD len, LPOVERLAPPED ov)
180 {
181 int prev;
182 WORD mask = 0;
183 int cid = GetCommPort_ov(ov,0);
184 struct DosDeviceStruct *ptr;
185
186 if(cid<0) {
187 ERR("async write with bad overlapped pointer\n");
188 return;
189 }
190 ptr = &COM[cid];
191
192 /* we get cancelled when CloseComm is called */
193 if (dwErrorCode==ERROR_OPERATION_ABORTED)
194 {
195 TRACE("Cancelled\n");
196 return;
197 }
198
199 /* read data from comm port */
200 if (dwErrorCode != NO_ERROR) {
201 ERR("async read failed, error %d\n",dwErrorCode);
202 COM[cid].commerror = CE_RXOVER;
203 return;
204 }
205 TRACE("async read completed %d bytes\n",len);
206
207 prev = comm_inbuf(ptr);
208
209 /* check for events */
210 if ((ptr->eventmask & EV_RXFLAG) &&
211 memchr(ptr->inbuf + ptr->ibuf_head, ptr->evtchar, len)) {
212 *(WORD*)(COM[cid].unknown) |= EV_RXFLAG;
213 mask |= CN_EVENT;
214 }
215 if (ptr->eventmask & EV_RXCHAR) {
216 *(WORD*)(COM[cid].unknown) |= EV_RXCHAR;
217 mask |= CN_EVENT;
218 }
219
220 /* advance buffer position */
221 ptr->ibuf_head += len;
222 if (ptr->ibuf_head >= ptr->ibuf_size)
223 ptr->ibuf_head = 0;
224
225 /* check for notification */
226 if (ptr->wnd && (ptr->n_read>0) && (prev<ptr->n_read) &&
227 (comm_inbuf(ptr)>=ptr->n_read)) {
228 /* passed the receive notification threshold */
229 mask |= CN_RECEIVE;
230 }
231
232 /* send notifications, if any */
233 if (ptr->wnd && mask) {
234 TRACE("notifying %p: cid=%d, mask=%02x\n", ptr->wnd, cid, mask);
235 PostMessageA(ptr->wnd, WM_COMMNOTIFY, cid, mask);
236 }
237
238 /* on real windows, this could cause problems, since it is recursive */
239 /* restart the receive */
240 comm_waitread(ptr);
241 }
242
243 /* this is meant to work like write() */
244 static INT COMM16_WriteFile(HANDLE hComm, LPCVOID buffer, DWORD len)
245 {
246 OVERLAPPED ov;
247 DWORD count= -1;
248
249 ZeroMemory(&ov,sizeof(ov));
250 ov.hEvent = CreateEventW(NULL,0,0,NULL);
251 if(ov.hEvent==INVALID_HANDLE_VALUE)
252 return -1;
253
254 if(!WriteFile(hComm,buffer,len,&count,&ov))
255 {
256 if(GetLastError()==ERROR_IO_PENDING)
257 {
258 GetOverlappedResult(hComm,&ov,&count,TRUE);
259 }
260 }
261 CloseHandle(ov.hEvent);
262
263 return count;
264 }
265
266 static VOID WINAPI COMM16_WriteComplete(DWORD dwErrorCode, DWORD len, LPOVERLAPPED ov)
267 {
268 int prev, bleft;
269 WORD mask = 0;
270 int cid = GetCommPort_ov(ov,1);
271 struct DosDeviceStruct *ptr;
272
273 if(cid<0) {
274 ERR("async write with bad overlapped pointer\n");
275 return;
276 }
277 ptr = &COM[cid];
278
279 /* read data from comm port */
280 if (dwErrorCode != NO_ERROR) {
281 ERR("async write failed, error %d\n",dwErrorCode);
282 COM[cid].commerror = CE_RXOVER;
283 return;
284 }
285 TRACE("async write completed %d bytes\n",len);
286
287 /* update the buffer pointers */
288 prev = comm_outbuf(&COM[cid]);
289 ptr->obuf_tail += len;
290 if (ptr->obuf_tail >= ptr->obuf_size)
291 ptr->obuf_tail = 0;
292
293 /* write any TransmitCommChar character */
294 if (ptr->xmit>=0) {
295 len = COMM16_WriteFile(ptr->handle, &(ptr->xmit), 1);
296 if (len > 0) ptr->xmit = -1;
297 }
298
299 /* write from output queue */
300 bleft = ((ptr->obuf_tail <= ptr->obuf_head) ?
301 ptr->obuf_head : ptr->obuf_size) - ptr->obuf_tail;
302
303 /* check for notification */
304 if (ptr->wnd && (ptr->n_write>0) && (prev>=ptr->n_write) &&
305 (comm_outbuf(ptr)<ptr->n_write)) {
306 /* passed the transmit notification threshold */
307 mask |= CN_TRANSMIT;
308 }
309
310 /* send notifications, if any */
311 if (ptr->wnd && mask) {
312 TRACE("notifying %p: cid=%d, mask=%02x\n", ptr->wnd, cid, mask);
313 PostMessageA(ptr->wnd, WM_COMMNOTIFY, cid, mask);
314 }
315
316 /* start again if necessary */
317 if(bleft)
318 comm_waitwrite(ptr);
319 }
320
321 static void comm_waitread(struct DosDeviceStruct *ptr)
322 {
323 unsigned int bleft;
324 COMSTAT stat;
325
326 /* FIXME: get timeouts working properly so we can read bleft bytes */
327 bleft = ((ptr->ibuf_tail > ptr->ibuf_head) ?
328 (ptr->ibuf_tail-1) : ptr->ibuf_size) - ptr->ibuf_head;
329
330 /* find out how many bytes are left in the buffer */
331 if(ClearCommError(ptr->handle,NULL,&stat))
332 bleft = (bleft<stat.cbInQue) ? bleft : stat.cbInQue;
333 else
334 bleft = 1;
335
336 /* always read at least one byte */
337 if(bleft==0)
338 bleft++;
339
340 ReadFileEx(ptr->handle,
341 ptr->inbuf + ptr->ibuf_head,
342 bleft,
343 &ptr->read_ov,
344 COMM16_ReadComplete);
345 }
346
347 static void comm_waitwrite(struct DosDeviceStruct *ptr)
348 {
349 int bleft;
350
351 bleft = ((ptr->obuf_tail <= ptr->obuf_head) ?
352 ptr->obuf_head : ptr->obuf_size) - ptr->obuf_tail;
353 WriteFileEx(ptr->handle,
354 ptr->outbuf + ptr->obuf_tail,
355 bleft,
356 &ptr->write_ov,
357 COMM16_WriteComplete);
358 }
359
360 /*****************************************************************************
361 * COMM16_DCBtoDCB16 (Internal)
362 */
363 static INT16 COMM16_DCBtoDCB16(const DCB *lpdcb, LPDCB16 lpdcb16)
364 {
365 if(lpdcb->BaudRate<0x10000)
366 lpdcb16->BaudRate = lpdcb->BaudRate;
367 else if(lpdcb->BaudRate==115200)
368 lpdcb16->BaudRate = 57601;
369 else {
370 WARN("Baud rate can't be converted\n");
371 lpdcb16->BaudRate = 57601;
372 }
373 lpdcb16->ByteSize = lpdcb->ByteSize;
374 lpdcb16->fParity = lpdcb->fParity;
375 lpdcb16->Parity = lpdcb->Parity;
376 lpdcb16->StopBits = lpdcb->StopBits;
377
378 lpdcb16->RlsTimeout = 50;
379 lpdcb16->CtsTimeout = 50;
380 lpdcb16->DsrTimeout = 50;
381 lpdcb16->fNull = 0;
382 lpdcb16->fChEvt = 0;
383 lpdcb16->fBinary = 1;
384
385 lpdcb16->fDtrflow = (lpdcb->fDtrControl==DTR_CONTROL_HANDSHAKE);
386 lpdcb16->fRtsflow = (lpdcb->fRtsControl==RTS_CONTROL_HANDSHAKE);
387 lpdcb16->fOutxCtsFlow = lpdcb->fOutxCtsFlow;
388 lpdcb16->fOutxDsrFlow = lpdcb->fOutxDsrFlow;
389 lpdcb16->fDtrDisable = (lpdcb->fDtrControl==DTR_CONTROL_DISABLE);
390
391 lpdcb16->fInX = lpdcb->fInX;
392
393 lpdcb16->fOutX = lpdcb->fOutX;
394 /*
395 lpdcb16->XonChar =
396 lpdcb16->XoffChar =
397 */
398 lpdcb16->XonLim = 10;
399 lpdcb16->XoffLim = 10;
400
401 return 0;
402 }
403
404
405 /**************************************************************************
406 * BuildCommDCB (USER.213)
407 *
408 * According to the ECMA-234 (368.3) the function will return FALSE on
409 * success, otherwise it will return -1.
410 */
411 INT16 WINAPI BuildCommDCB16(LPCSTR device, LPDCB16 lpdcb)
412 {
413 /* "COM1:96,n,8,1" */
414 /* 012345 */
415 int port;
416 DCB dcb;
417
418 TRACE("(%s), ptr %p\n", device, lpdcb);
419
420 if (strncasecmp(device,"COM",3))
421 return -1;
422 port = device[3] - '';
423
424 if (port-- == 0) {
425 ERR("BUG ! COM0 can't exist!\n");
426 return -1;
427 }
428
429 memset(lpdcb, 0, sizeof(DCB16)); /* initialize */
430
431 lpdcb->Id = port;
432 dcb.DCBlength = sizeof(DCB);
433
434 if (strchr(device,'=')) /* block new style */
435 return -1;
436
437 if(!BuildCommDCBA(device,&dcb))
438 return -1;
439
440 return COMM16_DCBtoDCB16(&dcb, lpdcb);
441 }
442
443 /*****************************************************************************
444 * OpenComm (USER.200)
445 */
446 INT16 WINAPI OpenComm16(LPCSTR device,UINT16 cbInQueue,UINT16 cbOutQueue)
447 {
448 int port;
449 HANDLE handle;
450
451 TRACE("%s, %d, %d\n", device, cbInQueue, cbOutQueue);
452
453 if (strlen(device) < 4)
454 return IE_BADID;
455
456 port = device[3] - '';
457
458 if (port-- == 0)
459 ERR("BUG ! COM0 or LPT0 don't exist !\n");
460
461 if (!strncasecmp(device,"COM",3))
462 {
463 if (COM[port].handle)
464 return IE_OPEN;
465
466 handle = CreateFileA(device, GENERIC_READ|GENERIC_WRITE,
467 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS,
468 FILE_FLAG_OVERLAPPED|FILE_FLAG_NO_BUFFERING, 0 );
469 if (handle == INVALID_HANDLE_VALUE) {
470 return IE_HARDWARE;
471 } else {
472 memset(COM[port].unknown, 0, sizeof(COM[port].unknown));
473 COM[port].seg_unknown = 0;
474 COM[port].handle = handle;
475 COM[port].commerror = 0;
476 COM[port].eventmask = 0;
477 COM[port].evtchar = 0; /* FIXME: default? */
478 /* save terminal state */
479 GetCommState16(port,&COM[port].dcb);
480 /* init priority characters */
481 COM[port].unget = -1;
482 COM[port].xmit = -1;
483 /* allocate buffers */
484 COM[port].ibuf_size = cbInQueue;
485 COM[port].ibuf_head = COM[port].ibuf_tail = 0;
486 COM[port].obuf_size = cbOutQueue;
487 COM[port].obuf_head = COM[port].obuf_tail = 0;
488
489 COM[port].inbuf = HeapAlloc(GetProcessHeap(), 0, cbInQueue);
490 if (COM[port].inbuf) {
491 COM[port].outbuf = HeapAlloc( GetProcessHeap(), 0, cbOutQueue);
492 if (!COM[port].outbuf)
493 HeapFree( GetProcessHeap(), 0, COM[port].inbuf);
494 } else COM[port].outbuf = NULL;
495 if (!COM[port].outbuf) {
496 /* not enough memory */
497 CloseHandle(COM[port].handle);
498 ERR("out of memory\n");
499 return IE_MEMORY;
500 }
501
502 ZeroMemory(&COM[port].read_ov,sizeof (OVERLAPPED));
503 ZeroMemory(&COM[port].write_ov,sizeof (OVERLAPPED));
504
505 comm_waitread( &COM[port] );
506 USER16_AlertableWait++;
507
508 return port;
509 }
510 }
511 else
512 if (!strncasecmp(device,"LPT",3)) {
513
514 if (LPT[port].handle)
515 return IE_OPEN;
516
517 handle = CreateFileA(device, GENERIC_READ|GENERIC_WRITE,
518 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, 0 );
519 if (handle == INVALID_HANDLE_VALUE) {
520 return IE_HARDWARE;
521 } else {
522 LPT[port].handle = handle;
523 LPT[port].commerror = 0;
524 LPT[port].eventmask = 0;
525 return port|FLAG_LPT;
526 }
527 }
528 return IE_BADID;
529 }
530
531 /*****************************************************************************
532 * CloseComm (USER.207)
533 */
534 INT16 WINAPI CloseComm16(INT16 cid)
535 {
536 struct DosDeviceStruct *ptr;
537
538 TRACE("cid=%d\n", cid);
539 if ((ptr = GetDeviceStruct(cid)) == NULL) {
540 FIXME("no cid=%d found!\n", cid);
541 return -1;
542 }
543 if (!(cid&FLAG_LPT)) {
544 /* COM port */
545 UnMapLS( COM[cid].seg_unknown );
546 USER16_AlertableWait--;
547 CancelIo(ptr->handle);
548
549 /* free buffers */
550 HeapFree( GetProcessHeap(), 0, ptr->outbuf);
551 HeapFree( GetProcessHeap(), 0, ptr->inbuf);
552
553 /* reset modem lines */
554 SetCommState16(&COM[cid].dcb);
555 }
556
557 if (!CloseHandle(ptr->handle)) {
558 ptr->commerror = WinError();
559 /* FIXME: should we clear ptr->handle here? */
560 return -1;
561 } else {
562 ptr->commerror = 0;
563 ptr->handle = 0;
564 return 0;
565 }
566 }
567
568 /*****************************************************************************
569 * SetCommBreak (USER.210)
570 */
571 INT16 WINAPI SetCommBreak16(INT16 cid)
572 {
573 struct DosDeviceStruct *ptr;
574
575 TRACE("cid=%d\n", cid);
576 if ((ptr = GetDeviceStruct(cid)) == NULL) {
577 FIXME("no cid=%d found!\n", cid);
578 return -1;
579 }
580
581 ptr->suspended = 1;
582 ptr->commerror = 0;
583 return 0;
584 }
585
586 /*****************************************************************************
587 * ClearCommBreak (USER.211)
588 */
589 INT16 WINAPI ClearCommBreak16(INT16 cid)
590 {
591 struct DosDeviceStruct *ptr;
592
593 TRACE("cid=%d\n", cid);
594 if (!(ptr = GetDeviceStruct(cid))) {
595 FIXME("no cid=%d found!\n", cid);
596 return -1;
597 }
598 ptr->suspended = 0;
599 ptr->commerror = 0;
600 return 0;
601 }
602
603 /*****************************************************************************
604 * EscapeCommFunction (USER.214)
605 */
606 LONG WINAPI EscapeCommFunction16(UINT16 cid,UINT16 nFunction)
607 {
608 struct DosDeviceStruct *ptr;
609
610 TRACE("cid=%d, function=%d\n", cid, nFunction);
611
612 switch(nFunction) {
613 case GETMAXCOM:
614 TRACE("GETMAXCOM\n");
615 return 4; /* FIXME */
616
617 case GETMAXLPT:
618 TRACE("GETMAXLPT\n");
619 return FLAG_LPT + 3; /* FIXME */
620
621 case GETBASEIRQ:
622 TRACE("GETBASEIRQ\n");
623 /* FIXME: use tables */
624 /* just fake something for now */
625 if (cid & FLAG_LPT) {
626 /* LPT1: irq 7, LPT2: irq 5 */
627 return (cid & 0x7f) ? 5 : 7;
628 } else {
629 /* COM1: irq 4, COM2: irq 3,
630 COM3: irq 4, COM4: irq 3 */
631 return 4 - (cid & 1);
632 }
633 }
634
635 if ((ptr = GetDeviceStruct(cid)) == NULL) {
636 FIXME("no cid=%d found!\n", cid);
637 return -1;
638 }
639
640 switch (nFunction) {
641 case RESETDEV:
642 case CLRDTR:
643 case CLRRTS:
644 case SETDTR:
645 case SETRTS:
646 case SETXOFF:
647 case SETXON:
648 if(EscapeCommFunction(ptr->handle,nFunction))
649 return 0;
650 else {
651 ptr->commerror = WinError();
652 return -1;
653 }
654
655 case CLRBREAK:
656 case SETBREAK:
657 default:
658 WARN("(cid=%d,nFunction=%d): Unknown function\n",
659 cid, nFunction);
660 }
661 return -1;
662 }
663
664 /*****************************************************************************
665 * FlushComm (USER.215)
666 */
667 INT16 WINAPI FlushComm16(INT16 cid,INT16 fnQueue)
668 {
669 DWORD queue;
670 struct DosDeviceStruct *ptr;
671
672 TRACE("cid=%d, queue=%d\n", cid, fnQueue);
673 if ((ptr = GetDeviceStruct(cid)) == NULL) {
674 FIXME("no cid=%d found!\n", cid);
675 return -1;
676 }
677 switch (fnQueue) {
678 case 0:
679 queue = PURGE_TXABORT;
680 ptr->obuf_tail = ptr->obuf_head;
681 break;
682 case 1:
683 queue = PURGE_RXABORT;
684 ptr->ibuf_head = ptr->ibuf_tail;
685 break;
686 default:
687 WARN("(cid=%d,fnQueue=%d):Unknown queue\n",
688 cid, fnQueue);
689 return -1;
690 }
691
692 if (!PurgeComm(ptr->handle,queue)) {
693 ptr->commerror = WinError();
694 return -1;
695 } else {
696 ptr->commerror = 0;
697 return 0;
698 }
699 }
700
701 /********************************************************************
702 * GetCommError (USER.203)
703 */
704 INT16 WINAPI GetCommError16(INT16 cid,LPCOMSTAT16 lpStat)
705 {
706 int temperror;
707 struct DosDeviceStruct *ptr;
708 unsigned char *stol;
709
710 if ((ptr = GetDeviceStruct(cid)) == NULL) {
711 FIXME("no handle for cid = %0x!\n",cid);
712 return -1;
713 }
714 if (cid&FLAG_LPT) {
715 WARN(" cid %d not comm port\n",cid);
716 return CE_MODE;
717 }
718 stol = (unsigned char *)COM[cid].unknown + COMM_MSR_OFFSET;
719 COMM_MSRUpdate( ptr->handle, stol );
720
721 if (lpStat) {
722 lpStat->status = 0;
723
724 if (comm_inbuf(ptr) == 0)
725 SleepEx(1,TRUE);
726
727 lpStat->cbOutQue = comm_outbuf(ptr);
728 lpStat->cbInQue = comm_inbuf(ptr);
729
730 TRACE("cid %d, error %d, stat %d in %d out %d, stol %x\n",
731 cid, ptr->commerror, lpStat->status, lpStat->cbInQue,
732 lpStat->cbOutQue, *stol);
733 }
734 else
735 TRACE("cid %d, error %d, lpStat NULL stol %x\n",
736 cid, ptr->commerror, *stol);
737
738 /* Return any errors and clear it */
739 temperror = ptr->commerror;
740 ptr->commerror = 0;
741 return(temperror);
742 }
743
744 /*****************************************************************************
745 * SetCommEventMask (USER.208)
746 */
747 SEGPTR WINAPI SetCommEventMask16(INT16 cid,UINT16 fuEvtMask)
748 {
749 struct DosDeviceStruct *ptr;
750 unsigned char *stol;
751
752 TRACE("cid %d,mask %d\n",cid,fuEvtMask);
753 if ((ptr = GetDeviceStruct(cid)) == NULL) {
754 FIXME("no handle for cid = %0x!\n",cid);
755 return 0;
756 }
757
758 ptr->eventmask = fuEvtMask;
759
760 if (cid&FLAG_LPT) {
761 WARN(" cid %d not comm port\n",cid);
762 return 0;
763 }
764 /* it's a COM port ? -> modify flags */
765 stol = (unsigned char *)COM[cid].unknown + COMM_MSR_OFFSET;
766 COMM_MSRUpdate( ptr->handle, stol );
767
768 TRACE(" modem dcd construct %x\n",*stol);
769 if (!COM[cid].seg_unknown) COM[cid].seg_unknown = MapLS( COM[cid].unknown );
770 return COM[cid].seg_unknown;
771 }
772
773 /*****************************************************************************
774 * GetCommEventMask (USER.209)
775 */
776 UINT16 WINAPI GetCommEventMask16(INT16 cid,UINT16 fnEvtClear)
777 {
778 struct DosDeviceStruct *ptr;
779 WORD events;
780
781 TRACE("cid %d, mask %d\n", cid, fnEvtClear);
782 if ((ptr = GetDeviceStruct(cid)) == NULL) {
783 FIXME("no handle for cid = %0x!\n",cid);
784 return 0;
785 }
786
787 if (cid&FLAG_LPT) {
788 WARN(" cid %d not comm port\n",cid);
789 return 0;
790 }
791
792 events = *(WORD*)(COM[cid].unknown) & fnEvtClear;
793 *(WORD*)(COM[cid].unknown) &= ~fnEvtClear;
794 return events;
795 }
796
797 /*****************************************************************************
798 * SetCommState (USER.201)
799 */
800 INT16 WINAPI SetCommState16(LPDCB16 lpdcb)
801 {
802 struct DosDeviceStruct *ptr;
803 DCB dcb;
804
805 TRACE("cid %d, ptr %p\n", lpdcb->Id, lpdcb);
806 if ((ptr = GetDeviceStruct(lpdcb->Id)) == NULL) {
807 FIXME("no handle for cid = %0x!\n",lpdcb->Id);
808 return -1;
809 }
810
811 memset(&dcb,0,sizeof(dcb));
812 dcb.DCBlength = sizeof(dcb);
813
814 /*
815 * according to MSDN, we should first interpret lpdcb->BaudRate as follows:
816 * 1. if the baud rate is a CBR constant, interpret it.
817 * 2. if it is greater than 57600, the baud rate is 115200
818 * 3. use the actual baudrate
819 * steps 2 and 3 are equivalent to 16550 baudrate divisor = 115200/BaudRate
820 */
821 switch(lpdcb->BaudRate)
822 {
823 case CBR_110: dcb.BaudRate = 110; break;
824 case CBR_300: dcb.BaudRate = 300; break;
825 case CBR_600: dcb.BaudRate = 600; break;
826 case CBR_1200: dcb.BaudRate = 1200; break;
827 case CBR_2400: dcb.BaudRate = 2400; break;
828 case CBR_4800: dcb.BaudRate = 4800; break;
829 case CBR_9600: dcb.BaudRate = 9600; break;
830 case CBR_14400: dcb.BaudRate = 14400; break;
831 case CBR_19200: dcb.BaudRate = 19200; break;
832 case CBR_38400: dcb.BaudRate = 38400; break;
833 case CBR_56000: dcb.BaudRate = 56000; break;
834 case CBR_128000: dcb.BaudRate = 128000; break;
835 case CBR_256000: dcb.BaudRate = 256000; break;
836 default:
837 if(lpdcb->BaudRate>57600)
838 dcb.BaudRate = 115200;
839 else
840 dcb.BaudRate = lpdcb->BaudRate;
841 }
842
843 dcb.ByteSize=lpdcb->ByteSize;
844 dcb.StopBits=lpdcb->StopBits;
845
846 dcb.fParity=lpdcb->fParity;
847 dcb.Parity=lpdcb->Parity;
848
849 dcb.fOutxCtsFlow = lpdcb->fOutxCtsFlow;
850
851 if (lpdcb->fDtrflow || lpdcb->fRtsflow)
852 dcb.fRtsControl = TRUE;
853
854 if (lpdcb->fDtrDisable)
855 dcb.fDtrControl = TRUE;
856
857 ptr->evtchar = lpdcb->EvtChar;
858
859 dcb.fInX = lpdcb->fInX;
860 dcb.fOutX = lpdcb->fOutX;
861
862 if (!SetCommState(ptr->handle,&dcb)) {
863 ptr->commerror = WinError();
864 return -1;
865 } else {
866 ptr->commerror = 0;
867 return 0;
868 }
869 }
870
871 /*****************************************************************************
872 * GetCommState (USER.202)
873 */
874 INT16 WINAPI GetCommState16(INT16 cid, LPDCB16 lpdcb)
875 {
876 struct DosDeviceStruct *ptr;
877 DCB dcb;
878
879 TRACE("cid %d, ptr %p\n", cid, lpdcb);
880 if ((ptr = GetDeviceStruct(cid)) == NULL) {
881 FIXME("no handle for cid = %0x!\n",cid);
882 return -1;
883 }
884 if (!GetCommState(ptr->handle,&dcb)) {
885 ptr->commerror = WinError();
886 return -1;
887 }
888
889 lpdcb->Id = cid;
890
891 COMM16_DCBtoDCB16(&dcb,lpdcb);
892
893 lpdcb->EvtChar = ptr->evtchar;
894
895 ptr->commerror = 0;
896 return 0;
897 }
898
899 /*****************************************************************************
900 * TransmitCommChar (USER.206)
901 */
902 INT16 WINAPI TransmitCommChar16(INT16 cid,CHAR chTransmit)
903 {
904 struct DosDeviceStruct *ptr;
905
906 TRACE("cid %d, data %d\n", cid, chTransmit);
907 if ((ptr = GetDeviceStruct(cid)) == NULL) {
908 FIXME("no handle for cid = %0x!\n",cid);
909 return -1;
910 }
911
912 if (ptr->suspended) {
913 ptr->commerror = IE_HARDWARE;
914 return -1;
915 }
916
917 if (ptr->xmit >= 0) {
918 /* character already queued */
919 /* FIXME: which error would Windows return? */
920 ptr->commerror = CE_TXFULL;
921 return -1;
922 }
923
924 if (ptr->obuf_head == ptr->obuf_tail) {
925 /* transmit queue empty, try to transmit directly */
926 if(1!=COMM16_WriteFile(ptr->handle, &chTransmit, 1))
927 {
928 /* didn't work, queue it */
929 ptr->xmit = chTransmit;
930 comm_waitwrite(ptr);
931 }
932 } else {
933 /* data in queue, let this char be transmitted next */
934 ptr->xmit = chTransmit;
935 comm_waitwrite(ptr);
936 }
937
938 ptr->commerror = 0;
939 return 0;
940 }
941
942 /*****************************************************************************
943 * UngetCommChar (USER.212)
944 */
945 INT16 WINAPI UngetCommChar16(INT16 cid,CHAR chUnget)
946 {
947 struct DosDeviceStruct *ptr;
948
949 TRACE("cid %d (char %d)\n", cid, chUnget);
950 if ((ptr = GetDeviceStruct(cid)) == NULL) {
951 FIXME("no handle for cid = %0x!\n",cid);
952 return -1;
953 }
954
955 if (ptr->suspended) {
956 ptr->commerror = IE_HARDWARE;
957 return -1;
958 }
959
960 if (ptr->unget>=0) {
961 /* character already queued */
962 /* FIXME: which error would Windows return? */
963 ptr->commerror = CE_RXOVER;
964 return -1;
965 }
966
967 ptr->unget = chUnget;
968
969 ptr->commerror = 0;
970 return 0;
971 }
972
973 /*****************************************************************************
974 * ReadComm (USER.204)
975 */
976 INT16 WINAPI ReadComm16(INT16 cid,LPSTR lpvBuf,INT16 cbRead)
977 {
978 int status, length;
979 struct DosDeviceStruct *ptr;
980 LPSTR orgBuf = lpvBuf;
981
982 TRACE("cid %d, ptr %p, length %d\n", cid, lpvBuf, cbRead);
983 if ((ptr = GetDeviceStruct(cid)) == NULL) {
984 FIXME("no handle for cid = %0x!\n",cid);
985 return -1;
986 }
987
988 if (ptr->suspended) {
989 ptr->commerror = IE_HARDWARE;
990 return -1;
991 }
992
993 if(0==comm_inbuf(ptr))
994 SleepEx(1,TRUE);
995
996 /* read unget character */
997 if (ptr->unget>=0) {
998 *lpvBuf++ = ptr->unget;
999 ptr->unget = -1;
1000
1001 length = 1;
1002 } else
1003 length = 0;
1004
1005 /* read from receive buffer */
1006 while (length < cbRead) {
1007 status = ((ptr->ibuf_head < ptr->ibuf_tail) ?
1008 ptr->ibuf_size : ptr->ibuf_head) - ptr->ibuf_tail;
1009 if (!status) break;
1010 if ((cbRead - length) < status)
1011 status = cbRead - length;
1012
1013 memcpy(lpvBuf, ptr->inbuf + ptr->ibuf_tail, status);
1014 ptr->ibuf_tail += status;
1015 if (ptr->ibuf_tail >= ptr->ibuf_size)
1016 ptr->ibuf_tail = 0;
1017 lpvBuf += status;
1018 length += status;
1019 }
1020
1021 TRACE("%s\n", debugstr_an( orgBuf, length ));
1022 ptr->commerror = 0;
1023 return length;
1024 }
1025
1026 /*****************************************************************************
1027 * WriteComm (USER.205)
1028 */
1029 INT16 WINAPI WriteComm16(INT16 cid, LPSTR lpvBuf, INT16 cbWrite)
1030 {
1031 int status, length;
1032 struct DosDeviceStruct *ptr;
1033
1034 TRACE("cid %d, ptr %p, length %d\n",
1035 cid, lpvBuf, cbWrite);
1036 if ((ptr = GetDeviceStruct(cid)) == NULL) {
1037 FIXME("no handle for cid = %0x!\n",cid);
1038 return -1;
1039 }
1040
1041 if (ptr->suspended) {
1042 ptr->commerror = IE_HARDWARE;
1043 return -1;
1044 }
1045
1046 TRACE("%s\n", debugstr_an( lpvBuf, cbWrite ));
1047
1048 length = 0;
1049 while (length < cbWrite) {
1050 if ((ptr->obuf_head == ptr->obuf_tail) && (ptr->xmit < 0)) {
1051 /* no data queued, try to write directly */
1052 status = COMM16_WriteFile(ptr->handle, lpvBuf, cbWrite - length);
1053 if (status > 0) {
1054 lpvBuf += status;
1055 length += status;
1056 continue;
1057 }
1058 }
1059 /* can't write directly, put into transmit buffer */
1060 status = ((ptr->obuf_tail > ptr->obuf_head) ?
1061 (ptr->obuf_tail-1) : ptr->obuf_size) - ptr->obuf_head;
1062 if (!status) break;
1063 if ((cbWrite - length) < status)
1064 status = cbWrite - length;
1065 memcpy(lpvBuf, ptr->outbuf + ptr->obuf_head, status);
1066 ptr->obuf_head += status;
1067 if (ptr->obuf_head >= ptr->obuf_size)
1068 ptr->obuf_head = 0;
1069 lpvBuf += status;
1070 length += status;
1071 comm_waitwrite(ptr);
1072 }
1073
1074 ptr->commerror = 0;
1075 return length;
1076 }
1077
1078 /***********************************************************************
1079 * EnableCommNotification (USER.245)
1080 */
1081 BOOL16 WINAPI EnableCommNotification16( INT16 cid, HWND16 hwnd,
1082 INT16 cbWriteNotify, INT16 cbOutQueue )
1083 {
1084 struct DosDeviceStruct *ptr;
1085
1086 TRACE("(%d, %x, %d, %d)\n", cid, hwnd, cbWriteNotify, cbOutQueue);
1087 if ((ptr = GetDeviceStruct(cid)) == NULL) {
1088 FIXME("no handle for cid = %0x!\n",cid);
1089 return -1;
1090 }
1091 ptr->wnd = WIN_Handle32( hwnd );
1092 ptr->n_read = cbWriteNotify;
1093 ptr->n_write = cbOutQueue;
1094 return TRUE;
1095 }
1096
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.