drivers/watchdog/sb_wdog.c

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

File Facts

System
Linux kernel
Corpus path
drivers/watchdog/sb_wdog.c
Extension
.c
Size
8773 bytes
Lines
363
Domain
Driver Families
Bucket
drivers/watchdog
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 sbwdog_fops = {
	.owner		= THIS_MODULE,
	.write		= sbwdog_write,
	.unlocked_ioctl	= sbwdog_ioctl,
	.compat_ioctl	= compat_ptr_ioctl,
	.open		= sbwdog_open,
	.release	= sbwdog_release,
};

static struct miscdevice sbwdog_miscdev = {
	.minor		= WATCHDOG_MINOR,
	.name		= "watchdog",
	.fops		= &sbwdog_fops,
};

static struct notifier_block sbwdog_notifier = {
	.notifier_call	= sbwdog_notify_sys,
};

/*
 * interrupt handler
 *
 * doesn't do a whole lot for user, but oh so cleverly written so kernel
 * code can use it to re-up the watchdog, thereby saving the kernel from
 * having to create and maintain a timer, just to tickle another timer,
 * which is just so wrong.
 */
irqreturn_t sbwdog_interrupt(int irq, void *addr)
{
	unsigned long wd_init;
	char *wd_cfg_reg = (char *)addr;
	u8 cfg;

	cfg = __raw_readb(wd_cfg_reg);
	wd_init = __raw_readq(wd_cfg_reg - 8) & 0x7fffff;

	/*
	 * if it's the second watchdog timer, it's for those users
	 */
	if (wd_cfg_reg == user_dog)
		pr_crit("%s in danger of initiating system reset "
			"in %ld.%01ld seconds\n",
			ident.identity,
			wd_init / 1000000, (wd_init / 100000) % 10);
	else
		cfg |= 1;

	__raw_writeb(cfg, wd_cfg_reg);

	return IRQ_HANDLED;
}

static int __init sbwdog_init(void)
{
	int ret;

	/*
	 * register a reboot notifier
	 */
	ret = register_reboot_notifier(&sbwdog_notifier);
	if (ret) {
		pr_err("%s: cannot register reboot notifier (err=%d)\n",
		       ident.identity, ret);
		return ret;
	}

	/*
	 * get the resources
	 */

	ret = request_irq(1, sbwdog_interrupt, IRQF_SHARED,
		ident.identity, (void *)user_dog);
	if (ret) {
		pr_err("%s: failed to request irq 1 - %d\n",
		       ident.identity, ret);
		goto out;
	}

	ret = misc_register(&sbwdog_miscdev);
	if (ret == 0) {
		pr_info("%s: timeout is %ld.%ld secs\n",
			ident.identity,
			timeout / 1000000, (timeout / 100000) % 10);
		return 0;
	}
	free_irq(1, (void *)user_dog);
out:
	unregister_reboot_notifier(&sbwdog_notifier);

	return ret;

Annotation

Implementation Notes