LPT0 support with DOSFS_OpenDevice
Ed Lea
ed at orangebits.cx
Fri Sep 5 05:37:35 CDT 2003
This patch provides initial support for accessing LPT0 via /dev/lp0. It
provides this support in very much the same way serial port support is
provided - most of the functions are subtly altered duplicates of that
code. Currently only syncronous accesses are supported, although the
infra-structure for asyncronous methods is in place it has not been
tested. It would be a good starting point for anyone to get this working
at a later date though.
The patch enables programs that communicate with parallel port devices
directly through LPT0 to work.
Ed Lea <ed at orangebits.cx>
-------------- next part --------------
? server/parallel.c
Index: files/dos_fs.c
===================================================================
RCS file: /home/wine/wine/files/dos_fs.c,v
retrieving revision 1.135
diff -u -u -r1.135 dos_fs.c
--- files/dos_fs.c 2 Sep 2003 18:14:50 -0000 1.135
+++ files/dos_fs.c 4 Sep 2003 14:56:47 -0000
@@ -930,6 +930,67 @@
return ret;
}
+
+/**************************************************************************
+ * DOSFS_CreateParallelPort
+ */
+static HANDLE DOSFS_CreateParallelPort(LPCWSTR name, DWORD access, DWORD attributes, LPSECURITY_ATTRIBUTES sa)
+{
+ HANDLE ret;
+ HKEY hkey;
+ DWORD dummy;
+ OBJECT_ATTRIBUTES attr;
+ UNICODE_STRING nameW;
+ WCHAR *devnameW;
+ char tmp[128];
+ char devname[40];
+
+ static const WCHAR parallelportsW[] = {'M','a','c','h','i','n','e','\\',
+ 'S','o','f','t','w','a','r','e','\\',
+ 'W','i','n','e','\\','W','i','n','e','\\',
+ 'C','o','n','f','i','g','\\',
+ 'P','a','r','a','l','l','e','l','P','o','r','t','s',0};
+
+ attr.Length = sizeof(attr);
+ attr.RootDirectory = 0;
+ attr.ObjectName = &nameW;
+ attr.Attributes = 0;
+ attr.SecurityDescriptor = NULL;
+ attr.SecurityQualityOfService = NULL;
+ RtlInitUnicodeString( &nameW, parallelportsW );
+
+ if (NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr )) return 0;
+
+ RtlInitUnicodeString( &nameW, name );
+ if (!NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &dummy ))
+ devnameW = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
+ else
+ devnameW = NULL;
+
+ NtClose( hkey );
+
+ if (!devnameW) return 0;
+ WideCharToMultiByte(CP_ACP, 0, devnameW, -1, devname, sizeof(devname), NULL, NULL);
+
+ SERVER_START_REQ( create_parallel )
+ {
+ req->access = access;
+ req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
+ req->attributes = attributes;
+ req->sharing = FILE_SHARE_READ|FILE_SHARE_WRITE;
+ wine_server_add_data( req, devname, strlen(devname) );
+ SetLastError(0);
+ wine_server_call_err( req );
+ ret = reply->handle;
+ }
+ SERVER_END_REQ;
+
+ if (!ret)
+ ERR("Could not open device '%s'.\n", devname);
+ return ret;
+}
+
+
/***********************************************************************
* DOSFS_OpenDevice
*
@@ -957,6 +1018,7 @@
static const WCHAR scsimgrW[] = {'S','C','S','I','M','G','R','$',0};
static const WCHAR hpscanW[] = {'H','P','S','C','A','N',0};
static const WCHAR emmxxxx0W[] = {'E','M','M','X','X','X','X','0',0};
+ static const WCHAR lpt1[] = {'L', 'P', 'T', '1', 0};
/* got it */
if (!strcmpiW(DOSFS_Devices[i].name, nulW))
return FILE_CreateFile( "/dev/null", access,
@@ -988,6 +1050,11 @@
{
return FILE_CreateDevice( i, access, sa );
}
+ if (!strcmpiW(DOSFS_Devices[i].name, lpt1))
+ {
+ if (handle = DOSFS_CreateParallelPort(DOSFS_Devices[i].name,access,attributes,sa))
+ return handle;
+ }
if( (handle=DOSFS_CreateCommPort(DOSFS_Devices[i].name,access,attributes,sa)) )
return handle;
Index: include/wine/server_protocol.h
===================================================================
RCS file: /home/wine/wine/include/wine/server_protocol.h,v
retrieving revision 1.81
diff -u -u -r1.81 server_protocol.h
--- include/wine/server_protocol.h 28 Aug 2003 21:43:34 -0000 1.81
+++ include/wine/server_protocol.h 4 Sep 2003 14:56:47 -0000
@@ -2393,6 +2393,24 @@
+struct create_parallel_request
+{
+ struct request_header __header;
+ unsigned int access;
+ int inherit;
+ unsigned int attributes;
+ unsigned int sharing;
+ /* VARARG(name,string); */
+};
+struct create_parallel_reply
+{
+ struct reply_header __header;
+ obj_handle_t handle;
+};
+
+
+
+
struct register_async_request
{
struct request_header __header;
@@ -3246,6 +3264,7 @@
REQ_create_serial,
REQ_get_serial_info,
REQ_set_serial_info,
+ REQ_create_parallel,
REQ_register_async,
REQ_create_named_pipe,
REQ_open_named_pipe,
@@ -3431,6 +3450,7 @@
struct create_serial_request create_serial_request;
struct get_serial_info_request get_serial_info_request;
struct set_serial_info_request set_serial_info_request;
+ struct create_parallel_request create_parallel_request;
struct register_async_request register_async_request;
struct create_named_pipe_request create_named_pipe_request;
struct open_named_pipe_request open_named_pipe_request;
@@ -3614,6 +3634,7 @@
struct create_serial_reply create_serial_reply;
struct get_serial_info_reply get_serial_info_reply;
struct set_serial_info_reply set_serial_info_reply;
+ struct create_parallel_reply create_parallel_reply;
struct register_async_reply register_async_reply;
struct create_named_pipe_reply create_named_pipe_reply;
struct open_named_pipe_reply open_named_pipe_reply;
Index: server/Makefile.in
===================================================================
RCS file: /home/wine/wine/server/Makefile.in,v
retrieving revision 1.47
diff -u -u -r1.47 Makefile.in
--- server/Makefile.in 24 Jul 2003 00:07:00 -0000 1.47
+++ server/Makefile.in 4 Sep 2003 14:56:47 -0000
@@ -26,6 +26,7 @@
mutex.c \
named_pipe.c \
object.c \
+ parallel.c \
process.c \
ptrace.c \
queue.c \
Index: server/protocol.def
===================================================================
RCS file: /home/wine/wine/server/protocol.def,v
retrieving revision 1.80
diff -u -u -r1.80 protocol.def
--- server/protocol.def 19 Aug 2003 03:08:17 -0000 1.80
+++ server/protocol.def 4 Sep 2003 14:56:47 -0000
@@ -1698,6 +1698,18 @@
#define SERIALINFO_SET_ERROR 0x04
+/* Open a parallel port */
+ at REQ(create_parallel)
+ unsigned int access; /* wanted access rights */
+ int inherit; /* inherit flag */
+ unsigned int attributes; /* eg. FILE_FLAG_OVERLAPPED */
+ unsigned int sharing; /* sharing flags */
+ VARARG(name,string); /* file name */
+ at REPLY
+ obj_handle_t handle; /* handle to the port */
+ at END
+
+
/* Create / reschedule an async I/O */
@REQ(register_async)
obj_handle_t handle; /* handle to comm port, socket or file */
Index: server/request.h
===================================================================
RCS file: /home/wine/wine/server/request.h,v
retrieving revision 1.88
diff -u -u -r1.88 request.h
--- server/request.h 19 Aug 2003 03:08:17 -0000 1.88
+++ server/request.h 4 Sep 2003 14:56:47 -0000
@@ -236,6 +236,7 @@
DECL_HANDLER(create_serial);
DECL_HANDLER(get_serial_info);
DECL_HANDLER(set_serial_info);
+DECL_HANDLER(create_parallel);
DECL_HANDLER(register_async);
DECL_HANDLER(create_named_pipe);
DECL_HANDLER(open_named_pipe);
@@ -420,6 +421,7 @@
(req_handler)req_create_serial,
(req_handler)req_get_serial_info,
(req_handler)req_set_serial_info,
+ (req_handler)req_create_parallel,
(req_handler)req_register_async,
(req_handler)req_create_named_pipe,
(req_handler)req_open_named_pipe,
--- /dev/null 2003-03-14 13:07:09.000000000 +0000
+++ server/parallel.c 2003-09-04 16:02:19.000000000 +0100
@@ -0,0 +1,327 @@
+/*
+ * Server-side parallel port communications management
+ *
+ * Copyright (C) 1998 Alexandre Julliard
+ * Copyright (C) 2000,2001 Mike McCormack
+ * Copyright (C) 2003 Ed Lea
+ *
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * This file is basically serial.c adapted for parallel accesses.
+ * FIXME: all accesses are done syncronously even if the access method specifies
+ * that they should be done asyncronously. The framework for asyncronous
+ * requests has been implemented from serial.c but remains untested.
+ */
+
+#include "config.h"
+#include "wine/port.h"
+
+#include <assert.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+#ifdef HAVE_UTIME_H
+#include <utime.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#include "winerror.h"
+#include "winbase.h"
+
+#include "file.h"
+#include "handle.h"
+#include "thread.h"
+#include "request.h"
+#include "async.h"
+
+static struct fd *parallel_get_fd( struct object *obj );
+static void parallel_destroy( struct object *obj);
+static void parallel_dump( struct object *obj, int verbose );
+
+static int parallel_get_poll_events( struct fd *fd );
+static void parallel_poll_event( struct fd *fd, int event );
+static int parallel_get_info( struct fd *fd, struct get_file_info_reply *reply, int *flags );
+static int parallel_flush( struct fd *fd, struct event **event );
+static void parallel_queue_async(struct fd *fd, void *ptr, unsigned int status, int type, int count);
+
+struct parallel
+{
+ struct object obj;
+ struct fd *fd;
+ unsigned int access;
+ unsigned int attrib;
+
+ /* timeout values */
+ unsigned int readinterval;
+ unsigned int readconst;
+ unsigned int readmult;
+ unsigned int writeconst;
+ unsigned int writemult;
+
+ struct async_queue read_q;
+ struct async_queue write_q;
+ struct async_queue wait_q;
+
+};
+
+static const struct object_ops parallel_ops =
+{
+ sizeof(struct parallel), /* size */
+ parallel_dump, /* dump */
+ default_fd_add_queue, /* add_queue */
+ default_fd_remove_queue, /* remove_queue */
+ default_fd_signaled, /* signaled */
+ no_satisfied, /* satisfied */
+ parallel_get_fd, /* get_fd */
+ parallel_destroy /* destroy */
+};
+
+static const struct fd_ops parallel_fd_ops =
+{
+ parallel_get_poll_events, /* get_poll_events */
+ parallel_poll_event, /* poll_event */
+ parallel_flush, /* flush */
+ parallel_get_info, /* get_file_info */
+ parallel_queue_async /* queue_async */
+};
+
+static struct parallel *create_parallel( const char *nameptr, size_t len, unsigned int access, int attributes )
+{
+ struct parallel *parallel;
+ int fd, flags = 0;
+ char *name;
+
+ if (!(name = mem_alloc( len + 1 ))) return NULL;
+ memcpy( name, nameptr, len );
+ name[len] = 0;
+
+ switch(access & (GENERIC_READ | GENERIC_WRITE))
+ {
+ case GENERIC_READ: flags |= O_RDONLY; break;
+ case GENERIC_WRITE: flags |= O_WRONLY; break;
+ case GENERIC_READ|GENERIC_WRITE: flags |= O_RDWR; break;
+ default: break;
+ }
+
+ flags |= O_NONBLOCK;
+
+ fd = open( name, flags );
+ free( name );
+ if (fd < 0)
+ {
+ file_set_error();
+ return NULL;
+ }
+
+ /* set the fd back to blocking if necessary */
+ if( ! (attributes & FILE_FLAG_OVERLAPPED) )
+ if(0>fcntl(fd, F_SETFL, 0))
+ perror("fcntl");
+
+ if (!(parallel = alloc_object( ¶llel_ops )))
+ {
+ close( fd );
+ return NULL;
+ }
+ parallel->attrib = attributes;
+ parallel->access = access;
+ parallel->readinterval = 0;
+ parallel->readmult = 0;
+ parallel->readconst = 0;
+ parallel->writemult = 0;
+ parallel->writeconst = 0;
+ init_async_queue(¶llel->read_q);
+ init_async_queue(¶llel->write_q);
+ init_async_queue(¶llel->wait_q);
+ if (!(parallel->fd = create_anonymous_fd( ¶llel_fd_ops, fd, ¶llel->obj )))
+ {
+ release_object( parallel );
+ return NULL;
+ }
+ return parallel;
+}
+
+static struct fd *parallel_get_fd( struct object *obj )
+{
+ struct parallel *parallel = (struct parallel *)obj;
+ return (struct fd *)grab_object( parallel->fd );
+}
+
+static void parallel_destroy( struct object *obj)
+{
+ struct parallel *parallel = (struct parallel *)obj;
+
+ destroy_async_queue(¶llel->read_q);
+ destroy_async_queue(¶llel->write_q);
+ destroy_async_queue(¶llel->wait_q);
+ if (parallel->fd) release_object( parallel->fd );
+}
+
+static void parallel_dump( struct object *obj, int verbose )
+{
+ struct parallel *parallel = (struct parallel *)obj;
+ assert( obj->ops == ¶llel_ops );
+ fprintf( stderr, "Port fd=%p\n", parallel->fd );
+}
+
+static struct parallel *get_parallel_obj( struct process *process, obj_handle_t handle, unsigned int access )
+{
+ return (struct parallel *)get_handle_obj( process, handle, access, ¶llel_ops );
+}
+
+static int parallel_get_poll_events (struct fd *fd)
+{
+ struct parallel *parallel = get_fd_user(fd);
+ int events = 0;
+ assert(parallel->obj.ops == ¶llel_ops);
+
+ if (IS_READY(parallel->read_q))
+ events |= POLLIN;
+ if (IS_READY(parallel->write_q))
+ events |= POLLOUT;
+ if (IS_READY(parallel->wait_q))
+ events |= POLLIN;
+
+ return events;
+}
+
+static int parallel_get_info (struct fd *fd, struct get_file_info_reply *reply, int *flags)
+{
+ struct parallel *parallel = get_fd_user(fd);
+ assert(parallel->obj.ops == ¶llel_ops);
+
+ if (reply)
+ {
+ reply->type = FILE_TYPE_CHAR;
+ reply->attr = 0;
+ reply->access_time = 0;
+ reply->write_time = 0;
+ reply->size_high = 0;
+ reply->size_low = 0;
+ reply->links = 0;
+ reply->index_high = 0;
+ reply->index_low = 0;
+ reply->serial = 0;
+ }
+
+ /* Only synchronous writes are currently supported. If FILE_FLAG_OVERLAPPED
+ * or FD_FLAG_TIMEOUT are set NtWriteFile will attempt an asynchronous
+ * write which will not work */
+ *flags = 0;
+
+ return FD_TYPE_DEFAULT;
+}
+
+static void parallel_poll_event (struct fd *fd, int event)
+{
+ struct parallel *parallel = get_fd_user( fd );
+
+ if (IS_READY(parallel->read_q) && (POLLIN & event))
+ async_notify(parallel->read_q.head,STATUS_ALERTED);
+
+ if (IS_READY(parallel->write_q) && (POLLOUT & event))
+ async_notify(parallel->write_q.head,STATUS_ALERTED);
+
+ if (IS_READY(parallel->wait_q) && (POLLIN & event))
+ async_notify(parallel->wait_q.head,STATUS_ALERTED);
+
+ set_fd_events(fd, parallel_get_poll_events(fd));
+}
+
+static void parallel_queue_async (struct fd *fd, void *ptr, unsigned int status, int type, int count)
+{
+ struct parallel *parallel = get_fd_user(fd);
+ struct async_queue *q;
+ struct async *async;
+ int timeout;
+ assert(parallel->obj.ops == ¶llel_ops);
+
+ fprintf(stderr, "parallel_queue_async\n");
+ switch(type)
+ {
+ case ASYNC_TYPE_READ:
+ q = ¶llel->read_q;
+ timeout = parallel->readconst + parallel->readmult*count;
+ break;
+ case ASYNC_TYPE_WAIT:
+ q = ¶llel->wait_q;
+ timeout = 0;
+ break;
+ case ASYNC_TYPE_WRITE:
+ q = ¶llel->write_q;
+ timeout = parallel->writeconst + parallel->writemult*count;
+ break;
+ default:
+ set_error(STATUS_INVALID_PARAMETER);
+ return;
+ }
+
+ async = find_async(q, current, ptr);
+
+ if (status == STATUS_PENDING)
+ {
+ int events;
+
+ if (!async)
+ async = create_async(¶llel->obj, current, ptr);
+ if (!async)
+ return;
+
+ async->status = STATUS_PENDING;
+ if (!async->q)
+ {
+ async_add_timeout(async, timeout);
+ async_insert(q, async);
+ }
+
+ events = check_fd_events(fd, parallel_get_poll_events(fd));
+ if (events)
+ {
+ parallel_poll_event(fd, events);
+ return;
+ }
+ }
+ else if (async) destroy_async(async);
+ else set_error(STATUS_INVALID_PARAMETER);
+
+ set_fd_events(fd, parallel_get_poll_events(fd));
+}
+
+static int parallel_flush (struct fd *fd, struct event **event)
+{
+ return 0;
+}
+
+/* create a parallel */
+DECL_HANDLER(create_parallel)
+{
+ struct parallel *parallel;
+
+ reply->handle = 0;
+ if ((parallel = create_parallel( get_req_data(), get_req_data_size(), req->access, req->attributes )))
+ {
+ reply->handle = alloc_handle( current->process, parallel, req->access, req->inherit );
+
+ release_object( parallel );
+ }
+}
More information about the wine-patches
mailing list