Moved all references to file descriptors out of the generic object
[wine] / server / serial.c
1 /*
2  * Server-side serial port communications management
3  *
4  * Copyright (C) 1998 Alexandre Julliard
5  * Copyright (C) 2000,2001 Mike McCormack
6  *
7  *
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
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 #include "config.h"
24 #include "wine/port.h"
25
26 #include <assert.h>
27 #include <fcntl.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <stdlib.h>
31 #include <sys/time.h>
32 #include <sys/types.h>
33 #include <time.h>
34 #include <unistd.h>
35 #ifdef HAVE_UTIME_H
36 #include <utime.h>
37 #endif
38 #ifdef HAVE_TERMIOS_H
39 #include <termios.h>
40 #endif
41 #ifdef HAVE_SYS_IOCTL_H
42 #include <sys/ioctl.h>
43 #endif
44
45 #include "winerror.h"
46 #include "winbase.h"
47
48 #include "file.h"
49 #include "handle.h"
50 #include "thread.h"
51 #include "request.h"
52 #include "async.h"
53
54 static void serial_dump( struct object *obj, int verbose );
55 static struct fd *serial_get_fd( struct object *obj );
56 static void serial_destroy(struct object *obj);
57
58 static int serial_get_poll_events( struct fd *fd );
59 static void serial_poll_event( struct fd *fd, int event );
60 static int serial_get_info( struct fd *fd, struct get_file_info_reply *reply, int *flags );
61 static int serial_flush( struct fd *fd );
62 static void serial_queue_async(struct fd *fd, void *ptr, unsigned int status, int type, int count);
63
64 struct serial
65 {
66     struct object       obj;
67     struct fd          *fd;
68     unsigned int        access;
69     unsigned int        attrib;
70
71     /* timeout values */
72     unsigned int        readinterval;
73     unsigned int        readconst;
74     unsigned int        readmult;
75     unsigned int        writeconst;
76     unsigned int        writemult;
77
78     unsigned int        eventmask;
79     unsigned int        commerror;
80
81     struct termios      original;
82
83     struct async_queue  read_q;
84     struct async_queue  write_q;
85     struct async_queue  wait_q;
86
87     /* FIXME: add dcb, comm status, handler module, sharing */
88 };
89
90 static const struct object_ops serial_ops =
91 {
92     sizeof(struct serial),        /* size */
93     serial_dump,                  /* dump */
94     default_fd_add_queue,         /* add_queue */
95     default_fd_remove_queue,      /* remove_queue */
96     default_fd_signaled,          /* signaled */
97     no_satisfied,                 /* satisfied */
98     serial_get_fd,                /* get_fd */
99     serial_destroy                /* destroy */
100 };
101
102 static const struct fd_ops serial_fd_ops =
103 {
104     serial_get_poll_events,       /* get_poll_events */
105     serial_poll_event,            /* poll_event */
106     serial_flush,                 /* flush */
107     serial_get_info,              /* get_file_info */
108     serial_queue_async            /* queue_async */
109 };
110
111 static struct serial *create_serial( const char *nameptr, size_t len, unsigned int access, int attributes )
112 {
113     struct serial *serial;
114     struct termios tios;
115     int fd, flags = 0;
116     char *name;
117
118     if (!(name = mem_alloc( len + 1 ))) return NULL;
119     memcpy( name, nameptr, len );
120     name[len] = 0;
121
122     switch(access & (GENERIC_READ | GENERIC_WRITE))
123     {
124     case GENERIC_READ:  flags |= O_RDONLY; break;
125     case GENERIC_WRITE: flags |= O_WRONLY; break;
126     case GENERIC_READ|GENERIC_WRITE: flags |= O_RDWR; break;
127     default: break;
128     }
129
130     flags |= O_NONBLOCK;
131
132     fd = open( name, flags );
133     free( name );
134     if (fd < 0)
135     {
136         file_set_error();
137         return NULL;
138     }
139
140     /* check its really a serial port */
141     if (tcgetattr(fd,&tios))
142     {
143         file_set_error();
144         close( fd );
145         return NULL;
146     }
147
148     /* set the fd back to blocking if necessary */
149     if( ! (attributes & FILE_FLAG_OVERLAPPED) )
150        if(0>fcntl(fd, F_SETFL, 0))
151            perror("fcntl");
152
153     if ((serial = alloc_object( &serial_ops )))
154     {
155         serial->attrib       = attributes;
156         serial->access       = access;
157         serial->readinterval = 0;
158         serial->readmult     = 0;
159         serial->readconst    = 0;
160         serial->writemult    = 0;
161         serial->writeconst   = 0;
162         serial->eventmask    = 0;
163         serial->commerror    = 0;
164         init_async_queue(&serial->read_q);
165         init_async_queue(&serial->write_q);
166         init_async_queue(&serial->wait_q);
167         if (!(serial->fd = alloc_fd( &serial_fd_ops, fd, &serial->obj )))
168         {
169             release_object( serial );
170             return NULL;
171         }
172     }
173     return serial;
174 }
175
176 static struct fd *serial_get_fd( struct object *obj )
177 {
178     struct serial *serial = (struct serial *)obj;
179     return (struct fd *)grab_object( serial->fd );
180 }
181
182 static void serial_destroy( struct object *obj)
183 {
184     struct serial *serial = (struct serial *)obj;
185
186     destroy_async_queue(&serial->read_q);
187     destroy_async_queue(&serial->write_q);
188     destroy_async_queue(&serial->wait_q);
189     if (serial->fd) release_object( serial->fd );
190 }
191
192 static void serial_dump( struct object *obj, int verbose )
193 {
194     struct serial *serial = (struct serial *)obj;
195     assert( obj->ops == &serial_ops );
196     fprintf( stderr, "Port fd=%p mask=%x\n", serial->fd, serial->eventmask );
197 }
198
199 static struct serial *get_serial_obj( struct process *process, obj_handle_t handle, unsigned int access )
200 {
201     return (struct serial *)get_handle_obj( process, handle, access, &serial_ops );
202 }
203
204 static int serial_get_poll_events( struct fd *fd )
205 {
206     struct serial *serial = get_fd_user( fd );
207     int events = 0;
208     assert( serial->obj.ops == &serial_ops );
209
210     if(IS_READY(serial->read_q))
211         events |= POLLIN;
212     if(IS_READY(serial->write_q))
213         events |= POLLOUT;
214     if(IS_READY(serial->wait_q))
215         events |= POLLIN;
216
217     /* fprintf(stderr,"poll events are %04x\n",events); */
218
219     return events;
220 }
221
222 static int serial_get_info( struct fd *fd, struct get_file_info_reply *reply, int *flags )
223 {
224     struct serial *serial = get_fd_user( fd );
225     assert( serial->obj.ops == &serial_ops );
226
227     if (reply)
228     {
229         reply->type        = FILE_TYPE_CHAR;
230         reply->attr        = 0;
231         reply->access_time = 0;
232         reply->write_time  = 0;
233         reply->size_high   = 0;
234         reply->size_low    = 0;
235         reply->links       = 0;
236         reply->index_high  = 0;
237         reply->index_low   = 0;
238         reply->serial      = 0;
239     }
240
241     *flags = 0;
242     if(serial->attrib & FILE_FLAG_OVERLAPPED)
243         *flags |= FD_FLAG_OVERLAPPED;
244     else if(!((serial->readinterval == MAXDWORD) &&
245               (serial->readmult == 0) && (serial->readconst == 0)) )
246         *flags |= FD_FLAG_TIMEOUT;
247
248     return FD_TYPE_DEFAULT;
249 }
250
251 static void serial_poll_event(struct fd *fd, int event)
252 {
253     struct serial *serial = get_fd_user( fd );
254
255     /* fprintf(stderr,"Poll event %02x\n",event); */
256
257     if(IS_READY(serial->read_q) && (POLLIN & event) )
258         async_notify(serial->read_q.head,STATUS_ALERTED);
259
260     if(IS_READY(serial->write_q) && (POLLOUT & event) )
261         async_notify(serial->write_q.head,STATUS_ALERTED);
262
263     if(IS_READY(serial->wait_q) && (POLLIN & event) )
264         async_notify(serial->wait_q.head,STATUS_ALERTED);
265
266     set_fd_events( fd, serial_get_poll_events(fd) );
267 }
268
269 static void serial_queue_async(struct fd *fd, void *ptr, unsigned int status, int type, int count)
270 {
271     struct serial *serial = get_fd_user( fd );
272     struct async_queue *q;
273     struct async *async;
274     int timeout;
275
276     assert(serial->obj.ops == &serial_ops);
277
278     switch(type)
279     {
280     case ASYNC_TYPE_READ:
281         q = &serial->read_q;
282         timeout = serial->readconst + serial->readmult*count;
283         break;
284     case ASYNC_TYPE_WAIT:
285         q = &serial->wait_q;
286         timeout = 0;
287         break;
288     case ASYNC_TYPE_WRITE:
289         q = &serial->write_q;
290         timeout = serial->writeconst + serial->writemult*count;
291         break;
292     default:
293         set_error(STATUS_INVALID_PARAMETER);
294         return;
295     }
296
297     async = find_async ( q, current, ptr );
298
299     if ( status == STATUS_PENDING )
300     {
301         int events;
302
303         if ( !async )
304             async = create_async ( &serial->obj, current, ptr );
305         if ( !async )
306             return;
307
308         async->status = STATUS_PENDING;
309         if(!async->q)
310         {
311             async_add_timeout(async,timeout);
312             async_insert(q, async);
313         }
314
315         /* Check if the new pending request can be served immediately */
316         events = check_fd_events( fd, serial_get_poll_events( fd ) );
317         if (events)
318         {
319             /* serial_poll_event() calls set_select_events() */
320             serial_poll_event( fd, events );
321             return;
322         }
323     }
324     else if ( async ) destroy_async ( async );
325     else set_error ( STATUS_INVALID_PARAMETER );
326
327     set_fd_events ( fd, serial_get_poll_events( fd ));
328 }
329
330 static int serial_flush( struct fd *fd )
331 {
332     /* MSDN says: If hFile is a handle to a communications device,
333      * the function only flushes the transmit buffer.
334      */
335     int ret = (tcflush( get_unix_fd(fd), TCOFLUSH ) != -1);
336     if (!ret) file_set_error();
337     return ret;
338 }
339
340 /* create a serial */
341 DECL_HANDLER(create_serial)
342 {
343     struct serial *serial;
344
345     reply->handle = 0;
346     if ((serial = create_serial( get_req_data(), get_req_data_size(), req->access, req->attributes )))
347     {
348         reply->handle = alloc_handle( current->process, serial, req->access, req->inherit );
349         release_object( serial );
350     }
351 }
352
353 DECL_HANDLER(get_serial_info)
354 {
355     struct serial *serial;
356
357     if ((serial = get_serial_obj( current->process, req->handle, 0 )))
358     {
359         /* timeouts */
360         reply->readinterval = serial->readinterval;
361         reply->readconst    = serial->readconst;
362         reply->readmult     = serial->readmult;
363         reply->writeconst   = serial->writeconst;
364         reply->writemult    = serial->writemult;
365
366         /* event mask */
367         reply->eventmask    = serial->eventmask;
368
369         /* comm port error status */
370         reply->commerror    = serial->commerror;
371
372         release_object( serial );
373     }
374 }
375
376 DECL_HANDLER(set_serial_info)
377 {
378     struct serial *serial;
379
380     if ((serial = get_serial_obj( current->process, req->handle, 0 )))
381     {
382         /* timeouts */
383         if(req->flags & SERIALINFO_SET_TIMEOUTS)
384         {
385             serial->readinterval = req->readinterval;
386             serial->readconst    = req->readconst;
387             serial->readmult     = req->readmult;
388             serial->writeconst   = req->writeconst;
389             serial->writemult    = req->writemult;
390         }
391
392         /* event mask */
393         if(req->flags & SERIALINFO_SET_MASK)
394         {
395             serial->eventmask = req->eventmask;
396             if(!serial->eventmask)
397             {
398                 while(serial->wait_q.head)
399                 {
400                     async_notify(serial->wait_q.head, STATUS_SUCCESS);
401                     destroy_async(serial->wait_q.head);
402                 }
403             }
404         }
405
406         /* comm port error status */
407         if(req->flags & SERIALINFO_SET_ERROR)
408         {
409             serial->commerror = req->commerror;
410         }
411
412         release_object( serial );
413     }
414 }