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