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