drivers/tty/goldfish.c

Source file repositories/reference/linux-study-clean/drivers/tty/goldfish.c

File Facts

System
Linux kernel
Corpus path
drivers/tty/goldfish.c
Extension
.c
Size
12140 bytes
Lines
473
Domain
Driver Families
Bucket
drivers/tty
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct goldfish_tty {
	struct tty_port port;
	spinlock_t lock;
	void __iomem *base;
	u32 irq;
	int opencount;
	struct console console;
	u32 version;
	struct device *dev;
};

static DEFINE_MUTEX(goldfish_tty_lock);
static struct tty_driver *goldfish_tty_driver;
static u32 goldfish_tty_line_count = 8;
static u32 goldfish_tty_current_line_count;
static struct goldfish_tty *goldfish_ttys;

static void do_rw_io(struct goldfish_tty *qtty, unsigned long address,
		     size_t count, bool is_write)
{
	unsigned long irq_flags;
	void __iomem *base = qtty->base;

	spin_lock_irqsave(&qtty->lock, irq_flags);
	gf_write_ptr((void *)address, base + GOLDFISH_TTY_REG_DATA_PTR,
		     base + GOLDFISH_TTY_REG_DATA_PTR_HIGH);
	gf_iowrite32(count, base + GOLDFISH_TTY_REG_DATA_LEN);

	if (is_write)
		gf_iowrite32(GOLDFISH_TTY_CMD_WRITE_BUFFER,
		       base + GOLDFISH_TTY_REG_CMD);
	else
		gf_iowrite32(GOLDFISH_TTY_CMD_READ_BUFFER,
		       base + GOLDFISH_TTY_REG_CMD);

	spin_unlock_irqrestore(&qtty->lock, irq_flags);
}

static void goldfish_tty_rw(struct goldfish_tty *qtty, unsigned long addr,
			    size_t count, bool is_write)
{
	dma_addr_t dma_handle;
	enum dma_data_direction dma_dir;

	dma_dir = (is_write ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
	if (qtty->version > 0) {
		/*
		 * Goldfish TTY for Ranchu platform uses
		 * physical addresses and DMA for read/write operations
		 */
		unsigned long addr_end = addr + count;

		while (addr < addr_end) {
			unsigned long pg_end = (addr & PAGE_MASK) + PAGE_SIZE;
			unsigned long next =
					pg_end < addr_end ? pg_end : addr_end;
			unsigned long avail = next - addr;

			/*
			 * Map the buffer's virtual address to the DMA address
			 * so the buffer can be accessed by the device.
			 */
			dma_handle = dma_map_single(qtty->dev, (void *)addr,
						    avail, dma_dir);

			if (dma_mapping_error(qtty->dev, dma_handle)) {
				dev_err(qtty->dev, "tty: DMA mapping error.\n");
				return;
			}
			do_rw_io(qtty, dma_handle, avail, is_write);

			/*
			 * Unmap the previously mapped region after
			 * the completion of the read/write operation.
			 */
			dma_unmap_single(qtty->dev, dma_handle, avail, dma_dir);

			addr += avail;
		}
	} else {
		/*
		 * Old style Goldfish TTY used on the Goldfish platform
		 * uses virtual addresses.
		 */
		do_rw_io(qtty, addr, count, is_write);
	}
}

static void goldfish_tty_do_write(int line, const u8 *buf, size_t count)
{

Annotation

Implementation Notes