예제 #1
0
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;
}
예제 #2
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;
}
예제 #3
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;
}
예제 #4
0
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;
}