2005-08-17 11:07:44 +04:00
/*
2005-09-02 00:34:53 +04:00
* i6300esb : Watchdog timer driver for Intel 6300 ESB chipset
2005-08-17 11:07:44 +04:00
*
* ( c ) Copyright 2004 Google Inc .
2007-10-20 01:21:04 +04:00
* ( c ) Copyright 2005 David Härdeman < david @ 2 gen . com >
2005-08-17 11:07:44 +04:00
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version
* 2 of the License , or ( at your option ) any later version .
*
2008-08-07 00:19:41 +04:00
* based on i810 - tco . c which is in turn based on softdog . c
2005-08-17 11:07:44 +04:00
*
2008-08-07 00:19:41 +04:00
* The timer is implemented in the following I / O controller hubs :
* ( See the intel documentation on http : //developer.intel.com.)
2009-03-19 22:02:44 +03:00
* 6300 ESB chip : document number 300641 - 004
2005-08-17 11:07:44 +04:00
*
* 2004 YYZZ Ross Biro
* Initial version 0.01
* 2004 YYZZ Ross Biro
2008-08-07 00:19:41 +04:00
* Version 0.02
2007-10-20 01:21:04 +04:00
* 20050210 David Härdeman < david @ 2 gen . com >
2008-08-07 00:19:41 +04:00
* Ported driver to kernel 2.6
2005-08-17 11:07:44 +04:00
*/
/*
* Includes , defines , variables , module parameters , . . .
*/
# include <linux/module.h>
# include <linux/types.h>
# include <linux/kernel.h>
# include <linux/fs.h>
# include <linux/mm.h>
# include <linux/miscdevice.h>
# include <linux/watchdog.h>
2009-03-19 22:02:44 +03:00
# include <linux/platform_device.h>
2005-08-17 11:07:44 +04:00
# include <linux/init.h>
# include <linux/pci.h>
# include <linux/ioport.h>
2008-05-19 17:05:57 +04:00
# include <linux/uaccess.h>
# include <linux/io.h>
2005-08-17 11:07:44 +04:00
/* Module and version information */
2009-03-19 22:02:44 +03:00
# define ESB_VERSION "0.04"
2005-08-17 11:07:44 +04:00
# define ESB_MODULE_NAME "i6300ESB timer"
# define ESB_DRIVER_NAME ESB_MODULE_NAME ", v" ESB_VERSION
# define PFX ESB_MODULE_NAME ": "
2005-09-02 00:34:53 +04:00
/* PCI configuration registers */
# define ESB_CONFIG_REG 0x60 /* Config register */
# define ESB_LOCK_REG 0x68 /* WDT lock register */
/* Memory mapped registers */
2009-03-25 22:20:10 +03:00
# define ESB_TIMER1_REG (BASEADDR + 0x00) /* Timer1 value after each reset */
# define ESB_TIMER2_REG (BASEADDR + 0x04) /* Timer2 value after each reset */
# define ESB_GINTSR_REG (BASEADDR + 0x08) /* General Interrupt Status Register */
# define ESB_RELOAD_REG (BASEADDR + 0x0c) /* Reload register */
2005-09-02 00:34:53 +04:00
/* Lock register bits */
2008-05-19 17:05:57 +04:00
# define ESB_WDT_FUNC (0x01 << 2) /* Watchdog functionality */
# define ESB_WDT_ENABLE (0x01 << 1) /* Enable WDT */
# define ESB_WDT_LOCK (0x01 << 0) /* Lock (nowayout) */
2005-09-02 00:34:53 +04:00
/* Config register bits */
2008-05-19 17:05:57 +04:00
# define ESB_WDT_REBOOT (0x01 << 5) /* Enable reboot on timeout */
# define ESB_WDT_FREQ (0x01 << 2) /* Decrement frequency */
# define ESB_WDT_INTTYPE (0x11 << 0) /* Interrupt type on timer1 timeout */
2005-09-02 00:34:53 +04:00
/* Reload register bits */
2009-03-25 22:14:45 +03:00
# define ESB_WDT_TIMEOUT (0x01 << 9) /* Watchdog timed out */
2008-05-19 17:05:57 +04:00
# define ESB_WDT_RELOAD (0x01 << 8) /* prevent timeout */
2005-09-02 00:34:53 +04:00
/* Magic constants */
# define ESB_UNLOCK1 0x80 /* Step 1 to unlock reset registers */
# define ESB_UNLOCK2 0x86 /* Step 2 to unlock reset registers */
2005-08-17 11:07:44 +04:00
/* internal variables */
static void __iomem * BASEADDR ;
2007-11-02 02:27:08 +03:00
static DEFINE_SPINLOCK ( esb_lock ) ; /* Guards the hardware */
2005-08-17 11:07:44 +04:00
static unsigned long timer_alive ;
static struct pci_dev * esb_pci ;
static unsigned short triggered ; /* The status of the watchdog upon boot */
static char esb_expect_close ;
2009-03-19 22:02:44 +03:00
static struct platform_device * esb_platform_device ;
2005-08-17 11:07:44 +04:00
/* module parameters */
2008-05-19 17:05:57 +04:00
/* 30 sec default heartbeat (1 < heartbeat < 2*1023) */
# define WATCHDOG_HEARTBEAT 30
2005-08-17 11:07:44 +04:00
static int heartbeat = WATCHDOG_HEARTBEAT ; /* in seconds */
module_param ( heartbeat , int , 0 ) ;
2008-05-19 17:05:57 +04:00
MODULE_PARM_DESC ( heartbeat ,
" Watchdog heartbeat in seconds. (1<heartbeat<2046, default= "
__MODULE_STRING ( WATCHDOG_HEARTBEAT ) " ) " ) ;
2005-08-17 11:07:44 +04:00
2005-08-21 15:02:41 +04:00
static int nowayout = WATCHDOG_NOWAYOUT ;
2005-08-17 11:07:44 +04:00
module_param ( nowayout , int , 0 ) ;
2008-05-19 17:05:57 +04:00
MODULE_PARM_DESC ( nowayout ,
" Watchdog cannot be stopped once started (default= "
__MODULE_STRING ( WATCHDOG_NOWAYOUT ) " ) " ) ;
2005-08-17 11:07:44 +04:00
/*
* Some i6300ESB specific functions
*/
/*
* Prepare for reloading the timer by unlocking the proper registers .
* This is performed by first writing 0x80 followed by 0x86 to the
* reload register . After this the appropriate registers can be written
* to once before they need to be unlocked again .
*/
2008-08-07 00:19:41 +04:00
static inline void esb_unlock_registers ( void )
{
2008-05-19 17:05:57 +04:00
writeb ( ESB_UNLOCK1 , ESB_RELOAD_REG ) ;
writeb ( ESB_UNLOCK2 , ESB_RELOAD_REG ) ;
2005-08-17 11:07:44 +04:00
}
2009-03-23 16:50:38 +03:00
static int esb_timer_start ( void )
2005-08-17 11:07:44 +04:00
{
u8 val ;
2009-03-23 16:50:38 +03:00
spin_lock ( & esb_lock ) ;
esb_unlock_registers ( ) ;
writew ( ESB_WDT_RELOAD , ESB_RELOAD_REG ) ;
2005-08-17 11:07:44 +04:00
/* Enable or Enable + Lock? */
2009-03-25 22:16:28 +03:00
val = ESB_WDT_ENABLE | ( nowayout ? ESB_WDT_LOCK : 0x00 ) ;
2008-05-19 17:05:57 +04:00
pci_write_config_byte ( esb_pci , ESB_LOCK_REG , val ) ;
2009-03-23 16:50:38 +03:00
spin_unlock ( & esb_lock ) ;
return 0 ;
2005-08-17 11:07:44 +04:00
}
static int esb_timer_stop ( void )
{
u8 val ;
spin_lock ( & esb_lock ) ;
/* First, reset timers as suggested by the docs */
esb_unlock_registers ( ) ;
2005-08-17 11:11:46 +04:00
writew ( ESB_WDT_RELOAD , ESB_RELOAD_REG ) ;
2005-08-17 11:07:44 +04:00
/* Then disable the WDT */
pci_write_config_byte ( esb_pci , ESB_LOCK_REG , 0x0 ) ;
pci_read_config_byte ( esb_pci , ESB_LOCK_REG , & val ) ;
spin_unlock ( & esb_lock ) ;
/* Returns 0 if the timer was disabled, non-zero otherwise */
2009-03-25 22:16:28 +03:00
return val & ESB_WDT_ENABLE ;
2005-08-17 11:07:44 +04:00
}
static void esb_timer_keepalive ( void )
{
spin_lock ( & esb_lock ) ;
esb_unlock_registers ( ) ;
2005-08-17 11:11:46 +04:00
writew ( ESB_WDT_RELOAD , ESB_RELOAD_REG ) ;
2008-05-19 17:05:57 +04:00
/* FIXME: Do we need to flush anything here? */
2005-08-17 11:07:44 +04:00
spin_unlock ( & esb_lock ) ;
}
static int esb_timer_set_heartbeat ( int time )
{
u32 val ;
if ( time < 0x1 | | time > ( 2 * 0x03ff ) )
return - EINVAL ;
spin_lock ( & esb_lock ) ;
/* We shift by 9, so if we are passed a value of 1 sec,
* val will be 1 < < 9 = 512 , then write that to two
* timers = > 2 * 512 = 1024 ( which is decremented at 1 KHz )
*/
val = time < < 9 ;
/* Write timer 1 */
esb_unlock_registers ( ) ;
writel ( val , ESB_TIMER1_REG ) ;
/* Write timer 2 */
esb_unlock_registers ( ) ;
2008-08-07 00:19:41 +04:00
writel ( val , ESB_TIMER2_REG ) ;
2005-08-17 11:07:44 +04:00
2008-05-19 17:05:57 +04:00
/* Reload */
2005-08-17 11:07:44 +04:00
esb_unlock_registers ( ) ;
2005-08-17 11:11:46 +04:00
writew ( ESB_WDT_RELOAD , ESB_RELOAD_REG ) ;
2005-08-17 11:07:44 +04:00
/* FIXME: Do we need to flush everything out? */
/* Done */
heartbeat = time ;
spin_unlock ( & esb_lock ) ;
return 0 ;
}
/*
2008-08-07 00:19:41 +04:00
* / dev / watchdog handling
2005-08-17 11:07:44 +04:00
*/
2008-05-19 17:05:57 +04:00
static int esb_open ( struct inode * inode , struct file * file )
2005-08-17 11:07:44 +04:00
{
2008-05-19 17:05:57 +04:00
/* /dev/watchdog can only be opened once */
if ( test_and_set_bit ( 0 , & timer_alive ) )
return - EBUSY ;
2005-08-17 11:07:44 +04:00
2008-05-19 17:05:57 +04:00
/* Reload and activate timer */
esb_timer_start ( ) ;
2005-08-17 11:07:44 +04:00
return nonseekable_open ( inode , file ) ;
}
2008-05-19 17:05:57 +04:00
static int esb_release ( struct inode * inode , struct file * file )
2005-08-17 11:07:44 +04:00
{
2008-05-19 17:05:57 +04:00
/* Shut off the timer. */
if ( esb_expect_close = = 42 )
esb_timer_stop ( ) ;
else {
printk ( KERN_CRIT PFX
" Unexpected close, not stopping watchdog! \n " ) ;
esb_timer_keepalive ( ) ;
}
clear_bit ( 0 , & timer_alive ) ;
esb_expect_close = 0 ;
return 0 ;
2005-08-17 11:07:44 +04:00
}
2008-05-19 17:05:57 +04:00
static ssize_t esb_write ( struct file * file , const char __user * data ,
size_t len , loff_t * ppos )
2005-08-17 11:07:44 +04:00
{
/* See if we got the magic character 'V' and reload the timer */
2008-05-19 17:05:57 +04:00
if ( len ) {
2005-08-17 11:07:44 +04:00
if ( ! nowayout ) {
size_t i ;
/* note: just in case someone wrote the magic character
* five months ago . . . */
esb_expect_close = 0 ;
2009-03-18 11:35:09 +03:00
/* scan to see whether or not we got the
* magic character */
2005-08-17 11:07:44 +04:00
for ( i = 0 ; i ! = len ; i + + ) {
char c ;
2008-08-07 00:19:41 +04:00
if ( get_user ( c , data + i ) )
2005-08-17 11:07:44 +04:00
return - EFAULT ;
if ( c = = ' V ' )
esb_expect_close = 42 ;
}
}
/* someone wrote to us, we should reload the timer */
2008-05-19 17:05:57 +04:00
esb_timer_keepalive ( ) ;
2005-08-17 11:07:44 +04:00
}
return len ;
}
2008-05-19 17:05:57 +04:00
static long esb_ioctl ( struct file * file , unsigned int cmd , unsigned long arg )
2005-08-17 11:07:44 +04:00
{
int new_options , retval = - EINVAL ;
int new_heartbeat ;
void __user * argp = ( void __user * ) arg ;
int __user * p = argp ;
static struct watchdog_info ident = {
2008-08-07 00:19:41 +04:00
. options = WDIOF_SETTIMEOUT |
2005-08-17 11:07:44 +04:00
WDIOF_KEEPALIVEPING |
WDIOF_MAGICCLOSE ,
2008-08-07 00:19:41 +04:00
. firmware_version = 0 ,
. identity = ESB_MODULE_NAME ,
2005-08-17 11:07:44 +04:00
} ;
switch ( cmd ) {
2008-05-19 17:05:57 +04:00
case WDIOC_GETSUPPORT :
return copy_to_user ( argp , & ident ,
sizeof ( ident ) ) ? - EFAULT : 0 ;
2005-08-17 11:07:44 +04:00
2008-05-19 17:05:57 +04:00
case WDIOC_GETSTATUS :
2009-03-25 22:14:45 +03:00
return put_user ( 0 , p ) ;
2005-08-17 11:07:44 +04:00
2008-05-19 17:05:57 +04:00
case WDIOC_GETBOOTSTATUS :
return put_user ( triggered , p ) ;
2005-08-17 11:07:44 +04:00
2008-05-19 17:05:57 +04:00
case WDIOC_SETOPTIONS :
{
if ( get_user ( new_options , p ) )
return - EFAULT ;
2005-08-17 11:07:44 +04:00
2008-05-19 17:05:57 +04:00
if ( new_options & WDIOS_DISABLECARD ) {
esb_timer_stop ( ) ;
retval = 0 ;
}
2005-08-17 11:07:44 +04:00
2008-05-19 17:05:57 +04:00
if ( new_options & WDIOS_ENABLECARD ) {
esb_timer_start ( ) ;
retval = 0 ;
}
return retval ;
}
2008-07-18 15:41:17 +04:00
case WDIOC_KEEPALIVE :
esb_timer_keepalive ( ) ;
return 0 ;
2008-05-19 17:05:57 +04:00
case WDIOC_SETTIMEOUT :
{
if ( get_user ( new_heartbeat , p ) )
return - EFAULT ;
if ( esb_timer_set_heartbeat ( new_heartbeat ) )
return - EINVAL ;
esb_timer_keepalive ( ) ;
/* Fall */
}
case WDIOC_GETTIMEOUT :
return put_user ( heartbeat , p ) ;
default :
return - ENOTTY ;
}
2005-08-17 11:07:44 +04:00
}
/*
* Kernel Interfaces
*/
2006-07-03 11:24:21 +04:00
static const struct file_operations esb_fops = {
2008-05-19 17:05:57 +04:00
. owner = THIS_MODULE ,
. llseek = no_llseek ,
. write = esb_write ,
. unlocked_ioctl = esb_ioctl ,
. open = esb_open ,
. release = esb_release ,
2005-08-17 11:07:44 +04:00
} ;
static struct miscdevice esb_miscdev = {
2008-05-19 17:05:57 +04:00
. minor = WATCHDOG_MINOR ,
. name = " watchdog " ,
. fops = & esb_fops ,
2005-08-17 11:07:44 +04:00
} ;
/*
* Data for PCI driver interface
*
* This data only exists for exporting the supported
* PCI ids via MODULE_DEVICE_TABLE . We do not actually
* register a pci_driver , because someone else might one day
* want to register another driver on the same PCI id .
*/
static struct pci_device_id esb_pci_tbl [ ] = {
2008-05-19 17:05:57 +04:00
{ PCI_DEVICE ( PCI_VENDOR_ID_INTEL , PCI_DEVICE_ID_INTEL_ESB_9 ) , } ,
{ 0 , } , /* End of list */
2005-08-17 11:07:44 +04:00
} ;
2008-05-19 17:05:57 +04:00
MODULE_DEVICE_TABLE ( pci , esb_pci_tbl ) ;
2005-08-17 11:07:44 +04:00
/*
* Init & exit routines
*/
2009-03-19 22:02:44 +03:00
static unsigned char __devinit esb_getdevice ( void )
2005-08-17 11:07:44 +04:00
{
2008-05-19 17:05:57 +04:00
/*
* Find the PCI device
*/
2005-08-17 11:07:44 +04:00
2008-05-19 17:05:57 +04:00
esb_pci = pci_get_device ( PCI_VENDOR_ID_INTEL ,
PCI_DEVICE_ID_INTEL_ESB_9 , NULL ) ;
2005-08-17 11:07:44 +04:00
2009-03-25 22:16:28 +03:00
if ( ! esb_pci )
return 0 ;
2005-08-17 11:07:44 +04:00
2009-03-25 22:16:28 +03:00
if ( pci_enable_device ( esb_pci ) ) {
printk ( KERN_ERR PFX " failed to enable device \n " ) ;
goto err_devput ;
}
2005-08-17 11:07:44 +04:00
2009-03-25 22:16:28 +03:00
if ( pci_request_region ( esb_pci , 0 , ESB_MODULE_NAME ) ) {
printk ( KERN_ERR PFX " failed to request region \n " ) ;
goto err_disable ;
}
2005-08-17 11:07:44 +04:00
2009-03-25 22:16:28 +03:00
BASEADDR = pci_ioremap_bar ( esb_pci , 0 ) ;
if ( BASEADDR = = NULL ) {
/* Something's wrong here, BASEADDR has to be set */
printk ( KERN_ERR PFX " failed to get BASEADDR \n " ) ;
goto err_release ;
}
/* Done */
return 1 ;
2005-08-17 11:07:44 +04:00
err_release :
2009-03-25 22:16:28 +03:00
pci_release_region ( esb_pci , 0 ) ;
2005-08-17 11:07:44 +04:00
err_disable :
2009-03-25 22:16:28 +03:00
pci_disable_device ( esb_pci ) ;
2005-08-21 15:02:41 +04:00
err_devput :
2009-03-25 22:16:28 +03:00
pci_dev_put ( esb_pci ) ;
2005-08-17 11:07:44 +04:00
return 0 ;
}
2009-03-25 22:16:28 +03:00
static void __devinit esb_initdevice ( void )
{
u8 val1 ;
u16 val2 ;
/*
* Config register :
* Bit 5 : 0 = Enable WDT_OUTPUT
* Bit 2 : 0 = set the timer frequency to the PCI clock
* divided by 2 ^ 15 ( approx 1 KHz ) .
* Bits 1 : 0 : 11 = WDT_INT_TYPE Disabled .
* The watchdog has two timers , it can be setup so that the
* expiry of timer1 results in an interrupt and the expiry of
* timer2 results in a reboot . We set it to not generate
* any interrupts as there is not much we can do with it
* right now .
*/
pci_write_config_word ( esb_pci , ESB_CONFIG_REG , 0x0003 ) ;
/* Check that the WDT isn't already locked */
pci_read_config_byte ( esb_pci , ESB_LOCK_REG , & val1 ) ;
if ( val1 & ESB_WDT_LOCK )
printk ( KERN_WARNING PFX " nowayout already set \n " ) ;
/* Set the timer to watchdog mode and disable it for now */
pci_write_config_byte ( esb_pci , ESB_LOCK_REG , 0x00 ) ;
/* Check if the watchdog was previously triggered */
esb_unlock_registers ( ) ;
val2 = readw ( ESB_RELOAD_REG ) ;
if ( val2 & ESB_WDT_TIMEOUT )
triggered = WDIOF_CARDRESET ;
/* Reset WDT_TIMEOUT flag and timers */
esb_unlock_registers ( ) ;
writew ( ( ESB_WDT_TIMEOUT | ESB_WDT_RELOAD ) , ESB_RELOAD_REG ) ;
/* And set the correct timeout value */
esb_timer_set_heartbeat ( heartbeat ) ;
}
2009-03-19 22:02:44 +03:00
static int __devinit esb_probe ( struct platform_device * dev )
2005-08-17 11:07:44 +04:00
{
2008-05-19 17:05:57 +04:00
int ret ;
/* Check whether or not the hardware watchdog is there */
if ( ! esb_getdevice ( ) | | esb_pci = = NULL )
return - ENODEV ;
/* Check that the heartbeat value is within it's range;
if not reset to the default */
2009-03-25 22:16:28 +03:00
if ( heartbeat < 0x1 | | heartbeat > 2 * 0x03ff ) {
heartbeat = WATCHDOG_HEARTBEAT ;
2008-05-19 17:05:57 +04:00
printk ( KERN_INFO PFX
" heartbeat value must be 1<heartbeat<2046, using %d \n " ,
heartbeat ) ;
}
2005-08-17 11:07:44 +04:00
2009-03-25 22:16:28 +03:00
/* Initialize the watchdog and make sure it does not run */
esb_initdevice ( ) ;
/* Register the watchdog so that userspace has access to it */
2008-05-19 17:05:57 +04:00
ret = misc_register ( & esb_miscdev ) ;
if ( ret ! = 0 ) {
printk ( KERN_ERR PFX
" cannot register miscdev on minor=%d (err=%d) \n " ,
WATCHDOG_MINOR , ret ) ;
2009-03-19 22:02:44 +03:00
goto err_unmap ;
2008-05-19 17:05:57 +04:00
}
printk ( KERN_INFO PFX
" initialized (0x%p). heartbeat=%d sec (nowayout=%d) \n " ,
BASEADDR , heartbeat , nowayout ) ;
return 0 ;
2005-08-17 11:07:44 +04:00
err_unmap :
iounmap ( BASEADDR ) ;
pci_release_region ( esb_pci , 0 ) ;
pci_disable_device ( esb_pci ) ;
2005-08-17 11:09:13 +04:00
pci_dev_put ( esb_pci ) ;
2008-05-19 17:05:57 +04:00
return ret ;
2005-08-17 11:07:44 +04:00
}
2009-03-19 22:02:44 +03:00
static int __devexit esb_remove ( struct platform_device * dev )
2005-08-17 11:07:44 +04:00
{
/* Stop the timer before we leave */
if ( ! nowayout )
2008-05-19 17:05:57 +04:00
esb_timer_stop ( ) ;
2005-08-17 11:07:44 +04:00
/* Deregister */
misc_deregister ( & esb_miscdev ) ;
iounmap ( BASEADDR ) ;
pci_release_region ( esb_pci , 0 ) ;
pci_disable_device ( esb_pci ) ;
2005-08-17 11:09:13 +04:00
pci_dev_put ( esb_pci ) ;
2009-03-19 22:02:44 +03:00
return 0 ;
}
static void esb_shutdown ( struct platform_device * dev )
{
esb_timer_stop ( ) ;
}
static struct platform_driver esb_platform_driver = {
. probe = esb_probe ,
. remove = __devexit_p ( esb_remove ) ,
. shutdown = esb_shutdown ,
. driver = {
. owner = THIS_MODULE ,
. name = ESB_MODULE_NAME ,
} ,
} ;
static int __init watchdog_init ( void )
{
int err ;
printk ( KERN_INFO PFX " Intel 6300ESB WatchDog Timer Driver v%s \n " ,
ESB_VERSION ) ;
err = platform_driver_register ( & esb_platform_driver ) ;
if ( err )
return err ;
esb_platform_device = platform_device_register_simple ( ESB_MODULE_NAME ,
- 1 , NULL , 0 ) ;
if ( IS_ERR ( esb_platform_device ) ) {
err = PTR_ERR ( esb_platform_device ) ;
goto unreg_platform_driver ;
}
return 0 ;
unreg_platform_driver :
platform_driver_unregister ( & esb_platform_driver ) ;
return err ;
}
static void __exit watchdog_cleanup ( void )
{
platform_device_unregister ( esb_platform_device ) ;
platform_driver_unregister ( & esb_platform_driver ) ;
printk ( KERN_INFO PFX " Watchdog Module Unloaded. \n " ) ;
2005-08-17 11:07:44 +04:00
}
module_init ( watchdog_init ) ;
module_exit ( watchdog_cleanup ) ;
2007-10-20 01:21:04 +04:00
MODULE_AUTHOR ( " Ross Biro and David Härdeman " ) ;
2005-08-17 11:07:44 +04:00
MODULE_DESCRIPTION ( " Watchdog driver for Intel 6300ESB chipsets " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_ALIAS_MISCDEV ( WATCHDOG_MINOR ) ;