blob: 587fee1ce890e0b77a4fcc53671296c953816596 [file] [log] [blame]
Mike McCormack44b5bf52000-09-07 18:39:51 +00001/*
2 * Server-side serial port communications management
3 *
4 * Copyright (C) 1998 Alexandre Julliard
Mike McCormack6f011c02001-12-20 00:07:05 +00005 * Copyright (C) 2000,2001 Mike McCormack
Mike McCormack44b5bf52000-09-07 18:39:51 +00006 *
Alexandre Julliard0799c1a2002-03-09 23:29:33 +00007 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
Jonathan Ernst360a3f92006-05-18 14:49:52 +020020 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
Mike McCormack44b5bf52000-09-07 18:39:51 +000021 */
22
23#include "config.h"
Martin Wilckff1f3202002-04-26 18:31:19 +000024#include "wine/port.h"
Mike McCormack44b5bf52000-09-07 18:39:51 +000025
26#include <assert.h>
27#include <fcntl.h>
Alexandre Julliarde37c6e12003-09-05 23:08:26 +000028#include <stdarg.h>
Mike McCormack44b5bf52000-09-07 18:39:51 +000029#include <stdio.h>
30#include <string.h>
31#include <stdlib.h>
Mike McCormack44b5bf52000-09-07 18:39:51 +000032#include <sys/time.h>
33#include <sys/types.h>
34#include <time.h>
35#include <unistd.h>
Steven Edwards037c8a12003-02-11 22:27:13 +000036#ifdef HAVE_UTIME_H
Mike McCormack44b5bf52000-09-07 18:39:51 +000037#include <utime.h>
Steven Edwards037c8a12003-02-11 22:27:13 +000038#endif
39#ifdef HAVE_TERMIOS_H
Mike McCormack44b5bf52000-09-07 18:39:51 +000040#include <termios.h>
Steven Edwards037c8a12003-02-11 22:27:13 +000041#endif
42#ifdef HAVE_SYS_IOCTL_H
Mike McCormack44b5bf52000-09-07 18:39:51 +000043#include <sys/ioctl.h>
Steven Edwards037c8a12003-02-11 22:27:13 +000044#endif
Steven Edwards57279182005-03-04 12:38:36 +000045#ifdef HAVE_POLL_H
46#include <poll.h>
47#endif
Mike McCormack44b5bf52000-09-07 18:39:51 +000048
Ge van Geldorp1a1583a2005-11-28 17:32:54 +010049#include "ntstatus.h"
50#define WIN32_NO_STATUS
Alexandre Julliarde37c6e12003-09-05 23:08:26 +000051#include "windef.h"
Alexandre Julliardadc06102004-03-18 04:08:48 +000052#include "winternl.h"
Mike McCormack44b5bf52000-09-07 18:39:51 +000053
Alexandre Julliard863637b2003-01-30 00:26:44 +000054#include "file.h"
Mike McCormack44b5bf52000-09-07 18:39:51 +000055#include "handle.h"
56#include "thread.h"
57#include "request.h"
58
59static void serial_dump( struct object *obj, int verbose );
Alexandre Julliarde66207e2003-02-19 00:33:32 +000060static struct fd *serial_get_fd( struct object *obj );
Alexandre Julliardcf27a7f2003-02-14 20:27:09 +000061static void serial_destroy(struct object *obj);
62
Alexandre Julliard7a9363a2007-04-10 22:26:23 +020063static enum server_fd_type serial_get_fd_type( struct fd *fd );
Alexandre Julliarddf651872007-03-27 16:51:44 +020064static void serial_flush( struct fd *fd, struct event **event );
Alexandre Julliard111610c2007-03-20 20:21:12 +010065static void serial_queue_async( struct fd *fd, const async_data_t *data, int type, int count );
Mike McCormack44b5bf52000-09-07 18:39:51 +000066
67struct serial
68{
69 struct object obj;
Alexandre Julliarde66207e2003-02-19 00:33:32 +000070 struct fd *fd;
Mike McCormack44b5bf52000-09-07 18:39:51 +000071
72 /* timeout values */
73 unsigned int readinterval;
74 unsigned int readconst;
75 unsigned int readmult;
76 unsigned int writeconst;
77 unsigned int writemult;
78
79 unsigned int eventmask;
Mike McCormack44b5bf52000-09-07 18:39:51 +000080
81 struct termios original;
82
83 /* FIXME: add dcb, comm status, handler module, sharing */
84};
85
86static const struct object_ops serial_ops =
87{
88 sizeof(struct serial), /* size */
89 serial_dump, /* dump */
Alexandre Julliard8382eb02007-12-05 18:16:42 +010090 no_get_type, /* get_type */
Alexandre Julliardba896e72007-04-04 19:39:29 +020091 add_queue, /* add_queue */
92 remove_queue, /* remove_queue */
Alexandre Julliard863637b2003-01-30 00:26:44 +000093 default_fd_signaled, /* signaled */
Mike McCormack44b5bf52000-09-07 18:39:51 +000094 no_satisfied, /* satisfied */
Mike McCormackf92fff62005-04-24 17:35:52 +000095 no_signal, /* signal */
Alexandre Julliarde66207e2003-02-19 00:33:32 +000096 serial_get_fd, /* get_fd */
Alexandre Julliard24001e82007-10-02 14:20:15 +020097 default_fd_map_access, /* map_access */
Rob Shearmanc1707d82007-10-03 13:10:37 +010098 default_get_sd, /* get_sd */
99 default_set_sd, /* set_sd */
Vitaliy Margolenbaffcb92005-11-22 14:55:42 +0000100 no_lookup_name, /* lookup_name */
Alexandre Julliard7e71c1d2007-03-22 11:44:29 +0100101 no_open_file, /* open_file */
Alexandre Julliard715d78e2006-11-02 20:52:22 +0100102 fd_close_handle, /* close_handle */
Alexandre Julliardcf27a7f2003-02-14 20:27:09 +0000103 serial_destroy /* destroy */
Alexandre Julliard863637b2003-01-30 00:26:44 +0000104};
105
106static const struct fd_ops serial_fd_ops =
107{
Alexandre Julliardfd6f83d2007-04-02 12:49:09 +0200108 default_fd_get_poll_events, /* get_poll_events */
109 default_poll_event, /* poll_event */
Marcus Meissner1e54c1f2002-07-16 01:20:38 +0000110 serial_flush, /* flush */
Eric Pouechc1d35ba2010-08-28 13:14:37 +0200111 serial_get_fd_type, /* get_fd_type */
Alexandre Julliard63571432007-04-16 14:45:03 +0200112 default_fd_ioctl, /* ioctl */
Eric Pouech46344472005-01-14 19:54:38 +0000113 serial_queue_async, /* queue_async */
Alexandre Julliard72bff2e2007-04-10 17:07:27 +0200114 default_fd_reselect_async, /* reselect_async */
Alexandre Julliardfd6f83d2007-04-02 12:49:09 +0200115 default_fd_cancel_async /* cancel_async */
Mike McCormack44b5bf52000-09-07 18:39:51 +0000116};
117
Alexandre Julliardadc06102004-03-18 04:08:48 +0000118/* check if the given fd is a serial port */
119int is_serial_fd( struct fd *fd )
120{
121 struct termios tios;
122
123 return !tcgetattr( get_unix_fd(fd), &tios );
124}
125
126/* create a serial object for a given fd */
Alexandre Julliardf85437c2007-04-10 22:25:07 +0200127struct object *create_serial( struct fd *fd )
Alexandre Julliard57f05e12000-10-15 00:40:25 +0000128{
129 struct serial *serial;
Mike McCormack568c67e2001-10-08 20:40:57 +0000130
Alexandre Julliardab5ca5c2006-01-24 13:31:48 +0100131 if (!(serial = alloc_object( &serial_ops ))) return NULL;
132
Alexandre Julliard580da242003-03-12 22:38:14 +0000133 serial->readinterval = 0;
134 serial->readmult = 0;
135 serial->readconst = 0;
136 serial->writemult = 0;
137 serial->writeconst = 0;
138 serial->eventmask = 0;
Alexandre Julliardab5ca5c2006-01-24 13:31:48 +0100139 serial->fd = (struct fd *)grab_object( fd );
140 set_fd_user( fd, &serial_fd_ops, &serial->obj );
Alexandre Julliardadc06102004-03-18 04:08:48 +0000141 return &serial->obj;
Alexandre Julliard57f05e12000-10-15 00:40:25 +0000142}
143
Alexandre Julliarde66207e2003-02-19 00:33:32 +0000144static struct fd *serial_get_fd( struct object *obj )
145{
146 struct serial *serial = (struct serial *)obj;
147 return (struct fd *)grab_object( serial->fd );
148}
149
Alexandre Julliardcf27a7f2003-02-14 20:27:09 +0000150static void serial_destroy( struct object *obj)
Mike McCormack6f011c02001-12-20 00:07:05 +0000151{
152 struct serial *serial = (struct serial *)obj;
Alexandre Julliardfd6f83d2007-04-02 12:49:09 +0200153 release_object( serial->fd );
Mike McCormack6f011c02001-12-20 00:07:05 +0000154}
155
Mike McCormack44b5bf52000-09-07 18:39:51 +0000156static void serial_dump( struct object *obj, int verbose )
157{
158 struct serial *serial = (struct serial *)obj;
159 assert( obj->ops == &serial_ops );
Alexandre Julliarde66207e2003-02-19 00:33:32 +0000160 fprintf( stderr, "Port fd=%p mask=%x\n", serial->fd, serial->eventmask );
Mike McCormack44b5bf52000-09-07 18:39:51 +0000161}
162
Alexandre Julliarde66207e2003-02-19 00:33:32 +0000163static struct serial *get_serial_obj( struct process *process, obj_handle_t handle, unsigned int access )
Mike McCormack44b5bf52000-09-07 18:39:51 +0000164{
165 return (struct serial *)get_handle_obj( process, handle, access, &serial_ops );
166}
167
Alexandre Julliard7a9363a2007-04-10 22:26:23 +0200168static enum server_fd_type serial_get_fd_type( struct fd *fd )
Mike McCormack44b5bf52000-09-07 18:39:51 +0000169{
Alexandre Julliard89304272006-11-20 14:14:04 +0100170 return FD_TYPE_SERIAL;
Mike McCormack44b5bf52000-09-07 18:39:51 +0000171}
172
Alexandre Julliard111610c2007-03-20 20:21:12 +0100173static void serial_queue_async( struct fd *fd, const async_data_t *data, int type, int count )
Mike McCormack6f011c02001-12-20 00:07:05 +0000174{
Alexandre Julliardcf27a7f2003-02-14 20:27:09 +0000175 struct serial *serial = get_fd_user( fd );
Alexandre Julliardaaf477f2007-04-17 20:08:59 +0200176 timeout_t timeout = 0;
Alexandre Julliard0aae1ca2007-04-02 20:41:59 +0200177 struct async *async;
Mike McCormack6f011c02001-12-20 00:07:05 +0000178
Alexandre Julliardcf27a7f2003-02-14 20:27:09 +0000179 assert(serial->obj.ops == &serial_ops);
Mike McCormack1eac1912000-11-13 19:27:21 +0000180
Eric Pouech46344472005-01-14 19:54:38 +0000181 switch (type)
Mike McCormack1eac1912000-11-13 19:27:21 +0000182 {
183 case ASYNC_TYPE_READ:
Alexandre Julliardaaf477f2007-04-17 20:08:59 +0200184 timeout = serial->readconst + (timeout_t)serial->readmult*count;
Mike McCormack6f011c02001-12-20 00:07:05 +0000185 break;
Mike McCormack1eac1912000-11-13 19:27:21 +0000186 case ASYNC_TYPE_WRITE:
Alexandre Julliardaaf477f2007-04-17 20:08:59 +0200187 timeout = serial->writeconst + (timeout_t)serial->writemult*count;
Mike McCormack6f011c02001-12-20 00:07:05 +0000188 break;
Mike McCormack1eac1912000-11-13 19:27:21 +0000189 }
Mike McCormack6f011c02001-12-20 00:07:05 +0000190
Alexandre Julliard9ed42d22008-12-26 12:27:48 +0100191 if ((async = fd_queue_async( fd, data, type )))
Alexandre Julliard0aae1ca2007-04-02 20:41:59 +0200192 {
Alexandre Julliardaaf477f2007-04-17 20:08:59 +0200193 if (timeout) async_set_timeout( async, timeout * -10000, STATUS_TIMEOUT );
Alexandre Julliard0aae1ca2007-04-02 20:41:59 +0200194 release_object( async );
195 set_error( STATUS_PENDING );
196 }
Mike McCormack6f011c02001-12-20 00:07:05 +0000197}
Mike McCormack1eac1912000-11-13 19:27:21 +0000198
Alexandre Julliarddf651872007-03-27 16:51:44 +0200199static void serial_flush( struct fd *fd, struct event **event )
Marcus Meissner1e54c1f2002-07-16 01:20:38 +0000200{
Marcus Meissner1e54c1f2002-07-16 01:20:38 +0000201 /* MSDN says: If hFile is a handle to a communications device,
202 * the function only flushes the transmit buffer.
203 */
Alexandre Julliarddf651872007-03-27 16:51:44 +0200204 if (tcflush( get_unix_fd(fd), TCOFLUSH ) == -1) file_set_error();
Marcus Meissner1e54c1f2002-07-16 01:20:38 +0000205}
206
Mike McCormack654fcc72000-09-16 20:55:12 +0000207DECL_HANDLER(get_serial_info)
208{
209 struct serial *serial;
210
211 if ((serial = get_serial_obj( current->process, req->handle, 0 )))
212 {
213 /* timeouts */
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000214 reply->readinterval = serial->readinterval;
215 reply->readconst = serial->readconst;
216 reply->readmult = serial->readmult;
217 reply->writeconst = serial->writeconst;
218 reply->writemult = serial->writemult;
Mike McCormack654fcc72000-09-16 20:55:12 +0000219
220 /* event mask */
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000221 reply->eventmask = serial->eventmask;
Mike McCormack654fcc72000-09-16 20:55:12 +0000222
Mike McCormack654fcc72000-09-16 20:55:12 +0000223 release_object( serial );
224 }
225}
226
227DECL_HANDLER(set_serial_info)
228{
229 struct serial *serial;
230
231 if ((serial = get_serial_obj( current->process, req->handle, 0 )))
232 {
233 /* timeouts */
Eric Pouech46344472005-01-14 19:54:38 +0000234 if (req->flags & SERIALINFO_SET_TIMEOUTS)
Mike McCormack654fcc72000-09-16 20:55:12 +0000235 {
236 serial->readinterval = req->readinterval;
237 serial->readconst = req->readconst;
238 serial->readmult = req->readmult;
239 serial->writeconst = req->writeconst;
240 serial->writemult = req->writemult;
241 }
242
243 /* event mask */
Eric Pouech46344472005-01-14 19:54:38 +0000244 if (req->flags & SERIALINFO_SET_MASK)
Mike McCormack654fcc72000-09-16 20:55:12 +0000245 {
246 serial->eventmask = req->eventmask;
Eric Pouech46344472005-01-14 19:54:38 +0000247 if (!serial->eventmask)
Mike McCormack32521ab2002-03-12 19:19:57 +0000248 {
Alexandre Julliarddf09ac52007-04-02 20:09:29 +0200249 fd_async_wake_up( serial->fd, ASYNC_TYPE_WAIT, STATUS_SUCCESS );
Mike McCormack32521ab2002-03-12 19:19:57 +0000250 }
Mike McCormack654fcc72000-09-16 20:55:12 +0000251 }
252
Mike McCormack654fcc72000-09-16 20:55:12 +0000253 release_object( serial );
254 }
255}