6 A Linux/Unix toolset and driver for Nokia mobile phones.
8 Released under the terms of the GNU GPL, see file COPYING for more details.
10 This file provides a virtual modem interface to the GSM phone by calling
11 code in gsm-api.c, at-emulator.c and datapump.c. The code here provides
12 the overall framework and coordinates switching between command mode
13 (AT-emulator) and "online" mode where the data pump code translates data
14 from/to the GSM handset and the modem data/fax stream.
22 /* This is the right way to include stdlib with __USE_XOPEN defined */
24 # define _XOPEN_SOURCE 500
25 # include <features.h>
35 #include <sys/types.h>
46 #include "gsm-common.h"
47 #include "data/at-emulator.h"
48 #include "data/datapump.h"
49 #include "data/virtmodem.h"
50 #include "data/rlp-common.h"
52 /* Global variables */
55 #define GNOKII_DEV "/var/gnokii-dev"
57 //extern bool TerminateThread;
61 int PtyRDFD; /* File descriptor for reading and writing to/from */
62 int PtyWRFD; /* pty interface - only different in debug mode. */
64 static bool UseSTDIO; /* Use STDIO for debugging purposes instead of pty */
67 static GSM_Error VM_GSMInitialise(char *model, char *port, char *initlength, GSM_ConnectionType connection, char *synchronizetime);
68 static int VM_PtySetup(char *bindir);
70 /* If initialised in debug mode, stdin/out is used instead
71 of ptys for interface. */
72 bool VM_Initialise(char *model,char *port, char *initlength, GSM_ConnectionType connection, char *bindir, bool debug_mode, bool GSMInit,char *synchronizetime)
76 if (debug_mode == true) {
85 fprintf (stderr , "Initialising GSM\n");
87 if ((VM_GSMInitialise(model, port, initlength, connection, synchronizetime) != GE_NONE)) {
88 fprintf (stderr, _("VM_Initialise - VM_GSMInitialise failed!\n"));
95 if (VM_PtySetup(bindir) < 0) {
96 fprintf (stderr, _("VM_Initialise - VM_PtySetup failed!\n"));
100 if (ATEM_Initialise(PtyRDFD, PtyWRFD, model, port) != true) {
101 fprintf (stderr, _("VM_Initialise - ATEM_Initialise failed!\n"));
105 if (DP_Initialise(PtyRDFD, PtyWRFD) != true) {
106 fprintf (stderr, _("VM_Initialise - DP_Initialise failed!\n"));
111 /* Create and start thread, */
112 return VM_ThreadLoop();
118 static void VM_CharHandler(void);
119 extern GSM_Error N6110_SendStatusRequest(void);
121 bool VM_ThreadLoop(void)
125 struct timeval timeout;
127 /* Note we can't use signals here as they are already used
128 in the FBUS code. This may warrant changing the FBUS
129 code around sometime to use select instead to free up
130 the SIGIO handler for mainline code. */
135 } else { /* If we are in data mode, leave it to datapump to get the data */
138 FD_SET(PtyRDFD,&readfds);
139 FD_SET(device_portfd,&readfds);
141 timeout.tv_usec=0;/*500*1000;*/
143 res = select((device_portfd > PtyRDFD ? device_portfd : PtyRDFD)+1,
144 &readfds,NULL/*writefds*/,NULL/*exceptfds*/,&timeout);
147 case 0: /* Timeout */
149 N6110_SendStatusRequest();
156 perror("VM_ThreadLoop - select");
160 if (FD_ISSET(PtyRDFD,&readfds))
162 if (FD_ISSET(device_portfd,&readfds))
164 if (!FD_ISSET(PtyRDFD,&readfds) && !FD_ISSET(device_portfd,&readfds))
165 usleep(500); /* Probably the file has been closed */
173 /* Application should call VM_Terminate to shut down
174 the virtual modem thread */
175 void VM_Terminate(void)
183 static int VM_GetMasterPty(char **name);
185 /* Open pseudo tty interface and (in due course create a symlink
186 to be /dev/gnokii etc. ) */
188 static int VM_PtySetup(char *bindir)
192 char mgnokiidev[200];
201 strncpy(mgnokiidev, bindir, 200);
202 strcat(mgnokiidev, "/");
204 strncat(mgnokiidev, "mgnokiidev", 200 - strlen(bindir));
208 PtyRDFD = STDIN_FILENO;
209 PtyWRFD = STDOUT_FILENO;
213 PtyRDFD = VM_GetMasterPty(&slave_name);
215 fprintf (stderr, _("Couldn't open pty!\n"));
221 /* Check we haven't been installed setuid root for some reason
222 if so, don't create /dev/gnokii */
223 if (getuid() != geteuid()) {
224 fprintf(stderr, _("gnokiid should not be installed setuid root!\n"));
230 fprintf (stderr, _("Slave pty is %s, calling %s to create \"%s\".\n"), slave_name,
240 /* Create command line, something line ./mkgnokiidev ttyp0 */
241 sprintf(cmdline, "%s %s", mgnokiidev, slave_name);
243 /* And use system to call it. */
244 err = system (cmdline);
247 /* Remove symlink in case it already exists. Don't care if it fails. */
251 err = symlink(slave_name, GNOKII_DEV);
259 /* Handler called when characters received from serial port.
260 calls state machine code to process it. */
261 static void VM_CharHandler(void)
263 unsigned char buffer[255];
267 /* If we are in command mode, get the character, otherwise leave it */
269 if (CommandMode && ATEM_Initialised) {
271 res = read(PtyRDFD, buffer, 255);
273 /* A returned value of -1 means something serious has gone wrong - so quit!! */
274 /* Note that file closure etc. should have been dealt with in ThreadLoop */
277 // TerminateThread=true;
281 ATEM_HandleIncomingData(buffer, res);
285 /* Initialise GSM interface, returning GSM_Error as appropriate */
286 static GSM_Error VM_GSMInitialise(char *model, char *port, char *initlength, GSM_ConnectionType connection, char *synchronizetime)
291 /* Initialise the code for the GSM interface. */
293 error = GSM_Initialise(model,port, initlength, connection, RLP_DisplayF96Frame, synchronizetime);
295 if (error != GE_NONE) {
296 fprintf(stderr, _("GSM/FBUS init failed! (Unknown model ?). Quitting.\n"));
300 /* First (and important!) wait for GSM link to be active. We allow 10
303 while (count++ < 200 && *GSM_LinkOK == false) {
307 if (*GSM_LinkOK == false) {
308 fprintf (stderr, _("Hmmm... GSM_LinkOK never went true. Quitting. \n"));
316 Takes a double-indirect character pointer in which to put a slave
317 name, and returns an integer file descriptor. If it returns < 0, an
318 error has occurred. Otherwise, it has returned the master pty
319 file descriptor, and fills in *name with the name of the
320 corresponding slave pty. Once the slave pty has been opened,
321 you are responsible to free *name. Code is from Developling Linux
322 Applications by Troan and Johnson */
325 static int VM_GetMasterPty(char **name) {
327 #ifdef USE_UNIX98PTYS
330 master = open("/dev/ptmx", O_RDWR | O_NOCTTY | O_NONBLOCK);
332 err = grantpt(master);
333 err = err || unlockpt(master);
335 *name = ptsname(master);
340 #else /* USE_UNIX98PTYS */
342 /* default to returning error */
345 /* create a dummy name to fill in */
346 *name = strdup("/dev/ptyXX");
348 /* search for an unused pty */
349 for (i=0; i<16 && master <= 0; i++) {
350 for (j=0; j<16 && master <= 0; j++) {
351 static const char *ptyp8="pqrstuvwxyzPQRST";
352 static const char *ptyp9="0123456789abcdef";
354 (*name)[8] = ptyp8[i];
355 (*name)[9] = ptyp9[j];
356 /* open the master pty */
357 if ((master = open(*name, O_RDWR | O_NOCTTY | O_NONBLOCK )) < 0) {
358 if (errno == ENOENT) {
359 /* we are out of pty devices */
366 if ((master < 0) && (i == 16) && (j == 16)) {
367 /* must have tried every pty unsuccessfully */
372 /* By substituting a letter, we change the master pty
373 * name into the slave pty name.
377 #endif /* USE_UNIX98PTYS */