1 /* 2 * Copyright (C) 2007 Google, Inc. 3 * Copyright (C) 2012 Intel, Inc. 4 * 5 * This software is licensed under the terms of the GNU General Public 6 * License version 2, as published by the Free Software Foundation, and 7 * may be copied, distributed, and modified under those terms. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 */ 15 16 #include <linux/console.h> 17 #include <linux/interrupt.h> 18 #include <linux/platform_device.h> 19 #include <linux/tty.h> 20 #include <linux/tty_flip.h> 21 #include <linux/slab.h> 22 #include <linux/io.h> 23 #include <linux/module.h> 24 #include <linux/goldfish.h> 25 26 enum { 27 GOLDFISH_TTY_PUT_CHAR = 0x00, 28 GOLDFISH_TTY_BYTES_READY = 0x04, 29 GOLDFISH_TTY_CMD = 0x08, 30 31 GOLDFISH_TTY_DATA_PTR = 0x10, 32 GOLDFISH_TTY_DATA_LEN = 0x14, 33 GOLDFISH_TTY_DATA_PTR_HIGH = 0x18, 34 35 GOLDFISH_TTY_CMD_INT_DISABLE = 0, 36 GOLDFISH_TTY_CMD_INT_ENABLE = 1, 37 GOLDFISH_TTY_CMD_WRITE_BUFFER = 2, 38 GOLDFISH_TTY_CMD_READ_BUFFER = 3, 39 }; 40 41 struct goldfish_tty { 42 struct tty_port port; 43 spinlock_t lock; 44 void __iomem *base; 45 u32 irq; 46 int opencount; 47 struct console console; 48 }; 49 50 static DEFINE_MUTEX(goldfish_tty_lock); 51 static struct tty_driver *goldfish_tty_driver; 52 static u32 goldfish_tty_line_count = 8; 53 static u32 goldfish_tty_current_line_count; 54 static struct goldfish_tty *goldfish_ttys; 55 56 static void goldfish_tty_do_write(int line, const char *buf, unsigned count) 57 { 58 unsigned long irq_flags; 59 struct goldfish_tty *qtty = &goldfish_ttys[line]; 60 void __iomem *base = qtty->base; 61 spin_lock_irqsave(&qtty->lock, irq_flags); 62 gf_write_ptr(buf, base + GOLDFISH_TTY_DATA_PTR, 63 base + GOLDFISH_TTY_DATA_PTR_HIGH); 64 writel(count, base + GOLDFISH_TTY_DATA_LEN); 65 writel(GOLDFISH_TTY_CMD_WRITE_BUFFER, base + GOLDFISH_TTY_CMD); 66 spin_unlock_irqrestore(&qtty->lock, irq_flags); 67 } 68 69 static irqreturn_t goldfish_tty_interrupt(int irq, void *dev_id) 70 { 71 struct platform_device *pdev = dev_id; 72 struct goldfish_tty *qtty = &goldfish_ttys[pdev->id]; 73 void __iomem *base = qtty->base; 74 unsigned long irq_flags; 75 unsigned char *buf; 76 u32 count; 77 78 count = readl(base + GOLDFISH_TTY_BYTES_READY); 79 if (count == 0) 80 return IRQ_NONE; 81 82 count = tty_prepare_flip_string(&qtty->port, &buf, count); 83 spin_lock_irqsave(&qtty->lock, irq_flags); 84 gf_write_ptr(buf, base + GOLDFISH_TTY_DATA_PTR, 85 base + GOLDFISH_TTY_DATA_PTR_HIGH); 86 writel(count, base + GOLDFISH_TTY_DATA_LEN); 87 writel(GOLDFISH_TTY_CMD_READ_BUFFER, base + GOLDFISH_TTY_CMD); 88 spin_unlock_irqrestore(&qtty->lock, irq_flags); 89 tty_schedule_flip(&qtty->port); 90 return IRQ_HANDLED; 91 } 92 93 static int goldfish_tty_activate(struct tty_port *port, struct tty_struct *tty) 94 { 95 struct goldfish_tty *qtty = container_of(port, struct goldfish_tty, 96 port); 97 writel(GOLDFISH_TTY_CMD_INT_ENABLE, qtty->base + GOLDFISH_TTY_CMD); 98 return 0; 99 } 100 101 static void goldfish_tty_shutdown(struct tty_port *port) 102 { 103 struct goldfish_tty *qtty = container_of(port, struct goldfish_tty, 104 port); 105 writel(GOLDFISH_TTY_CMD_INT_DISABLE, qtty->base + GOLDFISH_TTY_CMD); 106 } 107 108 static int goldfish_tty_open(struct tty_struct *tty, struct file *filp) 109 { 110 struct goldfish_tty *qtty = &goldfish_ttys[tty->index]; 111 return tty_port_open(&qtty->port, tty, filp); 112 } 113 114 static void goldfish_tty_close(struct tty_struct *tty, struct file *filp) 115 { 116 tty_port_close(tty->port, tty, filp); 117 } 118 119 static void goldfish_tty_hangup(struct tty_struct *tty) 120 { 121 tty_port_hangup(tty->port); 122 } 123 124 static int goldfish_tty_write(struct tty_struct *tty, const unsigned char *buf, 125 int count) 126 { 127 goldfish_tty_do_write(tty->index, buf, count); 128 return count; 129 } 130 131 static int goldfish_tty_write_room(struct tty_struct *tty) 132 { 133 return 0x10000; 134 } 135 136 static int goldfish_tty_chars_in_buffer(struct tty_struct *tty) 137 { 138 struct goldfish_tty *qtty = &goldfish_ttys[tty->index]; 139 void __iomem *base = qtty->base; 140 return readl(base + GOLDFISH_TTY_BYTES_READY); 141 } 142 143 static void goldfish_tty_console_write(struct console *co, const char *b, 144 unsigned count) 145 { 146 goldfish_tty_do_write(co->index, b, count); 147 } 148 149 static struct tty_driver *goldfish_tty_console_device(struct console *c, 150 int *index) 151 { 152 *index = c->index; 153 return goldfish_tty_driver; 154 } 155 156 static int goldfish_tty_console_setup(struct console *co, char *options) 157 { 158 if ((unsigned)co->index >= goldfish_tty_line_count) 159 return -ENODEV; 160 if (!goldfish_ttys[co->index].base) 161 return -ENODEV; 162 return 0; 163 } 164 165 static struct tty_port_operations goldfish_port_ops = { 166 .activate = goldfish_tty_activate, 167 .shutdown = goldfish_tty_shutdown 168 }; 169 170 static const struct tty_operations goldfish_tty_ops = { 171 .open = goldfish_tty_open, 172 .close = goldfish_tty_close, 173 .hangup = goldfish_tty_hangup, 174 .write = goldfish_tty_write, 175 .write_room = goldfish_tty_write_room, 176 .chars_in_buffer = goldfish_tty_chars_in_buffer, 177 }; 178 179 static int goldfish_tty_create_driver(void) 180 { 181 int ret; 182 struct tty_driver *tty; 183 184 goldfish_ttys = kzalloc(sizeof(*goldfish_ttys) * 185 goldfish_tty_line_count, GFP_KERNEL); 186 if (goldfish_ttys == NULL) { 187 ret = -ENOMEM; 188 goto err_alloc_goldfish_ttys_failed; 189 } 190 tty = alloc_tty_driver(goldfish_tty_line_count); 191 if (tty == NULL) { 192 ret = -ENOMEM; 193 goto err_alloc_tty_driver_failed; 194 } 195 tty->driver_name = "goldfish"; 196 tty->name = "ttyGF"; 197 tty->type = TTY_DRIVER_TYPE_SERIAL; 198 tty->subtype = SERIAL_TYPE_NORMAL; 199 tty->init_termios = tty_std_termios; 200 tty->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW | 201 TTY_DRIVER_DYNAMIC_DEV; 202 tty_set_operations(tty, &goldfish_tty_ops); 203 ret = tty_register_driver(tty); 204 if (ret) 205 goto err_tty_register_driver_failed; 206 207 goldfish_tty_driver = tty; 208 return 0; 209 210 err_tty_register_driver_failed: 211 put_tty_driver(tty); 212 err_alloc_tty_driver_failed: 213 kfree(goldfish_ttys); 214 goldfish_ttys = NULL; 215 err_alloc_goldfish_ttys_failed: 216 return ret; 217 } 218 219 static void goldfish_tty_delete_driver(void) 220 { 221 tty_unregister_driver(goldfish_tty_driver); 222 put_tty_driver(goldfish_tty_driver); 223 goldfish_tty_driver = NULL; 224 kfree(goldfish_ttys); 225 goldfish_ttys = NULL; 226 } 227 228 static int goldfish_tty_probe(struct platform_device *pdev) 229 { 230 struct goldfish_tty *qtty; 231 int ret = -EINVAL; 232 struct resource *r; 233 struct device *ttydev; 234 void __iomem *base; 235 u32 irq; 236 237 r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 238 if (r == NULL) 239 return -EINVAL; 240 241 base = ioremap(r->start, 0x1000); 242 if (base == NULL) 243 pr_err("goldfish_tty: unable to remap base\n"); 244 245 r = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 246 if (r == NULL) 247 goto err_unmap; 248 249 irq = r->start; 250 251 if (pdev->id >= goldfish_tty_line_count) 252 goto err_unmap; 253 254 mutex_lock(&goldfish_tty_lock); 255 if (goldfish_tty_current_line_count == 0) { 256 ret = goldfish_tty_create_driver(); 257 if (ret) 258 goto err_create_driver_failed; 259 } 260 goldfish_tty_current_line_count++; 261 262 qtty = &goldfish_ttys[pdev->id]; 263 spin_lock_init(&qtty->lock); 264 tty_port_init(&qtty->port); 265 qtty->port.ops = &goldfish_port_ops; 266 qtty->base = base; 267 qtty->irq = irq; 268 269 writel(GOLDFISH_TTY_CMD_INT_DISABLE, base + GOLDFISH_TTY_CMD); 270 271 ret = request_irq(irq, goldfish_tty_interrupt, IRQF_SHARED, 272 "goldfish_tty", pdev); 273 if (ret) 274 goto err_request_irq_failed; 275 276 277 ttydev = tty_port_register_device(&qtty->port, goldfish_tty_driver, 278 pdev->id, &pdev->dev); 279 if (IS_ERR(ttydev)) { 280 ret = PTR_ERR(ttydev); 281 goto err_tty_register_device_failed; 282 } 283 284 strcpy(qtty->console.name, "ttyGF"); 285 qtty->console.write = goldfish_tty_console_write; 286 qtty->console.device = goldfish_tty_console_device; 287 qtty->console.setup = goldfish_tty_console_setup; 288 qtty->console.flags = CON_PRINTBUFFER; 289 qtty->console.index = pdev->id; 290 register_console(&qtty->console); 291 292 mutex_unlock(&goldfish_tty_lock); 293 return 0; 294 295 err_tty_register_device_failed: 296 free_irq(irq, pdev); 297 err_request_irq_failed: 298 goldfish_tty_current_line_count--; 299 if (goldfish_tty_current_line_count == 0) 300 goldfish_tty_delete_driver(); 301 err_create_driver_failed: 302 mutex_unlock(&goldfish_tty_lock); 303 err_unmap: 304 iounmap(base); 305 return ret; 306 } 307 308 static int goldfish_tty_remove(struct platform_device *pdev) 309 { 310 struct goldfish_tty *qtty; 311 312 mutex_lock(&goldfish_tty_lock); 313 314 qtty = &goldfish_ttys[pdev->id]; 315 unregister_console(&qtty->console); 316 tty_unregister_device(goldfish_tty_driver, pdev->id); 317 iounmap(qtty->base); 318 qtty->base = NULL; 319 free_irq(qtty->irq, pdev); 320 goldfish_tty_current_line_count--; 321 if (goldfish_tty_current_line_count == 0) 322 goldfish_tty_delete_driver(); 323 mutex_unlock(&goldfish_tty_lock); 324 return 0; 325 } 326 327 static struct platform_driver goldfish_tty_platform_driver = { 328 .probe = goldfish_tty_probe, 329 .remove = goldfish_tty_remove, 330 .driver = { 331 .name = "goldfish_tty" 332 } 333 }; 334 335 module_platform_driver(goldfish_tty_platform_driver); 336 337 MODULE_LICENSE("GPL v2"); 338