drivers/watchdog/nic7018_wdt.c

Source file repositories/reference/linux-study-clean/drivers/watchdog/nic7018_wdt.c

File Facts

System
Linux kernel
Corpus path
drivers/watchdog/nic7018_wdt.c
Extension
.c
Size
5758 bytes
Lines
252
Domain
Driver Families
Bucket
drivers/watchdog
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 nic7018_wdt {
	u16 io_base;
	u32 period;
	struct watchdog_device wdd;
};

struct nic7018_config {
	u32 period;
	u8 divider;
};

static const struct nic7018_config nic7018_configs[] = {
	{  2, 4 },
	{ 32, 5 },
};

static inline u32 nic7018_timeout(u32 period, u8 counter)
{
	return period * counter - period / 2;
}

static const struct nic7018_config *nic7018_get_config(u32 timeout,
						       u8 *counter)
{
	const struct nic7018_config *config;
	u8 count;

	if (timeout < 30 && timeout != 16) {
		config = &nic7018_configs[0];
		count = timeout / 2 + 1;
	} else {
		config = &nic7018_configs[1];
		count = DIV_ROUND_UP(timeout + 16, 32);

		if (count > WDT_MAX_COUNTER)
			count = WDT_MAX_COUNTER;
	}
	*counter = count;
	return config;
}

static int nic7018_set_timeout(struct watchdog_device *wdd,
			       unsigned int timeout)
{
	struct nic7018_wdt *wdt = watchdog_get_drvdata(wdd);
	const struct nic7018_config *config;
	u8 counter;

	config = nic7018_get_config(timeout, &counter);

	outb(counter << 4 | config->divider,
	     wdt->io_base + WDT_PRESET_PRESCALE);

	wdd->timeout = nic7018_timeout(config->period, counter);
	wdt->period = config->period;

	return 0;
}

static int nic7018_start(struct watchdog_device *wdd)
{
	struct nic7018_wdt *wdt = watchdog_get_drvdata(wdd);
	u8 control;

	nic7018_set_timeout(wdd, wdd->timeout);

	control = inb(wdt->io_base + WDT_RELOAD_CTRL);
	outb(control | WDT_RELOAD_PORT_EN, wdt->io_base + WDT_RELOAD_CTRL);

	outb(1, wdt->io_base + WDT_RELOAD_PORT);

	control = inb(wdt->io_base + WDT_CTRL);
	outb(control | WDT_CTRL_RESET_EN, wdt->io_base + WDT_CTRL);

	return 0;
}

static int nic7018_stop(struct watchdog_device *wdd)
{
	struct nic7018_wdt *wdt = watchdog_get_drvdata(wdd);

	outb(0, wdt->io_base + WDT_CTRL);
	outb(0, wdt->io_base + WDT_RELOAD_CTRL);
	outb(0xF0, wdt->io_base + WDT_PRESET_PRESCALE);

	return 0;
}

static int nic7018_ping(struct watchdog_device *wdd)
{

Annotation

Implementation Notes