Make serial fd blocking mode depend on FILE_FLAG_OVERLAPPED.
[wine] / server / serial.c
1 /*
2  * Server-side serial port communications management
3  *
4  * Copyright (C) 1998 Alexandre Julliard
5  * Copyright (C) 2000 Mike McCormack
6  *
7  * TODO:
8  *  Add async read, write and WaitCommEvent handling.
9  *
10  */
11
12 #include "config.h"
13
14 #include <assert.h>
15 #include <fcntl.h>
16 #include <stdio.h>
17 #include <string.h>
18 #include <stdlib.h>
19 #include <errno.h>
20 #ifdef HAVE_SYS_ERRNO_H
21 #include <sys/errno.h>
22 #endif
23 #include <sys/time.h>
24 #include <sys/types.h>
25 #include <time.h>
26 #include <unistd.h>
27 #include <utime.h>
28 #include <termios.h>
29 #include <sys/ioctl.h>
30
31 #include "winerror.h"
32 #include "winbase.h"
33
34 #include "handle.h"
35 #include "thread.h"
36 #include "request.h"
37
38 static void serial_dump( struct object *obj, int verbose );
39 static int serial_get_fd( struct object *obj );
40 static int serial_get_info( struct object *obj, struct get_file_info_request *req );
41 static int serial_get_poll_events( struct object *obj );
42
43 struct serial
44 {
45     struct object       obj;
46     unsigned int        access;
47     unsigned int        attrib;
48
49     /* timeout values */
50     unsigned int        readinterval;
51     unsigned int        readconst;
52     unsigned int        readmult;
53     unsigned int        writeconst;
54     unsigned int        writemult;
55
56     unsigned int        eventmask;
57     unsigned int        commerror;
58
59     struct termios      original;
60
61     /* FIXME: add dcb, comm status, handler module, sharing */
62 };
63
64 static const struct object_ops serial_ops =
65 {
66     sizeof(struct serial),        /* size */
67     serial_dump,                  /* dump */
68     default_poll_add_queue,       /* add_queue */
69     default_poll_remove_queue,    /* remove_queue */
70     default_poll_signaled,        /* signaled */
71     no_satisfied,                 /* satisfied */
72     serial_get_poll_events,       /* get_poll_events */
73     default_poll_event,           /* poll_event */
74     serial_get_fd,                /* get_fd */
75     no_flush,                     /* flush */
76     serial_get_info,              /* get_file_info */
77     no_destroy                    /* destroy */
78 };
79
80 /* SERIAL PORT functions */
81
82 static struct serial *create_serial( const char *nameptr, size_t len, unsigned int access, int attributes )
83 {
84     struct serial *serial;
85     struct termios tios;
86     int fd, flags = 0;
87     char *name;
88
89     if (!(name = mem_alloc( len + 1 ))) return NULL;
90     memcpy( name, nameptr, len );
91     name[len] = 0;
92
93     switch(access & (GENERIC_READ | GENERIC_WRITE))
94     {
95     case GENERIC_READ:  flags |= O_RDONLY; break;
96     case GENERIC_WRITE: flags |= O_WRONLY; break;
97     case GENERIC_READ|GENERIC_WRITE: flags |= O_RDWR; break;
98     default: break;
99     }
100
101     flags |= O_NONBLOCK;
102
103     fd = open( name, flags );
104     free( name );
105     if (fd < 0)
106     {
107         file_set_error();
108         return NULL;
109     }
110
111     /* check its really a serial port */
112     if (tcgetattr(fd,&tios))
113     {
114         file_set_error();
115         close( fd );
116         return NULL;
117     }
118
119     /* set the fd back to blocking if necessary */
120     if( ! (attributes & FILE_FLAG_OVERLAPPED) )
121        if(0>fcntl(fd, F_SETFL, 0))
122            perror("fcntl");
123
124     if ((serial = alloc_object( &serial_ops, fd )))
125     {
126         serial->attrib       = attributes;
127         serial->access       = access;
128         serial->readinterval = 0;
129         serial->readmult     = 0;
130         serial->readconst    = 0;
131         serial->writemult    = 0;
132         serial->writeconst   = 0;
133         serial->eventmask    = 0;
134         serial->commerror    = 0;
135     }
136     return serial;
137 }
138
139 static void serial_dump( struct object *obj, int verbose )
140 {
141     struct serial *serial = (struct serial *)obj;
142     assert( obj->ops == &serial_ops );
143     fprintf( stderr, "Port fd=%d mask=%x\n", serial->obj.fd, serial->eventmask );
144 }
145
146 struct serial *get_serial_obj( struct process *process, handle_t handle, unsigned int access )
147 {
148     return (struct serial *)get_handle_obj( process, handle, access, &serial_ops );
149 }
150
151 static int serial_get_poll_events( struct object *obj )
152 {
153     struct serial *serial = (struct serial *)obj;
154     int events = 0;
155     assert( obj->ops == &serial_ops );
156     if (serial->access & GENERIC_READ) events |= POLLIN;
157     if (serial->access & GENERIC_WRITE) events |= POLLOUT;
158     return events;
159 }
160
161 static int serial_get_fd( struct object *obj )
162 {
163     struct serial *serial = (struct serial *)obj;
164     assert( obj->ops == &serial_ops );
165     return serial->obj.fd;
166 }
167
168 static int serial_get_info( struct object *obj, struct get_file_info_request *req )
169 {
170     struct serial *serial = (struct serial *) obj;
171     assert( obj->ops == &serial_ops );
172
173     if (req)
174     {
175         req->type        = FILE_TYPE_CHAR;
176         req->attr        = 0;
177         req->access_time = 0;
178         req->write_time  = 0;
179         req->size_high   = 0;
180         req->size_low    = 0;
181         req->links       = 0;
182         req->index_high  = 0;
183         req->index_low   = 0;
184         req->serial      = 0;
185     }
186
187     if(serial->attrib & FILE_FLAG_OVERLAPPED)
188         return FD_TYPE_OVERLAPPED;
189
190     return FD_TYPE_TIMEOUT;
191 }
192
193 /* these function calculates the timeout for an async operation
194    on a serial port */
195 int get_serial_async_timeout(struct object *obj, int type, int count)
196 {
197     struct serial *serial = (struct serial *)obj;
198
199     if(obj->ops != &serial_ops)
200         return 0;
201
202     switch(type)
203     {
204     case ASYNC_TYPE_READ:
205         return serial->readconst + serial->readmult*count;
206     case ASYNC_TYPE_WRITE:
207         return serial->writeconst + serial->writemult*count;
208     }
209     return 0;
210 }
211
212
213 /* create a serial */
214 DECL_HANDLER(create_serial)
215 {
216     struct serial *serial;
217
218     req->handle = 0;
219     if ((serial = create_serial( get_req_data(req), get_req_data_size(req), req->access, req->attributes )))
220     {
221         req->handle = alloc_handle( current->process, serial, req->access, req->inherit );
222         release_object( serial );
223     }
224 }
225
226 DECL_HANDLER(get_serial_info)
227 {
228     struct serial *serial;
229
230     if ((serial = get_serial_obj( current->process, req->handle, 0 )))
231     {
232         /* timeouts */
233         req->readinterval = serial->readinterval;
234         req->readconst    = serial->readconst;
235         req->readmult     = serial->readmult;
236         req->writeconst   = serial->writeconst;
237         req->writemult    = serial->writemult;
238
239         /* event mask */
240         req->eventmask    = serial->eventmask;
241
242         /* comm port error status */
243         req->commerror    = serial->commerror;
244
245         release_object( serial );
246     }
247 }
248
249 DECL_HANDLER(set_serial_info)
250 {
251     struct serial *serial;
252
253     if ((serial = get_serial_obj( current->process, req->handle, 0 )))
254     {
255         /* timeouts */
256         if(req->flags & SERIALINFO_SET_TIMEOUTS)
257         {
258             serial->readinterval = req->readinterval;
259             serial->readconst    = req->readconst;
260             serial->readmult     = req->readmult;
261             serial->writeconst   = req->writeconst;
262             serial->writemult    = req->writemult;
263         }
264
265         /* event mask */
266         if(req->flags & SERIALINFO_SET_MASK)
267         {
268             serial->eventmask = req->eventmask;
269         }
270
271         /* comm port error status */
272         if(req->flags & SERIALINFO_SET_ERROR)
273         {
274             serial->commerror = req->commerror;
275         }
276
277         release_object( serial );
278     }
279 }
280