Gammu internals  1.38.0
ser_w32.c
Go to the documentation of this file.
1 /* (c) 2002-2004 by Marcin Wiacek */
2 /* based on some work from MSDN and others */
3 /* based on some work from Gnokii (www.gnokii.org)
4  * (C) 1999-2000 Hugh Blemings & Pavel Janik ml. (C) 2001-2004 Pawel Kot
5  * GNU GPL version 2 or later
6  */
7 /* Due to a problem in the source code management, the names of some of
8  * the authors have unfortunately been lost. We do not mean to belittle
9  * their efforts and hope they will contact us to see their names
10  * properly added to the Copyright notice above.
11  * Having published their contributions under the terms of the GNU
12  * General Public License (GPL) [version 2], the Copyright of these
13  * authors will remain respected by adhering to the license they chose
14  * to publish their code under.
15  */
16 
17 /* To define GUID and not only declare */
18 #define INITGUID
19 
20 #include "../../gsmstate.h"
21 
22 #ifdef GSM_ENABLE_SERIALDEVICE
23 #ifdef WIN32
24 
25 #define WIN32_LEAN_AND_MEAN
26 #include <windows.h>
27 #include <string.h>
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <io.h>
31 #include <memory.h>
32 
33 #if defined(GSM_ENABLE_DKU2PHONET) || defined(GSM_ENABLE_DKU2AT)
34 # include <initguid.h>
35 # include <setupapi.h>
36 # ifndef __GNUC__
37 # pragma comment(lib, "setupapi.lib")
38 # pragma comment(lib, "advapi32.lib")
39 # endif
40 #endif
41 
42 #include "../../gsmcomon.h"
43 #include "ser_w32.h"
44 
45 static GSM_Error serial_close(GSM_StateMachine *s)
46 {
47  GSM_Device_SerialData *d = &s->Device.Data.Serial;
48 
49  if (s->ConnectionType != GCT_DKU2PHONET) {
50  /* Disables all monitored events for device */
51  SetCommMask(d->hPhone, 0);
52 
53  /* Discards all characters from input/output buffer and terminates
54  * pending read/write operations
55  */
56  PurgeComm(d->hPhone, PURGE_TXABORT | PURGE_RXABORT |
57  PURGE_TXCLEAR | PURGE_RXCLEAR);
58 
59  /* Clears the DTR (data-terminal-ready) signal */
60  EscapeCommFunction(d->hPhone, CLRDTR);
61 
62  /* Restores old settings */
63  if (SetCommState(d->hPhone, &d->old_settings)==0) {
64  GSM_OSErrorInfo(s, "SetCommState in serial_close");
65  }
66  }
67 
68  /* Closes device */
69  if (CloseHandle(d->hPhone)==0) {
70  GSM_OSErrorInfo(s, "CloseHandle in serial_close");
71  }
72 
73  return ERR_NONE;
74 }
75 
76 #if defined(GSM_ENABLE_DKU2PHONET) || defined(GSM_ENABLE_DKU2AT)
77  DEFINE_GUID(DKU2AT, 0x4F919104, 0x4adf, 0x11d5, 0x88, 0x2d, 0x0, 0xb0, 0xd0, 0x2f, 0xe3, 0x81); /* "4F919104-4ADF-11D5-882D-00B0D02FE381" */
78  DEFINE_GUID(DKU2FBUS2, 0x4F919102, 0x4adf, 0x11d5, 0x88, 0x2d, 0x0, 0xb0, 0xd0, 0x2f, 0xe3, 0x81); /* "4F919102-4ADF-11D5-882D-00B0D02FE381" */
79  DEFINE_GUID(DKU2OBEX, 0x4F919100, 0x4adf, 0x11d5, 0x88, 0x2d, 0x0, 0xb0, 0xd0, 0x2f, 0xe3, 0x81); /* "4F919100-4ADF-11D5-882D-00B0D02FE381" */
80 #endif
81 
82 static GSM_Error serial_open (GSM_StateMachine *s)
83 {
84  GSM_Device_SerialData *d = &s->Device.Data.Serial;
85  DCB dcb;
86  unsigned char DeviceName[256],DeviceName2[256];
87  int i;
88  DWORD err;
89 #if defined(GSM_ENABLE_DKU2PHONET) || defined(GSM_ENABLE_DKU2AT)
90  UCHAR bu[sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA) +(sizeof(TCHAR)*1000)];
91  DWORD reqsize;
92  SP_DEVINFO_DATA DeviceInfoData;
93  SP_DEVICE_INTERFACE_DATA DeviceInterfaceData;
94  PSP_DEVICE_INTERFACE_DETAIL_DATA DeviceInterfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)bu;
95  HDEVINFO ListHandle;
96  unsigned char KeyName2[256];
97 #endif
98 #ifdef GSM_ENABLE_DKU5FBUS2
99  HKEY hKey;
100  DWORD DeviceNameLen, KeyNameLen;
101  unsigned char KeyName[256];
102 #endif
103 
104  strcpy(DeviceName2,s->CurrentConfig->Device);
105 
106 #ifdef GSM_ENABLE_DKU2PHONET
107  if (s->ConnectionType == GCT_DKU2PHONET) {
108  ListHandle = SetupDiGetClassDevs(&DKU2FBUS2, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
109  if (ListHandle == INVALID_HANDLE_VALUE) {
110  SetupDiDestroyDeviceInfoList(ListHandle);
111  return ERR_UNKNOWN;
112  }
113  DeviceInfoData.cbSize = sizeof(DeviceInfoData);
114  DeviceInterfaceData.cbSize = sizeof(DeviceInterfaceData);
115  if (SetupDiEnumDeviceInfo(ListHandle, 0, &DeviceInfoData)) {
116  SetupDiGetDeviceRegistryProperty(ListHandle, &DeviceInfoData, SPDRP_DEVICEDESC, NULL, KeyName2, 200, &reqsize);
117  if (SetupDiEnumDeviceInterfaces(ListHandle, &DeviceInfoData, &DKU2FBUS2, 0, &DeviceInterfaceData)) {
118  DeviceInterfaceDetailData->cbSize = 5;
119  if (SetupDiGetDeviceInterfaceDetail(ListHandle, &DeviceInterfaceData, DeviceInterfaceDetailData, 200, &reqsize, &DeviceInfoData)) {
120  strcpy(DeviceName2,DeviceInterfaceDetailData->DevicePath);
121  }
122  }
123  }
124  SetupDiDestroyDeviceInfoList(ListHandle);
125  }
126 #endif
127 #ifdef GSM_ENABLE_DKU2AT
128  if (s->ConnectionType == GCT_DKU2AT) {
129  ListHandle = SetupDiGetClassDevs(&DKU2AT, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
130  if (ListHandle == INVALID_HANDLE_VALUE) {
131  SetupDiDestroyDeviceInfoList(ListHandle);
132  return ERR_UNKNOWN;
133  }
134  DeviceInfoData.cbSize = sizeof(DeviceInfoData);
135  DeviceInterfaceData.cbSize = sizeof(DeviceInterfaceData);
136  if (SetupDiEnumDeviceInfo(ListHandle, 0, &DeviceInfoData)) {
137  SetupDiGetDeviceRegistryProperty(ListHandle, &DeviceInfoData, SPDRP_DEVICEDESC, NULL, KeyName2, 200, &reqsize);
138  if (SetupDiEnumDeviceInterfaces(ListHandle, &DeviceInfoData, &DKU2AT, 0, &DeviceInterfaceData)) {
139  DeviceInterfaceDetailData->cbSize = 5;
140  if (SetupDiGetDeviceInterfaceDetail(ListHandle, &DeviceInterfaceData, DeviceInterfaceDetailData, 200, &reqsize, &DeviceInfoData)) {
141  strcpy(DeviceName2,DeviceInterfaceDetailData->DevicePath);
142  }
143  }
144  }
145  SetupDiDestroyDeviceInfoList(ListHandle);
146  }
147 #endif
148 #ifdef GSM_ENABLE_DKU5FBUS2
149  if (s->ConnectionType == GCT_DKU5FBUS2) {
150  smprintf(s,"Reading DKU5 device\n");
151  /* win xp */
152  DeviceName2[0] = 0;
153  if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "HARDWARE\\DEVICEMAP\\SERIALCOMM", 0, KEY_QUERY_VALUE, &hKey) != ERROR_SUCCESS) {
154  smprintf(s,"Error opening key\n");
155  return ERR_DEVICENOTEXIST;
156  }
157  i = 0;
158  while(1) {
159  DeviceNameLen = 80;
160  KeyNameLen = 100;
161  if (RegEnumValue(hKey,i,KeyName,&KeyNameLen,NULL,NULL,DeviceName2,&DeviceNameLen) != ERROR_SUCCESS) break;
162  if (!strncmp(KeyName,"\\Device\\AtmelVirtualPort",24)) break;
163  DeviceName2[0] = 0;
164  i++;
165  }
166  RegCloseKey(hKey);
167  if (strlen(DeviceName2) == 0) {
168  /* win 98 */
169  if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Enum\\USBVSP\\ATMELPORT\\0000", 0, KEY_QUERY_VALUE, &hKey) != ERROR_SUCCESS) {
170  smprintf(s,"Error opening key\n");
171  return ERR_DEVICENOTEXIST;
172  }
173  i = 0;
174  while(1) {
175  DeviceNameLen = 80;
176  KeyNameLen = 100;
177  if (RegEnumValue(hKey,i,KeyName,&KeyNameLen,NULL,NULL,DeviceName2,&DeviceNameLen) != ERROR_SUCCESS) break;
178  if (!strncmp(KeyName,"PORTNAME",8)) break;
179  DeviceName2[0] = 0;
180  i++;
181  }
182  RegCloseKey(hKey);
183  if (strlen(DeviceName2) == 0) {
184  return ERR_DEVICENOTEXIST;
185  }
186  }
187  smprintf(s,"DKU5 device is \"%s\"\n",DeviceName2);
188  }
189 #endif
190 
191  if ((s->ConnectionType == GCT_DKU5FBUS2) ||
192  (!strncmp(DeviceName2,"com",3) && strlen(DeviceName2)>3)) {
193  sprintf(DeviceName,"\\\\.\\COM%i",atoi(DeviceName2+3));
194  } else {
195  strcpy(DeviceName,DeviceName2);
196  }
197 
198  smprintf(s,"Device is %s\n",DeviceName);
199 
200  /* Allows for reading/writing, no device sharing */
201  d->hPhone = CreateFile(DeviceName,
202  GENERIC_READ | GENERIC_WRITE,
203  0,
204  0,
205  OPEN_EXISTING,
206  FILE_ATTRIBUTE_NORMAL,
207  NULL);
208 
209  if (d->hPhone == INVALID_HANDLE_VALUE) {
210  err = GetLastError();
211  GSM_OSErrorInfo(s, "CreateFile in serial_open");
212  if (err == ERROR_FILE_NOT_FOUND) return ERR_DEVICENOTEXIST; /* can't find specified file */
213  if (err == ERROR_ACCESS_DENIED) return ERR_DEVICEBUSY; /* access denied */
214  if (err == ERROR_GEN_FAILURE) return ERR_DEVICENOTWORK; /* attached device not working */
215  if (err == ERROR_INVALID_NAME) return ERR_DEVICENOTEXIST;
216  if (err == ERROR_PATH_NOT_FOUND) return ERR_DEVICENOTEXIST; /* can't find specified file */
217  return ERR_DEVICEOPENERROR;
218  }
219 
221  d->old_settings.DCBlength = sizeof(DCB);
222  if (GetCommState(d->hPhone, &d->old_settings)==0) {
223  GSM_OSErrorInfo(s, "GetCommState in serial_open");
224  return ERR_DEVICEOPENERROR;
225  }
226 
227  /* When char will be received, we will receive notifications */
228  SetCommMask(d->hPhone, EV_RXCHAR | EV_BREAK | EV_ERR);
229 
230  /* Sets size for input/output buffer */
231  SetupComm(d->hPhone, 4096, 4096);
232 
233  /* Discards all characters from input/output buffer and terminates
234  * pending read/write operations
235  */
236  PurgeComm(d->hPhone, PURGE_TXABORT | PURGE_RXABORT |
237  PURGE_TXCLEAR | PURGE_RXCLEAR);
238 
239  memcpy(&dcb, &d->old_settings, sizeof(DCB));
240 
241  dcb.ByteSize = 8;
242  dcb.Parity = NOPARITY;
243  dcb.StopBits = ONESTOPBIT;
244 
245  /* No Xon/Xof flow control */
246  /* dcb.fOutX = FALSE; */
247  /* dcb.fInX = FALSE; */
248 
249  /* Hardware flow control */
250  /* dcb.fOutxDsrFlow = TRUE; */
251  /* dcb.fOutxCtsFlow = TRUE; */
252  /* dcb.fDtrControl = DTR_CONTROL_HANDSHAKE; */
253  /* dcb.fRtsControl = RTS_CONTROL_HANDSHAKE; */
254 
255  /* Initialise the port settings */
256  if (SetCommState(d->hPhone, &dcb)==0) {
257  GSM_OSErrorInfo(s, "SetCommState in serial_open");
258  return ERR_DEVICEOPENERROR;
259  }
260  }
261 
262  return ERR_NONE;
263 }
264 
265 static GSM_Error serial_setparity (GSM_StateMachine *s, gboolean parity)
266 {
267  DCB dcb;
268  GSM_Device_SerialData *d = &s->Device.Data.Serial;
269 
270  dcb.DCBlength = sizeof(DCB);
271  if (GetCommState(d->hPhone, &dcb)==0) {
272  GSM_OSErrorInfo(s, "ReadDevice in serial_setparity");
273  return ERR_DEVICEREADERROR;
274  }
275 
276  if (parity) {
277  dcb.Parity = ODDPARITY;
278  } else {
279  dcb.Parity = NOPARITY;
280  }
281 
282  if (SetCommState(d->hPhone, &dcb)==0) {
283  GSM_OSErrorInfo(s, "WriteDevice in serial_setparity");
284  return ERR_DEVICEPARITYERROR;
285  }
286 
287  return ERR_NONE;
288 }
289 
290 static GSM_Error serial_setdtrrts(GSM_StateMachine *s, gboolean dtr, gboolean rts)
291 {
292  DCB dcb;
293  GSM_Device_SerialData *d = &s->Device.Data.Serial;
294 
295  if (s->SkipDtrRts) return ERR_NONE;
296 
297  dcb.DCBlength = sizeof(DCB);
298  if (GetCommState(d->hPhone, &dcb)==0) {
299  GSM_OSErrorInfo(s, "ReadDevice in serial_setdtrrts");
300  return ERR_DEVICEREADERROR;
301  }
302 
303  dcb.fOutxDsrFlow = 0;
304  dcb.fDtrControl = DTR_CONTROL_DISABLE;
305  if (dtr) dcb.fDtrControl = DTR_CONTROL_ENABLE;
306 
307  dcb.fOutxCtsFlow = 0;
308  dcb.fRtsControl = RTS_CONTROL_DISABLE;
309  if (rts) dcb.fRtsControl = RTS_CONTROL_ENABLE;
310 
311  /* no software (Xon/Xof) flow control */
312  dcb.fInX = dcb.fOutX = 0;
313 
314  if (SetCommState(d->hPhone, &dcb)==0) {
315  GSM_OSErrorInfo(s, "WriteDevice in serial_setdtrrts");
316  return ERR_DEVICEDTRRTSERROR;
317  }
318 
319  /* the rest of function checks, if setting was really done */
320 
321  dcb.DCBlength = sizeof(DCB);
322  GetCommState(d->hPhone, &dcb);
323 
324  smprintf(s, "Serial device:");
325  smprintf(s, " DTR is ");
326  switch (dcb.fDtrControl) {
327  case DTR_CONTROL_ENABLE : smprintf(s, "up"); break;
328  case DTR_CONTROL_DISABLE : smprintf(s, "down"); break;
329  case DTR_CONTROL_HANDSHAKE : smprintf(s, "handshake"); break;
330  }
331  smprintf(s, ", RTS is ");
332  switch (dcb.fRtsControl) {
333  case RTS_CONTROL_ENABLE : smprintf(s, "up"); break;
334  case RTS_CONTROL_DISABLE : smprintf(s, "down"); break;
335  case RTS_CONTROL_HANDSHAKE : smprintf(s, "handshake"); break;
336  case RTS_CONTROL_TOGGLE : smprintf(s, "toggle"); break;
337  }
338  smprintf(s, "\n");
339  if ( dtr && dcb.fDtrControl != DTR_CONTROL_ENABLE ) return ERR_DEVICEDTRRTSERROR;
340  if (!dtr && dcb.fDtrControl != DTR_CONTROL_DISABLE) return ERR_DEVICEDTRRTSERROR;
341  if ( rts && dcb.fRtsControl != RTS_CONTROL_ENABLE ) return ERR_DEVICEDTRRTSERROR;
342  if (!rts && dcb.fRtsControl != RTS_CONTROL_DISABLE) return ERR_DEVICEDTRRTSERROR;
343 
344  PurgeComm(d->hPhone, PURGE_TXABORT | PURGE_RXABORT |
345  PURGE_TXCLEAR | PURGE_RXCLEAR);
346 
347  return ERR_NONE;
348 }
349 
350 static GSM_Error serial_setspeed(GSM_StateMachine *s, int speed)
351 {
352  DCB dcb;
353  GSM_Device_SerialData *d = &s->Device.Data.Serial;
354 
355  if (s->SkipDtrRts) return ERR_NONE;
356 
357  dcb.DCBlength = sizeof(DCB);
358  if (GetCommState(d->hPhone, &dcb)==0) {
359  GSM_OSErrorInfo(s, "ReadDevice in serial_setspeed");
360  return ERR_DEVICEREADERROR;
361  }
362 
363  dcb.BaudRate = speed;
364 
365  if (SetCommState(d->hPhone, &dcb)==0) {
366  GSM_OSErrorInfo(s, "WriteDevice in serial_setspeed");
368  }
369 
370  smprintf(s, "Setting speed to %d\n", speed);
371 
372  return ERR_NONE;
373 }
374 
375 static int serial_read(GSM_StateMachine *s, void *buf, size_t nbytes)
376 {
377  COMSTAT ComStat;
378  DWORD ErrorFlags, Length, Error;
379  GSM_Device_SerialData *d = &s->Device.Data.Serial;
380  BOOL ReadStatus;
381 
383  /* Gets information about a communications error and
384  * current status of device
385  */
386  ClearCommError(d->hPhone, &ErrorFlags, &ComStat);
387 
388  /* How much we can read? */
389  Length = min(nbytes, ComStat.cbInQue);
390  } else {
391  Length = 5;
392  }
393 
394  /* Nothing to read */
395  if (Length <= 0) goto end;
396 
397  /* Isn't that to much? */
398  if (Length > nbytes) Length = nbytes;
399 
400  /* Read without problems */
401  ReadStatus = ReadFile(d->hPhone, buf, Length, &Length, &d->osRead);
402 
403  if (!ReadStatus) {
404  if (GetLastError() != ERROR_IO_PENDING) {
405  Length = 0;
406  ClearCommError(d->hPhone, &ErrorFlags, &ComStat);
407  goto end;
408  }
409 
410  /* Operation did not complete */
411  GSM_OSErrorInfo(s, "win_serial_read-pending");
412 
413  /* Wait for completing */
414  while (!GetOverlappedResult(d->hPhone, &d->osRead, &Length, TRUE)) {
415  Error = GetLastError();
416  if (Error == ERROR_IO_INCOMPLETE) {
417  /* Just go on */
418  continue;
419  } else {
420  /* Something went wrong, bail out */
421  GSM_OSErrorInfo(s, "win_serial_read-overlapped");
422  ClearCommError(d->hPhone, &ErrorFlags, &ComStat);
423  break;
424  }
425  }
426  }
427 end:
428  return Length;
429 }
430 
431 static int serial_write(GSM_StateMachine *s, const void *buf, size_t nbytes)
432 {
433  DWORD BytesWritten,ErrorFlags,BytesSent=0;
434  COMSTAT ComStat;
435  GSM_Device_SerialData *d = &s->Device.Data.Serial;
436 
437  if (WriteFile(d->hPhone, buf, nbytes, &BytesSent, &d->osWrite)) return BytesSent;
438 
439  if (GetLastError() != ERROR_IO_PENDING) {
440  GSM_OSErrorInfo(s, "serial_write1");
441  ClearCommError(d->hPhone, &ErrorFlags, &ComStat);
442  return BytesSent;
443  }
444 
445  while (1) {
446  if (GetOverlappedResult(d->hPhone, &d->osWrite, &BytesWritten, TRUE)) break;
447  if (GetLastError() != ERROR_IO_INCOMPLETE) {
448  GSM_OSErrorInfo(s, "serial_write2");
449  ClearCommError(d->hPhone, &ErrorFlags, &ComStat);
450  break;
451  }
452  BytesSent += BytesWritten;
453  }
454  BytesSent += BytesWritten;
455 
456  return BytesSent;
457 }
458 
459 GSM_Device_Functions SerialDevice = {
460  serial_open,
461  serial_close,
462  serial_setparity,
463  serial_setdtrrts,
464  serial_setspeed,
465  serial_read,
466  serial_write
467 };
468 
469 #endif
470 #endif
471 
472 /* How should editor hadle tabs in this file? Add editor commands here.
473  * vim: noexpandtab sw=8 ts=8 sts=8:
474  */
GSM_Config * CurrentConfig
Definition: gsmstate.h:1415
union GSM_Device::@0 Data
GSM_ConnectionType ConnectionType
Definition: gsmstate.h:1402
GSM_Error
Definition: gammu-error.h:23
int gboolean
Definition: gammu-types.h:23
void GSM_OSErrorInfo(GSM_StateMachine *s, const char *description)
Definition: gsmstate.c:1593
gboolean SkipDtrRts
Definition: gsmstate.h:1406
struct termios old_settings
Definition: ser_unx.h:13
#define TRUE
Definition: gammu-types.h:28
GSM_Device Device
Definition: gsmstate.h:1429
int smprintf(GSM_StateMachine *s, const char *format,...)
Definition: debug.c:261