e9dcb17728cf3847429e45cae39d7a93ef0fdf0a
[gnokii.git] / common / devices / unixserial.c
1 /*
2   
3   $Id$
4
5   G N O K I I
6
7   A Linux/Unix toolset and driver for Nokia mobile phones.
8
9   Copyright (C) 1999, 2000 Hugh Blemings & Pavel Janík ml.
10
11   Released under the terms of the GNU GPL, see file COPYING for more details.
12
13   $Log$
14   Revision 1.1.1.2  2001/11/27 22:01:15  short
15   :pserver:cvs@pserver.samba.org:/cvsroot - gnokii - Tue Nov 27 22:58 CET 2001
16
17   Revision 1.11  2001/11/27 12:19:01  pkot
18   Cleanup, indentation, ANSI complaint preprocesor symbols (Jan Kratochvil, me)
19
20   Revision 1.10  2001/11/14 10:46:12  pkot
21   Small cleanup with __unices__
22
23   Revision 1.9  2001/09/14 12:15:28  pkot
24   Cleanups from 0.3.3 (part1)
25
26   Revision 1.8  2001/08/20 23:27:37  pkot
27   Add hardware shakehand to the link layer (Manfred Jonsson)
28
29   Revision 1.7  2001/07/03 00:03:36  pkot
30   Small fixes to let gnokii compile and work under solaris (thanks to Artur Kubiak)
31
32   Revision 1.6  2001/03/21 23:36:04  chris
33   Added the statemachine
34   This will break gnokii --identify and --monitor except for 6210/7110
35
36   Revision 1.5  2001/03/19 23:43:46  pkot
37   Solaris/ *BSD '#if defined' cleanup
38
39   Revision 1.4  2001/03/13 01:21:38  pkot
40   *BSD updates (Bert Driehuis)
41
42   Revision 1.3  2001/03/06 22:27:46  pkot
43   Misc docs and Makefiles updates and cleanups
44
45   Revision 1.2  2001/02/21 19:57:05  chris
46   More fiddling with the directory layout
47
48 */
49
50 #include "misc.h"
51
52 /* Do not compile this file under Win32 systems. */
53
54 #ifndef WIN32
55
56 #include <stdio.h>
57 #include <fcntl.h>
58 #include <sys/ioctl.h>
59 #include <string.h>
60
61 #include <termios.h>
62 #include "devices/unixserial.h"
63
64 #ifdef HAVE_SYS_IOCTL_COMPAT_H
65 #  include <sys/ioctl_compat.h>
66 #endif
67
68 #ifdef HAVE_SYS_SELECT_H
69 #  include <sys/select.h>
70 #endif
71
72 /* If the target operating system does not have cfsetspeed, we can emulate
73    it. */
74
75 #ifndef HAVE_CFSETSPEED
76 #  if defined(HAVE_CFSETISPEED) && defined(HAVE_CFSETOSPEED)
77 #    define cfsetspeed(t, speed) \
78             (cfsetispeed(t, speed) || cfsetospeed(t, speed))
79 #  else
80 static int cfsetspeed(struct termios *t, int speed)
81 {
82 #    ifdef HAVE_TERMIOS_CSPEED
83         t->c_ispeed = speed;
84         t->c_ospeed = speed;
85 #    else
86         t->c_cflag |= speed;
87 #    endif                      /* HAVE_TERMIOS_CSPEED */
88         return 0;
89 }
90 #  endif                        /* HAVE_CFSETISPEED && HAVE_CFSETOSPEED */
91 #endif                          /* HAVE_CFSETSPEED */
92
93 #ifndef O_NONBLOCK
94 #  define O_NONBLOCK  0
95 #endif
96
97 /* Structure to backup the setting of the terminal. */
98 struct termios serial_termios;
99
100 /* Open the serial port and store the settings. */
101 int serial_open(__const char *__file, int __oflag)
102 {
103         int __fd;
104         int retcode;
105
106         __fd = open(__file, __oflag);
107         if (__fd == -1) {
108                 perror("Gnokii serial_open: open");
109                 return (-1);
110         }
111
112         retcode = tcgetattr(__fd, &serial_termios);
113         if (retcode == -1) {
114                 perror("Gnokii serial_open:tcgetattr");
115                 /* Don't call serial_close since serial_termios is not valid */
116                 close(__fd);
117                 return (-1);
118         }
119
120         return __fd;
121 }
122
123 /* Close the serial port and restore old settings. */
124 int serial_close(int __fd)
125 {
126         if (__fd >= 0)
127                 tcsetattr(__fd, TCSANOW, &serial_termios);
128
129         return (close(__fd));
130 }
131
132 /* Open a device with standard options. */
133 int serial_opendevice(__const char *__file, int __with_odd_parity,
134                       int __with_async, int __with_hw_handshake)
135 {
136         int fd;
137         int retcode;
138         struct termios tp;
139
140         /* Open device */
141         fd = serial_open(__file, O_RDWR | O_NOCTTY | O_NONBLOCK);
142
143         if (fd < 0) return fd;
144
145         /* Allow process/thread to receive SIGIO */
146 #if !(__unices__)
147         retcode = fcntl(fd, F_SETOWN, getpid());
148         if (retcode == -1) {
149                 perror("Gnokii serial_opendevice: fnctl(F_SETOWN)");
150                 serial_close(fd);
151                 return (-1);
152         }
153 #endif
154
155         /* Make filedescriptor asynchronous. */
156         if (__with_async) {
157                 retcode = fcntl(fd, F_SETFL, FASYNC);
158                 if (retcode == -1) {
159                         perror("Gnokii serial_opendevice: fnctl(F_SETFL)");
160                         serial_close(fd);
161                         return (-1);
162                 }
163         }
164
165         /* Initialise the port settings */
166         memcpy(&tp, &serial_termios, sizeof(struct termios));
167
168         /* Set port settings for canonical input processing */
169         tp.c_cflag = B0 | CS8 | CLOCAL | CREAD;
170         if (__with_odd_parity) {
171                 tp.c_cflag |= (PARENB | PARODD);
172                 tp.c_iflag = 0;
173         } else
174                 tp.c_iflag = IGNPAR;
175         if (__with_hw_handshake)
176                 tp.c_cflag |= CRTSCTS;
177         else
178                 tp.c_cflag &= ~CRTSCTS;
179
180         tp.c_oflag = 0;
181         tp.c_lflag = 0;
182         tp.c_cc[VMIN] = 1;
183         tp.c_cc[VTIME] = 0;
184
185         retcode = tcflush(fd, TCIFLUSH);
186         if (retcode == -1) {
187                 perror("Gnokii serial_opendevice: tcflush");
188                 serial_close(fd);
189                 return (-1);
190         }
191
192         retcode = tcsetattr(fd, TCSANOW, &tp);
193         if (retcode == -1) {
194                 perror("Gnokii serial_opendevice: tcsetattr");
195                 serial_close(fd);
196                 return (-1);
197         }
198
199         return fd;
200 }
201
202 /* Set the DTR and RTS bit of the serial device. */
203 void serial_setdtrrts(int __fd, int __dtr, int __rts)
204 {
205         unsigned int flags;
206
207         flags = TIOCM_DTR;
208
209         if (__dtr)
210                 ioctl(__fd, TIOCMBIS, &flags);
211         else
212                 ioctl(__fd, TIOCMBIC, &flags);
213
214         flags = TIOCM_RTS;
215
216         if (__rts)
217                 ioctl(__fd, TIOCMBIS, &flags);
218         else
219                 ioctl(__fd, TIOCMBIC, &flags);
220 }
221
222
223 int serial_select(int fd, struct timeval *timeout)
224 {
225         fd_set readfds;
226
227         FD_ZERO(&readfds);
228         FD_SET(fd, &readfds);
229
230         return (select(fd + 1, &readfds, NULL, NULL, timeout));
231 }
232
233
234 /* Change the speed of the serial device. */
235 void serial_changespeed(int __fd, int __speed)
236 {
237 #ifndef SGTTY
238         struct termios t;
239 #else
240         struct sgttyb t;
241 #endif
242         int speed = B9600;
243
244         switch (__speed) {
245         case 9600:
246                 speed = B9600;
247                 break;
248         case 19200:
249                 speed = B19200;
250                 break;
251         case 38400:
252                 speed = B38400;
253                 break;
254         case 57600:
255                 speed = B57600;
256                 break;
257         case 115200:
258                 speed = B115200;
259                 break;
260         }
261
262 #ifndef SGTTY
263         tcgetattr(__fd, &t);
264
265         // This is not needed! We set up the speed via cfsetspeed
266         //  t.c_cflag &= ~CBAUD;
267         //  t.c_cflag |= speed;
268         if (cfsetspeed(&t, speed) == -1)
269                 dprintf(_("Serial port speed setting failed\n"));
270
271         tcsetattr(__fd, TCSADRAIN, &t);
272 #else
273         ioctl(__fd, TIOCGETP, &t);
274
275         t.sg_ispeed = speed;
276         t.sg_ospeed = speed;
277
278         ioctl(__fd, TIOCSETN, &t);
279 #endif
280 }
281
282 /* Read from serial device. */
283 size_t serial_read(int __fd, __ptr_t __buf, size_t __nbytes)
284 {
285         return (read(__fd, __buf, __nbytes));
286 }
287
288 /* Write to serial device. */
289 size_t serial_write(int __fd, __const __ptr_t __buf, size_t __n)
290 {
291         return (write(__fd, __buf, __n));
292 }
293
294 #endif /* WIN32 */