cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

wdt_pci.c (17484B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 *	Industrial Computer Source PCI-WDT500/501 driver
      4 *
      5 *	(c) Copyright 1996-1997 Alan Cox <alan@lxorguk.ukuu.org.uk>,
      6 *						All Rights Reserved.
      7 *
      8 *	Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
      9 *	warranty for any of this software. This material is provided
     10 *	"AS-IS" and at no charge.
     11 *
     12 *	(c) Copyright 1995    Alan Cox <alan@lxorguk.ukuu.org.uk>
     13 *
     14 *	Release 0.10.
     15 *
     16 *	Fixes
     17 *		Dave Gregorich	:	Modularisation and minor bugs
     18 *		Alan Cox	:	Added the watchdog ioctl() stuff
     19 *		Alan Cox	:	Fixed the reboot problem (as noted by
     20 *					Matt Crocker).
     21 *		Alan Cox	:	Added wdt= boot option
     22 *		Alan Cox	:	Cleaned up copy/user stuff
     23 *		Tim Hockin	:	Added insmod parameters, comment cleanup
     24 *					Parameterized timeout
     25 *		JP Nollmann	:	Added support for PCI wdt501p
     26 *		Alan Cox	:	Split ISA and PCI cards into two drivers
     27 *		Jeff Garzik	:	PCI cleanups
     28 *		Tigran Aivazian	:	Restructured wdtpci_init_one() to handle
     29 *					failures
     30 *		Joel Becker	:	Added WDIOC_GET/SETTIMEOUT
     31 *		Zwane Mwaikambo	:	Magic char closing, locking changes,
     32 *					cleanups
     33 *		Matt Domsch	:	nowayout module option
     34 */
     35
     36#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
     37
     38#include <linux/interrupt.h>
     39#include <linux/module.h>
     40#include <linux/moduleparam.h>
     41#include <linux/types.h>
     42#include <linux/miscdevice.h>
     43#include <linux/watchdog.h>
     44#include <linux/ioport.h>
     45#include <linux/delay.h>
     46#include <linux/notifier.h>
     47#include <linux/reboot.h>
     48#include <linux/fs.h>
     49#include <linux/pci.h>
     50#include <linux/io.h>
     51#include <linux/uaccess.h>
     52
     53
     54#define WDT_IS_PCI
     55#include "wd501p.h"
     56
     57/* We can only use 1 card due to the /dev/watchdog restriction */
     58static int dev_count;
     59
     60static unsigned long open_lock;
     61static DEFINE_SPINLOCK(wdtpci_lock);
     62static char expect_close;
     63
     64static resource_size_t io;
     65static int irq;
     66
     67/* Default timeout */
     68#define WD_TIMO 60			/* Default heartbeat = 60 seconds */
     69
     70static int heartbeat = WD_TIMO;
     71static int wd_heartbeat;
     72module_param(heartbeat, int, 0);
     73MODULE_PARM_DESC(heartbeat,
     74		"Watchdog heartbeat in seconds. (0<heartbeat<65536, default="
     75				__MODULE_STRING(WD_TIMO) ")");
     76
     77static bool nowayout = WATCHDOG_NOWAYOUT;
     78module_param(nowayout, bool, 0);
     79MODULE_PARM_DESC(nowayout,
     80		"Watchdog cannot be stopped once started (default="
     81				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
     82
     83/* Support for the Fan Tachometer on the PCI-WDT501 */
     84static int tachometer;
     85module_param(tachometer, int, 0);
     86MODULE_PARM_DESC(tachometer,
     87		"PCI-WDT501 Fan Tachometer support (0=disable, default=0)");
     88
     89static int type = 500;
     90module_param(type, int, 0);
     91MODULE_PARM_DESC(type,
     92		"PCI-WDT501 Card type (500 or 501 , default=500)");
     93
     94/*
     95 *	Programming support
     96 */
     97
     98static void wdtpci_ctr_mode(int ctr, int mode)
     99{
    100	ctr <<= 6;
    101	ctr |= 0x30;
    102	ctr |= (mode << 1);
    103	outb(ctr, WDT_CR);
    104	udelay(8);
    105}
    106
    107static void wdtpci_ctr_load(int ctr, int val)
    108{
    109	outb(val & 0xFF, WDT_COUNT0 + ctr);
    110	udelay(8);
    111	outb(val >> 8, WDT_COUNT0 + ctr);
    112	udelay(8);
    113}
    114
    115/**
    116 *	wdtpci_start:
    117 *
    118 *	Start the watchdog driver.
    119 */
    120
    121static int wdtpci_start(void)
    122{
    123	unsigned long flags;
    124
    125	spin_lock_irqsave(&wdtpci_lock, flags);
    126
    127	/*
    128	 * "pet" the watchdog, as Access says.
    129	 * This resets the clock outputs.
    130	 */
    131	inb(WDT_DC);			/* Disable watchdog */
    132	udelay(8);
    133	wdtpci_ctr_mode(2, 0);		/* Program CTR2 for Mode 0:
    134						Pulse on Terminal Count */
    135	outb(0, WDT_DC);		/* Enable watchdog */
    136	udelay(8);
    137	inb(WDT_DC);			/* Disable watchdog */
    138	udelay(8);
    139	outb(0, WDT_CLOCK);		/* 2.0833MHz clock */
    140	udelay(8);
    141	inb(WDT_BUZZER);		/* disable */
    142	udelay(8);
    143	inb(WDT_OPTONOTRST);		/* disable */
    144	udelay(8);
    145	inb(WDT_OPTORST);		/* disable */
    146	udelay(8);
    147	inb(WDT_PROGOUT);		/* disable */
    148	udelay(8);
    149	wdtpci_ctr_mode(0, 3);		/* Program CTR0 for Mode 3:
    150						Square Wave Generator */
    151	wdtpci_ctr_mode(1, 2);		/* Program CTR1 for Mode 2:
    152						Rate Generator */
    153	wdtpci_ctr_mode(2, 1);		/* Program CTR2 for Mode 1:
    154						Retriggerable One-Shot */
    155	wdtpci_ctr_load(0, 20833);	/* count at 100Hz */
    156	wdtpci_ctr_load(1, wd_heartbeat);/* Heartbeat */
    157	/* DO NOT LOAD CTR2 on PCI card! -- JPN */
    158	outb(0, WDT_DC);		/* Enable watchdog */
    159	udelay(8);
    160
    161	spin_unlock_irqrestore(&wdtpci_lock, flags);
    162	return 0;
    163}
    164
    165/**
    166 *	wdtpci_stop:
    167 *
    168 *	Stop the watchdog driver.
    169 */
    170
    171static int wdtpci_stop(void)
    172{
    173	unsigned long flags;
    174
    175	/* Turn the card off */
    176	spin_lock_irqsave(&wdtpci_lock, flags);
    177	inb(WDT_DC);			/* Disable watchdog */
    178	udelay(8);
    179	wdtpci_ctr_load(2, 0);		/* 0 length reset pulses now */
    180	spin_unlock_irqrestore(&wdtpci_lock, flags);
    181	return 0;
    182}
    183
    184/**
    185 *	wdtpci_ping:
    186 *
    187 *	Reload counter one with the watchdog heartbeat. We don't bother
    188 *	reloading the cascade counter.
    189 */
    190
    191static int wdtpci_ping(void)
    192{
    193	unsigned long flags;
    194
    195	spin_lock_irqsave(&wdtpci_lock, flags);
    196	/* Write a watchdog value */
    197	inb(WDT_DC);			/* Disable watchdog */
    198	udelay(8);
    199	wdtpci_ctr_mode(1, 2);		/* Re-Program CTR1 for Mode 2:
    200							Rate Generator */
    201	wdtpci_ctr_load(1, wd_heartbeat);/* Heartbeat */
    202	outb(0, WDT_DC);		/* Enable watchdog */
    203	udelay(8);
    204	spin_unlock_irqrestore(&wdtpci_lock, flags);
    205	return 0;
    206}
    207
    208/**
    209 *	wdtpci_set_heartbeat:
    210 *	@t:		the new heartbeat value that needs to be set.
    211 *
    212 *	Set a new heartbeat value for the watchdog device. If the heartbeat
    213 *	value is incorrect we keep the old value and return -EINVAL.
    214 *	If successful we return 0.
    215 */
    216static int wdtpci_set_heartbeat(int t)
    217{
    218	/* Arbitrary, can't find the card's limits */
    219	if (t < 1 || t > 65535)
    220		return -EINVAL;
    221
    222	heartbeat = t;
    223	wd_heartbeat = t * 100;
    224	return 0;
    225}
    226
    227/**
    228 *	wdtpci_get_status:
    229 *	@status:		the new status.
    230 *
    231 *	Extract the status information from a WDT watchdog device. There are
    232 *	several board variants so we have to know which bits are valid. Some
    233 *	bits default to one and some to zero in order to be maximally painful.
    234 *
    235 *	we then map the bits onto the status ioctl flags.
    236 */
    237
    238static int wdtpci_get_status(int *status)
    239{
    240	unsigned char new_status;
    241	unsigned long flags;
    242
    243	spin_lock_irqsave(&wdtpci_lock, flags);
    244	new_status = inb(WDT_SR);
    245	spin_unlock_irqrestore(&wdtpci_lock, flags);
    246
    247	*status = 0;
    248	if (new_status & WDC_SR_ISOI0)
    249		*status |= WDIOF_EXTERN1;
    250	if (new_status & WDC_SR_ISII1)
    251		*status |= WDIOF_EXTERN2;
    252	if (type == 501) {
    253		if (!(new_status & WDC_SR_TGOOD))
    254			*status |= WDIOF_OVERHEAT;
    255		if (!(new_status & WDC_SR_PSUOVER))
    256			*status |= WDIOF_POWEROVER;
    257		if (!(new_status & WDC_SR_PSUUNDR))
    258			*status |= WDIOF_POWERUNDER;
    259		if (tachometer) {
    260			if (!(new_status & WDC_SR_FANGOOD))
    261				*status |= WDIOF_FANFAULT;
    262		}
    263	}
    264	return 0;
    265}
    266
    267/**
    268 *	wdtpci_get_temperature:
    269 *
    270 *	Reports the temperature in degrees Fahrenheit. The API is in
    271 *	farenheit. It was designed by an imperial measurement luddite.
    272 */
    273
    274static int wdtpci_get_temperature(int *temperature)
    275{
    276	unsigned short c;
    277	unsigned long flags;
    278	spin_lock_irqsave(&wdtpci_lock, flags);
    279	c = inb(WDT_RT);
    280	udelay(8);
    281	spin_unlock_irqrestore(&wdtpci_lock, flags);
    282	*temperature = (c * 11 / 15) + 7;
    283	return 0;
    284}
    285
    286/**
    287 *	wdtpci_interrupt:
    288 *	@irq:		Interrupt number
    289 *	@dev_id:	Unused as we don't allow multiple devices.
    290 *
    291 *	Handle an interrupt from the board. These are raised when the status
    292 *	map changes in what the board considers an interesting way. That means
    293 *	a failure condition occurring.
    294 */
    295
    296static irqreturn_t wdtpci_interrupt(int irq, void *dev_id)
    297{
    298	/*
    299	 *	Read the status register see what is up and
    300	 *	then printk it.
    301	 */
    302	unsigned char status;
    303
    304	spin_lock(&wdtpci_lock);
    305
    306	status = inb(WDT_SR);
    307	udelay(8);
    308
    309	pr_crit("status %d\n", status);
    310
    311	if (type == 501) {
    312		if (!(status & WDC_SR_TGOOD)) {
    313			pr_crit("Overheat alarm (%d)\n", inb(WDT_RT));
    314			udelay(8);
    315		}
    316		if (!(status & WDC_SR_PSUOVER))
    317			pr_crit("PSU over voltage\n");
    318		if (!(status & WDC_SR_PSUUNDR))
    319			pr_crit("PSU under voltage\n");
    320		if (tachometer) {
    321			if (!(status & WDC_SR_FANGOOD))
    322				pr_crit("Possible fan fault\n");
    323		}
    324	}
    325	if (!(status & WDC_SR_WCCR)) {
    326#ifdef SOFTWARE_REBOOT
    327#ifdef ONLY_TESTING
    328		pr_crit("Would Reboot\n");
    329#else
    330		pr_crit("Initiating system reboot\n");
    331		emergency_restart();
    332#endif
    333#else
    334		pr_crit("Reset in 5ms\n");
    335#endif
    336	}
    337	spin_unlock(&wdtpci_lock);
    338	return IRQ_HANDLED;
    339}
    340
    341
    342/**
    343 *	wdtpci_write:
    344 *	@file: file handle to the watchdog
    345 *	@buf: buffer to write (unused as data does not matter here
    346 *	@count: count of bytes
    347 *	@ppos: pointer to the position to write. No seeks allowed
    348 *
    349 *	A write to a watchdog device is defined as a keepalive signal. Any
    350 *	write of data will do, as we we don't define content meaning.
    351 */
    352
    353static ssize_t wdtpci_write(struct file *file, const char __user *buf,
    354						size_t count, loff_t *ppos)
    355{
    356	if (count) {
    357		if (!nowayout) {
    358			size_t i;
    359
    360			/* In case it was set long ago */
    361			expect_close = 0;
    362
    363			for (i = 0; i != count; i++) {
    364				char c;
    365				if (get_user(c, buf + i))
    366					return -EFAULT;
    367				if (c == 'V')
    368					expect_close = 42;
    369			}
    370		}
    371		wdtpci_ping();
    372	}
    373	return count;
    374}
    375
    376/**
    377 *	wdtpci_ioctl:
    378 *	@file: file handle to the device
    379 *	@cmd: watchdog command
    380 *	@arg: argument pointer
    381 *
    382 *	The watchdog API defines a common set of functions for all watchdogs
    383 *	according to their available features. We only actually usefully support
    384 *	querying capabilities and current status.
    385 */
    386
    387static long wdtpci_ioctl(struct file *file, unsigned int cmd,
    388							unsigned long arg)
    389{
    390	void __user *argp = (void __user *)arg;
    391	int __user *p = argp;
    392	int new_heartbeat;
    393	int status;
    394
    395	struct watchdog_info ident = {
    396		.options =		WDIOF_SETTIMEOUT|
    397					WDIOF_MAGICCLOSE|
    398					WDIOF_KEEPALIVEPING,
    399		.firmware_version =	1,
    400		.identity =		"PCI-WDT500/501",
    401	};
    402
    403	/* Add options according to the card we have */
    404	ident.options |= (WDIOF_EXTERN1|WDIOF_EXTERN2);
    405	if (type == 501) {
    406		ident.options |= (WDIOF_OVERHEAT|WDIOF_POWERUNDER|
    407							WDIOF_POWEROVER);
    408		if (tachometer)
    409			ident.options |= WDIOF_FANFAULT;
    410	}
    411
    412	switch (cmd) {
    413	case WDIOC_GETSUPPORT:
    414		return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
    415	case WDIOC_GETSTATUS:
    416		wdtpci_get_status(&status);
    417		return put_user(status, p);
    418	case WDIOC_GETBOOTSTATUS:
    419		return put_user(0, p);
    420	case WDIOC_KEEPALIVE:
    421		wdtpci_ping();
    422		return 0;
    423	case WDIOC_SETTIMEOUT:
    424		if (get_user(new_heartbeat, p))
    425			return -EFAULT;
    426		if (wdtpci_set_heartbeat(new_heartbeat))
    427			return -EINVAL;
    428		wdtpci_ping();
    429		fallthrough;
    430	case WDIOC_GETTIMEOUT:
    431		return put_user(heartbeat, p);
    432	default:
    433		return -ENOTTY;
    434	}
    435}
    436
    437/**
    438 *	wdtpci_open:
    439 *	@inode: inode of device
    440 *	@file: file handle to device
    441 *
    442 *	The watchdog device has been opened. The watchdog device is single
    443 *	open and on opening we load the counters. Counter zero is a 100Hz
    444 *	cascade, into counter 1 which downcounts to reboot. When the counter
    445 *	triggers counter 2 downcounts the length of the reset pulse which
    446 *	set set to be as long as possible.
    447 */
    448
    449static int wdtpci_open(struct inode *inode, struct file *file)
    450{
    451	if (test_and_set_bit(0, &open_lock))
    452		return -EBUSY;
    453
    454	if (nowayout)
    455		__module_get(THIS_MODULE);
    456	/*
    457	 *	Activate
    458	 */
    459	wdtpci_start();
    460	return stream_open(inode, file);
    461}
    462
    463/**
    464 *	wdtpci_release:
    465 *	@inode: inode to board
    466 *	@file: file handle to board
    467 *
    468 *	The watchdog has a configurable API. There is a religious dispute
    469 *	between people who want their watchdog to be able to shut down and
    470 *	those who want to be sure if the watchdog manager dies the machine
    471 *	reboots. In the former case we disable the counters, in the latter
    472 *	case you have to open it again very soon.
    473 */
    474
    475static int wdtpci_release(struct inode *inode, struct file *file)
    476{
    477	if (expect_close == 42) {
    478		wdtpci_stop();
    479	} else {
    480		pr_crit("Unexpected close, not stopping timer!\n");
    481		wdtpci_ping();
    482	}
    483	expect_close = 0;
    484	clear_bit(0, &open_lock);
    485	return 0;
    486}
    487
    488/**
    489 *	wdtpci_temp_read:
    490 *	@file: file handle to the watchdog board
    491 *	@buf: buffer to write 1 byte into
    492 *	@count: length of buffer
    493 *	@ptr: offset (no seek allowed)
    494 *
    495 *	Read reports the temperature in degrees Fahrenheit. The API is in
    496 *	fahrenheit. It was designed by an imperial measurement luddite.
    497 */
    498
    499static ssize_t wdtpci_temp_read(struct file *file, char __user *buf,
    500						size_t count, loff_t *ptr)
    501{
    502	int temperature;
    503
    504	if (wdtpci_get_temperature(&temperature))
    505		return -EFAULT;
    506
    507	if (copy_to_user(buf, &temperature, 1))
    508		return -EFAULT;
    509
    510	return 1;
    511}
    512
    513/**
    514 *	wdtpci_temp_open:
    515 *	@inode: inode of device
    516 *	@file: file handle to device
    517 *
    518 *	The temperature device has been opened.
    519 */
    520
    521static int wdtpci_temp_open(struct inode *inode, struct file *file)
    522{
    523	return stream_open(inode, file);
    524}
    525
    526/**
    527 *	wdtpci_temp_release:
    528 *	@inode: inode to board
    529 *	@file: file handle to board
    530 *
    531 *	The temperature device has been closed.
    532 */
    533
    534static int wdtpci_temp_release(struct inode *inode, struct file *file)
    535{
    536	return 0;
    537}
    538
    539/**
    540 *	wdtpci_notify_sys:
    541 *	@this: our notifier block
    542 *	@code: the event being reported
    543 *	@unused: unused
    544 *
    545 *	Our notifier is called on system shutdowns. We want to turn the card
    546 *	off at reboot otherwise the machine will reboot again during memory
    547 *	test or worse yet during the following fsck. This would suck, in fact
    548 *	trust me - if it happens it does suck.
    549 */
    550
    551static int wdtpci_notify_sys(struct notifier_block *this, unsigned long code,
    552							void *unused)
    553{
    554	if (code == SYS_DOWN || code == SYS_HALT)
    555		wdtpci_stop();
    556	return NOTIFY_DONE;
    557}
    558
    559/*
    560 *	Kernel Interfaces
    561 */
    562
    563
    564static const struct file_operations wdtpci_fops = {
    565	.owner		= THIS_MODULE,
    566	.llseek		= no_llseek,
    567	.write		= wdtpci_write,
    568	.unlocked_ioctl	= wdtpci_ioctl,
    569	.compat_ioctl	= compat_ptr_ioctl,
    570	.open		= wdtpci_open,
    571	.release	= wdtpci_release,
    572};
    573
    574static struct miscdevice wdtpci_miscdev = {
    575	.minor	= WATCHDOG_MINOR,
    576	.name	= "watchdog",
    577	.fops	= &wdtpci_fops,
    578};
    579
    580static const struct file_operations wdtpci_temp_fops = {
    581	.owner		= THIS_MODULE,
    582	.llseek		= no_llseek,
    583	.read		= wdtpci_temp_read,
    584	.open		= wdtpci_temp_open,
    585	.release	= wdtpci_temp_release,
    586};
    587
    588static struct miscdevice temp_miscdev = {
    589	.minor	= TEMP_MINOR,
    590	.name	= "temperature",
    591	.fops	= &wdtpci_temp_fops,
    592};
    593
    594/*
    595 *	The WDT card needs to learn about soft shutdowns in order to
    596 *	turn the timebomb registers off.
    597 */
    598
    599static struct notifier_block wdtpci_notifier = {
    600	.notifier_call = wdtpci_notify_sys,
    601};
    602
    603
    604static int wdtpci_init_one(struct pci_dev *dev,
    605					const struct pci_device_id *ent)
    606{
    607	int ret = -EIO;
    608
    609	dev_count++;
    610	if (dev_count > 1) {
    611		pr_err("This driver only supports one device\n");
    612		return -ENODEV;
    613	}
    614
    615	if (type != 500 && type != 501) {
    616		pr_err("unknown card type '%d'\n", type);
    617		return -ENODEV;
    618	}
    619
    620	if (pci_enable_device(dev)) {
    621		pr_err("Not possible to enable PCI Device\n");
    622		return -ENODEV;
    623	}
    624
    625	if (pci_resource_start(dev, 2) == 0x0000) {
    626		pr_err("No I/O-Address for card detected\n");
    627		ret = -ENODEV;
    628		goto out_pci;
    629	}
    630
    631	if (pci_request_region(dev, 2, "wdt_pci")) {
    632		pr_err("I/O address 0x%llx already in use\n",
    633		       (unsigned long long)pci_resource_start(dev, 2));
    634		goto out_pci;
    635	}
    636
    637	irq = dev->irq;
    638	io = pci_resource_start(dev, 2);
    639
    640	if (request_irq(irq, wdtpci_interrupt, IRQF_SHARED,
    641			 "wdt_pci", &wdtpci_miscdev)) {
    642		pr_err("IRQ %d is not free\n", irq);
    643		goto out_reg;
    644	}
    645
    646	pr_info("PCI-WDT500/501 (PCI-WDG-CSM) driver 0.10 at 0x%llx (Interrupt %d)\n",
    647		(unsigned long long)io, irq);
    648
    649	/* Check that the heartbeat value is within its range;
    650	   if not reset to the default */
    651	if (wdtpci_set_heartbeat(heartbeat)) {
    652		wdtpci_set_heartbeat(WD_TIMO);
    653		pr_info("heartbeat value must be 0 < heartbeat < 65536, using %d\n",
    654			WD_TIMO);
    655	}
    656
    657	ret = register_reboot_notifier(&wdtpci_notifier);
    658	if (ret) {
    659		pr_err("cannot register reboot notifier (err=%d)\n", ret);
    660		goto out_irq;
    661	}
    662
    663	if (type == 501) {
    664		ret = misc_register(&temp_miscdev);
    665		if (ret) {
    666			pr_err("cannot register miscdev on minor=%d (err=%d)\n",
    667			       TEMP_MINOR, ret);
    668			goto out_rbt;
    669		}
    670	}
    671
    672	ret = misc_register(&wdtpci_miscdev);
    673	if (ret) {
    674		pr_err("cannot register miscdev on minor=%d (err=%d)\n",
    675		       WATCHDOG_MINOR, ret);
    676		goto out_misc;
    677	}
    678
    679	pr_info("initialized. heartbeat=%d sec (nowayout=%d)\n",
    680		heartbeat, nowayout);
    681	if (type == 501)
    682		pr_info("Fan Tachometer is %s\n",
    683			tachometer ? "Enabled" : "Disabled");
    684
    685	ret = 0;
    686out:
    687	return ret;
    688
    689out_misc:
    690	if (type == 501)
    691		misc_deregister(&temp_miscdev);
    692out_rbt:
    693	unregister_reboot_notifier(&wdtpci_notifier);
    694out_irq:
    695	free_irq(irq, &wdtpci_miscdev);
    696out_reg:
    697	pci_release_region(dev, 2);
    698out_pci:
    699	pci_disable_device(dev);
    700	goto out;
    701}
    702
    703
    704static void wdtpci_remove_one(struct pci_dev *pdev)
    705{
    706	/* here we assume only one device will ever have
    707	 * been picked up and registered by probe function */
    708	misc_deregister(&wdtpci_miscdev);
    709	if (type == 501)
    710		misc_deregister(&temp_miscdev);
    711	unregister_reboot_notifier(&wdtpci_notifier);
    712	free_irq(irq, &wdtpci_miscdev);
    713	pci_release_region(pdev, 2);
    714	pci_disable_device(pdev);
    715	dev_count--;
    716}
    717
    718
    719static const struct pci_device_id wdtpci_pci_tbl[] = {
    720	{
    721		.vendor	   = PCI_VENDOR_ID_ACCESSIO,
    722		.device	   = PCI_DEVICE_ID_ACCESSIO_WDG_CSM,
    723		.subvendor = PCI_ANY_ID,
    724		.subdevice = PCI_ANY_ID,
    725	},
    726	{ 0, }, /* terminate list */
    727};
    728MODULE_DEVICE_TABLE(pci, wdtpci_pci_tbl);
    729
    730
    731static struct pci_driver wdtpci_driver = {
    732	.name		= "wdt_pci",
    733	.id_table	= wdtpci_pci_tbl,
    734	.probe		= wdtpci_init_one,
    735	.remove		= wdtpci_remove_one,
    736};
    737
    738module_pci_driver(wdtpci_driver);
    739
    740MODULE_AUTHOR("JP Nollmann, Alan Cox");
    741MODULE_DESCRIPTION("Driver for the ICS PCI-WDT500/501 watchdog cards");
    742MODULE_LICENSE("GPL");