ddraw: Align user vertex data.
[wine] / server / device.c
1 /*
2  * Server-side device support
3  *
4  * Copyright (C) 2007 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include <assert.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <stdarg.h>
25
26 #include "ntstatus.h"
27 #define WIN32_NO_STATUS
28 #include "windef.h"
29 #include "winternl.h"
30
31 #include "object.h"
32 #include "file.h"
33 #include "handle.h"
34 #include "request.h"
35 #include "process.h"
36
37 struct ioctl_call
38 {
39     struct object          obj;           /* object header */
40     struct list            dev_entry;     /* entry in device queue */
41     struct list            mgr_entry;     /* entry in manager queue */
42     struct device         *device;        /* device containing this ioctl */
43     struct thread         *thread;        /* thread that queued the ioctl */
44     client_ptr_t           user_arg;      /* user arg used to identify the request */
45     struct async          *async;         /* pending async op */
46     ioctl_code_t           code;          /* ioctl code */
47     unsigned int           status;        /* resulting status (or STATUS_PENDING) */
48     data_size_t            in_size;       /* size of input data */
49     void                  *in_data;       /* input data */
50     data_size_t            out_size;      /* size of output data */
51     void                  *out_data;      /* output data */
52 };
53
54 static void ioctl_call_dump( struct object *obj, int verbose );
55 static int ioctl_call_signaled( struct object *obj, struct thread *thread );
56 static void ioctl_call_destroy( struct object *obj );
57
58 static const struct object_ops ioctl_call_ops =
59 {
60     sizeof(struct ioctl_call),        /* size */
61     ioctl_call_dump,                  /* dump */
62     no_get_type,                      /* get_type */
63     add_queue,                        /* add_queue */
64     remove_queue,                     /* remove_queue */
65     ioctl_call_signaled,              /* signaled */
66     no_satisfied,                     /* satisfied */
67     no_signal,                        /* signal */
68     no_get_fd,                        /* get_fd */
69     no_map_access,                    /* map_access */
70     default_get_sd,                   /* get_sd */
71     default_set_sd,                   /* set_sd */
72     no_lookup_name,                   /* lookup_name */
73     no_open_file,                     /* open_file */
74     no_close_handle,                  /* close_handle */
75     ioctl_call_destroy                /* destroy */
76 };
77
78
79 struct device_manager
80 {
81     struct object          obj;           /* object header */
82     struct list            devices;       /* list of devices */
83     struct list            requests;      /* list of pending ioctls across all devices */
84 };
85
86 static void device_manager_dump( struct object *obj, int verbose );
87 static int device_manager_signaled( struct object *obj, struct thread *thread );
88 static void device_manager_destroy( struct object *obj );
89
90 static const struct object_ops device_manager_ops =
91 {
92     sizeof(struct device_manager),    /* size */
93     device_manager_dump,              /* dump */
94     no_get_type,                      /* get_type */
95     add_queue,                        /* add_queue */
96     remove_queue,                     /* remove_queue */
97     device_manager_signaled,          /* signaled */
98     no_satisfied,                     /* satisfied */
99     no_signal,                        /* signal */
100     no_get_fd,                        /* get_fd */
101     no_map_access,                    /* map_access */
102     default_get_sd,                   /* get_sd */
103     default_set_sd,                   /* set_sd */
104     no_lookup_name,                   /* lookup_name */
105     no_open_file,                     /* open_file */
106     no_close_handle,                  /* close_handle */
107     device_manager_destroy            /* destroy */
108 };
109
110
111 struct device
112 {
113     struct object          obj;           /* object header */
114     struct device_manager *manager;       /* manager for this device (or NULL if deleted) */
115     struct fd             *fd;            /* file descriptor for ioctl */
116     client_ptr_t           user_ptr;      /* opaque ptr for client side */
117     struct list            entry;         /* entry in device manager list */
118     struct list            requests;      /* list of pending ioctl requests */
119 };
120
121 static void device_dump( struct object *obj, int verbose );
122 static struct object_type *device_get_type( struct object *obj );
123 static struct fd *device_get_fd( struct object *obj );
124 static void device_destroy( struct object *obj );
125 static struct object *device_open_file( struct object *obj, unsigned int access,
126                                         unsigned int sharing, unsigned int options );
127 static enum server_fd_type device_get_fd_type( struct fd *fd );
128 static obj_handle_t device_ioctl( struct fd *fd, ioctl_code_t code, const async_data_t *async_data,
129                                   int blocking, const void *data, data_size_t size );
130
131 static const struct object_ops device_ops =
132 {
133     sizeof(struct device),            /* size */
134     device_dump,                      /* dump */
135     device_get_type,                  /* get_type */
136     no_add_queue,                     /* add_queue */
137     NULL,                             /* remove_queue */
138     NULL,                             /* signaled */
139     no_satisfied,                     /* satisfied */
140     no_signal,                        /* signal */
141     device_get_fd,                    /* get_fd */
142     default_fd_map_access,            /* map_access */
143     default_get_sd,                   /* get_sd */
144     default_set_sd,                   /* set_sd */
145     no_lookup_name,                   /* lookup_name */
146     device_open_file,                 /* open_file */
147     no_close_handle,                  /* close_handle */
148     device_destroy                    /* destroy */
149 };
150
151 static const struct fd_ops device_fd_ops =
152 {
153     default_fd_get_poll_events,       /* get_poll_events */
154     default_poll_event,               /* poll_event */
155     no_flush,                         /* flush */
156     device_get_fd_type,               /* get_fd_type */
157     device_ioctl,                     /* ioctl */
158     default_fd_queue_async,           /* queue_async */
159     default_fd_reselect_async,        /* reselect_async */
160     default_fd_cancel_async           /* cancel_async */
161 };
162
163
164 static void ioctl_call_dump( struct object *obj, int verbose )
165 {
166     struct ioctl_call *ioctl = (struct ioctl_call *)obj;
167     fprintf( stderr, "Ioctl call code=%08x device=%p\n", ioctl->code, ioctl->device );
168 }
169
170 static int ioctl_call_signaled( struct object *obj, struct thread *thread )
171 {
172     struct ioctl_call *ioctl = (struct ioctl_call *)obj;
173
174     return !ioctl->device;  /* device is cleared once the ioctl has completed */
175 }
176
177 static void ioctl_call_destroy( struct object *obj )
178 {
179     struct ioctl_call *ioctl = (struct ioctl_call *)obj;
180
181     free( ioctl->in_data );
182     free( ioctl->out_data );
183     if (ioctl->async)
184     {
185         async_terminate( ioctl->async, STATUS_CANCELLED );
186         release_object( ioctl->async );
187     }
188     if (ioctl->device) release_object( ioctl->device );
189     release_object( ioctl->thread );
190 }
191
192 static struct ioctl_call *create_ioctl( struct device *device, ioctl_code_t code,
193                                         const void *in_data, data_size_t in_size,
194                                         data_size_t out_size )
195 {
196     struct ioctl_call *ioctl;
197
198     if ((ioctl = alloc_object( &ioctl_call_ops )))
199     {
200         ioctl->device   = (struct device *)grab_object( device );
201         ioctl->code     = code;
202         ioctl->async    = NULL;
203         ioctl->status   = STATUS_PENDING;
204         ioctl->in_size  = in_size;
205         ioctl->in_data  = NULL;
206         ioctl->out_size = out_size;
207         ioctl->out_data = NULL;
208
209         if (ioctl->in_size && !(ioctl->in_data = memdup( in_data, in_size )))
210         {
211             release_object( ioctl );
212             ioctl = NULL;
213         }
214     }
215     return ioctl;
216 }
217
218 static void set_ioctl_result( struct ioctl_call *ioctl, unsigned int status,
219                               const void *out_data, data_size_t out_size )
220 {
221     struct device *device = ioctl->device;
222
223     if (!device) return;  /* already finished */
224
225     /* FIXME: handle the STATUS_PENDING case */
226     ioctl->status = status;
227     ioctl->out_size = min( ioctl->out_size, out_size );
228     if (ioctl->out_size && !(ioctl->out_data = memdup( out_data, ioctl->out_size )))
229         ioctl->out_size = 0;
230     release_object( device );
231     ioctl->device = NULL;
232     if (ioctl->async)
233     {
234         if (ioctl->out_size) status = STATUS_ALERTED;
235         async_terminate( ioctl->async, status );
236         release_object( ioctl->async );
237         ioctl->async = NULL;
238     }
239     wake_up( &ioctl->obj, 0 );
240
241     if (status != STATUS_ALERTED)
242     {
243         /* remove it from the device queue */
244         /* (for STATUS_ALERTED this will be done in get_ioctl_result) */
245         list_remove( &ioctl->dev_entry );
246         release_object( ioctl );  /* no longer on the device queue */
247     }
248 }
249
250
251 static void device_dump( struct object *obj, int verbose )
252 {
253     struct device *device = (struct device *)obj;
254
255     fprintf( stderr, "Device " );
256     dump_object_name( &device->obj );
257     fputc( '\n', stderr );
258 }
259
260 static struct object_type *device_get_type( struct object *obj )
261 {
262     static const WCHAR name[] = {'D','e','v','i','c','e'};
263     static const struct unicode_str str = { name, sizeof(name) };
264     return get_object_type( &str );
265 }
266
267 static struct fd *device_get_fd( struct object *obj )
268 {
269     struct device *device = (struct device *)obj;
270
271     return (struct fd *)grab_object( device->fd );
272 }
273
274 static void device_destroy( struct object *obj )
275 {
276     struct device *device = (struct device *)obj;
277     struct ioctl_call *ioctl, *next;
278
279     LIST_FOR_EACH_ENTRY_SAFE( ioctl, next, &device->requests, struct ioctl_call, dev_entry )
280     {
281         list_remove( &ioctl->dev_entry );
282         release_object( ioctl );  /* no longer on the device queue */
283     }
284     if (device->fd) release_object( device->fd );
285     if (device->manager) list_remove( &device->entry );
286 }
287
288 static struct object *device_open_file( struct object *obj, unsigned int access,
289                                         unsigned int sharing, unsigned int options )
290 {
291     return grab_object( obj );
292 }
293
294 static enum server_fd_type device_get_fd_type( struct fd *fd )
295 {
296     return FD_TYPE_DEVICE;
297 }
298
299 static struct ioctl_call *find_ioctl_call( struct device *device, struct thread *thread,
300                                            client_ptr_t user_arg )
301 {
302     struct ioctl_call *ioctl;
303
304     LIST_FOR_EACH_ENTRY( ioctl, &device->requests, struct ioctl_call, dev_entry )
305         if (ioctl->thread == thread && ioctl->user_arg == user_arg) return ioctl;
306
307     set_error( STATUS_INVALID_PARAMETER );
308     return NULL;
309 }
310
311 static obj_handle_t device_ioctl( struct fd *fd, ioctl_code_t code, const async_data_t *async_data,
312                                   int blocking, const void *data, data_size_t size )
313 {
314     struct device *device = get_fd_user( fd );
315     struct ioctl_call *ioctl;
316     obj_handle_t handle;
317
318     if (!device->manager)  /* it has been deleted */
319     {
320         set_error( STATUS_FILE_DELETED );
321         return 0;
322     }
323
324     if (!(ioctl = create_ioctl( device, code, data, size, get_reply_max_size() )))
325         return 0;
326
327     ioctl->thread   = (struct thread *)grab_object( current );
328     ioctl->user_arg = async_data->arg;
329
330     if (!(handle = alloc_handle( current->process, ioctl, SYNCHRONIZE, 0 )))
331     {
332         release_object( ioctl );
333         return 0;
334     }
335
336     if (!(ioctl->async = fd_queue_async( device->fd, async_data, ASYNC_TYPE_WAIT )))
337     {
338         close_handle( current->process, handle );
339         release_object( ioctl );
340         return 0;
341     }
342     list_add_tail( &device->requests, &ioctl->dev_entry );
343     list_add_tail( &device->manager->requests, &ioctl->mgr_entry );
344     if (list_head( &device->manager->requests ) == &ioctl->mgr_entry)  /* first one */
345         wake_up( &device->manager->obj, 0 );
346     /* don't release ioctl since it is now queued in the device */
347     set_error( STATUS_PENDING );
348     return handle;
349 }
350
351 static struct device *create_device( struct directory *root, const struct unicode_str *name,
352                                      struct device_manager *manager, unsigned int attr )
353 {
354     struct device *device;
355
356     if ((device = create_named_object_dir( root, name, attr, &device_ops )))
357     {
358         if (get_error() != STATUS_OBJECT_NAME_EXISTS)
359         {
360             /* initialize it if it didn't already exist */
361             device->manager = manager;
362             list_add_tail( &manager->devices, &device->entry );
363             list_init( &device->requests );
364             if (!(device->fd = alloc_pseudo_fd( &device_fd_ops, &device->obj, 0 )))
365             {
366                 release_object( device );
367                 device = NULL;
368             }
369         }
370     }
371     return device;
372 }
373
374 static void delete_device( struct device *device )
375 {
376     struct ioctl_call *ioctl, *next;
377
378     if (!device->manager) return;  /* already deleted */
379
380     /* terminate all pending requests */
381     LIST_FOR_EACH_ENTRY_SAFE( ioctl, next, &device->requests, struct ioctl_call, dev_entry )
382     {
383         list_remove( &ioctl->mgr_entry );
384         set_ioctl_result( ioctl, STATUS_FILE_DELETED, NULL, 0 );
385     }
386     unlink_named_object( &device->obj );
387     list_remove( &device->entry );
388     device->manager = NULL;
389 }
390
391
392 static void device_manager_dump( struct object *obj, int verbose )
393 {
394     fprintf( stderr, "Device manager\n" );
395 }
396
397 static int device_manager_signaled( struct object *obj, struct thread *thread )
398 {
399     struct device_manager *manager = (struct device_manager *)obj;
400
401     return !list_empty( &manager->requests );
402 }
403
404 static void device_manager_destroy( struct object *obj )
405 {
406     struct device_manager *manager = (struct device_manager *)obj;
407     struct list *ptr;
408
409     while ((ptr = list_head( &manager->devices )))
410     {
411         struct device *device = LIST_ENTRY( ptr, struct device, entry );
412         delete_device( device );
413     }
414 }
415
416 static struct device_manager *create_device_manager(void)
417 {
418     struct device_manager *manager;
419
420     if ((manager = alloc_object( &device_manager_ops )))
421     {
422         list_init( &manager->devices );
423         list_init( &manager->requests );
424     }
425     return manager;
426 }
427
428
429 /* create a device manager */
430 DECL_HANDLER(create_device_manager)
431 {
432     struct device_manager *manager = create_device_manager();
433
434     if (manager)
435     {
436         reply->handle = alloc_handle( current->process, manager, req->access, req->attributes );
437         release_object( manager );
438     }
439 }
440
441
442 /* create a device */
443 DECL_HANDLER(create_device)
444 {
445     struct device *device;
446     struct unicode_str name;
447     struct device_manager *manager;
448     struct directory *root = NULL;
449
450     if (!(manager = (struct device_manager *)get_handle_obj( current->process, req->manager,
451                                                              0, &device_manager_ops )))
452         return;
453
454     get_req_unicode_str( &name );
455     if (req->rootdir && !(root = get_directory_obj( current->process, req->rootdir, 0 )))
456     {
457         release_object( manager );
458         return;
459     }
460
461     if ((device = create_device( root, &name, manager, req->attributes )))
462     {
463         device->user_ptr = req->user_ptr;
464         reply->handle = alloc_handle( current->process, device, req->access, req->attributes );
465         release_object( device );
466     }
467
468     if (root) release_object( root );
469     release_object( manager );
470 }
471
472
473 /* delete a device */
474 DECL_HANDLER(delete_device)
475 {
476     struct device *device;
477
478     if ((device = (struct device *)get_handle_obj( current->process, req->handle, 0, &device_ops )))
479     {
480         delete_device( device );
481         release_object( device );
482     }
483 }
484
485
486 /* retrieve the next pending device ioctl request */
487 DECL_HANDLER(get_next_device_request)
488 {
489     struct ioctl_call *ioctl;
490     struct device_manager *manager;
491     struct list *ptr;
492
493     if (!(manager = (struct device_manager *)get_handle_obj( current->process, req->manager,
494                                                              0, &device_manager_ops )))
495         return;
496
497     if (req->prev)
498     {
499         if ((ioctl = (struct ioctl_call *)get_handle_obj( current->process, req->prev,
500                                                           0, &ioctl_call_ops )))
501         {
502             set_ioctl_result( ioctl, req->status, get_req_data(), get_req_data_size() );
503             close_handle( current->process, req->prev );  /* avoid an extra round-trip for close */
504             release_object( ioctl );
505         }
506         clear_error();
507     }
508
509     if ((ptr = list_head( &manager->requests )))
510     {
511         ioctl = LIST_ENTRY( ptr, struct ioctl_call, mgr_entry );
512         reply->code = ioctl->code;
513         reply->user_ptr = ioctl->device->user_ptr;
514         reply->client_pid = get_process_id( ioctl->thread->process );
515         reply->client_tid = get_thread_id( ioctl->thread );
516         reply->in_size = ioctl->in_size;
517         reply->out_size = ioctl->out_size;
518         if (ioctl->in_size > get_reply_max_size()) set_error( STATUS_BUFFER_OVERFLOW );
519         else if ((reply->next = alloc_handle( current->process, ioctl, 0, 0 )))
520         {
521             set_reply_data_ptr( ioctl->in_data, ioctl->in_size );
522             ioctl->in_data = NULL;
523             ioctl->in_size = 0;
524             list_remove( &ioctl->mgr_entry );
525             list_init( &ioctl->mgr_entry );
526         }
527     }
528     else set_error( STATUS_PENDING );
529
530     release_object( manager );
531 }
532
533
534 /* retrieve results of an async ioctl */
535 DECL_HANDLER(get_ioctl_result)
536 {
537     struct device *device;
538     struct ioctl_call *ioctl;
539
540     if (!(device = (struct device *)get_handle_obj( current->process, req->handle, 0, &device_ops )))
541         return;
542
543     if ((ioctl = find_ioctl_call( device, current, req->user_arg )))
544     {
545         if (ioctl->out_data)
546         {
547             data_size_t size = min( ioctl->out_size, get_reply_max_size() );
548             if (size)
549             {
550                 set_reply_data_ptr( ioctl->out_data, size );
551                 ioctl->out_data = NULL;
552             }
553         }
554         set_error( ioctl->status );
555         list_remove( &ioctl->dev_entry );
556         release_object( ioctl );  /* no longer on the device queue */
557     }
558     release_object( device );
559 }