master
c 306 lines 8.29 KB
Raw
1 /*
2 * QEMU System Emulator
3 *
4 * Copyright (c) 2003-2008 Fabrice Bellard
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24
25 #include "qemu/osdep.h"
26 #include "chardev/char.h"
27 #include "qapi/error.h"
28 #include "qemu/module.h"
29 #include "qemu/option.h"
30 #include <sys/ioctl.h>
31
32 #ifdef CONFIG_BSD
33 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
34 #include <dev/ppbus/ppi.h>
35 #include <dev/ppbus/ppbconf.h>
36 #elif defined(__DragonFly__)
37 #include <dev/misc/ppi/ppi.h>
38 #include <bus/ppbus/ppbconf.h>
39 #endif
40 #else
41 #ifdef __linux__
42 #include <linux/ppdev.h>
43 #include <linux/parport.h>
44 #endif
45 #endif
46
47 #include "chardev/char-fd.h"
48 #include "chardev/char-parallel.h"
49
50 #if defined(__linux__)
51
52 typedef struct {
53 Chardev parent;
54 int fd;
55 int mode;
56 } ParallelChardev;
57
58 #define PARALLEL_CHARDEV(obj) \
59 OBJECT_CHECK(ParallelChardev, (obj), TYPE_CHARDEV_PARALLEL)
60
61 static int pp_hw_mode(ParallelChardev *s, uint16_t mode)
62 {
63 if (s->mode != mode) {
64 int m = mode;
65 if (ioctl(s->fd, PPSETMODE, &m) < 0) {
66 return 0;
67 }
68 s->mode = mode;
69 }
70 return 1;
71 }
72
73 static int parallel_chr_ioctl(Chardev *chr, int cmd, void *arg)
74 {
75 ParallelChardev *drv = PARALLEL_CHARDEV(chr);
76 int fd = drv->fd;
77 uint8_t b;
78
79 switch (cmd) {
80 case CHR_IOCTL_PP_READ_DATA:
81 if (ioctl(fd, PPRDATA, &b) < 0) {
82 return -ENOTSUP;
83 }
84 *(uint8_t *)arg = b;
85 break;
86 case CHR_IOCTL_PP_WRITE_DATA:
87 b = *(uint8_t *)arg;
88 if (ioctl(fd, PPWDATA, &b) < 0) {
89 return -ENOTSUP;
90 }
91 break;
92 case CHR_IOCTL_PP_READ_CONTROL:
93 if (ioctl(fd, PPRCONTROL, &b) < 0) {
94 return -ENOTSUP;
95 }
96 /* Linux gives only the lowest bits, and no way to know data
97 direction! For better compatibility set the fixed upper
98 bits. */
99 *(uint8_t *)arg = b | 0xc0;
100 break;
101 case CHR_IOCTL_PP_WRITE_CONTROL:
102 b = *(uint8_t *)arg;
103 if (ioctl(fd, PPWCONTROL, &b) < 0) {
104 return -ENOTSUP;
105 }
106 break;
107 case CHR_IOCTL_PP_READ_STATUS:
108 if (ioctl(fd, PPRSTATUS, &b) < 0) {
109 return -ENOTSUP;
110 }
111 *(uint8_t *)arg = b;
112 break;
113 case CHR_IOCTL_PP_DATA_DIR:
114 if (ioctl(fd, PPDATADIR, (int *)arg) < 0) {
115 return -ENOTSUP;
116 }
117 break;
118 case CHR_IOCTL_PP_EPP_READ_ADDR:
119 if (pp_hw_mode(drv, IEEE1284_MODE_EPP | IEEE1284_ADDR)) {
120 struct ParallelIOArg *parg = arg;
121 int n = read(fd, parg->buffer, parg->count);
122 if (n != parg->count) {
123 return -EIO;
124 }
125 }
126 break;
127 case CHR_IOCTL_PP_EPP_READ:
128 if (pp_hw_mode(drv, IEEE1284_MODE_EPP)) {
129 struct ParallelIOArg *parg = arg;
130 int n = read(fd, parg->buffer, parg->count);
131 if (n != parg->count) {
132 return -EIO;
133 }
134 }
135 break;
136 case CHR_IOCTL_PP_EPP_WRITE_ADDR:
137 if (pp_hw_mode(drv, IEEE1284_MODE_EPP | IEEE1284_ADDR)) {
138 struct ParallelIOArg *parg = arg;
139 int n = write(fd, parg->buffer, parg->count);
140 if (n != parg->count) {
141 return -EIO;
142 }
143 }
144 break;
145 case CHR_IOCTL_PP_EPP_WRITE:
146 if (pp_hw_mode(drv, IEEE1284_MODE_EPP)) {
147 struct ParallelIOArg *parg = arg;
148 int n = write(fd, parg->buffer, parg->count);
149 if (n != parg->count) {
150 return -EIO;
151 }
152 }
153 break;
154 default:
155 return -ENOTSUP;
156 }
157 return 0;
158 }
159
160 static bool parallel_chr_open_fd(Chardev *chr, int fd, Error **errp)
161 {
162 ParallelChardev *drv = PARALLEL_CHARDEV(chr);
163
164 drv->fd = fd;
165
166 if (ioctl(fd, PPCLAIM) < 0) {
167 error_setg_errno(errp, errno, "not a parallel port");
168 return false;
169 }
170
171 drv->mode = IEEE1284_MODE_COMPAT;
172 qemu_chr_be_event(chr, CHR_EVENT_OPENED);
173 return true;
174 }
175 #endif /* __linux__ */
176
177 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
178
179 typedef struct {
180 Chardev parent;
181 int fd;
182 } ParallelChardev;
183
184 #define PARALLEL_CHARDEV(obj) \
185 OBJECT_CHECK(ParallelChardev, (obj), TYPE_CHARDEV_PARALLEL)
186
187 static int parallel_chr_ioctl(Chardev *chr, int cmd, void *arg)
188 {
189 ParallelChardev *drv = PARALLEL_CHARDEV(chr);
190 uint8_t b;
191
192 switch (cmd) {
193 case CHR_IOCTL_PP_READ_DATA:
194 if (ioctl(drv->fd, PPIGDATA, &b) < 0) {
195 return -ENOTSUP;
196 }
197 *(uint8_t *)arg = b;
198 break;
199 case CHR_IOCTL_PP_WRITE_DATA:
200 b = *(uint8_t *)arg;
201 if (ioctl(drv->fd, PPISDATA, &b) < 0) {
202 return -ENOTSUP;
203 }
204 break;
205 case CHR_IOCTL_PP_READ_CONTROL:
206 if (ioctl(drv->fd, PPIGCTRL, &b) < 0) {
207 return -ENOTSUP;
208 }
209 *(uint8_t *)arg = b;
210 break;
211 case CHR_IOCTL_PP_WRITE_CONTROL:
212 b = *(uint8_t *)arg;
213 if (ioctl(drv->fd, PPISCTRL, &b) < 0) {
214 return -ENOTSUP;
215 }
216 break;
217 case CHR_IOCTL_PP_READ_STATUS:
218 if (ioctl(drv->fd, PPIGSTATUS, &b) < 0) {
219 return -ENOTSUP;
220 }
221 *(uint8_t *)arg = b;
222 break;
223 default:
224 return -ENOTSUP;
225 }
226 return 0;
227 }
228
229 static bool parallel_chr_open_fd(Chardev *chr, int fd, Error **errp)
230 {
231 ParallelChardev *drv = PARALLEL_CHARDEV(chr);
232 drv->fd = fd;
233 return true;
234 }
235 #endif
236
237 #ifdef HAVE_CHARDEV_PARALLEL
238 static bool parallel_chr_open(Chardev *chr,
239 ChardevBackend *backend,
240 Error **errp)
241 {
242 ChardevHostdev *parallel = backend->u.parallel.data;
243 int fd;
244
245 fd = qmp_chardev_open_file_source(parallel->device, O_RDWR, errp);
246 if (fd < 0) {
247 return false;
248 }
249 return parallel_chr_open_fd(chr, fd, errp);
250 }
251
252 static void parallel_chr_parse(QemuOpts *opts, ChardevBackend *backend,
253 Error **errp)
254 {
255 const char *device = qemu_opt_get(opts, "path");
256 ChardevHostdev *parallel;
257
258 if (device == NULL) {
259 error_setg(errp, "chardev: parallel: no device path given");
260 return;
261 }
262 backend->type = CHARDEV_BACKEND_KIND_PARALLEL;
263 parallel = backend->u.parallel.data = g_new0(ChardevHostdev, 1);
264 qemu_chr_parse_common(opts, qapi_ChardevHostdev_base(parallel));
265 parallel->device = g_strdup(device);
266 }
267
268 static void char_parallel_class_init(ObjectClass *oc, const void *data)
269 {
270 ChardevClass *cc = CHARDEV_CLASS(oc);
271
272 cc->chr_parse = parallel_chr_parse;
273 cc->chr_open = parallel_chr_open;
274 cc->chr_ioctl = parallel_chr_ioctl;
275 }
276
277 static void char_parallel_finalize(Object *obj)
278 {
279 Chardev *chr = CHARDEV(obj);
280 ParallelChardev *drv = PARALLEL_CHARDEV(chr);
281 int fd = drv->fd;
282
283 #if defined(__linux__)
284 pp_hw_mode(drv, IEEE1284_MODE_COMPAT);
285 ioctl(fd, PPRELEASE);
286 #endif
287 close(fd);
288 qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
289 }
290
291 static const TypeInfo char_parallel_type_info = {
292 .name = TYPE_CHARDEV_PARALLEL,
293 .parent = TYPE_CHARDEV,
294 .instance_size = sizeof(ParallelChardev),
295 .instance_finalize = char_parallel_finalize,
296 .class_init = char_parallel_class_init,
297 };
298
299 static void register_types(void)
300 {
301 type_register_static(&char_parallel_type_info);
302 }
303
304 type_init(register_types);
305
306 #endif /* HAVE_CHARDEV_PARALLEL */