server: Add support for generic device objects managed from the client side.
diff --git a/server/Makefile.in b/server/Makefile.in
index 5e31826..7648281 100644
--- a/server/Makefile.in
+++ b/server/Makefile.in
@@ -19,6 +19,7 @@
context_sparc.c \
context_x86_64.c \
debugger.c \
+ device.c \
directory.c \
event.c \
fd.c \
diff --git a/server/device.c b/server/device.c
new file mode 100644
index 0000000..8a911b7
--- /dev/null
+++ b/server/device.c
@@ -0,0 +1,259 @@
+/*
+ * Server-side device support
+ *
+ * Copyright (C) 2007 Alexandre Julliard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
+#include "windef.h"
+#include "winternl.h"
+
+#include "object.h"
+#include "file.h"
+#include "handle.h"
+#include "request.h"
+
+struct device_manager
+{
+ struct object obj; /* object header */
+ struct list devices; /* list of devices */
+};
+
+static void device_manager_dump( struct object *obj, int verbose );
+static void device_manager_destroy( struct object *obj );
+
+static const struct object_ops device_manager_ops =
+{
+ sizeof(struct device_manager), /* size */
+ device_manager_dump, /* dump */
+ no_add_queue, /* add_queue */
+ NULL, /* remove_queue */
+ NULL, /* signaled */
+ no_satisfied, /* satisfied */
+ no_signal, /* signal */
+ no_get_fd, /* get_fd */
+ no_map_access, /* map_access */
+ no_lookup_name, /* lookup_name */
+ no_open_file, /* open_file */
+ no_close_handle, /* close_handle */
+ device_manager_destroy /* destroy */
+};
+
+
+struct device
+{
+ struct object obj; /* object header */
+ struct device_manager *manager; /* manager for this device (or NULL if deleted) */
+ struct fd *fd; /* file descriptor for ioctl */
+ void *user_ptr; /* opaque ptr for client side */
+ struct list entry; /* entry in device manager list */
+};
+
+static void device_dump( struct object *obj, int verbose );
+static struct fd *device_get_fd( struct object *obj );
+static void device_destroy( struct object *obj );
+static struct object *device_open_file( struct object *obj, unsigned int access,
+ unsigned int sharing, unsigned int options );
+static enum server_fd_type device_get_fd_type( struct fd *fd );
+
+static const struct object_ops device_ops =
+{
+ sizeof(struct device), /* size */
+ device_dump, /* dump */
+ no_add_queue, /* add_queue */
+ NULL, /* remove_queue */
+ NULL, /* signaled */
+ no_satisfied, /* satisfied */
+ no_signal, /* signal */
+ device_get_fd, /* get_fd */
+ no_map_access, /* map_access */
+ no_lookup_name, /* lookup_name */
+ device_open_file, /* open_file */
+ no_close_handle, /* close_handle */
+ device_destroy /* destroy */
+};
+
+static const struct fd_ops device_fd_ops =
+{
+ default_fd_get_poll_events, /* get_poll_events */
+ default_poll_event, /* poll_event */
+ no_flush, /* flush */
+ device_get_fd_type, /* get_fd_type */
+ default_fd_ioctl, /* ioctl */
+ default_fd_queue_async, /* queue_async */
+ default_fd_reselect_async, /* reselect_async */
+ default_fd_cancel_async /* cancel_async */
+};
+
+
+static void device_dump( struct object *obj, int verbose )
+{
+ struct device *device = (struct device *)obj;
+
+ fprintf( stderr, "Device " );
+ dump_object_name( &device->obj );
+ fputc( '\n', stderr );
+}
+
+static struct fd *device_get_fd( struct object *obj )
+{
+ struct device *device = (struct device *)obj;
+
+ return (struct fd *)grab_object( device->fd );
+}
+
+static void device_destroy( struct object *obj )
+{
+ struct device *device = (struct device *)obj;
+
+ if (device->fd) release_object( device->fd );
+ if (device->manager) list_remove( &device->entry );
+}
+
+static struct object *device_open_file( struct object *obj, unsigned int access,
+ unsigned int sharing, unsigned int options )
+{
+ return grab_object( obj );
+}
+
+static enum server_fd_type device_get_fd_type( struct fd *fd )
+{
+ return FD_TYPE_DEVICE;
+}
+
+static struct device *create_device( struct directory *root, const struct unicode_str *name,
+ struct device_manager *manager, unsigned int attr )
+{
+ struct device *device;
+
+ if ((device = create_named_object_dir( root, name, attr, &device_ops )))
+ {
+ if (get_error() != STATUS_OBJECT_NAME_EXISTS)
+ {
+ /* initialize it if it didn't already exist */
+ device->manager = manager;
+ list_add_tail( &manager->devices, &device->entry );
+ if (!(device->fd = alloc_pseudo_fd( &device_fd_ops, &device->obj, 0 )))
+ {
+ release_object( device );
+ device = NULL;
+ }
+ }
+ }
+ return device;
+}
+
+static void delete_device( struct device *device )
+{
+ if (!device->manager) return; /* already deleted */
+
+ unlink_named_object( &device->obj );
+ list_remove( &device->entry );
+ device->manager = NULL;
+}
+
+
+static void device_manager_dump( struct object *obj, int verbose )
+{
+ fprintf( stderr, "Device manager\n" );
+}
+
+static void device_manager_destroy( struct object *obj )
+{
+ struct device_manager *manager = (struct device_manager *)obj;
+ struct list *ptr;
+
+ while ((ptr = list_head( &manager->devices )))
+ {
+ struct device *device = LIST_ENTRY( ptr, struct device, entry );
+ delete_device( device );
+ }
+}
+
+static struct device_manager *create_device_manager(void)
+{
+ struct device_manager *manager;
+
+ if ((manager = alloc_object( &device_manager_ops )))
+ {
+ list_init( &manager->devices );
+ }
+ return manager;
+}
+
+
+/* create a device manager */
+DECL_HANDLER(create_device_manager)
+{
+ struct device_manager *manager = create_device_manager();
+
+ if (manager)
+ {
+ reply->handle = alloc_handle( current->process, manager, req->access, req->attributes );
+ release_object( manager );
+ }
+}
+
+
+/* create a device */
+DECL_HANDLER(create_device)
+{
+ struct device *device;
+ struct unicode_str name;
+ struct device_manager *manager;
+ struct directory *root = NULL;
+
+ if (!(manager = (struct device_manager *)get_handle_obj( current->process, req->manager,
+ 0, &device_manager_ops )))
+ return;
+
+ get_req_unicode_str( &name );
+ if (req->rootdir && !(root = get_directory_obj( current->process, req->rootdir, 0 )))
+ {
+ release_object( manager );
+ return;
+ }
+
+ if ((device = create_device( root, &name, manager, req->attributes )))
+ {
+ device->user_ptr = req->user_ptr;
+ reply->handle = alloc_handle( current->process, device, req->access, req->attributes );
+ release_object( device );
+ }
+
+ if (root) release_object( root );
+ release_object( manager );
+}
+
+
+/* delete a device */
+DECL_HANDLER(delete_device)
+{
+ struct device *device;
+
+ if ((device = (struct device *)get_handle_obj( current->process, req->handle, 0, &device_ops )))
+ {
+ delete_device( device );
+ release_object( device );
+ }
+}
diff --git a/server/protocol.def b/server/protocol.def
index dd59acb..a7b4dfd 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -2854,3 +2854,31 @@
@REPLY
luid_t luid;
@END
+
+
+/* Create a device manager */
+@REQ(create_device_manager)
+ unsigned int access; /* wanted access rights */
+ unsigned int attributes; /* object attributes */
+@REPLY
+ obj_handle_t handle; /* handle to the device */
+@END
+
+
+/* Create a device */
+@REQ(create_device)
+ unsigned int access; /* wanted access rights */
+ unsigned int attributes; /* object attributes */
+ obj_handle_t rootdir; /* root directory */
+ obj_handle_t manager; /* device manager */
+ void* user_ptr; /* opaque ptr for use by client */
+ VARARG(name,unicode_str); /* object name */
+@REPLY
+ obj_handle_t handle; /* handle to the device */
+@END
+
+
+/* Delete a device */
+@REQ(delete_device)
+ obj_handle_t handle; /* handle to the device */
+@END
diff --git a/server/request.h b/server/request.h
index 3630154..6d769c1 100644
--- a/server/request.h
+++ b/server/request.h
@@ -324,6 +324,9 @@
DECL_HANDLER(get_object_info);
DECL_HANDLER(get_token_impersonation_level);
DECL_HANDLER(allocate_locally_unique_id);
+DECL_HANDLER(create_device_manager);
+DECL_HANDLER(create_device);
+DECL_HANDLER(delete_device);
#ifdef WANT_REQUEST_HANDLERS
@@ -544,6 +547,9 @@
(req_handler)req_get_object_info,
(req_handler)req_get_token_impersonation_level,
(req_handler)req_allocate_locally_unique_id,
+ (req_handler)req_create_device_manager,
+ (req_handler)req_create_device,
+ (req_handler)req_delete_device,
};
#endif /* WANT_REQUEST_HANDLERS */
diff --git a/server/trace.c b/server/trace.c
index 71e5cb0..5762331 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -3460,6 +3460,38 @@
dump_luid( &req->luid );
}
+static void dump_create_device_manager_request( const struct create_device_manager_request *req )
+{
+ fprintf( stderr, " access=%08x,", req->access );
+ fprintf( stderr, " attributes=%08x", req->attributes );
+}
+
+static void dump_create_device_manager_reply( const struct create_device_manager_reply *req )
+{
+ fprintf( stderr, " handle=%p", req->handle );
+}
+
+static void dump_create_device_request( const struct create_device_request *req )
+{
+ fprintf( stderr, " access=%08x,", req->access );
+ fprintf( stderr, " attributes=%08x,", req->attributes );
+ fprintf( stderr, " rootdir=%p,", req->rootdir );
+ fprintf( stderr, " manager=%p,", req->manager );
+ fprintf( stderr, " user_ptr=%p,", req->user_ptr );
+ fprintf( stderr, " name=" );
+ dump_varargs_unicode_str( cur_size );
+}
+
+static void dump_create_device_reply( const struct create_device_reply *req )
+{
+ fprintf( stderr, " handle=%p", req->handle );
+}
+
+static void dump_delete_device_request( const struct delete_device_request *req )
+{
+ fprintf( stderr, " handle=%p", req->handle );
+}
+
static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_new_process_request,
(dump_func)dump_get_new_process_info_request,
@@ -3675,6 +3707,9 @@
(dump_func)dump_get_object_info_request,
(dump_func)dump_get_token_impersonation_level_request,
(dump_func)dump_allocate_locally_unique_id_request,
+ (dump_func)dump_create_device_manager_request,
+ (dump_func)dump_create_device_request,
+ (dump_func)dump_delete_device_request,
};
static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
@@ -3892,6 +3927,9 @@
(dump_func)dump_get_object_info_reply,
(dump_func)dump_get_token_impersonation_level_reply,
(dump_func)dump_allocate_locally_unique_id_reply,
+ (dump_func)dump_create_device_manager_reply,
+ (dump_func)dump_create_device_reply,
+ (dump_func)0,
};
static const char * const req_names[REQ_NB_REQUESTS] = {
@@ -4109,6 +4147,9 @@
"get_object_info",
"get_token_impersonation_level",
"allocate_locally_unique_id",
+ "create_device_manager",
+ "create_device",
+ "delete_device",
};
static const struct