• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2012 Intel, Inc.
4  * Copyright (C) 2013 Intel, Inc.
5  * Copyright (C) 2014 Linaro Limited
6  * Copyright (C) 2011-2016 Google, Inc.
7  *
8  * This software is licensed under the terms of the GNU General Public
9  * License version 2, as published by the Free Software Foundation, and
10  * may be copied, distributed, and modified under those terms.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  */
18 
19 /* This source file contains the implementation of a special device driver
20  * that intends to provide a *very* fast communication channel between the
21  * guest system and the QEMU emulator.
22  *
23  * Usage from the guest is simply the following (error handling simplified):
24  *
25  *    int  fd = open("/dev/qemu_pipe",O_RDWR);
26  *    .... write() or read() through the pipe.
27  *
28  * This driver doesn't deal with the exact protocol used during the session.
29  * It is intended to be as simple as something like:
30  *
31  *    // do this _just_ after opening the fd to connect to a specific
32  *    // emulator service.
33  *    const char*  msg = "<pipename>";
34  *    if (write(fd, msg, strlen(msg)+1) < 0) {
35  *       ... could not connect to <pipename> service
36  *       close(fd);
37  *    }
38  *
39  *    // after this, simply read() and write() to communicate with the
40  *    // service. Exact protocol details left as an exercise to the reader.
41  *
42  * This driver is very fast because it doesn't copy any data through
43  * intermediate buffers, since the emulator is capable of translating
44  * guest user addresses into host ones.
45  *
46  * Note that we must however ensure that each user page involved in the
47  * exchange is properly mapped during a transfer.
48  */
49 
50 #include <linux/module.h>
51 #include <linux/mod_devicetable.h>
52 #include <linux/interrupt.h>
53 #include <linux/kernel.h>
54 #include <linux/platform_device.h>
55 #include <linux/io.h>
56 #include <linux/acpi.h>
57 #include "goldfish_pipe_qemu.h"
58 #include "goldfish_pipe.h"
59 #include "goldfish_pipe_v1.h"
60 #include "goldfish_pipe_v2.h"
61 
62 /*
63  * Update this when something changes in the driver's behavior so the host
64  * can benefit from knowing it
65  * Notes:
66  *	version 2 was an intermediate release and isn't supported anymore.
67  *	version 3 is goldfish_pipe_v2 without DMA support.
68  *	version 4 (current) is goldfish_pipe_v2 with DMA support.
69  */
70 enum {
71 	PIPE_DRIVER_VERSION = 4,
72 	PIPE_CURRENT_DEVICE_VERSION = 2
73 };
74 
goldfish_pipe_probe(struct platform_device * pdev)75 static int goldfish_pipe_probe(struct platform_device *pdev)
76 {
77 	struct resource *r;
78 	char __iomem *base;
79 	int irq;
80 	int version;
81 
82 	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
83 	if (!r || resource_size(r) < PAGE_SIZE) {
84 		dev_err(&pdev->dev, "can't allocate i/o page\n");
85 		return -EINVAL;
86 	}
87 	base = devm_ioremap(&pdev->dev, r->start, PAGE_SIZE);
88 	if (!base) {
89 		dev_err(&pdev->dev, "ioremap failed\n");
90 		return -EINVAL;
91 	}
92 
93 	r = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
94 	if (!r)
95 		return -EINVAL;
96 
97 	irq = r->start;
98 
99 	/*
100 	 * Exchange the versions with the host device
101 	 *
102 	 * Note: v1 driver used to not report its version, so we write it before
103 	 *  reading device version back: this allows the host implementation to
104 	 *  detect the old driver (if there was no version write before read).
105 	 */
106 	writel(PIPE_DRIVER_VERSION, base + PIPE_V2_REG_VERSION);
107 	version = readl(base + PIPE_V2_REG_VERSION);
108 
109 	if (version < PIPE_CURRENT_DEVICE_VERSION)
110 		return goldfish_pipe_device_v1_init(pdev, base, irq);
111 	else
112 		return goldfish_pipe_device_v2_init(pdev, base, irq);
113 }
114 
goldfish_pipe_remove(struct platform_device * pdev)115 static int goldfish_pipe_remove(struct platform_device *pdev)
116 {
117 	struct goldfish_pipe_dev_base *dev = platform_get_drvdata(pdev);
118 
119 	return dev->deinit(dev, pdev);
120 }
121 
122 static const struct acpi_device_id goldfish_pipe_acpi_match[] = {
123 	{ "GFSH0003", 0 },
124 	{ },
125 };
126 MODULE_DEVICE_TABLE(acpi, goldfish_pipe_acpi_match);
127 
128 static const struct of_device_id goldfish_pipe_of_match[] = {
129 	{ .compatible = "google,android-pipe", },
130 	{},
131 };
132 MODULE_DEVICE_TABLE(of, goldfish_pipe_of_match);
133 
134 static struct platform_driver goldfish_pipe_driver = {
135 	.probe = goldfish_pipe_probe,
136 	.remove = goldfish_pipe_remove,
137 	.driver = {
138 		.name = "goldfish_pipe",
139 		.of_match_table = goldfish_pipe_of_match,
140 		.acpi_match_table = ACPI_PTR(goldfish_pipe_acpi_match),
141 	}
142 };
143 
144 module_platform_driver(goldfish_pipe_driver);
145 MODULE_AUTHOR("David Turner <digit@google.com>");
146 MODULE_LICENSE("GPL v2");
147