static int goldfish_tty_remove(struct platform_device *pdev) { mutex_lock(&goldfish_tty_lock); unregister_console(&goldfish_ttys[pdev->id].console); tty_unregister_device(goldfish_tty_driver, pdev->id); goldfish_ttys[pdev->id].base = 0; free_irq(goldfish_ttys[pdev->id].irq, pdev); goldfish_tty_current_line_count--; if(goldfish_tty_current_line_count == 0) { goldfish_tty_delete_driver(); } mutex_unlock(&goldfish_tty_lock); return 0; }
static int goldfish_tty_remove(struct platform_device *pdev) { struct goldfish_tty *qtty = platform_get_drvdata(pdev); mutex_lock(&goldfish_tty_lock); unregister_console(&qtty->console); tty_unregister_device(goldfish_tty_driver, qtty->console.index); iounmap(qtty->base); qtty->base = NULL; free_irq(qtty->irq, pdev); goldfish_tty_current_line_count--; if (goldfish_tty_current_line_count == 0) goldfish_tty_delete_driver(); mutex_unlock(&goldfish_tty_lock); return 0; }
static int goldfish_tty_probe(struct platform_device *pdev) { int ret; int i; struct resource *r; struct device *ttydev; uint32_t base; uint32_t irq; r = platform_get_resource(pdev, IORESOURCE_MEM, 0); if(r == NULL) return -EINVAL; base = IO_ADDRESS(r->start - IO_START); r = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if(r == NULL) return -EINVAL; irq = r->start; if(pdev->id >= goldfish_tty_line_count) return -EINVAL; mutex_lock(&goldfish_tty_lock); if(goldfish_tty_current_line_count == 0) { ret = goldfish_tty_create_driver(); if(ret) goto err_create_driver_failed; } goldfish_tty_current_line_count++; spin_lock_init(&goldfish_ttys[pdev->id].lock); goldfish_ttys[pdev->id].base = base; goldfish_ttys[pdev->id].irq = irq; writel(GOLDFISH_TTY_CMD_INT_DISABLE, base + GOLDFISH_TTY_CMD); ret = request_irq(irq, goldfish_tty_interrupt, IRQF_SHARED, "goldfish_tty", pdev); if(ret) goto err_request_irq_failed; ttydev = tty_register_device(goldfish_tty_driver, pdev->id, NULL); if(IS_ERR(ttydev)) { ret = PTR_ERR(ttydev); goto err_tty_register_device_failed; } strcpy(goldfish_ttys[pdev->id].console.name, "ttyS"); goldfish_ttys[pdev->id].console.write = goldfish_tty_console_write; goldfish_ttys[pdev->id].console.device = goldfish_tty_console_device; goldfish_ttys[pdev->id].console.setup = goldfish_tty_console_setup; goldfish_ttys[pdev->id].console.flags = CON_PRINTBUFFER; goldfish_ttys[pdev->id].console.index = pdev->id; register_console(&goldfish_ttys[pdev->id].console); mutex_unlock(&goldfish_tty_lock); return 0; tty_unregister_device(goldfish_tty_driver, i); err_tty_register_device_failed: free_irq(irq, pdev); err_request_irq_failed: goldfish_tty_current_line_count--; if(goldfish_tty_current_line_count == 0) { goldfish_tty_delete_driver(); } err_create_driver_failed: mutex_unlock(&goldfish_tty_lock); return ret; }
static int goldfish_tty_probe(struct platform_device *pdev) { struct goldfish_tty *qtty; int ret = -ENODEV; struct resource *r; struct device *ttydev; void __iomem *base; u32 irq; unsigned int line; r = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!r) { pr_err("goldfish_tty: No MEM resource available!\n"); return -ENOMEM; } base = ioremap(r->start, 0x1000); if (!base) { pr_err("goldfish_tty: Unable to ioremap base!\n"); return -ENOMEM; } r = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!r) { pr_err("goldfish_tty: No IRQ resource available!\n"); goto err_unmap; } irq = r->start; mutex_lock(&goldfish_tty_lock); if (pdev->id == PLATFORM_DEVID_NONE) line = goldfish_tty_current_line_count; else line = pdev->id; if (line >= goldfish_tty_line_count) { pr_err("goldfish_tty: Reached maximum tty number of %d.\n", goldfish_tty_current_line_count); ret = -ENOMEM; goto err_unlock; } if (goldfish_tty_current_line_count == 0) { ret = goldfish_tty_create_driver(); if (ret) goto err_unlock; } goldfish_tty_current_line_count++; qtty = &goldfish_ttys[line]; spin_lock_init(&qtty->lock); tty_port_init(&qtty->port); qtty->port.ops = &goldfish_port_ops; qtty->base = base; qtty->irq = irq; qtty->dev = &pdev->dev; /* * Goldfish TTY device used by the Goldfish emulator * should identify itself with 0, forcing the driver * to use virtual addresses. Goldfish TTY device * on Ranchu emulator (qemu2) returns 1 here and * driver will use physical addresses. */ qtty->version = readl(base + GOLDFISH_TTY_REG_VERSION); /* * Goldfish TTY device on Ranchu emulator (qemu2) * will use DMA for read/write IO operations. */ if (qtty->version > 0) { /* * Initialize dma_mask to 32-bits. */ if (!pdev->dev.dma_mask) pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); if (ret) { dev_err(&pdev->dev, "No suitable DMA available.\n"); goto err_dec_line_count; } } writel(GOLDFISH_TTY_CMD_INT_DISABLE, base + GOLDFISH_TTY_REG_CMD); ret = request_irq(irq, goldfish_tty_interrupt, IRQF_SHARED, "goldfish_tty", qtty); if (ret) { pr_err("goldfish_tty: No IRQ available!\n"); goto err_dec_line_count; } ttydev = tty_port_register_device(&qtty->port, goldfish_tty_driver, line, &pdev->dev); if (IS_ERR(ttydev)) { ret = PTR_ERR(ttydev); goto err_tty_register_device_failed; } strcpy(qtty->console.name, "ttyGF"); qtty->console.write = goldfish_tty_console_write; qtty->console.device = goldfish_tty_console_device; qtty->console.setup = goldfish_tty_console_setup; qtty->console.flags = CON_PRINTBUFFER; qtty->console.index = line; register_console(&qtty->console); platform_set_drvdata(pdev, qtty); mutex_unlock(&goldfish_tty_lock); return 0; err_tty_register_device_failed: free_irq(irq, qtty); err_dec_line_count: goldfish_tty_current_line_count--; if (goldfish_tty_current_line_count == 0) goldfish_tty_delete_driver(); err_unlock: mutex_unlock(&goldfish_tty_lock); err_unmap: iounmap(base); return ret; }