1 /* -*- c-basic-offset: 8 -*-
2    rdesktop: A Remote Desktop Protocol client.
3    Copyright (C) Matthew Chapman 1999-2005
4 
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2 of the License, or
8    (at your option) any later version.
9 
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14 
15    You should have received a copy of the GNU General Public License along
16    with this program; if not, write to the Free Software Foundation, Inc.,
17    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 #define	MAX_PARALLEL_DEVICES		1
20 
21 #define FILE_DEVICE_PARALLEL		0x22
22 
23 #define IOCTL_PAR_QUERY_RAW_DEVICE_ID	0x0c
24 
25 #include "rdesktop.h"
26 #include <unistd.h>
27 #include <fcntl.h>
28 #include <sys/ioctl.h>
29 #include <errno.h>
30 
31 #if defined(__linux__)
32 #include <linux/lp.h>
33 #endif
34 
35 /* Enumeration of devices from rdesktop.c        */
36 /* returns numer of units found and initialized. */
37 /* optarg looks like ':LPT1=/dev/lp0'            */
38 /* when it arrives to this function.             */
39 int
40 parallel_enum_devices(RDPCLIENT * This, uint32 * id, char *optarg)
41 {
42 	PARALLEL_DEVICE *ppar_info;
43 
44 	char *pos = optarg;
45 	char *pos2;
46 	int count = 0;
47 
48 	/* skip the first colon */
49 	optarg++;
50 	while ((pos = next_arg(optarg, ',')) && *id < RDPDR_MAX_DEVICES)
51 	{
52 		ppar_info = (PARALLEL_DEVICE *) xmalloc(sizeof(PARALLEL_DEVICE));
53 
54 		pos2 = next_arg(optarg, '=');
55 		strcpy(This->rdpdr_device[*id].name, optarg);
56 
57 		toupper_str(This->rdpdr_device[*id].name);
58 
59 		This->rdpdr_device[*id].local_path = xmalloc(strlen(pos2) + 1);
60 		strcpy(This->rdpdr_device[*id].local_path, pos2);
61 		printf("PARALLEL %s to %s\n", optarg, pos2);
62 
63 		/* set device type */
64 		This->rdpdr_device[*id].device_type = DEVICE_TYPE_PARALLEL;
65 		This->rdpdr_device[*id].pdevice_data = (void *) ppar_info;
66 		This->rdpdr_device[*id].handle = 0;
67 		count++;
68 		(*id)++;
69 
70 		optarg = pos;
71 	}
72 	return count;
73 }
74 
75 static NTSTATUS
76 parallel_create(RDPCLIENT * This, uint32 device_id, uint32 access, uint32 share_mode, uint32 disposition,
77 		uint32 flags, char *filename, NTHANDLE * handle)
78 {
79 	int parallel_fd;
80 
81 	parallel_fd = open(This->rdpdr_device[device_id].local_path, O_RDWR);
82 	if (parallel_fd == -1)
83 	{
84 		perror("open");
85 		return STATUS_ACCESS_DENIED;
86 	}
87 
88 	/* all read and writes should be non blocking */
89 	if (fcntl(parallel_fd, F_SETFL, O_NONBLOCK) == -1)
90 		perror("fcntl");
91 
92 #if defined(LPABORT)
93 	/* Retry on errors */
94 	ioctl(parallel_fd, LPABORT, (int) 1);
95 #endif
96 
97 	This->rdpdr_device[device_id].handle = parallel_fd;
98 
99 	*handle = parallel_fd;
100 
101 	return STATUS_SUCCESS;
102 }
103 
104 static NTSTATUS
105 parallel_close(RDPCLIENT * This, NTHANDLE handle)
106 {
107 	int i = get_device_index(This, handle);
108 	if (i >= 0)
109 		This->rdpdr_device[i].handle = 0;
110 	close(handle);
111 	return STATUS_SUCCESS;
112 }
113 
114 static NTSTATUS
115 parallel_read(RDPCLIENT * This, NTHANDLE handle, uint8 * data, uint32 length, uint32 offset, uint32 * result)
116 {
117 	*result = read(handle, data, length);
118 	return STATUS_SUCCESS;
119 }
120 
121 static NTSTATUS
122 parallel_write(RDPCLIENT * This, NTHANDLE handle, uint8 * data, uint32 length, uint32 offset, uint32 * result)
123 {
124 	int rc = STATUS_SUCCESS;
125 
126 	int n = write(handle, data, length);
127 	if (n < 0)
128 	{
129 #if defined(LPGETSTATUS)
130 		int status;
131 #endif
132 
133 		*result = 0;
134 		switch (errno)
135 		{
136 			case EAGAIN:
137 				rc = STATUS_DEVICE_OFF_LINE;
138 			case ENOSPC:
139 				rc = STATUS_DEVICE_PAPER_EMPTY;
140 			case EIO:
141 				rc = STATUS_DEVICE_OFF_LINE;
142 			default:
143 				rc = STATUS_DEVICE_POWERED_OFF;
144 		}
145 #if defined(LPGETSTATUS)
146 		if (ioctl(handle, LPGETSTATUS, &status) == 0)
147 		{
148 			/* coming soon: take care for the printer status */
149 			printf("parallel_write: status = %d, errno = %d\n", status, errno);
150 		}
151 #endif
152 	}
153 	*result = n;
154 	return rc;
155 }
156 
157 static NTSTATUS
158 parallel_device_control(RDPCLIENT * This, NTHANDLE handle, uint32 request, STREAM in, STREAM out)
159 {
160 	if ((request >> 16) != FILE_DEVICE_PARALLEL)
161 		return STATUS_INVALID_PARAMETER;
162 
163 	/* extract operation */
164 	request >>= 2;
165 	request &= 0xfff;
166 
167 	printf("PARALLEL IOCTL %d: ", request);
168 
169 	switch (request)
170 	{
171 		case IOCTL_PAR_QUERY_RAW_DEVICE_ID:
172 
173 		default:
174 
175 			printf("\n");
176 			unimpl("UNKNOWN IOCTL %d\n", request);
177 	}
178 	return STATUS_SUCCESS;
179 }
180 
181 DEVICE_FNS parallel_fns = {
182 	parallel_create,
183 	parallel_close,
184 	parallel_read,
185 	parallel_write,
186 	parallel_device_control
187 };
188