aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char
diff options
context:
space:
mode:
authorDave Airlie <airlied@starflyer.(none)>2005-09-25 13:14:45 +1000
committerDave Airlie <airlied@linux.ie>2005-09-25 13:14:45 +1000
commit4e0c1159d83a658d1ffba5bc3442f4ec4cadb436 (patch)
tree36a5079ba7ba9b9e0f2f633356705b980940eac4 /drivers/char
parentea98a92ff18c03bf7f4d21536986cbbcb4c10cd9 (diff)
parentef6bd6eb90ad72ee8ee7ba8b271f27102e9a90c1 (diff)
downloadkernel_samsung_aries-4e0c1159d83a658d1ffba5bc3442f4ec4cadb436.zip
kernel_samsung_aries-4e0c1159d83a658d1ffba5bc3442f4ec4cadb436.tar.gz
kernel_samsung_aries-4e0c1159d83a658d1ffba5bc3442f4ec4cadb436.tar.bz2
update from upstream
Diffstat (limited to 'drivers/char')
-rw-r--r--drivers/char/Kconfig11
-rw-r--r--drivers/char/agp/amd64-agp.c2
-rw-r--r--drivers/char/agp/backend.c7
-rw-r--r--drivers/char/agp/generic.c33
-rw-r--r--drivers/char/agp/hp-agp.c2
-rw-r--r--drivers/char/amiserial.c4
-rw-r--r--drivers/char/applicom.c24
-rw-r--r--drivers/char/cyclades.c2
-rw-r--r--drivers/char/digi1.h38
-rw-r--r--drivers/char/digiFep1.h154
-rw-r--r--drivers/char/drm/drmP.h4
-rw-r--r--drivers/char/epca.c1634
-rw-r--r--drivers/char/epca.h108
-rw-r--r--drivers/char/ftape/lowlevel/fdc-io.c6
-rw-r--r--drivers/char/hangcheck-timer.c3
-rw-r--r--drivers/char/hpet.c17
-rw-r--r--drivers/char/hvc_console.c6
-rw-r--r--drivers/char/hw_random.c5
-rw-r--r--drivers/char/ip2/i2lib.c6
-rw-r--r--drivers/char/ip2main.c3
-rw-r--r--drivers/char/ipmi/ipmi_bt_sm.c69
-rw-r--r--drivers/char/ipmi/ipmi_devintf.c106
-rw-r--r--drivers/char/ipmi/ipmi_kcs_sm.c3
-rw-r--r--drivers/char/ipmi/ipmi_msghandler.c342
-rw-r--r--drivers/char/ipmi/ipmi_poweroff.c168
-rw-r--r--drivers/char/ipmi/ipmi_si_intf.c418
-rw-r--r--drivers/char/ipmi/ipmi_smic_sm.c3
-rw-r--r--drivers/char/ipmi/ipmi_watchdog.c52
-rw-r--r--drivers/char/istallion.c2
-rw-r--r--drivers/char/keyboard.c114
-rw-r--r--drivers/char/lcd.c7
-rw-r--r--drivers/char/lp.c3
-rw-r--r--drivers/char/mbcs.c2
-rw-r--r--drivers/char/mem.c4
-rw-r--r--drivers/char/misc.c9
-rw-r--r--drivers/char/moxa.c2
-rw-r--r--drivers/char/mxser.c13
-rw-r--r--drivers/char/n_tty.c2
-rw-r--r--drivers/char/pcmcia/synclink_cs.c16
-rw-r--r--drivers/char/pty.c5
-rw-r--r--drivers/char/rtc.c5
-rw-r--r--drivers/char/sonypi.c118
-rw-r--r--drivers/char/synclink.c29
-rw-r--r--drivers/char/synclinkmp.c41
-rw-r--r--drivers/char/tpm/Kconfig2
-rw-r--r--drivers/char/tpm/tpm_atmel.c3
-rw-r--r--drivers/char/tpm/tpm_infineon.c76
-rw-r--r--drivers/char/tty_io.c93
-rw-r--r--drivers/char/vt.c59
-rw-r--r--drivers/char/watchdog/Kconfig109
-rw-r--r--drivers/char/watchdog/Makefile78
-rw-r--r--drivers/char/watchdog/booke_wdt.c192
-rw-r--r--drivers/char/watchdog/i6300esb.c527
-rw-r--r--drivers/char/watchdog/ibmasr.c405
-rw-r--r--drivers/char/watchdog/ixp2000_wdt.c2
-rw-r--r--drivers/char/watchdog/ixp4xx_wdt.c2
-rw-r--r--drivers/char/watchdog/mixcomwd.c2
-rw-r--r--drivers/char/watchdog/mpcore_wdt.c436
-rw-r--r--drivers/char/watchdog/mv64x60_wdt.c252
-rw-r--r--drivers/char/watchdog/pcwd_pci.c44
-rw-r--r--drivers/char/watchdog/s3c2410_wdt.c87
-rw-r--r--drivers/char/watchdog/sbc8360.c414
-rw-r--r--drivers/char/watchdog/scx200_wdt.c2
-rw-r--r--drivers/char/watchdog/softdog.c13
-rw-r--r--drivers/char/watchdog/w83627hf_wdt.c6
-rw-r--r--drivers/char/watchdog/w83977f_wdt.c543
66 files changed, 4755 insertions, 2194 deletions
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 7333b41..c29365d 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -80,7 +80,7 @@ config SERIAL_NONSTANDARD
config COMPUTONE
tristate "Computone IntelliPort Plus serial support"
- depends on SERIAL_NONSTANDARD && BROKEN_ON_SMP && (BROKEN || !SPARC32)
+ depends on SERIAL_NONSTANDARD && BROKEN_ON_SMP
---help---
This driver supports the entire family of Intelliport II/Plus
controllers with the exception of the MicroChannel controllers and
@@ -138,7 +138,7 @@ config CYZ_INTR
config DIGIEPCA
tristate "Digiboard Intelligent Async Support"
- depends on SERIAL_NONSTANDARD && BROKEN_ON_SMP && (!64BIT || BROKEN)
+ depends on SERIAL_NONSTANDARD
---help---
This is a driver for Digi International's Xx, Xeve, and Xem series
of cards which provide multiple serial ports. You would need
@@ -208,7 +208,7 @@ config SYNCLINK
config SYNCLINKMP
tristate "SyncLink Multiport support"
- depends on SERIAL_NONSTANDARD && (BROKEN || !SPARC32)
+ depends on SERIAL_NONSTANDARD
help
Enable support for the SyncLink Multiport (2 or 4 ports)
serial adapter, running asynchronous and HDLC communications up
@@ -735,7 +735,7 @@ config SGI_IP27_RTC
config GEN_RTC
tristate "Generic /dev/rtc emulation"
- depends on RTC!=y && !IA64 && !ARM && !PPC64 && !M32R && !SPARC32
+ depends on RTC!=y && !IA64 && !ARM && !PPC64 && !M32R && !SPARC32 && !SPARC64
---help---
If you say Y here and create a character special file /dev/rtc with
major number 10 and minor number 135 using mknod ("man mknod"), you
@@ -842,8 +842,7 @@ config SONYPI
config TANBAC_TB0219
tristate "TANBAC TB0219 base board support"
- depends TANBAC_TB0229
-
+ depends TANBAC_TB022X
menu "Ftape, the floppy tape device driver"
diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c
index 59f589d..0a7624a 100644
--- a/drivers/char/agp/amd64-agp.c
+++ b/drivers/char/agp/amd64-agp.c
@@ -429,7 +429,7 @@ static int __devinit uli_agp_init(struct pci_dev *pdev)
struct pci_dev *dev1;
int i;
unsigned size = amd64_fetch_size();
- printk(KERN_INFO "Setting up ULi AGP. \n");
+ printk(KERN_INFO "Setting up ULi AGP.\n");
dev1 = pci_find_slot ((unsigned int)pdev->bus->number,PCI_DEVFN(0,0));
if (dev1 == NULL) {
printk(KERN_INFO PFX "Detected a ULi chipset, "
diff --git a/drivers/char/agp/backend.c b/drivers/char/agp/backend.c
index 4d4e602..82b43c5 100644
--- a/drivers/char/agp/backend.c
+++ b/drivers/char/agp/backend.c
@@ -206,10 +206,9 @@ static void agp_backend_cleanup(struct agp_bridge_data *bridge)
bridge->driver->cleanup();
if (bridge->driver->free_gatt_table)
bridge->driver->free_gatt_table(bridge);
- if (bridge->key_list) {
- vfree(bridge->key_list);
- bridge->key_list = NULL;
- }
+
+ vfree(bridge->key_list);
+ bridge->key_list = NULL;
if (bridge->driver->agp_destroy_page &&
bridge->driver->needs_scratch_page)
diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c
index f0079e9..ac9da0c 100644
--- a/drivers/char/agp/generic.c
+++ b/drivers/char/agp/generic.c
@@ -319,7 +319,6 @@ int agp_copy_info(struct agp_bridge_data *bridge, struct agp_kern_info *info)
info->mode = bridge->mode & ~AGP3_RESERVED_MASK;
else
info->mode = bridge->mode & ~AGP2_RESERVED_MASK;
- info->mode = bridge->mode;
info->aper_base = bridge->gart_bus_addr;
info->aper_size = agp_return_size();
info->max_memory = bridge->max_memory_agp;
@@ -356,7 +355,7 @@ int agp_bind_memory(struct agp_memory *curr, off_t pg_start)
return -EINVAL;
if (curr->is_bound == TRUE) {
- printk (KERN_INFO PFX "memory %p is already bound!\n", curr);
+ printk(KERN_INFO PFX "memory %p is already bound!\n", curr);
return -EINVAL;
}
if (curr->is_flushed == FALSE) {
@@ -391,7 +390,7 @@ int agp_unbind_memory(struct agp_memory *curr)
return -EINVAL;
if (curr->is_bound != TRUE) {
- printk (KERN_INFO PFX "memory %p was not bound!\n", curr);
+ printk(KERN_INFO PFX "memory %p was not bound!\n", curr);
return -EINVAL;
}
@@ -415,7 +414,7 @@ static void agp_v2_parse_one(u32 *requested_mode, u32 *bridge_agpstat, u32 *vga_
u32 tmp;
if (*requested_mode & AGP2_RESERVED_MASK) {
- printk (KERN_INFO PFX "reserved bits set in mode 0x%x. Fixed.\n", *requested_mode);
+ printk(KERN_INFO PFX "reserved bits set in mode 0x%x. Fixed.\n", *requested_mode);
*requested_mode &= ~AGP2_RESERVED_MASK;
}
@@ -423,7 +422,7 @@ static void agp_v2_parse_one(u32 *requested_mode, u32 *bridge_agpstat, u32 *vga_
tmp = *requested_mode & 7;
switch (tmp) {
case 0:
- printk (KERN_INFO PFX "%s tried to set rate=x0. Setting to x1 mode.\n", current->comm);
+ printk(KERN_INFO PFX "%s tried to set rate=x0. Setting to x1 mode.\n", current->comm);
*requested_mode |= AGPSTAT2_1X;
break;
case 1:
@@ -493,18 +492,18 @@ static void agp_v3_parse_one(u32 *requested_mode, u32 *bridge_agpstat, u32 *vga_
u32 tmp;
if (*requested_mode & AGP3_RESERVED_MASK) {
- printk (KERN_INFO PFX "reserved bits set in mode 0x%x. Fixed.\n", *requested_mode);
+ printk(KERN_INFO PFX "reserved bits set in mode 0x%x. Fixed.\n", *requested_mode);
*requested_mode &= ~AGP3_RESERVED_MASK;
}
/* Check the speed bits make sense. */
tmp = *requested_mode & 7;
if (tmp == 0) {
- printk (KERN_INFO PFX "%s tried to set rate=x0. Setting to AGP3 x4 mode.\n", current->comm);
+ printk(KERN_INFO PFX "%s tried to set rate=x0. Setting to AGP3 x4 mode.\n", current->comm);
*requested_mode |= AGPSTAT3_4X;
}
if (tmp >= 3) {
- printk (KERN_INFO PFX "%s tried to set rate=x%d. Setting to AGP3 x8 mode.\n", current->comm, tmp * 4);
+ printk(KERN_INFO PFX "%s tried to set rate=x%d. Setting to AGP3 x8 mode.\n", current->comm, tmp * 4);
*requested_mode = (*requested_mode & ~7) | AGPSTAT3_8X;
}
@@ -533,7 +532,7 @@ static void agp_v3_parse_one(u32 *requested_mode, u32 *bridge_agpstat, u32 *vga_
* AGP2.x 4x -> AGP3.0 4x.
*/
if (*requested_mode & AGPSTAT2_4X) {
- printk (KERN_INFO PFX "%s passes broken AGP3 flags (%x). Fixed.\n",
+ printk(KERN_INFO PFX "%s passes broken AGP3 flags (%x). Fixed.\n",
current->comm, *requested_mode);
*requested_mode &= ~AGPSTAT2_4X;
*requested_mode |= AGPSTAT3_4X;
@@ -544,7 +543,7 @@ static void agp_v3_parse_one(u32 *requested_mode, u32 *bridge_agpstat, u32 *vga_
* but have been passed an AGP 2.x mode.
* Convert AGP 1x,2x,4x -> AGP 3.0 4x.
*/
- printk (KERN_INFO PFX "%s passes broken AGP2 flags (%x) in AGP3 mode. Fixed.\n",
+ printk(KERN_INFO PFX "%s passes broken AGP2 flags (%x) in AGP3 mode. Fixed.\n",
current->comm, *requested_mode);
*requested_mode &= ~(AGPSTAT2_4X | AGPSTAT2_2X | AGPSTAT2_1X);
*requested_mode |= AGPSTAT3_4X;
@@ -554,13 +553,13 @@ static void agp_v3_parse_one(u32 *requested_mode, u32 *bridge_agpstat, u32 *vga_
if (!(*bridge_agpstat & AGPSTAT3_8X)) {
*bridge_agpstat &= ~(AGPSTAT3_8X | AGPSTAT3_RSVD);
*bridge_agpstat |= AGPSTAT3_4X;
- printk ("%s requested AGPx8 but bridge not capable.\n", current->comm);
+ printk(KERN_INFO PFX "%s requested AGPx8 but bridge not capable.\n", current->comm);
return;
}
if (!(*vga_agpstat & AGPSTAT3_8X)) {
*bridge_agpstat &= ~(AGPSTAT3_8X | AGPSTAT3_RSVD);
*bridge_agpstat |= AGPSTAT3_4X;
- printk ("%s requested AGPx8 but graphic card not capable.\n", current->comm);
+ printk(KERN_INFO PFX "%s requested AGPx8 but graphic card not capable.\n", current->comm);
return;
}
/* All set, bridge & device can do AGP x8*/
@@ -578,13 +577,13 @@ static void agp_v3_parse_one(u32 *requested_mode, u32 *bridge_agpstat, u32 *vga_
if ((*bridge_agpstat & AGPSTAT3_4X) && (*vga_agpstat & AGPSTAT3_4X))
*bridge_agpstat |= AGPSTAT3_4X;
else {
- printk (KERN_INFO PFX "Badness. Don't know which AGP mode to set. "
+ printk(KERN_INFO PFX "Badness. Don't know which AGP mode to set. "
"[bridge_agpstat:%x vga_agpstat:%x fell back to:- bridge_agpstat:%x vga_agpstat:%x]\n",
origbridge, origvga, *bridge_agpstat, *vga_agpstat);
if (!(*bridge_agpstat & AGPSTAT3_4X))
- printk (KERN_INFO PFX "Bridge couldn't do AGP x4.\n");
+ printk(KERN_INFO PFX "Bridge couldn't do AGP x4.\n");
if (!(*vga_agpstat & AGPSTAT3_4X))
- printk (KERN_INFO PFX "Graphic card couldn't do AGP x4.\n");
+ printk(KERN_INFO PFX "Graphic card couldn't do AGP x4.\n");
return;
}
}
@@ -622,7 +621,7 @@ u32 agp_collect_device_status(struct agp_bridge_data *bridge, u32 requested_mode
for (;;) {
device = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, device);
if (!device) {
- printk (KERN_INFO PFX "Couldn't find an AGP VGA controller.\n");
+ printk(KERN_INFO PFX "Couldn't find an AGP VGA controller.\n");
return 0;
}
cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP);
@@ -734,7 +733,7 @@ void agp_generic_enable(struct agp_bridge_data *bridge, u32 requested_mode)
pci_write_config_dword(bridge->dev,
bridge->capndx+AGPCTRL, temp);
- printk (KERN_INFO PFX "Device is in legacy mode,"
+ printk(KERN_INFO PFX "Device is in legacy mode,"
" falling back to 2.x\n");
}
}
diff --git a/drivers/char/agp/hp-agp.c b/drivers/char/agp/hp-agp.c
index 99762b6..de5d6d2 100644
--- a/drivers/char/agp/hp-agp.c
+++ b/drivers/char/agp/hp-agp.c
@@ -252,7 +252,7 @@ hp_zx1_configure (void)
readl(hp->ioc_regs+HP_ZX1_PDIR_BASE);
writel(hp->io_tlb_ps, hp->ioc_regs+HP_ZX1_TCNFG);
readl(hp->ioc_regs+HP_ZX1_TCNFG);
- writel(~(HP_ZX1_IOVA_SIZE-1), hp->ioc_regs+HP_ZX1_IMASK);
+ writel((unsigned int)(~(HP_ZX1_IOVA_SIZE-1)), hp->ioc_regs+HP_ZX1_IMASK);
readl(hp->ioc_regs+HP_ZX1_IMASK);
writel(hp->iova_base|1, hp->ioc_regs+HP_ZX1_IBASE);
readl(hp->ioc_regs+HP_ZX1_IBASE);
diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c
index 2a36561..a124f8c 100644
--- a/drivers/char/amiserial.c
+++ b/drivers/char/amiserial.c
@@ -2053,10 +2053,6 @@ static int __init rs_init(void)
state->icount.rx = state->icount.tx = 0;
state->icount.frame = state->icount.parity = 0;
state->icount.overrun = state->icount.brk = 0;
- /*
- if(state->port && check_region(state->port,REGION_LENGTH(state)))
- continue;
- */
printk(KERN_INFO "ttyS%d is the amiga builtin serial port\n",
state->line);
diff --git a/drivers/char/applicom.c b/drivers/char/applicom.c
index 11f9ee5..927a5bb 100644
--- a/drivers/char/applicom.c
+++ b/drivers/char/applicom.c
@@ -172,7 +172,7 @@ static int ac_register_board(unsigned long physloc, void __iomem *loc,
void cleanup_module(void)
{
- int i;
+ unsigned int i;
misc_deregister(&ac_miscdev);
@@ -195,7 +195,7 @@ int __init applicom_init(void)
int i, numisa = 0;
struct pci_dev *dev = NULL;
void __iomem *RamIO;
- int boardno;
+ int boardno, ret;
printk(KERN_INFO "Applicom driver: $Id: ac.c,v 1.30 2000/03/22 16:03:57 dwmw2 Exp $\n");
@@ -294,7 +294,8 @@ int __init applicom_init(void)
}
if (!numisa)
- printk(KERN_WARNING"ac.o: No valid ISA Applicom boards found at mem 0x%lx\n",mem);
+ printk(KERN_WARNING "ac.o: No valid ISA Applicom boards found "
+ "at mem 0x%lx\n", mem);
fin:
init_waitqueue_head(&FlagSleepRec);
@@ -304,7 +305,11 @@ int __init applicom_init(void)
DeviceErrorCount = 0;
if (numboards) {
- misc_register(&ac_miscdev);
+ ret = misc_register(&ac_miscdev);
+ if (ret) {
+ printk(KERN_WARNING "ac.o: Unable to register misc device\n");
+ goto out;
+ }
for (i = 0; i < MAX_BOARD; i++) {
int serial;
char boardname[(SERIAL_NUMBER - TYPE_CARD) + 1];
@@ -337,6 +342,17 @@ int __init applicom_init(void)
else
return -ENXIO;
+
+out:
+ for (i = 0; i < MAX_BOARD; i++) {
+ if (!apbs[i].RamIO)
+ continue;
+ if (apbs[i].irq)
+ free_irq(apbs[i].irq, &dummy);
+ iounmap(apbs[i].RamIO);
+ }
+ pci_disable_device(dev);
+ return ret;
}
diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c
index 6a5337b..cf4c364 100644
--- a/drivers/char/cyclades.c
+++ b/drivers/char/cyclades.c
@@ -865,7 +865,7 @@ static void cyz_poll(unsigned long);
static long cyz_polling_cycle = CZ_DEF_POLL;
static int cyz_timeron = 0;
-static struct timer_list cyz_timerlist = TIMER_INITIALIZER(cyz_poll, 0, 0);
+static DEFINE_TIMER(cyz_timerlist, cyz_poll, 0, 0);
#else /* CONFIG_CYZ_INTR */
static void cyz_rx_restart(unsigned long);
diff --git a/drivers/char/digi1.h b/drivers/char/digi1.h
index 184378d..94d4eab 100644
--- a/drivers/char/digi1.h
+++ b/drivers/char/digi1.h
@@ -1,46 +1,46 @@
/* Definitions for DigiBoard ditty(1) command. */
#if !defined(TIOCMODG)
-#define TIOCMODG ('d'<<8) | 250 /* get modem ctrl state */
-#define TIOCMODS ('d'<<8) | 251 /* set modem ctrl state */
+#define TIOCMODG (('d'<<8) | 250) /* get modem ctrl state */
+#define TIOCMODS (('d'<<8) | 251) /* set modem ctrl state */
#endif
#if !defined(TIOCMSET)
-#define TIOCMSET ('d'<<8) | 252 /* set modem ctrl state */
-#define TIOCMGET ('d'<<8) | 253 /* set modem ctrl state */
+#define TIOCMSET (('d'<<8) | 252) /* set modem ctrl state */
+#define TIOCMGET (('d'<<8) | 253) /* set modem ctrl state */
#endif
#if !defined(TIOCMBIC)
-#define TIOCMBIC ('d'<<8) | 254 /* set modem ctrl state */
-#define TIOCMBIS ('d'<<8) | 255 /* set modem ctrl state */
+#define TIOCMBIC (('d'<<8) | 254) /* set modem ctrl state */
+#define TIOCMBIS (('d'<<8) | 255) /* set modem ctrl state */
#endif
#if !defined(TIOCSDTR)
-#define TIOCSDTR ('e'<<8) | 0 /* set DTR */
-#define TIOCCDTR ('e'<<8) | 1 /* clear DTR */
+#define TIOCSDTR (('e'<<8) | 0) /* set DTR */
+#define TIOCCDTR (('e'<<8) | 1) /* clear DTR */
#endif
/************************************************************************
* Ioctl command arguments for DIGI parameters.
************************************************************************/
-#define DIGI_GETA ('e'<<8) | 94 /* Read params */
+#define DIGI_GETA (('e'<<8) | 94) /* Read params */
-#define DIGI_SETA ('e'<<8) | 95 /* Set params */
-#define DIGI_SETAW ('e'<<8) | 96 /* Drain & set params */
-#define DIGI_SETAF ('e'<<8) | 97 /* Drain, flush & set params */
+#define DIGI_SETA (('e'<<8) | 95) /* Set params */
+#define DIGI_SETAW (('e'<<8) | 96) /* Drain & set params */
+#define DIGI_SETAF (('e'<<8) | 97) /* Drain, flush & set params */
-#define DIGI_GETFLOW ('e'<<8) | 99 /* Get startc/stopc flow */
+#define DIGI_GETFLOW (('e'<<8) | 99) /* Get startc/stopc flow */
/* control characters */
-#define DIGI_SETFLOW ('e'<<8) | 100 /* Set startc/stopc flow */
+#define DIGI_SETFLOW (('e'<<8) | 100) /* Set startc/stopc flow */
/* control characters */
-#define DIGI_GETAFLOW ('e'<<8) | 101 /* Get Aux. startc/stopc */
+#define DIGI_GETAFLOW (('e'<<8) | 101) /* Get Aux. startc/stopc */
/* flow control chars */
-#define DIGI_SETAFLOW ('e'<<8) | 102 /* Set Aux. startc/stopc */
+#define DIGI_SETAFLOW (('e'<<8) | 102) /* Set Aux. startc/stopc */
/* flow control chars */
-#define DIGI_GETINFO ('e'<<8) | 103 /* Fill in digi_info */
-#define DIGI_POLLER ('e'<<8) | 104 /* Turn on/off poller */
-#define DIGI_INIT ('e'<<8) | 105 /* Allow things to run. */
+#define DIGI_GETINFO (('e'<<8) | 103) /* Fill in digi_info */
+#define DIGI_POLLER (('e'<<8) | 104) /* Turn on/off poller */
+#define DIGI_INIT (('e'<<8) | 105) /* Allow things to run. */
struct digiflow_struct
{
diff --git a/drivers/char/digiFep1.h b/drivers/char/digiFep1.h
index c47d7fc..3c1f192 100644
--- a/drivers/char/digiFep1.h
+++ b/drivers/char/digiFep1.h
@@ -13,88 +13,88 @@
struct global_data
{
- volatile ushort cin;
- volatile ushort cout;
- volatile ushort cstart;
- volatile ushort cmax;
- volatile ushort ein;
- volatile ushort eout;
- volatile ushort istart;
- volatile ushort imax;
+ u16 cin;
+ u16 cout;
+ u16 cstart;
+ u16 cmax;
+ u16 ein;
+ u16 eout;
+ u16 istart;
+ u16 imax;
};
struct board_chan
{
- int filler1;
- int filler2;
- volatile ushort tseg;
- volatile ushort tin;
- volatile ushort tout;
- volatile ushort tmax;
-
- volatile ushort rseg;
- volatile ushort rin;
- volatile ushort rout;
- volatile ushort rmax;
-
- volatile ushort tlow;
- volatile ushort rlow;
- volatile ushort rhigh;
- volatile ushort incr;
-
- volatile ushort etime;
- volatile ushort edelay;
- volatile unchar *dev;
-
- volatile ushort iflag;
- volatile ushort oflag;
- volatile ushort cflag;
- volatile ushort gmask;
-
- volatile ushort col;
- volatile ushort delay;
- volatile ushort imask;
- volatile ushort tflush;
-
- int filler3;
- int filler4;
- int filler5;
- int filler6;
-
- volatile unchar num;
- volatile unchar ract;
- volatile unchar bstat;
- volatile unchar tbusy;
- volatile unchar iempty;
- volatile unchar ilow;
- volatile unchar idata;
- volatile unchar eflag;
-
- volatile unchar tflag;
- volatile unchar rflag;
- volatile unchar xmask;
- volatile unchar xval;
- volatile unchar mstat;
- volatile unchar mchange;
- volatile unchar mint;
- volatile unchar lstat;
-
- volatile unchar mtran;
- volatile unchar orun;
- volatile unchar startca;
- volatile unchar stopca;
- volatile unchar startc;
- volatile unchar stopc;
- volatile unchar vnext;
- volatile unchar hflow;
-
- volatile unchar fillc;
- volatile unchar ochar;
- volatile unchar omask;
-
- unchar filler7;
- unchar filler8[28];
+ u32 filler1;
+ u32 filler2;
+ u16 tseg;
+ u16 tin;
+ u16 tout;
+ u16 tmax;
+
+ u16 rseg;
+ u16 rin;
+ u16 rout;
+ u16 rmax;
+
+ u16 tlow;
+ u16 rlow;
+ u16 rhigh;
+ u16 incr;
+
+ u16 etime;
+ u16 edelay;
+ unchar *dev;
+
+ u16 iflag;
+ u16 oflag;
+ u16 cflag;
+ u16 gmask;
+
+ u16 col;
+ u16 delay;
+ u16 imask;
+ u16 tflush;
+
+ u32 filler3;
+ u32 filler4;
+ u32 filler5;
+ u32 filler6;
+
+ u8 num;
+ u8 ract;
+ u8 bstat;
+ u8 tbusy;
+ u8 iempty;
+ u8 ilow;
+ u8 idata;
+ u8 eflag;
+
+ u8 tflag;
+ u8 rflag;
+ u8 xmask;
+ u8 xval;
+ u8 mstat;
+ u8 mchange;
+ u8 mint;
+ u8 lstat;
+
+ u8 mtran;
+ u8 orun;
+ u8 startca;
+ u8 stopca;
+ u8 startc;
+ u8 stopc;
+ u8 vnext;
+ u8 hflow;
+
+ u8 fillc;
+ u8 ochar;
+ u8 omask;
+
+ u8 filler7;
+ u8 filler8[28];
};
diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h
index c164c76..cf58a52 100644
--- a/drivers/char/drm/drmP.h
+++ b/drivers/char/drm/drmP.h
@@ -1083,5 +1083,9 @@ extern void *drm_calloc(size_t nmemb, size_t size, int area);
extern unsigned long drm_core_get_map_ofs(drm_map_t *map);
extern unsigned long drm_core_get_reg_ofs(struct drm_device *dev);
+#ifndef pci_pretty_name
+#define pci_pretty_name(dev) ""
+#endif
+
#endif /* __KERNEL__ */
#endif
diff --git a/drivers/char/epca.c b/drivers/char/epca.c
index 6025e18..407708a 100644
--- a/drivers/char/epca.c
+++ b/drivers/char/epca.c
@@ -6,6 +6,8 @@
For technical support please email digiLinux@dgii.com or
call Digi tech support at (612) 912-3456
+ ** This driver is no longer supported by Digi **
+
Much of this design and code came from epca.c which was
copyright (C) 1994, 1995 Troy De Jongh, and subsquently
modified by David Nugent, Christoph Lameter, Mike McLagan.
@@ -43,31 +45,19 @@
#include <linux/interrupt.h>
#include <asm/uaccess.h>
#include <asm/io.h>
-
-#ifdef CONFIG_PCI
-#define ENABLE_PCI
-#endif /* CONFIG_PCI */
-
-#define putUser(arg1, arg2) put_user(arg1, (unsigned long __user *)arg2)
-#define getUser(arg1, arg2) get_user(arg1, (unsigned __user *)arg2)
-
-#ifdef ENABLE_PCI
+#include <linux/spinlock.h>
#include <linux/pci.h>
#include "digiPCI.h"
-#endif /* ENABLE_PCI */
+
#include "digi1.h"
#include "digiFep1.h"
#include "epca.h"
#include "epcaconfig.h"
-#if BITS_PER_LONG != 32
-# error FIXME: this driver only works on 32-bit platforms
-#endif
-
/* ---------------------- Begin defines ------------------------ */
-#define VERSION "1.3.0.1-LK"
+#define VERSION "1.3.0.1-LK2.6"
/* This major needs to be submitted to Linux to join the majors list */
@@ -81,13 +71,17 @@
/* ----------------- Begin global definitions ------------------- */
-static char mesg[100];
static int nbdevs, num_cards, liloconfig;
static int digi_poller_inhibited = 1 ;
static int setup_error_code;
static int invalid_lilo_config;
+/* The ISA boards do window flipping into the same spaces so its only sane
+ with a single lock. It's still pretty efficient */
+
+static spinlock_t epca_lock = SPIN_LOCK_UNLOCKED;
+
/* -----------------------------------------------------------------------
MAXBOARDS is typically 12, but ISA and EISA cards are restricted to
7 below.
@@ -129,58 +123,58 @@ static struct timer_list epca_timer;
configured.
----------------------------------------------------------------------- */
-static inline void memwinon(struct board_info *b, unsigned int win);
-static inline void memwinoff(struct board_info *b, unsigned int win);
-static inline void globalwinon(struct channel *ch);
-static inline void rxwinon(struct channel *ch);
-static inline void txwinon(struct channel *ch);
-static inline void memoff(struct channel *ch);
-static inline void assertgwinon(struct channel *ch);
-static inline void assertmemoff(struct channel *ch);
+static void memwinon(struct board_info *b, unsigned int win);
+static void memwinoff(struct board_info *b, unsigned int win);
+static void globalwinon(struct channel *ch);
+static void rxwinon(struct channel *ch);
+static void txwinon(struct channel *ch);
+static void memoff(struct channel *ch);
+static void assertgwinon(struct channel *ch);
+static void assertmemoff(struct channel *ch);
/* ---- Begin more 'specific' memory functions for cx_like products --- */
-static inline void pcxem_memwinon(struct board_info *b, unsigned int win);
-static inline void pcxem_memwinoff(struct board_info *b, unsigned int win);
-static inline void pcxem_globalwinon(struct channel *ch);
-static inline void pcxem_rxwinon(struct channel *ch);
-static inline void pcxem_txwinon(struct channel *ch);
-static inline void pcxem_memoff(struct channel *ch);
+static void pcxem_memwinon(struct board_info *b, unsigned int win);
+static void pcxem_memwinoff(struct board_info *b, unsigned int win);
+static void pcxem_globalwinon(struct channel *ch);
+static void pcxem_rxwinon(struct channel *ch);
+static void pcxem_txwinon(struct channel *ch);
+static void pcxem_memoff(struct channel *ch);
/* ------ Begin more 'specific' memory functions for the pcxe ------- */
-static inline void pcxe_memwinon(struct board_info *b, unsigned int win);
-static inline void pcxe_memwinoff(struct board_info *b, unsigned int win);
-static inline void pcxe_globalwinon(struct channel *ch);
-static inline void pcxe_rxwinon(struct channel *ch);
-static inline void pcxe_txwinon(struct channel *ch);
-static inline void pcxe_memoff(struct channel *ch);
+static void pcxe_memwinon(struct board_info *b, unsigned int win);
+static void pcxe_memwinoff(struct board_info *b, unsigned int win);
+static void pcxe_globalwinon(struct channel *ch);
+static void pcxe_rxwinon(struct channel *ch);
+static void pcxe_txwinon(struct channel *ch);
+static void pcxe_memoff(struct channel *ch);
/* ---- Begin more 'specific' memory functions for the pc64xe and pcxi ---- */
/* Note : pc64xe and pcxi share the same windowing routines */
-static inline void pcxi_memwinon(struct board_info *b, unsigned int win);
-static inline void pcxi_memwinoff(struct board_info *b, unsigned int win);
-static inline void pcxi_globalwinon(struct channel *ch);
-static inline void pcxi_rxwinon(struct channel *ch);
-static inline void pcxi_txwinon(struct channel *ch);
-static inline void pcxi_memoff(struct channel *ch);
+static void pcxi_memwinon(struct board_info *b, unsigned int win);
+static void pcxi_memwinoff(struct board_info *b, unsigned int win);
+static void pcxi_globalwinon(struct channel *ch);
+static void pcxi_rxwinon(struct channel *ch);
+static void pcxi_txwinon(struct channel *ch);
+static void pcxi_memoff(struct channel *ch);
/* - Begin 'specific' do nothing memory functions needed for some cards - */
-static inline void dummy_memwinon(struct board_info *b, unsigned int win);
-static inline void dummy_memwinoff(struct board_info *b, unsigned int win);
-static inline void dummy_globalwinon(struct channel *ch);
-static inline void dummy_rxwinon(struct channel *ch);
-static inline void dummy_txwinon(struct channel *ch);
-static inline void dummy_memoff(struct channel *ch);
-static inline void dummy_assertgwinon(struct channel *ch);
-static inline void dummy_assertmemoff(struct channel *ch);
+static void dummy_memwinon(struct board_info *b, unsigned int win);
+static void dummy_memwinoff(struct board_info *b, unsigned int win);
+static void dummy_globalwinon(struct channel *ch);
+static void dummy_rxwinon(struct channel *ch);
+static void dummy_txwinon(struct channel *ch);
+static void dummy_memoff(struct channel *ch);
+static void dummy_assertgwinon(struct channel *ch);
+static void dummy_assertmemoff(struct channel *ch);
/* ------------------- Begin declare functions ----------------------- */
-static inline struct channel *verifyChannel(register struct tty_struct *);
-static inline void pc_sched_event(struct channel *, int);
+static struct channel *verifyChannel(struct tty_struct *);
+static void pc_sched_event(struct channel *, int);
static void epca_error(int, char *);
static void pc_close(struct tty_struct *, struct file *);
static void shutdown(struct channel *);
@@ -215,15 +209,11 @@ static void pc_unthrottle(struct tty_struct *tty);
static void digi_send_break(struct channel *ch, int msec);
static void setup_empty_event(struct tty_struct *tty, struct channel *ch);
void epca_setup(char *, int *);
-void console_print(const char *);
static int get_termio(struct tty_struct *, struct termio __user *);
static int pc_write(struct tty_struct *, const unsigned char *, int);
-int pc_init(void);
-
-#ifdef ENABLE_PCI
+static int pc_init(void);
static int init_PCI(void);
-#endif /* ENABLE_PCI */
/* ------------------------------------------------------------------
@@ -237,41 +227,41 @@ static int init_PCI(void);
making direct calls deserves what they get.
-------------------------------------------------------------------- */
-static inline void memwinon(struct board_info *b, unsigned int win)
+static void memwinon(struct board_info *b, unsigned int win)
{
(b->memwinon)(b, win);
}
-static inline void memwinoff(struct board_info *b, unsigned int win)
+static void memwinoff(struct board_info *b, unsigned int win)
{
(b->memwinoff)(b, win);
}
-static inline void globalwinon(struct channel *ch)
+static void globalwinon(struct channel *ch)
{
(ch->board->globalwinon)(ch);
}
-static inline void rxwinon(struct channel *ch)
+static void rxwinon(struct channel *ch)
{
(ch->board->rxwinon)(ch);
}
-static inline void txwinon(struct channel *ch)
+static void txwinon(struct channel *ch)
{
(ch->board->txwinon)(ch);
}
-static inline void memoff(struct channel *ch)
+static void memoff(struct channel *ch)
{
(ch->board->memoff)(ch);
}
-static inline void assertgwinon(struct channel *ch)
+static void assertgwinon(struct channel *ch)
{
(ch->board->assertgwinon)(ch);
}
-static inline void assertmemoff(struct channel *ch)
+static void assertmemoff(struct channel *ch)
{
(ch->board->assertmemoff)(ch);
}
@@ -281,66 +271,66 @@ static inline void assertmemoff(struct channel *ch)
and CX series cards.
------------------------------------------------------------ */
-static inline void pcxem_memwinon(struct board_info *b, unsigned int win)
+static void pcxem_memwinon(struct board_info *b, unsigned int win)
{
- outb_p(FEPWIN|win, (int)b->port + 1);
+ outb_p(FEPWIN|win, b->port + 1);
}
-static inline void pcxem_memwinoff(struct board_info *b, unsigned int win)
+static void pcxem_memwinoff(struct board_info *b, unsigned int win)
{
- outb_p(0, (int)b->port + 1);
+ outb_p(0, b->port + 1);
}
-static inline void pcxem_globalwinon(struct channel *ch)
+static void pcxem_globalwinon(struct channel *ch)
{
outb_p( FEPWIN, (int)ch->board->port + 1);
}
-static inline void pcxem_rxwinon(struct channel *ch)
+static void pcxem_rxwinon(struct channel *ch)
{
outb_p(ch->rxwin, (int)ch->board->port + 1);
}
-static inline void pcxem_txwinon(struct channel *ch)
+static void pcxem_txwinon(struct channel *ch)
{
outb_p(ch->txwin, (int)ch->board->port + 1);
}
-static inline void pcxem_memoff(struct channel *ch)
+static void pcxem_memoff(struct channel *ch)
{
outb_p(0, (int)ch->board->port + 1);
}
/* ----------------- Begin pcxe memory window stuff ------------------ */
-static inline void pcxe_memwinon(struct board_info *b, unsigned int win)
+static void pcxe_memwinon(struct board_info *b, unsigned int win)
{
- outb_p(FEPWIN | win, (int)b->port + 1);
+ outb_p(FEPWIN | win, b->port + 1);
}
-static inline void pcxe_memwinoff(struct board_info *b, unsigned int win)
+static void pcxe_memwinoff(struct board_info *b, unsigned int win)
{
- outb_p(inb((int)b->port) & ~FEPMEM,
- (int)b->port + 1);
- outb_p(0, (int)b->port + 1);
+ outb_p(inb(b->port) & ~FEPMEM,
+ b->port + 1);
+ outb_p(0, b->port + 1);
}
-static inline void pcxe_globalwinon(struct channel *ch)
+static void pcxe_globalwinon(struct channel *ch)
{
outb_p( FEPWIN, (int)ch->board->port + 1);
}
-static inline void pcxe_rxwinon(struct channel *ch)
+static void pcxe_rxwinon(struct channel *ch)
{
outb_p(ch->rxwin, (int)ch->board->port + 1);
}
-static inline void pcxe_txwinon(struct channel *ch)
+static void pcxe_txwinon(struct channel *ch)
{
outb_p(ch->txwin, (int)ch->board->port + 1);
}
-static inline void pcxe_memoff(struct channel *ch)
+static void pcxe_memoff(struct channel *ch)
{
outb_p(0, (int)ch->board->port);
outb_p(0, (int)ch->board->port + 1);
@@ -348,44 +338,44 @@ static inline void pcxe_memoff(struct channel *ch)
/* ------------- Begin pc64xe and pcxi memory window stuff -------------- */
-static inline void pcxi_memwinon(struct board_info *b, unsigned int win)
+static void pcxi_memwinon(struct board_info *b, unsigned int win)
{
- outb_p(inb((int)b->port) | FEPMEM, (int)b->port);
+ outb_p(inb(b->port) | FEPMEM, b->port);
}
-static inline void pcxi_memwinoff(struct board_info *b, unsigned int win)
+static void pcxi_memwinoff(struct board_info *b, unsigned int win)
{
- outb_p(inb((int)b->port) & ~FEPMEM, (int)b->port);
+ outb_p(inb(b->port) & ~FEPMEM, b->port);
}
-static inline void pcxi_globalwinon(struct channel *ch)
+static void pcxi_globalwinon(struct channel *ch)
{
- outb_p(FEPMEM, (int)ch->board->port);
+ outb_p(FEPMEM, ch->board->port);
}
-static inline void pcxi_rxwinon(struct channel *ch)
+static void pcxi_rxwinon(struct channel *ch)
{
- outb_p(FEPMEM, (int)ch->board->port);
+ outb_p(FEPMEM, ch->board->port);
}
-static inline void pcxi_txwinon(struct channel *ch)
+static void pcxi_txwinon(struct channel *ch)
{
- outb_p(FEPMEM, (int)ch->board->port);
+ outb_p(FEPMEM, ch->board->port);
}
-static inline void pcxi_memoff(struct channel *ch)
+static void pcxi_memoff(struct channel *ch)
{
- outb_p(0, (int)ch->board->port);
+ outb_p(0, ch->board->port);
}
-static inline void pcxi_assertgwinon(struct channel *ch)
+static void pcxi_assertgwinon(struct channel *ch)
{
- epcaassert(inb((int)ch->board->port) & FEPMEM, "Global memory off");
+ epcaassert(inb(ch->board->port) & FEPMEM, "Global memory off");
}
-static inline void pcxi_assertmemoff(struct channel *ch)
+static void pcxi_assertmemoff(struct channel *ch)
{
- epcaassert(!(inb((int)ch->board->port) & FEPMEM), "Memory on");
+ epcaassert(!(inb(ch->board->port) & FEPMEM), "Memory on");
}
@@ -398,185 +388,143 @@ static inline void pcxi_assertmemoff(struct channel *ch)
may or may not do anything.
---------------------------------------------------------------------------*/
-static inline void dummy_memwinon(struct board_info *b, unsigned int win)
+static void dummy_memwinon(struct board_info *b, unsigned int win)
{
}
-static inline void dummy_memwinoff(struct board_info *b, unsigned int win)
+static void dummy_memwinoff(struct board_info *b, unsigned int win)
{
}
-static inline void dummy_globalwinon(struct channel *ch)
+static void dummy_globalwinon(struct channel *ch)
{
}
-static inline void dummy_rxwinon(struct channel *ch)
+static void dummy_rxwinon(struct channel *ch)
{
}
-static inline void dummy_txwinon(struct channel *ch)
+static void dummy_txwinon(struct channel *ch)
{
}
-static inline void dummy_memoff(struct channel *ch)
+static void dummy_memoff(struct channel *ch)
{
}
-static inline void dummy_assertgwinon(struct channel *ch)
+static void dummy_assertgwinon(struct channel *ch)
{
}
-static inline void dummy_assertmemoff(struct channel *ch)
+static void dummy_assertmemoff(struct channel *ch)
{
}
/* ----------------- Begin verifyChannel function ----------------------- */
-static inline struct channel *verifyChannel(register struct tty_struct *tty)
+static struct channel *verifyChannel(struct tty_struct *tty)
{ /* Begin verifyChannel */
-
/* --------------------------------------------------------------------
This routine basically provides a sanity check. It insures that
the channel returned is within the proper range of addresses as
well as properly initialized. If some bogus info gets passed in
through tty->driver_data this should catch it.
- --------------------------------------------------------------------- */
-
- if (tty)
- { /* Begin if tty */
-
- register struct channel *ch = (struct channel *)tty->driver_data;
-
- if ((ch >= &digi_channels[0]) && (ch < &digi_channels[nbdevs]))
- {
+ --------------------------------------------------------------------- */
+ if (tty) {
+ struct channel *ch = (struct channel *)tty->driver_data;
+ if ((ch >= &digi_channels[0]) && (ch < &digi_channels[nbdevs])) {
if (ch->magic == EPCA_MAGIC)
return ch;
}
-
- } /* End if tty */
-
- /* Else return a NULL for invalid */
+ }
return NULL;
} /* End verifyChannel */
/* ------------------ Begin pc_sched_event ------------------------- */
-static inline void pc_sched_event(struct channel *ch, int event)
-{ /* Begin pc_sched_event */
-
-
+static void pc_sched_event(struct channel *ch, int event)
+{
/* ----------------------------------------------------------------------
We call this to schedule interrupt processing on some event. The
kernel sees our request and calls the related routine in OUR driver.
-------------------------------------------------------------------------*/
-
ch->event |= 1 << event;
schedule_work(&ch->tqueue);
-
-
} /* End pc_sched_event */
/* ------------------ Begin epca_error ------------------------- */
static void epca_error(int line, char *msg)
-{ /* Begin epca_error */
-
+{
printk(KERN_ERR "epca_error (Digi): line = %d %s\n",line,msg);
- return;
-
-} /* End epca_error */
+}
/* ------------------ Begin pc_close ------------------------- */
static void pc_close(struct tty_struct * tty, struct file * filp)
-{ /* Begin pc_close */
-
+{
struct channel *ch;
unsigned long flags;
-
/* ---------------------------------------------------------
verifyChannel returns the channel from the tty struct
if it is valid. This serves as a sanity check.
------------------------------------------------------------- */
-
- if ((ch = verifyChannel(tty)) != NULL)
- { /* Begin if ch != NULL */
-
- save_flags(flags);
- cli();
-
- if (tty_hung_up_p(filp))
- {
- restore_flags(flags);
+ if ((ch = verifyChannel(tty)) != NULL) { /* Begin if ch != NULL */
+ spin_lock_irqsave(&epca_lock, flags);
+ if (tty_hung_up_p(filp)) {
+ spin_unlock_irqrestore(&epca_lock, flags);
return;
}
-
/* Check to see if the channel is open more than once */
- if (ch->count-- > 1)
- { /* Begin channel is open more than once */
-
+ if (ch->count-- > 1) {
+ /* Begin channel is open more than once */
/* -------------------------------------------------------------
Return without doing anything. Someone might still be using
the channel.
---------------------------------------------------------------- */
-
- restore_flags(flags);
+ spin_unlock_irqrestore(&epca_lock, flags);
return;
} /* End channel is open more than once */
/* Port open only once go ahead with shutdown & reset */
-
- if (ch->count < 0)
- {
- ch->count = 0;
- }
+ if (ch->count < 0)
+ BUG();
/* ---------------------------------------------------------------
Let the rest of the driver know the channel is being closed.
This becomes important if an open is attempted before close
is finished.
------------------------------------------------------------------ */
-
ch->asyncflags |= ASYNC_CLOSING;
-
tty->closing = 1;
- if (ch->asyncflags & ASYNC_INITIALIZED)
- {
+ spin_unlock_irqrestore(&epca_lock, flags);
+
+ if (ch->asyncflags & ASYNC_INITIALIZED) {
/* Setup an event to indicate when the transmit buffer empties */
setup_empty_event(tty, ch);
tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */
}
-
if (tty->driver->flush_buffer)
tty->driver->flush_buffer(tty);
tty_ldisc_flush(tty);
shutdown(ch);
+
+ spin_lock_irqsave(&epca_lock, flags);
tty->closing = 0;
ch->event = 0;
ch->tty = NULL;
+ spin_unlock_irqrestore(&epca_lock, flags);
- if (ch->blocked_open)
- { /* Begin if blocked_open */
-
+ if (ch->blocked_open) { /* Begin if blocked_open */
if (ch->close_delay)
- {
msleep_interruptible(jiffies_to_msecs(ch->close_delay));
- }
-
wake_up_interruptible(&ch->open_wait);
-
} /* End if blocked_open */
-
ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED |
ASYNC_CLOSING);
wake_up_interruptible(&ch->close_wait);
-
-
- restore_flags(flags);
-
} /* End if ch != NULL */
-
} /* End pc_close */
/* ------------------ Begin shutdown ------------------------- */
@@ -586,15 +534,14 @@ static void shutdown(struct channel *ch)
unsigned long flags;
struct tty_struct *tty;
- volatile struct board_chan *bc;
+ struct board_chan __iomem *bc;
if (!(ch->asyncflags & ASYNC_INITIALIZED))
return;
- save_flags(flags);
- cli();
- globalwinon(ch);
+ spin_lock_irqsave(&epca_lock, flags);
+ globalwinon(ch);
bc = ch->brdchan;
/* ------------------------------------------------------------------
@@ -604,20 +551,17 @@ static void shutdown(struct channel *ch)
--------------------------------------------------------------------- */
if (bc)
- bc->idata = 0;
-
+ writeb(0, &bc->idata);
tty = ch->tty;
/* ----------------------------------------------------------------
If we're a modem control device and HUPCL is on, drop RTS & DTR.
------------------------------------------------------------------ */
- if (tty->termios->c_cflag & HUPCL)
- {
+ if (tty->termios->c_cflag & HUPCL) {
ch->omodem &= ~(ch->m_rts | ch->m_dtr);
fepcmd(ch, SETMODEM, 0, ch->m_dtr | ch->m_rts, 10, 1);
}
-
memoff(ch);
/* ------------------------------------------------------------------
@@ -628,7 +572,7 @@ static void shutdown(struct channel *ch)
/* Prevent future Digi programmed interrupts from coming active */
ch->asyncflags &= ~ASYNC_INITIALIZED;
- restore_flags(flags);
+ spin_unlock_irqrestore(&epca_lock, flags);
} /* End shutdown */
@@ -636,7 +580,6 @@ static void shutdown(struct channel *ch)
static void pc_hangup(struct tty_struct *tty)
{ /* Begin pc_hangup */
-
struct channel *ch;
/* ---------------------------------------------------------
@@ -644,25 +587,21 @@ static void pc_hangup(struct tty_struct *tty)
if it is valid. This serves as a sanity check.
------------------------------------------------------------- */
- if ((ch = verifyChannel(tty)) != NULL)
- { /* Begin if ch != NULL */
-
+ if ((ch = verifyChannel(tty)) != NULL) { /* Begin if ch != NULL */
unsigned long flags;
- save_flags(flags);
- cli();
if (tty->driver->flush_buffer)
tty->driver->flush_buffer(tty);
tty_ldisc_flush(tty);
shutdown(ch);
+ spin_lock_irqsave(&epca_lock, flags);
ch->tty = NULL;
ch->event = 0;
ch->count = 0;
- restore_flags(flags);
ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED);
+ spin_unlock_irqrestore(&epca_lock, flags);
wake_up_interruptible(&ch->open_wait);
-
} /* End if ch != NULL */
} /* End pc_hangup */
@@ -672,18 +611,14 @@ static void pc_hangup(struct tty_struct *tty)
static int pc_write(struct tty_struct * tty,
const unsigned char *buf, int bytesAvailable)
{ /* Begin pc_write */
-
- register unsigned int head, tail;
- register int dataLen;
- register int size;
- register int amountCopied;
-
-
+ unsigned int head, tail;
+ int dataLen;
+ int size;
+ int amountCopied;
struct channel *ch;
unsigned long flags;
int remain;
- volatile struct board_chan *bc;
-
+ struct board_chan __iomem *bc;
/* ----------------------------------------------------------------
pc_write is primarily called directly by the kernel routine
@@ -706,24 +641,20 @@ static int pc_write(struct tty_struct * tty,
bc = ch->brdchan;
size = ch->txbufsize;
-
amountCopied = 0;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&epca_lock, flags);
globalwinon(ch);
- head = bc->tin & (size - 1);
- tail = bc->tout;
+ head = readw(&bc->tin) & (size - 1);
+ tail = readw(&bc->tout);
- if (tail != bc->tout)
- tail = bc->tout;
+ if (tail != readw(&bc->tout))
+ tail = readw(&bc->tout);
tail &= (size - 1);
/* If head >= tail, head has not wrapped around. */
- if (head >= tail)
- { /* Begin head has not wrapped */
-
+ if (head >= tail) { /* Begin head has not wrapped */
/* ---------------------------------------------------------------
remain (much like dataLen above) represents the total amount of
space available on the card for data. Here dataLen represents
@@ -731,26 +662,19 @@ static int pc_write(struct tty_struct * tty,
buffer. This is important because a memcpy cannot be told to
automatically wrap around when it hits the buffer end.
------------------------------------------------------------------ */
-
dataLen = size - head;
remain = size - (head - tail) - 1;
-
- } /* End head has not wrapped */
- else
- { /* Begin head has wrapped around */
+ } else { /* Begin head has wrapped around */
remain = tail - head - 1;
dataLen = remain;
} /* End head has wrapped around */
-
/* -------------------------------------------------------------------
Check the space on the card. If we have more data than
space; reduce the amount of data to fit the space.
---------------------------------------------------------------------- */
-
bytesAvailable = min(remain, bytesAvailable);
-
txwinon(ch);
while (bytesAvailable > 0)
{ /* Begin while there is data to copy onto card */
@@ -761,32 +685,27 @@ static int pc_write(struct tty_struct * tty,
------------------------------------------------------------------- */
dataLen = min(bytesAvailable, dataLen);
- memcpy(ch->txptr + head, buf, dataLen);
+ memcpy_toio(ch->txptr + head, buf, dataLen);
buf += dataLen;
head += dataLen;
amountCopied += dataLen;
bytesAvailable -= dataLen;
- if (head >= size)
- {
+ if (head >= size) {
head = 0;
dataLen = tail;
}
-
} /* End while there is data to copy onto card */
-
ch->statusflags |= TXBUSY;
globalwinon(ch);
- bc->tin = head;
+ writew(head, &bc->tin);
- if ((ch->statusflags & LOWWAIT) == 0)
- {
+ if ((ch->statusflags & LOWWAIT) == 0) {
ch->statusflags |= LOWWAIT;
- bc->ilow = 1;
+ writeb(1, &bc->ilow);
}
memoff(ch);
- restore_flags(flags);
-
+ spin_unlock_irqrestore(&epca_lock, flags);
return(amountCopied);
} /* End pc_write */
@@ -795,11 +714,7 @@ static int pc_write(struct tty_struct * tty,
static void pc_put_char(struct tty_struct *tty, unsigned char c)
{ /* Begin pc_put_char */
-
-
pc_write(tty, &c, 1);
- return;
-
} /* End pc_put_char */
/* ------------------ Begin pc_write_room ------------------------- */
@@ -811,7 +726,7 @@ static int pc_write_room(struct tty_struct *tty)
struct channel *ch;
unsigned long flags;
unsigned int head, tail;
- volatile struct board_chan *bc;
+ struct board_chan __iomem *bc;
remain = 0;
@@ -820,33 +735,29 @@ static int pc_write_room(struct tty_struct *tty)
if it is valid. This serves as a sanity check.
------------------------------------------------------------- */
- if ((ch = verifyChannel(tty)) != NULL)
- {
- save_flags(flags);
- cli();
+ if ((ch = verifyChannel(tty)) != NULL) {
+ spin_lock_irqsave(&epca_lock, flags);
globalwinon(ch);
bc = ch->brdchan;
- head = bc->tin & (ch->txbufsize - 1);
- tail = bc->tout;
+ head = readw(&bc->tin) & (ch->txbufsize - 1);
+ tail = readw(&bc->tout);
- if (tail != bc->tout)
- tail = bc->tout;
+ if (tail != readw(&bc->tout))
+ tail = readw(&bc->tout);
/* Wrap tail if necessary */
tail &= (ch->txbufsize - 1);
if ((remain = tail - head - 1) < 0 )
remain += ch->txbufsize;
- if (remain && (ch->statusflags & LOWWAIT) == 0)
- {
+ if (remain && (ch->statusflags & LOWWAIT) == 0) {
ch->statusflags |= LOWWAIT;
- bc->ilow = 1;
+ writeb(1, &bc->ilow);
}
memoff(ch);
- restore_flags(flags);
+ spin_unlock_irqrestore(&epca_lock, flags);
}
-
/* Return how much room is left on card */
return remain;
@@ -862,8 +773,7 @@ static int pc_chars_in_buffer(struct tty_struct *tty)
int remain;
unsigned long flags;
struct channel *ch;
- volatile struct board_chan *bc;
-
+ struct board_chan __iomem *bc;
/* ---------------------------------------------------------
verifyChannel returns the channel from the tty struct
@@ -873,34 +783,27 @@ static int pc_chars_in_buffer(struct tty_struct *tty)
if ((ch = verifyChannel(tty)) == NULL)
return(0);
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&epca_lock, flags);
globalwinon(ch);
bc = ch->brdchan;
- tail = bc->tout;
- head = bc->tin;
- ctail = ch->mailbox->cout;
+ tail = readw(&bc->tout);
+ head = readw(&bc->tin);
+ ctail = readw(&ch->mailbox->cout);
- if (tail == head && ch->mailbox->cin == ctail && bc->tbusy == 0)
+ if (tail == head && readw(&ch->mailbox->cin) == ctail && readb(&bc->tbusy) == 0)
chars = 0;
- else
- { /* Begin if some space on the card has been used */
-
- head = bc->tin & (ch->txbufsize - 1);
+ else { /* Begin if some space on the card has been used */
+ head = readw(&bc->tin) & (ch->txbufsize - 1);
tail &= (ch->txbufsize - 1);
-
/* --------------------------------------------------------------
The logic here is basically opposite of the above pc_write_room
here we are finding the amount of bytes in the buffer filled.
Not the amount of bytes empty.
------------------------------------------------------------------- */
-
if ((remain = tail - head - 1) < 0 )
remain += ch->txbufsize;
-
chars = (int)(ch->txbufsize - remain);
-
/* -------------------------------------------------------------
Make it possible to wakeup anything waiting for output
in tty_ioctl.c, etc.
@@ -908,15 +811,12 @@ static int pc_chars_in_buffer(struct tty_struct *tty)
If not already set. Setup an event to indicate when the
transmit buffer empties
----------------------------------------------------------------- */
-
if (!(ch->statusflags & EMPTYWAIT))
setup_empty_event(tty,ch);
} /* End if some space on the card has been used */
-
memoff(ch);
- restore_flags(flags);
-
+ spin_unlock_irqrestore(&epca_lock, flags);
/* Return number of characters residing on card. */
return(chars);
@@ -930,67 +830,46 @@ static void pc_flush_buffer(struct tty_struct *tty)
unsigned int tail;
unsigned long flags;
struct channel *ch;
- volatile struct board_chan *bc;
-
-
+ struct board_chan __iomem *bc;
/* ---------------------------------------------------------
verifyChannel returns the channel from the tty struct
if it is valid. This serves as a sanity check.
------------------------------------------------------------- */
-
if ((ch = verifyChannel(tty)) == NULL)
return;
- save_flags(flags);
- cli();
-
+ spin_lock_irqsave(&epca_lock, flags);
globalwinon(ch);
-
bc = ch->brdchan;
- tail = bc->tout;
-
+ tail = readw(&bc->tout);
/* Have FEP move tout pointer; effectively flushing transmit buffer */
-
fepcmd(ch, STOUT, (unsigned) tail, 0, 0, 0);
-
memoff(ch);
- restore_flags(flags);
-
+ spin_unlock_irqrestore(&epca_lock, flags);
wake_up_interruptible(&tty->write_wait);
tty_wakeup(tty);
-
} /* End pc_flush_buffer */
/* ------------------ Begin pc_flush_chars ---------------------- */
static void pc_flush_chars(struct tty_struct *tty)
{ /* Begin pc_flush_chars */
-
struct channel * ch;
-
/* ---------------------------------------------------------
verifyChannel returns the channel from the tty struct
if it is valid. This serves as a sanity check.
------------------------------------------------------------- */
-
- if ((ch = verifyChannel(tty)) != NULL)
- {
+ if ((ch = verifyChannel(tty)) != NULL) {
unsigned long flags;
-
- save_flags(flags);
- cli();
-
+ spin_lock_irqsave(&epca_lock, flags);
/* ----------------------------------------------------------------
If not already set and the transmitter is busy setup an event
to indicate when the transmit empties.
------------------------------------------------------------------- */
-
if ((ch->statusflags & TXBUSY) && !(ch->statusflags & EMPTYWAIT))
setup_empty_event(tty,ch);
-
- restore_flags(flags);
+ spin_unlock_irqrestore(&epca_lock, flags);
}
-
} /* End pc_flush_chars */
/* ------------------ Begin block_til_ready ---------------------- */
@@ -998,14 +877,11 @@ static void pc_flush_chars(struct tty_struct *tty)
static int block_til_ready(struct tty_struct *tty,
struct file *filp, struct channel *ch)
{ /* Begin block_til_ready */
-
DECLARE_WAITQUEUE(wait,current);
int retval, do_clocal = 0;
unsigned long flags;
-
- if (tty_hung_up_p(filp))
- {
+ if (tty_hung_up_p(filp)) {
if (ch->asyncflags & ASYNC_HUP_NOTIFY)
retval = -EAGAIN;
else
@@ -1017,8 +893,7 @@ static int block_til_ready(struct tty_struct *tty,
If the device is in the middle of being closed, then block
until it's done, and then try again.
-------------------------------------------------------------------- */
- if (ch->asyncflags & ASYNC_CLOSING)
- {
+ if (ch->asyncflags & ASYNC_CLOSING) {
interruptible_sleep_on(&ch->close_wait);
if (ch->asyncflags & ASYNC_HUP_NOTIFY)
@@ -1027,43 +902,29 @@ static int block_til_ready(struct tty_struct *tty,
return -ERESTARTSYS;
}
- if (filp->f_flags & O_NONBLOCK)
- {
+ if (filp->f_flags & O_NONBLOCK) {
/* -----------------------------------------------------------------
If non-blocking mode is set, then make the check up front
and then exit.
-------------------------------------------------------------------- */
-
ch->asyncflags |= ASYNC_NORMAL_ACTIVE;
-
return 0;
}
-
-
if (tty->termios->c_cflag & CLOCAL)
do_clocal = 1;
-
- /* Block waiting for the carrier detect and the line to become free */
+ /* Block waiting for the carrier detect and the line to become free */
retval = 0;
add_wait_queue(&ch->open_wait, &wait);
- save_flags(flags);
- cli();
-
+ spin_lock_irqsave(&epca_lock, flags);
/* We dec count so that pc_close will know when to free things */
if (!tty_hung_up_p(filp))
ch->count--;
-
- restore_flags(flags);
-
ch->blocked_open++;
-
while(1)
{ /* Begin forever while */
-
set_current_state(TASK_INTERRUPTIBLE);
-
if (tty_hung_up_p(filp) ||
!(ch->asyncflags & ASYNC_INITIALIZED))
{
@@ -1073,17 +934,14 @@ static int block_til_ready(struct tty_struct *tty,
retval = -ERESTARTSYS;
break;
}
-
if (!(ch->asyncflags & ASYNC_CLOSING) &&
(do_clocal || (ch->imodem & ch->dcd)))
break;
-
- if (signal_pending(current))
- {
+ if (signal_pending(current)) {
retval = -ERESTARTSYS;
break;
}
-
+ spin_unlock_irqrestore(&epca_lock, flags);
/* ---------------------------------------------------------------
Allow someone else to be scheduled. We will occasionally go
through this loop until one of the above conditions change.
@@ -1091,25 +949,23 @@ static int block_til_ready(struct tty_struct *tty,
prevent this loop from hogging the cpu.
------------------------------------------------------------------ */
schedule();
+ spin_lock_irqsave(&epca_lock, flags);
} /* End forever while */
current->state = TASK_RUNNING;
remove_wait_queue(&ch->open_wait, &wait);
- cli();
if (!tty_hung_up_p(filp))
ch->count++;
- restore_flags(flags);
-
ch->blocked_open--;
+ spin_unlock_irqrestore(&epca_lock, flags);
+
if (retval)
return retval;
ch->asyncflags |= ASYNC_NORMAL_ACTIVE;
-
return 0;
-
} /* End block_til_ready */
/* ------------------ Begin pc_open ---------------------- */
@@ -1120,17 +976,12 @@ static int pc_open(struct tty_struct *tty, struct file * filp)
struct channel *ch;
unsigned long flags;
int line, retval, boardnum;
- volatile struct board_chan *bc;
- volatile unsigned int head;
+ struct board_chan __iomem *bc;
+ unsigned int head;
line = tty->index;
- if (line < 0 || line >= nbdevs)
- {
- printk(KERN_ERR "<Error> - pc_open : line out of range in pc_open\n");
- tty->driver_data = NULL;
- return(-ENODEV);
- }
-
+ if (line < 0 || line >= nbdevs)
+ return -ENODEV;
ch = &digi_channels[line];
boardnum = ch->boardnum;
@@ -1143,78 +994,61 @@ static int pc_open(struct tty_struct *tty, struct file * filp)
goes here.
---------------------------------------------------------------------- */
- if (invalid_lilo_config)
- {
+ if (invalid_lilo_config) {
if (setup_error_code & INVALID_BOARD_TYPE)
- printk(KERN_ERR "<Error> - pc_open: Invalid board type specified in LILO command\n");
-
+ printk(KERN_ERR "epca: pc_open: Invalid board type specified in kernel options.\n");
if (setup_error_code & INVALID_NUM_PORTS)
- printk(KERN_ERR "<Error> - pc_open: Invalid number of ports specified in LILO command\n");
-
+ printk(KERN_ERR "epca: pc_open: Invalid number of ports specified in kernel options.\n");
if (setup_error_code & INVALID_MEM_BASE)
- printk(KERN_ERR "<Error> - pc_open: Invalid board memory address specified in LILO command\n");
-
+ printk(KERN_ERR "epca: pc_open: Invalid board memory address specified in kernel options.\n");
if (setup_error_code & INVALID_PORT_BASE)
- printk(KERN_ERR "<Error> - pc_open: Invalid board port address specified in LILO command\n");
-
+ printk(KERN_ERR "epca; pc_open: Invalid board port address specified in kernel options.\n");
if (setup_error_code & INVALID_BOARD_STATUS)
- printk(KERN_ERR "<Error> - pc_open: Invalid board status specified in LILO command\n");
-
+ printk(KERN_ERR "epca: pc_open: Invalid board status specified in kernel options.\n");
if (setup_error_code & INVALID_ALTPIN)
- printk(KERN_ERR "<Error> - pc_open: Invalid board altpin specified in LILO command\n");
-
+ printk(KERN_ERR "epca: pc_open: Invalid board altpin specified in kernel options;\n");
tty->driver_data = NULL; /* Mark this device as 'down' */
- return(-ENODEV);
+ return -ENODEV;
}
-
- if ((boardnum >= num_cards) || (boards[boardnum].status == DISABLED))
- {
+ if (boardnum >= num_cards || boards[boardnum].status == DISABLED) {
tty->driver_data = NULL; /* Mark this device as 'down' */
return(-ENODEV);
}
- if (( bc = ch->brdchan) == 0)
- {
+ if ((bc = ch->brdchan) == 0) {
tty->driver_data = NULL;
- return(-ENODEV);
+ return -ENODEV;
}
+ spin_lock_irqsave(&epca_lock, flags);
/* ------------------------------------------------------------------
Every time a channel is opened, increment a counter. This is
necessary because we do not wish to flush and shutdown the channel
until the last app holding the channel open, closes it.
--------------------------------------------------------------------- */
-
ch->count++;
-
/* ----------------------------------------------------------------
Set a kernel structures pointer to our local channel
structure. This way we can get to it when passed only
a tty struct.
------------------------------------------------------------------ */
-
tty->driver_data = ch;
-
/* ----------------------------------------------------------------
If this is the first time the channel has been opened, initialize
the tty->termios struct otherwise let pc_close handle it.
-------------------------------------------------------------------- */
-
- save_flags(flags);
- cli();
-
globalwinon(ch);
ch->statusflags = 0;
/* Save boards current modem status */
- ch->imodem = bc->mstat;
+ ch->imodem = readb(&bc->mstat);
/* ----------------------------------------------------------------
Set receive head and tail ptrs to each other. This indicates
no data available to read.
----------------------------------------------------------------- */
- head = bc->rin;
- bc->rout = head;
+ head = readw(&bc->rin);
+ writew(head, &bc->rout);
/* Set the channels associated tty structure */
ch->tty = tty;
@@ -1224,122 +1058,74 @@ static int pc_open(struct tty_struct *tty, struct file * filp)
issues, etc.... It effect both control flags and input flags.
-------------------------------------------------------------------- */
epcaparam(tty,ch);
-
ch->asyncflags |= ASYNC_INITIALIZED;
memoff(ch);
-
- restore_flags(flags);
+ spin_unlock_irqrestore(&epca_lock, flags);
retval = block_til_ready(tty, filp, ch);
if (retval)
- {
return retval;
- }
-
/* -------------------------------------------------------------
Set this again in case a hangup set it to zero while this
open() was waiting for the line...
--------------------------------------------------------------- */
+ spin_lock_irqsave(&epca_lock, flags);
ch->tty = tty;
-
- save_flags(flags);
- cli();
globalwinon(ch);
-
/* Enable Digi Data events */
- bc->idata = 1;
-
+ writeb(1, &bc->idata);
memoff(ch);
- restore_flags(flags);
-
+ spin_unlock_irqrestore(&epca_lock, flags);
return 0;
-
} /* End pc_open */
-#ifdef MODULE
static int __init epca_module_init(void)
{ /* Begin init_module */
-
- unsigned long flags;
-
- save_flags(flags);
- cli();
-
- pc_init();
-
- restore_flags(flags);
-
- return(0);
+ return pc_init();
}
module_init(epca_module_init);
-#endif
-#ifdef ENABLE_PCI
static struct pci_driver epca_driver;
-#endif
-
-#ifdef MODULE
-/* -------------------- Begin cleanup_module ---------------------- */
static void __exit epca_module_exit(void)
{
-
int count, crd;
struct board_info *bd;
struct channel *ch;
- unsigned long flags;
del_timer_sync(&epca_timer);
- save_flags(flags);
- cli();
-
if ((tty_unregister_driver(pc_driver)) ||
(tty_unregister_driver(pc_info)))
{
- printk(KERN_WARNING "<Error> - DIGI : cleanup_module failed to un-register tty driver\n");
- restore_flags(flags);
+ printk(KERN_WARNING "epca: cleanup_module failed to un-register tty driver\n");
return;
}
put_tty_driver(pc_driver);
put_tty_driver(pc_info);
- for (crd = 0; crd < num_cards; crd++)
- { /* Begin for each card */
-
+ for (crd = 0; crd < num_cards; crd++) { /* Begin for each card */
bd = &boards[crd];
-
if (!bd)
{ /* Begin sanity check */
printk(KERN_ERR "<Error> - Digi : cleanup_module failed\n");
return;
} /* End sanity check */
-
- ch = card_ptr[crd];
-
+ ch = card_ptr[crd];
for (count = 0; count < bd->numports; count++, ch++)
{ /* Begin for each port */
-
- if (ch)
- {
+ if (ch) {
if (ch->tty)
tty_hangup(ch->tty);
kfree(ch->tmp_buf);
}
-
} /* End for each port */
} /* End for each card */
-
-#ifdef ENABLE_PCI
pci_unregister_driver (&epca_driver);
-#endif
-
- restore_flags(flags);
-
}
+
module_exit(epca_module_exit);
-#endif /* MODULE */
static struct tty_operations pc_ops = {
.open = pc_open,
@@ -1371,34 +1157,15 @@ static struct tty_operations info_ops = {
/* ------------------ Begin pc_init ---------------------- */
-int __init pc_init(void)
+static int __init pc_init(void)
{ /* Begin pc_init */
-
- /* ----------------------------------------------------------------
- pc_init is called by the operating system during boot up prior to
- any open calls being made. In the older versions of Linux (Prior
- to 2.0.0) an entry is made into tty_io.c. A pointer to the last
- memory location (from kernel space) used (kmem_start) is passed
- to pc_init. It is pc_inits responsibility to modify this value
- for any memory that the Digi driver might need and then return
- this value to the operating system. For example if the driver
- wishes to allocate 1K of kernel memory, pc_init would return
- (kmem_start + 1024). This memory (Between kmem_start and kmem_start
- + 1024) would then be available for use exclusively by the driver.
- In this case our driver does not allocate any of this kernel
- memory.
- ------------------------------------------------------------------*/
-
- ulong flags;
int crd;
struct board_info *bd;
unsigned char board_id = 0;
-#ifdef ENABLE_PCI
int pci_boards_found, pci_count;
pci_count = 0;
-#endif /* ENABLE_PCI */
pc_driver = alloc_tty_driver(MAX_ALLOC);
if (!pc_driver)
@@ -1416,8 +1183,7 @@ int __init pc_init(void)
Note : If LILO has ran epca_setup then epca_setup will handle defining
num_cards as well as copying the data into the board structure.
-------------------------------------------------------------------------- */
- if (!liloconfig)
- { /* Begin driver has been configured via. epcaconfig */
+ if (!liloconfig) { /* Begin driver has been configured via. epcaconfig */
nbdevs = NBDEVS;
num_cards = NUMCARDS;
@@ -1440,8 +1206,6 @@ int __init pc_init(void)
printk(KERN_INFO "DIGI epca driver version %s loaded.\n",VERSION);
-#ifdef ENABLE_PCI
-
/* ------------------------------------------------------------------
NOTE : This code assumes that the number of ports found in
the boards array is correct. This could be wrong if
@@ -1467,8 +1231,6 @@ int __init pc_init(void)
pci_boards_found += init_PCI();
num_cards += pci_boards_found;
-#endif /* ENABLE_PCI */
-
pc_driver->owner = THIS_MODULE;
pc_driver->name = "ttyD";
pc_driver->devfs_name = "tts/D";
@@ -1499,9 +1261,6 @@ int __init pc_init(void)
tty_set_operations(pc_info, &info_ops);
- save_flags(flags);
- cli();
-
for (crd = 0; crd < num_cards; crd++)
{ /* Begin for each card */
@@ -1610,11 +1369,7 @@ int __init pc_init(void)
if ((board_id & 0x30) == 0x30)
bd->memory_seg = 0x8000;
- } /* End it is an XI card */
- else
- {
- printk(KERN_ERR "<Error> - Board at 0x%x doesn't appear to be an XI\n",(int)bd->port);
- }
+ } else printk(KERN_ERR "epca: Board at 0x%x doesn't appear to be an XI\n",(int)bd->port);
break;
} /* End switch on bd->type */
@@ -1634,9 +1389,6 @@ int __init pc_init(void)
init_timer(&epca_timer);
epca_timer.function = epcapoll;
mod_timer(&epca_timer, jiffies + HZ/25);
-
- restore_flags(flags);
-
return 0;
} /* End pc_init */
@@ -1647,10 +1399,10 @@ static void post_fep_init(unsigned int crd)
{ /* Begin post_fep_init */
int i;
- unchar *memaddr;
- volatile struct global_data *gd;
+ void __iomem *memaddr;
+ struct global_data __iomem *gd;
struct board_info *bd;
- volatile struct board_chan *bc;
+ struct board_chan __iomem *bc;
struct channel *ch;
int shrinkmem = 0, lowwater ;
@@ -1669,9 +1421,7 @@ static void post_fep_init(unsigned int crd)
after DIGI_INIT has been called will return the proper values.
------------------------------------------------------------------- */
- if (bd->type >= PCIXEM) /* If the board in question is PCI */
- { /* Begin get PCI number of ports */
-
+ if (bd->type >= PCIXEM) { /* Begin get PCI number of ports */
/* --------------------------------------------------------------------
Below we use XEMPORTS as a memory offset regardless of which PCI
card it is. This is because all of the supported PCI cards have
@@ -1685,15 +1435,15 @@ static void post_fep_init(unsigned int crd)
(FYI - The id should be located at 0x1ac (And may use up to 4 bytes
if the box in question is a XEM or CX)).
------------------------------------------------------------------------ */
-
- bd->numports = (unsigned short)*(unsigned char *)bus_to_virt((unsigned long)
- (bd->re_map_membase + XEMPORTS));
-
-
+ /* PCI cards are already remapped at this point ISA are not */
+ bd->numports = readw(bd->re_map_membase + XEMPORTS);
epcaassert(bd->numports <= 64,"PCI returned a invalid number of ports");
nbdevs += (bd->numports);
-
- } /* End get PCI number of ports */
+ } else {
+ /* Fix up the mappings for ISA/EISA etc */
+ /* FIXME: 64K - can we be smarter ? */
+ bd->re_map_membase = ioremap(bd->membase, 0x10000);
+ }
if (crd != 0)
card_ptr[crd] = card_ptr[crd-1] + boards[crd-1].numports;
@@ -1701,19 +1451,9 @@ static void post_fep_init(unsigned int crd)
card_ptr[crd] = &digi_channels[crd]; /* <- For card 0 only */
ch = card_ptr[crd];
-
-
epcaassert(ch <= &digi_channels[nbdevs - 1], "ch out of range");
- memaddr = (unchar *)bd->re_map_membase;
-
- /*
- The below command is necessary because newer kernels (2.1.x and
- up) do not have a 1:1 virtual to physical mapping. The below
- call adjust for that.
- */
-
- memaddr = (unsigned char *)bus_to_virt((unsigned long)memaddr);
+ memaddr = bd->re_map_membase;
/* -----------------------------------------------------------------
The below assignment will set bc to point at the BEGINING of
@@ -1721,7 +1461,7 @@ static void post_fep_init(unsigned int crd)
8 and 64 of these structures.
-------------------------------------------------------------------- */
- bc = (volatile struct board_chan *)((ulong)memaddr + CHANSTRUCT);
+ bc = memaddr + CHANSTRUCT;
/* -------------------------------------------------------------------
The below assignment will set gd to point at the BEGINING of
@@ -1730,20 +1470,18 @@ static void post_fep_init(unsigned int crd)
pointer begins at 0xd10.
---------------------------------------------------------------------- */
- gd = (volatile struct global_data *)((ulong)memaddr + GLOBAL);
+ gd = memaddr + GLOBAL;
/* --------------------------------------------------------------------
XEPORTS (address 0xc22) points at the number of channels the
card supports. (For 64XE, XI, XEM, and XR use 0xc02)
----------------------------------------------------------------------- */
- if (((bd->type == PCXEVE) | (bd->type == PCXE)) &&
- (*(ushort *)((ulong)memaddr + XEPORTS) < 3))
+ if ((bd->type == PCXEVE || bd->type == PCXE) && (readw(memaddr + XEPORTS) < 3))
shrinkmem = 1;
if (bd->type < PCIXEM)
if (!request_region((int)bd->port, 4, board_desc[bd->type]))
return;
-
memwinon(bd, 0);
/* --------------------------------------------------------------------
@@ -1753,17 +1491,17 @@ static void post_fep_init(unsigned int crd)
/* For every port on the card do ..... */
- for (i = 0; i < bd->numports; i++, ch++, bc++)
- { /* Begin for each port */
+ for (i = 0; i < bd->numports; i++, ch++, bc++) { /* Begin for each port */
+ unsigned long flags;
+ u16 tseg, rseg;
ch->brdchan = bc;
ch->mailbox = gd;
INIT_WORK(&ch->tqueue, do_softint, ch);
ch->board = &boards[crd];
- switch (bd->type)
- { /* Begin switch bd->type */
-
+ spin_lock_irqsave(&epca_lock, flags);
+ switch (bd->type) {
/* ----------------------------------------------------------------
Since some of the boards use different bitmaps for their
control signals we cannot hard code these values and retain
@@ -1796,14 +1534,12 @@ static void post_fep_init(unsigned int crd)
} /* End switch bd->type */
- if (boards[crd].altpin)
- {
+ if (boards[crd].altpin) {
ch->dsr = ch->m_dcd;
ch->dcd = ch->m_dsr;
ch->digiext.digi_flags |= DIGI_ALTPIN;
}
- else
- {
+ else {
ch->dcd = ch->m_dcd;
ch->dsr = ch->m_dsr;
}
@@ -1813,57 +1549,58 @@ static void post_fep_init(unsigned int crd)
ch->magic = EPCA_MAGIC;
ch->tty = NULL;
- if (shrinkmem)
- {
+ if (shrinkmem) {
fepcmd(ch, SETBUFFER, 32, 0, 0, 0);
shrinkmem = 0;
}
- switch (bd->type)
- { /* Begin switch bd->type */
+ tseg = readw(&bc->tseg);
+ rseg = readw(&bc->rseg);
+
+ switch (bd->type) {
case PCIXEM:
case PCIXRJ:
case PCIXR:
/* Cover all the 2MEG cards */
- ch->txptr = memaddr + (((bc->tseg) << 4) & 0x1fffff);
- ch->rxptr = memaddr + (((bc->rseg) << 4) & 0x1fffff);
- ch->txwin = FEPWIN | ((bc->tseg) >> 11);
- ch->rxwin = FEPWIN | ((bc->rseg) >> 11);
+ ch->txptr = memaddr + ((tseg << 4) & 0x1fffff);
+ ch->rxptr = memaddr + ((rseg << 4) & 0x1fffff);
+ ch->txwin = FEPWIN | (tseg >> 11);
+ ch->rxwin = FEPWIN | (rseg >> 11);
break;
case PCXEM:
case EISAXEM:
/* Cover all the 32K windowed cards */
/* Mask equal to window size - 1 */
- ch->txptr = memaddr + (((bc->tseg) << 4) & 0x7fff);
- ch->rxptr = memaddr + (((bc->rseg) << 4) & 0x7fff);
- ch->txwin = FEPWIN | ((bc->tseg) >> 11);
- ch->rxwin = FEPWIN | ((bc->rseg) >> 11);
+ ch->txptr = memaddr + ((tseg << 4) & 0x7fff);
+ ch->rxptr = memaddr + ((rseg << 4) & 0x7fff);
+ ch->txwin = FEPWIN | (tseg >> 11);
+ ch->rxwin = FEPWIN | (rseg >> 11);
break;
case PCXEVE:
case PCXE:
- ch->txptr = memaddr + (((bc->tseg - bd->memory_seg) << 4) & 0x1fff);
- ch->txwin = FEPWIN | ((bc->tseg - bd->memory_seg) >> 9);
- ch->rxptr = memaddr + (((bc->rseg - bd->memory_seg) << 4) & 0x1fff);
- ch->rxwin = FEPWIN | ((bc->rseg - bd->memory_seg) >>9 );
+ ch->txptr = memaddr + (((tseg - bd->memory_seg) << 4) & 0x1fff);
+ ch->txwin = FEPWIN | ((tseg - bd->memory_seg) >> 9);
+ ch->rxptr = memaddr + (((rseg - bd->memory_seg) << 4) & 0x1fff);
+ ch->rxwin = FEPWIN | ((rseg - bd->memory_seg) >>9 );
break;
case PCXI:
case PC64XE:
- ch->txptr = memaddr + ((bc->tseg - bd->memory_seg) << 4);
- ch->rxptr = memaddr + ((bc->rseg - bd->memory_seg) << 4);
+ ch->txptr = memaddr + ((tseg - bd->memory_seg) << 4);
+ ch->rxptr = memaddr + ((rseg - bd->memory_seg) << 4);
ch->txwin = ch->rxwin = 0;
break;
} /* End switch bd->type */
ch->txbufhead = 0;
- ch->txbufsize = bc->tmax + 1;
+ ch->txbufsize = readw(&bc->tmax) + 1;
ch->rxbufhead = 0;
- ch->rxbufsize = bc->rmax + 1;
+ ch->rxbufsize = readw(&bc->rmax) + 1;
lowwater = ch->txbufsize >= 2000 ? 1024 : (ch->txbufsize / 2);
@@ -1878,13 +1615,13 @@ static void post_fep_init(unsigned int crd)
fepcmd(ch, SRXHWATER, (3 * ch->rxbufsize / 4), 0, 10, 0);
- bc->edelay = 100;
- bc->idata = 1;
+ writew(100, &bc->edelay);
+ writeb(1, &bc->idata);
- ch->startc = bc->startc;
- ch->stopc = bc->stopc;
- ch->startca = bc->startca;
- ch->stopca = bc->stopca;
+ ch->startc = readb(&bc->startc);
+ ch->stopc = readb(&bc->stopc);
+ ch->startca = readb(&bc->startca);
+ ch->stopca = readb(&bc->stopca);
ch->fepcflag = 0;
ch->fepiflag = 0;
@@ -1899,27 +1636,23 @@ static void post_fep_init(unsigned int crd)
ch->blocked_open = 0;
init_waitqueue_head(&ch->open_wait);
init_waitqueue_head(&ch->close_wait);
+
+ spin_unlock_irqrestore(&epca_lock, flags);
+
ch->tmp_buf = kmalloc(ch->txbufsize,GFP_KERNEL);
- if (!(ch->tmp_buf))
- {
+ if (!ch->tmp_buf) {
printk(KERN_ERR "POST FEP INIT : kmalloc failed for port 0x%x\n",i);
release_region((int)bd->port, 4);
while(i-- > 0)
kfree((ch--)->tmp_buf);
return;
- }
- else
+ } else
memset((void *)ch->tmp_buf,0,ch->txbufsize);
} /* End for each port */
printk(KERN_INFO
"Digi PC/Xx Driver V%s: %s I/O = 0x%lx Mem = 0x%lx Ports = %d\n",
VERSION, board_desc[bd->type], (long)bd->port, (long)bd->membase, bd->numports);
- sprintf(mesg,
- "Digi PC/Xx Driver V%s: %s I/O = 0x%lx Mem = 0x%lx Ports = %d\n",
- VERSION, board_desc[bd->type], (long)bd->port, (long)bd->membase, bd->numports);
- console_print(mesg);
-
memwinoff(bd, 0);
} /* End post_fep_init */
@@ -1943,9 +1676,6 @@ static void epcapoll(unsigned long ignored)
buffer empty) and acts on those events.
----------------------------------------------------------------------- */
- save_flags(flags);
- cli();
-
for (crd = 0; crd < num_cards; crd++)
{ /* Begin for each card */
@@ -1961,6 +1691,8 @@ static void epcapoll(unsigned long ignored)
some legacy boards.
---------------------------------------------------------------- */
+ spin_lock_irqsave(&epca_lock, flags);
+
assertmemoff(ch);
globalwinon(ch);
@@ -1970,21 +1702,19 @@ static void epcapoll(unsigned long ignored)
the transmit or receive queue.
------------------------------------------------------------------- */
- head = ch->mailbox->ein;
- tail = ch->mailbox->eout;
+ head = readw(&ch->mailbox->ein);
+ tail = readw(&ch->mailbox->eout);
/* If head isn't equal to tail we have an event */
if (head != tail)
doevent(crd);
-
memoff(ch);
- } /* End for each card */
+ spin_unlock_irqrestore(&epca_lock, flags);
+ } /* End for each card */
mod_timer(&epca_timer, jiffies + (HZ / 25));
-
- restore_flags(flags);
} /* End epcapoll */
/* --------------------- Begin doevent ------------------------ */
@@ -1992,53 +1722,42 @@ static void epcapoll(unsigned long ignored)
static void doevent(int crd)
{ /* Begin doevent */
- volatile unchar *eventbuf;
+ void __iomem *eventbuf;
struct channel *ch, *chan0;
static struct tty_struct *tty;
- volatile struct board_info *bd;
- volatile struct board_chan *bc;
- register volatile unsigned int tail, head;
- register int event, channel;
- register int mstat, lstat;
+ struct board_info *bd;
+ struct board_chan __iomem *bc;
+ unsigned int tail, head;
+ int event, channel;
+ int mstat, lstat;
/* -------------------------------------------------------------------
This subroutine is called by epcapoll when an event is detected
in the event queue. This routine responds to those events.
--------------------------------------------------------------------- */
-
bd = &boards[crd];
chan0 = card_ptr[crd];
epcaassert(chan0 <= &digi_channels[nbdevs - 1], "ch out of range");
-
assertgwinon(chan0);
-
- while ((tail = chan0->mailbox->eout) != (head = chan0->mailbox->ein))
+ while ((tail = readw(&chan0->mailbox->eout)) != (head = readw(&chan0->mailbox->ein)))
{ /* Begin while something in event queue */
-
assertgwinon(chan0);
-
- eventbuf = (volatile unchar *)bus_to_virt((ulong)(bd->re_map_membase + tail + ISTART));
-
+ eventbuf = bd->re_map_membase + tail + ISTART;
/* Get the channel the event occurred on */
- channel = eventbuf[0];
-
+ channel = readb(eventbuf);
/* Get the actual event code that occurred */
- event = eventbuf[1];
-
+ event = readb(eventbuf + 1);
/* ----------------------------------------------------------------
The two assignments below get the current modem status (mstat)
and the previous modem status (lstat). These are useful becuase
an event could signal a change in modem signals itself.
------------------------------------------------------------------- */
-
- mstat = eventbuf[2];
- lstat = eventbuf[3];
+ mstat = readb(eventbuf + 2);
+ lstat = readb(eventbuf + 3);
ch = chan0 + channel;
-
- if ((unsigned)channel >= bd->numports || !ch)
- {
+ if ((unsigned)channel >= bd->numports || !ch) {
if (channel >= bd->numports)
ch = chan0;
bc = ch->brdchan;
@@ -2048,97 +1767,53 @@ static void doevent(int crd)
if ((bc = ch->brdchan) == NULL)
goto next;
- if (event & DATA_IND)
- { /* Begin DATA_IND */
-
+ if (event & DATA_IND) { /* Begin DATA_IND */
receive_data(ch);
assertgwinon(ch);
-
} /* End DATA_IND */
/* else *//* Fix for DCD transition missed bug */
- if (event & MODEMCHG_IND)
- { /* Begin MODEMCHG_IND */
-
+ if (event & MODEMCHG_IND) { /* Begin MODEMCHG_IND */
/* A modem signal change has been indicated */
-
ch->imodem = mstat;
-
- if (ch->asyncflags & ASYNC_CHECK_CD)
- {
+ if (ch->asyncflags & ASYNC_CHECK_CD) {
if (mstat & ch->dcd) /* We are now receiving dcd */
wake_up_interruptible(&ch->open_wait);
else
pc_sched_event(ch, EPCA_EVENT_HANGUP); /* No dcd; hangup */
}
-
} /* End MODEMCHG_IND */
-
tty = ch->tty;
- if (tty)
- { /* Begin if valid tty */
-
- if (event & BREAK_IND)
- { /* Begin if BREAK_IND */
-
+ if (tty) { /* Begin if valid tty */
+ if (event & BREAK_IND) { /* Begin if BREAK_IND */
/* A break has been indicated */
-
tty->flip.count++;
*tty->flip.flag_buf_ptr++ = TTY_BREAK;
-
*tty->flip.char_buf_ptr++ = 0;
-
tty_schedule_flip(tty);
-
- } /* End if BREAK_IND */
- else
- if (event & LOWTX_IND)
- { /* Begin LOWTX_IND */
-
+ } else if (event & LOWTX_IND) { /* Begin LOWTX_IND */
if (ch->statusflags & LOWWAIT)
{ /* Begin if LOWWAIT */
-
ch->statusflags &= ~LOWWAIT;
tty_wakeup(tty);
wake_up_interruptible(&tty->write_wait);
-
} /* End if LOWWAIT */
-
- } /* End LOWTX_IND */
- else
- if (event & EMPTYTX_IND)
- { /* Begin EMPTYTX_IND */
-
+ } else if (event & EMPTYTX_IND) { /* Begin EMPTYTX_IND */
/* This event is generated by setup_empty_event */
-
ch->statusflags &= ~TXBUSY;
- if (ch->statusflags & EMPTYWAIT)
- { /* Begin if EMPTYWAIT */
-
+ if (ch->statusflags & EMPTYWAIT) { /* Begin if EMPTYWAIT */
ch->statusflags &= ~EMPTYWAIT;
tty_wakeup(tty);
-
wake_up_interruptible(&tty->write_wait);
-
} /* End if EMPTYWAIT */
-
} /* End EMPTYTX_IND */
-
} /* End if valid tty */
-
-
next:
globalwinon(ch);
-
- if (!bc)
- printk(KERN_ERR "<Error> - bc == NULL in doevent!\n");
- else
- bc->idata = 1;
-
- chan0->mailbox->eout = (tail + 4) & (IMAX - ISTART - 4);
+ BUG_ON(!bc);
+ writew(1, &bc->idata);
+ writew((tail + 4) & (IMAX - ISTART - 4), &chan0->mailbox->eout);
globalwinon(chan0);
-
} /* End while something in event queue */
-
} /* End doevent */
/* --------------------- Begin fepcmd ------------------------ */
@@ -2146,8 +1821,7 @@ static void doevent(int crd)
static void fepcmd(struct channel *ch, int cmd, int word_or_byte,
int byte2, int ncmds, int bytecmd)
{ /* Begin fepcmd */
-
- unchar *memaddr;
+ unchar __iomem *memaddr;
unsigned int head, cmdTail, cmdStart, cmdMax;
long count;
int n;
@@ -2155,93 +1829,57 @@ static void fepcmd(struct channel *ch, int cmd, int word_or_byte,
/* This is the routine in which commands may be passed to the card. */
if (ch->board->status == DISABLED)
- {
return;
- }
-
assertgwinon(ch);
-
/* Remember head (As well as max) is just an offset not a base addr */
- head = ch->mailbox->cin;
-
+ head = readw(&ch->mailbox->cin);
/* cmdStart is a base address */
- cmdStart = ch->mailbox->cstart;
-
+ cmdStart = readw(&ch->mailbox->cstart);
/* ------------------------------------------------------------------
We do the addition below because we do not want a max pointer
relative to cmdStart. We want a max pointer that points at the
physical end of the command queue.
-------------------------------------------------------------------- */
-
- cmdMax = (cmdStart + 4 + (ch->mailbox->cmax));
-
+ cmdMax = (cmdStart + 4 + readw(&ch->mailbox->cmax));
memaddr = ch->board->re_map_membase;
- /*
- The below command is necessary because newer kernels (2.1.x and
- up) do not have a 1:1 virtual to physical mapping. The below
- call adjust for that.
- */
-
- memaddr = (unsigned char *)bus_to_virt((unsigned long)memaddr);
-
- if (head >= (cmdMax - cmdStart) || (head & 03))
- {
- printk(KERN_ERR "line %d: Out of range, cmd = %x, head = %x\n", __LINE__,
- cmd, head);
- printk(KERN_ERR "line %d: Out of range, cmdMax = %x, cmdStart = %x\n", __LINE__,
- cmdMax, cmdStart);
+ if (head >= (cmdMax - cmdStart) || (head & 03)) {
+ printk(KERN_ERR "line %d: Out of range, cmd = %x, head = %x\n", __LINE__, cmd, head);
+ printk(KERN_ERR "line %d: Out of range, cmdMax = %x, cmdStart = %x\n", __LINE__, cmdMax, cmdStart);
return;
}
-
- if (bytecmd)
- {
- *(volatile unchar *)(memaddr + head + cmdStart + 0) = (unchar)cmd;
-
- *(volatile unchar *)(memaddr + head + cmdStart + 1) = (unchar)ch->channelnum;
+ if (bytecmd) {
+ writeb(cmd, memaddr + head + cmdStart + 0);
+ writeb(ch->channelnum, memaddr + head + cmdStart + 1);
/* Below word_or_byte is bits to set */
- *(volatile unchar *)(memaddr + head + cmdStart + 2) = (unchar)word_or_byte;
+ writeb(word_or_byte, memaddr + head + cmdStart + 2);
/* Below byte2 is bits to reset */
- *(volatile unchar *)(memaddr + head + cmdStart + 3) = (unchar)byte2;
-
- }
- else
- {
- *(volatile unchar *)(memaddr + head + cmdStart + 0) = (unchar)cmd;
- *(volatile unchar *)(memaddr + head + cmdStart + 1) = (unchar)ch->channelnum;
- *(volatile ushort*)(memaddr + head + cmdStart + 2) = (ushort)word_or_byte;
+ writeb(byte2, memaddr + head + cmdStart + 3);
+ } else {
+ writeb(cmd, memaddr + head + cmdStart + 0);
+ writeb(ch->channelnum, memaddr + head + cmdStart + 1);
+ writeb(word_or_byte, memaddr + head + cmdStart + 2);
}
-
head = (head + 4) & (cmdMax - cmdStart - 4);
- ch->mailbox->cin = head;
-
+ writew(head, &ch->mailbox->cin);
count = FEPTIMEOUT;
- for (;;)
- { /* Begin forever loop */
-
+ for (;;) { /* Begin forever loop */
count--;
- if (count == 0)
- {
+ if (count == 0) {
printk(KERN_ERR "<Error> - Fep not responding in fepcmd()\n");
return;
}
-
- head = ch->mailbox->cin;
- cmdTail = ch->mailbox->cout;
-
+ head = readw(&ch->mailbox->cin);
+ cmdTail = readw(&ch->mailbox->cout);
n = (head - cmdTail) & (cmdMax - cmdStart - 4);
-
/* ----------------------------------------------------------
Basically this will break when the FEP acknowledges the
command by incrementing cmdTail (Making it equal to head).
------------------------------------------------------------- */
-
if (n <= ncmds * (sizeof(short) * 4))
break; /* Well nearly forever :-) */
-
} /* End forever loop */
-
} /* End fepcmd */
/* ---------------------------------------------------------------------
@@ -2255,11 +1893,9 @@ static void fepcmd(struct channel *ch, int cmd, int word_or_byte,
static unsigned termios2digi_h(struct channel *ch, unsigned cflag)
{ /* Begin termios2digi_h */
-
unsigned res = 0;
- if (cflag & CRTSCTS)
- {
+ if (cflag & CRTSCTS) {
ch->digiext.digi_flags |= (RTSPACE | CTSPACE);
res |= ((ch->m_cts) | (ch->m_rts));
}
@@ -2295,7 +1931,6 @@ static unsigned termios2digi_i(struct channel *ch, unsigned iflag)
unsigned res = iflag & (IGNBRK | BRKINT | IGNPAR | PARMRK |
INPCK | ISTRIP|IXON|IXANY|IXOFF);
-
if (ch->digiext.digi_flags & DIGI_AIXON)
res |= IAIXON;
return res;
@@ -2308,28 +1943,15 @@ static unsigned termios2digi_c(struct channel *ch, unsigned cflag)
{ /* Begin termios2digi_c */
unsigned res = 0;
-
-#ifdef SPEED_HACK
- /* CL: HACK to force 115200 at 38400 and 57600 at 19200 Baud */
- if ((cflag & CBAUD)== B38400) cflag=cflag - B38400 + B115200;
- if ((cflag & CBAUD)== B19200) cflag=cflag - B19200 + B57600;
-#endif /* SPEED_HACK */
-
- if (cflag & CBAUDEX)
- { /* Begin detected CBAUDEX */
-
+ if (cflag & CBAUDEX) { /* Begin detected CBAUDEX */
ch->digiext.digi_flags |= DIGI_FAST;
-
/* -------------------------------------------------------------
HUPCL bit is used by FEP to indicate fast baud
table is to be used.
----------------------------------------------------------------- */
-
res |= FEP_HUPCL;
-
} /* End detected CBAUDEX */
else ch->digiext.digi_flags &= ~DIGI_FAST;
-
/* -------------------------------------------------------------------
CBAUD has bit position 0x1000 set these days to indicate Linux
baud rate remap. Digi hardware can't handle the bit assignment.
@@ -2337,7 +1959,6 @@ static unsigned termios2digi_c(struct channel *ch, unsigned cflag)
bit out.
---------------------------------------------------------------------- */
res |= cflag & ((CBAUD ^ CBAUDEX) | PARODD | PARENB | CSTOPB | CSIZE);
-
/* -------------------------------------------------------------
This gets a little confusing. The Digi cards have their own
representation of c_cflags controling baud rate. For the most
@@ -2357,10 +1978,8 @@ static unsigned termios2digi_c(struct channel *ch, unsigned cflag)
should be checked for a screened out prior to termios2digi_c
returning. Since CLOCAL isn't used by the board this can be
ignored as long as the returned value is used only by Digi hardware.
- ----------------------------------------------------------------- */
-
- if (cflag & CBAUDEX)
- {
+ ----------------------------------------------------------------- */
+ if (cflag & CBAUDEX) {
/* -------------------------------------------------------------
The below code is trying to guarantee that only baud rates
115200 and 230400 are remapped. We use exclusive or because
@@ -2371,138 +1990,96 @@ static unsigned termios2digi_c(struct channel *ch, unsigned cflag)
if ((!((cflag & 0x7) ^ (B115200 & ~CBAUDEX))) ||
(!((cflag & 0x7) ^ (B230400 & ~CBAUDEX))))
- {
res += 1;
- }
}
-
return res;
} /* End termios2digi_c */
/* --------------------- Begin epcaparam ----------------------- */
+/* Caller must hold the locks */
static void epcaparam(struct tty_struct *tty, struct channel *ch)
{ /* Begin epcaparam */
unsigned int cmdHead;
struct termios *ts;
- volatile struct board_chan *bc;
+ struct board_chan __iomem *bc;
unsigned mval, hflow, cflag, iflag;
bc = ch->brdchan;
epcaassert(bc !=0, "bc out of range");
assertgwinon(ch);
-
ts = tty->termios;
-
- if ((ts->c_cflag & CBAUD) == 0)
- { /* Begin CBAUD detected */
-
- cmdHead = bc->rin;
- bc->rout = cmdHead;
- cmdHead = bc->tin;
-
+ if ((ts->c_cflag & CBAUD) == 0) { /* Begin CBAUD detected */
+ cmdHead = readw(&bc->rin);
+ writew(cmdHead, &bc->rout);
+ cmdHead = readw(&bc->tin);
/* Changing baud in mid-stream transmission can be wonderful */
/* ---------------------------------------------------------------
Flush current transmit buffer by setting cmdTail pointer (tout)
to cmdHead pointer (tin). Hopefully the transmit buffer is empty.
----------------------------------------------------------------- */
-
fepcmd(ch, STOUT, (unsigned) cmdHead, 0, 0, 0);
mval = 0;
-
- } /* End CBAUD detected */
- else
- { /* Begin CBAUD not detected */
-
+ } else { /* Begin CBAUD not detected */
/* -------------------------------------------------------------------
c_cflags have changed but that change had nothing to do with BAUD.
Propagate the change to the card.
---------------------------------------------------------------------- */
-
cflag = termios2digi_c(ch, ts->c_cflag);
-
- if (cflag != ch->fepcflag)
- {
+ if (cflag != ch->fepcflag) {
ch->fepcflag = cflag;
/* Set baud rate, char size, stop bits, parity */
fepcmd(ch, SETCTRLFLAGS, (unsigned) cflag, 0, 0, 0);
}
-
-
/* ----------------------------------------------------------------
If the user has not forced CLOCAL and if the device is not a
CALLOUT device (Which is always CLOCAL) we set flags such that
the driver will wait on carrier detect.
------------------------------------------------------------------- */
-
if (ts->c_cflag & CLOCAL)
- { /* Begin it is a cud device or a ttyD device with CLOCAL on */
ch->asyncflags &= ~ASYNC_CHECK_CD;
- } /* End it is a cud device or a ttyD device with CLOCAL on */
else
- { /* Begin it is a ttyD device */
ch->asyncflags |= ASYNC_CHECK_CD;
- } /* End it is a ttyD device */
-
mval = ch->m_dtr | ch->m_rts;
-
} /* End CBAUD not detected */
-
iflag = termios2digi_i(ch, ts->c_iflag);
-
/* Check input mode flags */
-
- if (iflag != ch->fepiflag)
- {
+ if (iflag != ch->fepiflag) {
ch->fepiflag = iflag;
-
/* ---------------------------------------------------------------
Command sets channels iflag structure on the board. Such things
as input soft flow control, handling of parity errors, and
break handling are all set here.
------------------------------------------------------------------- */
-
/* break handling, parity handling, input stripping, flow control chars */
fepcmd(ch, SETIFLAGS, (unsigned int) ch->fepiflag, 0, 0, 0);
}
-
/* ---------------------------------------------------------------
Set the board mint value for this channel. This will cause hardware
events to be generated each time the DCD signal (Described in mint)
changes.
------------------------------------------------------------------- */
- bc->mint = ch->dcd;
-
+ writeb(ch->dcd, &bc->mint);
if ((ts->c_cflag & CLOCAL) || (ch->digiext.digi_flags & DIGI_FORCEDCD))
if (ch->digiext.digi_flags & DIGI_FORCEDCD)
- bc->mint = 0;
-
- ch->imodem = bc->mstat;
-
+ writeb(0, &bc->mint);
+ ch->imodem = readb(&bc->mstat);
hflow = termios2digi_h(ch, ts->c_cflag);
-
- if (hflow != ch->hflow)
- {
+ if (hflow != ch->hflow) {
ch->hflow = hflow;
-
/* --------------------------------------------------------------
Hard flow control has been selected but the board is not
using it. Activate hard flow control now.
----------------------------------------------------------------- */
-
fepcmd(ch, SETHFLOW, hflow, 0xff, 0, 1);
}
-
-
mval ^= ch->modemfake & (mval ^ ch->modem);
- if (ch->omodem ^ mval)
- {
+ if (ch->omodem ^ mval) {
ch->omodem = mval;
-
/* --------------------------------------------------------------
The below command sets the DTR and RTS mstat structure. If
hard flow control is NOT active these changes will drive the
@@ -2514,87 +2091,65 @@ static void epcaparam(struct tty_struct *tty, struct channel *ch)
/* First reset DTR & RTS; then set them */
fepcmd(ch, SETMODEM, 0, ((ch->m_dtr)|(ch->m_rts)), 0, 1);
fepcmd(ch, SETMODEM, mval, 0, 0, 1);
-
}
-
- if (ch->startc != ch->fepstartc || ch->stopc != ch->fepstopc)
- {
+ if (ch->startc != ch->fepstartc || ch->stopc != ch->fepstopc) {
ch->fepstartc = ch->startc;
ch->fepstopc = ch->stopc;
-
/* ------------------------------------------------------------
The XON / XOFF characters have changed; propagate these
changes to the card.
--------------------------------------------------------------- */
-
fepcmd(ch, SONOFFC, ch->fepstartc, ch->fepstopc, 0, 1);
}
-
- if (ch->startca != ch->fepstartca || ch->stopca != ch->fepstopca)
- {
+ if (ch->startca != ch->fepstartca || ch->stopca != ch->fepstopca) {
ch->fepstartca = ch->startca;
ch->fepstopca = ch->stopca;
-
/* ---------------------------------------------------------------
Similar to the above, this time the auxilarly XON / XOFF
characters have changed; propagate these changes to the card.
------------------------------------------------------------------ */
-
fepcmd(ch, SAUXONOFFC, ch->fepstartca, ch->fepstopca, 0, 1);
}
-
} /* End epcaparam */
/* --------------------- Begin receive_data ----------------------- */
-
+/* Caller holds lock */
static void receive_data(struct channel *ch)
{ /* Begin receive_data */
unchar *rptr;
struct termios *ts = NULL;
struct tty_struct *tty;
- volatile struct board_chan *bc;
- register int dataToRead, wrapgap, bytesAvailable;
- register unsigned int tail, head;
+ struct board_chan __iomem *bc;
+ int dataToRead, wrapgap, bytesAvailable;
+ unsigned int tail, head;
unsigned int wrapmask;
int rc;
-
/* ---------------------------------------------------------------
This routine is called by doint when a receive data event
has taken place.
------------------------------------------------------------------- */
globalwinon(ch);
-
if (ch->statusflags & RXSTOPPED)
return;
-
tty = ch->tty;
if (tty)
ts = tty->termios;
-
bc = ch->brdchan;
-
- if (!bc)
- {
- printk(KERN_ERR "<Error> - bc is NULL in receive_data!\n");
- return;
- }
-
+ BUG_ON(!bc);
wrapmask = ch->rxbufsize - 1;
/* ---------------------------------------------------------------------
Get the head and tail pointers to the receiver queue. Wrap the
head pointer if it has reached the end of the buffer.
------------------------------------------------------------------------ */
-
- head = bc->rin;
+ head = readw(&bc->rin);
head &= wrapmask;
- tail = bc->rout & wrapmask;
+ tail = readw(&bc->rout) & wrapmask;
bytesAvailable = (head - tail) & wrapmask;
-
if (bytesAvailable == 0)
return;
@@ -2602,73 +2157,53 @@ static void receive_data(struct channel *ch)
If CREAD bit is off or device not open, set TX tail to head
--------------------------------------------------------------------- */
- if (!tty || !ts || !(ts->c_cflag & CREAD))
- {
- bc->rout = head;
+ if (!tty || !ts || !(ts->c_cflag & CREAD)) {
+ writew(head, &bc->rout);
return;
}
if (tty->flip.count == TTY_FLIPBUF_SIZE)
return;
- if (bc->orun)
- {
- bc->orun = 0;
- printk(KERN_WARNING "overrun! DigiBoard device %s\n",tty->name);
+ if (readb(&bc->orun)) {
+ writeb(0, &bc->orun);
+ printk(KERN_WARNING "epca; overrun! DigiBoard device %s\n",tty->name);
}
-
rxwinon(ch);
rptr = tty->flip.char_buf_ptr;
rc = tty->flip.count;
-
- while (bytesAvailable > 0)
- { /* Begin while there is data on the card */
-
+ while (bytesAvailable > 0) { /* Begin while there is data on the card */
wrapgap = (head >= tail) ? head - tail : ch->rxbufsize - tail;
-
/* ---------------------------------------------------------------
Even if head has wrapped around only report the amount of
data to be equal to the size - tail. Remember memcpy can't
automaticly wrap around the receive buffer.
----------------------------------------------------------------- */
-
dataToRead = (wrapgap < bytesAvailable) ? wrapgap : bytesAvailable;
-
/* --------------------------------------------------------------
Make sure we don't overflow the buffer
----------------------------------------------------------------- */
-
if ((rc + dataToRead) > TTY_FLIPBUF_SIZE)
dataToRead = TTY_FLIPBUF_SIZE - rc;
-
if (dataToRead == 0)
break;
-
/* ---------------------------------------------------------------
Move data read from our card into the line disciplines buffer
for translation if necessary.
------------------------------------------------------------------ */
-
- if ((memcpy(rptr, ch->rxptr + tail, dataToRead)) != rptr)
- printk(KERN_ERR "<Error> - receive_data : memcpy failed\n");
-
+ memcpy_fromio(rptr, ch->rxptr + tail, dataToRead);
rc += dataToRead;
rptr += dataToRead;
tail = (tail + dataToRead) & wrapmask;
bytesAvailable -= dataToRead;
-
} /* End while there is data on the card */
-
-
tty->flip.count = rc;
tty->flip.char_buf_ptr = rptr;
globalwinon(ch);
- bc->rout = tail;
-
+ writew(tail, &bc->rout);
/* Must be called with global data */
tty_schedule_flip(ch->tty);
return;
-
} /* End receive_data */
static int info_ioctl(struct tty_struct *tty, struct file * file,
@@ -2676,17 +2211,15 @@ static int info_ioctl(struct tty_struct *tty, struct file * file,
{
switch (cmd)
{ /* Begin switch cmd */
-
case DIGI_GETINFO:
{ /* Begin case DIGI_GETINFO */
-
struct digi_info di ;
int brd;
- getUser(brd, (unsigned int __user *)arg);
-
- if ((brd < 0) || (brd >= num_cards) || (num_cards == 0))
- return (-ENODEV);
+ if(get_user(brd, (unsigned int __user *)arg))
+ return -EFAULT;
+ if (brd < 0 || brd >= num_cards || num_cards == 0)
+ return -ENODEV;
memset(&di, 0, sizeof(di));
@@ -2694,8 +2227,9 @@ static int info_ioctl(struct tty_struct *tty, struct file * file,
di.status = boards[brd].status;
di.type = boards[brd].type ;
di.numports = boards[brd].numports ;
- di.port = boards[brd].port ;
- di.membase = boards[brd].membase ;
+ /* Legacy fixups - just move along nothing to see */
+ di.port = (unsigned char *)boards[brd].port ;
+ di.membase = (unsigned char *)boards[brd].membase ;
if (copy_to_user((void __user *)arg, &di, sizeof (di)))
return -EFAULT;
@@ -2709,39 +2243,29 @@ static int info_ioctl(struct tty_struct *tty, struct file * file,
int brd = arg & 0xff000000 >> 16 ;
unsigned char state = arg & 0xff ;
- if ((brd < 0) || (brd >= num_cards))
- {
- printk(KERN_ERR "<Error> - DIGI POLLER : brd not valid!\n");
+ if (brd < 0 || brd >= num_cards) {
+ printk(KERN_ERR "epca: DIGI POLLER : brd not valid!\n");
return (-ENODEV);
}
-
digi_poller_inhibited = state ;
break ;
-
} /* End case DIGI_POLLER */
case DIGI_INIT:
{ /* Begin case DIGI_INIT */
-
/* ------------------------------------------------------------
This call is made by the apps to complete the initilization
of the board(s). This routine is responsible for setting
the card to its initial state and setting the drivers control
fields to the sutianle settings for the card in question.
---------------------------------------------------------------- */
-
int crd ;
for (crd = 0; crd < num_cards; crd++)
post_fep_init (crd);
-
break ;
-
} /* End case DIGI_INIT */
-
-
default:
- return -ENOIOCTLCMD;
-
+ return -ENOTTY;
} /* End switch cmd */
return (0) ;
}
@@ -2750,43 +2274,33 @@ static int info_ioctl(struct tty_struct *tty, struct file * file,
static int pc_tiocmget(struct tty_struct *tty, struct file *file)
{
struct channel *ch = (struct channel *) tty->driver_data;
- volatile struct board_chan *bc;
+ struct board_chan __iomem *bc;
unsigned int mstat, mflag = 0;
unsigned long flags;
if (ch)
bc = ch->brdchan;
else
- {
- printk(KERN_ERR "<Error> - ch is NULL in pc_tiocmget!\n");
- return(-EINVAL);
- }
+ return -EINVAL;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&epca_lock, flags);
globalwinon(ch);
- mstat = bc->mstat;
+ mstat = readb(&bc->mstat);
memoff(ch);
- restore_flags(flags);
+ spin_unlock_irqrestore(&epca_lock, flags);
if (mstat & ch->m_dtr)
mflag |= TIOCM_DTR;
-
if (mstat & ch->m_rts)
mflag |= TIOCM_RTS;
-
if (mstat & ch->m_cts)
mflag |= TIOCM_CTS;
-
if (mstat & ch->dsr)
mflag |= TIOCM_DSR;
-
if (mstat & ch->m_ri)
mflag |= TIOCM_RI;
-
if (mstat & ch->dcd)
mflag |= TIOCM_CD;
-
return mflag;
}
@@ -2796,13 +2310,10 @@ static int pc_tiocmset(struct tty_struct *tty, struct file *file,
struct channel *ch = (struct channel *) tty->driver_data;
unsigned long flags;
- if (!ch) {
- printk(KERN_ERR "<Error> - ch is NULL in pc_tiocmset!\n");
- return(-EINVAL);
- }
+ if (!ch)
+ return -EINVAL;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&epca_lock, flags);
/*
* I think this modemfake stuff is broken. It doesn't
* correctly reflect the behaviour desired by the TIOCM*
@@ -2824,17 +2335,14 @@ static int pc_tiocmset(struct tty_struct *tty, struct file *file,
ch->modemfake |= ch->m_dtr;
ch->modem &= ~ch->m_dtr;
}
-
globalwinon(ch);
-
/* --------------------------------------------------------------
The below routine generally sets up parity, baud, flow control
issues, etc.... It effect both control flags and input flags.
------------------------------------------------------------------ */
-
epcaparam(tty,ch);
memoff(ch);
- restore_flags(flags);
+ spin_unlock_irqrestore(&epca_lock, flags);
return 0;
}
@@ -2847,19 +2355,14 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file,
unsigned long flags;
unsigned int mflag, mstat;
unsigned char startc, stopc;
- volatile struct board_chan *bc;
+ struct board_chan __iomem *bc;
struct channel *ch = (struct channel *) tty->driver_data;
void __user *argp = (void __user *)arg;
if (ch)
bc = ch->brdchan;
else
- {
- printk(KERN_ERR "<Error> - ch is NULL in pc_ioctl!\n");
- return(-EINVAL);
- }
-
- save_flags(flags);
+ return -EINVAL;
/* -------------------------------------------------------------------
For POSIX compliance we need to add more ioctls. See tty_ioctl.c
@@ -2871,46 +2374,39 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file,
{ /* Begin switch cmd */
case TCGETS:
- if (copy_to_user(argp,
- tty->termios, sizeof(struct termios)))
+ if (copy_to_user(argp, tty->termios, sizeof(struct termios)))
return -EFAULT;
- return(0);
-
+ return 0;
case TCGETA:
return get_termio(tty, argp);
-
case TCSBRK: /* SVID version: non-zero arg --> no break */
-
retval = tty_check_change(tty);
if (retval)
return retval;
-
/* Setup an event to indicate when the transmit buffer empties */
-
+ spin_lock_irqsave(&epca_lock, flags);
setup_empty_event(tty,ch);
+ spin_unlock_irqrestore(&epca_lock, flags);
tty_wait_until_sent(tty, 0);
if (!arg)
digi_send_break(ch, HZ/4); /* 1/4 second */
return 0;
-
case TCSBRKP: /* support for POSIX tcsendbreak() */
-
retval = tty_check_change(tty);
if (retval)
return retval;
/* Setup an event to indicate when the transmit buffer empties */
-
+ spin_lock_irqsave(&epca_lock, flags);
setup_empty_event(tty,ch);
+ spin_unlock_irqrestore(&epca_lock, flags);
tty_wait_until_sent(tty, 0);
digi_send_break(ch, arg ? arg*(HZ/10) : HZ/4);
return 0;
-
case TIOCGSOFTCAR:
if (put_user(C_CLOCAL(tty)?1:0, (unsigned long __user *)arg))
return -EFAULT;
return 0;
-
case TIOCSSOFTCAR:
{
unsigned int value;
@@ -2922,75 +2418,63 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file,
(value ? CLOCAL : 0));
return 0;
}
-
case TIOCMODG:
mflag = pc_tiocmget(tty, file);
if (put_user(mflag, (unsigned long __user *)argp))
return -EFAULT;
break;
-
case TIOCMODS:
if (get_user(mstat, (unsigned __user *)argp))
return -EFAULT;
return pc_tiocmset(tty, file, mstat, ~mstat);
-
case TIOCSDTR:
+ spin_lock_irqsave(&epca_lock, flags);
ch->omodem |= ch->m_dtr;
- cli();
globalwinon(ch);
fepcmd(ch, SETMODEM, ch->m_dtr, 0, 10, 1);
memoff(ch);
- restore_flags(flags);
+ spin_unlock_irqrestore(&epca_lock, flags);
break;
case TIOCCDTR:
+ spin_lock_irqsave(&epca_lock, flags);
ch->omodem &= ~ch->m_dtr;
- cli();
globalwinon(ch);
fepcmd(ch, SETMODEM, 0, ch->m_dtr, 10, 1);
memoff(ch);
- restore_flags(flags);
+ spin_unlock_irqrestore(&epca_lock, flags);
break;
-
case DIGI_GETA:
if (copy_to_user(argp, &ch->digiext, sizeof(digi_t)))
return -EFAULT;
break;
-
case DIGI_SETAW:
case DIGI_SETAF:
- if ((cmd) == (DIGI_SETAW))
- {
+ if (cmd == DIGI_SETAW) {
/* Setup an event to indicate when the transmit buffer empties */
-
+ spin_lock_irqsave(&epca_lock, flags);
setup_empty_event(tty,ch);
+ spin_unlock_irqrestore(&epca_lock, flags);
tty_wait_until_sent(tty, 0);
- }
- else
- {
+ } else {
/* ldisc lock already held in ioctl */
if (tty->ldisc.flush_buffer)
tty->ldisc.flush_buffer(tty);
}
-
/* Fall Thru */
-
case DIGI_SETA:
if (copy_from_user(&ch->digiext, argp, sizeof(digi_t)))
return -EFAULT;
- if (ch->digiext.digi_flags & DIGI_ALTPIN)
- {
+ if (ch->digiext.digi_flags & DIGI_ALTPIN) {
ch->dcd = ch->m_dsr;
ch->dsr = ch->m_dcd;
- }
- else
- {
+ } else {
ch->dcd = ch->m_dcd;
ch->dsr = ch->m_dsr;
}
- cli();
+ spin_lock_irqsave(&epca_lock, flags);
globalwinon(ch);
/* -----------------------------------------------------------------
@@ -3000,25 +2484,22 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file,
epcaparam(tty,ch);
memoff(ch);
- restore_flags(flags);
+ spin_unlock_irqrestore(&epca_lock, flags);
break;
case DIGI_GETFLOW:
case DIGI_GETAFLOW:
- cli();
+ spin_lock_irqsave(&epca_lock, flags);
globalwinon(ch);
- if ((cmd) == (DIGI_GETFLOW))
- {
- dflow.startc = bc->startc;
- dflow.stopc = bc->stopc;
- }
- else
- {
- dflow.startc = bc->startca;
- dflow.stopc = bc->stopca;
+ if (cmd == DIGI_GETFLOW) {
+ dflow.startc = readb(&bc->startc);
+ dflow.stopc = readb(&bc->stopc);
+ } else {
+ dflow.startc = readb(&bc->startca);
+ dflow.stopc = readb(&bc->stopca);
}
memoff(ch);
- restore_flags(flags);
+ spin_unlock_irqrestore(&epca_lock, flags);
if (copy_to_user(argp, &dflow, sizeof(dflow)))
return -EFAULT;
@@ -3026,13 +2507,10 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file,
case DIGI_SETAFLOW:
case DIGI_SETFLOW:
- if ((cmd) == (DIGI_SETFLOW))
- {
+ if (cmd == DIGI_SETFLOW) {
startc = ch->startc;
stopc = ch->stopc;
- }
- else
- {
+ } else {
startc = ch->startca;
stopc = ch->stopca;
}
@@ -3040,40 +2518,31 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file,
if (copy_from_user(&dflow, argp, sizeof(dflow)))
return -EFAULT;
- if (dflow.startc != startc || dflow.stopc != stopc)
- { /* Begin if setflow toggled */
- cli();
+ if (dflow.startc != startc || dflow.stopc != stopc) { /* Begin if setflow toggled */
+ spin_lock_irqsave(&epca_lock, flags);
globalwinon(ch);
- if ((cmd) == (DIGI_SETFLOW))
- {
+ if (cmd == DIGI_SETFLOW) {
ch->fepstartc = ch->startc = dflow.startc;
ch->fepstopc = ch->stopc = dflow.stopc;
fepcmd(ch, SONOFFC, ch->fepstartc, ch->fepstopc, 0, 1);
- }
- else
- {
+ } else {
ch->fepstartca = ch->startca = dflow.startc;
ch->fepstopca = ch->stopca = dflow.stopc;
fepcmd(ch, SAUXONOFFC, ch->fepstartca, ch->fepstopca, 0, 1);
}
- if (ch->statusflags & TXSTOPPED)
+ if (ch->statusflags & TXSTOPPED)
pc_start(tty);
memoff(ch);
- restore_flags(flags);
-
+ spin_unlock_irqrestore(&epca_lock, flags);
} /* End if setflow toggled */
break;
-
default:
return -ENOIOCTLCMD;
-
} /* End switch cmd */
-
return 0;
-
} /* End pc_ioctl */
/* --------------------- Begin pc_set_termios ----------------------- */
@@ -3083,20 +2552,16 @@ static void pc_set_termios(struct tty_struct *tty, struct termios *old_termios)
struct channel *ch;
unsigned long flags;
-
/* ---------------------------------------------------------
verifyChannel returns the channel from the tty struct
if it is valid. This serves as a sanity check.
------------------------------------------------------------- */
-
- if ((ch = verifyChannel(tty)) != NULL)
- { /* Begin if channel valid */
-
- save_flags(flags);
- cli();
+ if ((ch = verifyChannel(tty)) != NULL) { /* Begin if channel valid */
+ spin_lock_irqsave(&epca_lock, flags);
globalwinon(ch);
epcaparam(tty, ch);
memoff(ch);
+ spin_unlock_irqrestore(&epca_lock, flags);
if ((old_termios->c_cflag & CRTSCTS) &&
((tty->termios->c_cflag & CRTSCTS) == 0))
@@ -3106,8 +2571,6 @@ static void pc_set_termios(struct tty_struct *tty, struct termios *old_termios)
(tty->termios->c_cflag & CLOCAL))
wake_up_interruptible(&ch->open_wait);
- restore_flags(flags);
-
} /* End if channel valid */
} /* End pc_set_termios */
@@ -3116,29 +2579,18 @@ static void pc_set_termios(struct tty_struct *tty, struct termios *old_termios)
static void do_softint(void *private_)
{ /* Begin do_softint */
-
struct channel *ch = (struct channel *) private_;
-
-
/* Called in response to a modem change event */
-
- if (ch && ch->magic == EPCA_MAGIC)
- { /* Begin EPCA_MAGIC */
-
+ if (ch && ch->magic == EPCA_MAGIC) { /* Begin EPCA_MAGIC */
struct tty_struct *tty = ch->tty;
- if (tty && tty->driver_data)
- {
- if (test_and_clear_bit(EPCA_EVENT_HANGUP, &ch->event))
- { /* Begin if clear_bit */
-
+ if (tty && tty->driver_data) {
+ if (test_and_clear_bit(EPCA_EVENT_HANGUP, &ch->event)) { /* Begin if clear_bit */
tty_hangup(tty); /* FIXME: module removal race here - AKPM */
wake_up_interruptible(&ch->open_wait);
ch->asyncflags &= ~ASYNC_NORMAL_ACTIVE;
-
} /* End if clear_bit */
}
-
} /* End EPCA_MAGIC */
} /* End do_softint */
@@ -3154,82 +2606,49 @@ static void pc_stop(struct tty_struct *tty)
struct channel *ch;
unsigned long flags;
-
/* ---------------------------------------------------------
verifyChannel returns the channel from the tty struct
if it is valid. This serves as a sanity check.
------------------------------------------------------------- */
-
- if ((ch = verifyChannel(tty)) != NULL)
- { /* Begin if valid channel */
-
- save_flags(flags);
- cli();
-
- if ((ch->statusflags & TXSTOPPED) == 0)
- { /* Begin if transmit stop requested */
-
+ if ((ch = verifyChannel(tty)) != NULL) { /* Begin if valid channel */
+ spin_lock_irqsave(&epca_lock, flags);
+ if ((ch->statusflags & TXSTOPPED) == 0) { /* Begin if transmit stop requested */
globalwinon(ch);
-
/* STOP transmitting now !! */
-
fepcmd(ch, PAUSETX, 0, 0, 0, 0);
-
ch->statusflags |= TXSTOPPED;
memoff(ch);
-
} /* End if transmit stop requested */
-
- restore_flags(flags);
-
+ spin_unlock_irqrestore(&epca_lock, flags);
} /* End if valid channel */
-
} /* End pc_stop */
/* --------------------- Begin pc_start ----------------------- */
static void pc_start(struct tty_struct *tty)
{ /* Begin pc_start */
-
struct channel *ch;
-
/* ---------------------------------------------------------
verifyChannel returns the channel from the tty struct
if it is valid. This serves as a sanity check.
------------------------------------------------------------- */
-
- if ((ch = verifyChannel(tty)) != NULL)
- { /* Begin if channel valid */
-
+ if ((ch = verifyChannel(tty)) != NULL) { /* Begin if channel valid */
unsigned long flags;
-
- save_flags(flags);
- cli();
-
+ spin_lock_irqsave(&epca_lock, flags);
/* Just in case output was resumed because of a change in Digi-flow */
- if (ch->statusflags & TXSTOPPED)
- { /* Begin transmit resume requested */
-
- volatile struct board_chan *bc;
-
+ if (ch->statusflags & TXSTOPPED) { /* Begin transmit resume requested */
+ struct board_chan __iomem *bc;
globalwinon(ch);
bc = ch->brdchan;
if (ch->statusflags & LOWWAIT)
- bc->ilow = 1;
-
+ writeb(1, &bc->ilow);
/* Okay, you can start transmitting again... */
-
fepcmd(ch, RESUMETX, 0, 0, 0, 0);
-
ch->statusflags &= ~TXSTOPPED;
memoff(ch);
-
} /* End transmit resume requested */
-
- restore_flags(flags);
-
+ spin_unlock_irqrestore(&epca_lock, flags);
} /* End if channel valid */
-
} /* End pc_start */
/* ------------------------------------------------------------------
@@ -3244,86 +2663,55 @@ ______________________________________________________________________ */
static void pc_throttle(struct tty_struct * tty)
{ /* Begin pc_throttle */
-
struct channel *ch;
unsigned long flags;
-
/* ---------------------------------------------------------
verifyChannel returns the channel from the tty struct
if it is valid. This serves as a sanity check.
------------------------------------------------------------- */
-
- if ((ch = verifyChannel(tty)) != NULL)
- { /* Begin if channel valid */
-
-
- save_flags(flags);
- cli();
-
- if ((ch->statusflags & RXSTOPPED) == 0)
- {
+ if ((ch = verifyChannel(tty)) != NULL) { /* Begin if channel valid */
+ spin_lock_irqsave(&epca_lock, flags);
+ if ((ch->statusflags & RXSTOPPED) == 0) {
globalwinon(ch);
fepcmd(ch, PAUSERX, 0, 0, 0, 0);
-
ch->statusflags |= RXSTOPPED;
memoff(ch);
}
- restore_flags(flags);
-
+ spin_unlock_irqrestore(&epca_lock, flags);
} /* End if channel valid */
-
} /* End pc_throttle */
/* --------------------- Begin unthrottle ----------------------- */
static void pc_unthrottle(struct tty_struct *tty)
{ /* Begin pc_unthrottle */
-
struct channel *ch;
unsigned long flags;
- volatile struct board_chan *bc;
-
-
/* ---------------------------------------------------------
verifyChannel returns the channel from the tty struct
if it is valid. This serves as a sanity check.
------------------------------------------------------------- */
-
- if ((ch = verifyChannel(tty)) != NULL)
- { /* Begin if channel valid */
-
-
+ if ((ch = verifyChannel(tty)) != NULL) { /* Begin if channel valid */
/* Just in case output was resumed because of a change in Digi-flow */
- save_flags(flags);
- cli();
-
- if (ch->statusflags & RXSTOPPED)
- {
-
+ spin_lock_irqsave(&epca_lock, flags);
+ if (ch->statusflags & RXSTOPPED) {
globalwinon(ch);
- bc = ch->brdchan;
fepcmd(ch, RESUMERX, 0, 0, 0, 0);
-
ch->statusflags &= ~RXSTOPPED;
memoff(ch);
}
- restore_flags(flags);
-
+ spin_unlock_irqrestore(&epca_lock, flags);
} /* End if channel valid */
-
} /* End pc_unthrottle */
/* --------------------- Begin digi_send_break ----------------------- */
void digi_send_break(struct channel *ch, int msec)
{ /* Begin digi_send_break */
-
unsigned long flags;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&epca_lock, flags);
globalwinon(ch);
-
/* --------------------------------------------------------------------
Maybe I should send an infinite break here, schedule() for
msec amount of time, and then stop the break. This way,
@@ -3331,36 +2719,28 @@ void digi_send_break(struct channel *ch, int msec)
to be called (i.e. via an ioctl()) more than once in msec amount
of time. Try this for now...
------------------------------------------------------------------------ */
-
fepcmd(ch, SENDBREAK, msec, 0, 10, 0);
memoff(ch);
-
- restore_flags(flags);
-
+ spin_unlock_irqrestore(&epca_lock, flags);
} /* End digi_send_break */
/* --------------------- Begin setup_empty_event ----------------------- */
+/* Caller MUST hold the lock */
+
static void setup_empty_event(struct tty_struct *tty, struct channel *ch)
{ /* Begin setup_empty_event */
- volatile struct board_chan *bc = ch->brdchan;
- unsigned long int flags;
+ struct board_chan __iomem *bc = ch->brdchan;
- save_flags(flags);
- cli();
globalwinon(ch);
ch->statusflags |= EMPTYWAIT;
-
/* ------------------------------------------------------------------
When set the iempty flag request a event to be generated when the
transmit buffer is empty (If there is no BREAK in progress).
--------------------------------------------------------------------- */
-
- bc->iempty = 1;
+ writeb(1, &bc->iempty);
memoff(ch);
- restore_flags(flags);
-
} /* End setup_empty_event */
/* --------------------- Begin get_termio ----------------------- */
@@ -3369,10 +2749,10 @@ static int get_termio(struct tty_struct * tty, struct termio __user * termio)
{ /* Begin get_termio */
return kernel_termios_to_user_termio(termio, tty->termios);
} /* End get_termio */
+
/* ---------------------- Begin epca_setup -------------------------- */
void epca_setup(char *str, int *ints)
{ /* Begin epca_setup */
-
struct board_info board;
int index, loop, last;
char *temp, *t2;
@@ -3394,49 +2774,41 @@ void epca_setup(char *str, int *ints)
for (last = 0, index = 1; index <= ints[0]; index++)
switch(index)
{ /* Begin parse switch */
-
case 1:
board.status = ints[index];
-
/* ---------------------------------------------------------
We check for 2 (As opposed to 1; because 2 is a flag
instructing the driver to ignore epcaconfig.) For this
reason we check for 2.
------------------------------------------------------------ */
- if (board.status == 2)
- { /* Begin ignore epcaconfig as well as lilo cmd line */
+ if (board.status == 2) { /* Begin ignore epcaconfig as well as lilo cmd line */
nbdevs = 0;
num_cards = 0;
return;
} /* End ignore epcaconfig as well as lilo cmd line */
- if (board.status > 2)
- {
- printk(KERN_ERR "<Error> - epca_setup: Invalid board status 0x%x\n", board.status);
+ if (board.status > 2) {
+ printk(KERN_ERR "epca_setup: Invalid board status 0x%x\n", board.status);
invalid_lilo_config = 1;
setup_error_code |= INVALID_BOARD_STATUS;
return;
}
last = index;
break;
-
case 2:
board.type = ints[index];
- if (board.type >= PCIXEM)
- {
- printk(KERN_ERR "<Error> - epca_setup: Invalid board type 0x%x\n", board.type);
+ if (board.type >= PCIXEM) {
+ printk(KERN_ERR "epca_setup: Invalid board type 0x%x\n", board.type);
invalid_lilo_config = 1;
setup_error_code |= INVALID_BOARD_TYPE;
return;
}
last = index;
break;
-
case 3:
board.altpin = ints[index];
- if (board.altpin > 1)
- {
- printk(KERN_ERR "<Error> - epca_setup: Invalid board altpin 0x%x\n", board.altpin);
+ if (board.altpin > 1) {
+ printk(KERN_ERR "epca_setup: Invalid board altpin 0x%x\n", board.altpin);
invalid_lilo_config = 1;
setup_error_code |= INVALID_ALTPIN;
return;
@@ -3446,9 +2818,8 @@ void epca_setup(char *str, int *ints)
case 4:
board.numports = ints[index];
- if ((board.numports < 2) || (board.numports > 256))
- {
- printk(KERN_ERR "<Error> - epca_setup: Invalid board numports 0x%x\n", board.numports);
+ if (board.numports < 2 || board.numports > 256) {
+ printk(KERN_ERR "epca_setup: Invalid board numports 0x%x\n", board.numports);
invalid_lilo_config = 1;
setup_error_code |= INVALID_NUM_PORTS;
return;
@@ -3458,10 +2829,9 @@ void epca_setup(char *str, int *ints)
break;
case 5:
- board.port = (unsigned char *)ints[index];
- if (ints[index] <= 0)
- {
- printk(KERN_ERR "<Error> - epca_setup: Invalid io port 0x%x\n", (unsigned int)board.port);
+ board.port = ints[index];
+ if (ints[index] <= 0) {
+ printk(KERN_ERR "epca_setup: Invalid io port 0x%x\n", (unsigned int)board.port);
invalid_lilo_config = 1;
setup_error_code |= INVALID_PORT_BASE;
return;
@@ -3470,10 +2840,9 @@ void epca_setup(char *str, int *ints)
break;
case 6:
- board.membase = (unsigned char *)ints[index];
- if (ints[index] <= 0)
- {
- printk(KERN_ERR "<Error> - epca_setup: Invalid memory base 0x%x\n",(unsigned int)board.membase);
+ board.membase = ints[index];
+ if (ints[index] <= 0) {
+ printk(KERN_ERR "epca_setup: Invalid memory base 0x%x\n",(unsigned int)board.membase);
invalid_lilo_config = 1;
setup_error_code |= INVALID_MEM_BASE;
return;
@@ -3487,21 +2856,16 @@ void epca_setup(char *str, int *ints)
} /* End parse switch */
- while (str && *str)
- { /* Begin while there is a string arg */
-
+ while (str && *str) { /* Begin while there is a string arg */
/* find the next comma or terminator */
temp = str;
-
/* While string is not null, and a comma hasn't been found */
while (*temp && (*temp != ','))
temp++;
-
if (!*temp)
temp = NULL;
else
*temp++ = 0;
-
/* Set index to the number of args + 1 */
index = last + 1;
@@ -3511,12 +2875,10 @@ void epca_setup(char *str, int *ints)
len = strlen(str);
if (strncmp("Disable", str, len) == 0)
board.status = 0;
- else
- if (strncmp("Enable", str, len) == 0)
+ else if (strncmp("Enable", str, len) == 0)
board.status = 1;
- else
- {
- printk(KERN_ERR "<Error> - epca_setup: Invalid status %s\n", str);
+ else {
+ printk(KERN_ERR "epca_setup: Invalid status %s\n", str);
invalid_lilo_config = 1;
setup_error_code |= INVALID_BOARD_STATUS;
return;
@@ -3525,22 +2887,17 @@ void epca_setup(char *str, int *ints)
break;
case 2:
-
for(loop = 0; loop < EPCA_NUM_TYPES; loop++)
if (strcmp(board_desc[loop], str) == 0)
break;
-
-
/* ---------------------------------------------------------------
If the index incremented above refers to a legitamate board
type set it here.
------------------------------------------------------------------*/
-
if (index < EPCA_NUM_TYPES)
board.type = loop;
- else
- {
- printk(KERN_ERR "<Error> - epca_setup: Invalid board type: %s\n", str);
+ else {
+ printk(KERN_ERR "epca_setup: Invalid board type: %s\n", str);
invalid_lilo_config = 1;
setup_error_code |= INVALID_BOARD_TYPE;
return;
@@ -3552,12 +2909,10 @@ void epca_setup(char *str, int *ints)
len = strlen(str);
if (strncmp("Disable", str, len) == 0)
board.altpin = 0;
- else
- if (strncmp("Enable", str, len) == 0)
+ else if (strncmp("Enable", str, len) == 0)
board.altpin = 1;
- else
- {
- printk(KERN_ERR "<Error> - epca_setup: Invalid altpin %s\n", str);
+ else {
+ printk(KERN_ERR "epca_setup: Invalid altpin %s\n", str);
invalid_lilo_config = 1;
setup_error_code |= INVALID_ALTPIN;
return;
@@ -3570,9 +2925,8 @@ void epca_setup(char *str, int *ints)
while (isdigit(*t2))
t2++;
- if (*t2)
- {
- printk(KERN_ERR "<Error> - epca_setup: Invalid port count %s\n", str);
+ if (*t2) {
+ printk(KERN_ERR "epca_setup: Invalid port count %s\n", str);
invalid_lilo_config = 1;
setup_error_code |= INVALID_NUM_PORTS;
return;
@@ -3601,15 +2955,14 @@ void epca_setup(char *str, int *ints)
while (isxdigit(*t2))
t2++;
- if (*t2)
- {
- printk(KERN_ERR "<Error> - epca_setup: Invalid i/o address %s\n", str);
+ if (*t2) {
+ printk(KERN_ERR "epca_setup: Invalid i/o address %s\n", str);
invalid_lilo_config = 1;
setup_error_code |= INVALID_PORT_BASE;
return;
}
- board.port = (unsigned char *)simple_strtoul(str, NULL, 16);
+ board.port = simple_strtoul(str, NULL, 16);
last = index;
break;
@@ -3618,52 +2971,38 @@ void epca_setup(char *str, int *ints)
while (isxdigit(*t2))
t2++;
- if (*t2)
- {
- printk(KERN_ERR "<Error> - epca_setup: Invalid memory base %s\n",str);
+ if (*t2) {
+ printk(KERN_ERR "epca_setup: Invalid memory base %s\n",str);
invalid_lilo_config = 1;
setup_error_code |= INVALID_MEM_BASE;
return;
}
-
- board.membase = (unsigned char *)simple_strtoul(str, NULL, 16);
+ board.membase = simple_strtoul(str, NULL, 16);
last = index;
break;
-
default:
- printk(KERN_ERR "PC/Xx: Too many string parms\n");
+ printk(KERN_ERR "epca: Too many string parms\n");
return;
}
str = temp;
-
} /* End while there is a string arg */
-
- if (last < 6)
- {
- printk(KERN_ERR "PC/Xx: Insufficient parms specified\n");
+ if (last < 6) {
+ printk(KERN_ERR "epca: Insufficient parms specified\n");
return;
}
/* I should REALLY validate the stuff here */
-
/* Copies our local copy of board into boards */
memcpy((void *)&boards[num_cards],(void *)&board, sizeof(board));
-
-
/* Does this get called once per lilo arg are what ? */
-
printk(KERN_INFO "PC/Xx: Added board %i, %s %i ports at 0x%4.4X base 0x%6.6X\n",
num_cards, board_desc[board.type],
board.numports, (int)board.port, (unsigned int) board.membase);
-
num_cards++;
-
} /* End epca_setup */
-
-#ifdef ENABLE_PCI
/* ------------------------ Begin init_PCI --------------------------- */
enum epic_board_types {
@@ -3685,7 +3024,6 @@ static struct {
{ PCIXRJ, 2, },
};
-
static int __devinit epca_init_one (struct pci_dev *pdev,
const struct pci_device_id *ent)
{
@@ -3711,10 +3049,8 @@ static int __devinit epca_init_one (struct pci_dev *pdev,
boards[board_idx].status = ENABLED;
boards[board_idx].type = epca_info_tbl[info_idx].board_type;
boards[board_idx].numports = 0x0;
- boards[board_idx].port =
- (unsigned char *)((char *) addr + PCI_IO_OFFSET);
- boards[board_idx].membase =
- (unsigned char *)((char *) addr);
+ boards[board_idx].port = addr + PCI_IO_OFFSET;
+ boards[board_idx].membase = addr;
if (!request_mem_region (addr + PCI_IO_OFFSET, 0x200000, "epca")) {
printk (KERN_ERR PFX "resource 0x%x @ 0x%lx unavailable\n",
@@ -3775,15 +3111,13 @@ static struct pci_device_id epca_pci_tbl[] = {
MODULE_DEVICE_TABLE(pci, epca_pci_tbl);
int __init init_PCI (void)
-{ /* Begin init_PCI */
+{ /* Begin init_PCI */
memset (&epca_driver, 0, sizeof (epca_driver));
epca_driver.name = "epca";
epca_driver.id_table = epca_pci_tbl;
epca_driver.probe = epca_init_one;
return pci_register_driver(&epca_driver);
-} /* End init_PCI */
-
-#endif /* ENABLE_PCI */
+}
MODULE_LICENSE("GPL");
diff --git a/drivers/char/epca.h b/drivers/char/epca.h
index 52205ef..456d6c8 100644
--- a/drivers/char/epca.h
+++ b/drivers/char/epca.h
@@ -85,73 +85,73 @@ static char *board_desc[] =
struct channel
{
long magic;
- unchar boardnum;
- unchar channelnum;
- unchar omodem; /* FEP output modem status */
- unchar imodem; /* FEP input modem status */
- unchar modemfake; /* Modem values to be forced */
- unchar modem; /* Force values */
- unchar hflow;
- unchar dsr;
- unchar dcd;
- unchar m_rts ; /* The bits used in whatever FEP */
- unchar m_dcd ; /* is indiginous to this board to */
- unchar m_dsr ; /* represent each of the physical */
- unchar m_cts ; /* handshake lines */
- unchar m_ri ;
- unchar m_dtr ;
- unchar stopc;
- unchar startc;
- unchar stopca;
- unchar startca;
- unchar fepstopc;
- unchar fepstartc;
- unchar fepstopca;
- unchar fepstartca;
- unchar txwin;
- unchar rxwin;
- ushort fepiflag;
- ushort fepcflag;
- ushort fepoflag;
- ushort txbufhead;
- ushort txbufsize;
- ushort rxbufhead;
- ushort rxbufsize;
+ unsigned char boardnum;
+ unsigned char channelnum;
+ unsigned char omodem; /* FEP output modem status */
+ unsigned char imodem; /* FEP input modem status */
+ unsigned char modemfake; /* Modem values to be forced */
+ unsigned char modem; /* Force values */
+ unsigned char hflow;
+ unsigned char dsr;
+ unsigned char dcd;
+ unsigned char m_rts ; /* The bits used in whatever FEP */
+ unsigned char m_dcd ; /* is indiginous to this board to */
+ unsigned char m_dsr ; /* represent each of the physical */
+ unsigned char m_cts ; /* handshake lines */
+ unsigned char m_ri ;
+ unsigned char m_dtr ;
+ unsigned char stopc;
+ unsigned char startc;
+ unsigned char stopca;
+ unsigned char startca;
+ unsigned char fepstopc;
+ unsigned char fepstartc;
+ unsigned char fepstopca;
+ unsigned char fepstartca;
+ unsigned char txwin;
+ unsigned char rxwin;
+ unsigned short fepiflag;
+ unsigned short fepcflag;
+ unsigned short fepoflag;
+ unsigned short txbufhead;
+ unsigned short txbufsize;
+ unsigned short rxbufhead;
+ unsigned short rxbufsize;
int close_delay;
int count;
int blocked_open;
- ulong event;
+ unsigned long event;
int asyncflags;
uint dev;
- ulong statusflags;
- ulong c_iflag;
- ulong c_cflag;
- ulong c_lflag;
- ulong c_oflag;
- unchar *txptr;
- unchar *rxptr;
- unchar *tmp_buf;
+ unsigned long statusflags;
+ unsigned long c_iflag;
+ unsigned long c_cflag;
+ unsigned long c_lflag;
+ unsigned long c_oflag;
+ unsigned char __iomem *txptr;
+ unsigned char __iomem *rxptr;
+ unsigned char *tmp_buf;
struct board_info *board;
- volatile struct board_chan *brdchan;
+ struct board_chan __iomem *brdchan;
struct digi_struct digiext;
struct tty_struct *tty;
wait_queue_head_t open_wait;
wait_queue_head_t close_wait;
- struct work_struct tqueue;
- volatile struct global_data *mailbox;
+ struct work_struct tqueue;
+ struct global_data __iomem *mailbox;
};
struct board_info
{
- unchar status;
- unchar type;
- unchar altpin;
- ushort numports;
- unchar *port;
- unchar *membase;
- unchar __iomem *re_map_port;
- unchar *re_map_membase;
- ulong memory_seg;
+ unsigned char status;
+ unsigned char type;
+ unsigned char altpin;
+ unsigned short numports;
+ unsigned long port;
+ unsigned long membase;
+ void __iomem *re_map_port;
+ void __iomem *re_map_membase;
+ unsigned long memory_seg;
void ( * memwinon ) (struct board_info *, unsigned int) ;
void ( * memwinoff ) (struct board_info *, unsigned int) ;
void ( * globalwinon ) (struct channel *) ;
@@ -160,6 +160,6 @@ struct board_info
void ( * memoff ) (struct channel *) ;
void ( * assertgwinon ) (struct channel *) ;
void ( * assertmemoff ) (struct channel *) ;
- unchar poller_inhibited ;
+ unsigned char poller_inhibited ;
};
diff --git a/drivers/char/ftape/lowlevel/fdc-io.c b/drivers/char/ftape/lowlevel/fdc-io.c
index 1704a2a..b2e0928 100644
--- a/drivers/char/ftape/lowlevel/fdc-io.c
+++ b/drivers/char/ftape/lowlevel/fdc-io.c
@@ -387,10 +387,8 @@ int fdc_interrupt_wait(unsigned int time)
set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&ftape_wait_intr, &wait);
- while (!ft_interrupt_seen && timeout) {
- set_current_state(TASK_INTERRUPTIBLE);
- timeout = schedule_timeout(timeout);
- }
+ while (!ft_interrupt_seen && timeout)
+ timeout = schedule_timeout_interruptible(timeout);
spin_lock_irq(&current->sighand->siglock);
current->blocked = old_sigmask;
diff --git a/drivers/char/hangcheck-timer.c b/drivers/char/hangcheck-timer.c
index 81d811e..a54bc93 100644
--- a/drivers/char/hangcheck-timer.c
+++ b/drivers/char/hangcheck-timer.c
@@ -149,8 +149,7 @@ static unsigned long long hangcheck_tsc, hangcheck_tsc_margin;
static void hangcheck_fire(unsigned long);
-static struct timer_list hangcheck_ticktock =
- TIMER_INITIALIZER(hangcheck_fire, 0, 0);
+static DEFINE_TIMER(hangcheck_ticktock, hangcheck_fire, 0, 0);
static void hangcheck_fire(unsigned long data)
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c
index 762fa43..c055bb6 100644
--- a/drivers/char/hpet.c
+++ b/drivers/char/hpet.c
@@ -44,7 +44,7 @@
/*
* The High Precision Event Timer driver.
* This driver is closely modelled after the rtc.c driver.
- * http://www.intel.com/labs/platcomp/hpet/hpetspec.htm
+ * http://www.intel.com/hardwaredesign/hpetspec.htm
*/
#define HPET_USER_FREQ (64)
#define HPET_DRIFT (500)
@@ -100,14 +100,14 @@ static struct hpets *hpets;
#endif
#ifndef readq
-static unsigned long long __inline readq(void __iomem *addr)
+static inline unsigned long long readq(void __iomem *addr)
{
return readl(addr) | (((unsigned long long)readl(addr + 4)) << 32LL);
}
#endif
#ifndef writeq
-static void __inline writeq(unsigned long long v, void __iomem *addr)
+static inline void writeq(unsigned long long v, void __iomem *addr)
{
writel(v & 0xffffffff, addr);
writel(v >> 32, addr + 4);
@@ -273,7 +273,6 @@ static int hpet_mmap(struct file *file, struct vm_area_struct *vma)
vma->vm_flags |= VM_IO;
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
- addr = __pa(addr);
if (io_remap_pfn_range(vma, vma->vm_start, addr >> PAGE_SHIFT,
PAGE_SIZE, vma->vm_page_prot)) {
@@ -712,7 +711,7 @@ static void hpet_register_interpolator(struct hpets *hpetp)
ti->shift = 10;
ti->addr = &hpetp->hp_hpet->hpet_mc;
ti->frequency = hpet_time_div(hpets->hp_period);
- ti->drift = ti->frequency * HPET_DRIFT / 1000000;
+ ti->drift = HPET_DRIFT;
ti->mask = -1;
hpetp->hp_interpolator = ti;
@@ -906,11 +905,15 @@ static acpi_status hpet_resources(struct acpi_resource *res, void *data)
if (irqp->number_of_interrupts > 0) {
hdp->hd_nirqs = irqp->number_of_interrupts;
- for (i = 0; i < hdp->hd_nirqs; i++)
- hdp->hd_irq[i] =
+ for (i = 0; i < hdp->hd_nirqs; i++) {
+ int rc =
acpi_register_gsi(irqp->interrupts[i],
irqp->edge_level,
irqp->active_high_low);
+ if (rc < 0)
+ return AE_ERROR;
+ hdp->hd_irq[i] = rc;
+ }
}
}
diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c
index cddb789..f921776 100644
--- a/drivers/char/hvc_console.c
+++ b/drivers/char/hvc_console.c
@@ -839,9 +839,6 @@ int __init hvc_init(void)
hvc_driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(hvc_driver, &hvc_ops);
- if (tty_register_driver(hvc_driver))
- panic("Couldn't register hvc console driver\n");
-
/* Always start the kthread because there can be hotplug vty adapters
* added later. */
hvc_task = kthread_run(khvcd, NULL, "khvcd");
@@ -851,6 +848,9 @@ int __init hvc_init(void)
return -EIO;
}
+ if (tty_register_driver(hvc_driver))
+ panic("Couldn't register hvc console driver\n");
+
return 0;
}
module_init(hvc_init);
diff --git a/drivers/char/hw_random.c b/drivers/char/hw_random.c
index 3480535..6f673d2 100644
--- a/drivers/char/hw_random.c
+++ b/drivers/char/hw_random.c
@@ -513,10 +513,7 @@ static ssize_t rng_dev_read (struct file *filp, char __user *buf, size_t size,
return ret ? : -EAGAIN;
if(need_resched())
- {
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(1);
- }
+ schedule_timeout_interruptible(1);
else
udelay(200); /* FIXME: We could poll for 250uS ?? */
diff --git a/drivers/char/ip2/i2lib.c b/drivers/char/ip2/i2lib.c
index 82c5f30..ba85eb1 100644
--- a/drivers/char/ip2/i2lib.c
+++ b/drivers/char/ip2/i2lib.c
@@ -655,8 +655,7 @@ i2QueueCommands(int type, i2ChanStrPtr pCh, int timeout, int nCommands,
timeout--; // So negative values == forever
if (!in_interrupt()) {
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(1); // short nap
+ schedule_timeout_interruptible(1); // short nap
} else {
// we cannot sched/sleep in interrrupt silly
return 0;
@@ -1132,8 +1131,7 @@ i2Output(i2ChanStrPtr pCh, const char *pSource, int count, int user )
ip2trace (CHANN, ITRC_OUTPUT, 61, 0 );
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(2);
+ schedule_timeout_interruptible(2);
if (signal_pending(current)) {
break;
}
diff --git a/drivers/char/ip2main.c b/drivers/char/ip2main.c
index cf0cd58..9e4e26a 100644
--- a/drivers/char/ip2main.c
+++ b/drivers/char/ip2main.c
@@ -120,7 +120,6 @@
#include <linux/vmalloc.h>
#include <linux/init.h>
-#include <asm/serial.h>
#include <asm/uaccess.h>
@@ -255,7 +254,7 @@ static unsigned long bh_counter = 0;
* selected, the board is serviced periodically to see if anything needs doing.
*/
#define POLL_TIMEOUT (jiffies + 1)
-static struct timer_list PollTimer = TIMER_INITIALIZER(ip2_poll, 0, 0);
+static DEFINE_TIMER(PollTimer, ip2_poll, 0, 0);
static char TimerOn;
#ifdef IP2DEBUG_TRACE
diff --git a/drivers/char/ipmi/ipmi_bt_sm.c b/drivers/char/ipmi/ipmi_bt_sm.c
index 5ce9c62..3386267 100644
--- a/drivers/char/ipmi/ipmi_bt_sm.c
+++ b/drivers/char/ipmi/ipmi_bt_sm.c
@@ -31,8 +31,6 @@
#include <linux/ipmi_msgdefs.h> /* for completion codes */
#include "ipmi_si_sm.h"
-#define IPMI_BT_VERSION "v33"
-
static int bt_debug = 0x00; /* Production value 0, see following flags */
#define BT_DEBUG_ENABLE 1
@@ -163,7 +161,8 @@ static int bt_start_transaction(struct si_sm_data *bt,
{
unsigned int i;
- if ((size < 2) || (size > IPMI_MAX_MSG_LENGTH)) return -1;
+ if ((size < 2) || (size > IPMI_MAX_MSG_LENGTH))
+ return -1;
if ((bt->state != BT_STATE_IDLE) && (bt->state != BT_STATE_HOSED))
return -2;
@@ -171,7 +170,8 @@ static int bt_start_transaction(struct si_sm_data *bt,
if (bt_debug & BT_DEBUG_MSG) {
printk(KERN_WARNING "+++++++++++++++++++++++++++++++++++++\n");
printk(KERN_WARNING "BT: write seq=0x%02X:", bt->seq);
- for (i = 0; i < size; i ++) printk (" %02x", data[i]);
+ for (i = 0; i < size; i ++)
+ printk (" %02x", data[i]);
printk("\n");
}
bt->write_data[0] = size + 1; /* all data plus seq byte */
@@ -210,15 +210,18 @@ static int bt_get_result(struct si_sm_data *bt,
} else {
data[0] = bt->read_data[1];
data[1] = bt->read_data[3];
- if (length < msg_len) bt->truncated = 1;
+ if (length < msg_len)
+ bt->truncated = 1;
if (bt->truncated) { /* can be set in read_all_bytes() */
data[2] = IPMI_ERR_MSG_TRUNCATED;
msg_len = 3;
- } else memcpy(data + 2, bt->read_data + 4, msg_len - 2);
+ } else
+ memcpy(data + 2, bt->read_data + 4, msg_len - 2);
if (bt_debug & BT_DEBUG_MSG) {
printk (KERN_WARNING "BT: res (raw)");
- for (i = 0; i < msg_len; i++) printk(" %02x", data[i]);
+ for (i = 0; i < msg_len; i++)
+ printk(" %02x", data[i]);
printk ("\n");
}
}
@@ -231,8 +234,10 @@ static int bt_get_result(struct si_sm_data *bt,
static void reset_flags(struct si_sm_data *bt)
{
- if (BT_STATUS & BT_H_BUSY) BT_CONTROL(BT_H_BUSY);
- if (BT_STATUS & BT_B_BUSY) BT_CONTROL(BT_B_BUSY);
+ if (BT_STATUS & BT_H_BUSY)
+ BT_CONTROL(BT_H_BUSY);
+ if (BT_STATUS & BT_B_BUSY)
+ BT_CONTROL(BT_B_BUSY);
BT_CONTROL(BT_CLR_WR_PTR);
BT_CONTROL(BT_SMS_ATN);
#ifdef DEVELOPMENT_ONLY_NOT_FOR_PRODUCTION
@@ -241,7 +246,8 @@ static void reset_flags(struct si_sm_data *bt)
BT_CONTROL(BT_H_BUSY);
BT_CONTROL(BT_B2H_ATN);
BT_CONTROL(BT_CLR_RD_PTR);
- for (i = 0; i < IPMI_MAX_MSG_LENGTH + 2; i++) BMC2HOST;
+ for (i = 0; i < IPMI_MAX_MSG_LENGTH + 2; i++)
+ BMC2HOST;
BT_CONTROL(BT_H_BUSY);
}
#endif
@@ -258,7 +264,8 @@ static inline void write_all_bytes(struct si_sm_data *bt)
printk (" %02x", bt->write_data[i]);
printk ("\n");
}
- for (i = 0; i < bt->write_count; i++) HOST2BMC(bt->write_data[i]);
+ for (i = 0; i < bt->write_count; i++)
+ HOST2BMC(bt->write_data[i]);
}
static inline int read_all_bytes(struct si_sm_data *bt)
@@ -278,7 +285,8 @@ static inline int read_all_bytes(struct si_sm_data *bt)
bt->truncated = 1;
return 1; /* let next XACTION START clean it up */
}
- for (i = 1; i <= bt->read_count; i++) bt->read_data[i] = BMC2HOST;
+ for (i = 1; i <= bt->read_count; i++)
+ bt->read_data[i] = BMC2HOST;
bt->read_count++; /* account for the length byte */
if (bt_debug & BT_DEBUG_MSG) {
@@ -295,7 +303,8 @@ static inline int read_all_bytes(struct si_sm_data *bt)
((bt->read_data[1] & 0xF8) == (bt->write_data[1] & 0xF8)))
return 1;
- if (bt_debug & BT_DEBUG_MSG) printk(KERN_WARNING "BT: bad packet: "
+ if (bt_debug & BT_DEBUG_MSG)
+ printk(KERN_WARNING "BT: bad packet: "
"want 0x(%02X, %02X, %02X) got (%02X, %02X, %02X)\n",
bt->write_data[1], bt->write_data[2], bt->write_data[3],
bt->read_data[1], bt->read_data[2], bt->read_data[3]);
@@ -359,7 +368,8 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time)
time);
bt->last_state = bt->state;
- if (bt->state == BT_STATE_HOSED) return SI_SM_HOSED;
+ if (bt->state == BT_STATE_HOSED)
+ return SI_SM_HOSED;
if (bt->state != BT_STATE_IDLE) { /* do timeout test */
@@ -371,7 +381,8 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time)
/* FIXME: bt_event is sometimes called with time > BT_NORMAL_TIMEOUT
(noticed in ipmi_smic_sm.c January 2004) */
- if ((time <= 0) || (time >= BT_NORMAL_TIMEOUT)) time = 100;
+ if ((time <= 0) || (time >= BT_NORMAL_TIMEOUT))
+ time = 100;
bt->timeout -= time;
if ((bt->timeout < 0) && (bt->state < BT_STATE_RESET1)) {
error_recovery(bt, "timed out");
@@ -393,12 +404,14 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time)
BT_CONTROL(BT_H_BUSY);
break;
}
- if (status & BT_B2H_ATN) break;
+ if (status & BT_B2H_ATN)
+ break;
bt->state = BT_STATE_WRITE_BYTES;
return SI_SM_CALL_WITHOUT_DELAY; /* for logging */
case BT_STATE_WRITE_BYTES:
- if (status & (BT_B_BUSY | BT_H2B_ATN)) break;
+ if (status & (BT_B_BUSY | BT_H2B_ATN))
+ break;
BT_CONTROL(BT_CLR_WR_PTR);
write_all_bytes(bt);
BT_CONTROL(BT_H2B_ATN); /* clears too fast to catch? */
@@ -406,7 +419,8 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time)
return SI_SM_CALL_WITHOUT_DELAY; /* it MIGHT sail through */
case BT_STATE_WRITE_CONSUME: /* BMCs usually blow right thru here */
- if (status & (BT_H2B_ATN | BT_B_BUSY)) break;
+ if (status & (BT_H2B_ATN | BT_B_BUSY))
+ break;
bt->state = BT_STATE_B2H_WAIT;
/* fall through with status */
@@ -415,15 +429,18 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time)
generation of B2H_ATN so ALWAYS return CALL_WITH_DELAY. */
case BT_STATE_B2H_WAIT:
- if (!(status & BT_B2H_ATN)) break;
+ if (!(status & BT_B2H_ATN))
+ break;
/* Assume ordered, uncached writes: no need to wait */
- if (!(status & BT_H_BUSY)) BT_CONTROL(BT_H_BUSY); /* set */
+ if (!(status & BT_H_BUSY))
+ BT_CONTROL(BT_H_BUSY); /* set */
BT_CONTROL(BT_B2H_ATN); /* clear it, ACK to the BMC */
BT_CONTROL(BT_CLR_RD_PTR); /* reset the queue */
i = read_all_bytes(bt);
BT_CONTROL(BT_H_BUSY); /* clear */
- if (!i) break; /* Try this state again */
+ if (!i) /* Try this state again */
+ break;
bt->state = BT_STATE_READ_END;
return SI_SM_CALL_WITHOUT_DELAY; /* for logging */
@@ -436,7 +453,8 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time)
#ifdef MAKE_THIS_TRUE_IF_NECESSARY
- if (status & BT_H_BUSY) break;
+ if (status & BT_H_BUSY)
+ break;
#endif
bt->seq++;
bt->state = BT_STATE_IDLE;
@@ -459,7 +477,8 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time)
break;
case BT_STATE_RESET3:
- if (bt->timeout > 0) return SI_SM_CALL_WITH_DELAY;
+ if (bt->timeout > 0)
+ return SI_SM_CALL_WITH_DELAY;
bt->state = BT_STATE_RESTART; /* printk in debug modes */
break;
@@ -485,7 +504,8 @@ static int bt_detect(struct si_sm_data *bt)
but that's what you get from reading a bogus address, so we
test that first. The calling routine uses negative logic. */
- if ((BT_STATUS == 0xFF) && (BT_INTMASK_R == 0xFF)) return 1;
+ if ((BT_STATUS == 0xFF) && (BT_INTMASK_R == 0xFF))
+ return 1;
reset_flags(bt);
return 0;
}
@@ -501,7 +521,6 @@ static int bt_size(void)
struct si_sm_handlers bt_smi_handlers =
{
- .version = IPMI_BT_VERSION,
.init_data = bt_init_data,
.start_transaction = bt_start_transaction,
.get_result = bt_get_result,
diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c
index e0a5357..a09ff10 100644
--- a/drivers/char/ipmi/ipmi_devintf.c
+++ b/drivers/char/ipmi/ipmi_devintf.c
@@ -47,8 +47,6 @@
#include <linux/device.h>
#include <linux/compat.h>
-#define IPMI_DEVINTF_VERSION "v33"
-
struct ipmi_file_private
{
ipmi_user_t user;
@@ -411,6 +409,7 @@ static int ipmi_ioctl(struct inode *inode,
break;
}
+ /* The next four are legacy, not per-channel. */
case IPMICTL_SET_MY_ADDRESS_CMD:
{
unsigned int val;
@@ -420,22 +419,25 @@ static int ipmi_ioctl(struct inode *inode,
break;
}
- ipmi_set_my_address(priv->user, val);
- rv = 0;
+ rv = ipmi_set_my_address(priv->user, 0, val);
break;
}
case IPMICTL_GET_MY_ADDRESS_CMD:
{
- unsigned int val;
+ unsigned int val;
+ unsigned char rval;
+
+ rv = ipmi_get_my_address(priv->user, 0, &rval);
+ if (rv)
+ break;
- val = ipmi_get_my_address(priv->user);
+ val = rval;
if (copy_to_user(arg, &val, sizeof(val))) {
rv = -EFAULT;
break;
}
- rv = 0;
break;
}
@@ -448,24 +450,94 @@ static int ipmi_ioctl(struct inode *inode,
break;
}
- ipmi_set_my_LUN(priv->user, val);
- rv = 0;
+ rv = ipmi_set_my_LUN(priv->user, 0, val);
break;
}
case IPMICTL_GET_MY_LUN_CMD:
{
- unsigned int val;
+ unsigned int val;
+ unsigned char rval;
- val = ipmi_get_my_LUN(priv->user);
+ rv = ipmi_get_my_LUN(priv->user, 0, &rval);
+ if (rv)
+ break;
+
+ val = rval;
+
+ if (copy_to_user(arg, &val, sizeof(val))) {
+ rv = -EFAULT;
+ break;
+ }
+ break;
+ }
+
+ case IPMICTL_SET_MY_CHANNEL_ADDRESS_CMD:
+ {
+ struct ipmi_channel_lun_address_set val;
+
+ if (copy_from_user(&val, arg, sizeof(val))) {
+ rv = -EFAULT;
+ break;
+ }
+
+ return ipmi_set_my_address(priv->user, val.channel, val.value);
+ break;
+ }
+
+ case IPMICTL_GET_MY_CHANNEL_ADDRESS_CMD:
+ {
+ struct ipmi_channel_lun_address_set val;
+
+ if (copy_from_user(&val, arg, sizeof(val))) {
+ rv = -EFAULT;
+ break;
+ }
+
+ rv = ipmi_get_my_address(priv->user, val.channel, &val.value);
+ if (rv)
+ break;
+
+ if (copy_to_user(arg, &val, sizeof(val))) {
+ rv = -EFAULT;
+ break;
+ }
+ break;
+ }
+
+ case IPMICTL_SET_MY_CHANNEL_LUN_CMD:
+ {
+ struct ipmi_channel_lun_address_set val;
+
+ if (copy_from_user(&val, arg, sizeof(val))) {
+ rv = -EFAULT;
+ break;
+ }
+
+ rv = ipmi_set_my_LUN(priv->user, val.channel, val.value);
+ break;
+ }
+
+ case IPMICTL_GET_MY_CHANNEL_LUN_CMD:
+ {
+ struct ipmi_channel_lun_address_set val;
+
+ if (copy_from_user(&val, arg, sizeof(val))) {
+ rv = -EFAULT;
+ break;
+ }
+
+ rv = ipmi_get_my_LUN(priv->user, val.channel, &val.value);
+ if (rv)
+ break;
if (copy_to_user(arg, &val, sizeof(val))) {
rv = -EFAULT;
break;
}
- rv = 0;
break;
}
+
case IPMICTL_SET_TIMING_PARMS_CMD:
{
struct ipmi_timing_parms parms;
@@ -663,7 +735,8 @@ static long compat_ipmi_ioctl(struct file *filep, unsigned int cmd,
case COMPAT_IPMICTL_RECEIVE_MSG:
case COMPAT_IPMICTL_RECEIVE_MSG_TRUNC:
{
- struct ipmi_recv *precv64, recv64;
+ struct ipmi_recv __user *precv64;
+ struct ipmi_recv recv64;
if (get_compat_ipmi_recv(&recv64, compat_ptr(arg)))
return -EFAULT;
@@ -676,7 +749,7 @@ static long compat_ipmi_ioctl(struct file *filep, unsigned int cmd,
((cmd == COMPAT_IPMICTL_RECEIVE_MSG)
? IPMICTL_RECEIVE_MSG
: IPMICTL_RECEIVE_MSG_TRUNC),
- (long) precv64);
+ (unsigned long) precv64);
if (rc != 0)
return rc;
@@ -748,8 +821,7 @@ static __init int init_ipmi_devintf(void)
if (ipmi_major < 0)
return -EINVAL;
- printk(KERN_INFO "ipmi device interface version "
- IPMI_DEVINTF_VERSION "\n");
+ printk(KERN_INFO "ipmi device interface\n");
ipmi_class = class_create(THIS_MODULE, "ipmi");
if (IS_ERR(ipmi_class)) {
@@ -792,3 +864,5 @@ static __exit void cleanup_ipmi(void)
module_exit(cleanup_ipmi);
MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>");
+MODULE_DESCRIPTION("Linux device interface for the IPMI message handler.");
diff --git a/drivers/char/ipmi/ipmi_kcs_sm.c b/drivers/char/ipmi/ipmi_kcs_sm.c
index 48cce24..d21853a 100644
--- a/drivers/char/ipmi/ipmi_kcs_sm.c
+++ b/drivers/char/ipmi/ipmi_kcs_sm.c
@@ -42,8 +42,6 @@
#include <linux/ipmi_msgdefs.h> /* for completion codes */
#include "ipmi_si_sm.h"
-#define IPMI_KCS_VERSION "v33"
-
/* Set this if you want a printout of why the state machine was hosed
when it gets hosed. */
#define DEBUG_HOSED_REASON
@@ -489,7 +487,6 @@ static void kcs_cleanup(struct si_sm_data *kcs)
struct si_sm_handlers kcs_smi_handlers =
{
- .version = IPMI_KCS_VERSION,
.init_data = init_kcs_data,
.start_transaction = start_kcs_transaction,
.get_result = get_kcs_result,
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
index e16c13f..32fa82c 100644
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -47,7 +47,8 @@
#include <linux/proc_fs.h>
#define PFX "IPMI message handler: "
-#define IPMI_MSGHANDLER_VERSION "v33"
+
+#define IPMI_DRIVER_VERSION "36.0"
static struct ipmi_recv_msg *ipmi_alloc_recv_msg(void);
static int ipmi_init_msghandler(void);
@@ -116,7 +117,7 @@ struct seq_table
do { \
seq = ((msgid >> 26) & 0x3f); \
seqid = (msgid & 0x3fffff); \
- } while(0)
+ } while (0)
#define NEXT_SEQID(seqid) (((seqid) + 1) & 0x3fffff)
@@ -124,6 +125,14 @@ struct ipmi_channel
{
unsigned char medium;
unsigned char protocol;
+
+ /* My slave address. This is initialized to IPMI_BMC_SLAVE_ADDR,
+ but may be changed by the user. */
+ unsigned char address;
+
+ /* My LUN. This should generally stay the SMS LUN, but just in
+ case... */
+ unsigned char lun;
};
#ifdef CONFIG_PROC_FS
@@ -135,7 +144,7 @@ struct ipmi_proc_entry
#endif
#define IPMI_IPMB_NUM_SEQ 64
-#define IPMI_MAX_CHANNELS 8
+#define IPMI_MAX_CHANNELS 16
struct ipmi_smi
{
/* What interface number are we? */
@@ -193,20 +202,6 @@ struct ipmi_smi
struct list_head waiting_events;
unsigned int waiting_events_count; /* How many events in queue? */
- /* This will be non-null if someone registers to receive all
- IPMI commands (this is for interface emulation). There
- may not be any things in the cmd_rcvrs list above when
- this is registered. */
- ipmi_user_t all_cmd_rcvr;
-
- /* My slave address. This is initialized to IPMI_BMC_SLAVE_ADDR,
- but may be changed by the user. */
- unsigned char my_address;
-
- /* My LUN. This should generally stay the SMS LUN, but just in
- case... */
- unsigned char my_lun;
-
/* The event receiver for my BMC, only really used at panic
shutdown as a place to store this. */
unsigned char event_receiver;
@@ -218,7 +213,7 @@ struct ipmi_smi
interface comes in with a NULL user, call this routine with
it. Note that the message will still be freed by the
caller. This only works on the system interface. */
- void (*null_user_handler)(ipmi_smi_t intf, struct ipmi_smi_msg *msg);
+ void (*null_user_handler)(ipmi_smi_t intf, struct ipmi_recv_msg *msg);
/* When we are scanning the channels for an SMI, this will
tell which channel we are scanning. */
@@ -325,7 +320,7 @@ int ipmi_smi_watcher_register(struct ipmi_smi_watcher *watcher)
down_read(&interfaces_sem);
down_write(&smi_watchers_sem);
list_add(&(watcher->link), &smi_watchers);
- for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+ for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
if (ipmi_interfaces[i] != NULL) {
watcher->new_smi(i);
}
@@ -458,7 +453,27 @@ unsigned int ipmi_addr_length(int addr_type)
static void deliver_response(struct ipmi_recv_msg *msg)
{
- msg->user->handler->ipmi_recv_hndl(msg, msg->user->handler_data);
+ if (! msg->user) {
+ ipmi_smi_t intf = msg->user_msg_data;
+ unsigned long flags;
+
+ /* Special handling for NULL users. */
+ if (intf->null_user_handler) {
+ intf->null_user_handler(intf, msg);
+ spin_lock_irqsave(&intf->counter_lock, flags);
+ intf->handled_local_responses++;
+ spin_unlock_irqrestore(&intf->counter_lock, flags);
+ } else {
+ /* No handler, so give up. */
+ spin_lock_irqsave(&intf->counter_lock, flags);
+ intf->unhandled_local_responses++;
+ spin_unlock_irqrestore(&intf->counter_lock, flags);
+ }
+ ipmi_free_recv_msg(msg);
+ } else {
+ msg->user->handler->ipmi_recv_hndl(msg,
+ msg->user->handler_data);
+ }
}
/* Find the next sequence number not being used and add the given
@@ -475,9 +490,9 @@ static int intf_next_seq(ipmi_smi_t intf,
int rv = 0;
unsigned int i;
- for (i=intf->curr_seq;
+ for (i = intf->curr_seq;
(i+1)%IPMI_IPMB_NUM_SEQ != intf->curr_seq;
- i=(i+1)%IPMI_IPMB_NUM_SEQ)
+ i = (i+1)%IPMI_IPMB_NUM_SEQ)
{
if (! intf->seq_table[i].inuse)
break;
@@ -712,7 +727,7 @@ static int ipmi_destroy_user_nolock(ipmi_user_t user)
/* Remove the user from the interfaces sequence table. */
spin_lock_irqsave(&(user->intf->seq_lock), flags);
- for (i=0; i<IPMI_IPMB_NUM_SEQ; i++) {
+ for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) {
if (user->intf->seq_table[i].inuse
&& (user->intf->seq_table[i].recv_msg->user == user))
{
@@ -766,26 +781,44 @@ void ipmi_get_version(ipmi_user_t user,
*minor = user->intf->version_minor;
}
-void ipmi_set_my_address(ipmi_user_t user,
- unsigned char address)
+int ipmi_set_my_address(ipmi_user_t user,
+ unsigned int channel,
+ unsigned char address)
{
- user->intf->my_address = address;
+ if (channel >= IPMI_MAX_CHANNELS)
+ return -EINVAL;
+ user->intf->channels[channel].address = address;
+ return 0;
}
-unsigned char ipmi_get_my_address(ipmi_user_t user)
+int ipmi_get_my_address(ipmi_user_t user,
+ unsigned int channel,
+ unsigned char *address)
{
- return user->intf->my_address;
+ if (channel >= IPMI_MAX_CHANNELS)
+ return -EINVAL;
+ *address = user->intf->channels[channel].address;
+ return 0;
}
-void ipmi_set_my_LUN(ipmi_user_t user,
- unsigned char LUN)
+int ipmi_set_my_LUN(ipmi_user_t user,
+ unsigned int channel,
+ unsigned char LUN)
{
- user->intf->my_lun = LUN & 0x3;
+ if (channel >= IPMI_MAX_CHANNELS)
+ return -EINVAL;
+ user->intf->channels[channel].lun = LUN & 0x3;
+ return 0;
}
-unsigned char ipmi_get_my_LUN(ipmi_user_t user)
+int ipmi_get_my_LUN(ipmi_user_t user,
+ unsigned int channel,
+ unsigned char *address)
{
- return user->intf->my_lun;
+ if (channel >= IPMI_MAX_CHANNELS)
+ return -EINVAL;
+ *address = user->intf->channels[channel].lun;
+ return 0;
}
int ipmi_set_gets_events(ipmi_user_t user, int val)
@@ -828,11 +861,6 @@ int ipmi_register_for_cmd(ipmi_user_t user,
read_lock(&(user->intf->users_lock));
write_lock_irqsave(&(user->intf->cmd_rcvr_lock), flags);
- if (user->intf->all_cmd_rcvr != NULL) {
- rv = -EBUSY;
- goto out_unlock;
- }
-
/* Make sure the command/netfn is not already registered. */
list_for_each_entry(cmp, &(user->intf->cmd_rcvrs), link) {
if ((cmp->netfn == netfn) && (cmp->cmd == cmd)) {
@@ -847,7 +875,7 @@ int ipmi_register_for_cmd(ipmi_user_t user,
rcvr->user = user;
list_add_tail(&(rcvr->link), &(user->intf->cmd_rcvrs));
}
- out_unlock:
+
write_unlock_irqrestore(&(user->intf->cmd_rcvr_lock), flags);
read_unlock(&(user->intf->users_lock));
@@ -1213,7 +1241,7 @@ static inline int i_ipmi_request(ipmi_user_t user,
unsigned char ipmb_seq;
long seqid;
- if (addr->channel > IPMI_NUM_CHANNELS) {
+ if (addr->channel >= IPMI_NUM_CHANNELS) {
spin_lock_irqsave(&intf->counter_lock, flags);
intf->sent_invalid_commands++;
spin_unlock_irqrestore(&intf->counter_lock, flags);
@@ -1331,7 +1359,7 @@ static inline int i_ipmi_request(ipmi_user_t user,
#ifdef DEBUG_MSGING
{
int m;
- for (m=0; m<smi_msg->data_size; m++)
+ for (m = 0; m < smi_msg->data_size; m++)
printk(" %2.2x", smi_msg->data[m]);
printk("\n");
}
@@ -1346,6 +1374,18 @@ static inline int i_ipmi_request(ipmi_user_t user,
return rv;
}
+static int check_addr(ipmi_smi_t intf,
+ struct ipmi_addr *addr,
+ unsigned char *saddr,
+ unsigned char *lun)
+{
+ if (addr->channel >= IPMI_MAX_CHANNELS)
+ return -EINVAL;
+ *lun = intf->channels[addr->channel].lun;
+ *saddr = intf->channels[addr->channel].address;
+ return 0;
+}
+
int ipmi_request_settime(ipmi_user_t user,
struct ipmi_addr *addr,
long msgid,
@@ -1355,6 +1395,14 @@ int ipmi_request_settime(ipmi_user_t user,
int retries,
unsigned int retry_time_ms)
{
+ unsigned char saddr, lun;
+ int rv;
+
+ if (! user)
+ return -EINVAL;
+ rv = check_addr(user->intf, addr, &saddr, &lun);
+ if (rv)
+ return rv;
return i_ipmi_request(user,
user->intf,
addr,
@@ -1363,8 +1411,8 @@ int ipmi_request_settime(ipmi_user_t user,
user_msg_data,
NULL, NULL,
priority,
- user->intf->my_address,
- user->intf->my_lun,
+ saddr,
+ lun,
retries,
retry_time_ms);
}
@@ -1378,6 +1426,14 @@ int ipmi_request_supply_msgs(ipmi_user_t user,
struct ipmi_recv_msg *supplied_recv,
int priority)
{
+ unsigned char saddr, lun;
+ int rv;
+
+ if (! user)
+ return -EINVAL;
+ rv = check_addr(user->intf, addr, &saddr, &lun);
+ if (rv)
+ return rv;
return i_ipmi_request(user,
user->intf,
addr,
@@ -1387,8 +1443,8 @@ int ipmi_request_supply_msgs(ipmi_user_t user,
supplied_smi,
supplied_recv,
priority,
- user->intf->my_address,
- user->intf->my_lun,
+ saddr,
+ lun,
-1, 0);
}
@@ -1397,8 +1453,15 @@ static int ipmb_file_read_proc(char *page, char **start, off_t off,
{
char *out = (char *) page;
ipmi_smi_t intf = data;
+ int i;
+ int rv= 0;
- return sprintf(out, "%x\n", intf->my_address);
+ for (i = 0; i < IPMI_MAX_CHANNELS; i++)
+ rv += sprintf(out+rv, "%x ", intf->channels[i].address);
+ out[rv-1] = '\n'; /* Replace the final space with a newline */
+ out[rv] = '\0';
+ rv++;
+ return rv;
}
static int version_file_read_proc(char *page, char **start, off_t off,
@@ -1588,29 +1651,30 @@ send_channel_info_cmd(ipmi_smi_t intf, int chan)
(struct ipmi_addr *) &si,
0,
&msg,
- NULL,
+ intf,
NULL,
NULL,
0,
- intf->my_address,
- intf->my_lun,
+ intf->channels[0].address,
+ intf->channels[0].lun,
-1, 0);
}
static void
-channel_handler(ipmi_smi_t intf, struct ipmi_smi_msg *msg)
+channel_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
{
int rv = 0;
int chan;
- if ((msg->rsp[0] == (IPMI_NETFN_APP_RESPONSE << 2))
- && (msg->rsp[1] == IPMI_GET_CHANNEL_INFO_CMD))
+ if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
+ && (msg->msg.netfn == IPMI_NETFN_APP_RESPONSE)
+ && (msg->msg.cmd == IPMI_GET_CHANNEL_INFO_CMD))
{
/* It's the one we want */
- if (msg->rsp[2] != 0) {
+ if (msg->msg.data[0] != 0) {
/* Got an error from the channel, just go on. */
- if (msg->rsp[2] == IPMI_INVALID_COMMAND_ERR) {
+ if (msg->msg.data[0] == IPMI_INVALID_COMMAND_ERR) {
/* If the MC does not support this
command, that is legal. We just
assume it has one IPMB at channel
@@ -1627,13 +1691,13 @@ channel_handler(ipmi_smi_t intf, struct ipmi_smi_msg *msg)
}
goto next_channel;
}
- if (msg->rsp_size < 6) {
+ if (msg->msg.data_len < 4) {
/* Message not big enough, just go on. */
goto next_channel;
}
chan = intf->curr_channel;
- intf->channels[chan].medium = msg->rsp[4] & 0x7f;
- intf->channels[chan].protocol = msg->rsp[5] & 0x1f;
+ intf->channels[chan].medium = msg->msg.data[2] & 0x7f;
+ intf->channels[chan].protocol = msg->msg.data[3] & 0x1f;
next_channel:
intf->curr_channel++;
@@ -1691,22 +1755,24 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
rv = -ENOMEM;
down_write(&interfaces_sem);
- for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+ for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
if (ipmi_interfaces[i] == NULL) {
new_intf->intf_num = i;
new_intf->version_major = version_major;
new_intf->version_minor = version_minor;
- if (slave_addr == 0)
- new_intf->my_address = IPMI_BMC_SLAVE_ADDR;
- else
- new_intf->my_address = slave_addr;
- new_intf->my_lun = 2; /* the SMS LUN. */
+ for (j = 0; j < IPMI_MAX_CHANNELS; j++) {
+ new_intf->channels[j].address
+ = IPMI_BMC_SLAVE_ADDR;
+ new_intf->channels[j].lun = 2;
+ }
+ if (slave_addr != 0)
+ new_intf->channels[0].address = slave_addr;
rwlock_init(&(new_intf->users_lock));
INIT_LIST_HEAD(&(new_intf->users));
new_intf->handlers = handlers;
new_intf->send_info = send_info;
spin_lock_init(&(new_intf->seq_lock));
- for (j=0; j<IPMI_IPMB_NUM_SEQ; j++) {
+ for (j = 0; j < IPMI_IPMB_NUM_SEQ; j++) {
new_intf->seq_table[j].inuse = 0;
new_intf->seq_table[j].seqid = 0;
}
@@ -1722,7 +1788,6 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
rwlock_init(&(new_intf->cmd_rcvr_lock));
init_waitqueue_head(&new_intf->waitq);
INIT_LIST_HEAD(&(new_intf->cmd_rcvrs));
- new_intf->all_cmd_rcvr = NULL;
spin_lock_init(&(new_intf->counter_lock));
@@ -1814,7 +1879,7 @@ static void clean_up_interface_data(ipmi_smi_t intf)
free_recv_msg_list(&(intf->waiting_events));
free_cmd_rcvr_list(&(intf->cmd_rcvrs));
- for (i=0; i<IPMI_IPMB_NUM_SEQ; i++) {
+ for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) {
if ((intf->seq_table[i].inuse)
&& (intf->seq_table[i].recv_msg))
{
@@ -1833,7 +1898,7 @@ int ipmi_unregister_smi(ipmi_smi_t intf)
down_write(&interfaces_sem);
if (list_empty(&(intf->users)))
{
- for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+ for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
if (ipmi_interfaces[i] == intf) {
remove_proc_entries(intf);
spin_lock_irqsave(&interfaces_lock, flags);
@@ -1960,15 +2025,11 @@ static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf,
read_lock(&(intf->cmd_rcvr_lock));
- if (intf->all_cmd_rcvr) {
- user = intf->all_cmd_rcvr;
- } else {
- /* Find the command/netfn. */
- list_for_each_entry(rcvr, &(intf->cmd_rcvrs), link) {
- if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)) {
- user = rcvr->user;
- break;
- }
+ /* Find the command/netfn. */
+ list_for_each_entry(rcvr, &(intf->cmd_rcvrs), link) {
+ if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)) {
+ user = rcvr->user;
+ break;
}
}
read_unlock(&(intf->cmd_rcvr_lock));
@@ -1985,7 +2046,7 @@ static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf,
msg->data[3] = msg->rsp[6];
msg->data[4] = ((netfn + 1) << 2) | (msg->rsp[7] & 0x3);
msg->data[5] = ipmb_checksum(&(msg->data[3]), 2);
- msg->data[6] = intf->my_address;
+ msg->data[6] = intf->channels[msg->rsp[3] & 0xf].address;
/* rqseq/lun */
msg->data[7] = (msg->rsp[7] & 0xfc) | (msg->rsp[4] & 0x3);
msg->data[8] = msg->rsp[8]; /* cmd */
@@ -1997,7 +2058,7 @@ static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf,
{
int m;
printk("Invalid command:");
- for (m=0; m<msg->data_size; m++)
+ for (m = 0; m < msg->data_size; m++)
printk(" %2.2x", msg->data[m]);
printk("\n");
}
@@ -2145,15 +2206,11 @@ static int handle_lan_get_msg_cmd(ipmi_smi_t intf,
read_lock(&(intf->cmd_rcvr_lock));
- if (intf->all_cmd_rcvr) {
- user = intf->all_cmd_rcvr;
- } else {
- /* Find the command/netfn. */
- list_for_each_entry(rcvr, &(intf->cmd_rcvrs), link) {
- if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)) {
- user = rcvr->user;
- break;
- }
+ /* Find the command/netfn. */
+ list_for_each_entry(rcvr, &(intf->cmd_rcvrs), link) {
+ if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)) {
+ user = rcvr->user;
+ break;
}
}
read_unlock(&(intf->cmd_rcvr_lock));
@@ -2330,6 +2387,14 @@ static int handle_bmc_rsp(ipmi_smi_t intf,
unsigned long flags;
recv_msg = (struct ipmi_recv_msg *) msg->user_data;
+ if (recv_msg == NULL)
+ {
+ printk(KERN_WARNING"IPMI message received with no owner. This\n"
+ "could be because of a malformed message, or\n"
+ "because of a hardware error. Contact your\n"
+ "hardware vender for assistance\n");
+ return 0;
+ }
/* Make sure the user still exists. */
list_for_each_entry(user, &(intf->users), link) {
@@ -2340,19 +2405,11 @@ static int handle_bmc_rsp(ipmi_smi_t intf,
}
}
- if (!found) {
- /* Special handling for NULL users. */
- if (!recv_msg->user && intf->null_user_handler){
- intf->null_user_handler(intf, msg);
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->handled_local_responses++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
- }else{
- /* The user for the message went away, so give up. */
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->unhandled_local_responses++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
- }
+ if ((! found) && recv_msg->user) {
+ /* The user for the message went away, so give up. */
+ spin_lock_irqsave(&intf->counter_lock, flags);
+ intf->unhandled_local_responses++;
+ spin_unlock_irqrestore(&intf->counter_lock, flags);
ipmi_free_recv_msg(recv_msg);
} else {
struct ipmi_system_interface_addr *smi_addr;
@@ -2392,7 +2449,7 @@ static int handle_new_recv_msg(ipmi_smi_t intf,
#ifdef DEBUG_MSGING
int m;
printk("Recv:");
- for (m=0; m<msg->rsp_size; m++)
+ for (m = 0; m < msg->rsp_size; m++)
printk(" %2.2x", msg->rsp[m]);
printk("\n");
#endif
@@ -2563,7 +2620,7 @@ void ipmi_smi_msg_received(ipmi_smi_t intf,
spin_lock_irqsave(&(intf->waiting_msgs_lock), flags);
if (!list_empty(&(intf->waiting_msgs))) {
list_add_tail(&(msg->link), &(intf->waiting_msgs));
- spin_unlock(&(intf->waiting_msgs_lock));
+ spin_unlock_irqrestore(&(intf->waiting_msgs_lock), flags);
goto out_unlock;
}
spin_unlock_irqrestore(&(intf->waiting_msgs_lock), flags);
@@ -2572,9 +2629,9 @@ void ipmi_smi_msg_received(ipmi_smi_t intf,
if (rv > 0) {
/* Could not handle the message now, just add it to a
list to handle later. */
- spin_lock(&(intf->waiting_msgs_lock));
+ spin_lock_irqsave(&(intf->waiting_msgs_lock), flags);
list_add_tail(&(msg->link), &(intf->waiting_msgs));
- spin_unlock(&(intf->waiting_msgs_lock));
+ spin_unlock_irqrestore(&(intf->waiting_msgs_lock), flags);
} else if (rv == 0) {
ipmi_free_smi_msg(msg);
}
@@ -2626,7 +2683,7 @@ smi_from_recv_msg(ipmi_smi_t intf, struct ipmi_recv_msg *recv_msg,
{
int m;
printk("Resend: ");
- for (m=0; m<smi_msg->data_size; m++)
+ for (m = 0; m < smi_msg->data_size; m++)
printk(" %2.2x", smi_msg->data[m]);
printk("\n");
}
@@ -2647,7 +2704,7 @@ ipmi_timeout_handler(long timeout_period)
INIT_LIST_HEAD(&timeouts);
spin_lock(&interfaces_lock);
- for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+ for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
intf = ipmi_interfaces[i];
if (intf == NULL)
continue;
@@ -2672,7 +2729,7 @@ ipmi_timeout_handler(long timeout_period)
have timed out, putting them in the timeouts
list. */
spin_lock_irqsave(&(intf->seq_lock), flags);
- for (j=0; j<IPMI_IPMB_NUM_SEQ; j++) {
+ for (j = 0; j < IPMI_IPMB_NUM_SEQ; j++) {
struct seq_table *ent = &(intf->seq_table[j]);
if (!ent->inuse)
continue;
@@ -2712,7 +2769,7 @@ ipmi_timeout_handler(long timeout_period)
spin_unlock(&intf->counter_lock);
smi_msg = smi_from_recv_msg(intf,
ent->recv_msg, j, ent->seqid);
- if(!smi_msg)
+ if (! smi_msg)
continue;
spin_unlock_irqrestore(&(intf->seq_lock),flags);
@@ -2743,7 +2800,7 @@ static void ipmi_request_event(void)
int i;
spin_lock(&interfaces_lock);
- for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+ for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
intf = ipmi_interfaces[i];
if (intf == NULL)
continue;
@@ -2838,28 +2895,30 @@ static void dummy_recv_done_handler(struct ipmi_recv_msg *msg)
}
#ifdef CONFIG_IPMI_PANIC_STRING
-static void event_receiver_fetcher(ipmi_smi_t intf, struct ipmi_smi_msg *msg)
+static void event_receiver_fetcher(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
{
- if ((msg->rsp[0] == (IPMI_NETFN_SENSOR_EVENT_RESPONSE << 2))
- && (msg->rsp[1] == IPMI_GET_EVENT_RECEIVER_CMD)
- && (msg->rsp[2] == IPMI_CC_NO_ERROR))
+ if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
+ && (msg->msg.netfn == IPMI_NETFN_SENSOR_EVENT_RESPONSE)
+ && (msg->msg.cmd == IPMI_GET_EVENT_RECEIVER_CMD)
+ && (msg->msg.data[0] == IPMI_CC_NO_ERROR))
{
/* A get event receiver command, save it. */
- intf->event_receiver = msg->rsp[3];
- intf->event_receiver_lun = msg->rsp[4] & 0x3;
+ intf->event_receiver = msg->msg.data[1];
+ intf->event_receiver_lun = msg->msg.data[2] & 0x3;
}
}
-static void device_id_fetcher(ipmi_smi_t intf, struct ipmi_smi_msg *msg)
+static void device_id_fetcher(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
{
- if ((msg->rsp[0] == (IPMI_NETFN_APP_RESPONSE << 2))
- && (msg->rsp[1] == IPMI_GET_DEVICE_ID_CMD)
- && (msg->rsp[2] == IPMI_CC_NO_ERROR))
+ if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
+ && (msg->msg.netfn == IPMI_NETFN_APP_RESPONSE)
+ && (msg->msg.cmd == IPMI_GET_DEVICE_ID_CMD)
+ && (msg->msg.data[0] == IPMI_CC_NO_ERROR))
{
/* A get device id command, save if we are an event
receiver or generator. */
- intf->local_sel_device = (msg->rsp[8] >> 2) & 1;
- intf->local_event_generator = (msg->rsp[8] >> 5) & 1;
+ intf->local_sel_device = (msg->msg.data[6] >> 2) & 1;
+ intf->local_event_generator = (msg->msg.data[6] >> 5) & 1;
}
}
#endif
@@ -2903,7 +2962,7 @@ static void send_panic_events(char *str)
recv_msg.done = dummy_recv_done_handler;
/* For every registered interface, send the event. */
- for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+ for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
intf = ipmi_interfaces[i];
if (intf == NULL)
continue;
@@ -2915,12 +2974,12 @@ static void send_panic_events(char *str)
&addr,
0,
&msg,
- NULL,
+ intf,
&smi_msg,
&recv_msg,
0,
- intf->my_address,
- intf->my_lun,
+ intf->channels[0].address,
+ intf->channels[0].lun,
0, 1); /* Don't retry, and don't wait. */
}
@@ -2930,7 +2989,7 @@ static void send_panic_events(char *str)
if (!str)
return;
- for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+ for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
char *p = str;
struct ipmi_ipmb_addr *ipmb;
int j;
@@ -2961,12 +3020,12 @@ static void send_panic_events(char *str)
&addr,
0,
&msg,
- NULL,
+ intf,
&smi_msg,
&recv_msg,
0,
- intf->my_address,
- intf->my_lun,
+ intf->channels[0].address,
+ intf->channels[0].lun,
0, 1); /* Don't retry, and don't wait. */
if (intf->local_event_generator) {
@@ -2981,12 +3040,12 @@ static void send_panic_events(char *str)
&addr,
0,
&msg,
- NULL,
+ intf,
&smi_msg,
&recv_msg,
0,
- intf->my_address,
- intf->my_lun,
+ intf->channels[0].address,
+ intf->channels[0].lun,
0, 1); /* no retry, and no wait. */
}
intf->null_user_handler = NULL;
@@ -2996,7 +3055,7 @@ static void send_panic_events(char *str)
be zero, and it must not be my address. */
if (((intf->event_receiver & 1) == 0)
&& (intf->event_receiver != 0)
- && (intf->event_receiver != intf->my_address))
+ && (intf->event_receiver != intf->channels[0].address))
{
/* The event receiver is valid, send an IPMB
message. */
@@ -3031,7 +3090,7 @@ static void send_panic_events(char *str)
data[0] = 0;
data[1] = 0;
data[2] = 0xf0; /* OEM event without timestamp. */
- data[3] = intf->my_address;
+ data[3] = intf->channels[0].address;
data[4] = j++; /* sequence # */
/* Always give 11 bytes, so strncpy will fill
it with zeroes for me. */
@@ -3043,12 +3102,12 @@ static void send_panic_events(char *str)
&addr,
0,
&msg,
- NULL,
+ intf,
&smi_msg,
&recv_msg,
0,
- intf->my_address,
- intf->my_lun,
+ intf->channels[0].address,
+ intf->channels[0].lun,
0, 1); /* no retry, and no wait. */
}
}
@@ -3070,7 +3129,7 @@ static int panic_event(struct notifier_block *this,
has_paniced = 1;
/* For every registered interface, set it to run to completion. */
- for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+ for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
intf = ipmi_interfaces[i];
if (intf == NULL)
continue;
@@ -3099,9 +3158,9 @@ static int ipmi_init_msghandler(void)
return 0;
printk(KERN_INFO "ipmi message handler version "
- IPMI_MSGHANDLER_VERSION "\n");
+ IPMI_DRIVER_VERSION "\n");
- for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+ for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
ipmi_interfaces[i] = NULL;
}
@@ -3171,6 +3230,9 @@ module_exit(cleanup_ipmi);
module_init(ipmi_init_msghandler_mod);
MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>");
+MODULE_DESCRIPTION("Incoming and outgoing message routing for an IPMI interface.");
+MODULE_VERSION(IPMI_DRIVER_VERSION);
EXPORT_SYMBOL(ipmi_create_user);
EXPORT_SYMBOL(ipmi_destroy_user);
diff --git a/drivers/char/ipmi/ipmi_poweroff.c b/drivers/char/ipmi/ipmi_poweroff.c
index f951c30..e82a96b 100644
--- a/drivers/char/ipmi/ipmi_poweroff.c
+++ b/drivers/char/ipmi/ipmi_poweroff.c
@@ -42,7 +42,6 @@
#include <linux/ipmi_smi.h>
#define PFX "IPMI poweroff: "
-#define IPMI_POWEROFF_VERSION "v33"
/* Where to we insert our poweroff function? */
extern void (*pm_power_off)(void);
@@ -53,16 +52,17 @@ extern void (*pm_power_off)(void);
#define IPMI_CHASSIS_POWER_CYCLE 0x02 /* power cycle */
/* the IPMI data command */
-static int poweroff_control = IPMI_CHASSIS_POWER_DOWN;
+static int poweroff_powercycle;
/* parameter definition to allow user to flag power cycle */
-module_param(poweroff_control, int, IPMI_CHASSIS_POWER_DOWN);
-MODULE_PARM_DESC(poweroff_control, " Set to 2 to enable power cycle instead of power down. Power cycle is contingent on hardware support, otherwise it defaults back to power down.");
+module_param(poweroff_powercycle, int, 0);
+MODULE_PARM_DESC(poweroff_powercycles, " Set to non-zero to enable power cycle instead of power down. Power cycle is contingent on hardware support, otherwise it defaults back to power down.");
/* Stuff from the get device id command. */
static unsigned int mfg_id;
static unsigned int prod_id;
static unsigned char capabilities;
+static unsigned char ipmi_version;
/* We use our own messages for this operation, we don't let the system
allocate them, since we may be in a panic situation. The whole
@@ -338,6 +338,25 @@ static void ipmi_poweroff_cpi1 (ipmi_user_t user)
}
/*
+ * ipmi_dell_chassis_detect()
+ * Dell systems with IPMI < 1.5 don't set the chassis capability bit
+ * but they can handle a chassis poweroff or powercycle command.
+ */
+
+#define DELL_IANA_MFR_ID {0xA2, 0x02, 0x00}
+static int ipmi_dell_chassis_detect (ipmi_user_t user)
+{
+ const char ipmi_version_major = ipmi_version & 0xF;
+ const char ipmi_version_minor = (ipmi_version >> 4) & 0xF;
+ const char mfr[3]=DELL_IANA_MFR_ID;
+ if (!memcmp(mfr, &mfg_id, sizeof(mfr)) &&
+ ipmi_version_major <= 1 &&
+ ipmi_version_minor < 5)
+ return 1;
+ return 0;
+}
+
+/*
* Standard chassis support
*/
@@ -366,37 +385,34 @@ static void ipmi_poweroff_chassis (ipmi_user_t user)
powercyclefailed:
printk(KERN_INFO PFX "Powering %s via IPMI chassis control command\n",
- ((poweroff_control != IPMI_CHASSIS_POWER_CYCLE) ? "down" : "cycle"));
+ (poweroff_powercycle ? "cycle" : "down"));
/*
* Power down
*/
send_msg.netfn = IPMI_NETFN_CHASSIS_REQUEST;
send_msg.cmd = IPMI_CHASSIS_CONTROL_CMD;
- data[0] = poweroff_control;
+ if (poweroff_powercycle)
+ data[0] = IPMI_CHASSIS_POWER_CYCLE;
+ else
+ data[0] = IPMI_CHASSIS_POWER_DOWN;
send_msg.data = data;
send_msg.data_len = sizeof(data);
rv = ipmi_request_in_rc_mode(user,
(struct ipmi_addr *) &smi_addr,
&send_msg);
if (rv) {
- switch (poweroff_control) {
- case IPMI_CHASSIS_POWER_CYCLE:
- /* power cycle failed, default to power down */
- printk(KERN_ERR PFX "Unable to send chassis power " \
- "cycle message, IPMI error 0x%x\n", rv);
- poweroff_control = IPMI_CHASSIS_POWER_DOWN;
- goto powercyclefailed;
-
- case IPMI_CHASSIS_POWER_DOWN:
- default:
- printk(KERN_ERR PFX "Unable to send chassis power " \
- "down message, IPMI error 0x%x\n", rv);
- break;
+ if (poweroff_powercycle) {
+ /* power cycle failed, default to power down */
+ printk(KERN_ERR PFX "Unable to send chassis power " \
+ "cycle message, IPMI error 0x%x\n", rv);
+ poweroff_powercycle = 0;
+ goto powercyclefailed;
}
- }
- return;
+ printk(KERN_ERR PFX "Unable to send chassis power " \
+ "down message, IPMI error 0x%x\n", rv);
+ }
}
@@ -414,6 +430,9 @@ static struct poweroff_function poweroff_functions[] = {
{ .platform_type = "CPI1",
.detect = ipmi_cpi1_detect,
.poweroff_func = ipmi_poweroff_cpi1 },
+ { .platform_type = "chassis",
+ .detect = ipmi_dell_chassis_detect,
+ .poweroff_func = ipmi_poweroff_chassis },
/* Chassis should generally be last, other things should override
it. */
{ .platform_type = "chassis",
@@ -499,10 +518,11 @@ static void ipmi_po_new_smi(int if_num)
prod_id = (halt_recv_msg.msg.data[10]
| (halt_recv_msg.msg.data[11] << 8));
capabilities = halt_recv_msg.msg.data[6];
+ ipmi_version = halt_recv_msg.msg.data[5];
/* Scan for a poweroff method */
- for (i=0; i<NUM_PO_FUNCS; i++) {
+ for (i = 0; i < NUM_PO_FUNCS; i++) {
if (poweroff_functions[i].detect(ipmi_user))
goto found;
}
@@ -538,39 +558,35 @@ static struct ipmi_smi_watcher smi_watcher =
#ifdef CONFIG_PROC_FS
-/* displays properties to proc */
-static int proc_read_chassctrl(char *page, char **start, off_t off, int count,
- int *eof, void *data)
-{
- return sprintf(page, "%d\t[ 0=powerdown 2=powercycle ]\n",
- poweroff_control);
-}
+#include <linux/sysctl.h>
+
+static ctl_table ipmi_table[] = {
+ { .ctl_name = DEV_IPMI_POWEROFF_POWERCYCLE,
+ .procname = "poweroff_powercycle",
+ .data = &poweroff_powercycle,
+ .maxlen = sizeof(poweroff_powercycle),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec },
+ { }
+};
-/* process property writes from proc */
-static int proc_write_chassctrl(struct file *file, const char *buffer,
- unsigned long count, void *data)
-{
- int rv = count;
- unsigned int newval = 0;
-
- sscanf(buffer, "%d", &newval);
- switch (newval) {
- case IPMI_CHASSIS_POWER_CYCLE:
- printk(KERN_INFO PFX "power cycle is now enabled\n");
- poweroff_control = newval;
- break;
-
- case IPMI_CHASSIS_POWER_DOWN:
- poweroff_control = IPMI_CHASSIS_POWER_DOWN;
- break;
-
- default:
- rv = -EINVAL;
- break;
- }
+static ctl_table ipmi_dir_table[] = {
+ { .ctl_name = DEV_IPMI,
+ .procname = "ipmi",
+ .mode = 0555,
+ .child = ipmi_table },
+ { }
+};
- return rv;
-}
+static ctl_table ipmi_root_table[] = {
+ { .ctl_name = CTL_DEV,
+ .procname = "dev",
+ .mode = 0555,
+ .child = ipmi_dir_table },
+ { }
+};
+
+static struct ctl_table_header *ipmi_table_header;
#endif /* CONFIG_PROC_FS */
/*
@@ -578,42 +594,32 @@ static int proc_write_chassctrl(struct file *file, const char *buffer,
*/
static int ipmi_poweroff_init (void)
{
- int rv;
- struct proc_dir_entry *file;
+ int rv;
printk ("Copyright (C) 2004 MontaVista Software -"
- " IPMI Powerdown via sys_reboot version "
- IPMI_POWEROFF_VERSION ".\n");
-
- switch (poweroff_control) {
- case IPMI_CHASSIS_POWER_CYCLE:
- printk(KERN_INFO PFX "Power cycle is enabled.\n");
- break;
-
- case IPMI_CHASSIS_POWER_DOWN:
- default:
- poweroff_control = IPMI_CHASSIS_POWER_DOWN;
- break;
+ " IPMI Powerdown via sys_reboot.\n");
+
+ if (poweroff_powercycle)
+ printk(KERN_INFO PFX "Power cycle is enabled.\n");
+
+#ifdef CONFIG_PROC_FS
+ ipmi_table_header = register_sysctl_table(ipmi_root_table, 1);
+ if (!ipmi_table_header) {
+ printk(KERN_ERR PFX "Unable to register powercycle sysctl\n");
+ rv = -ENOMEM;
+ goto out_err;
}
+#endif
+#ifdef CONFIG_PROC_FS
rv = ipmi_smi_watcher_register(&smi_watcher);
+#endif
if (rv) {
+ unregister_sysctl_table(ipmi_table_header);
printk(KERN_ERR PFX "Unable to register SMI watcher: %d\n", rv);
goto out_err;
}
-#ifdef CONFIG_PROC_FS
- file = create_proc_entry("poweroff_control", 0, proc_ipmi_root);
- if (!file) {
- printk(KERN_ERR PFX "Unable to create proc power control\n");
- } else {
- file->nlink = 1;
- file->read_proc = proc_read_chassctrl;
- file->write_proc = proc_write_chassctrl;
- file->owner = THIS_MODULE;
- }
-#endif
-
out_err:
return rv;
}
@@ -624,7 +630,7 @@ static __exit void ipmi_poweroff_cleanup(void)
int rv;
#ifdef CONFIG_PROC_FS
- remove_proc_entry("poweroff_control", proc_ipmi_root);
+ unregister_sysctl_table(ipmi_table_header);
#endif
ipmi_smi_watcher_unregister(&smi_watcher);
@@ -642,3 +648,5 @@ module_exit(ipmi_poweroff_cleanup);
module_init(ipmi_poweroff_init);
MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>");
+MODULE_DESCRIPTION("IPMI Poweroff extension to sys_reboot");
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index a44b973..b6e5cbf 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -61,11 +61,11 @@
# endif
static inline void add_usec_to_timer(struct timer_list *t, long v)
{
- t->sub_expires += nsec_to_arch_cycle(v * 1000);
- while (t->sub_expires >= arch_cycles_per_jiffy)
+ t->arch_cycle_expires += nsec_to_arch_cycle(v * 1000);
+ while (t->arch_cycle_expires >= arch_cycles_per_jiffy)
{
t->expires++;
- t->sub_expires -= arch_cycles_per_jiffy;
+ t->arch_cycle_expires -= arch_cycles_per_jiffy;
}
}
#endif
@@ -75,8 +75,7 @@ static inline void add_usec_to_timer(struct timer_list *t, long v)
#include <asm/io.h>
#include "ipmi_si_sm.h"
#include <linux/init.h>
-
-#define IPMI_SI_VERSION "v33"
+#include <linux/dmi.h>
/* Measure times between events in the driver. */
#undef DEBUG_TIMING
@@ -109,6 +108,21 @@ enum si_type {
SI_KCS, SI_SMIC, SI_BT
};
+struct ipmi_device_id {
+ unsigned char device_id;
+ unsigned char device_revision;
+ unsigned char firmware_revision_1;
+ unsigned char firmware_revision_2;
+ unsigned char ipmi_version;
+ unsigned char additional_device_support;
+ unsigned char manufacturer_id[3];
+ unsigned char product_id[2];
+ unsigned char aux_firmware_revision[4];
+} __attribute__((packed));
+
+#define ipmi_version_major(v) ((v)->ipmi_version & 0xf)
+#define ipmi_version_minor(v) ((v)->ipmi_version >> 4)
+
struct smi_info
{
ipmi_smi_t intf;
@@ -131,12 +145,24 @@ struct smi_info
void (*irq_cleanup)(struct smi_info *info);
unsigned int io_size;
+ /* Per-OEM handler, called from handle_flags().
+ Returns 1 when handle_flags() needs to be re-run
+ or 0 indicating it set si_state itself.
+ */
+ int (*oem_data_avail_handler)(struct smi_info *smi_info);
+
/* Flags from the last GET_MSG_FLAGS command, used when an ATTN
is set to hold the flags until we are done handling everything
from the flags. */
#define RECEIVE_MSG_AVAIL 0x01
#define EVENT_MSG_BUFFER_FULL 0x02
#define WDT_PRE_TIMEOUT_INT 0x08
+#define OEM0_DATA_AVAIL 0x20
+#define OEM1_DATA_AVAIL 0x40
+#define OEM2_DATA_AVAIL 0x80
+#define OEM_DATA_AVAIL (OEM0_DATA_AVAIL | \
+ OEM1_DATA_AVAIL | \
+ OEM2_DATA_AVAIL)
unsigned char msg_flags;
/* If set to true, this will request events the next time the
@@ -175,11 +201,7 @@ struct smi_info
interrupts. */
int interrupt_disabled;
- unsigned char ipmi_si_dev_rev;
- unsigned char ipmi_si_fw_rev_major;
- unsigned char ipmi_si_fw_rev_minor;
- unsigned char ipmi_version_major;
- unsigned char ipmi_version_minor;
+ struct ipmi_device_id device_id;
/* Slave address, could be reported from DMI. */
unsigned char slave_addr;
@@ -245,7 +267,7 @@ static enum si_sm_result start_next_msg(struct smi_info *smi_info)
entry = smi_info->xmit_msgs.next;
}
- if (!entry) {
+ if (! entry) {
smi_info->curr_msg = NULL;
rv = SI_SM_IDLE;
} else {
@@ -306,7 +328,7 @@ static void start_clear_flags(struct smi_info *smi_info)
memory, we will re-enable the interrupt. */
static inline void disable_si_irq(struct smi_info *smi_info)
{
- if ((smi_info->irq) && (!smi_info->interrupt_disabled)) {
+ if ((smi_info->irq) && (! smi_info->interrupt_disabled)) {
disable_irq_nosync(smi_info->irq);
smi_info->interrupt_disabled = 1;
}
@@ -322,6 +344,7 @@ static inline void enable_si_irq(struct smi_info *smi_info)
static void handle_flags(struct smi_info *smi_info)
{
+ retry:
if (smi_info->msg_flags & WDT_PRE_TIMEOUT_INT) {
/* Watchdog pre-timeout */
spin_lock(&smi_info->count_lock);
@@ -336,7 +359,7 @@ static void handle_flags(struct smi_info *smi_info)
} else if (smi_info->msg_flags & RECEIVE_MSG_AVAIL) {
/* Messages available. */
smi_info->curr_msg = ipmi_alloc_smi_msg();
- if (!smi_info->curr_msg) {
+ if (! smi_info->curr_msg) {
disable_si_irq(smi_info);
smi_info->si_state = SI_NORMAL;
return;
@@ -355,7 +378,7 @@ static void handle_flags(struct smi_info *smi_info)
} else if (smi_info->msg_flags & EVENT_MSG_BUFFER_FULL) {
/* Events available. */
smi_info->curr_msg = ipmi_alloc_smi_msg();
- if (!smi_info->curr_msg) {
+ if (! smi_info->curr_msg) {
disable_si_irq(smi_info);
smi_info->si_state = SI_NORMAL;
return;
@@ -371,6 +394,10 @@ static void handle_flags(struct smi_info *smi_info)
smi_info->curr_msg->data,
smi_info->curr_msg->data_size);
smi_info->si_state = SI_GETTING_EVENTS;
+ } else if (smi_info->msg_flags & OEM_DATA_AVAIL) {
+ if (smi_info->oem_data_avail_handler)
+ if (smi_info->oem_data_avail_handler(smi_info))
+ goto retry;
} else {
smi_info->si_state = SI_NORMAL;
}
@@ -387,7 +414,7 @@ static void handle_transaction_done(struct smi_info *smi_info)
#endif
switch (smi_info->si_state) {
case SI_NORMAL:
- if (!smi_info->curr_msg)
+ if (! smi_info->curr_msg)
break;
smi_info->curr_msg->rsp_size
@@ -761,18 +788,20 @@ static void si_restart_short_timer(struct smi_info *smi_info)
#if defined(CONFIG_HIGH_RES_TIMERS)
unsigned long flags;
unsigned long jiffies_now;
+ unsigned long seq;
if (del_timer(&(smi_info->si_timer))) {
/* If we don't delete the timer, then it will go off
immediately, anyway. So we only process if we
actually delete the timer. */
- /* We already have irqsave on, so no need for it
- here. */
- read_lock(&xtime_lock);
- jiffies_now = jiffies;
- smi_info->si_timer.expires = jiffies_now;
- smi_info->si_timer.sub_expires = get_arch_cycles(jiffies_now);
+ do {
+ seq = read_seqbegin_irqsave(&xtime_lock, flags);
+ jiffies_now = jiffies;
+ smi_info->si_timer.expires = jiffies_now;
+ smi_info->si_timer.arch_cycle_expires
+ = get_arch_cycles(jiffies_now);
+ } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
add_usec_to_timer(&smi_info->si_timer, SI_SHORT_TIMEOUT_USEC);
@@ -826,15 +855,19 @@ static void smi_timeout(unsigned long data)
/* If the state machine asks for a short delay, then shorten
the timer timeout. */
if (smi_result == SI_SM_CALL_WITH_DELAY) {
+#if defined(CONFIG_HIGH_RES_TIMERS)
+ unsigned long seq;
+#endif
spin_lock_irqsave(&smi_info->count_lock, flags);
smi_info->short_timeouts++;
spin_unlock_irqrestore(&smi_info->count_lock, flags);
#if defined(CONFIG_HIGH_RES_TIMERS)
- read_lock(&xtime_lock);
- smi_info->si_timer.expires = jiffies;
- smi_info->si_timer.sub_expires
- = get_arch_cycles(smi_info->si_timer.expires);
- read_unlock(&xtime_lock);
+ do {
+ seq = read_seqbegin_irqsave(&xtime_lock, flags);
+ smi_info->si_timer.expires = jiffies;
+ smi_info->si_timer.arch_cycle_expires
+ = get_arch_cycles(smi_info->si_timer.expires);
+ } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
add_usec_to_timer(&smi_info->si_timer, SI_SHORT_TIMEOUT_USEC);
#else
smi_info->si_timer.expires = jiffies + 1;
@@ -845,7 +878,7 @@ static void smi_timeout(unsigned long data)
spin_unlock_irqrestore(&smi_info->count_lock, flags);
smi_info->si_timer.expires = jiffies + SI_TIMEOUT_JIFFIES;
#if defined(CONFIG_HIGH_RES_TIMERS)
- smi_info->si_timer.sub_expires = 0;
+ smi_info->si_timer.arch_cycle_expires = 0;
#endif
}
@@ -986,7 +1019,7 @@ MODULE_PARM_DESC(slave_addrs, "Set the default IPMB slave address for"
#define IPMI_MEM_ADDR_SPACE 1
#define IPMI_IO_ADDR_SPACE 2
-#if defined(CONFIG_ACPI_INTERPRETER) || defined(CONFIG_X86) || defined(CONFIG_PCI)
+#if defined(CONFIG_ACPI) || defined(CONFIG_X86) || defined(CONFIG_PCI)
static int is_new_interface(int intf, u8 addr_space, unsigned long base_addr)
{
int i;
@@ -1014,7 +1047,7 @@ static int std_irq_setup(struct smi_info *info)
{
int rv;
- if (!info->irq)
+ if (! info->irq)
return 0;
if (info->si_type == SI_BT) {
@@ -1023,7 +1056,7 @@ static int std_irq_setup(struct smi_info *info)
SA_INTERRUPT,
DEVICE_NAME,
info);
- if (!rv)
+ if (! rv)
/* Enable the interrupt in the BT interface. */
info->io.outputb(&info->io, IPMI_BT_INTMASK_REG,
IPMI_BT_INTMASK_ENABLE_IRQ_BIT);
@@ -1048,7 +1081,7 @@ static int std_irq_setup(struct smi_info *info)
static void std_irq_cleanup(struct smi_info *info)
{
- if (!info->irq)
+ if (! info->irq)
return;
if (info->si_type == SI_BT)
@@ -1121,7 +1154,7 @@ static int port_setup(struct smi_info *info)
unsigned int *addr = info->io.info;
int mapsize;
- if (!addr || (!*addr))
+ if (! addr || (! *addr))
return -ENODEV;
info->io_cleanup = port_cleanup;
@@ -1164,15 +1197,15 @@ static int try_init_port(int intf_num, struct smi_info **new_info)
{
struct smi_info *info;
- if (!ports[intf_num])
+ if (! ports[intf_num])
return -ENODEV;
- if (!is_new_interface(intf_num, IPMI_IO_ADDR_SPACE,
+ if (! is_new_interface(intf_num, IPMI_IO_ADDR_SPACE,
ports[intf_num]))
return -ENODEV;
info = kmalloc(sizeof(*info), GFP_KERNEL);
- if (!info) {
+ if (! info) {
printk(KERN_ERR "ipmi_si: Could not allocate SI data (1)\n");
return -ENOMEM;
}
@@ -1182,10 +1215,10 @@ static int try_init_port(int intf_num, struct smi_info **new_info)
info->io.info = &(ports[intf_num]);
info->io.addr = NULL;
info->io.regspacing = regspacings[intf_num];
- if (!info->io.regspacing)
+ if (! info->io.regspacing)
info->io.regspacing = DEFAULT_REGSPACING;
info->io.regsize = regsizes[intf_num];
- if (!info->io.regsize)
+ if (! info->io.regsize)
info->io.regsize = DEFAULT_REGSPACING;
info->io.regshift = regshifts[intf_num];
info->irq = 0;
@@ -1270,7 +1303,7 @@ static int mem_setup(struct smi_info *info)
unsigned long *addr = info->io.info;
int mapsize;
- if (!addr || (!*addr))
+ if (! addr || (! *addr))
return -ENODEV;
info->io_cleanup = mem_cleanup;
@@ -1325,15 +1358,15 @@ static int try_init_mem(int intf_num, struct smi_info **new_info)
{
struct smi_info *info;
- if (!addrs[intf_num])
+ if (! addrs[intf_num])
return -ENODEV;
- if (!is_new_interface(intf_num, IPMI_MEM_ADDR_SPACE,
+ if (! is_new_interface(intf_num, IPMI_MEM_ADDR_SPACE,
addrs[intf_num]))
return -ENODEV;
info = kmalloc(sizeof(*info), GFP_KERNEL);
- if (!info) {
+ if (! info) {
printk(KERN_ERR "ipmi_si: Could not allocate SI data (2)\n");
return -ENOMEM;
}
@@ -1343,10 +1376,10 @@ static int try_init_mem(int intf_num, struct smi_info **new_info)
info->io.info = &addrs[intf_num];
info->io.addr = NULL;
info->io.regspacing = regspacings[intf_num];
- if (!info->io.regspacing)
+ if (! info->io.regspacing)
info->io.regspacing = DEFAULT_REGSPACING;
info->io.regsize = regsizes[intf_num];
- if (!info->io.regsize)
+ if (! info->io.regsize)
info->io.regsize = DEFAULT_REGSPACING;
info->io.regshift = regshifts[intf_num];
info->irq = 0;
@@ -1362,7 +1395,7 @@ static int try_init_mem(int intf_num, struct smi_info **new_info)
}
-#ifdef CONFIG_ACPI_INTERPRETER
+#ifdef CONFIG_ACPI
#include <linux/acpi.h>
@@ -1404,7 +1437,7 @@ static int acpi_gpe_irq_setup(struct smi_info *info)
{
acpi_status status;
- if (!info->irq)
+ if (! info->irq)
return 0;
/* FIXME - is level triggered right? */
@@ -1428,7 +1461,7 @@ static int acpi_gpe_irq_setup(struct smi_info *info)
static void acpi_gpe_irq_cleanup(struct smi_info *info)
{
- if (!info->irq)
+ if (! info->irq)
return;
acpi_remove_gpe_handler(NULL, info->irq, &ipmi_acpi_gpe);
@@ -1484,6 +1517,9 @@ static int try_init_acpi(int intf_num, struct smi_info **new_info)
char *io_type;
u8 addr_space;
+ if (acpi_disabled)
+ return -ENODEV;
+
if (acpi_failure)
return -ENODEV;
@@ -1504,10 +1540,10 @@ static int try_init_acpi(int intf_num, struct smi_info **new_info)
addr_space = IPMI_MEM_ADDR_SPACE;
else
addr_space = IPMI_IO_ADDR_SPACE;
- if (!is_new_interface(-1, addr_space, spmi->addr.address))
+ if (! is_new_interface(-1, addr_space, spmi->addr.address))
return -ENODEV;
- if (!spmi->addr.register_bit_width) {
+ if (! spmi->addr.register_bit_width) {
acpi_failure = 1;
return -ENODEV;
}
@@ -1534,7 +1570,7 @@ static int try_init_acpi(int intf_num, struct smi_info **new_info)
}
info = kmalloc(sizeof(*info), GFP_KERNEL);
- if (!info) {
+ if (! info) {
printk(KERN_ERR "ipmi_si: Could not allocate SI data (3)\n");
return -ENOMEM;
}
@@ -1610,22 +1646,15 @@ typedef struct dmi_ipmi_data
static dmi_ipmi_data_t dmi_data[SI_MAX_DRIVERS];
static int dmi_data_entries;
-typedef struct dmi_header
-{
- u8 type;
- u8 length;
- u16 handle;
-} dmi_header_t;
-
-static int decode_dmi(dmi_header_t __iomem *dm, int intf_num)
+static int __init decode_dmi(struct dmi_header *dm, int intf_num)
{
- u8 __iomem *data = (u8 __iomem *)dm;
+ u8 *data = (u8 *)dm;
unsigned long base_addr;
u8 reg_spacing;
- u8 len = readb(&dm->length);
+ u8 len = dm->length;
dmi_ipmi_data_t *ipmi_data = dmi_data+intf_num;
- ipmi_data->type = readb(&data[4]);
+ ipmi_data->type = data[4];
memcpy(&base_addr, data+8, sizeof(unsigned long));
if (len >= 0x11) {
@@ -1640,12 +1669,12 @@ static int decode_dmi(dmi_header_t __iomem *dm, int intf_num)
}
/* If bit 4 of byte 0x10 is set, then the lsb for the address
is odd. */
- ipmi_data->base_addr = base_addr | ((readb(&data[0x10]) & 0x10) >> 4);
+ ipmi_data->base_addr = base_addr | ((data[0x10] & 0x10) >> 4);
- ipmi_data->irq = readb(&data[0x11]);
+ ipmi_data->irq = data[0x11];
/* The top two bits of byte 0x10 hold the register spacing. */
- reg_spacing = (readb(&data[0x10]) & 0xC0) >> 6;
+ reg_spacing = (data[0x10] & 0xC0) >> 6;
switch(reg_spacing){
case 0x00: /* Byte boundaries */
ipmi_data->offset = 1;
@@ -1673,7 +1702,7 @@ static int decode_dmi(dmi_header_t __iomem *dm, int intf_num)
ipmi_data->offset = 1;
}
- ipmi_data->slave_addr = readb(&data[6]);
+ ipmi_data->slave_addr = data[6];
if (is_new_interface(-1, ipmi_data->addr_space,ipmi_data->base_addr)) {
dmi_data_entries++;
@@ -1685,94 +1714,29 @@ static int decode_dmi(dmi_header_t __iomem *dm, int intf_num)
return -1;
}
-static int dmi_table(u32 base, int len, int num)
+static void __init dmi_find_bmc(void)
{
- u8 __iomem *buf;
- struct dmi_header __iomem *dm;
- u8 __iomem *data;
- int i=1;
- int status=-1;
+ struct dmi_device *dev = NULL;
int intf_num = 0;
- buf = ioremap(base, len);
- if(buf==NULL)
- return -1;
-
- data = buf;
-
- while(i<num && (data - buf) < len)
- {
- dm=(dmi_header_t __iomem *)data;
-
- if((data-buf+readb(&dm->length)) >= len)
- break;
-
- if (readb(&dm->type) == 38) {
- if (decode_dmi(dm, intf_num) == 0) {
- intf_num++;
- if (intf_num >= SI_MAX_DRIVERS)
- break;
- }
- }
-
- data+=readb(&dm->length);
- while((data-buf) < len && (readb(data)||readb(data+1)))
- data++;
- data+=2;
- i++;
- }
- iounmap(buf);
-
- return status;
-}
-
-static inline int dmi_checksum(u8 *buf)
-{
- u8 sum=0;
- int a;
-
- for(a=0; a<15; a++)
- sum+=buf[a];
- return (sum==0);
-}
-
-static int dmi_decode(void)
-{
- u8 buf[15];
- u32 fp=0xF0000;
-
-#ifdef CONFIG_SIMNOW
- return -1;
-#endif
-
- while(fp < 0xFFFFF)
- {
- isa_memcpy_fromio(buf, fp, 15);
- if(memcmp(buf, "_DMI_", 5)==0 && dmi_checksum(buf))
- {
- u16 num=buf[13]<<8|buf[12];
- u16 len=buf[7]<<8|buf[6];
- u32 base=buf[11]<<24|buf[10]<<16|buf[9]<<8|buf[8];
+ while ((dev = dmi_find_device(DMI_DEV_TYPE_IPMI, NULL, dev))) {
+ if (intf_num >= SI_MAX_DRIVERS)
+ break;
- if(dmi_table(base, len, num) == 0)
- return 0;
- }
- fp+=16;
+ decode_dmi((struct dmi_header *) dev->device_data, intf_num++);
}
-
- return -1;
}
static int try_init_smbios(int intf_num, struct smi_info **new_info)
{
- struct smi_info *info;
- dmi_ipmi_data_t *ipmi_data = dmi_data+intf_num;
- char *io_type;
+ struct smi_info *info;
+ dmi_ipmi_data_t *ipmi_data = dmi_data+intf_num;
+ char *io_type;
if (intf_num >= dmi_data_entries)
return -ENODEV;
- switch(ipmi_data->type) {
+ switch (ipmi_data->type) {
case 0x01: /* KCS */
si_type[intf_num] = "kcs";
break;
@@ -1787,7 +1751,7 @@ static int try_init_smbios(int intf_num, struct smi_info **new_info)
}
info = kmalloc(sizeof(*info), GFP_KERNEL);
- if (!info) {
+ if (! info) {
printk(KERN_ERR "ipmi_si: Could not allocate SI data (4)\n");
return -ENOMEM;
}
@@ -1811,7 +1775,7 @@ static int try_init_smbios(int intf_num, struct smi_info **new_info)
regspacings[intf_num] = ipmi_data->offset;
info->io.regspacing = regspacings[intf_num];
- if (!info->io.regspacing)
+ if (! info->io.regspacing)
info->io.regspacing = DEFAULT_REGSPACING;
info->io.regsize = DEFAULT_REGSPACING;
info->io.regshift = regshifts[intf_num];
@@ -1853,14 +1817,14 @@ static int find_pci_smic(int intf_num, struct smi_info **new_info)
pci_smic_checked = 1;
- if ((pci_dev = pci_get_device(PCI_HP_VENDOR_ID, PCI_MMC_DEVICE_ID,
- NULL)))
- ;
- else if ((pci_dev = pci_get_class(PCI_ERMC_CLASSCODE, NULL)) &&
- pci_dev->subsystem_vendor == PCI_HP_VENDOR_ID)
- fe_rmc = 1;
- else
- return -ENODEV;
+ pci_dev = pci_get_device(PCI_HP_VENDOR_ID, PCI_MMC_DEVICE_ID, NULL);
+ if (! pci_dev) {
+ pci_dev = pci_get_class(PCI_ERMC_CLASSCODE, NULL);
+ if (pci_dev && (pci_dev->subsystem_vendor == PCI_HP_VENDOR_ID))
+ fe_rmc = 1;
+ else
+ return -ENODEV;
+ }
error = pci_read_config_word(pci_dev, PCI_MMC_ADDR_CW, &base_addr);
if (error)
@@ -1873,7 +1837,7 @@ static int find_pci_smic(int intf_num, struct smi_info **new_info)
}
/* Bit 0: 1 specifies programmed I/O, 0 specifies memory mapped I/O */
- if (!(base_addr & 0x0001))
+ if (! (base_addr & 0x0001))
{
pci_dev_put(pci_dev);
printk(KERN_ERR
@@ -1883,17 +1847,17 @@ static int find_pci_smic(int intf_num, struct smi_info **new_info)
}
base_addr &= 0xFFFE;
- if (!fe_rmc)
+ if (! fe_rmc)
/* Data register starts at base address + 1 in eRMC */
++base_addr;
- if (!is_new_interface(-1, IPMI_IO_ADDR_SPACE, base_addr)) {
+ if (! is_new_interface(-1, IPMI_IO_ADDR_SPACE, base_addr)) {
pci_dev_put(pci_dev);
return -ENODEV;
}
info = kmalloc(sizeof(*info), GFP_KERNEL);
- if (!info) {
+ if (! info) {
pci_dev_put(pci_dev);
printk(KERN_ERR "ipmi_si: Could not allocate SI data (5)\n");
return -ENOMEM;
@@ -1904,7 +1868,7 @@ static int find_pci_smic(int intf_num, struct smi_info **new_info)
ports[intf_num] = base_addr;
info->io.info = &(ports[intf_num]);
info->io.regspacing = regspacings[intf_num];
- if (!info->io.regspacing)
+ if (! info->io.regspacing)
info->io.regspacing = DEFAULT_REGSPACING;
info->io.regsize = DEFAULT_REGSPACING;
info->io.regshift = regshifts[intf_num];
@@ -1925,7 +1889,7 @@ static int find_pci_smic(int intf_num, struct smi_info **new_info)
static int try_init_plug_and_play(int intf_num, struct smi_info **new_info)
{
#ifdef CONFIG_PCI
- if (find_pci_smic(intf_num, new_info)==0)
+ if (find_pci_smic(intf_num, new_info) == 0)
return 0;
#endif
/* Include other methods here. */
@@ -1943,7 +1907,7 @@ static int try_get_dev_id(struct smi_info *smi_info)
int rv = 0;
resp = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL);
- if (!resp)
+ if (! resp)
return -ENOMEM;
/* Do a Get Device ID command, since it comes back with some
@@ -1956,8 +1920,7 @@ static int try_get_dev_id(struct smi_info *smi_info)
for (;;)
{
if (smi_result == SI_SM_CALL_WITH_DELAY) {
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(1);
+ schedule_timeout_uninterruptible(1);
smi_result = smi_info->handlers->event(
smi_info->si_sm, 100);
}
@@ -1992,11 +1955,8 @@ static int try_get_dev_id(struct smi_info *smi_info)
}
/* Record info from the get device id, in case we need it. */
- smi_info->ipmi_si_dev_rev = resp[4] & 0xf;
- smi_info->ipmi_si_fw_rev_major = resp[5] & 0x7f;
- smi_info->ipmi_si_fw_rev_minor = resp[6];
- smi_info->ipmi_version_major = resp[7] & 0xf;
- smi_info->ipmi_version_minor = resp[7] >> 4;
+ memcpy(&smi_info->device_id, &resp[3],
+ min_t(unsigned long, resp_len-3, sizeof(smi_info->device_id)));
out:
kfree(resp);
@@ -2028,7 +1988,7 @@ static int stat_file_read_proc(char *page, char **start, off_t off,
struct smi_info *smi = data;
out += sprintf(out, "interrupts_enabled: %d\n",
- smi->irq && !smi->interrupt_disabled);
+ smi->irq && ! smi->interrupt_disabled);
out += sprintf(out, "short_timeouts: %ld\n",
smi->short_timeouts);
out += sprintf(out, "long_timeouts: %ld\n",
@@ -2057,6 +2017,73 @@ static int stat_file_read_proc(char *page, char **start, off_t off,
return (out - ((char *) page));
}
+/*
+ * oem_data_avail_to_receive_msg_avail
+ * @info - smi_info structure with msg_flags set
+ *
+ * Converts flags from OEM_DATA_AVAIL to RECEIVE_MSG_AVAIL
+ * Returns 1 indicating need to re-run handle_flags().
+ */
+static int oem_data_avail_to_receive_msg_avail(struct smi_info *smi_info)
+{
+ smi_info->msg_flags = ((smi_info->msg_flags & ~OEM_DATA_AVAIL) |
+ RECEIVE_MSG_AVAIL);
+ return 1;
+}
+
+/*
+ * setup_dell_poweredge_oem_data_handler
+ * @info - smi_info.device_id must be populated
+ *
+ * Systems that match, but have firmware version < 1.40 may assert
+ * OEM0_DATA_AVAIL on their own, without being told via Set Flags that
+ * it's safe to do so. Such systems will de-assert OEM1_DATA_AVAIL
+ * upon receipt of IPMI_GET_MSG_CMD, so we should treat these flags
+ * as RECEIVE_MSG_AVAIL instead.
+ *
+ * As Dell has no plans to release IPMI 1.5 firmware that *ever*
+ * assert the OEM[012] bits, and if it did, the driver would have to
+ * change to handle that properly, we don't actually check for the
+ * firmware version.
+ * Device ID = 0x20 BMC on PowerEdge 8G servers
+ * Device Revision = 0x80
+ * Firmware Revision1 = 0x01 BMC version 1.40
+ * Firmware Revision2 = 0x40 BCD encoded
+ * IPMI Version = 0x51 IPMI 1.5
+ * Manufacturer ID = A2 02 00 Dell IANA
+ *
+ */
+#define DELL_POWEREDGE_8G_BMC_DEVICE_ID 0x20
+#define DELL_POWEREDGE_8G_BMC_DEVICE_REV 0x80
+#define DELL_POWEREDGE_8G_BMC_IPMI_VERSION 0x51
+#define DELL_IANA_MFR_ID {0xA2, 0x02, 0x00}
+static void setup_dell_poweredge_oem_data_handler(struct smi_info *smi_info)
+{
+ struct ipmi_device_id *id = &smi_info->device_id;
+ const char mfr[3]=DELL_IANA_MFR_ID;
+ if (! memcmp(mfr, id->manufacturer_id, sizeof(mfr))
+ && (id->device_id == DELL_POWEREDGE_8G_BMC_DEVICE_ID)
+ && (id->device_revision == DELL_POWEREDGE_8G_BMC_DEVICE_REV)
+ && (id->ipmi_version == DELL_POWEREDGE_8G_BMC_IPMI_VERSION))
+ {
+ smi_info->oem_data_avail_handler =
+ oem_data_avail_to_receive_msg_avail;
+ }
+}
+
+/*
+ * setup_oem_data_handler
+ * @info - smi_info.device_id must be filled in already
+ *
+ * Fills in smi_info.device_id.oem_data_available_handler
+ * when we know what function to use there.
+ */
+
+static void setup_oem_data_handler(struct smi_info *smi_info)
+{
+ setup_dell_poweredge_oem_data_handler(smi_info);
+}
+
/* Returns 0 if initialized, or negative on an error. */
static int init_one_smi(int intf_num, struct smi_info **smi)
{
@@ -2067,20 +2094,16 @@ static int init_one_smi(int intf_num, struct smi_info **smi)
rv = try_init_mem(intf_num, &new_smi);
if (rv)
rv = try_init_port(intf_num, &new_smi);
-#ifdef CONFIG_ACPI_INTERPRETER
- if ((rv) && (si_trydefaults)) {
+#ifdef CONFIG_ACPI
+ if (rv && si_trydefaults)
rv = try_init_acpi(intf_num, &new_smi);
- }
#endif
#ifdef CONFIG_X86
- if ((rv) && (si_trydefaults)) {
+ if (rv && si_trydefaults)
rv = try_init_smbios(intf_num, &new_smi);
- }
#endif
- if ((rv) && (si_trydefaults)) {
+ if (rv && si_trydefaults)
rv = try_init_plug_and_play(intf_num, &new_smi);
- }
-
if (rv)
return rv;
@@ -2090,7 +2113,7 @@ static int init_one_smi(int intf_num, struct smi_info **smi)
new_smi->si_sm = NULL;
new_smi->handlers = NULL;
- if (!new_smi->irq_setup) {
+ if (! new_smi->irq_setup) {
new_smi->irq = irqs[intf_num];
new_smi->irq_setup = std_irq_setup;
new_smi->irq_cleanup = std_irq_cleanup;
@@ -2124,7 +2147,7 @@ static int init_one_smi(int intf_num, struct smi_info **smi)
/* Allocate the state machine's data and initialize it. */
new_smi->si_sm = kmalloc(new_smi->handlers->size(), GFP_KERNEL);
- if (!new_smi->si_sm) {
+ if (! new_smi->si_sm) {
printk(" Could not allocate state machine memory\n");
rv = -ENOMEM;
goto out_err;
@@ -2155,6 +2178,8 @@ static int init_one_smi(int intf_num, struct smi_info **smi)
if (rv)
goto out_err;
+ setup_oem_data_handler(new_smi);
+
/* Try to claim any interrupts. */
new_smi->irq_setup(new_smi);
@@ -2188,8 +2213,8 @@ static int init_one_smi(int intf_num, struct smi_info **smi)
rv = ipmi_register_smi(&handlers,
new_smi,
- new_smi->ipmi_version_major,
- new_smi->ipmi_version_minor,
+ ipmi_version_major(&new_smi->device_id),
+ ipmi_version_minor(&new_smi->device_id),
new_smi->slave_addr,
&(new_smi->intf));
if (rv) {
@@ -2230,10 +2255,8 @@ static int init_one_smi(int intf_num, struct smi_info **smi)
/* Wait for the timer to stop. This avoids problems with race
conditions removing the timer here. */
- while (!new_smi->timer_stopped) {
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(1);
- }
+ while (!new_smi->timer_stopped)
+ schedule_timeout_uninterruptible(1);
out_err:
if (new_smi->intf)
@@ -2270,7 +2293,7 @@ static __init int init_ipmi_si(void)
/* Parse out the si_type string into its components. */
str = si_type_str;
if (*str != '\0') {
- for (i=0; (i<SI_MAX_PARMS) && (*str != '\0'); i++) {
+ for (i = 0; (i < SI_MAX_PARMS) && (*str != '\0'); i++) {
si_type[i] = str;
str = strchr(str, ',');
if (str) {
@@ -2282,22 +2305,14 @@ static __init int init_ipmi_si(void)
}
}
- printk(KERN_INFO "IPMI System Interface driver version "
- IPMI_SI_VERSION);
- if (kcs_smi_handlers.version)
- printk(", KCS version %s", kcs_smi_handlers.version);
- if (smic_smi_handlers.version)
- printk(", SMIC version %s", smic_smi_handlers.version);
- if (bt_smi_handlers.version)
- printk(", BT version %s", bt_smi_handlers.version);
- printk("\n");
+ printk(KERN_INFO "IPMI System Interface driver.\n");
#ifdef CONFIG_X86
- dmi_decode();
+ dmi_find_bmc();
#endif
rv = init_one_smi(0, &(smi_infos[pos]));
- if (rv && !ports[0] && si_trydefaults) {
+ if (rv && ! ports[0] && si_trydefaults) {
/* If we are trying defaults and the initial port is
not set, then set it. */
si_type[0] = "kcs";
@@ -2319,7 +2334,7 @@ static __init int init_ipmi_si(void)
if (rv == 0)
pos++;
- for (i=1; i < SI_MAX_PARMS; i++) {
+ for (i = 1; i < SI_MAX_PARMS; i++) {
rv = init_one_smi(i, &(smi_infos[pos]));
if (rv == 0)
pos++;
@@ -2361,17 +2376,14 @@ static void __exit cleanup_one_si(struct smi_info *to_clean)
/* Wait for the timer to stop. This avoids problems with race
conditions removing the timer here. */
- while (!to_clean->timer_stopped) {
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(1);
- }
+ while (!to_clean->timer_stopped)
+ schedule_timeout_uninterruptible(1);
/* Interrupts and timeouts are stopped, now make sure the
interface is in a clean state. */
- while ((to_clean->curr_msg) || (to_clean->si_state != SI_NORMAL)) {
+ while (to_clean->curr_msg || (to_clean->si_state != SI_NORMAL)) {
poll(to_clean);
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(1);
+ schedule_timeout_uninterruptible(1);
}
rv = ipmi_unregister_smi(to_clean->intf);
@@ -2392,13 +2404,15 @@ static __exit void cleanup_ipmi_si(void)
{
int i;
- if (!initialized)
+ if (! initialized)
return;
- for (i=0; i<SI_MAX_DRIVERS; i++) {
+ for (i = 0; i < SI_MAX_DRIVERS; i++) {
cleanup_one_si(smi_infos[i]);
}
}
module_exit(cleanup_ipmi_si);
MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>");
+MODULE_DESCRIPTION("Interface to the IPMI driver for the KCS, SMIC, and BT system interfaces.");
diff --git a/drivers/char/ipmi/ipmi_smic_sm.c b/drivers/char/ipmi/ipmi_smic_sm.c
index ae18747..add2aa2 100644
--- a/drivers/char/ipmi/ipmi_smic_sm.c
+++ b/drivers/char/ipmi/ipmi_smic_sm.c
@@ -46,8 +46,6 @@
#include <linux/ipmi_msgdefs.h> /* for completion codes */
#include "ipmi_si_sm.h"
-#define IPMI_SMIC_VERSION "v33"
-
/* smic_debug is a bit-field
* SMIC_DEBUG_ENABLE - turned on for now
* SMIC_DEBUG_MSG - commands and their responses
@@ -588,7 +586,6 @@ static int smic_size(void)
struct si_sm_handlers smic_smi_handlers =
{
- .version = IPMI_SMIC_VERSION,
.init_data = init_smic_data,
.start_transaction = start_smic_transaction,
.get_result = smic_get_result,
diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c
index d35a953..2da64bf 100644
--- a/drivers/char/ipmi/ipmi_watchdog.c
+++ b/drivers/char/ipmi/ipmi_watchdog.c
@@ -53,8 +53,6 @@
#define PFX "IPMI Watchdog: "
-#define IPMI_WATCHDOG_VERSION "v33"
-
/*
* The IPMI command/response information for the watchdog timer.
*/
@@ -259,7 +257,7 @@ static int i_ipmi_set_timeout(struct ipmi_smi_msg *smi_msg,
data[1] = 0;
WDOG_SET_TIMEOUT_ACT(data[1], ipmi_watchdog_state);
- if (pretimeout > 0) {
+ if ((pretimeout > 0) && (ipmi_watchdog_state != WDOG_TIMEOUT_NONE)) {
WDOG_SET_PRETIMEOUT_ACT(data[1], preaction_val);
data[2] = pretimeout;
} else {
@@ -659,19 +657,18 @@ static ssize_t ipmi_read(struct file *file,
static int ipmi_open(struct inode *ino, struct file *filep)
{
- switch (iminor(ino))
- {
- case WATCHDOG_MINOR:
- if(test_and_set_bit(0, &ipmi_wdog_open))
+ switch (iminor(ino)) {
+ case WATCHDOG_MINOR:
+ if (test_and_set_bit(0, &ipmi_wdog_open))
return -EBUSY;
- /* Don't start the timer now, let it start on the
- first heartbeat. */
- ipmi_start_timer_on_heartbeat = 1;
- return nonseekable_open(ino, filep);
+ /* Don't start the timer now, let it start on the
+ first heartbeat. */
+ ipmi_start_timer_on_heartbeat = 1;
+ return nonseekable_open(ino, filep);
- default:
- return (-ENODEV);
+ default:
+ return (-ENODEV);
}
}
@@ -817,15 +814,19 @@ static void ipmi_register_watchdog(int ipmi_intf)
static int
ipmi_nmi(void *dev_id, struct pt_regs *regs, int cpu, int handled)
{
+ /* If we are not expecting a timeout, ignore it. */
+ if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE)
+ return NOTIFY_DONE;
+
/* If no one else handled the NMI, we assume it was the IPMI
watchdog. */
- if ((!handled) && (preop_val == WDOG_PREOP_PANIC))
+ if ((!handled) && (preop_val == WDOG_PREOP_PANIC)) {
+ /* On some machines, the heartbeat will give
+ an error and not work unless we re-enable
+ the timer. So do so. */
+ pretimeout_since_last_heartbeat = 1;
panic(PFX "pre-timeout");
-
- /* On some machines, the heartbeat will give
- an error and not work unless we re-enable
- the timer. So do so. */
- pretimeout_since_last_heartbeat = 1;
+ }
return NOTIFY_DONE;
}
@@ -924,9 +925,6 @@ static int __init ipmi_wdog_init(void)
{
int rv;
- printk(KERN_INFO PFX "driver version "
- IPMI_WATCHDOG_VERSION "\n");
-
if (strcmp(action, "reset") == 0) {
action_val = WDOG_TIMEOUT_RESET;
} else if (strcmp(action, "none") == 0) {
@@ -1011,6 +1009,8 @@ static int __init ipmi_wdog_init(void)
register_reboot_notifier(&wdog_reboot_notifier);
notifier_chain_register(&panic_notifier_list, &wdog_panic_notifier);
+ printk(KERN_INFO PFX "driver initialized\n");
+
return 0;
}
@@ -1037,10 +1037,8 @@ static __exit void ipmi_unregister_watchdog(void)
/* Wait to make sure the message makes it out. The lower layer has
pointers to our buffers, we want to make sure they are done before
we release our memory. */
- while (atomic_read(&set_timeout_tofree)) {
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(1);
- }
+ while (atomic_read(&set_timeout_tofree))
+ schedule_timeout_uninterruptible(1);
/* Disconnect from IPMI. */
rv = ipmi_destroy_user(watchdog_user);
@@ -1062,3 +1060,5 @@ static void __exit ipmi_wdog_exit(void)
module_exit(ipmi_wdog_exit);
module_init(ipmi_wdog_init);
MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>");
+MODULE_DESCRIPTION("watchdog timer based upon the IPMI interface.");
diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c
index 52a073e..9c19e54 100644
--- a/drivers/char/istallion.c
+++ b/drivers/char/istallion.c
@@ -780,7 +780,7 @@ static struct file_operations stli_fsiomem = {
* much cheaper on host cpu than using interrupts. It turns out to
* not increase character latency by much either...
*/
-static struct timer_list stli_timerlist = TIMER_INITIALIZER(stli_poll, 0, 0);
+static DEFINE_TIMER(stli_timerlist, stli_poll, 0, 0);
static int stli_timeron;
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c
index 523fd3c..449d029 100644
--- a/drivers/char/keyboard.c
+++ b/drivers/char/keyboard.c
@@ -14,7 +14,7 @@
* `Sticky' modifier keys, 951006.
*
* 11-11-96: SAK should now work in the raw mode (Martin Mares)
- *
+ *
* Modified to provide 'generic' keyboard support by Hamish Macdonald
* Merge with the m68k keyboard driver and split-off of the PC low-level
* parts by Geert Uytterhoeven, May 1997
@@ -52,7 +52,7 @@ extern void ctrl_alt_del(void);
/*
* Some laptops take the 789uiojklm,. keys as number pad when NumLock is on.
* This seems a good reason to start with NumLock off. On HIL keyboards
- * of PARISC machines however there is no NumLock key and everyone expects the keypad
+ * of PARISC machines however there is no NumLock key and everyone expects the keypad
* to be used for numbers.
*/
@@ -76,17 +76,17 @@ void compute_shiftstate(void);
k_meta, k_ascii, k_lock, k_lowercase,\
k_slock, k_dead2, k_ignore, k_ignore
-typedef void (k_handler_fn)(struct vc_data *vc, unsigned char value,
+typedef void (k_handler_fn)(struct vc_data *vc, unsigned char value,
char up_flag, struct pt_regs *regs);
static k_handler_fn K_HANDLERS;
static k_handler_fn *k_handler[16] = { K_HANDLERS };
#define FN_HANDLERS\
- fn_null, fn_enter, fn_show_ptregs, fn_show_mem,\
- fn_show_state, fn_send_intr, fn_lastcons, fn_caps_toggle,\
- fn_num, fn_hold, fn_scroll_forw, fn_scroll_back,\
- fn_boot_it, fn_caps_on, fn_compose, fn_SAK,\
- fn_dec_console, fn_inc_console, fn_spawn_con, fn_bare_num
+ fn_null, fn_enter, fn_show_ptregs, fn_show_mem,\
+ fn_show_state, fn_send_intr, fn_lastcons, fn_caps_toggle,\
+ fn_num, fn_hold, fn_scroll_forw, fn_scroll_back,\
+ fn_boot_it, fn_caps_on, fn_compose, fn_SAK,\
+ fn_dec_console, fn_inc_console, fn_spawn_con, fn_bare_num
typedef void (fn_handler_fn)(struct vc_data *vc, struct pt_regs *regs);
static fn_handler_fn FN_HANDLERS;
@@ -159,13 +159,13 @@ static int sysrq_alt;
*/
int getkeycode(unsigned int scancode)
{
- struct list_head * node;
+ struct list_head *node;
struct input_dev *dev = NULL;
- list_for_each(node,&kbd_handler.h_list) {
- struct input_handle * handle = to_handle_h(node);
- if (handle->dev->keycodesize) {
- dev = handle->dev;
+ list_for_each(node, &kbd_handler.h_list) {
+ struct input_handle *handle = to_handle_h(node);
+ if (handle->dev->keycodesize) {
+ dev = handle->dev;
break;
}
}
@@ -181,15 +181,15 @@ int getkeycode(unsigned int scancode)
int setkeycode(unsigned int scancode, unsigned int keycode)
{
- struct list_head * node;
+ struct list_head *node;
struct input_dev *dev = NULL;
unsigned int i, oldkey;
- list_for_each(node,&kbd_handler.h_list) {
+ list_for_each(node, &kbd_handler.h_list) {
struct input_handle *handle = to_handle_h(node);
- if (handle->dev->keycodesize) {
- dev = handle->dev;
- break;
+ if (handle->dev->keycodesize) {
+ dev = handle->dev;
+ break;
}
}
@@ -200,7 +200,7 @@ int setkeycode(unsigned int scancode, unsigned int keycode)
return -EINVAL;
if (keycode < 0 || keycode > KEY_MAX)
return -EINVAL;
- if (keycode >> (dev->keycodesize * 8))
+ if (dev->keycodesize < sizeof(keycode) && (keycode >> (dev->keycodesize * 8)))
return -EINVAL;
oldkey = SET_INPUT_KEYCODE(dev, scancode, keycode);
@@ -216,11 +216,11 @@ int setkeycode(unsigned int scancode, unsigned int keycode)
}
/*
- * Making beeps and bells.
+ * Making beeps and bells.
*/
static void kd_nosound(unsigned long ignored)
{
- struct list_head * node;
+ struct list_head *node;
list_for_each(node,&kbd_handler.h_list) {
struct input_handle *handle = to_handle_h(node);
@@ -233,17 +233,16 @@ static void kd_nosound(unsigned long ignored)
}
}
-static struct timer_list kd_mksound_timer =
- TIMER_INITIALIZER(kd_nosound, 0, 0);
+static DEFINE_TIMER(kd_mksound_timer, kd_nosound, 0, 0);
void kd_mksound(unsigned int hz, unsigned int ticks)
{
- struct list_head * node;
+ struct list_head *node;
del_timer(&kd_mksound_timer);
if (hz) {
- list_for_each_prev(node,&kbd_handler.h_list) {
+ list_for_each_prev(node, &kbd_handler.h_list) {
struct input_handle *handle = to_handle_h(node);
if (test_bit(EV_SND, handle->dev->evbit)) {
if (test_bit(SND_TONE, handle->dev->sndbit)) {
@@ -338,19 +337,19 @@ static void to_utf8(struct vc_data *vc, ushort c)
if (c < 0x80)
/* 0******* */
put_queue(vc, c);
- else if (c < 0x800) {
+ else if (c < 0x800) {
/* 110***** 10****** */
- put_queue(vc, 0xc0 | (c >> 6));
+ put_queue(vc, 0xc0 | (c >> 6));
put_queue(vc, 0x80 | (c & 0x3f));
- } else {
+ } else {
/* 1110**** 10****** 10****** */
put_queue(vc, 0xe0 | (c >> 12));
put_queue(vc, 0x80 | ((c >> 6) & 0x3f));
put_queue(vc, 0x80 | (c & 0x3f));
- }
+ }
}
-/*
+/*
* Called after returning from RAW mode or when changing consoles - recompute
* shift_down[] and shift_state from key_down[] maybe called when keymap is
* undefined, so that shiftkey release is seen
@@ -361,7 +360,7 @@ void compute_shiftstate(void)
shift_state = 0;
memset(shift_down, 0, sizeof(shift_down));
-
+
for (i = 0; i < ARRAY_SIZE(key_down); i++) {
if (!key_down[i])
@@ -500,9 +499,9 @@ static void fn_dec_console(struct vc_data *vc, struct pt_regs *regs)
if (want_console != -1)
cur = want_console;
- for (i = cur-1; i != cur; i--) {
+ for (i = cur - 1; i != cur; i--) {
if (i == -1)
- i = MAX_NR_CONSOLES-1;
+ i = MAX_NR_CONSOLES - 1;
if (vc_cons_allocated(i))
break;
}
@@ -568,9 +567,9 @@ static void fn_compose(struct vc_data *vc, struct pt_regs *regs)
static void fn_spawn_con(struct vc_data *vc, struct pt_regs *regs)
{
- if (spawnpid)
- if(kill_proc(spawnpid, spawnsig, 1))
- spawnpid = 0;
+ if (spawnpid)
+ if (kill_proc(spawnpid, spawnsig, 1))
+ spawnpid = 0;
}
static void fn_SAK(struct vc_data *vc, struct pt_regs *regs)
@@ -604,8 +603,8 @@ static void k_spec(struct vc_data *vc, unsigned char value, char up_flag, struct
return;
if (value >= ARRAY_SIZE(fn_handler))
return;
- if ((kbd->kbdmode == VC_RAW ||
- kbd->kbdmode == VC_MEDIUMRAW) &&
+ if ((kbd->kbdmode == VC_RAW ||
+ kbd->kbdmode == VC_MEDIUMRAW) &&
value != KVAL(K_SAK))
return; /* SAK is allowed even in raw mode */
fn_handler[value](vc, regs);
@@ -895,11 +894,11 @@ static inline unsigned char getleds(void)
static void kbd_bh(unsigned long dummy)
{
- struct list_head * node;
+ struct list_head *node;
unsigned char leds = getleds();
if (leds != ledstate) {
- list_for_each(node,&kbd_handler.h_list) {
+ list_for_each(node, &kbd_handler.h_list) {
struct input_handle * handle = to_handle_h(node);
input_event(handle->dev, EV_LED, LED_SCROLLL, !!(leds & 0x01));
input_event(handle->dev, EV_LED, LED_NUML, !!(leds & 0x02));
@@ -964,11 +963,11 @@ static int sparc_l1_a_state = 0;
extern void sun_do_break(void);
#endif
-static int emulate_raw(struct vc_data *vc, unsigned int keycode,
+static int emulate_raw(struct vc_data *vc, unsigned int keycode,
unsigned char up_flag)
{
if (keycode > 255 || !x86_keycodes[keycode])
- return -1;
+ return -1;
switch (keycode) {
case KEY_PAUSE:
@@ -982,7 +981,7 @@ static int emulate_raw(struct vc_data *vc, unsigned int keycode,
case KEY_HANJA:
if (!up_flag) put_queue(vc, 0xf2);
return 0;
- }
+ }
if (keycode == KEY_SYSRQ && sysrq_alt) {
put_queue(vc, 0x54 | up_flag);
@@ -1105,11 +1104,12 @@ static void kbd_keycode(unsigned int keycode, int down,
else
clear_bit(keycode, key_down);
- if (rep && (!vc_kbd_mode(kbd, VC_REPEAT) || (tty &&
- (!L_ECHO(tty) && tty->driver->chars_in_buffer(tty))))) {
+ if (rep &&
+ (!vc_kbd_mode(kbd, VC_REPEAT) ||
+ (tty && !L_ECHO(tty) && tty->driver->chars_in_buffer(tty)))) {
/*
* Don't repeat a key if the input buffers are not empty and the
- * characters get aren't echoed locally. This makes key repeat
+ * characters get aren't echoed locally. This makes key repeat
* usable with slow applications and under heavy loads.
*/
return;
@@ -1131,7 +1131,8 @@ static void kbd_keycode(unsigned int keycode, int down,
type = KTYP(keysym);
if (type < 0xf0) {
- if (down && !raw_mode) to_utf8(vc, keysym);
+ if (down && !raw_mode)
+ to_utf8(vc, keysym);
return;
}
@@ -1155,7 +1156,7 @@ static void kbd_keycode(unsigned int keycode, int down,
kbd->slockstate = 0;
}
-static void kbd_event(struct input_handle *handle, unsigned int event_type,
+static void kbd_event(struct input_handle *handle, unsigned int event_type,
unsigned int event_code, int value)
{
if (event_type == EV_MSC && event_code == MSC_RAW && HW_RAW(handle->dev))
@@ -1167,15 +1168,13 @@ static void kbd_event(struct input_handle *handle, unsigned int event_type,
schedule_console_callback();
}
-static char kbd_name[] = "kbd";
-
/*
* When a keyboard (or other input device) is found, the kbd_connect
* function is called. The function then looks at the device, and if it
* likes it, it can open it and get events from it. In this (kbd_connect)
* function, we should decide which VT to bind that keyboard to initially.
*/
-static struct input_handle *kbd_connect(struct input_handler *handler,
+static struct input_handle *kbd_connect(struct input_handler *handler,
struct input_dev *dev,
struct input_device_id *id)
{
@@ -1183,18 +1182,19 @@ static struct input_handle *kbd_connect(struct input_handler *handler,
int i;
for (i = KEY_RESERVED; i < BTN_MISC; i++)
- if (test_bit(i, dev->keybit)) break;
+ if (test_bit(i, dev->keybit))
+ break;
- if ((i == BTN_MISC) && !test_bit(EV_SND, dev->evbit))
+ if (i == BTN_MISC && !test_bit(EV_SND, dev->evbit))
return NULL;
- if (!(handle = kmalloc(sizeof(struct input_handle), GFP_KERNEL)))
+ if (!(handle = kmalloc(sizeof(struct input_handle), GFP_KERNEL)))
return NULL;
memset(handle, 0, sizeof(struct input_handle));
handle->dev = dev;
handle->handler = handler;
- handle->name = kbd_name;
+ handle->name = "kbd";
input_open_device(handle);
kbd_refresh_leds(handle);
@@ -1213,11 +1213,11 @@ static struct input_device_id kbd_ids[] = {
.flags = INPUT_DEVICE_ID_MATCH_EVBIT,
.evbit = { BIT(EV_KEY) },
},
-
+
{
.flags = INPUT_DEVICE_ID_MATCH_EVBIT,
.evbit = { BIT(EV_SND) },
- },
+ },
{ }, /* Terminating entry */
};
diff --git a/drivers/char/lcd.c b/drivers/char/lcd.c
index cf01a72..b771611 100644
--- a/drivers/char/lcd.c
+++ b/drivers/char/lcd.c
@@ -613,10 +613,15 @@ static struct miscdevice lcd_dev = {
static int lcd_init(void)
{
+ int ret;
unsigned long data;
pr_info("%s\n", LCD_DRIVER);
- misc_register(&lcd_dev);
+ ret = misc_register(&lcd_dev);
+ if (ret) {
+ printk(KERN_WARNING LCD "Unable to register misc device.\n");
+ return ret;
+ }
/* Check region? Naaah! Just snarf it up. */
/* request_region(RTC_PORT(0), RTC_IO_EXTENT, "lcd");*/
diff --git a/drivers/char/lp.c b/drivers/char/lp.c
index 59eebe5..2afb903 100644
--- a/drivers/char/lp.c
+++ b/drivers/char/lp.c
@@ -128,6 +128,7 @@
#include <linux/console.h>
#include <linux/device.h>
#include <linux/wait.h>
+#include <linux/jiffies.h>
#include <linux/parport.h>
#undef LP_STATS
@@ -307,7 +308,7 @@ static ssize_t lp_write(struct file * file, const char __user * buf,
(LP_F(minor) & LP_ABORT));
#ifdef LP_STATS
- if (jiffies-lp_table[minor].lastcall > LP_TIME(minor))
+ if (time_after(jiffies, lp_table[minor].lastcall + LP_TIME(minor)))
lp_table[minor].runchars = 0;
lp_table[minor].lastcall = jiffies;
diff --git a/drivers/char/mbcs.c b/drivers/char/mbcs.c
index 115dbb3..3fa64c6 100644
--- a/drivers/char/mbcs.c
+++ b/drivers/char/mbcs.c
@@ -750,7 +750,7 @@ static int mbcs_probe(struct cx_dev *dev, const struct cx_device_id *id)
dev->soft = NULL;
- soft = kcalloc(1, sizeof(struct mbcs_soft), GFP_KERNEL);
+ soft = kzalloc(sizeof(struct mbcs_soft), GFP_KERNEL);
if (soft == NULL)
return -ENOMEM;
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 850a78c..f182752 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -35,10 +35,6 @@
# include <linux/efi.h>
#endif
-#if defined(CONFIG_S390_TAPE) && defined(CONFIG_S390_TAPE_CHAR)
-extern void tapechar_init(void);
-#endif
-
/*
* Architectures vary in how they handle caching for addresses
* outside of main memory.
diff --git a/drivers/char/misc.c b/drivers/char/misc.c
index 931efd5..0c83751 100644
--- a/drivers/char/misc.c
+++ b/drivers/char/misc.c
@@ -63,8 +63,6 @@ static DECLARE_MUTEX(misc_sem);
#define DYNAMIC_MINORS 64 /* like dynamic majors */
static unsigned char misc_minors[DYNAMIC_MINORS / 8];
-extern int rtc_DP8570A_init(void);
-extern int rtc_MK48T08_init(void);
extern int pmu_device_init(void);
#ifdef CONFIG_PROC_FS
@@ -303,12 +301,7 @@ static int __init misc_init(void)
misc_class = class_create(THIS_MODULE, "misc");
if (IS_ERR(misc_class))
return PTR_ERR(misc_class);
-#ifdef CONFIG_MVME16x
- rtc_MK48T08_init();
-#endif
-#ifdef CONFIG_BVME6000
- rtc_DP8570A_init();
-#endif
+
if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) {
printk("unable to get major %d for misc devices\n",
MISC_MAJOR);
diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c
index 95f7046..79e490e 100644
--- a/drivers/char/moxa.c
+++ b/drivers/char/moxa.c
@@ -339,7 +339,7 @@ static int __init moxa_init(void)
init_MUTEX(&moxaBuffSem);
moxaDriver->owner = THIS_MODULE;
- moxaDriver->name = "ttya";
+ moxaDriver->name = "ttyMX";
moxaDriver->devfs_name = "tts/a";
moxaDriver->major = ttymajor;
moxaDriver->minor_start = 0;
diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c
index f022f09..45d012d 100644
--- a/drivers/char/mxser.c
+++ b/drivers/char/mxser.c
@@ -63,7 +63,6 @@
#include <asm/system.h>
#include <asm/io.h>
#include <asm/irq.h>
-#include <asm/segment.h>
#include <asm/bitops.h>
#include <asm/uaccess.h>
@@ -1059,8 +1058,7 @@ static void mxser_close(struct tty_struct *tty, struct file *filp)
*/
timeout = jiffies + HZ;
while (!(inb(info->base + UART_LSR) & UART_LSR_TEMT)) {
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(5);
+ schedule_timeout_interruptible(5);
if (time_after(jiffies, timeout))
break;
}
@@ -1081,10 +1079,8 @@ static void mxser_close(struct tty_struct *tty, struct file *filp)
info->event = 0;
info->tty = NULL;
if (info->blocked_open) {
- if (info->close_delay) {
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(info->close_delay);
- }
+ if (info->close_delay)
+ schedule_timeout_interruptible(info->close_delay);
wake_up_interruptible(&info->open_wait);
}
@@ -1802,8 +1798,7 @@ static void mxser_wait_until_sent(struct tty_struct *tty, int timeout)
#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
printk("lsr = %d (jiff=%lu)...", lsr, jiffies);
#endif
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(char_time);
+ schedule_timeout_interruptible(char_time);
if (signal_pending(current))
break;
if (timeout && time_after(jiffies, orig_jiffies + timeout))
diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c
index 09103b3..c9bdf54 100644
--- a/drivers/char/n_tty.c
+++ b/drivers/char/n_tty.c
@@ -62,7 +62,7 @@
static inline unsigned char *alloc_buf(void)
{
- int prio = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL;
+ unsigned int prio = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL;
if (PAGE_SIZE != N_TTY_BUF_SIZE)
return kmalloc(N_TTY_BUF_SIZE, prio);
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index 7a0c746..02d7f04 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -1,7 +1,7 @@
/*
* linux/drivers/char/pcmcia/synclink_cs.c
*
- * $Id: synclink_cs.c,v 4.26 2004/08/11 19:30:02 paulkf Exp $
+ * $Id: synclink_cs.c,v 4.34 2005/09/08 13:20:54 paulkf Exp $
*
* Device driver for Microgate SyncLink PC Card
* multiprotocol serial adapter.
@@ -472,7 +472,7 @@ module_param_array(dosyncppp, int, NULL, 0);
MODULE_LICENSE("GPL");
static char *driver_name = "SyncLink PC Card driver";
-static char *driver_version = "$Revision: 4.26 $";
+static char *driver_version = "$Revision: 4.34 $";
static struct tty_driver *serial_driver;
@@ -1457,6 +1457,8 @@ static int startup(MGSLPC_INFO * info)
info->pending_bh = 0;
+ memset(&info->icount, 0, sizeof(info->icount));
+
init_timer(&info->tx_timer);
info->tx_timer.data = (unsigned long)info;
info->tx_timer.function = tx_timeout;
@@ -1946,9 +1948,13 @@ static int get_stats(MGSLPC_INFO * info, struct mgsl_icount __user *user_icount)
int err;
if (debug_level >= DEBUG_LEVEL_INFO)
printk("get_params(%s)\n", info->device_name);
- COPY_TO_USER(err,user_icount, &info->icount, sizeof(struct mgsl_icount));
- if (err)
- return -EFAULT;
+ if (!user_icount) {
+ memset(&info->icount, 0, sizeof(info->icount));
+ } else {
+ COPY_TO_USER(err, user_icount, &info->icount, sizeof(struct mgsl_icount));
+ if (err)
+ return -EFAULT;
+ }
return 0;
}
diff --git a/drivers/char/pty.c b/drivers/char/pty.c
index da32889..49f3997 100644
--- a/drivers/char/pty.c
+++ b/drivers/char/pty.c
@@ -149,15 +149,14 @@ static int pty_write_room(struct tty_struct *tty)
static int pty_chars_in_buffer(struct tty_struct *tty)
{
struct tty_struct *to = tty->link;
- ssize_t (*chars_in_buffer)(struct tty_struct *);
int count;
/* We should get the line discipline lock for "tty->link" */
- if (!to || !(chars_in_buffer = to->ldisc.chars_in_buffer))
+ if (!to || !to->ldisc.chars_in_buffer)
return 0;
/* The ldisc must report 0 if no characters available to be read */
- count = chars_in_buffer(to);
+ count = to->ldisc.chars_in_buffer(to);
if (tty->driver->subtype == PTY_TYPE_SLAVE) return count;
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c
index cd4fe8b..63fff7c 100644
--- a/drivers/char/rtc.c
+++ b/drivers/char/rtc.c
@@ -938,10 +938,9 @@ found:
/*
* XXX Interrupt pin #7 in Espresso is shared between RTC and
- * PCI Slot 2 INTA# (and some INTx# in Slot 1). SA_INTERRUPT here
- * is asking for trouble with add-on boards. Change to SA_SHIRQ.
+ * PCI Slot 2 INTA# (and some INTx# in Slot 1).
*/
- if (request_irq(rtc_irq, rtc_interrupt, SA_INTERRUPT, "rtc", (void *)&rtc_port)) {
+ if (request_irq(rtc_irq, rtc_interrupt, SA_SHIRQ, "rtc", (void *)&rtc_port)) {
/*
* Standard way for sparc to print irq's is to use
* __irq_itoa(). I think for EBus it's ok to use %d.
diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c
index cefbe98..36ae9ad 100644
--- a/drivers/char/sonypi.c
+++ b/drivers/char/sonypi.c
@@ -98,12 +98,13 @@ MODULE_PARM_DESC(useinput,
#define SONYPI_DEVICE_MODEL_TYPE1 1
#define SONYPI_DEVICE_MODEL_TYPE2 2
+#define SONYPI_DEVICE_MODEL_TYPE3 3
/* type1 models use those */
#define SONYPI_IRQ_PORT 0x8034
#define SONYPI_IRQ_SHIFT 22
-#define SONYPI_BASE 0x50
-#define SONYPI_G10A (SONYPI_BASE+0x14)
+#define SONYPI_TYPE1_BASE 0x50
+#define SONYPI_G10A (SONYPI_TYPE1_BASE+0x14)
#define SONYPI_TYPE1_REGION_SIZE 0x08
#define SONYPI_TYPE1_EVTYPE_OFFSET 0x04
@@ -114,6 +115,13 @@ MODULE_PARM_DESC(useinput,
#define SONYPI_TYPE2_REGION_SIZE 0x20
#define SONYPI_TYPE2_EVTYPE_OFFSET 0x12
+/* type3 series specifics */
+#define SONYPI_TYPE3_BASE 0x40
+#define SONYPI_TYPE3_GID2 (SONYPI_TYPE3_BASE+0x48) /* 16 bits */
+#define SONYPI_TYPE3_MISC (SONYPI_TYPE3_BASE+0x6d) /* 8 bits */
+#define SONYPI_TYPE3_REGION_SIZE 0x20
+#define SONYPI_TYPE3_EVTYPE_OFFSET 0x12
+
/* battery / brightness addresses */
#define SONYPI_BAT_FLAGS 0x81
#define SONYPI_LCD_LIGHT 0x96
@@ -159,6 +167,10 @@ static struct sonypi_ioport_list sonypi_type2_ioport_list[] = {
{ 0x0, 0x0 }
};
+/* same as in type 2 models */
+static struct sonypi_ioport_list *sonypi_type3_ioport_list =
+ sonypi_type2_ioport_list;
+
/* The set of possible interrupts */
struct sonypi_irq_list {
u16 irq;
@@ -180,6 +192,9 @@ static struct sonypi_irq_list sonypi_type2_irq_list[] = {
{ 0, 0x00 } /* no IRQ, 0x00 in SIRQ in AML */
};
+/* same as in type2 models */
+static struct sonypi_irq_list *sonypi_type3_irq_list = sonypi_type2_irq_list;
+
#define SONYPI_CAMERA_BRIGHTNESS 0
#define SONYPI_CAMERA_CONTRAST 1
#define SONYPI_CAMERA_HUE 2
@@ -223,6 +238,7 @@ static struct sonypi_irq_list sonypi_type2_irq_list[] = {
#define SONYPI_MEYE_MASK 0x00000400
#define SONYPI_MEMORYSTICK_MASK 0x00000800
#define SONYPI_BATTERY_MASK 0x00001000
+#define SONYPI_WIRELESS_MASK 0x00002000
struct sonypi_event {
u8 data;
@@ -305,6 +321,13 @@ static struct sonypi_event sonypi_blueev[] = {
{ 0, 0 }
};
+/* The set of possible wireless events */
+static struct sonypi_event sonypi_wlessev[] = {
+ { 0x59, SONYPI_EVENT_WIRELESS_ON },
+ { 0x5a, SONYPI_EVENT_WIRELESS_OFF },
+ { 0, 0 }
+};
+
/* The set of possible back button events */
static struct sonypi_event sonypi_backev[] = {
{ 0x20, SONYPI_EVENT_BACK_PRESSED },
@@ -383,7 +406,6 @@ static struct sonypi_eventtypes {
{ SONYPI_DEVICE_MODEL_TYPE2, 0x31, SONYPI_BLUETOOTH_MASK, sonypi_blueev },
{ SONYPI_DEVICE_MODEL_TYPE2, 0x08, SONYPI_PKEY_MASK, sonypi_pkeyev },
{ SONYPI_DEVICE_MODEL_TYPE2, 0x11, SONYPI_BACK_MASK, sonypi_backev },
- { SONYPI_DEVICE_MODEL_TYPE2, 0x08, SONYPI_HELP_MASK, sonypi_helpev },
{ SONYPI_DEVICE_MODEL_TYPE2, 0x21, SONYPI_HELP_MASK, sonypi_helpev },
{ SONYPI_DEVICE_MODEL_TYPE2, 0x21, SONYPI_ZOOM_MASK, sonypi_zoomev },
{ SONYPI_DEVICE_MODEL_TYPE2, 0x20, SONYPI_THUMBPHRASE_MASK, sonypi_thumbphraseev },
@@ -391,6 +413,12 @@ static struct sonypi_eventtypes {
{ SONYPI_DEVICE_MODEL_TYPE2, 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev },
{ SONYPI_DEVICE_MODEL_TYPE2, 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev },
+ { SONYPI_DEVICE_MODEL_TYPE3, 0, 0xffffffff, sonypi_releaseev },
+ { SONYPI_DEVICE_MODEL_TYPE3, 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
+ { SONYPI_DEVICE_MODEL_TYPE3, 0x31, SONYPI_WIRELESS_MASK, sonypi_wlessev },
+ { SONYPI_DEVICE_MODEL_TYPE3, 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
+ { SONYPI_DEVICE_MODEL_TYPE3, 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev },
+ { SONYPI_DEVICE_MODEL_TYPE3, 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev },
{ 0 }
};
@@ -563,6 +591,23 @@ static void sonypi_type2_srs(void)
udelay(10);
}
+static void sonypi_type3_srs(void)
+{
+ u16 v16;
+ u8 v8;
+
+ /* This model type uses the same initialiazation of
+ * the embedded controller as the type2 models. */
+ sonypi_type2_srs();
+
+ /* Initialization of PCI config space of the LPC interface bridge. */
+ v16 = (sonypi_device.ioport1 & 0xFFF0) | 0x01;
+ pci_write_config_word(sonypi_device.dev, SONYPI_TYPE3_GID2, v16);
+ pci_read_config_byte(sonypi_device.dev, SONYPI_TYPE3_MISC, &v8);
+ v8 = (v8 & 0xCF) | 0x10;
+ pci_write_config_byte(sonypi_device.dev, SONYPI_TYPE3_MISC, v8);
+}
+
/* Disables the device - this comes from the AML code in the ACPI bios */
static void sonypi_type1_dis(void)
{
@@ -587,6 +632,13 @@ static void sonypi_type2_dis(void)
printk(KERN_WARNING "ec_write failed\n");
}
+static void sonypi_type3_dis(void)
+{
+ sonypi_type2_dis();
+ udelay(10);
+ pci_write_config_word(sonypi_device.dev, SONYPI_TYPE3_GID2, 0);
+}
+
static u8 sonypi_call1(u8 dev)
{
u8 v1, v2;
@@ -1067,10 +1119,17 @@ static struct miscdevice sonypi_misc_device = {
static void sonypi_enable(unsigned int camera_on)
{
- if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2)
- sonypi_type2_srs();
- else
+ switch (sonypi_device.model) {
+ case SONYPI_DEVICE_MODEL_TYPE1:
sonypi_type1_srs();
+ break;
+ case SONYPI_DEVICE_MODEL_TYPE2:
+ sonypi_type2_srs();
+ break;
+ case SONYPI_DEVICE_MODEL_TYPE3:
+ sonypi_type3_srs();
+ break;
+ }
sonypi_call1(0x82);
sonypi_call2(0x81, 0xff);
@@ -1094,10 +1153,18 @@ static int sonypi_disable(void)
if (!SONYPI_ACPI_ACTIVE && fnkeyinit)
outb(0xf1, 0xb2);
- if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2)
- sonypi_type2_dis();
- else
+ switch (sonypi_device.model) {
+ case SONYPI_DEVICE_MODEL_TYPE1:
sonypi_type1_dis();
+ break;
+ case SONYPI_DEVICE_MODEL_TYPE2:
+ sonypi_type2_dis();
+ break;
+ case SONYPI_DEVICE_MODEL_TYPE3:
+ sonypi_type3_dis();
+ break;
+ }
+
return 0;
}
@@ -1143,12 +1210,16 @@ static int __devinit sonypi_probe(void)
struct sonypi_irq_list *irq_list;
struct pci_dev *pcidev;
- pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_82371AB_3, NULL);
+ if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_82371AB_3, NULL)))
+ sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE1;
+ else if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_ICH6_1, NULL)))
+ sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE3;
+ else
+ sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE2;
sonypi_device.dev = pcidev;
- sonypi_device.model = pcidev ?
- SONYPI_DEVICE_MODEL_TYPE1 : SONYPI_DEVICE_MODEL_TYPE2;
spin_lock_init(&sonypi_device.fifo_lock);
sonypi_device.fifo = kfifo_alloc(SONYPI_BUF_SIZE, GFP_KERNEL,
@@ -1176,16 +1247,22 @@ static int __devinit sonypi_probe(void)
goto out_miscreg;
}
- if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2) {
+
+ if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE1) {
+ ioport_list = sonypi_type1_ioport_list;
+ sonypi_device.region_size = SONYPI_TYPE1_REGION_SIZE;
+ sonypi_device.evtype_offset = SONYPI_TYPE1_EVTYPE_OFFSET;
+ irq_list = sonypi_type1_irq_list;
+ } else if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2) {
ioport_list = sonypi_type2_ioport_list;
sonypi_device.region_size = SONYPI_TYPE2_REGION_SIZE;
sonypi_device.evtype_offset = SONYPI_TYPE2_EVTYPE_OFFSET;
irq_list = sonypi_type2_irq_list;
} else {
- ioport_list = sonypi_type1_ioport_list;
- sonypi_device.region_size = SONYPI_TYPE1_REGION_SIZE;
- sonypi_device.evtype_offset = SONYPI_TYPE1_EVTYPE_OFFSET;
- irq_list = sonypi_type1_irq_list;
+ ioport_list = sonypi_type3_ioport_list;
+ sonypi_device.region_size = SONYPI_TYPE3_REGION_SIZE;
+ sonypi_device.evtype_offset = SONYPI_TYPE3_EVTYPE_OFFSET;
+ irq_list = sonypi_type3_irq_list;
}
for (i = 0; ioport_list[i].port1; i++) {
@@ -1274,11 +1351,10 @@ static int __devinit sonypi_probe(void)
printk(KERN_INFO "sonypi: Sony Programmable I/O Controller Driver"
"v%s.\n", SONYPI_DRIVER_VERSION);
- printk(KERN_INFO "sonypi: detected %s model, "
+ printk(KERN_INFO "sonypi: detected type%d model, "
"verbose = %d, fnkeyinit = %s, camera = %s, "
"compat = %s, mask = 0x%08lx, useinput = %s, acpi = %s\n",
- (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE1) ?
- "type1" : "type2",
+ sonypi_device.model,
verbose,
fnkeyinit ? "on" : "off",
camera ? "on" : "off",
diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c
index 37c8bea..ea2d54b 100644
--- a/drivers/char/synclink.c
+++ b/drivers/char/synclink.c
@@ -1,7 +1,7 @@
/*
* linux/drivers/char/synclink.c
*
- * $Id: synclink.c,v 4.28 2004/08/11 19:30:01 paulkf Exp $
+ * $Id: synclink.c,v 4.37 2005/09/07 13:13:19 paulkf Exp $
*
* Device driver for Microgate SyncLink ISA and PCI
* high speed multiprotocol serial adapters.
@@ -141,9 +141,9 @@ static MGSL_PARAMS default_params = {
typedef struct _DMABUFFERENTRY
{
u32 phys_addr; /* 32-bit flat physical address of data buffer */
- u16 count; /* buffer size/data count */
- u16 status; /* Control/status field */
- u16 rcc; /* character count field */
+ volatile u16 count; /* buffer size/data count */
+ volatile u16 status; /* Control/status field */
+ volatile u16 rcc; /* character count field */
u16 reserved; /* padding required by 16C32 */
u32 link; /* 32-bit flat link to next buffer entry */
char *virt_addr; /* virtual address of data buffer */
@@ -896,7 +896,7 @@ module_param_array(txdmabufs, int, NULL, 0);
module_param_array(txholdbufs, int, NULL, 0);
static char *driver_name = "SyncLink serial driver";
-static char *driver_version = "$Revision: 4.28 $";
+static char *driver_version = "$Revision: 4.37 $";
static int synclink_init_one (struct pci_dev *dev,
const struct pci_device_id *ent);
@@ -1814,6 +1814,8 @@ static int startup(struct mgsl_struct * info)
info->pending_bh = 0;
+ memset(&info->icount, 0, sizeof(info->icount));
+
init_timer(&info->tx_timer);
info->tx_timer.data = (unsigned long)info;
info->tx_timer.function = mgsl_tx_timeout;
@@ -2470,12 +2472,12 @@ static int mgsl_get_stats(struct mgsl_struct * info, struct mgsl_icount __user *
printk("%s(%d):mgsl_get_params(%s)\n",
__FILE__,__LINE__, info->device_name);
- COPY_TO_USER(err,user_icount, &info->icount, sizeof(struct mgsl_icount));
- if (err) {
- if ( debug_level >= DEBUG_LEVEL_INFO )
- printk( "%s(%d):mgsl_get_stats(%s) user buffer copy failed\n",
- __FILE__,__LINE__,info->device_name);
- return -EFAULT;
+ if (!user_icount) {
+ memset(&info->icount, 0, sizeof(info->icount));
+ } else {
+ COPY_TO_USER(err, user_icount, &info->icount, sizeof(struct mgsl_icount));
+ if (err)
+ return -EFAULT;
}
return 0;
@@ -6149,6 +6151,11 @@ static void usc_set_async_mode( struct mgsl_struct *info )
usc_OutReg(info, PCR, (u16)((usc_InReg(info, PCR) | BIT13) & ~BIT12));
}
+ if (info->params.loopback) {
+ info->loopback_bits = 0x300;
+ outw(0x0300, info->io_base + CCAR);
+ }
+
} /* end of usc_set_async_mode() */
/* usc_loopback_frame()
diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c
index ec949e4..6fb165c 100644
--- a/drivers/char/synclinkmp.c
+++ b/drivers/char/synclinkmp.c
@@ -1,5 +1,5 @@
/*
- * $Id: synclinkmp.c,v 4.34 2005/03/04 15:07:10 paulkf Exp $
+ * $Id: synclinkmp.c,v 4.38 2005/07/15 13:29:44 paulkf Exp $
*
* Device driver for Microgate SyncLink Multiport
* high speed multiprotocol serial adapter.
@@ -55,7 +55,6 @@
#include <linux/netdevice.h>
#include <linux/vmalloc.h>
#include <linux/init.h>
-#include <asm/serial.h>
#include <linux/delay.h>
#include <linux/ioctl.h>
@@ -487,7 +486,7 @@ module_param_array(maxframe, int, NULL, 0);
module_param_array(dosyncppp, int, NULL, 0);
static char *driver_name = "SyncLink MultiPort driver";
-static char *driver_version = "$Revision: 4.34 $";
+static char *driver_version = "$Revision: 4.38 $";
static int synclinkmp_init_one(struct pci_dev *dev,const struct pci_device_id *ent);
static void synclinkmp_remove_one(struct pci_dev *dev);
@@ -556,7 +555,6 @@ static int set_txidle(SLMP_INFO *info, int idle_mode);
static int tx_enable(SLMP_INFO *info, int enable);
static int tx_abort(SLMP_INFO *info);
static int rx_enable(SLMP_INFO *info, int enable);
-static int map_status(int signals);
static int modem_input_wait(SLMP_INFO *info,int arg);
static int wait_mgsl_event(SLMP_INFO *info, int __user *mask_ptr);
static int tiocmget(struct tty_struct *tty, struct file *file);
@@ -645,7 +643,7 @@ static unsigned char tx_active_fifo_level = 16; // tx request FIFO activation le
static unsigned char tx_negate_fifo_level = 32; // tx request FIFO negation level in bytes
static u32 misc_ctrl_value = 0x007e4040;
-static u32 lcr1_brdr_value = 0x00800029;
+static u32 lcr1_brdr_value = 0x00800028;
static u32 read_ahead_count = 8;
@@ -2750,6 +2748,8 @@ static int startup(SLMP_INFO * info)
info->pending_bh = 0;
+ memset(&info->icount, 0, sizeof(info->icount));
+
/* program hardware for current parameters */
reset_port(info);
@@ -2953,12 +2953,12 @@ static int get_stats(SLMP_INFO * info, struct mgsl_icount __user *user_icount)
printk("%s(%d):%s get_params()\n",
__FILE__,__LINE__, info->device_name);
- COPY_TO_USER(err,user_icount, &info->icount, sizeof(struct mgsl_icount));
- if (err) {
- if ( debug_level >= DEBUG_LEVEL_INFO )
- printk( "%s(%d):%s get_stats() user buffer copy failed\n",
- __FILE__,__LINE__,info->device_name);
- return -EFAULT;
+ if (!user_icount) {
+ memset(&info->icount, 0, sizeof(info->icount));
+ } else {
+ COPY_TO_USER(err, user_icount, &info->icount, sizeof(struct mgsl_icount));
+ if (err)
+ return -EFAULT;
}
return 0;
@@ -3109,16 +3109,6 @@ static int rx_enable(SLMP_INFO * info, int enable)
return 0;
}
-static int map_status(int signals)
-{
- /* Map status bits to API event bits */
-
- return ((signals & SerialSignal_DSR) ? MgslEvent_DsrActive : MgslEvent_DsrInactive) +
- ((signals & SerialSignal_CTS) ? MgslEvent_CtsActive : MgslEvent_CtsInactive) +
- ((signals & SerialSignal_DCD) ? MgslEvent_DcdActive : MgslEvent_DcdInactive) +
- ((signals & SerialSignal_RI) ? MgslEvent_RiActive : MgslEvent_RiInactive);
-}
-
/* wait for specified event to occur
*/
static int wait_mgsl_event(SLMP_INFO * info, int __user *mask_ptr)
@@ -3145,7 +3135,7 @@ static int wait_mgsl_event(SLMP_INFO * info, int __user *mask_ptr)
/* return immediately if state matches requested events */
get_signals(info);
- s = map_status(info->serial_signals);
+ s = info->serial_signals;
events = mask &
( ((s & SerialSignal_DSR) ? MgslEvent_DsrActive:MgslEvent_DsrInactive) +
@@ -4489,11 +4479,13 @@ void async_mode(SLMP_INFO *info)
/* MD2, Mode Register 2
*
* 07..02 Reserved, must be 0
- * 01..00 CNCT<1..0> Channel connection, 0=normal
+ * 01..00 CNCT<1..0> Channel connection, 00=normal 11=local loopback
*
* 0000 0000
*/
RegValue = 0x00;
+ if (info->params.loopback)
+ RegValue |= (BIT1 + BIT0);
write_reg(info, MD2, RegValue);
/* RXS, Receive clock source
@@ -4574,9 +4566,6 @@ void async_mode(SLMP_INFO *info)
write_reg(info, IE2, info->ie2_value);
set_rate( info, info->params.data_rate * 16 );
-
- if (info->params.loopback)
- enable_loopback(info,1);
}
/* Program the SCA for HDLC communications.
diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig
index 79e9832..b58adfe 100644
--- a/drivers/char/tpm/Kconfig
+++ b/drivers/char/tpm/Kconfig
@@ -17,7 +17,7 @@ config TCG_TPM
obtained at: <http://sourceforge.net/projects/trousers>. To
compile this driver as a module, choose M here; the module
will be called tpm. If unsure, say N.
- Note: For more TPM drivers enable CONFIG_PNP, CONFIG_ACPI_BUS
+ Note: For more TPM drivers enable CONFIG_PNP, CONFIG_ACPI
and CONFIG_PNPACPI.
config TCG_NSC
diff --git a/drivers/char/tpm/tpm_atmel.c b/drivers/char/tpm/tpm_atmel.c
index cc2cc77..c0d6491 100644
--- a/drivers/char/tpm/tpm_atmel.c
+++ b/drivers/char/tpm/tpm_atmel.c
@@ -206,6 +206,9 @@ static struct pci_device_id tpm_pci_tbl[] __devinitdata = {
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0)},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12)},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_0)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0)},
{PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_LPC)},
{PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6LPC)},
{0,}
diff --git a/drivers/char/tpm/tpm_infineon.c b/drivers/char/tpm/tpm_infineon.c
index dc8c540..939e51e 100644
--- a/drivers/char/tpm/tpm_infineon.c
+++ b/drivers/char/tpm/tpm_infineon.c
@@ -14,7 +14,6 @@
* License.
*/
-#include <acpi/acpi_bus.h>
#include <linux/pnp.h>
#include "tpm.h"
@@ -29,9 +28,10 @@
#define TPM_MAX_TRIES 5000
#define TPM_INFINEON_DEV_VEN_VALUE 0x15D1
-/* These values will be filled after ACPI-call */
+/* These values will be filled after PnP-call */
static int TPM_INF_DATA = 0;
static int TPM_INF_ADDR = 0;
+static int pnp_registered = 0;
/* TPM header definitions */
enum infineon_tpm_header {
@@ -356,24 +356,26 @@ static const struct pnp_device_id tpm_pnp_tbl[] = {
{"IFX0102", 0},
{"", 0}
};
+MODULE_DEVICE_TABLE(pnp, tpm_pnp_tbl);
-static int __devinit tpm_inf_acpi_probe(struct pnp_dev *dev,
+static int __devinit tpm_inf_pnp_probe(struct pnp_dev *dev,
const struct pnp_device_id *dev_id)
{
- TPM_INF_ADDR = (pnp_port_start(dev, 0) & 0xff);
- TPM_INF_DATA = ((TPM_INF_ADDR + 1) & 0xff);
- tpm_inf.base = pnp_port_start(dev, 1);
- dev_info(&dev->dev, "Found %s with ID %s\n",
- dev->name, dev_id->id);
- if (!((tpm_inf.base >> 8) & 0xff))
- tpm_inf.base = 0;
- return 0;
+ if (pnp_port_valid(dev, 0)) {
+ TPM_INF_ADDR = (pnp_port_start(dev, 0) & 0xff);
+ TPM_INF_DATA = ((TPM_INF_ADDR + 1) & 0xff);
+ tpm_inf.base = pnp_port_start(dev, 1);
+ dev_info(&dev->dev, "Found %s with ID %s\n",
+ dev->name, dev_id->id);
+ return 0;
+ }
+ return -ENODEV;
}
static struct pnp_driver tpm_inf_pnp = {
.name = "tpm_inf_pnp",
.id_table = tpm_pnp_tbl,
- .probe = tpm_inf_acpi_probe,
+ .probe = tpm_inf_pnp_probe,
};
static int __devinit tpm_inf_probe(struct pci_dev *pci_dev,
@@ -386,19 +388,30 @@ static int __devinit tpm_inf_probe(struct pci_dev *pci_dev,
int productid[2];
char chipname[20];
- if (pci_enable_device(pci_dev))
- return -EIO;
+ rc = pci_enable_device(pci_dev);
+ if (rc)
+ return rc;
dev_info(&pci_dev->dev, "LPC-bus found at 0x%x\n", pci_id->device);
- /* read IO-ports from ACPI */
- pnp_register_driver(&tpm_inf_pnp);
- pnp_unregister_driver(&tpm_inf_pnp);
+ /* read IO-ports from PnP */
+ rc = pnp_register_driver(&tpm_inf_pnp);
+ if (rc < 0) {
+ dev_err(&pci_dev->dev,
+ "Error %x from pnp_register_driver!\n",rc);
+ goto error2;
+ }
+ if (!rc) {
+ dev_info(&pci_dev->dev, "No Infineon TPM found!\n");
+ goto error;
+ } else {
+ pnp_registered = 1;
+ }
/* Make sure, we have received valid config ports */
if (!TPM_INF_ADDR) {
- pci_disable_device(pci_dev);
- return -EIO;
+ dev_err(&pci_dev->dev, "No valid IO-ports received!\n");
+ goto error;
}
/* query chip for its vendor, its version number a.s.o. */
@@ -418,23 +431,21 @@ static int __devinit tpm_inf_probe(struct pci_dev *pci_dev,
switch ((productid[0] << 8) | productid[1]) {
case 6:
- sprintf(chipname, " (SLD 9630 TT 1.1)");
+ snprintf(chipname, sizeof(chipname), " (SLD 9630 TT 1.1)");
break;
case 11:
- sprintf(chipname, " (SLB 9635 TT 1.2)");
+ snprintf(chipname, sizeof(chipname), " (SLB 9635 TT 1.2)");
break;
default:
- sprintf(chipname, " (unknown chip)");
+ snprintf(chipname, sizeof(chipname), " (unknown chip)");
break;
}
- chipname[19] = 0;
if ((vendorid[0] << 8 | vendorid[1]) == (TPM_INFINEON_DEV_VEN_VALUE)) {
if (tpm_inf.base == 0) {
dev_err(&pci_dev->dev, "No IO-ports found!\n");
- pci_disable_device(pci_dev);
- return -EIO;
+ goto error;
}
/* configure TPM with IO-ports */
outb(IOLIMH, TPM_INF_ADDR);
@@ -452,8 +463,7 @@ static int __devinit tpm_inf_probe(struct pci_dev *pci_dev,
dev_err(&pci_dev->dev,
"Could not set IO-ports to %04x\n",
tpm_inf.base);
- pci_disable_device(pci_dev);
- return -EIO;
+ goto error;
}
/* activate register */
@@ -479,14 +489,16 @@ static int __devinit tpm_inf_probe(struct pci_dev *pci_dev,
productid[0], productid[1], chipname);
rc = tpm_register_hardware(pci_dev, &tpm_inf);
- if (rc < 0) {
- pci_disable_device(pci_dev);
- return -ENODEV;
- }
+ if (rc < 0)
+ goto error;
return 0;
} else {
dev_info(&pci_dev->dev, "No Infineon TPM found!\n");
+error:
+ pnp_unregister_driver(&tpm_inf_pnp);
+error2:
pci_disable_device(pci_dev);
+ pnp_registered = 0;
return -ENODEV;
}
}
@@ -521,6 +533,8 @@ static int __init init_inf(void)
static void __exit cleanup_inf(void)
{
+ if (pnp_registered)
+ pnp_unregister_driver(&tpm_inf_pnp);
pci_unregister_driver(&inf_pci_driver);
}
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 6e4be3b..e5953f3 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -153,7 +153,6 @@ static int tty_release(struct inode *, struct file *);
int tty_ioctl(struct inode * inode, struct file * file,
unsigned int cmd, unsigned long arg);
static int tty_fasync(int fd, struct file * filp, int on);
-extern void rs_360_init(void);
static void release_mem(struct tty_struct *tty, int idx);
@@ -470,21 +469,19 @@ static void tty_ldisc_enable(struct tty_struct *tty)
static int tty_set_ldisc(struct tty_struct *tty, int ldisc)
{
- int retval = 0;
- struct tty_ldisc o_ldisc;
+ int retval = 0;
+ struct tty_ldisc o_ldisc;
char buf[64];
int work;
unsigned long flags;
struct tty_ldisc *ld;
+ struct tty_struct *o_tty;
if ((ldisc < N_TTY) || (ldisc >= NR_LDISCS))
return -EINVAL;
restart:
- if (tty->ldisc.num == ldisc)
- return 0; /* We are already in the desired discipline */
-
ld = tty_ldisc_get(ldisc);
/* Eduardo Blanco <ejbs@cs.cs.com.uy> */
/* Cyrus Durgin <cider@speakeasy.org> */
@@ -495,45 +492,74 @@ restart:
if (ld == NULL)
return -EINVAL;
- o_ldisc = tty->ldisc;
-
tty_wait_until_sent(tty, 0);
+ if (tty->ldisc.num == ldisc) {
+ tty_ldisc_put(ldisc);
+ return 0;
+ }
+
+ o_ldisc = tty->ldisc;
+ o_tty = tty->link;
+
/*
* Make sure we don't change while someone holds a
* reference to the line discipline. The TTY_LDISC bit
* prevents anyone taking a reference once it is clear.
* We need the lock to avoid racing reference takers.
*/
-
+
spin_lock_irqsave(&tty_ldisc_lock, flags);
- if(tty->ldisc.refcount)
- {
- /* Free the new ldisc we grabbed. Must drop the lock
- first. */
+ if (tty->ldisc.refcount || (o_tty && o_tty->ldisc.refcount)) {
+ if(tty->ldisc.refcount) {
+ /* Free the new ldisc we grabbed. Must drop the lock
+ first. */
+ spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+ tty_ldisc_put(ldisc);
+ /*
+ * There are several reasons we may be busy, including
+ * random momentary I/O traffic. We must therefore
+ * retry. We could distinguish between blocking ops
+ * and retries if we made tty_ldisc_wait() smarter. That
+ * is up for discussion.
+ */
+ if (wait_event_interruptible(tty_ldisc_wait, tty->ldisc.refcount == 0) < 0)
+ return -ERESTARTSYS;
+ goto restart;
+ }
+ if(o_tty && o_tty->ldisc.refcount) {
+ spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+ tty_ldisc_put(ldisc);
+ if (wait_event_interruptible(tty_ldisc_wait, o_tty->ldisc.refcount == 0) < 0)
+ return -ERESTARTSYS;
+ goto restart;
+ }
+ }
+
+ /* if the TTY_LDISC bit is set, then we are racing against another ldisc change */
+
+ if (!test_bit(TTY_LDISC, &tty->flags)) {
spin_unlock_irqrestore(&tty_ldisc_lock, flags);
tty_ldisc_put(ldisc);
- /*
- * There are several reasons we may be busy, including
- * random momentary I/O traffic. We must therefore
- * retry. We could distinguish between blocking ops
- * and retries if we made tty_ldisc_wait() smarter. That
- * is up for discussion.
- */
- if(wait_event_interruptible(tty_ldisc_wait, tty->ldisc.refcount == 0) < 0)
- return -ERESTARTSYS;
+ ld = tty_ldisc_ref_wait(tty);
+ tty_ldisc_deref(ld);
goto restart;
}
- clear_bit(TTY_LDISC, &tty->flags);
+
+ clear_bit(TTY_LDISC, &tty->flags);
clear_bit(TTY_DONT_FLIP, &tty->flags);
+ if (o_tty) {
+ clear_bit(TTY_LDISC, &o_tty->flags);
+ clear_bit(TTY_DONT_FLIP, &o_tty->flags);
+ }
spin_unlock_irqrestore(&tty_ldisc_lock, flags);
-
+
/*
* From this point on we know nobody has an ldisc
* usage reference, nor can they obtain one until
* we say so later on.
*/
-
+
work = cancel_delayed_work(&tty->flip.work);
/*
* Wait for ->hangup_work and ->flip.work handlers to terminate
@@ -584,10 +610,12 @@ restart:
*/
tty_ldisc_enable(tty);
+ if (o_tty)
+ tty_ldisc_enable(o_tty);
/* Restart it in case no characters kick it off. Safe if
already running */
- if(work)
+ if (work)
schedule_delayed_work(&tty->flip.work, 1);
return retval;
}
@@ -2426,6 +2454,7 @@ static void __do_SAK(void *arg)
int i;
struct file *filp;
struct tty_ldisc *disc;
+ struct fdtable *fdt;
if (!tty)
return;
@@ -2451,8 +2480,9 @@ static void __do_SAK(void *arg)
}
task_lock(p);
if (p->files) {
- spin_lock(&p->files->file_lock);
- for (i=0; i < p->files->max_fds; i++) {
+ rcu_read_lock();
+ fdt = files_fdtable(p->files);
+ for (i=0; i < fdt->max_fds; i++) {
filp = fcheck_files(p->files, i);
if (!filp)
continue;
@@ -2465,7 +2495,7 @@ static void __do_SAK(void *arg)
break;
}
}
- spin_unlock(&p->files->file_lock);
+ rcu_read_unlock();
}
task_unlock(p);
} while_each_task_pid(session, PIDTYPE_SID, p);
@@ -2911,11 +2941,6 @@ void __init console_init(void)
#ifdef CONFIG_EARLY_PRINTK
disable_early_printk();
#endif
-#ifdef CONFIG_SERIAL_68360
- /* This is not a console initcall. I know not what it's doing here.
- So I haven't moved it. dwmw2 */
- rs_360_init();
-#endif
call = __con_initcall_start;
while (call < __con_initcall_end) {
(*call)();
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index 665103c..e91268e 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -434,21 +434,25 @@ void invert_screen(struct vc_data *vc, int offset, int count, int viewed)
/* used by selection: complement pointer position */
void complement_pos(struct vc_data *vc, int offset)
{
- static unsigned short *p;
+ static int old_offset = -1;
static unsigned short old;
static unsigned short oldx, oldy;
WARN_CONSOLE_UNLOCKED();
- if (p) {
- scr_writew(old, p);
+ if (old_offset != -1 && old_offset >= 0 &&
+ old_offset < vc->vc_screenbuf_size) {
+ scr_writew(old, screenpos(vc, old_offset, 1));
if (DO_UPDATE(vc))
vc->vc_sw->con_putc(vc, old, oldy, oldx);
}
- if (offset == -1)
- p = NULL;
- else {
+
+ old_offset = offset;
+
+ if (offset != -1 && offset >= 0 &&
+ offset < vc->vc_screenbuf_size) {
unsigned short new;
+ unsigned short *p;
p = screenpos(vc, offset, 1);
old = scr_readw(p);
new = old ^ vc->vc_complement_mask;
@@ -459,6 +463,7 @@ void complement_pos(struct vc_data *vc, int offset)
vc->vc_sw->con_putc(vc, new, oldy, oldx);
}
}
+
}
static void insert_char(struct vc_data *vc, unsigned int nr)
@@ -746,6 +751,7 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines)
unsigned long old_origin, new_origin, new_scr_end, rlth, rrem, err = 0;
unsigned int old_cols, old_rows, old_row_size, old_screen_size;
unsigned int new_cols, new_rows, new_row_size, new_screen_size;
+ unsigned int end;
unsigned short *newscreen;
WARN_CONSOLE_UNLOCKED();
@@ -789,20 +795,45 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines)
old_origin = vc->vc_origin;
new_origin = (long) newscreen;
new_scr_end = new_origin + new_screen_size;
- if (new_rows < old_rows)
- old_origin += (old_rows - new_rows) * old_row_size;
+
+ if (vc->vc_y > new_rows) {
+ if (old_rows - vc->vc_y < new_rows) {
+ /*
+ * Cursor near the bottom, copy contents from the
+ * bottom of buffer
+ */
+ old_origin += (old_rows - new_rows) * old_row_size;
+ end = vc->vc_scr_end;
+ } else {
+ /*
+ * Cursor is in no man's land, copy 1/2 screenful
+ * from the top and bottom of cursor position
+ */
+ old_origin += (vc->vc_y - new_rows/2) * old_row_size;
+ end = old_origin + (old_row_size * new_rows);
+ }
+ } else
+ /*
+ * Cursor near the top, copy contents from the top of buffer
+ */
+ end = (old_rows > new_rows) ? old_origin +
+ (old_row_size * new_rows) :
+ vc->vc_scr_end;
update_attr(vc);
- while (old_origin < vc->vc_scr_end) {
- scr_memcpyw((unsigned short *) new_origin, (unsigned short *) old_origin, rlth);
+ while (old_origin < end) {
+ scr_memcpyw((unsigned short *) new_origin,
+ (unsigned short *) old_origin, rlth);
if (rrem)
- scr_memsetw((void *)(new_origin + rlth), vc->vc_video_erase_char, rrem);
+ scr_memsetw((void *)(new_origin + rlth),
+ vc->vc_video_erase_char, rrem);
old_origin += old_row_size;
new_origin += new_row_size;
}
if (new_scr_end > new_origin)
- scr_memsetw((void *)new_origin, vc->vc_video_erase_char, new_scr_end - new_origin);
+ scr_memsetw((void *)new_origin, vc->vc_video_erase_char,
+ new_scr_end - new_origin);
if (vc->vc_kmalloced)
kfree(vc->vc_screenbuf);
vc->vc_screenbuf = newscreen;
@@ -2272,7 +2303,9 @@ int tioclinux(struct tty_struct *tty, unsigned long arg)
ret = paste_selection(tty);
break;
case TIOCL_UNBLANKSCREEN:
+ acquire_console_sem();
unblank_screen();
+ release_console_sem();
break;
case TIOCL_SELLOADLUT:
ret = sel_loadlut(p);
@@ -2317,8 +2350,10 @@ int tioclinux(struct tty_struct *tty, unsigned long arg)
}
break;
case TIOCL_BLANKSCREEN: /* until explicitly unblanked, not only poked */
+ acquire_console_sem();
ignore_poke = 1;
do_blank_screen(0);
+ release_console_sem();
break;
case TIOCL_BLANKEDSCREEN:
ret = console_blanked;
diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig
index b53e2e2..344001b 100644
--- a/drivers/char/watchdog/Kconfig
+++ b/drivers/char/watchdog/Kconfig
@@ -84,6 +84,17 @@ config 977_WATCHDOG
Not sure? It's safe to say N.
+config IXP2000_WATCHDOG
+ tristate "IXP2000 Watchdog"
+ depends on WATCHDOG && ARCH_IXP2000
+ help
+ Say Y here if to include support for the watchdog timer
+ in the Intel IXP2000(2400, 2800, 2850) network processors.
+ This driver can be built as a module by choosing M. The module
+ will be called ixp2000_wdt.
+
+ Say N if you are unsure.
+
config IXP4XX_WATCHDOG
tristate "IXP4xx Watchdog"
depends on WATCHDOG && ARCH_IXP4XX
@@ -100,17 +111,6 @@ config IXP4XX_WATCHDOG
Say N if you are unsure.
-config IXP2000_WATCHDOG
- tristate "IXP2000 Watchdog"
- depends on WATCHDOG && ARCH_IXP2000
- help
- Say Y here if to include support for the watchdog timer
- in the Intel IXP2000(2400, 2800, 2850) network processors.
- This driver can be built as a module by choosing M. The module
- will be called ixp2000_wdt.
-
- Say N if you are unsure.
-
config S3C2410_WATCHDOG
tristate "S3C2410 Watchdog"
depends on WATCHDOG && ARCH_S3C2410
@@ -139,6 +139,15 @@ config SA1100_WATCHDOG
To compile this driver as a module, choose M here: the
module will be called sa1100_wdt.
+config MPCORE_WATCHDOG
+ tristate "MPcore watchdog"
+ depends on WATCHDOG && ARM_MPCORE_PLATFORM && LOCAL_TIMERS
+ help
+ Watchdog timer embedded into the MPcore system.
+
+ To compile this driver as a module, choose M here: the
+ module will be called mpcore_wdt.
+
# X86 (i386 + ia64 + x86_64) Architecture
config ACQUIRE_WDT
@@ -224,6 +233,16 @@ config IB700_WDT
Most people will say N.
+config IBMASR
+ tristate "IBM Automatic Server Restart"
+ depends on WATCHDOG && X86
+ help
+ This is the driver for the IBM Automatic Server Restart watchdog
+ timer builtin into some eServer xSeries machines.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ibmasr.
+
config WAFER_WDT
tristate "ICP Wafer 5823 Single Board Computer Watchdog"
depends on WATCHDOG && X86
@@ -234,6 +253,16 @@ config WAFER_WDT
To compile this driver as a module, choose M here: the
module will be called wafer5823wdt.
+config I6300ESB_WDT
+ tristate "Intel 6300ESB Timer/Watchdog"
+ depends on WATCHDOG && X86 && PCI
+ ---help---
+ Hardware driver for the watchdog timer built into the Intel
+ 6300ESB controller hub.
+
+ To compile this driver as a module, choose M here: the
+ module will be called i6300esb.
+
config I8XX_TCO
tristate "Intel i8xx TCO Timer/Watchdog"
depends on WATCHDOG && (X86 || IA64) && PCI
@@ -289,6 +318,19 @@ config 60XX_WDT
You can compile this driver directly into the kernel, or use
it as a module. The module will be called sbc60xxwdt.
+config SBC8360_WDT
+ tristate "SBC8360 Watchdog Timer"
+ depends on WATCHDOG && X86
+ ---help---
+
+ This is the driver for the hardware watchdog on the SBC8360 Single
+ Board Computer produced by Axiomtek Co., Ltd. (www.axiomtek.com).
+
+ To compile this driver as a module, choose M here: the
+ module will be called sbc8360.ko.
+
+ Most people will say N.
+
config CPU5_WDT
tristate "SMA CPU5 Watchdog"
depends on WATCHDOG && X86
@@ -327,6 +369,19 @@ config W83877F_WDT
Most people will say N.
+config W83977F_WDT
+ tristate "W83977F (PCM-5335) Watchdog Timer"
+ depends on WATCHDOG && X86
+ ---help---
+ This is the driver for the hardware watchdog on the W83977F I/O chip
+ as used in AAEON's PCM-5335 SBC (and likely others). This
+ watchdog simply watches your kernel to make sure it doesn't freeze,
+ and if it does, it reboots your computer after a certain amount of
+ time.
+
+ To compile this driver as a module, choose M here: the
+ module will be called w83977f_wdt.
+
config MACHZ_WDT
tristate "ZF MachZ Watchdog"
depends on WATCHDOG && X86
@@ -346,6 +401,28 @@ config 8xx_WDT
tristate "MPC8xx Watchdog Timer"
depends on WATCHDOG && 8xx
+config MV64X60_WDT
+ tristate "MV64X60 (Marvell Discovery) Watchdog Timer"
+ depends on WATCHDOG && MV64X60
+
+config BOOKE_WDT
+ tristate "PowerPC Book-E Watchdog Timer"
+ depends on WATCHDOG && (BOOKE || 4xx)
+ ---help---
+ Please see Documentation/watchdog/watchdog-api.txt for
+ more information.
+
+# PPC64 Architecture
+
+config WATCHDOG_RTAS
+ tristate "RTAS watchdog"
+ depends on WATCHDOG && PPC_RTAS
+ help
+ This driver adds watchdog support for the RTAS watchdog.
+
+ To compile this driver as a module, choose M here. The module
+ will be called wdrtas.
+
# MIPS Architecture
config INDYDOG
@@ -414,16 +491,6 @@ config WATCHDOG_RIO
machines. The watchdog timeout period is normally one minute but
can be changed with a boot-time parameter.
-# ppc64 RTAS watchdog
-config WATCHDOG_RTAS
- tristate "RTAS watchdog"
- depends on WATCHDOG && PPC_RTAS
- help
- This driver adds watchdog support for the RTAS watchdog.
-
- To compile this driver as a module, choose M here. The module
- will be called wdrtas.
-
#
# ISA-based Watchdog Cards
#
diff --git a/drivers/char/watchdog/Makefile b/drivers/char/watchdog/Makefile
index c183883..cfd0a39 100644
--- a/drivers/char/watchdog/Makefile
+++ b/drivers/char/watchdog/Makefile
@@ -2,42 +2,74 @@
# Makefile for the WatchDog device drivers.
#
+# Only one watchdog can succeed. We probe the ISA/PCI/USB based
+# watchdog-cards first, then the architecture specific watchdog
+# drivers and then the architecture independant "softdog" driver.
+# This means that if your ISA/PCI/USB card isn't detected that
+# you can fall back to an architecture specific driver and if
+# that also fails then you can fall back to the software watchdog
+# to give you some cover.
+
+# ISA-based Watchdog Cards
obj-$(CONFIG_PCWATCHDOG) += pcwd.o
-obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o
-obj-$(CONFIG_ADVANTECH_WDT) += advantechwdt.o
-obj-$(CONFIG_IB700_WDT) += ib700wdt.o
obj-$(CONFIG_MIXCOMWD) += mixcomwd.o
-obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o
-obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o
obj-$(CONFIG_WDT) += wdt.o
+
+# PCI-based Watchdog Cards
+obj-$(CONFIG_PCIPCWATCHDOG) += pcwd_pci.o
obj-$(CONFIG_WDTPCI) += wdt_pci.o
+
+# USB-based Watchdog Cards
+obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o
+
+# ARM Architecture
obj-$(CONFIG_21285_WATCHDOG) += wdt285.o
obj-$(CONFIG_977_WATCHDOG) += wdt977.o
-obj-$(CONFIG_I8XX_TCO) += i8xx_tco.o
-obj-$(CONFIG_MACHZ_WDT) += machzwd.o
-obj-$(CONFIG_SH_WDT) += shwdt.o
+obj-$(CONFIG_IXP2000_WATCHDOG) += ixp2000_wdt.o
+obj-$(CONFIG_IXP4XX_WATCHDOG) += ixp4xx_wdt.o
obj-$(CONFIG_S3C2410_WATCHDOG) += s3c2410_wdt.o
obj-$(CONFIG_SA1100_WATCHDOG) += sa1100_wdt.o
-obj-$(CONFIG_EUROTECH_WDT) += eurotechwdt.o
-obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o
-obj-$(CONFIG_W83627HF_WDT) += w83627hf_wdt.o
-obj-$(CONFIG_SC520_WDT) += sc520_wdt.o
-obj-$(CONFIG_ALIM7101_WDT) += alim7101_wdt.o
+obj-$(CONFIG_MPCORE_WATCHDOG) += mpcore_wdt.o
+
+# X86 (i386 + ia64 + x86_64) Architecture
+obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o
+obj-$(CONFIG_ADVANTECH_WDT) += advantechwdt.o
obj-$(CONFIG_ALIM1535_WDT) += alim1535_wdt.o
-obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o
+obj-$(CONFIG_ALIM7101_WDT) += alim7101_wdt.o
+obj-$(CONFIG_SC520_WDT) += sc520_wdt.o
+obj-$(CONFIG_EUROTECH_WDT) += eurotechwdt.o
+obj-$(CONFIG_IB700_WDT) += ib700wdt.o
+obj-$(CONFIG_IBMASR) += ibmasr.o
obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o
+obj-$(CONFIG_I6300ESB_WDT) += i6300esb.o
+obj-$(CONFIG_I8XX_TCO) += i8xx_tco.o
+obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o
+obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o
+obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o
+obj-$(CONFIG_SBC8360_WDT) += sbc8360.o
obj-$(CONFIG_CPU5_WDT) += cpu5wdt.o
-obj-$(CONFIG_INDYDOG) += indydog.o
-obj-$(CONFIG_PCIPCWATCHDOG) += pcwd_pci.o
-obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o
-obj-$(CONFIG_IXP4XX_WATCHDOG) += ixp4xx_wdt.o
-obj-$(CONFIG_IXP2000_WATCHDOG) += ixp2000_wdt.o
+obj-$(CONFIG_W83627HF_WDT) += w83627hf_wdt.o
+obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o
+obj-$(CONFIG_W83977F_WDT) += w83977f_wdt.o
+obj-$(CONFIG_MACHZ_WDT) += machzwd.o
+
+# PowerPC Architecture
obj-$(CONFIG_8xx_WDT) += mpc8xx_wdt.o
+obj-$(CONFIG_MV64X60_WDT) += mv64x60_wdt.o
+obj-$(CONFIG_BOOKE_WDT) += booke_wdt.o
+
+# PPC64 Architecture
obj-$(CONFIG_WATCHDOG_RTAS) += wdrtas.o
-# Only one watchdog can succeed. We probe the hardware watchdog
-# drivers first, then the softdog driver. This means if your hardware
-# watchdog dies or is 'borrowed' for some reason the software watchdog
-# still gives you some cover.
+# MIPS Architecture
+obj-$(CONFIG_INDYDOG) += indydog.o
+
+# S390 Architecture
+
+# SUPERH Architecture
+obj-$(CONFIG_SH_WDT) += shwdt.o
+
+# SPARC64 Architecture
+# Architecture Independant
obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o
diff --git a/drivers/char/watchdog/booke_wdt.c b/drivers/char/watchdog/booke_wdt.c
new file mode 100644
index 0000000..abc30cc
--- /dev/null
+++ b/drivers/char/watchdog/booke_wdt.c
@@ -0,0 +1,192 @@
+/*
+ * drivers/char/watchdog/booke_wdt.c
+ *
+ * Watchdog timer for PowerPC Book-E systems
+ *
+ * Author: Matthew McClintock
+ * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ *
+ * Copyright 2005 Freescale Semiconductor Inc.
+ *
+ * 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.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/notifier.h>
+#include <linux/watchdog.h>
+
+#include <asm/reg_booke.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+/* If the kernel parameter wdt_enable=1, the watchdog will be enabled at boot.
+ * Also, the wdt_period sets the watchdog timer period timeout.
+ * For E500 cpus the wdt_period sets which bit changing from 0->1 will
+ * trigger a watchog timeout. This watchdog timeout will occur 3 times, the
+ * first time nothing will happen, the second time a watchdog exception will
+ * occur, and the final time the board will reset.
+ */
+
+#ifdef CONFIG_FSL_BOOKE
+#define WDT_PERIOD_DEFAULT 63 /* Ex. wdt_period=28 bus=333Mhz , reset=~40sec */
+#else
+#define WDT_PERIOD_DEFAULT 4 /* Refer to the PPC40x and PPC4xx manuals */
+#endif /* for timing information */
+
+u32 booke_wdt_enabled = 0;
+u32 booke_wdt_period = WDT_PERIOD_DEFAULT;
+
+#ifdef CONFIG_FSL_BOOKE
+#define WDTP(x) ((((63-x)&0x3)<<30)|(((63-x)&0x3c)<<15))
+#else
+#define WDTP(x) (TCR_WP(x))
+#endif
+
+/*
+ * booke_wdt_enable:
+ */
+static __inline__ void booke_wdt_enable(void)
+{
+ u32 val;
+
+ val = mfspr(SPRN_TCR);
+ val |= (TCR_WIE|TCR_WRC(WRC_CHIP)|WDTP(booke_wdt_period));
+
+ mtspr(SPRN_TCR, val);
+}
+
+/*
+ * booke_wdt_ping:
+ */
+static __inline__ void booke_wdt_ping(void)
+{
+ mtspr(SPRN_TSR, TSR_ENW|TSR_WIS);
+}
+
+/*
+ * booke_wdt_write:
+ */
+static ssize_t booke_wdt_write (struct file *file, const char *buf,
+ size_t count, loff_t *ppos)
+{
+ booke_wdt_ping();
+ return count;
+}
+
+static struct watchdog_info ident = {
+ .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
+ .firmware_version = 0,
+ .identity = "PowerPC Book-E Watchdog",
+};
+
+/*
+ * booke_wdt_ioctl:
+ */
+static int booke_wdt_ioctl (struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ u32 tmp = 0;
+
+ switch (cmd) {
+ case WDIOC_GETSUPPORT:
+ if (copy_to_user ((struct watchdog_info *) arg, &ident,
+ sizeof(struct watchdog_info)))
+ return -EFAULT;
+ case WDIOC_GETSTATUS:
+ return put_user(ident.options, (u32 *) arg);
+ case WDIOC_GETBOOTSTATUS:
+ /* XXX: something is clearing TSR */
+ tmp = mfspr(SPRN_TSR) & TSR_WRS(3);
+ /* returns 1 if last reset was caused by the WDT */
+ return (tmp ? 1 : 0);
+ case WDIOC_KEEPALIVE:
+ booke_wdt_ping();
+ return 0;
+ case WDIOC_SETTIMEOUT:
+ if (get_user(booke_wdt_period, (u32 *) arg))
+ return -EFAULT;
+ mtspr(SPRN_TCR, (mfspr(SPRN_TCR)&~WDTP(0))|WDTP(booke_wdt_period));
+ return 0;
+ case WDIOC_GETTIMEOUT:
+ return put_user(booke_wdt_period, (u32 *) arg);
+ case WDIOC_SETOPTIONS:
+ if (get_user(tmp, (u32 *) arg))
+ return -EINVAL;
+ if (tmp == WDIOS_ENABLECARD) {
+ booke_wdt_ping();
+ break;
+ } else
+ return -EINVAL;
+ return 0;
+ default:
+ return -ENOIOCTLCMD;
+ }
+
+ return 0;
+}
+/*
+ * booke_wdt_open:
+ */
+static int booke_wdt_open (struct inode *inode, struct file *file)
+{
+ if (booke_wdt_enabled == 0) {
+ booke_wdt_enabled = 1;
+ booke_wdt_enable();
+ printk (KERN_INFO "PowerPC Book-E Watchdog Timer Enabled (wdt_period=%d)\n",
+ booke_wdt_period);
+ }
+
+ return 0;
+}
+
+static struct file_operations booke_wdt_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .write = booke_wdt_write,
+ .ioctl = booke_wdt_ioctl,
+ .open = booke_wdt_open,
+};
+
+static struct miscdevice booke_wdt_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &booke_wdt_fops,
+};
+
+static void __exit booke_wdt_exit(void)
+{
+ misc_deregister(&booke_wdt_miscdev);
+}
+
+/*
+ * booke_wdt_init:
+ */
+static int __init booke_wdt_init(void)
+{
+ int ret = 0;
+
+ printk (KERN_INFO "PowerPC Book-E Watchdog Timer Loaded\n");
+ ident.firmware_version = cpu_specs[0].pvr_value;
+
+ ret = misc_register(&booke_wdt_miscdev);
+ if (ret) {
+ printk (KERN_CRIT "Cannot register miscdev on minor=%d (err=%d)\n",
+ WATCHDOG_MINOR, ret);
+ return ret;
+ }
+
+ if (booke_wdt_enabled == 1) {
+ printk (KERN_INFO "PowerPC Book-E Watchdog Timer Enabled (wdt_period=%d)\n",
+ booke_wdt_period);
+ booke_wdt_enable();
+ }
+
+ return ret;
+}
+device_initcall(booke_wdt_init);
diff --git a/drivers/char/watchdog/i6300esb.c b/drivers/char/watchdog/i6300esb.c
new file mode 100644
index 0000000..93785f1
--- /dev/null
+++ b/drivers/char/watchdog/i6300esb.c
@@ -0,0 +1,527 @@
+/*
+ * i6300esb: Watchdog timer driver for Intel 6300ESB chipset
+ *
+ * (c) Copyright 2004 Google Inc.
+ * (c) Copyright 2005 David Härdeman <david@2gen.com>
+ *
+ * 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.
+ *
+ * based on i810-tco.c which is in turn based on softdog.c
+ *
+ * The timer is implemented in the following I/O controller hubs:
+ * (See the intel documentation on http://developer.intel.com.)
+ * 6300ESB chip : document number 300641-003
+ *
+ * 2004YYZZ Ross Biro
+ * Initial version 0.01
+ * 2004YYZZ Ross Biro
+ * Version 0.02
+ * 20050210 David Härdeman <david@2gen.com>
+ * Ported driver to kernel 2.6
+ */
+
+/*
+ * 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>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+/* Module and version information */
+#define ESB_VERSION "0.03"
+#define ESB_MODULE_NAME "i6300ESB timer"
+#define ESB_DRIVER_NAME ESB_MODULE_NAME ", v" ESB_VERSION
+#define PFX ESB_MODULE_NAME ": "
+
+/* PCI configuration registers */
+#define ESB_CONFIG_REG 0x60 /* Config register */
+#define ESB_LOCK_REG 0x68 /* WDT lock register */
+
+/* Memory mapped registers */
+#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 */
+
+/* Lock register bits */
+#define ESB_WDT_FUNC ( 0x01 << 2 ) /* Watchdog functionality */
+#define ESB_WDT_ENABLE ( 0x01 << 1 ) /* Enable WDT */
+#define ESB_WDT_LOCK ( 0x01 << 0 ) /* Lock (nowayout) */
+
+/* Config register bits */
+#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 */
+
+/* Reload register bits */
+#define ESB_WDT_RELOAD ( 0x01 << 8 ) /* prevent timeout */
+
+/* Magic constants */
+#define ESB_UNLOCK1 0x80 /* Step 1 to unlock reset registers */
+#define ESB_UNLOCK2 0x86 /* Step 2 to unlock reset registers */
+
+/* internal variables */
+static void __iomem *BASEADDR;
+static spinlock_t esb_lock; /* Guards the hardware */
+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;
+
+/* module parameters */
+#define WATCHDOG_HEARTBEAT 30 /* 30 sec default heartbeat (1<heartbeat<2*1023) */
+static int heartbeat = WATCHDOG_HEARTBEAT; /* in seconds */
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (1<heartbeat<2046, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
+/*
+ * 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.
+ */
+static inline void esb_unlock_registers(void) {
+ writeb(ESB_UNLOCK1, ESB_RELOAD_REG);
+ writeb(ESB_UNLOCK2, ESB_RELOAD_REG);
+}
+
+static void esb_timer_start(void)
+{
+ u8 val;
+
+ /* Enable or Enable + Lock? */
+ val = 0x02 | (nowayout ? 0x01 : 0x00);
+
+ pci_write_config_byte(esb_pci, ESB_LOCK_REG, val);
+}
+
+static int esb_timer_stop(void)
+{
+ u8 val;
+
+ spin_lock(&esb_lock);
+ /* First, reset timers as suggested by the docs */
+ esb_unlock_registers();
+ writew(ESB_WDT_RELOAD, ESB_RELOAD_REG);
+ /* 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 */
+ return (val & 0x01);
+}
+
+static void esb_timer_keepalive(void)
+{
+ spin_lock(&esb_lock);
+ esb_unlock_registers();
+ writew(ESB_WDT_RELOAD, ESB_RELOAD_REG);
+ /* FIXME: Do we need to flush anything here? */
+ 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 1KHz)
+ */
+ val = time << 9;
+
+ /* Write timer 1 */
+ esb_unlock_registers();
+ writel(val, ESB_TIMER1_REG);
+
+ /* Write timer 2 */
+ esb_unlock_registers();
+ writel(val, ESB_TIMER2_REG);
+
+ /* Reload */
+ esb_unlock_registers();
+ writew(ESB_WDT_RELOAD, ESB_RELOAD_REG);
+
+ /* FIXME: Do we need to flush everything out? */
+
+ /* Done */
+ heartbeat = time;
+ spin_unlock(&esb_lock);
+ return 0;
+}
+
+static int esb_timer_read (void)
+{
+ u32 count;
+
+ /* This isn't documented, and doesn't take into
+ * acount which stage is running, but it looks
+ * like a 20 bit count down, so we might as well report it.
+ */
+ pci_read_config_dword(esb_pci, 0x64, &count);
+ return (int)count;
+}
+
+/*
+ * /dev/watchdog handling
+ */
+
+static int esb_open (struct inode *inode, struct file *file)
+{
+ /* /dev/watchdog can only be opened once */
+ if (test_and_set_bit(0, &timer_alive))
+ return -EBUSY;
+
+ /* Reload and activate timer */
+ esb_timer_keepalive ();
+ esb_timer_start ();
+
+ return nonseekable_open(inode, file);
+}
+
+static int esb_release (struct inode *inode, struct file *file)
+{
+ /* 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;
+}
+
+static ssize_t esb_write (struct file *file, const char __user *data,
+ size_t len, loff_t * ppos)
+{
+ /* See if we got the magic character 'V' and reload the timer */
+ if (len) {
+ if (!nowayout) {
+ size_t i;
+
+ /* note: just in case someone wrote the magic character
+ * five months ago... */
+ esb_expect_close = 0;
+
+ /* scan to see whether or not we got the magic character */
+ for (i = 0; i != len; i++) {
+ char c;
+ if(get_user(c, data+i))
+ return -EFAULT;
+ if (c == 'V')
+ esb_expect_close = 42;
+ }
+ }
+
+ /* someone wrote to us, we should reload the timer */
+ esb_timer_keepalive ();
+ }
+ return len;
+}
+
+static int esb_ioctl (struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ int new_options, retval = -EINVAL;
+ int new_heartbeat;
+ void __user *argp = (void __user *)arg;
+ int __user *p = argp;
+ static struct watchdog_info ident = {
+ .options = WDIOF_SETTIMEOUT |
+ WDIOF_KEEPALIVEPING |
+ WDIOF_MAGICCLOSE,
+ .firmware_version = 0,
+ .identity = ESB_MODULE_NAME,
+ };
+
+ switch (cmd) {
+ case WDIOC_GETSUPPORT:
+ return copy_to_user(argp, &ident,
+ sizeof (ident)) ? -EFAULT : 0;
+
+ case WDIOC_GETSTATUS:
+ return put_user (esb_timer_read(), p);
+
+ case WDIOC_GETBOOTSTATUS:
+ return put_user (triggered, p);
+
+ case WDIOC_KEEPALIVE:
+ esb_timer_keepalive ();
+ return 0;
+
+ case WDIOC_SETOPTIONS:
+ {
+ if (get_user (new_options, p))
+ return -EFAULT;
+
+ if (new_options & WDIOS_DISABLECARD) {
+ esb_timer_stop ();
+ retval = 0;
+ }
+
+ if (new_options & WDIOS_ENABLECARD) {
+ esb_timer_keepalive ();
+ esb_timer_start ();
+ retval = 0;
+ }
+
+ return retval;
+ }
+
+ 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 -ENOIOCTLCMD;
+ }
+}
+
+/*
+ * Notify system
+ */
+
+static int esb_notify_sys (struct notifier_block *this, unsigned long code, void *unused)
+{
+ if (code==SYS_DOWN || code==SYS_HALT) {
+ /* Turn the WDT off */
+ esb_timer_stop ();
+ }
+
+ return NOTIFY_DONE;
+}
+
+/*
+ * Kernel Interfaces
+ */
+
+static struct file_operations esb_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .write = esb_write,
+ .ioctl = esb_ioctl,
+ .open = esb_open,
+ .release = esb_release,
+};
+
+static struct miscdevice esb_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &esb_fops,
+};
+
+static struct notifier_block esb_notifier = {
+ .notifier_call = esb_notify_sys,
+};
+
+/*
+ * 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[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_9), },
+ { 0, }, /* End of list */
+};
+MODULE_DEVICE_TABLE (pci, esb_pci_tbl);
+
+/*
+ * Init & exit routines
+ */
+
+static unsigned char __init esb_getdevice (void)
+{
+ u8 val1;
+ unsigned short val2;
+
+ struct pci_dev *dev = NULL;
+ /*
+ * Find the PCI device
+ */
+
+ for_each_pci_dev(dev) {
+ if (pci_match_id(esb_pci_tbl, dev)) {
+ esb_pci = dev;
+ break;
+ }
+ }
+
+ if (esb_pci) {
+ if (pci_enable_device(esb_pci)) {
+ printk (KERN_ERR PFX "failed to enable device\n");
+ goto err_devput;
+ }
+
+ if (pci_request_region(esb_pci, 0, ESB_MODULE_NAME)) {
+ printk (KERN_ERR PFX "failed to request region\n");
+ goto err_disable;
+ }
+
+ BASEADDR = ioremap(pci_resource_start(esb_pci, 0),
+ pci_resource_len(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;
+ }
+
+ /*
+ * 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.
+ *
+ * We also enable reboots and set the timer frequency to
+ * the PCI clock divided by 2^15 (approx 1KHz).
+ */
+ 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);
+ triggered = (val2 & (0x01 << 9) >> 9);
+
+ /* Reset trigger flag and timers */
+ esb_unlock_registers();
+ writew((0x11 << 8), ESB_RELOAD_REG);
+
+ /* Done */
+ return 1;
+
+err_release:
+ pci_release_region(esb_pci, 0);
+err_disable:
+ pci_disable_device(esb_pci);
+err_devput:
+ pci_dev_put(esb_pci);
+ }
+ return 0;
+}
+
+static int __init watchdog_init (void)
+{
+ int ret;
+
+ spin_lock_init(&esb_lock);
+
+ /* 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 */
+ if (esb_timer_set_heartbeat (heartbeat)) {
+ esb_timer_set_heartbeat (WATCHDOG_HEARTBEAT);
+ printk(KERN_INFO PFX "heartbeat value must be 1<heartbeat<2046, using %d\n",
+ heartbeat);
+ }
+
+ ret = register_reboot_notifier(&esb_notifier);
+ if (ret != 0) {
+ printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
+ ret);
+ goto err_unmap;
+ }
+
+ ret = misc_register(&esb_miscdev);
+ if (ret != 0) {
+ printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+ WATCHDOG_MINOR, ret);
+ goto err_notifier;
+ }
+
+ esb_timer_stop ();
+
+ printk (KERN_INFO PFX "initialized (0x%p). heartbeat=%d sec (nowayout=%d)\n",
+ BASEADDR, heartbeat, nowayout);
+
+ return 0;
+
+err_notifier:
+ unregister_reboot_notifier(&esb_notifier);
+err_unmap:
+ iounmap(BASEADDR);
+/* err_release: */
+ pci_release_region(esb_pci, 0);
+/* err_disable: */
+ pci_disable_device(esb_pci);
+/* err_devput: */
+ pci_dev_put(esb_pci);
+ return ret;
+}
+
+static void __exit watchdog_cleanup (void)
+{
+ /* Stop the timer before we leave */
+ if (!nowayout)
+ esb_timer_stop ();
+
+ /* Deregister */
+ misc_deregister(&esb_miscdev);
+ unregister_reboot_notifier(&esb_notifier);
+ iounmap(BASEADDR);
+ pci_release_region(esb_pci, 0);
+ pci_disable_device(esb_pci);
+ pci_dev_put(esb_pci);
+}
+
+module_init(watchdog_init);
+module_exit(watchdog_cleanup);
+
+MODULE_AUTHOR("Ross Biro and David Härdeman");
+MODULE_DESCRIPTION("Watchdog driver for Intel 6300ESB chipsets");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/ibmasr.c b/drivers/char/watchdog/ibmasr.c
new file mode 100644
index 0000000..294c474
--- /dev/null
+++ b/drivers/char/watchdog/ibmasr.c
@@ -0,0 +1,405 @@
+/*
+ * IBM Automatic Server Restart driver.
+ *
+ * Copyright (c) 2005 Andrey Panin <pazke@donpac.ru>
+ *
+ * Based on driver written by Pete Reynolds.
+ * Copyright (c) IBM Corporation, 1998-2004.
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU Public License, incorporated herein by reference.
+ */
+
+#include <linux/config.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/timer.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/dmi.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+
+enum {
+ ASMTYPE_UNKNOWN,
+ ASMTYPE_TOPAZ,
+ ASMTYPE_JASPER,
+ ASMTYPE_PEARL,
+ ASMTYPE_JUNIPER,
+ ASMTYPE_SPRUCE,
+};
+
+#define PFX "ibmasr: "
+
+#define TOPAZ_ASR_REG_OFFSET 4
+#define TOPAZ_ASR_TOGGLE 0x40
+#define TOPAZ_ASR_DISABLE 0x80
+
+/* PEARL ASR S/W REGISTER SUPERIO PORT ADDRESSES */
+#define PEARL_BASE 0xe04
+#define PEARL_WRITE 0xe06
+#define PEARL_READ 0xe07
+
+#define PEARL_ASR_DISABLE_MASK 0x80 /* bit 7: disable = 1, enable = 0 */
+#define PEARL_ASR_TOGGLE_MASK 0x40 /* bit 6: 0, then 1, then 0 */
+
+/* JASPER OFFSET FROM SIO BASE ADDR TO ASR S/W REGISTERS. */
+#define JASPER_ASR_REG_OFFSET 0x38
+
+#define JASPER_ASR_DISABLE_MASK 0x01 /* bit 0: disable = 1, enable = 0 */
+#define JASPER_ASR_TOGGLE_MASK 0x02 /* bit 1: 0, then 1, then 0 */
+
+#define JUNIPER_BASE_ADDRESS 0x54b /* Base address of Juniper ASR */
+#define JUNIPER_ASR_DISABLE_MASK 0x01 /* bit 0: disable = 1 enable = 0 */
+#define JUNIPER_ASR_TOGGLE_MASK 0x02 /* bit 1: 0, then 1, then 0 */
+
+#define SPRUCE_BASE_ADDRESS 0x118e /* Base address of Spruce ASR */
+#define SPRUCE_ASR_DISABLE_MASK 0x01 /* bit 1: disable = 1 enable = 0 */
+#define SPRUCE_ASR_TOGGLE_MASK 0x02 /* bit 0: 0, then 1, then 0 */
+
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+
+static unsigned long asr_is_open;
+static char asr_expect_close;
+
+static unsigned int asr_type, asr_base, asr_length;
+static unsigned int asr_read_addr, asr_write_addr;
+static unsigned char asr_toggle_mask, asr_disable_mask;
+
+static void asr_toggle(void)
+{
+ unsigned char reg = inb(asr_read_addr);
+
+ outb(reg & ~asr_toggle_mask, asr_write_addr);
+ reg = inb(asr_read_addr);
+
+ outb(reg | asr_toggle_mask, asr_write_addr);
+ reg = inb(asr_read_addr);
+
+ outb(reg & ~asr_toggle_mask, asr_write_addr);
+ reg = inb(asr_read_addr);
+}
+
+static void asr_enable(void)
+{
+ unsigned char reg;
+
+ if (asr_type == ASMTYPE_TOPAZ) {
+ /* asr_write_addr == asr_read_addr */
+ reg = inb(asr_read_addr);
+ outb(reg & ~(TOPAZ_ASR_TOGGLE | TOPAZ_ASR_DISABLE),
+ asr_read_addr);
+ } else {
+ /*
+ * First make sure the hardware timer is reset by toggling
+ * ASR hardware timer line.
+ */
+ asr_toggle();
+
+ reg = inb(asr_read_addr);
+ outb(reg & ~asr_disable_mask, asr_write_addr);
+ }
+ reg = inb(asr_read_addr);
+}
+
+static void asr_disable(void)
+{
+ unsigned char reg = inb(asr_read_addr);
+
+ if (asr_type == ASMTYPE_TOPAZ)
+ /* asr_write_addr == asr_read_addr */
+ outb(reg | TOPAZ_ASR_TOGGLE | TOPAZ_ASR_DISABLE,
+ asr_read_addr);
+ else {
+ outb(reg | asr_toggle_mask, asr_write_addr);
+ reg = inb(asr_read_addr);
+
+ outb(reg | asr_disable_mask, asr_write_addr);
+ }
+ reg = inb(asr_read_addr);
+}
+
+static int __init asr_get_base_address(void)
+{
+ unsigned char low, high;
+ const char *type = "";
+
+ asr_length = 1;
+
+ switch (asr_type) {
+ case ASMTYPE_TOPAZ:
+ /* SELECT SuperIO CHIP FOR QUERYING (WRITE 0x07 TO BOTH 0x2E and 0x2F) */
+ outb(0x07, 0x2e);
+ outb(0x07, 0x2f);
+
+ /* SELECT AND READ THE HIGH-NIBBLE OF THE GPIO BASE ADDRESS */
+ outb(0x60, 0x2e);
+ high = inb(0x2f);
+
+ /* SELECT AND READ THE LOW-NIBBLE OF THE GPIO BASE ADDRESS */
+ outb(0x61, 0x2e);
+ low = inb(0x2f);
+
+ asr_base = (high << 16) | low;
+ asr_read_addr = asr_write_addr =
+ asr_base + TOPAZ_ASR_REG_OFFSET;
+ asr_length = 5;
+
+ break;
+
+ case ASMTYPE_JASPER:
+ type = "Jaspers ";
+
+ /* FIXME: need to use pci_config_lock here, but it's not exported */
+
+/* spin_lock_irqsave(&pci_config_lock, flags);*/
+
+ /* Select the SuperIO chip in the PCI I/O port register */
+ outl(0x8000f858, 0xcf8);
+
+ /*
+ * Read the base address for the SuperIO chip.
+ * Only the lower 16 bits are valid, but the address is word
+ * aligned so the last bit must be masked off.
+ */
+ asr_base = inl(0xcfc) & 0xfffe;
+
+/* spin_unlock_irqrestore(&pci_config_lock, flags);*/
+
+ asr_read_addr = asr_write_addr =
+ asr_base + JASPER_ASR_REG_OFFSET;
+ asr_toggle_mask = JASPER_ASR_TOGGLE_MASK;
+ asr_disable_mask = JASPER_ASR_DISABLE_MASK;
+ asr_length = JASPER_ASR_REG_OFFSET + 1;
+
+ break;
+
+ case ASMTYPE_PEARL:
+ type = "Pearls ";
+ asr_base = PEARL_BASE;
+ asr_read_addr = PEARL_READ;
+ asr_write_addr = PEARL_WRITE;
+ asr_toggle_mask = PEARL_ASR_TOGGLE_MASK;
+ asr_disable_mask = PEARL_ASR_DISABLE_MASK;
+ asr_length = 4;
+ break;
+
+ case ASMTYPE_JUNIPER:
+ type = "Junipers ";
+ asr_base = JUNIPER_BASE_ADDRESS;
+ asr_read_addr = asr_write_addr = asr_base;
+ asr_toggle_mask = JUNIPER_ASR_TOGGLE_MASK;
+ asr_disable_mask = JUNIPER_ASR_DISABLE_MASK;
+ break;
+
+ case ASMTYPE_SPRUCE:
+ type = "Spruce's ";
+ asr_base = SPRUCE_BASE_ADDRESS;
+ asr_read_addr = asr_write_addr = asr_base;
+ asr_toggle_mask = SPRUCE_ASR_TOGGLE_MASK;
+ asr_disable_mask = SPRUCE_ASR_DISABLE_MASK;
+ break;
+ }
+
+ if (!request_region(asr_base, asr_length, "ibmasr")) {
+ printk(KERN_ERR PFX "address %#x already in use\n",
+ asr_base);
+ return -EBUSY;
+ }
+
+ printk(KERN_INFO PFX "found %sASR @ addr %#x\n", type, asr_base);
+
+ return 0;
+}
+
+
+static ssize_t asr_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ if (count) {
+ if (!nowayout) {
+ size_t i;
+
+ /* In case it was set long ago */
+ asr_expect_close = 0;
+
+ for (i = 0; i != count; i++) {
+ char c;
+ if (get_user(c, buf + i))
+ return -EFAULT;
+ if (c == 'V')
+ asr_expect_close = 42;
+ }
+ }
+ asr_toggle();
+ }
+ return count;
+}
+
+static int asr_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ static const struct watchdog_info ident = {
+ .options = WDIOF_KEEPALIVEPING |
+ WDIOF_MAGICCLOSE,
+ .identity = "IBM ASR"
+ };
+ void __user *argp = (void __user *)arg;
+ int __user *p = argp;
+ int heartbeat;
+
+ switch (cmd) {
+ case WDIOC_GETSUPPORT:
+ return copy_to_user(argp, &ident, sizeof(ident)) ?
+ -EFAULT : 0;
+
+ case WDIOC_GETSTATUS:
+ case WDIOC_GETBOOTSTATUS:
+ return put_user(0, p);
+
+ case WDIOC_KEEPALIVE:
+ asr_toggle();
+ return 0;
+
+ /*
+ * The hardware has a fixed timeout value, so no WDIOC_SETTIMEOUT
+ * and WDIOC_GETTIMEOUT always returns 256.
+ */
+ case WDIOC_GETTIMEOUT:
+ heartbeat = 256;
+ return put_user(heartbeat, p);
+
+ case WDIOC_SETOPTIONS: {
+ int new_options, retval = -EINVAL;
+
+ if (get_user(new_options, p))
+ return -EFAULT;
+
+ if (new_options & WDIOS_DISABLECARD) {
+ asr_disable();
+ retval = 0;
+ }
+
+ if (new_options & WDIOS_ENABLECARD) {
+ asr_enable();
+ asr_toggle();
+ retval = 0;
+ }
+
+ return retval;
+ }
+ }
+
+ return -ENOIOCTLCMD;
+}
+
+static int asr_open(struct inode *inode, struct file *file)
+{
+ if(test_and_set_bit(0, &asr_is_open))
+ return -EBUSY;
+
+ asr_toggle();
+ asr_enable();
+
+ return nonseekable_open(inode, file);
+}
+
+static int asr_release(struct inode *inode, struct file *file)
+{
+ if (asr_expect_close == 42)
+ asr_disable();
+ else {
+ printk(KERN_CRIT PFX "unexpected close, not stopping watchdog!\n");
+ asr_toggle();
+ }
+ clear_bit(0, &asr_is_open);
+ asr_expect_close = 0;
+ return 0;
+}
+
+static struct file_operations asr_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .write = asr_write,
+ .ioctl = asr_ioctl,
+ .open = asr_open,
+ .release = asr_release,
+};
+
+static struct miscdevice asr_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &asr_fops,
+};
+
+
+struct ibmasr_id {
+ const char *desc;
+ int type;
+};
+
+static struct ibmasr_id __initdata ibmasr_id_table[] = {
+ { "IBM Automatic Server Restart - eserver xSeries 220", ASMTYPE_TOPAZ },
+ { "IBM Automatic Server Restart - Machine Type 8673", ASMTYPE_PEARL },
+ { "IBM Automatic Server Restart - Machine Type 8480", ASMTYPE_JASPER },
+ { "IBM Automatic Server Restart - Machine Type 8482", ASMTYPE_JUNIPER },
+ { "IBM Automatic Server Restart - Machine Type 8648", ASMTYPE_SPRUCE },
+ { NULL }
+};
+
+static int __init ibmasr_init(void)
+{
+ struct ibmasr_id *id;
+ int rc;
+
+ for (id = ibmasr_id_table; id->desc; id++) {
+ if (dmi_find_device(DMI_DEV_TYPE_OTHER, id->desc, NULL)) {
+ asr_type = id->type;
+ break;
+ }
+ }
+
+ if (!asr_type)
+ return -ENODEV;
+
+ rc = misc_register(&asr_miscdev);
+ if (rc < 0) {
+ printk(KERN_ERR PFX "failed to register misc device\n");
+ return rc;
+ }
+
+ rc = asr_get_base_address();
+ if (rc) {
+ misc_deregister(&asr_miscdev);
+ return rc;
+ }
+
+ return 0;
+}
+
+static void __exit ibmasr_exit(void)
+{
+ if (!nowayout)
+ asr_disable();
+
+ misc_deregister(&asr_miscdev);
+
+ release_region(asr_base, asr_length);
+}
+
+module_init(ibmasr_init);
+module_exit(ibmasr_exit);
+
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
+MODULE_DESCRIPTION("IBM Automatic Server Restart driver");
+MODULE_AUTHOR("Andrey Panin");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/ixp2000_wdt.c b/drivers/char/watchdog/ixp2000_wdt.c
index e7640bc..0cfb9b9 100644
--- a/drivers/char/watchdog/ixp2000_wdt.c
+++ b/drivers/char/watchdog/ixp2000_wdt.c
@@ -182,7 +182,7 @@ static struct file_operations ixp2000_wdt_fops =
static struct miscdevice ixp2000_wdt_miscdev =
{
.minor = WATCHDOG_MINOR,
- .name = "IXP2000 Watchdog",
+ .name = "watchdog",
.fops = &ixp2000_wdt_fops,
};
diff --git a/drivers/char/watchdog/ixp4xx_wdt.c b/drivers/char/watchdog/ixp4xx_wdt.c
index 8d916af..b5be8b1 100644
--- a/drivers/char/watchdog/ixp4xx_wdt.c
+++ b/drivers/char/watchdog/ixp4xx_wdt.c
@@ -176,7 +176,7 @@ static struct file_operations ixp4xx_wdt_fops =
static struct miscdevice ixp4xx_wdt_miscdev =
{
.minor = WATCHDOG_MINOR,
- .name = "IXP4xx Watchdog",
+ .name = "watchdog",
.fops = &ixp4xx_wdt_fops,
};
diff --git a/drivers/char/watchdog/mixcomwd.c b/drivers/char/watchdog/mixcomwd.c
index c9b301d..7fc2188 100644
--- a/drivers/char/watchdog/mixcomwd.c
+++ b/drivers/char/watchdog/mixcomwd.c
@@ -59,7 +59,7 @@ static unsigned long mixcomwd_opened; /* long req'd for setbit --RR */
static int watchdog_port;
static int mixcomwd_timer_alive;
-static struct timer_list mixcomwd_timer = TIMER_INITIALIZER(NULL, 0, 0);
+static DEFINE_TIMER(mixcomwd_timer, NULL, 0, 0);
static char expect_close;
static int nowayout = WATCHDOG_NOWAYOUT;
diff --git a/drivers/char/watchdog/mpcore_wdt.c b/drivers/char/watchdog/mpcore_wdt.c
new file mode 100644
index 0000000..75ca84e
--- /dev/null
+++ b/drivers/char/watchdog/mpcore_wdt.c
@@ -0,0 +1,436 @@
+/*
+ * Watchdog driver for the mpcore watchdog timer
+ *
+ * (c) Copyright 2004 ARM Limited
+ *
+ * Based on the SoftDog driver:
+ * (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
+ * http://www.redhat.com
+ *
+ * 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.
+ *
+ * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
+ * warranty for any of this software. This material is provided
+ * "AS-IS" and at no charge.
+ *
+ * (c) Copyright 1995 Alan Cox <alan@lxorguk.ukuu.org.uk>
+ *
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/fs.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+
+#include <asm/hardware/arm_twd.h>
+#include <asm/uaccess.h>
+
+struct mpcore_wdt {
+ unsigned long timer_alive;
+ struct device *dev;
+ void __iomem *base;
+ int irq;
+ unsigned int perturb;
+ char expect_close;
+};
+
+static struct platform_device *mpcore_wdt_dev;
+
+extern unsigned int mpcore_timer_rate;
+
+#define TIMER_MARGIN 60
+static int mpcore_margin = TIMER_MARGIN;
+module_param(mpcore_margin, int, 0);
+MODULE_PARM_DESC(mpcore_margin, "MPcore timer margin in seconds. (0<mpcore_margin<65536, default=" __MODULE_STRING(TIMER_MARGIN) ")");
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+#define ONLY_TESTING 0
+static int mpcore_noboot = ONLY_TESTING;
+module_param(mpcore_noboot, int, 0);
+MODULE_PARM_DESC(mpcore_noboot, "MPcore watchdog action, set to 1 to ignore reboots, 0 to reboot (default=" __MODULE_STRING(ONLY_TESTING) ")");
+
+/*
+ * This is the interrupt handler. Note that we only use this
+ * in testing mode, so don't actually do a reboot here.
+ */
+static irqreturn_t mpcore_wdt_fire(int irq, void *arg, struct pt_regs *regs)
+{
+ struct mpcore_wdt *wdt = arg;
+
+ /* Check it really was our interrupt */
+ if (readl(wdt->base + TWD_WDOG_INTSTAT)) {
+ dev_printk(KERN_CRIT, wdt->dev, "Triggered - Reboot ignored.\n");
+
+ /* Clear the interrupt on the watchdog */
+ writel(1, wdt->base + TWD_WDOG_INTSTAT);
+
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+}
+
+/*
+ * mpcore_wdt_keepalive - reload the timer
+ *
+ * Note that the spec says a DIFFERENT value must be written to the reload
+ * register each time. The "perturb" variable deals with this by adding 1
+ * to the count every other time the function is called.
+ */
+static void mpcore_wdt_keepalive(struct mpcore_wdt *wdt)
+{
+ unsigned int count;
+
+ /* Assume prescale is set to 256 */
+ count = (mpcore_timer_rate / 256) * mpcore_margin;
+
+ /* Reload the counter */
+ writel(count + wdt->perturb, wdt->base + TWD_WDOG_LOAD);
+
+ wdt->perturb = wdt->perturb ? 0 : 1;
+}
+
+static void mpcore_wdt_stop(struct mpcore_wdt *wdt)
+{
+ writel(0x12345678, wdt->base + TWD_WDOG_DISABLE);
+ writel(0x87654321, wdt->base + TWD_WDOG_DISABLE);
+ writel(0x0, wdt->base + TWD_WDOG_CONTROL);
+}
+
+static void mpcore_wdt_start(struct mpcore_wdt *wdt)
+{
+ dev_printk(KERN_INFO, wdt->dev, "enabling watchdog.\n");
+
+ /* This loads the count register but does NOT start the count yet */
+ mpcore_wdt_keepalive(wdt);
+
+ if (mpcore_noboot) {
+ /* Enable watchdog - prescale=256, watchdog mode=0, enable=1 */
+ writel(0x0000FF01, wdt->base + TWD_WDOG_CONTROL);
+ } else {
+ /* Enable watchdog - prescale=256, watchdog mode=1, enable=1 */
+ writel(0x0000FF09, wdt->base + TWD_WDOG_CONTROL);
+ }
+}
+
+static int mpcore_wdt_set_heartbeat(int t)
+{
+ if (t < 0x0001 || t > 0xFFFF)
+ return -EINVAL;
+
+ mpcore_margin = t;
+ return 0;
+}
+
+/*
+ * /dev/watchdog handling
+ */
+static int mpcore_wdt_open(struct inode *inode, struct file *file)
+{
+ struct mpcore_wdt *wdt = dev_get_drvdata(&mpcore_wdt_dev->dev);
+
+ if (test_and_set_bit(0, &wdt->timer_alive))
+ return -EBUSY;
+
+ if (nowayout)
+ __module_get(THIS_MODULE);
+
+ file->private_data = wdt;
+
+ /*
+ * Activate timer
+ */
+ mpcore_wdt_start(wdt);
+
+ return nonseekable_open(inode, file);
+}
+
+static int mpcore_wdt_release(struct inode *inode, struct file *file)
+{
+ struct mpcore_wdt *wdt = file->private_data;
+
+ /*
+ * Shut off the timer.
+ * Lock it in if it's a module and we set nowayout
+ */
+ if (wdt->expect_close == 42) {
+ mpcore_wdt_stop(wdt);
+ } else {
+ dev_printk(KERN_CRIT, wdt->dev, "unexpected close, not stopping watchdog!\n");
+ mpcore_wdt_keepalive(wdt);
+ }
+ clear_bit(0, &wdt->timer_alive);
+ wdt->expect_close = 0;
+ return 0;
+}
+
+static ssize_t mpcore_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos)
+{
+ struct mpcore_wdt *wdt = file->private_data;
+
+ /* Can't seek (pwrite) on this device */
+ if (ppos != &file->f_pos)
+ return -ESPIPE;
+
+ /*
+ * Refresh the timer.
+ */
+ if (len) {
+ if (!nowayout) {
+ size_t i;
+
+ /* In case it was set long ago */
+ wdt->expect_close = 0;
+
+ for (i = 0; i != len; i++) {
+ char c;
+
+ if (get_user(c, data + i))
+ return -EFAULT;
+ if (c == 'V')
+ wdt->expect_close = 42;
+ }
+ }
+ mpcore_wdt_keepalive(wdt);
+ }
+ return len;
+}
+
+static struct watchdog_info ident = {
+ .options = WDIOF_SETTIMEOUT |
+ WDIOF_KEEPALIVEPING |
+ WDIOF_MAGICCLOSE,
+ .identity = "MPcore Watchdog",
+};
+
+static int mpcore_wdt_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct mpcore_wdt *wdt = file->private_data;
+ int ret;
+ union {
+ struct watchdog_info ident;
+ int i;
+ } uarg;
+
+ if (_IOC_DIR(cmd) && _IOC_SIZE(cmd) > sizeof(uarg))
+ return -ENOIOCTLCMD;
+
+ if (_IOC_DIR(cmd) & _IOC_WRITE) {
+ ret = copy_from_user(&uarg, (void __user *)arg, _IOC_SIZE(cmd));
+ if (ret)
+ return -EFAULT;
+ }
+
+ switch (cmd) {
+ case WDIOC_GETSUPPORT:
+ uarg.ident = ident;
+ ret = 0;
+ break;
+
+ case WDIOC_SETOPTIONS:
+ ret = -EINVAL;
+ if (uarg.i & WDIOS_DISABLECARD) {
+ mpcore_wdt_stop(wdt);
+ ret = 0;
+ }
+ if (uarg.i & WDIOS_ENABLECARD) {
+ mpcore_wdt_start(wdt);
+ ret = 0;
+ }
+ break;
+
+ case WDIOC_GETSTATUS:
+ case WDIOC_GETBOOTSTATUS:
+ uarg.i = 0;
+ ret = 0;
+ break;
+
+ case WDIOC_KEEPALIVE:
+ mpcore_wdt_keepalive(wdt);
+ ret = 0;
+ break;
+
+ case WDIOC_SETTIMEOUT:
+ ret = mpcore_wdt_set_heartbeat(uarg.i);
+ if (ret)
+ break;
+
+ mpcore_wdt_keepalive(wdt);
+ /* Fall */
+ case WDIOC_GETTIMEOUT:
+ uarg.i = mpcore_margin;
+ ret = 0;
+ break;
+
+ default:
+ return -ENOIOCTLCMD;
+ }
+
+ if (ret == 0 && _IOC_DIR(cmd) & _IOC_READ) {
+ ret = copy_to_user((void __user *)arg, &uarg, _IOC_SIZE(cmd));
+ if (ret)
+ ret = -EFAULT;
+ }
+ return ret;
+}
+
+/*
+ * System shutdown handler. Turn off the watchdog if we're
+ * restarting or halting the system.
+ */
+static void mpcore_wdt_shutdown(struct device *_dev)
+{
+ struct mpcore_wdt *wdt = dev_get_drvdata(_dev);
+
+ if (system_state == SYSTEM_RESTART || system_state == SYSTEM_HALT)
+ mpcore_wdt_stop(wdt);
+}
+
+/*
+ * Kernel Interfaces
+ */
+static struct file_operations mpcore_wdt_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .write = mpcore_wdt_write,
+ .ioctl = mpcore_wdt_ioctl,
+ .open = mpcore_wdt_open,
+ .release = mpcore_wdt_release,
+};
+
+static struct miscdevice mpcore_wdt_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &mpcore_wdt_fops,
+};
+
+static int __devinit mpcore_wdt_probe(struct device *_dev)
+{
+ struct platform_device *dev = to_platform_device(_dev);
+ struct mpcore_wdt *wdt;
+ struct resource *res;
+ int ret;
+
+ /* We only accept one device, and it must have an id of -1 */
+ if (dev->id != -1)
+ return -ENODEV;
+
+ res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ if (!res) {
+ ret = -ENODEV;
+ goto err_out;
+ }
+
+ wdt = kmalloc(sizeof(struct mpcore_wdt), GFP_KERNEL);
+ if (!wdt) {
+ ret = -ENOMEM;
+ goto err_out;
+ }
+ memset(wdt, 0, sizeof(struct mpcore_wdt));
+
+ wdt->dev = &dev->dev;
+ wdt->irq = platform_get_irq(dev, 0);
+ wdt->base = ioremap(res->start, res->end - res->start + 1);
+ if (!wdt->base) {
+ ret = -ENOMEM;
+ goto err_free;
+ }
+
+ mpcore_wdt_miscdev.dev = &dev->dev;
+ ret = misc_register(&mpcore_wdt_miscdev);
+ if (ret) {
+ dev_printk(KERN_ERR, _dev, "cannot register miscdev on minor=%d (err=%d)\n",
+ WATCHDOG_MINOR, ret);
+ goto err_misc;
+ }
+
+ ret = request_irq(wdt->irq, mpcore_wdt_fire, SA_INTERRUPT, "mpcore_wdt", wdt);
+ if (ret) {
+ dev_printk(KERN_ERR, _dev, "cannot register IRQ%d for watchdog\n", wdt->irq);
+ goto err_irq;
+ }
+
+ mpcore_wdt_stop(wdt);
+ dev_set_drvdata(&dev->dev, wdt);
+ mpcore_wdt_dev = dev;
+
+ return 0;
+
+ err_irq:
+ misc_deregister(&mpcore_wdt_miscdev);
+ err_misc:
+ iounmap(wdt->base);
+ err_free:
+ kfree(wdt);
+ err_out:
+ return ret;
+}
+
+static int __devexit mpcore_wdt_remove(struct device *dev)
+{
+ struct mpcore_wdt *wdt = dev_get_drvdata(dev);
+
+ dev_set_drvdata(dev, NULL);
+
+ misc_deregister(&mpcore_wdt_miscdev);
+
+ mpcore_wdt_dev = NULL;
+
+ free_irq(wdt->irq, wdt);
+ iounmap(wdt->base);
+ kfree(wdt);
+ return 0;
+}
+
+static struct device_driver mpcore_wdt_driver = {
+ .name = "mpcore_wdt",
+ .bus = &platform_bus_type,
+ .probe = mpcore_wdt_probe,
+ .remove = __devexit_p(mpcore_wdt_remove),
+ .shutdown = mpcore_wdt_shutdown,
+};
+
+static char banner[] __initdata = KERN_INFO "MPcore Watchdog Timer: 0.1. mpcore_noboot=%d mpcore_margin=%d sec (nowayout= %d)\n";
+
+static int __init mpcore_wdt_init(void)
+{
+ /*
+ * Check that the margin value is within it's range;
+ * if not reset to the default
+ */
+ if (mpcore_wdt_set_heartbeat(mpcore_margin)) {
+ mpcore_wdt_set_heartbeat(TIMER_MARGIN);
+ printk(KERN_INFO "mpcore_margin value must be 0<mpcore_margin<65536, using %d\n",
+ TIMER_MARGIN);
+ }
+
+ printk(banner, mpcore_noboot, mpcore_margin, nowayout);
+
+ return driver_register(&mpcore_wdt_driver);
+}
+
+static void __exit mpcore_wdt_exit(void)
+{
+ driver_unregister(&mpcore_wdt_driver);
+}
+
+module_init(mpcore_wdt_init);
+module_exit(mpcore_wdt_exit);
+
+MODULE_AUTHOR("ARM Limited");
+MODULE_DESCRIPTION("MPcore Watchdog Device Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/mv64x60_wdt.c b/drivers/char/watchdog/mv64x60_wdt.c
new file mode 100644
index 0000000..1436aea
--- /dev/null
+++ b/drivers/char/watchdog/mv64x60_wdt.c
@@ -0,0 +1,252 @@
+/*
+ * mv64x60_wdt.c - MV64X60 (Marvell Discovery) watchdog userspace interface
+ *
+ * Author: James Chapman <jchapman@katalix.com>
+ *
+ * Platform-specific setup code should configure the dog to generate
+ * interrupt or reset as required. This code only enables/disables
+ * and services the watchdog.
+ *
+ * Derived from mpc8xx_wdt.c, with the following copyright.
+ *
+ * 2002 (c) Florian Schirmer <jolt@tuxbox.org> This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#include <linux/config.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/watchdog.h>
+#include <asm/mv64x60.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+/* MV64x60 WDC (config) register access definitions */
+#define MV64x60_WDC_CTL1_MASK (3 << 24)
+#define MV64x60_WDC_CTL1(val) ((val & 3) << 24)
+#define MV64x60_WDC_CTL2_MASK (3 << 26)
+#define MV64x60_WDC_CTL2(val) ((val & 3) << 26)
+
+/* Flags bits */
+#define MV64x60_WDOG_FLAG_OPENED 0
+#define MV64x60_WDOG_FLAG_ENABLED 1
+
+static unsigned long wdt_flags;
+static int wdt_status;
+static void __iomem *mv64x60_regs;
+static int mv64x60_wdt_timeout;
+
+static void mv64x60_wdt_reg_write(u32 val)
+{
+ /* Allow write only to CTL1 / CTL2 fields, retaining values in
+ * other fields.
+ */
+ u32 data = readl(mv64x60_regs + MV64x60_WDT_WDC);
+ data &= ~(MV64x60_WDC_CTL1_MASK | MV64x60_WDC_CTL2_MASK);
+ data |= val;
+ writel(data, mv64x60_regs + MV64x60_WDT_WDC);
+}
+
+static void mv64x60_wdt_service(void)
+{
+ /* Write 01 followed by 10 to CTL2 */
+ mv64x60_wdt_reg_write(MV64x60_WDC_CTL2(0x01));
+ mv64x60_wdt_reg_write(MV64x60_WDC_CTL2(0x02));
+}
+
+static void mv64x60_wdt_handler_disable(void)
+{
+ if (test_and_clear_bit(MV64x60_WDOG_FLAG_ENABLED, &wdt_flags)) {
+ /* Write 01 followed by 10 to CTL1 */
+ mv64x60_wdt_reg_write(MV64x60_WDC_CTL1(0x01));
+ mv64x60_wdt_reg_write(MV64x60_WDC_CTL1(0x02));
+ printk(KERN_NOTICE "mv64x60_wdt: watchdog deactivated\n");
+ }
+}
+
+static void mv64x60_wdt_handler_enable(void)
+{
+ if (!test_and_set_bit(MV64x60_WDOG_FLAG_ENABLED, &wdt_flags)) {
+ /* Write 01 followed by 10 to CTL1 */
+ mv64x60_wdt_reg_write(MV64x60_WDC_CTL1(0x01));
+ mv64x60_wdt_reg_write(MV64x60_WDC_CTL1(0x02));
+ printk(KERN_NOTICE "mv64x60_wdt: watchdog activated\n");
+ }
+}
+
+static int mv64x60_wdt_open(struct inode *inode, struct file *file)
+{
+ if (test_and_set_bit(MV64x60_WDOG_FLAG_OPENED, &wdt_flags))
+ return -EBUSY;
+
+ mv64x60_wdt_service();
+ mv64x60_wdt_handler_enable();
+
+ return 0;
+}
+
+static int mv64x60_wdt_release(struct inode *inode, struct file *file)
+{
+ mv64x60_wdt_service();
+
+#if !defined(CONFIG_WATCHDOG_NOWAYOUT)
+ mv64x60_wdt_handler_disable();
+#endif
+
+ clear_bit(MV64x60_WDOG_FLAG_OPENED, &wdt_flags);
+
+ return 0;
+}
+
+static ssize_t mv64x60_wdt_write(struct file *file, const char *data,
+ size_t len, loff_t * ppos)
+{
+ if (*ppos != file->f_pos)
+ return -ESPIPE;
+
+ if (len)
+ mv64x60_wdt_service();
+
+ return len;
+}
+
+static int mv64x60_wdt_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ int timeout;
+ static struct watchdog_info info = {
+ .options = WDIOF_KEEPALIVEPING,
+ .firmware_version = 0,
+ .identity = "MV64x60 watchdog",
+ };
+
+ switch (cmd) {
+ case WDIOC_GETSUPPORT:
+ if (copy_to_user((void *)arg, &info, sizeof(info)))
+ return -EFAULT;
+ break;
+
+ case WDIOC_GETSTATUS:
+ case WDIOC_GETBOOTSTATUS:
+ if (put_user(wdt_status, (int *)arg))
+ return -EFAULT;
+ wdt_status &= ~WDIOF_KEEPALIVEPING;
+ break;
+
+ case WDIOC_GETTEMP:
+ return -EOPNOTSUPP;
+
+ case WDIOC_SETOPTIONS:
+ return -EOPNOTSUPP;
+
+ case WDIOC_KEEPALIVE:
+ mv64x60_wdt_service();
+ wdt_status |= WDIOF_KEEPALIVEPING;
+ break;
+
+ case WDIOC_SETTIMEOUT:
+ return -EOPNOTSUPP;
+
+ case WDIOC_GETTIMEOUT:
+ timeout = mv64x60_wdt_timeout * HZ;
+ if (put_user(timeout, (int *)arg))
+ return -EFAULT;
+ break;
+
+ default:
+ return -ENOIOCTLCMD;
+ }
+
+ return 0;
+}
+
+static struct file_operations mv64x60_wdt_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .write = mv64x60_wdt_write,
+ .ioctl = mv64x60_wdt_ioctl,
+ .open = mv64x60_wdt_open,
+ .release = mv64x60_wdt_release,
+};
+
+static struct miscdevice mv64x60_wdt_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &mv64x60_wdt_fops,
+};
+
+static int __devinit mv64x60_wdt_probe(struct device *dev)
+{
+ struct platform_device *pd = to_platform_device(dev);
+ struct mv64x60_wdt_pdata *pdata = pd->dev.platform_data;
+ int bus_clk = 133;
+
+ mv64x60_wdt_timeout = 10;
+ if (pdata) {
+ mv64x60_wdt_timeout = pdata->timeout;
+ bus_clk = pdata->bus_clk;
+ }
+
+ mv64x60_regs = mv64x60_get_bridge_vbase();
+
+ writel((mv64x60_wdt_timeout * (bus_clk * 1000000)) >> 8,
+ mv64x60_regs + MV64x60_WDT_WDC);
+
+ return misc_register(&mv64x60_wdt_miscdev);
+}
+
+static int __devexit mv64x60_wdt_remove(struct device *dev)
+{
+ misc_deregister(&mv64x60_wdt_miscdev);
+
+ mv64x60_wdt_service();
+ mv64x60_wdt_handler_disable();
+
+ return 0;
+}
+
+static struct device_driver mv64x60_wdt_driver = {
+ .name = MV64x60_WDT_NAME,
+ .bus = &platform_bus_type,
+ .probe = mv64x60_wdt_probe,
+ .remove = __devexit_p(mv64x60_wdt_remove),
+};
+
+static struct platform_device *mv64x60_wdt_dev;
+
+static int __init mv64x60_wdt_init(void)
+{
+ int ret;
+
+ printk(KERN_INFO "MV64x60 watchdog driver\n");
+
+ mv64x60_wdt_dev = platform_device_register_simple(MV64x60_WDT_NAME,
+ -1, NULL, 0);
+ if (IS_ERR(mv64x60_wdt_dev)) {
+ ret = PTR_ERR(mv64x60_wdt_dev);
+ goto out;
+ }
+
+ ret = driver_register(&mv64x60_wdt_driver);
+ out:
+ return ret;
+}
+
+static void __exit mv64x60_wdt_exit(void)
+{
+ driver_unregister(&mv64x60_wdt_driver);
+ platform_device_unregister(mv64x60_wdt_dev);
+}
+
+module_init(mv64x60_wdt_init);
+module_exit(mv64x60_wdt_exit);
+
+MODULE_AUTHOR("James Chapman <jchapman@katalix.com>");
+MODULE_DESCRIPTION("MV64x60 watchdog driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/pcwd_pci.c b/drivers/char/watchdog/pcwd_pci.c
index 2b13afb..5a80adb 100644
--- a/drivers/char/watchdog/pcwd_pci.c
+++ b/drivers/char/watchdog/pcwd_pci.c
@@ -29,27 +29,29 @@
* Includes, defines, variables, module parameters, ...
*/
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/types.h>
-#include <linux/delay.h>
-#include <linux/miscdevice.h>
-#include <linux/watchdog.h>
-#include <linux/notifier.h>
-#include <linux/reboot.h>
-#include <linux/init.h>
-#include <linux/fs.h>
-#include <linux/pci.h>
-#include <linux/ioport.h>
-#include <linux/spinlock.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
+#include <linux/config.h> /* For CONFIG_WATCHDOG_NOWAYOUT/... */
+#include <linux/module.h> /* For module specific items */
+#include <linux/moduleparam.h> /* For new moduleparam's */
+#include <linux/types.h> /* For standard types (like size_t) */
+#include <linux/errno.h> /* For the -ENODEV/... values */
+#include <linux/kernel.h> /* For printk/panic/... */
+#include <linux/delay.h> /* For mdelay function */
+#include <linux/miscdevice.h> /* For MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR) */
+#include <linux/watchdog.h> /* For the watchdog specific items */
+#include <linux/notifier.h> /* For notifier support */
+#include <linux/reboot.h> /* For reboot_notifier stuff */
+#include <linux/init.h> /* For __init/__exit/... */
+#include <linux/fs.h> /* For file operations */
+#include <linux/pci.h> /* For pci functions */
+#include <linux/ioport.h> /* For io-port access */
+#include <linux/spinlock.h> /* For spin_lock/spin_unlock/... */
+
+#include <asm/uaccess.h> /* For copy_to_user/put_user/... */
+#include <asm/io.h> /* For inb/outb/... */
/* Module and version information */
#define WATCHDOG_VERSION "1.01"
-#define WATCHDOG_DATE "15 Mar 2005"
+#define WATCHDOG_DATE "02 Sep 2005"
#define WATCHDOG_DRIVER_NAME "PCI-PC Watchdog"
#define WATCHDOG_NAME "pcwd_pci"
#define PFX WATCHDOG_NAME ": "
@@ -335,12 +337,14 @@ static int pcipcwd_ioctl(struct inode *inode, struct file *file,
return -EFAULT;
if (new_options & WDIOS_DISABLECARD) {
- pcipcwd_stop();
+ if (pcipcwd_stop())
+ return -EIO;
retval = 0;
}
if (new_options & WDIOS_ENABLECARD) {
- pcipcwd_start();
+ if (pcipcwd_start())
+ return -EIO;
retval = 0;
}
diff --git a/drivers/char/watchdog/s3c2410_wdt.c b/drivers/char/watchdog/s3c2410_wdt.c
index f85ac89..3625b26 100644
--- a/drivers/char/watchdog/s3c2410_wdt.c
+++ b/drivers/char/watchdog/s3c2410_wdt.c
@@ -27,7 +27,10 @@
* Fixed tmr_count / wdt_count confusion
* Added configurable debug
*
- * 11-Jan-2004 BJD Fixed divide-by-2 in timeout code
+ * 11-Jan-2005 BJD Fixed divide-by-2 in timeout code
+ *
+ * 25-Jan-2005 DA Added suspend/resume support
+ * Replaced reboot notifier with .shutdown method
*
* 10-Mar-2005 LCVR Changed S3C2410_VA to S3C24XX_VA
*/
@@ -40,8 +43,6 @@
#include <linux/miscdevice.h>
#include <linux/watchdog.h>
#include <linux/fs.h>
-#include <linux/notifier.h>
-#include <linux/reboot.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/interrupt.h>
@@ -317,20 +318,6 @@ static int s3c2410wdt_ioctl(struct inode *inode, struct file *file,
}
}
-/*
- * Notifier for system down
- */
-
-static int s3c2410wdt_notify_sys(struct notifier_block *this, unsigned long code,
- void *unused)
-{
- if(code==SYS_DOWN || code==SYS_HALT) {
- /* Turn the WDT off */
- s3c2410wdt_stop();
- }
- return NOTIFY_DONE;
-}
-
/* kernel interface */
static struct file_operations s3c2410wdt_fops = {
@@ -348,10 +335,6 @@ static struct miscdevice s3c2410wdt_miscdev = {
.fops = &s3c2410wdt_fops,
};
-static struct notifier_block s3c2410wdt_notifier = {
- .notifier_call = s3c2410wdt_notify_sys,
-};
-
/* interrupt handler code */
static irqreturn_t s3c2410wdt_irq(int irqno, void *param,
@@ -432,18 +415,10 @@ static int s3c2410wdt_probe(struct device *dev)
}
}
- ret = register_reboot_notifier(&s3c2410wdt_notifier);
- if (ret) {
- printk (KERN_ERR PFX "cannot register reboot notifier (%d)\n",
- ret);
- return ret;
- }
-
ret = misc_register(&s3c2410wdt_miscdev);
if (ret) {
printk (KERN_ERR PFX "cannot register miscdev on minor=%d (%d)\n",
WATCHDOG_MINOR, ret);
- unregister_reboot_notifier(&s3c2410wdt_notifier);
return ret;
}
@@ -479,15 +454,63 @@ static int s3c2410wdt_remove(struct device *dev)
return 0;
}
+static void s3c2410wdt_shutdown(struct device *dev)
+{
+ s3c2410wdt_stop();
+}
+
+#ifdef CONFIG_PM
+
+static unsigned long wtcon_save;
+static unsigned long wtdat_save;
+
+static int s3c2410wdt_suspend(struct device *dev, pm_message_t state, u32 level)
+{
+ if (level == SUSPEND_POWER_DOWN) {
+ /* Save watchdog state, and turn it off. */
+ wtcon_save = readl(wdt_base + S3C2410_WTCON);
+ wtdat_save = readl(wdt_base + S3C2410_WTDAT);
+
+ /* Note that WTCNT doesn't need to be saved. */
+ s3c2410wdt_stop();
+ }
+
+ return 0;
+}
+
+static int s3c2410wdt_resume(struct device *dev, u32 level)
+{
+ if (level == RESUME_POWER_ON) {
+ /* Restore watchdog state. */
+
+ writel(wtdat_save, wdt_base + S3C2410_WTDAT);
+ writel(wtdat_save, wdt_base + S3C2410_WTCNT); /* Reset count */
+ writel(wtcon_save, wdt_base + S3C2410_WTCON);
+
+ printk(KERN_INFO PFX "watchdog %sabled\n",
+ (wtcon_save & S3C2410_WTCON_ENABLE) ? "en" : "dis");
+ }
+
+ return 0;
+}
+
+#else
+#define s3c2410wdt_suspend NULL
+#define s3c2410wdt_resume NULL
+#endif /* CONFIG_PM */
+
+
static struct device_driver s3c2410wdt_driver = {
.name = "s3c2410-wdt",
.bus = &platform_bus_type,
.probe = s3c2410wdt_probe,
.remove = s3c2410wdt_remove,
+ .shutdown = s3c2410wdt_shutdown,
+ .suspend = s3c2410wdt_suspend,
+ .resume = s3c2410wdt_resume,
};
-
static char banner[] __initdata = KERN_INFO "S3C2410 Watchdog Timer, (c) 2004 Simtec Electronics\n";
static int __init watchdog_init(void)
@@ -499,13 +522,13 @@ static int __init watchdog_init(void)
static void __exit watchdog_exit(void)
{
driver_unregister(&s3c2410wdt_driver);
- unregister_reboot_notifier(&s3c2410wdt_notifier);
}
module_init(watchdog_init);
module_exit(watchdog_exit);
-MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>, "
+ "Dimitry Andric <dimitry.andric@tomtom.com>");
MODULE_DESCRIPTION("S3C2410 Watchdog Device Driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/sbc8360.c b/drivers/char/watchdog/sbc8360.c
new file mode 100644
index 0000000..c6cbf80
--- /dev/null
+++ b/drivers/char/watchdog/sbc8360.c
@@ -0,0 +1,414 @@
+/*
+ * SBC8360 Watchdog driver
+ *
+ * (c) Copyright 2005 Webcon, Inc.
+ *
+ * Based on ib700wdt.c, which is based on advantechwdt.c which is based
+ * on acquirewdt.c which is based on wdt.c.
+ *
+ * (c) Copyright 2001 Charles Howes <chowes@vsol.net>
+ *
+ * Based on advantechwdt.c which is based on acquirewdt.c which
+ * is based on wdt.c.
+ *
+ * (c) Copyright 2000-2001 Marek Michalkiewicz <marekm@linux.org.pl>
+ *
+ * Based on acquirewdt.c which is based on wdt.c.
+ * Original copyright messages:
+ *
+ * (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
+ * http://www.redhat.com
+ *
+ * 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.
+ *
+ * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
+ * warranty for any of this software. This material is provided
+ * "AS-IS" and at no charge.
+ *
+ * (c) Copyright 1995 Alan Cox <alan@redhat.com>
+ *
+ * 14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
+ * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
+ * Added timeout module option to override default
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/notifier.h>
+#include <linux/fs.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/moduleparam.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+static unsigned long sbc8360_is_open;
+static spinlock_t sbc8360_lock;
+static char expect_close;
+
+#define PFX "sbc8360: "
+
+/*
+ *
+ * Watchdog Timer Configuration
+ *
+ * The function of the watchdog timer is to reset the system automatically
+ * and is defined at I/O port 0120H and 0121H. To enable the watchdog timer
+ * and allow the system to reset, write appropriate values from the table
+ * below to I/O port 0120H and 0121H. To disable the timer, write a zero
+ * value to I/O port 0121H for the system to stop the watchdog function.
+ *
+ * The following describes how the timer should be programmed (according to
+ * the vendor documentation)
+ *
+ * Enabling Watchdog:
+ * MOV AX,000AH (enable, phase I)
+ * MOV DX,0120H
+ * OUT DX,AX
+ * MOV AX,000BH (enable, phase II)
+ * MOV DX,0120H
+ * OUT DX,AX
+ * MOV AX,000nH (set multiplier n, from 1-4)
+ * MOV DX,0120H
+ * OUT DX,AX
+ * MOV AX,000mH (set base timer m, from 0-F)
+ * MOV DX,0121H
+ * OUT DX,AX
+ *
+ * Reset timer:
+ * MOV AX,000mH (same as set base timer, above)
+ * MOV DX,0121H
+ * OUT DX,AX
+ *
+ * Disabling Watchdog:
+ * MOV AX,0000H (a zero value)
+ * MOV DX,0120H
+ * OUT DX,AX
+ *
+ * Watchdog timeout configuration values:
+ * N
+ * M | 1 2 3 4
+ * --|----------------------------------
+ * 0 | 0.5s 5s 50s 100s
+ * 1 | 1s 10s 100s 200s
+ * 2 | 1.5s 15s 150s 300s
+ * 3 | 2s 20s 200s 400s
+ * 4 | 2.5s 25s 250s 500s
+ * 5 | 3s 30s 300s 600s
+ * 6 | 3.5s 35s 350s 700s
+ * 7 | 4s 40s 400s 800s
+ * 8 | 4.5s 45s 450s 900s
+ * 9 | 5s 50s 500s 1000s
+ * A | 5.5s 55s 550s 1100s
+ * B | 6s 60s 600s 1200s
+ * C | 6.5s 65s 650s 1300s
+ * D | 7s 70s 700s 1400s
+ * E | 7.5s 75s 750s 1500s
+ * F | 8s 80s 800s 1600s
+ *
+ * Another way to say the same things is:
+ * For N=1, Timeout = (M+1) * 0.5s
+ * For N=2, Timeout = (M+1) * 5s
+ * For N=3, Timeout = (M+1) * 50s
+ * For N=4, Timeout = (M+1) * 100s
+ *
+ */
+
+static int wd_times[64][2] = {
+ {0, 1}, /* 0 = 0.5s */
+ {1, 1}, /* 1 = 1s */
+ {2, 1}, /* 2 = 1.5s */
+ {3, 1}, /* 3 = 2s */
+ {4, 1}, /* 4 = 2.5s */
+ {5, 1}, /* 5 = 3s */
+ {6, 1}, /* 6 = 3.5s */
+ {7, 1}, /* 7 = 4s */
+ {8, 1}, /* 8 = 4.5s */
+ {9, 1}, /* 9 = 5s */
+ {0xA, 1}, /* 10 = 5.5s */
+ {0xB, 1}, /* 11 = 6s */
+ {0xC, 1}, /* 12 = 6.5s */
+ {0xD, 1}, /* 13 = 7s */
+ {0xE, 1}, /* 14 = 7.5s */
+ {0xF, 1}, /* 15 = 8s */
+ {0, 2}, /* 16 = 5s */
+ {1, 2}, /* 17 = 10s */
+ {2, 2}, /* 18 = 15s */
+ {3, 2}, /* 19 = 20s */
+ {4, 2}, /* 20 = 25s */
+ {5, 2}, /* 21 = 30s */
+ {6, 2}, /* 22 = 35s */
+ {7, 2}, /* 23 = 40s */
+ {8, 2}, /* 24 = 45s */
+ {9, 2}, /* 25 = 50s */
+ {0xA, 2}, /* 26 = 55s */
+ {0xB, 2}, /* 27 = 60s */
+ {0xC, 2}, /* 28 = 65s */
+ {0xD, 2}, /* 29 = 70s */
+ {0xE, 2}, /* 30 = 75s */
+ {0xF, 2}, /* 31 = 80s */
+ {0, 3}, /* 32 = 50s */
+ {1, 3}, /* 33 = 100s */
+ {2, 3}, /* 34 = 150s */
+ {3, 3}, /* 35 = 200s */
+ {4, 3}, /* 36 = 250s */
+ {5, 3}, /* 37 = 300s */
+ {6, 3}, /* 38 = 350s */
+ {7, 3}, /* 39 = 400s */
+ {8, 3}, /* 40 = 450s */
+ {9, 3}, /* 41 = 500s */
+ {0xA, 3}, /* 42 = 550s */
+ {0xB, 3}, /* 43 = 600s */
+ {0xC, 3}, /* 44 = 650s */
+ {0xD, 3}, /* 45 = 700s */
+ {0xE, 3}, /* 46 = 750s */
+ {0xF, 3}, /* 47 = 800s */
+ {0, 4}, /* 48 = 100s */
+ {1, 4}, /* 49 = 200s */
+ {2, 4}, /* 50 = 300s */
+ {3, 4}, /* 51 = 400s */
+ {4, 4}, /* 52 = 500s */
+ {5, 4}, /* 53 = 600s */
+ {6, 4}, /* 54 = 700s */
+ {7, 4}, /* 55 = 800s */
+ {8, 4}, /* 56 = 900s */
+ {9, 4}, /* 57 = 1000s */
+ {0xA, 4}, /* 58 = 1100s */
+ {0xB, 4}, /* 59 = 1200s */
+ {0xC, 4}, /* 60 = 1300s */
+ {0xD, 4}, /* 61 = 1400s */
+ {0xE, 4}, /* 62 = 1500s */
+ {0xF, 4} /* 63 = 1600s */
+};
+
+#define SBC8360_ENABLE 0x120
+#define SBC8360_BASETIME 0x121
+
+static int timeout = 27;
+static int wd_margin = 0xB;
+static int wd_multiplier = 2;
+static int nowayout = WATCHDOG_NOWAYOUT;
+
+module_param(timeout, int, 27);
+MODULE_PARM_DESC(timeout, "Index into timeout table (0-63) (default=27 (60s))");
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout,
+ "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
+/*
+ * Kernel methods.
+ */
+
+/* Activate and pre-configure watchdog */
+static void sbc8360_activate(void)
+{
+ /* Enable the watchdog */
+ outb(0x0A, SBC8360_ENABLE);
+ msleep_interruptible(100);
+ outb(0x0B, SBC8360_ENABLE);
+ msleep_interruptible(100);
+ /* Set timeout multiplier */
+ outb(wd_multiplier, SBC8360_ENABLE);
+ msleep_interruptible(100);
+ /* Nothing happens until first sbc8360_ping() */
+}
+
+/* Kernel pings watchdog */
+static void sbc8360_ping(void)
+{
+ /* Write the base timer register */
+ outb(wd_margin, SBC8360_BASETIME);
+}
+
+/* Userspace pings kernel driver, or requests clean close */
+static ssize_t sbc8360_write(struct file *file, const char __user * buf,
+ size_t count, loff_t * ppos)
+{
+ if (count) {
+ if (!nowayout) {
+ size_t i;
+
+ /* In case it was set long ago */
+ expect_close = 0;
+
+ for (i = 0; i != count; i++) {
+ char c;
+ if (get_user(c, buf + i))
+ return -EFAULT;
+ if (c == 'V')
+ expect_close = 42;
+ }
+ }
+ sbc8360_ping();
+ }
+ return count;
+}
+
+static int sbc8360_open(struct inode *inode, struct file *file)
+{
+ spin_lock(&sbc8360_lock);
+ if (test_and_set_bit(0, &sbc8360_is_open)) {
+ spin_unlock(&sbc8360_lock);
+ return -EBUSY;
+ }
+ if (nowayout)
+ __module_get(THIS_MODULE);
+
+ /* Activate and ping once to start the countdown */
+ spin_unlock(&sbc8360_lock);
+ sbc8360_activate();
+ sbc8360_ping();
+ return nonseekable_open(inode, file);
+}
+
+static int sbc8360_close(struct inode *inode, struct file *file)
+{
+ spin_lock(&sbc8360_lock);
+ if (expect_close == 42)
+ outb(0, SBC8360_ENABLE);
+ else
+ printk(KERN_CRIT PFX
+ "SBC8360 device closed unexpectedly. SBC8360 will not stop!\n");
+
+ clear_bit(0, &sbc8360_is_open);
+ expect_close = 0;
+ spin_unlock(&sbc8360_lock);
+ return 0;
+}
+
+/*
+ * Notifier for system down
+ */
+
+static int sbc8360_notify_sys(struct notifier_block *this, unsigned long code,
+ void *unused)
+{
+ if (code == SYS_DOWN || code == SYS_HALT) {
+ /* Disable the SBC8360 Watchdog */
+ outb(0, SBC8360_ENABLE);
+ }
+ return NOTIFY_DONE;
+}
+
+/*
+ * Kernel Interfaces
+ */
+
+static struct file_operations sbc8360_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .write = sbc8360_write,
+ .open = sbc8360_open,
+ .release = sbc8360_close,
+};
+
+static struct miscdevice sbc8360_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &sbc8360_fops,
+};
+
+/*
+ * The SBC8360 needs to learn about soft shutdowns in order to
+ * turn the timebomb registers off.
+ */
+
+static struct notifier_block sbc8360_notifier = {
+ .notifier_call = sbc8360_notify_sys,
+};
+
+static int __init sbc8360_init(void)
+{
+ int res;
+ unsigned long int mseconds = 60000;
+
+ spin_lock_init(&sbc8360_lock);
+ res = misc_register(&sbc8360_miscdev);
+ if (res) {
+ printk(KERN_ERR PFX "failed to register misc device\n");
+ goto out_nomisc;
+ }
+
+ if (!request_region(SBC8360_ENABLE, 1, "SBC8360")) {
+ printk(KERN_ERR PFX "ENABLE method I/O %X is not available.\n",
+ SBC8360_ENABLE);
+ res = -EIO;
+ goto out_noenablereg;
+ }
+ if (!request_region(SBC8360_BASETIME, 1, "SBC8360")) {
+ printk(KERN_ERR PFX
+ "BASETIME method I/O %X is not available.\n",
+ SBC8360_BASETIME);
+ res = -EIO;
+ goto out_nobasetimereg;
+ }
+
+ res = register_reboot_notifier(&sbc8360_notifier);
+ if (res) {
+ printk(KERN_ERR PFX "Failed to register reboot notifier.\n");
+ goto out_noreboot;
+ }
+
+ if (timeout < 0 || timeout > 63) {
+ printk(KERN_ERR PFX "Invalid timeout index (must be 0-63).\n");
+ res = -EINVAL;
+ goto out_noreboot;
+ }
+
+ wd_margin = wd_times[timeout][0];
+ wd_multiplier = wd_times[timeout][1];
+
+ if (wd_multiplier == 1)
+ mseconds = (wd_margin + 1) * 500;
+ else if (wd_multiplier == 2)
+ mseconds = (wd_margin + 1) * 5000;
+ else if (wd_multiplier == 3)
+ mseconds = (wd_margin + 1) * 50000;
+ else if (wd_multiplier == 4)
+ mseconds = (wd_margin + 1) * 100000;
+
+ /* My kingdom for the ability to print "0.5 seconds" in the kernel! */
+ printk(KERN_INFO PFX "Timeout set at %ld ms.\n", mseconds);
+
+ return 0;
+
+ out_noreboot:
+ release_region(SBC8360_ENABLE, 1);
+ release_region(SBC8360_BASETIME, 1);
+ out_noenablereg:
+ out_nobasetimereg:
+ misc_deregister(&sbc8360_miscdev);
+ out_nomisc:
+ return res;
+}
+
+static void __exit sbc8360_exit(void)
+{
+ misc_deregister(&sbc8360_miscdev);
+ unregister_reboot_notifier(&sbc8360_notifier);
+ release_region(SBC8360_ENABLE, 1);
+ release_region(SBC8360_BASETIME, 1);
+}
+
+module_init(sbc8360_init);
+module_exit(sbc8360_exit);
+
+MODULE_AUTHOR("Ian E. Morgan <imorgan@webcon.ca>");
+MODULE_DESCRIPTION("SBC8360 watchdog driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1.0");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+
+/* end of sbc8360.c */
diff --git a/drivers/char/watchdog/scx200_wdt.c b/drivers/char/watchdog/scx200_wdt.c
index c456856..b4a102a 100644
--- a/drivers/char/watchdog/scx200_wdt.c
+++ b/drivers/char/watchdog/scx200_wdt.c
@@ -206,7 +206,7 @@ static struct file_operations scx200_wdt_fops = {
static struct miscdevice scx200_wdt_miscdev = {
.minor = WATCHDOG_MINOR,
- .name = NAME,
+ .name = "watchdog",
.fops = &scx200_wdt_fops,
};
diff --git a/drivers/char/watchdog/softdog.c b/drivers/char/watchdog/softdog.c
index 4d7ed93..20e5eb8 100644
--- a/drivers/char/watchdog/softdog.c
+++ b/drivers/char/watchdog/softdog.c
@@ -77,7 +77,7 @@ static void watchdog_fire(unsigned long);
static struct timer_list watchdog_ticktock =
TIMER_INITIALIZER(watchdog_fire, 0, 0);
-static unsigned long timer_alive;
+static unsigned long driver_open, orphan_timer;
static char expect_close;
@@ -87,6 +87,9 @@ static char expect_close;
static void watchdog_fire(unsigned long data)
{
+ if (test_and_clear_bit(0, &orphan_timer))
+ module_put(THIS_MODULE);
+
if (soft_noboot)
printk(KERN_CRIT PFX "Triggered - Reboot ignored.\n");
else
@@ -128,9 +131,9 @@ static int softdog_set_heartbeat(int t)
static int softdog_open(struct inode *inode, struct file *file)
{
- if(test_and_set_bit(0, &timer_alive))
+ if (test_and_set_bit(0, &driver_open))
return -EBUSY;
- if (nowayout)
+ if (!test_and_clear_bit(0, &orphan_timer))
__module_get(THIS_MODULE);
/*
* Activate timer
@@ -147,11 +150,13 @@ static int softdog_release(struct inode *inode, struct file *file)
*/
if (expect_close == 42) {
softdog_stop();
+ module_put(THIS_MODULE);
} else {
printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
+ set_bit(0, &orphan_timer);
softdog_keepalive();
}
- clear_bit(0, &timer_alive);
+ clear_bit(0, &driver_open);
expect_close = 0;
return 0;
}
diff --git a/drivers/char/watchdog/w83627hf_wdt.c b/drivers/char/watchdog/w83627hf_wdt.c
index 465e0fd..b5d8210 100644
--- a/drivers/char/watchdog/w83627hf_wdt.c
+++ b/drivers/char/watchdog/w83627hf_wdt.c
@@ -93,6 +93,12 @@ w83627hf_init(void)
w83627hf_select_wd_register();
+ outb_p(0xF6, WDT_EFER); /* Select CRF6 */
+ t=inb_p(WDT_EFDR); /* read CRF6 */
+ if (t != 0) {
+ printk (KERN_INFO PFX "Watchdog already running. Resetting timeout to %d sec\n", timeout);
+ outb_p(timeout, WDT_EFDR); /* Write back to CRF6 */
+ }
outb_p(0xF5, WDT_EFER); /* Select CRF5 */
t=inb_p(WDT_EFDR); /* read CRF5 */
t&=~0x0C; /* set second mode & disable keyboard turning off watchdog */
diff --git a/drivers/char/watchdog/w83977f_wdt.c b/drivers/char/watchdog/w83977f_wdt.c
new file mode 100644
index 0000000..a7ff64c
--- /dev/null
+++ b/drivers/char/watchdog/w83977f_wdt.c
@@ -0,0 +1,543 @@
+/*
+ * W83977F Watchdog Timer Driver for Winbond W83977F I/O Chip
+ *
+ * (c) Copyright 2005 Jose Goncalves <jose.goncalves@inov.pt>
+ *
+ * Based on w83877f_wdt.c by Scott Jennings,
+ * and wdt977.c by Woody Suwalski
+ *
+ * -----------------------
+ *
+ * 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/watchdog.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#define WATCHDOG_VERSION "1.00"
+#define WATCHDOG_NAME "W83977F WDT"
+#define PFX WATCHDOG_NAME ": "
+#define DRIVER_VERSION WATCHDOG_NAME " driver, v" WATCHDOG_VERSION "\n"
+
+#define IO_INDEX_PORT 0x3F0
+#define IO_DATA_PORT (IO_INDEX_PORT+1)
+
+#define UNLOCK_DATA 0x87
+#define LOCK_DATA 0xAA
+#define DEVICE_REGISTER 0x07
+
+#define DEFAULT_TIMEOUT 45 /* default timeout in seconds */
+
+static int timeout = DEFAULT_TIMEOUT;
+static int timeoutW; /* timeout in watchdog counter units */
+static unsigned long timer_alive;
+static int testmode;
+static char expect_close;
+static spinlock_t spinlock;
+
+module_param(timeout, int, 0);
+MODULE_PARM_DESC(timeout,"Watchdog timeout in seconds (15..7635), default=" __MODULE_STRING(DEFAULT_TIMEOUT) ")");
+module_param(testmode, int, 0);
+MODULE_PARM_DESC(testmode,"Watchdog testmode (1 = no reboot), default=0");
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
+/*
+ * Start the watchdog
+ */
+
+static int wdt_start(void)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&spinlock, flags);
+
+ /* Unlock the SuperIO chip */
+ outb_p(UNLOCK_DATA,IO_INDEX_PORT);
+ outb_p(UNLOCK_DATA,IO_INDEX_PORT);
+
+ /*
+ * Select device Aux2 (device=8) to set watchdog regs F2, F3 and F4.
+ * F2 has the timeout in watchdog counter units.
+ * F3 is set to enable watchdog LED blink at timeout.
+ * F4 is used to just clear the TIMEOUT'ed state (bit 0).
+ */
+ outb_p(DEVICE_REGISTER,IO_INDEX_PORT);
+ outb_p(0x08,IO_DATA_PORT);
+ outb_p(0xF2,IO_INDEX_PORT);
+ outb_p(timeoutW,IO_DATA_PORT);
+ outb_p(0xF3,IO_INDEX_PORT);
+ outb_p(0x08,IO_DATA_PORT);
+ outb_p(0xF4,IO_INDEX_PORT);
+ outb_p(0x00,IO_DATA_PORT);
+
+ /* Set device Aux2 active */
+ outb_p(0x30,IO_INDEX_PORT);
+ outb_p(0x01,IO_DATA_PORT);
+
+ /*
+ * Select device Aux1 (dev=7) to set GP16 as the watchdog output
+ * (in reg E6) and GP13 as the watchdog LED output (in reg E3).
+ * Map GP16 at pin 119.
+ * In test mode watch the bit 0 on F4 to indicate "triggered" or
+ * check watchdog LED on SBC.
+ */
+ outb_p(DEVICE_REGISTER,IO_INDEX_PORT);
+ outb_p(0x07,IO_DATA_PORT);
+ if (!testmode)
+ {
+ unsigned pin_map;
+
+ outb_p(0xE6,IO_INDEX_PORT);
+ outb_p(0x0A,IO_DATA_PORT);
+ outb_p(0x2C,IO_INDEX_PORT);
+ pin_map = inb_p(IO_DATA_PORT);
+ pin_map |= 0x10;
+ pin_map &= ~(0x20);
+ outb_p(0x2C,IO_INDEX_PORT);
+ outb_p(pin_map,IO_DATA_PORT);
+ }
+ outb_p(0xE3,IO_INDEX_PORT);
+ outb_p(0x08,IO_DATA_PORT);
+
+ /* Set device Aux1 active */
+ outb_p(0x30,IO_INDEX_PORT);
+ outb_p(0x01,IO_DATA_PORT);
+
+ /* Lock the SuperIO chip */
+ outb_p(LOCK_DATA,IO_INDEX_PORT);
+
+ spin_unlock_irqrestore(&spinlock, flags);
+
+ printk(KERN_INFO PFX "activated.\n");
+
+ return 0;
+}
+
+/*
+ * Stop the watchdog
+ */
+
+static int wdt_stop(void)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&spinlock, flags);
+
+ /* Unlock the SuperIO chip */
+ outb_p(UNLOCK_DATA,IO_INDEX_PORT);
+ outb_p(UNLOCK_DATA,IO_INDEX_PORT);
+
+ /*
+ * Select device Aux2 (device=8) to set watchdog regs F2, F3 and F4.
+ * F2 is reset to its default value (watchdog timer disabled).
+ * F3 is reset to its default state.
+ * F4 clears the TIMEOUT'ed state (bit 0) - back to default.
+ */
+ outb_p(DEVICE_REGISTER,IO_INDEX_PORT);
+ outb_p(0x08,IO_DATA_PORT);
+ outb_p(0xF2,IO_INDEX_PORT);
+ outb_p(0xFF,IO_DATA_PORT);
+ outb_p(0xF3,IO_INDEX_PORT);
+ outb_p(0x00,IO_DATA_PORT);
+ outb_p(0xF4,IO_INDEX_PORT);
+ outb_p(0x00,IO_DATA_PORT);
+ outb_p(0xF2,IO_INDEX_PORT);
+ outb_p(0x00,IO_DATA_PORT);
+
+ /*
+ * Select device Aux1 (dev=7) to set GP16 (in reg E6) and
+ * Gp13 (in reg E3) as inputs.
+ */
+ outb_p(DEVICE_REGISTER,IO_INDEX_PORT);
+ outb_p(0x07,IO_DATA_PORT);
+ if (!testmode)
+ {
+ outb_p(0xE6,IO_INDEX_PORT);
+ outb_p(0x01,IO_DATA_PORT);
+ }
+ outb_p(0xE3,IO_INDEX_PORT);
+ outb_p(0x01,IO_DATA_PORT);
+
+ /* Lock the SuperIO chip */
+ outb_p(LOCK_DATA,IO_INDEX_PORT);
+
+ spin_unlock_irqrestore(&spinlock, flags);
+
+ printk(KERN_INFO PFX "shutdown.\n");
+
+ return 0;
+}
+
+/*
+ * Send a keepalive ping to the watchdog
+ * This is done by simply re-writing the timeout to reg. 0xF2
+ */
+
+static int wdt_keepalive(void)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&spinlock, flags);
+
+ /* Unlock the SuperIO chip */
+ outb_p(UNLOCK_DATA,IO_INDEX_PORT);
+ outb_p(UNLOCK_DATA,IO_INDEX_PORT);
+
+ /* Select device Aux2 (device=8) to kick watchdog reg F2 */
+ outb_p(DEVICE_REGISTER,IO_INDEX_PORT);
+ outb_p(0x08,IO_DATA_PORT);
+ outb_p(0xF2,IO_INDEX_PORT);
+ outb_p(timeoutW,IO_DATA_PORT);
+
+ /* Lock the SuperIO chip */
+ outb_p(LOCK_DATA,IO_INDEX_PORT);
+
+ spin_unlock_irqrestore(&spinlock, flags);
+
+ return 0;
+}
+
+/*
+ * Set the watchdog timeout value
+ */
+
+static int wdt_set_timeout(int t)
+{
+ int tmrval;
+
+ /*
+ * Convert seconds to watchdog counter time units, rounding up.
+ * On PCM-5335 watchdog units are 30 seconds/step with 15 sec startup
+ * value. This information is supplied in the PCM-5335 manual and was
+ * checked by me on a real board. This is a bit strange because W83977f
+ * datasheet says counter unit is in minutes!
+ */
+ if (t < 15)
+ return -EINVAL;
+
+ tmrval = ((t + 15) + 29) / 30;
+
+ if (tmrval > 255)
+ return -EINVAL;
+
+ /*
+ * timeout is the timeout in seconds,
+ * timeoutW is the timeout in watchdog counter units.
+ */
+ timeoutW = tmrval;
+ timeout = (timeoutW * 30) - 15;
+ return 0;
+}
+
+/*
+ * Get the watchdog status
+ */
+
+static int wdt_get_status(int *status)
+{
+ int new_status;
+ unsigned long flags;
+
+ spin_lock_irqsave(&spinlock, flags);
+
+ /* Unlock the SuperIO chip */
+ outb_p(UNLOCK_DATA,IO_INDEX_PORT);
+ outb_p(UNLOCK_DATA,IO_INDEX_PORT);
+
+ /* Select device Aux2 (device=8) to read watchdog reg F4 */
+ outb_p(DEVICE_REGISTER,IO_INDEX_PORT);
+ outb_p(0x08,IO_DATA_PORT);
+ outb_p(0xF4,IO_INDEX_PORT);
+ new_status = inb_p(IO_DATA_PORT);
+
+ /* Lock the SuperIO chip */
+ outb_p(LOCK_DATA,IO_INDEX_PORT);
+
+ spin_unlock_irqrestore(&spinlock, flags);
+
+ *status = 0;
+ if (new_status & 1)
+ *status |= WDIOF_CARDRESET;
+
+ return 0;
+}
+
+
+/*
+ * /dev/watchdog handling
+ */
+
+static int wdt_open(struct inode *inode, struct file *file)
+{
+ /* If the watchdog is alive we don't need to start it again */
+ if( test_and_set_bit(0, &timer_alive) )
+ return -EBUSY;
+
+ if (nowayout)
+ __module_get(THIS_MODULE);
+
+ wdt_start();
+ return nonseekable_open(inode, file);
+}
+
+static int wdt_release(struct inode *inode, struct file *file)
+{
+ /*
+ * Shut off the timer.
+ * Lock it in if it's a module and we set nowayout
+ */
+ if (expect_close == 42)
+ {
+ wdt_stop();
+ clear_bit(0, &timer_alive);
+ } else {
+ wdt_keepalive();
+ printk(KERN_CRIT PFX "unexpected close, not stopping watchdog!\n");
+ }
+ expect_close = 0;
+ return 0;
+}
+
+/*
+ * wdt_write:
+ * @file: file handle to the watchdog
+ * @buf: buffer to write (unused as data does not matter here
+ * @count: count of bytes
+ * @ppos: pointer to the position to write. No seeks allowed
+ *
+ * A write to a watchdog device is defined as a keepalive signal. Any
+ * write of data will do, as we we don't define content meaning.
+ */
+
+static ssize_t wdt_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ /* See if we got the magic character 'V' and reload the timer */
+ if(count)
+ {
+ if (!nowayout)
+ {
+ size_t ofs;
+
+ /* note: just in case someone wrote the magic character long ago */
+ expect_close = 0;
+
+ /* scan to see whether or not we got the magic character */
+ for(ofs = 0; ofs != count; ofs++)
+ {
+ char c;
+ if (get_user(c, buf + ofs))
+ return -EFAULT;
+ if (c == 'V') {
+ expect_close = 42;
+ }
+ }
+ }
+
+ /* someone wrote to us, we should restart timer */
+ wdt_keepalive();
+ }
+ return count;
+}
+
+/*
+ * wdt_ioctl:
+ * @inode: inode of the device
+ * @file: file handle to the device
+ * @cmd: watchdog command
+ * @arg: argument pointer
+ *
+ * The watchdog API defines a common set of functions for all watchdogs
+ * according to their available features.
+ */
+
+static struct watchdog_info ident = {
+ .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,
+ .firmware_version = 1,
+ .identity = WATCHDOG_NAME,
+};
+
+static int wdt_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ int status;
+ int new_options, retval = -EINVAL;
+ int new_timeout;
+ union {
+ struct watchdog_info __user *ident;
+ int __user *i;
+ } uarg;
+
+ uarg.i = (int __user *)arg;
+
+ switch(cmd)
+ {
+ default:
+ return -ENOIOCTLCMD;
+
+ case WDIOC_GETSUPPORT:
+ return copy_to_user(uarg.ident, &ident, sizeof(ident)) ? -EFAULT : 0;
+
+ case WDIOC_GETSTATUS:
+ wdt_get_status(&status);
+ return put_user(status, uarg.i);
+
+ case WDIOC_GETBOOTSTATUS:
+ return put_user(0, uarg.i);
+
+ case WDIOC_KEEPALIVE:
+ wdt_keepalive();
+ return 0;
+
+ case WDIOC_SETOPTIONS:
+ if (get_user (new_options, uarg.i))
+ return -EFAULT;
+
+ if (new_options & WDIOS_DISABLECARD) {
+ wdt_stop();
+ retval = 0;
+ }
+
+ if (new_options & WDIOS_ENABLECARD) {
+ wdt_start();
+ retval = 0;
+ }
+
+ return retval;
+
+ case WDIOC_SETTIMEOUT:
+ if (get_user(new_timeout, uarg.i))
+ return -EFAULT;
+
+ if (wdt_set_timeout(new_timeout))
+ return -EINVAL;
+
+ wdt_keepalive();
+ /* Fall */
+
+ case WDIOC_GETTIMEOUT:
+ return put_user(timeout, uarg.i);
+
+ }
+}
+
+static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
+ void *unused)
+{
+ if (code==SYS_DOWN || code==SYS_HALT)
+ wdt_stop();
+ return NOTIFY_DONE;
+}
+
+static struct file_operations wdt_fops=
+{
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .write = wdt_write,
+ .ioctl = wdt_ioctl,
+ .open = wdt_open,
+ .release = wdt_release,
+};
+
+static struct miscdevice wdt_miscdev=
+{
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &wdt_fops,
+};
+
+static struct notifier_block wdt_notifier = {
+ .notifier_call = wdt_notify_sys,
+};
+
+static int __init w83977f_wdt_init(void)
+{
+ int rc;
+
+ printk(KERN_INFO PFX DRIVER_VERSION);
+
+ spin_lock_init(&spinlock);
+
+ /*
+ * Check that the timeout value is within it's range ;
+ * if not reset to the default
+ */
+ if (wdt_set_timeout(timeout)) {
+ wdt_set_timeout(DEFAULT_TIMEOUT);
+ printk(KERN_INFO PFX "timeout value must be 15<=timeout<=7635, using %d\n",
+ DEFAULT_TIMEOUT);
+ }
+
+ if (!request_region(IO_INDEX_PORT, 2, WATCHDOG_NAME))
+ {
+ printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
+ IO_INDEX_PORT);
+ rc = -EIO;
+ goto err_out;
+ }
+
+ rc = misc_register(&wdt_miscdev);
+ if (rc)
+ {
+ printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+ wdt_miscdev.minor, rc);
+ goto err_out_region;
+ }
+
+ rc = register_reboot_notifier(&wdt_notifier);
+ if (rc)
+ {
+ printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
+ rc);
+ goto err_out_miscdev;
+ }
+
+ printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d testmode=%d)\n",
+ timeout, nowayout, testmode);
+
+ return 0;
+
+err_out_miscdev:
+ misc_deregister(&wdt_miscdev);
+err_out_region:
+ release_region(IO_INDEX_PORT,2);
+err_out:
+ return rc;
+}
+
+static void __exit w83977f_wdt_exit(void)
+{
+ wdt_stop();
+ misc_deregister(&wdt_miscdev);
+ unregister_reboot_notifier(&wdt_notifier);
+ release_region(IO_INDEX_PORT,2);
+}
+
+module_init(w83977f_wdt_init);
+module_exit(w83977f_wdt_exit);
+
+MODULE_AUTHOR("Jose Goncalves <jose.goncalves@inov.pt>");
+MODULE_DESCRIPTION("Driver for watchdog timer in W83977F I/O chip");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);