Root/target/linux/goldfish/patches-2.6.30/0122--ARM-goldfish-tty-Adding-tty-driver-for-goldfish.patch

1From 4ff5a10b94c0c41088c8bbfa5be1ebab3822371b Mon Sep 17 00:00:00 2001
2From: =?utf-8?q?Arve=20Hj=C3=B8nnev=C3=A5g?= <arve@google.com>
3Date: Fri, 29 Jun 2007 21:41:20 -0700
4Subject: [PATCH 122/134] [ARM] goldfish: tty: Adding tty driver for goldfish.
5MIME-Version: 1.0
6Content-Type: text/plain; charset=utf-8
7Content-Transfer-Encoding: 8bit
8
9Signed-off-by: Mike A. Chan <mikechan@google.com>
10Signed-off-by: Arve Hjønnevåg <arve@android.com>
11---
12 drivers/char/Kconfig | 6 +
13 drivers/char/Makefile | 1 +
14 drivers/char/goldfish_tty.c | 323 +++++++++++++++++++++++++++++++++++++++++++
15 3 files changed, 330 insertions(+), 0 deletions(-)
16 create mode 100644 drivers/char/goldfish_tty.c
17
18--- a/drivers/char/Kconfig
19+++ b/drivers/char/Kconfig
20@@ -1106,6 +1106,12 @@ config DEVPORT
21     depends on ISA || PCI
22     default y
23 
24+config GOLDFISH_TTY
25+ tristate "Goldfish TTY Driver"
26+ default n
27+ help
28+ TTY driver for Goldfish Virtual Platform.
29+
30 source "drivers/s390/char/Kconfig"
31 
32 endmenu
33--- a/drivers/char/Makefile
34+++ b/drivers/char/Makefile
35@@ -98,6 +98,7 @@ obj-$(CONFIG_GPIO_DEVICE) += gpio_dev.o
36 obj-$(CONFIG_GPIO_VR41XX) += vr41xx_giu.o
37 obj-$(CONFIG_GPIO_TB0219) += tb0219.o
38 obj-$(CONFIG_TELCLOCK) += tlclk.o
39+obj-$(CONFIG_GOLDFISH_TTY) += goldfish_tty.o
40 
41 obj-$(CONFIG_MWAVE) += mwave/
42 obj-$(CONFIG_AGP) += agp/
43--- /dev/null
44+++ b/drivers/char/goldfish_tty.c
45@@ -0,0 +1,323 @@
46+/* drivers/char/goldfish_tty.c
47+**
48+** Copyright (C) 2007 Google, Inc.
49+**
50+** This software is licensed under the terms of the GNU General Public
51+** License version 2, as published by the Free Software Foundation, and
52+** may be copied, distributed, and modified under those terms.
53+**
54+** This program is distributed in the hope that it will be useful,
55+** but WITHOUT ANY WARRANTY; without even the implied warranty of
56+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
57+** GNU General Public License for more details.
58+**
59+*/
60+
61+#include <linux/console.h>
62+#include <linux/init.h>
63+#include <linux/interrupt.h>
64+#include <linux/platform_device.h>
65+#include <linux/tty.h>
66+#include <linux/tty_flip.h>
67+
68+#include <mach/hardware.h>
69+#include <asm/io.h>
70+
71+enum {
72+ GOLDFISH_TTY_PUT_CHAR = 0x00,
73+ GOLDFISH_TTY_BYTES_READY = 0x04,
74+ GOLDFISH_TTY_CMD = 0x08,
75+
76+ GOLDFISH_TTY_DATA_PTR = 0x10,
77+ GOLDFISH_TTY_DATA_LEN = 0x14,
78+
79+ GOLDFISH_TTY_CMD_INT_DISABLE = 0,
80+ GOLDFISH_TTY_CMD_INT_ENABLE = 1,
81+ GOLDFISH_TTY_CMD_WRITE_BUFFER = 2,
82+ GOLDFISH_TTY_CMD_READ_BUFFER = 3,
83+};
84+
85+struct goldfish_tty {
86+ spinlock_t lock;
87+ uint32_t base;
88+ uint32_t irq;
89+ int opencount;
90+ struct tty_struct *tty;
91+ struct console console;
92+};
93+
94+static DEFINE_MUTEX(goldfish_tty_lock);
95+static struct tty_driver *goldfish_tty_driver;
96+static uint32_t goldfish_tty_line_count = 8;
97+static uint32_t goldfish_tty_current_line_count;
98+static struct goldfish_tty *goldfish_ttys;
99+
100+static void goldfish_tty_do_write(int line, const char *buf, unsigned count)
101+{
102+ unsigned long irq_flags;
103+ struct goldfish_tty *qtty = &goldfish_ttys[line];
104+ uint32_t base = qtty->base;
105+ spin_lock_irqsave(&qtty->lock, irq_flags);
106+ writel(buf, base + GOLDFISH_TTY_DATA_PTR);
107+ writel(count, base + GOLDFISH_TTY_DATA_LEN);
108+ writel(GOLDFISH_TTY_CMD_WRITE_BUFFER, base + GOLDFISH_TTY_CMD);
109+ spin_unlock_irqrestore(&qtty->lock, irq_flags);
110+}
111+
112+static irqreturn_t goldfish_tty_interrupt(int irq, void *dev_id)
113+{
114+ struct platform_device *pdev = dev_id;
115+ struct goldfish_tty *qtty = &goldfish_ttys[pdev->id];
116+ uint32_t base = qtty->base;
117+ unsigned long irq_flags;
118+ unsigned char *buf;
119+ uint32_t count;
120+
121+ count = readl(base + GOLDFISH_TTY_BYTES_READY);
122+ if(count == 0) {
123+ return IRQ_NONE;
124+ }
125+ count = tty_prepare_flip_string(qtty->tty, &buf, count);
126+ spin_lock_irqsave(&qtty->lock, irq_flags);
127+ writel(buf, base + GOLDFISH_TTY_DATA_PTR);
128+ writel(count, base + GOLDFISH_TTY_DATA_LEN);
129+ writel(GOLDFISH_TTY_CMD_READ_BUFFER, base + GOLDFISH_TTY_CMD);
130+ spin_unlock_irqrestore(&qtty->lock, irq_flags);
131+ tty_schedule_flip(qtty->tty);
132+ return IRQ_HANDLED;
133+}
134+
135+static int goldfish_tty_open(struct tty_struct * tty, struct file * filp)
136+{
137+ int ret;
138+ struct goldfish_tty *qtty = &goldfish_ttys[tty->index];
139+
140+ mutex_lock(&goldfish_tty_lock);
141+ if(qtty->tty == NULL || qtty->tty == tty) {
142+ if(qtty->opencount++ == 0) {
143+ qtty->tty = tty;
144+ writel(GOLDFISH_TTY_CMD_INT_ENABLE, qtty->base + GOLDFISH_TTY_CMD);
145+ }
146+ ret = 0;
147+ }
148+ else
149+ ret = -EBUSY;
150+ mutex_unlock(&goldfish_tty_lock);
151+ return ret;
152+}
153+
154+static void goldfish_tty_close(struct tty_struct * tty, struct file * filp)
155+{
156+ struct goldfish_tty *qtty = &goldfish_ttys[tty->index];
157+
158+ mutex_lock(&goldfish_tty_lock);
159+ if(qtty->tty == tty) {
160+ if(--qtty->opencount == 0) {
161+ writel(GOLDFISH_TTY_CMD_INT_DISABLE, qtty->base + GOLDFISH_TTY_CMD);
162+ qtty->tty = NULL;
163+ }
164+ }
165+ mutex_unlock(&goldfish_tty_lock);
166+}
167+
168+static int goldfish_tty_write(struct tty_struct * tty, const unsigned char *buf, int count)
169+{
170+ goldfish_tty_do_write(tty->index, buf, count);
171+ return count;
172+}
173+
174+static int goldfish_tty_write_room(struct tty_struct *tty)
175+{
176+ return 0x10000;
177+}
178+
179+static int goldfish_tty_chars_in_buffer(struct tty_struct *tty)
180+{
181+ struct goldfish_tty *qtty = &goldfish_ttys[tty->index];
182+ uint32_t base = qtty->base;
183+ return readl(base + GOLDFISH_TTY_BYTES_READY);
184+}
185+
186+static void goldfish_tty_console_write(struct console *co, const char *b, unsigned count)
187+{
188+ goldfish_tty_do_write(co->index, b, count);
189+}
190+
191+static struct tty_driver *goldfish_tty_console_device(struct console *c, int *index)
192+{
193+ *index = c->index;
194+ return goldfish_tty_driver;
195+}
196+
197+static int goldfish_tty_console_setup(struct console *co, char *options)
198+{
199+ if((unsigned)co->index > goldfish_tty_line_count)
200+ return -ENODEV;
201+ if(goldfish_ttys[co->index].base == 0)
202+ return -ENODEV;
203+ return 0;
204+}
205+
206+static struct tty_operations goldfish_tty_ops = {
207+ .open = goldfish_tty_open,
208+ .close = goldfish_tty_close,
209+ .write = goldfish_tty_write,
210+ .write_room = goldfish_tty_write_room,
211+ .chars_in_buffer = goldfish_tty_chars_in_buffer,
212+};
213+
214+static int __devinit goldfish_tty_create_driver(void)
215+{
216+ int ret;
217+ struct tty_driver *tty;
218+
219+ goldfish_ttys = kzalloc(sizeof(*goldfish_ttys) * goldfish_tty_line_count, GFP_KERNEL);
220+ if(goldfish_ttys == NULL) {
221+ ret = -ENOMEM;
222+ goto err_alloc_goldfish_ttys_failed;
223+ }
224+
225+ tty = alloc_tty_driver(goldfish_tty_line_count);
226+ if(tty == NULL) {
227+ ret = -ENOMEM;
228+ goto err_alloc_tty_driver_failed;
229+ }
230+ tty->driver_name = "goldfish";
231+ tty->name = "ttyS";
232+ tty->type = TTY_DRIVER_TYPE_SERIAL;
233+ tty->subtype = SERIAL_TYPE_NORMAL;
234+ tty->init_termios = tty_std_termios;
235+ tty->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
236+ tty_set_operations(tty, &goldfish_tty_ops);
237+ ret = tty_register_driver(tty);
238+ if(ret)
239+ goto err_tty_register_driver_failed;
240+
241+ goldfish_tty_driver = tty;
242+ return 0;
243+
244+err_tty_register_driver_failed:
245+ put_tty_driver(tty);
246+err_alloc_tty_driver_failed:
247+ kfree(goldfish_ttys);
248+ goldfish_ttys = NULL;
249+err_alloc_goldfish_ttys_failed:
250+ return ret;
251+}
252+
253+static void goldfish_tty_delete_driver(void)
254+{
255+ tty_unregister_driver(goldfish_tty_driver);
256+ put_tty_driver(goldfish_tty_driver);
257+ goldfish_tty_driver = NULL;
258+ kfree(goldfish_ttys);
259+ goldfish_ttys = NULL;
260+}
261+
262+static int __devinit goldfish_tty_probe(struct platform_device *pdev)
263+{
264+ int ret;
265+ int i;
266+ struct resource *r;
267+ struct device *ttydev;
268+ uint32_t base;
269+ uint32_t irq;
270+
271+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
272+ if(r == NULL)
273+ return -EINVAL;
274+ base = IO_ADDRESS(r->start - IO_START);
275+ r = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
276+ if(r == NULL)
277+ return -EINVAL;
278+ irq = r->start;
279+
280+ if(pdev->id >= goldfish_tty_line_count)
281+ return -EINVAL;
282+
283+ mutex_lock(&goldfish_tty_lock);
284+ if(goldfish_tty_current_line_count == 0) {
285+ ret = goldfish_tty_create_driver();
286+ if(ret)
287+ goto err_create_driver_failed;
288+ }
289+ goldfish_tty_current_line_count++;
290+
291+ spin_lock_init(&goldfish_ttys[pdev->id].lock);
292+ goldfish_ttys[pdev->id].base = base;
293+ goldfish_ttys[pdev->id].irq = irq;
294+
295+ writel(GOLDFISH_TTY_CMD_INT_DISABLE, base + GOLDFISH_TTY_CMD);
296+
297+ ret = request_irq(irq, goldfish_tty_interrupt, IRQF_SHARED, "goldfish_tty", pdev);
298+ if(ret)
299+ goto err_request_irq_failed;
300+
301+
302+ ttydev = tty_register_device(goldfish_tty_driver, pdev->id, NULL);
303+ if(IS_ERR(ttydev)) {
304+ ret = PTR_ERR(ttydev);
305+ goto err_tty_register_device_failed;
306+ }
307+
308+ strcpy(goldfish_ttys[pdev->id].console.name, "ttyS");
309+ goldfish_ttys[pdev->id].console.write = goldfish_tty_console_write;
310+ goldfish_ttys[pdev->id].console.device = goldfish_tty_console_device;
311+ goldfish_ttys[pdev->id].console.setup = goldfish_tty_console_setup;
312+ goldfish_ttys[pdev->id].console.flags = CON_PRINTBUFFER;
313+ goldfish_ttys[pdev->id].console.index = pdev->id;
314+ register_console(&goldfish_ttys[pdev->id].console);
315+
316+
317+ mutex_unlock(&goldfish_tty_lock);
318+
319+ return 0;
320+
321+ tty_unregister_device(goldfish_tty_driver, i);
322+err_tty_register_device_failed:
323+ free_irq(irq, pdev);
324+err_request_irq_failed:
325+ goldfish_tty_current_line_count--;
326+ if(goldfish_tty_current_line_count == 0) {
327+ goldfish_tty_delete_driver();
328+ }
329+err_create_driver_failed:
330+ mutex_unlock(&goldfish_tty_lock);
331+ return ret;
332+}
333+
334+static int __devexit goldfish_tty_remove(struct platform_device *pdev)
335+{
336+ mutex_lock(&goldfish_tty_lock);
337+ unregister_console(&goldfish_ttys[pdev->id].console);
338+ tty_unregister_device(goldfish_tty_driver, pdev->id);
339+ goldfish_ttys[pdev->id].base = 0;
340+ free_irq(goldfish_ttys[pdev->id].irq, pdev);
341+ goldfish_tty_current_line_count--;
342+ if(goldfish_tty_current_line_count == 0) {
343+ goldfish_tty_delete_driver();
344+ }
345+ mutex_unlock(&goldfish_tty_lock);
346+ return 0;
347+}
348+
349+static struct platform_driver goldfish_tty_platform_driver = {
350+ .probe = goldfish_tty_probe,
351+ .remove = __devexit_p(goldfish_tty_remove),
352+ .driver = {
353+ .name = "goldfish_tty"
354+ }
355+};
356+
357+static int __init goldfish_tty_init(void)
358+{
359+ return platform_driver_register(&goldfish_tty_platform_driver);
360+}
361+
362+static void __exit goldfish_tty_exit(void)
363+{
364+ platform_driver_unregister(&goldfish_tty_platform_driver);
365+}
366+
367+module_init(goldfish_tty_init);
368+module_exit(goldfish_tty_exit);
369

Archive Download this file



interactive