linux/drivers/platform/goldfish/goldfish_pipe.c

// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (C) 2012 Intel, Inc.
 * Copyright (C) 2013 Intel, Inc.
 * Copyright (C) 2014 Linaro Limited
 * Copyright (C) 2011-2016 Google, Inc.
 *
 * This software is licensed under the terms of the GNU General Public
 * License version 2, as published by the Free Software Foundation, and
 * may be copied, distributed, and modified under those terms.
 *
 * This program 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 General Public License for more details.
 *
 */

/* This source file contains the implementation of a special device driver
 * that intends to provide a *very* fast communication channel between the
 * guest system and the QEMU emulator.
 *
 * Usage from the guest is simply the following (error handling simplified):
 *
 *    int  fd = open("/dev/qemu_pipe",O_RDWR);
 *    .... write() or read() through the pipe.
 *
 * This driver doesn't deal with the exact protocol used during the session.
 * It is intended to be as simple as something like:
 *
 *    // do this _just_ after opening the fd to connect to a specific
 *    // emulator service.
 *    const char*  msg = "<pipename>";
 *    if (write(fd, msg, strlen(msg)+1) < 0) {
 *       ... could not connect to <pipename> service
 *       close(fd);
 *    }
 *
 *    // after this, simply read() and write() to communicate with the
 *    // service. Exact protocol details left as an exercise to the reader.
 *
 * This driver is very fast because it doesn't copy any data through
 * intermediate buffers, since the emulator is capable of translating
 * guest user addresses into host ones.
 *
 * Note that we must however ensure that each user page involved in the
 * exchange is properly mapped during a transfer.
 */

#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/spinlock.h>
#include <linux/miscdevice.h>
#include <linux/platform_device.h>
#include <linux/poll.h>
#include <linux/sched.h>
#include <linux/bitops.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/dma-mapping.h>
#include <linux/mm.h>
#include <linux/acpi.h>
#include <linux/bug.h>
#include "goldfish_pipe_qemu.h"

/*
 * Update this when something changes in the driver's behavior so the host
 * can benefit from knowing it
 */
enum {};

enum {};

struct goldfish_pipe_dev;

/* A per-pipe command structure, shared with the host */
struct goldfish_pipe_command {};

/* A single signalled pipe information */
struct signalled_pipe_buffer {};

/* Parameters for the PIPE_CMD_OPEN command */
struct open_command_param {};

/* Device-level set of buffers shared with the host */
struct goldfish_pipe_dev_buffers {};

/* This data type models a given pipe instance */
struct goldfish_pipe {};

/* The global driver data. Holds a reference to the i/o page used to
 * communicate with the emulator, and a wake queue for blocked tasks
 * waiting to be awoken.
 */
struct goldfish_pipe_dev {};

static int goldfish_pipe_cmd_locked(struct goldfish_pipe *pipe,
				    enum PipeCmdCode cmd)
{}

static int goldfish_pipe_cmd(struct goldfish_pipe *pipe, enum PipeCmdCode cmd)
{}

/*
 * This function converts an error code returned by the emulator through
 * the PIPE_REG_STATUS i/o register into a valid negative errno value.
 */
static int goldfish_pipe_error_convert(int status)
{}

static int goldfish_pin_pages(unsigned long first_page,
			      unsigned long last_page,
			      unsigned int last_page_size,
			      int is_write,
			      struct page *pages[MAX_BUFFERS_PER_COMMAND],
			      unsigned int *iter_last_page_size)
{}

/* Populate the call parameters, merging adjacent pages together */
static void populate_rw_params(struct page **pages,
			       int pages_count,
			       unsigned long address,
			       unsigned long address_end,
			       unsigned long first_page,
			       unsigned long last_page,
			       unsigned int iter_last_page_size,
			       int is_write,
			       struct goldfish_pipe_command *command)
{}

static int transfer_max_buffers(struct goldfish_pipe *pipe,
				unsigned long address,
				unsigned long address_end,
				int is_write,
				unsigned long last_page,
				unsigned int last_page_size,
				s32 *consumed_size,
				int *status)
{}

