diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 7f6def05cd0..8239e369202 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -3970,6 +3970,50 @@ struct allocate_locally_unique_id_reply }; + +struct create_device_manager_request +{ + struct request_header __header; + unsigned int access; + unsigned int attributes; +}; +struct create_device_manager_reply +{ + struct reply_header __header; + obj_handle_t handle; +}; + + + +struct create_device_request +{ + struct request_header __header; + unsigned int access; + unsigned int attributes; + obj_handle_t rootdir; + obj_handle_t manager; + void* user_ptr; + /* VARARG(name,unicode_str); */ +}; +struct create_device_reply +{ + struct reply_header __header; + obj_handle_t handle; +}; + + + +struct delete_device_request +{ + struct request_header __header; + obj_handle_t handle; +}; +struct delete_device_reply +{ + struct reply_header __header; +}; + + enum request { REQ_new_process, @@ -4186,6 +4230,9 @@ enum request REQ_get_object_info, REQ_get_token_impersonation_level, REQ_allocate_locally_unique_id, + REQ_create_device_manager, + REQ_create_device, + REQ_delete_device, REQ_NB_REQUESTS }; @@ -4407,6 +4454,9 @@ union generic_request struct get_object_info_request get_object_info_request; struct get_token_impersonation_level_request get_token_impersonation_level_request; struct allocate_locally_unique_id_request allocate_locally_unique_id_request; + struct create_device_manager_request create_device_manager_request; + struct create_device_request create_device_request; + struct delete_device_request delete_device_request; }; union generic_reply { @@ -4626,8 +4676,11 @@ union generic_reply struct get_object_info_reply get_object_info_reply; struct get_token_impersonation_level_reply get_token_impersonation_level_reply; struct allocate_locally_unique_id_reply allocate_locally_unique_id_reply; + struct create_device_manager_reply create_device_manager_reply; + struct create_device_reply create_device_reply; + struct delete_device_reply delete_device_reply; }; -#define SERVER_PROTOCOL_VERSION 300 +#define SERVER_PROTOCOL_VERSION 301 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff --git a/server/Makefile.in b/server/Makefile.in index 5e31826b930..7648281f73f 100644 --- a/server/Makefile.in +++ b/server/Makefile.in @@ -19,6 +19,7 @@ C_SRCS = \ 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 00000000000..8a911b791ec --- /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 +#include +#include +#include + +#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 dd59acb9c61..a7b4dfd66fb 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -2854,3 +2854,31 @@ enum message_type @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 36301542c77..6d769c1973f 100644 --- a/server/request.h +++ b/server/request.h @@ -324,6 +324,9 @@ DECL_HANDLER(query_symlink); 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 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] = (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 71e5cb05696..5762331ac72 100644 --- a/server/trace.c +++ b/server/trace.c @@ -3460,6 +3460,38 @@ static void dump_allocate_locally_unique_id_reply( const struct allocate_locally 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 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = { (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 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { (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 @@ static const char * const req_names[REQ_NB_REQUESTS] = { "get_object_info", "get_token_impersonation_level", "allocate_locally_unique_id", + "create_device_manager", + "create_device", + "delete_device", }; static const struct