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_write64((u64)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_write64((u64)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 == 0) 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 int i; 233 struct resource *r; 234 struct device *ttydev; 235 void __iomem *base; 236 u32 irq; 237 238 r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 239 if (r == NULL) 240 return -EINVAL; 241 242 base = ioremap(r->start, 0x1000); 243 if (base == NULL) 244 pr_err("goldfish_tty: unable to remap base\n"); 245 246 r = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 247 if (r == NULL) 248 goto err_unmap; 249 250 irq = r->start; 251 252 if (pdev->id >= goldfish_tty_line_count) 253 goto err_unmap; 254 255 mutex_lock(&goldfish_tty_lock); 256 if (goldfish_tty_current_line_count == 0) { 257 ret = goldfish_tty_create_driver(); 258 if (ret) 259 goto err_create_driver_failed; 260 } 261 goldfish_tty_current_line_count++; 262 263 qtty = &goldfish_ttys[pdev->id]; 264 spin_lock_init(&qtty->lock); 265 tty_port_init(&qtty->port); 266 qtty->port.ops = &goldfish_port_ops; 267 qtty->base = base; 268 qtty->irq = irq; 269 270 writel(GOLDFISH_TTY_CMD_INT_DISABLE, base + GOLDFISH_TTY_CMD); 271 272 ret = request_irq(irq, goldfish_tty_interrupt, IRQF_SHARED, 273 "goldfish_tty", pdev); 274 if (ret) 275 goto err_request_irq_failed; 276 277 278 ttydev = tty_port_register_device(&qtty->port, goldfish_tty_driver, 279 pdev->id, &pdev->dev); 280 if (IS_ERR(ttydev)) { 281 ret = PTR_ERR(ttydev); 282 goto err_tty_register_device_failed; 283 } 284 285 strcpy(qtty->console.name, "ttyGF"); 286 qtty->console.write = goldfish_tty_console_write; 287 qtty->console.device = goldfish_tty_console_device; 288 qtty->console.setup = goldfish_tty_console_setup; 289 qtty->console.flags = CON_PRINTBUFFER; 290 qtty->console.index = pdev->id; 291 register_console(&qtty->console); 292 293 mutex_unlock(&goldfish_tty_lock); 294 return 0; 295 296 tty_unregister_device(goldfish_tty_driver, i); 297 err_tty_register_device_failed: 298 free_irq(irq, pdev); 299 err_request_irq_failed: 300 goldfish_tty_current_line_count--; 301 if (goldfish_tty_current_line_count == 0) 302 goldfish_tty_delete_driver(); 303 err_create_driver_failed: 304 mutex_unlock(&goldfish_tty_lock); 305 err_unmap: 306 iounmap(base); 307 return ret; 308 } 309 310 static int goldfish_tty_remove(struct platform_device *pdev) 311 { 312 struct goldfish_tty *qtty; 313 314 mutex_lock(&goldfish_tty_lock); 315 316 qtty = &goldfish_ttys[pdev->id]; 317 unregister_console(&qtty->console); 318 tty_unregister_device(goldfish_tty_driver, pdev->id); 319 iounmap(qtty->base); 320 qtty->base = 0; 321 free_irq(qtty->irq, pdev); 322 goldfish_tty_current_line_count--; 323 if (goldfish_tty_current_line_count == 0) 324 goldfish_tty_delete_driver(); 325 mutex_unlock(&goldfish_tty_lock); 326 return 0; 327 } 328 329 static struct platform_driver goldfish_tty_platform_driver = { 330 .probe = goldfish_tty_probe, 331 .remove = goldfish_tty_remove, 332 .driver = { 333 .name = "goldfish_tty" 334 } 335 }; 336 337 module_platform_driver(goldfish_tty_platform_driver); 338 339 MODULE_LICENSE("GPL v2"); 340