qemu/chardev/char-parallel.c
<<
>>
Prefs
   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
  52typedef 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
  61static 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
  73static int pp_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
 160static void qemu_chr_open_pp_fd(Chardev *chr,
 161                                int fd,
 162                                bool *be_opened,
 163                                Error **errp)
 164{
 165    ParallelChardev *drv = PARALLEL_CHARDEV(chr);
 166
 167    if (ioctl(fd, PPCLAIM) < 0) {
 168        error_setg_errno(errp, errno, "not a parallel port");
 169        close(fd);
 170        return;
 171    }
 172
 173    drv->fd = fd;
 174    drv->mode = IEEE1284_MODE_COMPAT;
 175}
 176#endif /* __linux__ */
 177
 178#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
 179
 180typedef struct {
 181    Chardev parent;
 182    int fd;
 183} ParallelChardev;
 184
 185#define PARALLEL_CHARDEV(obj)                                   \
 186    OBJECT_CHECK(ParallelChardev, (obj), TYPE_CHARDEV_PARALLEL)
 187
 188static int pp_ioctl(Chardev *chr, int cmd, void *arg)
 189{
 190    ParallelChardev *drv = PARALLEL_CHARDEV(chr);
 191    uint8_t b;
 192
 193    switch (cmd) {
 194    case CHR_IOCTL_PP_READ_DATA:
 195        if (ioctl(drv->fd, PPIGDATA, &b) < 0) {
 196            return -ENOTSUP;
 197        }
 198        *(uint8_t *)arg = b;
 199        break;
 200    case CHR_IOCTL_PP_WRITE_DATA:
 201        b = *(uint8_t *)arg;
 202        if (ioctl(drv->fd, PPISDATA, &b) < 0) {
 203            return -ENOTSUP;
 204        }
 205        break;
 206    case CHR_IOCTL_PP_READ_CONTROL:
 207        if (ioctl(drv->fd, PPIGCTRL, &b) < 0) {
 208            return -ENOTSUP;
 209        }
 210        *(uint8_t *)arg = b;
 211        break;
 212    case CHR_IOCTL_PP_WRITE_CONTROL:
 213        b = *(uint8_t *)arg;
 214        if (ioctl(drv->fd, PPISCTRL, &b) < 0) {
 215            return -ENOTSUP;
 216        }
 217        break;
 218    case CHR_IOCTL_PP_READ_STATUS:
 219        if (ioctl(drv->fd, PPIGSTATUS, &b) < 0) {
 220            return -ENOTSUP;
 221        }
 222        *(uint8_t *)arg = b;
 223        break;
 224    default:
 225        return -ENOTSUP;
 226    }
 227    return 0;
 228}
 229
 230static void qemu_chr_open_pp_fd(Chardev *chr,
 231                                int fd,
 232                                bool *be_opened,
 233                                Error **errp)
 234{
 235    ParallelChardev *drv = PARALLEL_CHARDEV(chr);
 236    drv->fd = fd;
 237    *be_opened = false;
 238}
 239#endif
 240
 241#ifdef HAVE_CHARDEV_PARPORT
 242static void qmp_chardev_open_parallel(Chardev *chr,
 243                                      ChardevBackend *backend,
 244                                      bool *be_opened,
 245                                      Error **errp)
 246{
 247    ChardevHostdev *parallel = backend->u.parallel.data;
 248    int fd;
 249
 250    fd = qmp_chardev_open_file_source(parallel->device, O_RDWR, errp);
 251    if (fd < 0) {
 252        return;
 253    }
 254    qemu_chr_open_pp_fd(chr, fd, be_opened, errp);
 255}
 256
 257static void qemu_chr_parse_parallel(QemuOpts *opts, ChardevBackend *backend,
 258                                    Error **errp)
 259{
 260    const char *device = qemu_opt_get(opts, "path");
 261    ChardevHostdev *parallel;
 262
 263    if (device == NULL) {
 264        error_setg(errp, "chardev: parallel: no device path given");
 265        return;
 266    }
 267    backend->type = CHARDEV_BACKEND_KIND_PARALLEL;
 268    parallel = backend->u.parallel.data = g_new0(ChardevHostdev, 1);
 269    qemu_chr_parse_common(opts, qapi_ChardevHostdev_base(parallel));
 270    parallel->device = g_strdup(device);
 271}
 272
 273static void char_parallel_class_init(ObjectClass *oc, void *data)
 274{
 275    ChardevClass *cc = CHARDEV_CLASS(oc);
 276
 277    cc->parse = qemu_chr_parse_parallel;
 278    cc->open = qmp_chardev_open_parallel;
 279#if defined(__linux__)
 280    cc->chr_ioctl = pp_ioctl;
 281#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \
 282    defined(__DragonFly__)
 283    cc->chr_ioctl = pp_ioctl;
 284#endif
 285}
 286
 287static void char_parallel_finalize(Object *obj)
 288{
 289#if defined(__linux__)
 290    Chardev *chr = CHARDEV(obj);
 291    ParallelChardev *drv = PARALLEL_CHARDEV(chr);
 292    int fd = drv->fd;
 293
 294    pp_hw_mode(drv, IEEE1284_MODE_COMPAT);
 295    ioctl(fd, PPRELEASE);
 296    close(fd);
 297    qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
 298#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \
 299    defined(__DragonFly__)
 300    /* FIXME: close fd? */
 301#endif
 302}
 303
 304static const TypeInfo char_parallel_type_info = {
 305    .name = TYPE_CHARDEV_PARALLEL,
 306    .parent = TYPE_CHARDEV,
 307    .instance_size = sizeof(ParallelChardev),
 308    .instance_finalize = char_parallel_finalize,
 309    .class_init = char_parallel_class_init,
 310};
 311
 312static void register_types(void)
 313{
 314    type_register_static(&char_parallel_type_info);
 315}
 316
 317type_init(register_types);
 318
 319#endif
 320