drivers/misc/bcm-vk/bcm_vk_tty.c

Source file repositories/reference/linux-study-clean/drivers/misc/bcm-vk/bcm_vk_tty.c

File Facts

System
Linux kernel
Corpus path
drivers/misc/bcm-vk/bcm_vk_tty.c
Extension
.c
Size
8371 bytes
Lines
339
Domain
Driver Families
Bucket
drivers/misc
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 bcm_vk_tty_chan {
	u32 reserved;
	u32 size;
	u32 wr;
	u32 rd;
	u32 *data;
};

#define VK_BAR_CHAN(v, DIR, e)	((v)->DIR##_offset \
				 + offsetof(struct bcm_vk_tty_chan, e))
#define VK_BAR_CHAN_SIZE(v, DIR)	VK_BAR_CHAN(v, DIR, size)
#define VK_BAR_CHAN_WR(v, DIR)		VK_BAR_CHAN(v, DIR, wr)
#define VK_BAR_CHAN_RD(v, DIR)		VK_BAR_CHAN(v, DIR, rd)
#define VK_BAR_CHAN_DATA(v, DIR, off)	(VK_BAR_CHAN(v, DIR, data) + (off))

#define VK_BAR0_REGSEG_TTY_DB_OFFSET	0x86c

/* Poll every 1/10 of second - temp hack till we use MSI interrupt */
#define SERIAL_TIMER_VALUE (HZ / 10)

static void bcm_vk_tty_poll(struct timer_list *t)
{
	struct bcm_vk *vk = timer_container_of(vk, t, serial_timer);

	queue_work(vk->tty_wq_thread, &vk->tty_wq_work);
	mod_timer(&vk->serial_timer, jiffies + SERIAL_TIMER_VALUE);
}

irqreturn_t bcm_vk_tty_irqhandler(int irq, void *dev_id)
{
	struct bcm_vk *vk = dev_id;

	queue_work(vk->tty_wq_thread, &vk->tty_wq_work);

	return IRQ_HANDLED;
}

static void bcm_vk_tty_wq_handler(struct work_struct *work)
{
	struct bcm_vk *vk = container_of(work, struct bcm_vk, tty_wq_work);
	struct bcm_vk_tty *vktty;
	int card_status;
	int count;
	int i;
	int wr;
	u8 c;

	card_status = vkread32(vk, BAR_0, BAR_CARD_STATUS);
	if (BCM_VK_INTF_IS_DOWN(card_status))
		return;

	for (i = 0; i < BCM_VK_NUM_TTY; i++) {
		count = 0;
		/* Check the card status that the tty channel is ready */
		if ((card_status & BIT(i)) == 0)
			continue;

		vktty = &vk->tty[i];

		/* Don't increment read index if tty app is closed */
		if (!vktty->is_opened)
			continue;

		/* Fetch the wr offset in buffer from VK */
		wr = vkread32(vk, BAR_1, VK_BAR_CHAN_WR(vktty, from));

		/* safe to ignore until bar read gives proper size */
		if (vktty->from_size == 0)
			continue;

		if (wr >= vktty->from_size) {
			dev_err(&vk->pdev->dev,
				"ERROR: wq handler ttyVK%d wr:0x%x > 0x%x\n",
				i, wr, vktty->from_size);
			/* Need to signal and close device in this case */
			continue;
		}

		/*
		 * Simple read of circular buffer and
		 * insert into tty flip buffer
		 */
		while (vk->tty[i].rd != wr) {
			c = vkread8(vk, BAR_1,
				    VK_BAR_CHAN_DATA(vktty, from, vktty->rd));
			vktty->rd++;
			if (vktty->rd >= vktty->from_size)
				vktty->rd = 0;
			tty_insert_flip_char(&vktty->port, c, TTY_NORMAL);
			count++;

Annotation

Implementation Notes