Replace some magic numbers with symbols.
[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, struct event **event );
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         close( fd );
156         return NULL;
157     }
158     serial->attrib       = attributes;
159     serial->access       = access;
160     serial->readinterval = 0;
161     serial->readmult     = 0;
162     serial->readconst    = 0;
163     serial->writemult    = 0;
164     serial->writeconst   = 0;
165     serial->eventmask    = 0;
166     serial->commerror    = 0;
167     init_async_queue(&serial->read_q);
168     init_async_queue(&serial->write_q);
169     init_async_queue(&serial->wait_q);
170     if (!(serial->fd = create_anonymous_fd( &serial_fd_ops, fd, &serial->obj )))
171     {
172         release_object( serial );
173         return NULL;
174     }
175     return serial;
176 }
177
178 static struct fd *serial_get_fd( struct object *obj )
179 {
180     struct serial *serial = (struct serial *)obj;
181     return (struct fd *)grab_object( serial->fd );
182 }
183
184 static void serial_destroy( struct object *obj)
185 {
186     struct serial *serial = (struct serial *)obj;
187
188     destroy_async_queue(&serial->read_q);
189     destroy_async_queue(&serial->write_q);
190     destroy_async_queue(&serial->wait_q);
191     if (serial->fd) release_object( serial->fd );
192 }
193
194 static void serial_dump( struct object *obj, int verbose )
195 {
196     struct serial *serial = (struct serial *)obj;
197     assert( obj->ops == &serial_ops );
198     fprintf( stderr, "Port fd=%p mask=%x\n", serial->fd, serial->eventmask );
199 }
200
201 static struct serial *get_serial_obj( struct process *process, obj_handle_t handle, unsigned int access )
202 {
203     return (struct serial *)get_handle_obj( process, handle, access, &serial_ops );
204 }
205
206 static int serial_get_poll_events( struct fd *fd )
207 {
208     struct serial *serial = get_fd_user( fd );
209     int events = 0;
210     assert( serial->obj.ops == &serial_ops );
211
212     if(IS_READY(serial->read_q))
213         events |= POLLIN;
214     if(IS_READY(serial->write_q))
215         events |= POLLOUT;
216     if(IS_READY(serial->wait_q))
217         events |= POLLIN;
218
219     /* fprintf(stderr,"poll events are %04x\n",events); */
220
221     return events;
222 }
223
224 static int serial_get_info( struct fd *fd, struct get_file_info_reply *reply, int *flags )
225 {
226     struct serial *serial = get_fd_user( fd );
227     assert( serial->obj.ops == &serial_ops );
228
229     if (reply)
230     {
231         reply->type        = FILE_TYPE_CHAR;
232         reply->attr        = 0;
233         reply->access_time = 0;
234         reply->write_time  = 0;
235         reply->size_high   = 0;
236         reply->size_low    = 0;
237         reply->links       = 0;
238         reply->index_high  = 0;
239         reply->index_low   = 0;
240         reply->serial      = 0;
241     }
242
243     *flags = 0;
244     if(serial->attrib & FILE_FLAG_OVERLAPPED)
245         *flags |= FD_FLAG_OVERLAPPED;
246     else if(!((serial->readinterval == MAXDWORD) &&
247               (serial->readmult == 0) && (serial->readconst == 0)) )
248         *flags |= FD_FLAG_TIMEOUT;
249
250     return FD_TYPE_DEFAULT;
251 }
252
253 static void serial_poll_event(struct fd *fd, int event)
254 {
255     struct serial *serial = get_fd_user( fd );
256
257     /* fprintf(stderr,"Poll event %02x\n",event); */
258
259     if(IS_READY(serial->read_q) && (POLLIN & event) )
260         async_notify(serial->read_q.head,STATUS_ALERTED);
261
262     if(IS_READY(serial->write_q) && (POLLOUT & event) )
263         async_notify(serial->write_q.head,STATUS_ALERTED);
264
265     if(IS_READY(serial->wait_q) && (POLLIN & event) )
266         async_notify(serial->wait_q.head,STATUS_ALERTED);
267
268     set_fd_events( fd, serial_get_poll_events(fd) );
269 }
270
271 static void serial_queue_async(struct fd *fd, void *ptr, unsigned int status, int type, int count)
272 {
273     struct serial *serial = get_fd_user( fd );
274     struct async_queue *q;
275     struct async *async;
276     int timeout;
277
278     assert(serial->obj.ops == &serial_ops);
279
280     switch(type)
281     {
282     case ASYNC_TYPE_READ:
283         q = &serial->read_q;
284         timeout = serial->readconst + serial->readmult*count;
285         break;
286     case ASYNC_TYPE_WAIT:
287         q = &serial->wait_q;
288         timeout = 0;
289         break;
290     case ASYNC_TYPE_WRITE:
291         q = &serial->write_q;
292         timeout = serial->writeconst + serial->writemult*count;
293         break;
294     default:
295         set_error(STATUS_INVALID_PARAMETER);
296         return;
297     }
298
299     async = find_async ( q, current, ptr );
300
301     if ( status == STATUS_PENDING )
302     {
303         int events;
304
305         if ( !async )
306             async = create_async ( &serial->obj, current, ptr );
307         if ( !async )
308             return;
309
310         async->status = STATUS_PENDING;
311         if(!async->q)
312         {
313             async_add_timeout(async,timeout);
314             async_insert(q, async);
315         }
316
317         /* Check if the new pending request can be served immediately */
318         events = check_fd_events( fd, serial_get_poll_events( fd ) );
319         if (events)
320         {
321             /* serial_poll_event() calls set_select_events() */
322             serial_poll_event( fd, events );
323             return;
324         }
325     }
326     else if ( async ) destroy_async ( async );
327     else set_error ( STATUS_INVALID_PARAMETER );
328
329     set_fd_events ( fd, serial_get_poll_events( fd ));
330 }
331
332 static int serial_flush( struct fd *fd, struct event **event )
333 {
334     /* MSDN says: If hFile is a handle to a communications device,
335      * the function only flushes the transmit buffer.
336      */
337     int ret = (tcflush( get_unix_fd(fd), TCOFLUSH ) != -1);
338     if (!ret) file_set_error();
339     return ret;
340 }
341
342 /* create a serial */
343 DECL_HANDLER(create_serial)
344 {
345     struct serial *serial;
346
347     reply->handle = 0;
348     if ((serial = create_serial( get_req_data(), get_req_data_size(), req->access, req->attributes )))
349     {
350         reply->handle = alloc_handle( current->process, serial, req->access, req->inherit );
351         release_object( serial );
352     }
353 }
354
355 DECL_HANDLER(get_serial_info)
356 {
357     struct serial *serial;
358
359     if ((serial = get_serial_obj( current->process, req->handle, 0 )))
360     {
361         /* timeouts */
362         reply->readinterval = serial->readinterval;
363         reply->readconst    = serial->readconst;
364         reply->readmult     = serial->readmult;
365         reply->writeconst   = serial->writeconst;
366         reply->writemult    = serial->writemult;
367
368         /* event mask */
369         reply->eventmask    = serial->eventmask;
370
371         /* comm port error status */
372         reply->commerror    = serial->commerror;
373
374         release_object( serial );
375     }
376 }
377
378 DECL_HANDLER(set_serial_info)
379 {
380     struct serial *serial;
381
382     if ((serial = get_serial_obj( current->process, req->handle, 0 )))
383     {
384         /* timeouts */
385         if(req->flags & SERIALINFO_SET_TIMEOUTS)
386         {
387             serial->readinterval = req->readinterval;
388             serial->readconst    = req->readconst;
389             serial->readmult     = req->readmult;
390             serial->writeconst   = req->writeconst;
391             serial->writemult    = req->writemult;
392         }
393
394         /* event mask */
395         if(req->flags & SERIALINFO_SET_MASK)
396         {
397             serial->eventmask = req->eventmask;
398             if(!serial->eventmask)
399             {
400                 while(serial->wait_q.head)
401                 {
402                     async_notify(serial->wait_q.head, STATUS_SUCCESS);
403                     destroy_async(serial->wait_q.head);
404                 }
405             }
406         }
407
408         /* comm port error status */
409         if(req->flags & SERIALINFO_SET_ERROR)
410         {
411             serial->commerror = req->commerror;
412         }
413
414         release_object( serial );
415     }
416 }