drivers/auxdisplay/panel.c

Source file repositories/reference/linux-study-clean/drivers/auxdisplay/panel.c

File Facts

System
Linux kernel
Corpus path
drivers/auxdisplay/panel.c
Extension
.c
Size
45825 bytes
Lines
1707
Domain
Driver Families
Bucket
drivers/auxdisplay
Inferred role
Driver Families: operation-table or driver-model contract
Status
pattern 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

static const struct file_operations keypad_fops = {
	.read    = keypad_read,		/* read */
	.open    = keypad_open,		/* open */
	.release = keypad_release,	/* close */
	.llseek  = default_llseek,
};

static struct miscdevice keypad_dev = {
	.minor	= KEYPAD_MINOR,
	.name	= "keypad",
	.fops	= &keypad_fops,
};

static void keypad_send_key(const char *string, int max_len)
{
	/* send the key to the device only if a process is attached to it. */
	if (!atomic_read(&keypad_available)) {
		while (max_len-- && keypad_buflen < KEYPAD_BUFFER && *string) {
			keypad_buffer[(keypad_start + keypad_buflen++) %
				      KEYPAD_BUFFER] = *string++;
		}
		wake_up_interruptible(&keypad_read_wait);
	}
}

/* this function scans all the bits involving at least one logical signal,
 * and puts the results in the bitfield "phys_read" (one bit per established
 * contact), and sets "phys_read_prev" to "phys_read".
 *
 * Note: to debounce input signals, we will only consider as switched a signal
 * which is stable across 2 measures. Signals which are different between two
 * reads will be kept as they previously were in their logical form (phys_prev).
 * A signal which has just switched will have a 1 in
 * (phys_read ^ phys_read_prev).
 */
static void phys_scan_contacts(void)
{
	int bit, bitval;
	char oldval;
	char bitmask;
	char gndmask;

	phys_prev = phys_curr;
	phys_read_prev = phys_read;
	phys_read = 0;		/* flush all signals */

	/* keep track of old value, with all outputs disabled */
	oldval = r_dtr(pprt) | scan_mask_o;
	/* activate all keyboard outputs (active low) */
	w_dtr(pprt, oldval & ~scan_mask_o);

	/* will have a 1 for each bit set to gnd */
	bitmask = PNL_PINPUT(r_str(pprt)) & scan_mask_i;
	/* disable all matrix signals */
	w_dtr(pprt, oldval);

	/* now that all outputs are cleared, the only active input bits are
	 * directly connected to the ground
	 */

	/* 1 for each grounded input */
	gndmask = PNL_PINPUT(r_str(pprt)) & scan_mask_i;

	/* grounded inputs are signals 40-44 */
	phys_read |= (__u64)gndmask << 40;

	if (bitmask != gndmask) {
		/*
		 * since clearing the outputs changed some inputs, we know
		 * that some input signals are currently tied to some outputs.
		 * So we'll scan them.
		 */
		for (bit = 0; bit < 8; bit++) {
			bitval = BIT(bit);

			if (!(scan_mask_o & bitval))	/* skip unused bits */
				continue;

			w_dtr(pprt, oldval & ~bitval);	/* enable this output */
			bitmask = PNL_PINPUT(r_str(pprt)) & ~gndmask;
			phys_read |= (__u64)bitmask << (5 * bit);
		}
		w_dtr(pprt, oldval);	/* disable all outputs */
	}
	/*
	 * this is easy: use old bits when they are flapping,
	 * use new ones when stable
	 */
	phys_curr = (phys_prev & (phys_read ^ phys_read_prev)) |
		    (phys_read & ~(phys_read ^ phys_read_prev));

Annotation

Implementation Notes