drivers/gpib/hp_82341/hp_82341.c

Source file repositories/reference/linux-study-clean/drivers/gpib/hp_82341/hp_82341.c

File Facts

System
Linux kernel
Corpus path
drivers/gpib/hp_82341/hp_82341.c
Extension
.c
Size
26527 bytes
Lines
909
Domain
Driver Families
Bucket
drivers/gpib
Inferred role
Driver Families: exported/initcall integration point
Status
integration 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

module_init(hp_82341_init_module);
module_exit(hp_82341_exit_module);

/*
 * GPIB interrupt service routines
 */
static unsigned short read_and_clear_event_status(struct gpib_board *board)
{
	struct hp_82341_priv *hp_priv = board->private_data;
	unsigned long flags;
	unsigned short status;

	spin_lock_irqsave(&board->spinlock, flags);
	status = hp_priv->event_status_bits;
	hp_priv->event_status_bits = 0;
	spin_unlock_irqrestore(&board->spinlock, flags);
	return status;
}

static irqreturn_t hp_82341_interrupt(int irq, void *arg)
{
	int status1, status2;
	struct gpib_board *board = arg;
	struct hp_82341_priv *hp_priv = board->private_data;
	struct tms9914_priv *tms_priv = &hp_priv->tms9914_priv;
	unsigned long flags;
	irqreturn_t retval = IRQ_NONE;
	int event_status;

	spin_lock_irqsave(&board->spinlock, flags);
	event_status = inb(hp_priv->iobase[0] + EVENT_STATUS_REG);
	if (event_status & INTERRUPT_PENDING_EVENT_BIT)
		retval = IRQ_HANDLED;
	// write-clear status bits
	if (event_status & (TI_INTERRUPT_EVENT_BIT | POINTERS_EQUAL_EVENT_BIT |
			    BUFFER_END_EVENT_BIT | TERMINAL_COUNT_EVENT_BIT)) {
		outb(event_status & (TI_INTERRUPT_EVENT_BIT | POINTERS_EQUAL_EVENT_BIT |
				     BUFFER_END_EVENT_BIT | TERMINAL_COUNT_EVENT_BIT),
		     hp_priv->iobase[0] + EVENT_STATUS_REG);
		hp_priv->event_status_bits |= event_status;
	}
	if (event_status & TI_INTERRUPT_EVENT_BIT) {
		status1 = read_byte(tms_priv, ISR0);
		status2 = read_byte(tms_priv, ISR1);
		tms9914_interrupt_have_status(board, tms_priv, status1, status2);
	}
	spin_unlock_irqrestore(&board->spinlock, flags);
	return retval;
}

static int read_transfer_counter(struct hp_82341_priv *hp_priv)
{
	int lo, mid, value;

	lo = inb(hp_priv->iobase[1] + TRANSFER_COUNT_LOW_REG);
	mid = inb(hp_priv->iobase[1] + TRANSFER_COUNT_MID_REG);
	value = (lo & 0xff) | ((mid << 8) & 0x7f00);
	value = ~(value - 1) & 0x7fff;
	return value;
}

static void set_transfer_counter(struct hp_82341_priv *hp_priv, int count)
{
	int complement = -count;

	outb(complement & 0xff, hp_priv->iobase[1] + TRANSFER_COUNT_LOW_REG);
	outb((complement >> 8) & 0xff, hp_priv->iobase[1] + TRANSFER_COUNT_MID_REG);
	// I don't think the hi count reg is even used, but oh well
	outb((complement >> 16) & 0xf, hp_priv->iobase[1] + TRANSFER_COUNT_HIGH_REG);
}

Annotation

Implementation Notes