static int wait_for_host_signal(struct goldfish_pipe *pipe, int is_write)
{}

static ssize_t goldfish_pipe_read_write(struct file *filp,
					char __user *buffer,
					size_t bufflen,
					int is_write)
{}

static ssize_t goldfish_pipe_read(struct file *filp, char __user *buffer,
				  size_t bufflen, loff_t *ppos)
{}

static ssize_t goldfish_pipe_write(struct file *filp,
				   const char __user *buffer, size_t bufflen,
				   loff_t *ppos)
{}

static __poll_t goldfish_pipe_poll(struct file *filp, poll_table *wait)
{}

static void signalled_pipes_add_locked(struct goldfish_pipe_dev *dev,
				       u32 id, u32 flags)
{}

static void signalled_pipes_remove_locked(struct goldfish_pipe_dev *dev,
					  struct goldfish_pipe *pipe)
{}

static struct goldfish_pipe *signalled_pipes_pop_front(
		struct goldfish_pipe_dev *dev, int *wakes)
{}

static irqreturn_t goldfish_interrupt_task(int irq, void *dev_addr)
{}

static void goldfish_pipe_device_deinit(struct platform_device *pdev,
					struct goldfish_pipe_dev *dev);

/*
 * The general idea of the (threaded) interrupt handling:
 *
 *  1. device raises an interrupt if there's at least one signalled pipe
 *  2. IRQ handler reads the signalled pipes and their count from the device
 *  3. device writes them into a shared buffer and returns the count
 *      it only resets the IRQ if it has returned all signalled pipes,
 *      otherwise it leaves it raised, so IRQ handler will be called
 *      again for the next chunk
 *  4. IRQ handler adds all returned pipes to the device's signalled pipes list
 *  5. IRQ handler defers processing the signalled pipes from the list in a
 *      separate context
 */
static irqreturn_t goldfish_pipe_interrupt(int irq, void *dev_id)
{}

static int get_free_pipe_id_locked(struct goldfish_pipe_dev *dev)
{}

/* A helper function to get the instance of goldfish_pipe_dev from file */
static struct goldfish_pipe_dev *to_goldfish_pipe_dev(struct file *file)
{}

/**
 *	goldfish_pipe_open - open a channel to the AVD
 *	@inode: inode of device
 *	@file: file struct of opener
 *
 *	Create a new pipe link between the emulator and the use application.
 *	Each new request produces a new pipe.
 *
 *	Note: we use the pipe ID as a mux. All goldfish emulations are 32bit
 *	right now so this is fine. A move to 64bit will need this addressing
 */
static int goldfish_pipe_open(struct inode *inode, struct file *file)
{}

static int goldfish_pipe_release(struct inode *inode, struct file *filp)
{}

static const struct file_operations goldfish_pipe_fops =;

static void init_miscdevice(struct miscdevice *miscdev)
{}

static void write_pa_addr(void *addr, void __iomem *portl, void __iomem *porth)
{}

static int goldfish_pipe_device_init(struct platform_device *pdev,
				     struct goldfish_pipe_dev *dev)
{}

static void goldfish_pipe_device_deinit(struct platform_device *pdev,
					struct goldfish_pipe_dev *dev)
{}

static int goldfish_pipe_probe(struct platform_device *pdev)
{}

static void goldfish_pipe_remove(struct platform_device *pdev)
{}

static const struct acpi_device_id goldfish_pipe_acpi_match[] =;
MODULE_DEVICE_TABLE(acpi, goldfish_pipe_acpi_match);

static const struct of_device_id goldfish_pipe_of_match[] =;
MODULE_DEVICE_TABLE(of, goldfish_pipe_of_match);

static struct platform_driver goldfish_pipe_driver =;

module_platform_driver();
MODULE_AUTHOR();
MODULE_DESCRIPTION();
MODULE_LICENSE();