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( &parallel_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(&parallel->read_q);
+    init_async_queue(&parallel->write_q);
+    init_async_queue(&parallel->wait_q);
+    if (!(parallel->fd = create_anonymous_fd( &parallel_fd_ops, fd, &parallel->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(&parallel->read_q);
+    destroy_async_queue(&parallel->write_q);
+    destroy_async_queue(&parallel->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 == &parallel_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, &parallel_ops );
+}
+
+static int parallel_get_poll_events (struct fd *fd)
+{
+    struct parallel *parallel = get_fd_user(fd);
+    int events = 0;
+    assert(parallel->obj.ops == &parallel_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 == &parallel_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 == &parallel_ops);
+
+    fprintf(stderr, "parallel_queue_async\n");
+    switch(type)
+    {
+        case ASYNC_TYPE_READ:
+            q = &parallel->read_q;
+            timeout = parallel->readconst + parallel->readmult*count;
+            break;
+        case ASYNC_TYPE_WAIT:
+            q = &parallel->wait_q;
+            timeout = 0;
+            break;
+        case ASYNC_TYPE_WRITE:
+            q = &parallel->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(&parallel->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