1c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner/* 2c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * Copyright (C) 2011 Google, Inc. 3c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * Copyright (C) 2012 Intel, Inc. 4c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * Copyright (C) 2013 Intel, Inc. 5c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * 6c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * This software is licensed under the terms of the GNU General Public 7c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * License version 2, as published by the Free Software Foundation, and 8c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * may be copied, distributed, and modified under those terms. 9c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * 10c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * This program is distributed in the hope that it will be useful, 11c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * but WITHOUT ANY WARRANTY; without even the implied warranty of 12c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * GNU General Public License for more details. 14c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * 15c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner */ 16c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 17c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner/* This source file contains the implementation of a special device driver 18c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * that intends to provide a *very* fast communication channel between the 19c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * guest system and the QEMU emulator. 20c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * 21c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * Usage from the guest is simply the following (error handling simplified): 22c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * 23c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * int fd = open("/dev/qemu_pipe",O_RDWR); 24c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * .... write() or read() through the pipe. 25c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * 26c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * This driver doesn't deal with the exact protocol used during the session. 27c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * It is intended to be as simple as something like: 28c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * 29c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * // do this _just_ after opening the fd to connect to a specific 30c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * // emulator service. 31c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * const char* msg = "<pipename>"; 32c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * if (write(fd, msg, strlen(msg)+1) < 0) { 33c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * ... could not connect to <pipename> service 34c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * close(fd); 35c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * } 36c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * 37c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * // after this, simply read() and write() to communicate with the 38c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * // service. Exact protocol details left as an exercise to the reader. 39c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * 40c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * This driver is very fast because it doesn't copy any data through 41c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * intermediate buffers, since the emulator is capable of translating 42c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * guest user addresses into host ones. 43c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * 44c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * Note that we must however ensure that each user page involved in the 45c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * exchange is properly mapped during a transfer. 46c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner */ 47c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 48c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#include <linux/module.h> 49c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#include <linux/interrupt.h> 50c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#include <linux/kernel.h> 51c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#include <linux/spinlock.h> 52c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#include <linux/miscdevice.h> 53c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#include <linux/platform_device.h> 54c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#include <linux/poll.h> 55c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#include <linux/sched.h> 56c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#include <linux/bitops.h> 57c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#include <linux/slab.h> 58c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#include <linux/io.h> 59a99698facdb92adebf4a4ed7691493b7e08ff5b6Alan#include <linux/goldfish.h> 60c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 61c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner/* 62c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * IMPORTANT: The following constants must match the ones used and defined 63c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * in external/qemu/hw/goldfish_pipe.c in the Android source tree. 64c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner */ 65c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 66c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner/* pipe device registers */ 67c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#define PIPE_REG_COMMAND 0x00 /* write: value = command */ 68c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#define PIPE_REG_STATUS 0x04 /* read */ 69c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#define PIPE_REG_CHANNEL 0x08 /* read/write: channel id */ 7049a75c444fcf07fdde2ec74428b6b1b9ff1c6b15Jun Tian#define PIPE_REG_CHANNEL_HIGH 0x30 /* read/write: channel id */ 71c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#define PIPE_REG_SIZE 0x0c /* read/write: buffer size */ 72c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#define PIPE_REG_ADDRESS 0x10 /* write: physical address */ 7349a75c444fcf07fdde2ec74428b6b1b9ff1c6b15Jun Tian#define PIPE_REG_ADDRESS_HIGH 0x34 /* write: physical address */ 74c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#define PIPE_REG_WAKES 0x14 /* read: wake flags */ 75c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#define PIPE_REG_PARAMS_ADDR_LOW 0x18 /* read/write: batch data address */ 76c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#define PIPE_REG_PARAMS_ADDR_HIGH 0x1c /* read/write: batch data address */ 77c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#define PIPE_REG_ACCESS_PARAMS 0x20 /* write: batch access */ 78c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 79c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner/* list of commands for PIPE_REG_COMMAND */ 80c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#define CMD_OPEN 1 /* open new channel */ 81c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#define CMD_CLOSE 2 /* close channel (from guest) */ 82c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#define CMD_POLL 3 /* poll read/write status */ 83c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 84c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner/* List of bitflags returned in status of CMD_POLL command */ 85c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#define PIPE_POLL_IN (1 << 0) 86c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#define PIPE_POLL_OUT (1 << 1) 87c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#define PIPE_POLL_HUP (1 << 2) 88c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 89c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner/* The following commands are related to write operations */ 90c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#define CMD_WRITE_BUFFER 4 /* send a user buffer to the emulator */ 91c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#define CMD_WAKE_ON_WRITE 5 /* tell the emulator to wake us when writing 92c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner is possible */ 93c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 94c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner/* The following commands are related to read operations, they must be 95c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * listed in the same order than the corresponding write ones, since we 96c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * will use (CMD_READ_BUFFER - CMD_WRITE_BUFFER) as a special offset 97c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * in goldfish_pipe_read_write() below. 98c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner */ 99c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#define CMD_READ_BUFFER 6 /* receive a user buffer from the emulator */ 100c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#define CMD_WAKE_ON_READ 7 /* tell the emulator to wake us when reading 101c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * is possible */ 102c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 103c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner/* Possible status values used to signal errors - see goldfish_pipe_error_convert */ 104c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#define PIPE_ERROR_INVAL -1 105c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#define PIPE_ERROR_AGAIN -2 106c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#define PIPE_ERROR_NOMEM -3 107c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#define PIPE_ERROR_IO -4 108c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 109c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner/* Bit-flags used to signal events from the emulator */ 110c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#define PIPE_WAKE_CLOSED (1 << 0) /* emulator closed pipe */ 111c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#define PIPE_WAKE_READ (1 << 1) /* pipe can now be read from */ 112c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#define PIPE_WAKE_WRITE (1 << 2) /* pipe can now be written to */ 113c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 114c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turnerstruct access_params { 11549a75c444fcf07fdde2ec74428b6b1b9ff1c6b15Jun Tian unsigned long channel; 116c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner u32 size; 11749a75c444fcf07fdde2ec74428b6b1b9ff1c6b15Jun Tian unsigned long address; 118c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner u32 cmd; 119c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner u32 result; 120c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner /* reserved for future extension */ 121c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner u32 flags; 122c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner}; 123c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 124c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner/* The global driver data. Holds a reference to the i/o page used to 125c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * communicate with the emulator, and a wake queue for blocked tasks 126c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * waiting to be awoken. 127c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner */ 128c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turnerstruct goldfish_pipe_dev { 129c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner spinlock_t lock; 130c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner unsigned char __iomem *base; 131c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner struct access_params *aps; 132c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner int irq; 133c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner}; 134c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 135c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turnerstatic struct goldfish_pipe_dev pipe_dev[1]; 136c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 137c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner/* This data type models a given pipe instance */ 138c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turnerstruct goldfish_pipe { 139c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner struct goldfish_pipe_dev *dev; 140c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner struct mutex lock; 141c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner unsigned long flags; 142c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner wait_queue_head_t wake_queue; 143c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner}; 144c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 145c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 146c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner/* Bit flags for the 'flags' field */ 147c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turnerenum { 148c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner BIT_CLOSED_ON_HOST = 0, /* pipe closed by host */ 149c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner BIT_WAKE_ON_WRITE = 1, /* want to be woken on writes */ 150c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner BIT_WAKE_ON_READ = 2, /* want to be woken on reads */ 151c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner}; 152c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 153c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 154c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turnerstatic u32 goldfish_cmd_status(struct goldfish_pipe *pipe, u32 cmd) 155a99698facdb92adebf4a4ed7691493b7e08ff5b6Alan{ 156c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner unsigned long flags; 157c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner u32 status; 158c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner struct goldfish_pipe_dev *dev = pipe->dev; 159c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 160c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner spin_lock_irqsave(&dev->lock, flags); 161f4e131dc38d34469b9fee1840ad237324831bce3Octavian Purdila gf_write64((u64)(unsigned long)pipe, dev->base + PIPE_REG_CHANNEL, 162a99698facdb92adebf4a4ed7691493b7e08ff5b6Alan dev->base + PIPE_REG_CHANNEL_HIGH); 163c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner writel(cmd, dev->base + PIPE_REG_COMMAND); 164c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner status = readl(dev->base + PIPE_REG_STATUS); 165c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner spin_unlock_irqrestore(&dev->lock, flags); 166c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return status; 167c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner} 168c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 169c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turnerstatic void goldfish_cmd(struct goldfish_pipe *pipe, u32 cmd) 170a99698facdb92adebf4a4ed7691493b7e08ff5b6Alan{ 171c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner unsigned long flags; 172c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner struct goldfish_pipe_dev *dev = pipe->dev; 173c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 174c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner spin_lock_irqsave(&dev->lock, flags); 175f4e131dc38d34469b9fee1840ad237324831bce3Octavian Purdila gf_write64((u64)(unsigned long)pipe, dev->base + PIPE_REG_CHANNEL, 176a99698facdb92adebf4a4ed7691493b7e08ff5b6Alan dev->base + PIPE_REG_CHANNEL_HIGH); 177c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner writel(cmd, dev->base + PIPE_REG_COMMAND); 178c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner spin_unlock_irqrestore(&dev->lock, flags); 179c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner} 180c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 181c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner/* This function converts an error code returned by the emulator through 182c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * the PIPE_REG_STATUS i/o register into a valid negative errno value. 183c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner */ 184c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turnerstatic int goldfish_pipe_error_convert(int status) 185c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner{ 186c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner switch (status) { 187c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner case PIPE_ERROR_AGAIN: 188c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return -EAGAIN; 189c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner case PIPE_ERROR_NOMEM: 190c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return -ENOMEM; 191c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner case PIPE_ERROR_IO: 192c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return -EIO; 193c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner default: 194c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return -EINVAL; 195c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner } 196c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner} 197c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 198c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner/* 199c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * Notice: QEMU will return 0 for un-known register access, indicating 200c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * param_acess is supported or not 201c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner */ 202c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turnerstatic int valid_batchbuffer_addr(struct goldfish_pipe_dev *dev, 203c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner struct access_params *aps) 204c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner{ 205c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner u32 aph, apl; 206c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner u64 paddr; 207c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner aph = readl(dev->base + PIPE_REG_PARAMS_ADDR_HIGH); 208c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner apl = readl(dev->base + PIPE_REG_PARAMS_ADDR_LOW); 209c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 210c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner paddr = ((u64)aph << 32) | apl; 211c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (paddr != (__pa(aps))) 212c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return 0; 213c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return 1; 214c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner} 215c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 216c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner/* 0 on success */ 217c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turnerstatic int setup_access_params_addr(struct platform_device *pdev, 218c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner struct goldfish_pipe_dev *dev) 219c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner{ 220c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner u64 paddr; 221c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner struct access_params *aps; 222c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 223c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner aps = devm_kzalloc(&pdev->dev, sizeof(struct access_params), GFP_KERNEL); 224c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (!aps) 225c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return -1; 226c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 227c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner /* FIXME */ 228c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner paddr = __pa(aps); 229c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner writel((u32)(paddr >> 32), dev->base + PIPE_REG_PARAMS_ADDR_HIGH); 230c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner writel((u32)paddr, dev->base + PIPE_REG_PARAMS_ADDR_LOW); 231c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 232c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (valid_batchbuffer_addr(dev, aps)) { 233c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner dev->aps = aps; 234c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return 0; 235c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner } else 236c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return -1; 237c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner} 238c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 239c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner/* A value that will not be set by qemu emulator */ 240c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner#define INITIAL_BATCH_RESULT (0xdeadbeaf) 241c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turnerstatic int access_with_param(struct goldfish_pipe_dev *dev, const int cmd, 242c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner unsigned long address, unsigned long avail, 243c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner struct goldfish_pipe *pipe, int *status) 244c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner{ 245c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner struct access_params *aps = dev->aps; 246c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 247c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (aps == NULL) 248c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return -1; 249c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 250c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner aps->result = INITIAL_BATCH_RESULT; 251c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner aps->channel = (unsigned long)pipe; 252c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner aps->size = avail; 253c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner aps->address = address; 254c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner aps->cmd = cmd; 255c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner writel(cmd, dev->base + PIPE_REG_ACCESS_PARAMS); 256c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner /* 257c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * If the aps->result has not changed, that means 258c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * that the batch command failed 259c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner */ 260c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (aps->result == INITIAL_BATCH_RESULT) 261c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return -1; 262c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner *status = aps->result; 263c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return 0; 264c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner} 265c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 266c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner/* This function is used for both reading from and writing to a given 267c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * pipe. 268c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner */ 269c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turnerstatic ssize_t goldfish_pipe_read_write(struct file *filp, char __user *buffer, 270c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner size_t bufflen, int is_write) 271c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner{ 272c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner unsigned long irq_flags; 273c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner struct goldfish_pipe *pipe = filp->private_data; 274c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner struct goldfish_pipe_dev *dev = pipe->dev; 275c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner const int cmd_offset = is_write ? 0 276c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner : (CMD_READ_BUFFER - CMD_WRITE_BUFFER); 277c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner unsigned long address, address_end; 278c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner int ret = 0; 279c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 280c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner /* If the emulator already closed the pipe, no need to go further */ 281c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (test_bit(BIT_CLOSED_ON_HOST, &pipe->flags)) 282c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return -EIO; 283c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 284c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner /* Null reads or writes succeeds */ 285c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (unlikely(bufflen) == 0) 286c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return 0; 287c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 288c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner /* Check the buffer range for access */ 289c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (!access_ok(is_write ? VERIFY_WRITE : VERIFY_READ, 290c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner buffer, bufflen)) 291c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return -EFAULT; 292c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 293c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner /* Serialize access to the pipe */ 294c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (mutex_lock_interruptible(&pipe->lock)) 295c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return -ERESTARTSYS; 296c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 297c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner address = (unsigned long)(void *)buffer; 298c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner address_end = address + bufflen; 299c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 300c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner while (address < address_end) { 301c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner unsigned long page_end = (address & PAGE_MASK) + PAGE_SIZE; 302c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner unsigned long next = page_end < address_end ? page_end 303c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner : address_end; 304c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner unsigned long avail = next - address; 305c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner int status, wakeBit; 306c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 307c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner /* Ensure that the corresponding page is properly mapped */ 30817c4c9db4a33ae0a8dcfafab3dc59a83ccaf6076Alan Cox /* FIXME: this isn't safe or sufficient - use get_user_pages */ 309c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (is_write) { 310c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner char c; 311c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner /* Ensure that the page is mapped and readable */ 312c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (__get_user(c, (char __user *)address)) { 313c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (!ret) 314c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner ret = -EFAULT; 315c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner break; 316c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner } 317c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner } else { 318c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner /* Ensure that the page is mapped and writable */ 319c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (__put_user(0, (char __user *)address)) { 320c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (!ret) 321c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner ret = -EFAULT; 322c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner break; 323c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner } 324c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner } 325c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 326c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner /* Now, try to transfer the bytes in the current page */ 327c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner spin_lock_irqsave(&dev->lock, irq_flags); 328c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (access_with_param(dev, CMD_WRITE_BUFFER + cmd_offset, 329c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner address, avail, pipe, &status)) { 330f4e131dc38d34469b9fee1840ad237324831bce3Octavian Purdila gf_write64((u64)(unsigned long)pipe, 331f4e131dc38d34469b9fee1840ad237324831bce3Octavian Purdila dev->base + PIPE_REG_CHANNEL, 332f4e131dc38d34469b9fee1840ad237324831bce3Octavian Purdila dev->base + PIPE_REG_CHANNEL_HIGH); 333c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner writel(avail, dev->base + PIPE_REG_SIZE); 334a99698facdb92adebf4a4ed7691493b7e08ff5b6Alan gf_write64(address, dev->base + PIPE_REG_ADDRESS, 335a99698facdb92adebf4a4ed7691493b7e08ff5b6Alan dev->base + PIPE_REG_ADDRESS_HIGH); 336c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner writel(CMD_WRITE_BUFFER + cmd_offset, 337c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner dev->base + PIPE_REG_COMMAND); 338c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner status = readl(dev->base + PIPE_REG_STATUS); 339c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner } 340c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner spin_unlock_irqrestore(&dev->lock, irq_flags); 341c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 342c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (status > 0) { /* Correct transfer */ 343c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner ret += status; 344c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner address += status; 345c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner continue; 346c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner } 347c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 348c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (status == 0) /* EOF */ 349c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner break; 350c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 351c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner /* An error occured. If we already transfered stuff, just 352c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * return with its count. We expect the next call to return 353c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * an error code */ 354c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (ret > 0) 355c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner break; 356c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 357c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner /* If the error is not PIPE_ERROR_AGAIN, or if we are not in 358c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * non-blocking mode, just return the error code. 359c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner */ 360c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (status != PIPE_ERROR_AGAIN || 361c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner (filp->f_flags & O_NONBLOCK) != 0) { 362c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner ret = goldfish_pipe_error_convert(status); 363c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner break; 364c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner } 365c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 366c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner /* We will have to wait until more data/space is available. 367c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * First, mark the pipe as waiting for a specific wake signal. 368c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner */ 369c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner wakeBit = is_write ? BIT_WAKE_ON_WRITE : BIT_WAKE_ON_READ; 370c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner set_bit(wakeBit, &pipe->flags); 371c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 372c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner /* Tell the emulator we're going to wait for a wake event */ 373c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner goldfish_cmd(pipe, CMD_WAKE_ON_WRITE + cmd_offset); 374c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 375c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner /* Unlock the pipe, then wait for the wake signal */ 376c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner mutex_unlock(&pipe->lock); 377c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 378c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner while (test_bit(wakeBit, &pipe->flags)) { 379c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (wait_event_interruptible( 380c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner pipe->wake_queue, 381c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner !test_bit(wakeBit, &pipe->flags))) 382c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return -ERESTARTSYS; 383c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 384c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (test_bit(BIT_CLOSED_ON_HOST, &pipe->flags)) 385c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return -EIO; 386c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner } 387c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 388c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner /* Try to re-acquire the lock */ 389c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (mutex_lock_interruptible(&pipe->lock)) 390c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return -ERESTARTSYS; 391c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 392c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner /* Try the transfer again */ 393c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner continue; 394c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner } 395c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner mutex_unlock(&pipe->lock); 396c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return ret; 397c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner} 398c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 399c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turnerstatic ssize_t goldfish_pipe_read(struct file *filp, char __user *buffer, 400c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner size_t bufflen, loff_t *ppos) 401c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner{ 402c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return goldfish_pipe_read_write(filp, buffer, bufflen, 0); 403c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner} 404c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 405c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turnerstatic ssize_t goldfish_pipe_write(struct file *filp, 406c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner const char __user *buffer, size_t bufflen, 407c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner loff_t *ppos) 408c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner{ 409c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return goldfish_pipe_read_write(filp, (char __user *)buffer, 410c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner bufflen, 1); 411c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner} 412c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 413c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 414c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turnerstatic unsigned int goldfish_pipe_poll(struct file *filp, poll_table *wait) 415c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner{ 416c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner struct goldfish_pipe *pipe = filp->private_data; 417c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner unsigned int mask = 0; 418c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner int status; 419c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 420c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner mutex_lock(&pipe->lock); 421c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 422c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner poll_wait(filp, &pipe->wake_queue, wait); 423c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 424c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner status = goldfish_cmd_status(pipe, CMD_POLL); 425c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 426c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner mutex_unlock(&pipe->lock); 427c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 428c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (status & PIPE_POLL_IN) 429c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner mask |= POLLIN | POLLRDNORM; 430c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 431c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (status & PIPE_POLL_OUT) 432c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner mask |= POLLOUT | POLLWRNORM; 433c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 434c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (status & PIPE_POLL_HUP) 435c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner mask |= POLLHUP; 436c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 437c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (test_bit(BIT_CLOSED_ON_HOST, &pipe->flags)) 438c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner mask |= POLLERR; 439c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 440c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return mask; 441c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner} 442c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 443c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turnerstatic irqreturn_t goldfish_pipe_interrupt(int irq, void *dev_id) 444c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner{ 445c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner struct goldfish_pipe_dev *dev = dev_id; 446c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner unsigned long irq_flags; 447c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner int count = 0; 448c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 449c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner /* We're going to read from the emulator a list of (channel,flags) 450c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * pairs corresponding to the wake events that occured on each 451c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * blocked pipe (i.e. channel). 452c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner */ 453c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner spin_lock_irqsave(&dev->lock, irq_flags); 454c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner for (;;) { 455c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner /* First read the channel, 0 means the end of the list */ 456c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner struct goldfish_pipe *pipe; 457c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner unsigned long wakes; 45849a75c444fcf07fdde2ec74428b6b1b9ff1c6b15Jun Tian unsigned long channel = 0; 45949a75c444fcf07fdde2ec74428b6b1b9ff1c6b15Jun Tian 46049a75c444fcf07fdde2ec74428b6b1b9ff1c6b15Jun Tian#ifdef CONFIG_64BIT 46149a75c444fcf07fdde2ec74428b6b1b9ff1c6b15Jun Tian channel = (u64)readl(dev->base + PIPE_REG_CHANNEL_HIGH) << 32; 46225c72c786cb571cfdf39a31f9f64d143d8623a7aJun Tian 46325c72c786cb571cfdf39a31f9f64d143d8623a7aJun Tian if (channel == 0) 46425c72c786cb571cfdf39a31f9f64d143d8623a7aJun Tian break; 46549a75c444fcf07fdde2ec74428b6b1b9ff1c6b15Jun Tian#endif 46649a75c444fcf07fdde2ec74428b6b1b9ff1c6b15Jun Tian channel |= readl(dev->base + PIPE_REG_CHANNEL); 467c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 468c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (channel == 0) 469c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner break; 470c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 471c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner /* Convert channel to struct pipe pointer + read wake flags */ 472c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner wakes = readl(dev->base + PIPE_REG_WAKES); 473c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner pipe = (struct goldfish_pipe *)(ptrdiff_t)channel; 474c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 475c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner /* Did the emulator just closed a pipe? */ 476c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (wakes & PIPE_WAKE_CLOSED) { 477c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner set_bit(BIT_CLOSED_ON_HOST, &pipe->flags); 478c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner wakes |= PIPE_WAKE_READ | PIPE_WAKE_WRITE; 479c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner } 480c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (wakes & PIPE_WAKE_READ) 481c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner clear_bit(BIT_WAKE_ON_READ, &pipe->flags); 482c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (wakes & PIPE_WAKE_WRITE) 483c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner clear_bit(BIT_WAKE_ON_WRITE, &pipe->flags); 484c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 485c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner wake_up_interruptible(&pipe->wake_queue); 486c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner count++; 487c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner } 488c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner spin_unlock_irqrestore(&dev->lock, irq_flags); 489c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 490c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return (count == 0) ? IRQ_NONE : IRQ_HANDLED; 491c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner} 492c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 493c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner/** 494c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * goldfish_pipe_open - open a channel to the AVD 495c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * @inode: inode of device 496c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * @file: file struct of opener 497c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * 498c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * Create a new pipe link between the emulator and the use application. 499c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * Each new request produces a new pipe. 500c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * 501c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * Note: we use the pipe ID as a mux. All goldfish emulations are 32bit 502c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * right now so this is fine. A move to 64bit will need this addressing 503c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner */ 504c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turnerstatic int goldfish_pipe_open(struct inode *inode, struct file *file) 505c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner{ 506c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner struct goldfish_pipe *pipe; 507c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner struct goldfish_pipe_dev *dev = pipe_dev; 508c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner int32_t status; 509c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 510c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner /* Allocate new pipe kernel object */ 511c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner pipe = kzalloc(sizeof(*pipe), GFP_KERNEL); 512c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (pipe == NULL) 513c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return -ENOMEM; 514c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 515c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner pipe->dev = dev; 516c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner mutex_init(&pipe->lock); 517c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner init_waitqueue_head(&pipe->wake_queue); 518c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 519c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner /* 520c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * Now, tell the emulator we're opening a new pipe. We use the 521c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner * pipe object's address as the channel identifier for simplicity. 522c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner */ 523c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 524c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner status = goldfish_cmd_status(pipe, CMD_OPEN); 525c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (status < 0) { 526c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner kfree(pipe); 527c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return status; 528c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner } 529c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 530c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner /* All is done, save the pipe into the file's private data field */ 531c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner file->private_data = pipe; 532c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return 0; 533c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner} 534c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 535c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turnerstatic int goldfish_pipe_release(struct inode *inode, struct file *filp) 536c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner{ 537c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner struct goldfish_pipe *pipe = filp->private_data; 538c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 539c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner /* The guest is closing the channel, so tell the emulator right now */ 540c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner goldfish_cmd(pipe, CMD_CLOSE); 541c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner kfree(pipe); 542c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner filp->private_data = NULL; 543c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return 0; 544c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner} 545c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 546c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turnerstatic const struct file_operations goldfish_pipe_fops = { 547c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner .owner = THIS_MODULE, 548c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner .read = goldfish_pipe_read, 549c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner .write = goldfish_pipe_write, 550c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner .poll = goldfish_pipe_poll, 551c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner .open = goldfish_pipe_open, 552c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner .release = goldfish_pipe_release, 553c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner}; 554c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 555c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turnerstatic struct miscdevice goldfish_pipe_device = { 556c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner .minor = MISC_DYNAMIC_MINOR, 557c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner .name = "goldfish_pipe", 558c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner .fops = &goldfish_pipe_fops, 559c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner}; 560c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 561c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turnerstatic int goldfish_pipe_probe(struct platform_device *pdev) 562c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner{ 563c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner int err; 564c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner struct resource *r; 565c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner struct goldfish_pipe_dev *dev = pipe_dev; 566c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 567c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner /* not thread safe, but this should not happen */ 568c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner WARN_ON(dev->base != NULL); 569c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 570c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner spin_lock_init(&dev->lock); 571c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 572c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 573c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (r == NULL || resource_size(r) < PAGE_SIZE) { 574c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner dev_err(&pdev->dev, "can't allocate i/o page\n"); 575c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return -EINVAL; 576c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner } 577c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner dev->base = devm_ioremap(&pdev->dev, r->start, PAGE_SIZE); 578c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (dev->base == NULL) { 579c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner dev_err(&pdev->dev, "ioremap failed\n"); 580c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return -EINVAL; 581c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner } 582c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 583c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner r = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 584c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (r == NULL) { 585c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner err = -EINVAL; 586c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner goto error; 587c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner } 588c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner dev->irq = r->start; 589c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 590c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner err = devm_request_irq(&pdev->dev, dev->irq, goldfish_pipe_interrupt, 591c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner IRQF_SHARED, "goldfish_pipe", dev); 592c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (err) { 593c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner dev_err(&pdev->dev, "unable to allocate IRQ\n"); 594c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner goto error; 595c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner } 596c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 597c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner err = misc_register(&goldfish_pipe_device); 598c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner if (err) { 599c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner dev_err(&pdev->dev, "unable to register device\n"); 600c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner goto error; 601c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner } 602c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner setup_access_params_addr(pdev, dev); 603c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return 0; 604c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 605c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turnererror: 606c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner dev->base = NULL; 607c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return err; 608c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner} 609c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 610c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turnerstatic int goldfish_pipe_remove(struct platform_device *pdev) 611c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner{ 612c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner struct goldfish_pipe_dev *dev = pipe_dev; 613c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner misc_deregister(&goldfish_pipe_device); 614c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner dev->base = NULL; 615c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner return 0; 616c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner} 617c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 618c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turnerstatic struct platform_driver goldfish_pipe = { 619c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner .probe = goldfish_pipe_probe, 620c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner .remove = goldfish_pipe_remove, 621c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner .driver = { 622c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner .name = "goldfish_pipe" 623c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner } 624c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner}; 625c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turner 626c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' Turnermodule_platform_driver(goldfish_pipe); 627c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' TurnerMODULE_AUTHOR("David Turner <digit@google.com>"); 628c89f2750e9845aa115ca30c062edd569da619cadDavid 'Digit' TurnerMODULE_LICENSE("GPL"); 629