6 A Linux/Unix toolset and driver for Nokia mobile phones.
8 Copyright (C) 1999, 2000 Hugh Blemings & Pavel Janík ml.
10 Released under the terms of the GNU GPL, see file COPYING for more details.
12 This file provides a virtual modem interface to the GSM phone by calling
13 code in gsm-api.c, at-emulator.c and datapump.c. The code here provides
14 the overall framework and coordinates switching between command mode
15 (AT-emulator) and "online" mode where the data pump code translates data
16 from/to the GSM handset and the modem data/fax stream.
19 Revision 1.1.1.1 2001/11/25 21:59:08 short
20 :pserver:cvs@pserver.samba.org:/cvsroot - gnokii - Sun Nov 25 22:56 CET 2001
22 Revision 1.4 2001/04/14 23:23:43 pkot
23 Fixed problems with grantpt
25 Revision 1.3 2001/03/21 23:36:04 chris
26 Added the statemachine
27 This will break gnokii --identify and --monitor except for 6210/7110
29 Revision 1.2 2001/02/21 19:57:02 chris
30 More fiddling with the directory layout
32 Revision 1.1 2001/02/16 14:29:51 chris
33 Restructure of common/. Fixed a problem in fbus-phonet.c
34 Lots of dprintfs for Marcin
35 Any size xpm can now be loaded (eg for 7110 startup logos)
36 nk7110 code detects 7110/6210 and alters startup logo size to suit
37 Moved Marcin's extended phonebook code into gnokii.c
39 Revision 1.5 2001/01/08 15:11:37 pkot
40 Documentation updates.
41 Fixed some bugs and removed FIXMEs.
42 We need to move some stuff from configure.in to aclocal.m4
44 Revision 1.4 2001/01/02 09:09:09 pkot
45 Misc fixes and updates.
47 Revision 1.3 2000/12/27 10:54:14 pkot
48 Added Unix98 PTYs support (Michael Mráka).
57 /* This is the right way to include stdlib with __USE_XOPEN defined */
59 # define _XOPEN_SOURCE 500
60 # include <features.h>
70 #include <sys/types.h>
79 #include "gsm-common.h"
80 #include "data/at-emulator.h"
81 #include "data/datapump.h"
82 #include "data/virtmodem.h"
83 #include "data/rlp-common.h"
85 /* Global variables */
87 extern bool TerminateThread;
92 int PtyRDFD; /* File descriptor for reading and writing to/from */
93 int PtyWRFD; /* pty interface - only different in debug mode. */
95 bool UseSTDIO; /* Use STDIO for debugging purposes instead of pty */
99 bool RequestTerminate;
102 /* If initialised in debug mode, stdin/out is used instead
103 of ptys for interface. */
104 bool VM_Initialise(char *model,char *port, char *initlength, GSM_ConnectionType connection, char *bindir, bool debug_mode, bool GSMInit)
110 RequestTerminate = false;
112 if (debug_mode == true) {
121 fprintf (stderr , "Initialising GSM\n");
123 if ((VM_GSMInitialise(model, port, initlength, connection) != GE_NONE)) {
124 fprintf (stderr, _("VM_Initialise - VM_GSMInitialise failed!\n"));
130 if (VM_PtySetup(bindir) < 0) {
131 fprintf (stderr, _("VM_Initialise - VM_PtySetup failed!\n"));
135 if (ATEM_Initialise(PtyRDFD, PtyWRFD, model, port) != true) {
136 fprintf (stderr, _("VM_Initialise - ATEM_Initialise failed!\n"));
140 if (DP_Initialise(PtyRDFD, PtyWRFD) != true) {
141 fprintf (stderr, _("VM_Initialise - DP_Initialise failed!\n"));
145 /* Create and start thread, */
146 rtn = pthread_create(&Thread, NULL, (void *) VM_ThreadLoop, (void *)NULL);
148 if (rtn == EAGAIN || rtn == EINVAL) {
154 void VM_ThreadLoop(void)
159 /* Note we can't use signals here as they are already used
160 in the FBUS code. This may warrant changing the FBUS
161 code around sometime to use select instead to free up
162 the SIGIO handler for mainline code. */
167 while (!RequestTerminate) {
170 } else { /* If we are in data mode, leave it to datapump to get the data */
172 res=poll(&ufds,1,500);
175 case 0: /* Timeout */
179 perror("VM_ThreadLoop - select");
183 if (ufds.revents==POLLIN) {
185 } else usleep(500); /* Probably the file has been closed */
193 /* Application should call VM_Terminate to shut down
194 the virtual modem thread */
195 void VM_Terminate(void)
198 /* Request termination of thread */
199 RequestTerminate = true;
201 /* Now wait for thread to terminate. */
202 pthread_join(Thread, NULL);
210 /* Open pseudo tty interface and (in due course create a symlink
211 to be /dev/gnokii etc. ) */
213 int VM_PtySetup(char *bindir)
216 char mgnokiidev[200];
221 strncpy(mgnokiidev, bindir, 200);
222 strcat(mgnokiidev, "/");
224 strncat(mgnokiidev, "mgnokiidev", 200 - strlen(bindir));
227 PtyRDFD = STDIN_FILENO;
228 PtyWRFD = STDOUT_FILENO;
232 PtyRDFD = VM_GetMasterPty(&slave_name);
234 fprintf (stderr, _("Couldn't open pty!\n"));
239 /* Check we haven't been installed setuid root for some reason
240 if so, don't create /dev/gnokii */
241 if (getuid() != geteuid()) {
242 fprintf(stderr, _("gnokiid should not be installed setuid root!\n"));
247 fprintf (stderr, _("Slave pty is %s, calling %s to create /dev/gnokii.\n"), slave_name, mgnokiidev);
250 /* Create command line, something line ./mkgnokiidev ttyp0 */
251 sprintf(cmdline, "%s %s", mgnokiidev, slave_name);
253 /* And use system to call it. */
254 err = system (cmdline);
260 /* Handler called when characters received from serial port.
261 calls state machine code to process it. */
262 void VM_CharHandler(void)
264 unsigned char buffer[255];
268 /* If we are in command mode, get the character, otherwise leave it */
270 if (CommandMode && ATEM_Initialised) {
272 res = read(PtyRDFD, buffer, 255);
274 /* A returned value of -1 means something serious has gone wrong - so quit!! */
275 /* Note that file closure etc. should have been dealt with in ThreadLoop */
278 TerminateThread=true;
282 ATEM_HandleIncomingData(buffer, res);
286 /* Initialise GSM interface, returning GSM_Error as appropriate */
287 GSM_Error VM_GSMInitialise(char *model, char *port, char *initlength, GSM_ConnectionType connection)
291 static GSM_Statemachine sm;
293 /* Initialise the code for the GSM interface. */
295 error = GSM_Initialise(model,port, initlength, connection, RLP_DisplayF96Frame, &sm);
297 if (error != GE_NONE) {
298 fprintf(stderr, _("GSM/FBUS init failed! (Unknown model ?). Quitting.\n"));
302 /* First (and important!) wait for GSM link to be active. We allow 10
305 while (count++ < 200 && *GSM_LinkOK == false) {
309 if (*GSM_LinkOK == false) {
310 fprintf (stderr, _("Hmmm... GSM_LinkOK never went true. Quitting. \n"));
318 Takes a double-indirect character pointer in which to put a slave
319 name, and returns an integer file descriptor. If it returns < 0, an
320 error has occurred. Otherwise, it has returned the master pty
321 file descriptor, and fills in *name with the name of the
322 corresponding slave pty. Once the slave pty has been opened,
323 you are responsible to free *name. Code is from Developling Linux
324 Applications by Troan and Johnson */
327 int VM_GetMasterPty(char **name) {
329 #ifdef USE_UNIX98PTYS
332 master = open("/dev/ptmx", O_RDWR | O_NOCTTY | O_NONBLOCK);
334 err = grantpt(master);
335 err = err || unlockpt(master);
337 *name = ptsname(master);
342 #else /* USE_UNIX98PTYS */
344 /* default to returning error */
347 /* create a dummy name to fill in */
348 *name = strdup("/dev/ptyXX");
350 /* search for an unused pty */
351 for (i=0; i<16 && master <= 0; i++) {
352 for (j=0; j<16 && master <= 0; j++) {
353 (*name)[8] = "pqrstuvwxyzPQRST"[i];
354 (*name)[9] = "0123456789abcdef"[j];
355 /* open the master pty */
356 if ((master = open(*name, O_RDWR | O_NOCTTY | O_NONBLOCK )) < 0) {
357 if (errno == ENOENT) {
358 /* we are out of pty devices */
365 if ((master < 0) && (i == 16) && (j == 16)) {
366 /* must have tried every pty unsuccessfully */
371 /* By substituting a letter, we change the master pty
372 * name into the slave pty name.
376 #endif /* USE_UNIX98PTYS */