/*
* Generated by util/mkerr.pl DO NOT EDIT
* Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include <openssl/err.h>
#include <openssl/randerr.h>
#ifndef OPENSSL_NO_ERR
static const ERR_STRING_DATA RAND_str_reasons[] = {
{ERR_PACK(ERR_LIB_RAND, 0, RAND_R_ADDITIONAL_INPUT_TOO_LONG),
"additional input too long"},
{ERR_PACK(ERR_LIB_RAND, 0, RAND_R_ALREADY_INSTANTIATED),
"already instantiated"},
{ERR_PACK(ERR_LIB_RAND, 0, RAND_R_ARGUMENT_OUT_OF_RANGE),
"argument out of range"},
{ERR_PACK(ERR_LIB_RAND, 0, RAND_R_CANNOT_OPEN_FILE), "Cannot open file"<#include <linux/module.h>
#include <linux/virtio.h>
#include <linux/virtio_config.h>
#include <linux/input.h>
#include <uapi/linux/virtio_ids.h>
#include <uapi/linux/virtio_input.h>
struct virtio_input {
struct virtio_device *vdev;
struct input_dev *idev;
char name[64];
char serial[64];
char phys[64];
struct virtqueue *evt, *sts;
struct virtio_input_event evts[64];
spinlock_t lock;
bool ready;
};
static void virtinput_queue_evtbuf(struct virtio_input *vi,
struct virtio_input_event *evtbuf)
{
struct scatterlist sg[1];
sg_init_one(sg, evtbuf, sizeof(*evtbuf));
virtqueue_add_inbuf(vi->evt, sg, 1, evtbuf, GFP_ATOMIC);
}
static void virtinput_recv_events(struct virtqueue *vq)
{
struct virtio_input *vi = vq->vdev->priv;
struct virtio_input_event *event;
unsigned long flags;
unsigned int len;
spin_lock_irqsave(&vi->lock, flags);
if (vi->ready) {
while ((event = virtqueue_get_buf(vi->evt, &len)) != NULL) {
spin_unlock_irqrestore(&vi->lock, flags);
input_event(vi->idev,
le16_to_cpu(event->type),
le16_to_cpu(event->code),
le32_to_cpu(event->value));
spin_lock_irqsave(&vi->lock, flags);
virtinput_queue_evtbuf(vi, event);
}
virtqueue_kick(vq);
}
spin_unlock_irqrestore(&vi->lock, flags);
}
/*
* On error we are losing the status update, which isn't critical as
* this is typically used for stuff like keyboard leds.
*/
static int virtinput_send_status(struct virtio_input *vi,
u16 type, u16 code, s32 value)
{
struct virtio_input_event *stsbuf;
struct scatterlist sg[1];
unsigned long flags;
int rc;
stsbuf = kzalloc(sizeof(*stsbuf), GFP_ATOMIC);
if (!stsbuf)
return -ENOMEM;
stsbuf->type = cpu_to_le16(type);
stsbuf->code = cpu_to_le16(code);
stsbuf->value = cpu_to_le32(value);
sg_init_one(sg, stsbuf, sizeof(*stsbuf));
spin_lock_irqsave(&vi->lock, flags);
if (vi->ready) {
rc = virtqueue_add_outbuf(vi->sts, sg, 1, stsbuf, GFP_ATOMIC);
virtqueue_kick(vi->sts);
} else {
rc = -ENODEV;
}
spin_unlock_irqrestore(&vi->lock, flags);
if (rc != 0)
kfree(stsbuf);
return rc;
}
static void virtinput_recv_status(struct virtqueue *vq)
{
struct virtio_input *vi = vq->vdev->priv;
struct virtio_input_event *stsbuf;
unsigned long flags;
unsigned int len;
spin_lock_irqsave(&vi->lock, flags);
while ((stsbuf = virtqueue_get_buf(vi->sts, &len)) != NULL)
kfree(stsbuf);
spin_unlock_irqrestore(&vi->lock, flags);
}
static int virtinput_status(struct input_dev *idev, unsigned int type,
unsigned int code, int value)
{
struct virtio_input *vi = input_get_drvdata(idev);
return virtinput_send_status(vi, type, code, value);
}
static u8 virtinput_cfg_select(struct virtio_input *vi,
u8 select, u8 subsel)
{
u8 size;
virtio_cwrite(vi->vdev, struct virtio_input_config, select, &select);
virtio_cwrite(vi->vdev, struct virtio_input_config, subsel, &subsel);
virtio_cread(vi->vdev, struct virtio_input_config, size, &size);
return size;
}
static void virtinput_cfg_bits(struct virtio_input *vi, int select, int subsel,
unsigned long *bits, unsigned int bitcount)
{
unsigned int bit;
u8 *virtio_bits;
u8 bytes;
bytes = virtinput_cfg_select(vi, select, subsel);
if (!bytes)
return;
if (bitcount > bytes * 8)
bitcount = bytes * 8;
/*
* Bitmap in virtio config space is a simple stream of bytes,
* with the first byte carrying bits 0-7, second bits 8-15 and
* so on.
*/
virtio_bits = kzalloc(bytes, GFP_KERNEL);
if (!virtio_bits)
return;
virtio_cread_bytes(vi->vdev, offsetof(struct virtio_input_config,
u.bitmap),
virtio_bits, bytes);
for (bit = 0; bit < bitcount; bit++) {
if (virtio_bits[bit / 8] & (1 << (bit % 8)))
__set_bit(bit, bits);
}
kfree(virtio_bits);
if (select == VIRTIO_INPUT_CFG_EV_BITS)
__set_bit(subsel, vi->idev->evbit);
}
static void virtinput_cfg_abs(struct virtio_input *vi, int abs)
{
u32 mi, ma, re, fu, fl;
virtinput_cfg_select(vi, VIRTIO_INPUT_CFG_ABS_INFO, abs);
virtio_cread(vi->vdev, struct virtio_input_config, u.abs.min, &mi);
virtio_cread(vi->vdev, struct virtio_input_config, u.abs.max, &ma);
virtio_cread(vi->vdev, struct virtio_input_config, u.abs.res, &re);
virtio_cread(vi->vdev, struct virtio_input_config, u.abs.fuzz, &fu);
virtio_cread(vi->vdev, struct virtio_input_config, u.abs.flat, &fl);
input_set_abs_params(vi->idev, abs, mi, ma, fu, fl);
input_abs_set_res(vi->idev, abs, re);
}
static int virtinput_init_vqs(struct virtio_input *vi)
{
struct virtqueue *vqs[2];
vq_callback_t *cbs[] = { virtinput_recv_events,
virtinput_recv_status };
static const char * const names[] = { "events", "status" };
int err;
err = vi->vdev->config->find_vqs(vi->vdev, 2, vqs, cbs, names);
if (err)
return err;
vi->evt = vqs[0];
vi->sts = vqs[1];
return 0;
}
static void virtinput_fill_evt(struct virtio_input *vi)
{
unsigned long flags;
int i, size;
spin_lock_irqsave(&vi->lock, flags);
size = virtqueue_get_vring_size(vi->evt);
if (size > ARRAY_SIZE(vi->evts))
size = ARRAY_SIZE(vi->evts);
for (i = 0; i < size; i++)
virtinput_queue_evtbuf(vi, &vi->evts[i]);
virtqueue_kick(vi->evt);
spin_unlock_irqrestore(&vi->lock, flags);
}
static int virtinput_probe(struct virtio_device *vdev)
{
struct virtio_input *vi;
unsigned long flags;
size_t size;
int abs, err;
if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1))
return -ENODEV;
vi = kzalloc(sizeof(*vi), GFP_KERNEL);
if (!vi)
return -ENOMEM;
vdev->priv = vi;