diff options
author | Jeff Garzik <jgarzik@pobox.com> | 2005-10-06 05:51:07 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2005-10-06 05:51:07 -0400 |
commit | 012e060c95e547eceea4a12c6f58592473bf4011 (patch) | |
tree | b57d3eafb50ce517577d2cf366c9ef0b4b286589 /drivers/char | |
parent | 923f122573851d18a3832ca808269fa2d5046fb1 (diff) | |
parent | ed39f731ab2e77e58122232f6e27333331d7793d (diff) |
Merge branch 'master'
Diffstat (limited to 'drivers/char')
-rw-r--r-- | drivers/char/agp/hp-agp.c | 2 | ||||
-rw-r--r-- | drivers/char/amiserial.c | 4 | ||||
-rw-r--r-- | drivers/char/drm/drm_drv.c | 2 | ||||
-rw-r--r-- | drivers/char/drm/drm_proc.c | 2 | ||||
-rw-r--r-- | drivers/char/epca.c | 84 | ||||
-rw-r--r-- | drivers/char/epca.h | 12 | ||||
-rw-r--r-- | drivers/char/hpet.c | 1 | ||||
-rw-r--r-- | drivers/char/hvc_console.c | 6 | ||||
-rw-r--r-- | drivers/char/ipmi/ipmi_msghandler.c | 6 | ||||
-rw-r--r-- | drivers/char/ipmi/ipmi_poweroff.c | 2 | ||||
-rw-r--r-- | drivers/char/n_r3964.c | 84 | ||||
-rw-r--r-- | drivers/char/vt.c | 5 | ||||
-rw-r--r-- | drivers/char/watchdog/Kconfig | 93 | ||||
-rw-r--r-- | drivers/char/watchdog/Makefile | 7 | ||||
-rw-r--r-- | drivers/char/watchdog/i6300esb.c | 527 | ||||
-rw-r--r-- | drivers/char/watchdog/ibmasr.c | 405 | ||||
-rw-r--r-- | drivers/char/watchdog/mpcore_wdt.c | 2 | ||||
-rw-r--r-- | drivers/char/watchdog/mv64x60_wdt.c | 252 | ||||
-rw-r--r-- | drivers/char/watchdog/pcwd_pci.c | 44 | ||||
-rw-r--r-- | drivers/char/watchdog/s3c2410_wdt.c | 2 | ||||
-rw-r--r-- | drivers/char/watchdog/sbc8360.c | 414 | ||||
-rw-r--r-- | drivers/char/watchdog/w83977f_wdt.c | 543 |
22 files changed, 2351 insertions, 148 deletions
diff --git a/drivers/char/agp/hp-agp.c b/drivers/char/agp/hp-agp.c index 99762b6c19ae..de5d6d212674 100644 --- a/drivers/char/agp/hp-agp.c +++ b/drivers/char/agp/hp-agp.c | |||
@@ -252,7 +252,7 @@ hp_zx1_configure (void) | |||
252 | readl(hp->ioc_regs+HP_ZX1_PDIR_BASE); | 252 | readl(hp->ioc_regs+HP_ZX1_PDIR_BASE); |
253 | writel(hp->io_tlb_ps, hp->ioc_regs+HP_ZX1_TCNFG); | 253 | writel(hp->io_tlb_ps, hp->ioc_regs+HP_ZX1_TCNFG); |
254 | readl(hp->ioc_regs+HP_ZX1_TCNFG); | 254 | readl(hp->ioc_regs+HP_ZX1_TCNFG); |
255 | writel(~(HP_ZX1_IOVA_SIZE-1), hp->ioc_regs+HP_ZX1_IMASK); | 255 | writel((unsigned int)(~(HP_ZX1_IOVA_SIZE-1)), hp->ioc_regs+HP_ZX1_IMASK); |
256 | readl(hp->ioc_regs+HP_ZX1_IMASK); | 256 | readl(hp->ioc_regs+HP_ZX1_IMASK); |
257 | writel(hp->iova_base|1, hp->ioc_regs+HP_ZX1_IBASE); | 257 | writel(hp->iova_base|1, hp->ioc_regs+HP_ZX1_IBASE); |
258 | readl(hp->ioc_regs+HP_ZX1_IBASE); | 258 | readl(hp->ioc_regs+HP_ZX1_IBASE); |
diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c index 2a36561eec68..a124f8c5d062 100644 --- a/drivers/char/amiserial.c +++ b/drivers/char/amiserial.c | |||
@@ -2053,10 +2053,6 @@ static int __init rs_init(void) | |||
2053 | state->icount.rx = state->icount.tx = 0; | 2053 | state->icount.rx = state->icount.tx = 0; |
2054 | state->icount.frame = state->icount.parity = 0; | 2054 | state->icount.frame = state->icount.parity = 0; |
2055 | state->icount.overrun = state->icount.brk = 0; | 2055 | state->icount.overrun = state->icount.brk = 0; |
2056 | /* | ||
2057 | if(state->port && check_region(state->port,REGION_LENGTH(state))) | ||
2058 | continue; | ||
2059 | */ | ||
2060 | 2056 | ||
2061 | printk(KERN_INFO "ttyS%d is the amiga builtin serial port\n", | 2057 | printk(KERN_INFO "ttyS%d is the amiga builtin serial port\n", |
2062 | state->line); | 2058 | state->line); |
diff --git a/drivers/char/drm/drm_drv.c b/drivers/char/drm/drm_drv.c index 6ba48f346fcf..041bb47b5c39 100644 --- a/drivers/char/drm/drm_drv.c +++ b/drivers/char/drm/drm_drv.c | |||
@@ -376,7 +376,7 @@ static int __init drm_core_init(void) | |||
376 | goto err_p2; | 376 | goto err_p2; |
377 | } | 377 | } |
378 | 378 | ||
379 | drm_proc_root = create_proc_entry("dri", S_IFDIR, NULL); | 379 | drm_proc_root = proc_mkdir("dri", NULL); |
380 | if (!drm_proc_root) { | 380 | if (!drm_proc_root) { |
381 | DRM_ERROR("Cannot create /proc/dri\n"); | 381 | DRM_ERROR("Cannot create /proc/dri\n"); |
382 | ret = -1; | 382 | ret = -1; |
diff --git a/drivers/char/drm/drm_proc.c b/drivers/char/drm/drm_proc.c index 32d2bb99462c..977961002488 100644 --- a/drivers/char/drm/drm_proc.c +++ b/drivers/char/drm/drm_proc.c | |||
@@ -95,7 +95,7 @@ int drm_proc_init(drm_device_t *dev, int minor, | |||
95 | char name[64]; | 95 | char name[64]; |
96 | 96 | ||
97 | sprintf(name, "%d", minor); | 97 | sprintf(name, "%d", minor); |
98 | *dev_root = create_proc_entry(name, S_IFDIR, root); | 98 | *dev_root = proc_mkdir(name, root); |
99 | if (!*dev_root) { | 99 | if (!*dev_root) { |
100 | DRM_ERROR("Cannot create /proc/dri/%s\n", name); | 100 | DRM_ERROR("Cannot create /proc/dri/%s\n", name); |
101 | return -1; | 101 | return -1; |
diff --git a/drivers/char/epca.c b/drivers/char/epca.c index 58d3738a2b7f..407708a001e4 100644 --- a/drivers/char/epca.c +++ b/drivers/char/epca.c | |||
@@ -534,7 +534,7 @@ static void shutdown(struct channel *ch) | |||
534 | 534 | ||
535 | unsigned long flags; | 535 | unsigned long flags; |
536 | struct tty_struct *tty; | 536 | struct tty_struct *tty; |
537 | struct board_chan *bc; | 537 | struct board_chan __iomem *bc; |
538 | 538 | ||
539 | if (!(ch->asyncflags & ASYNC_INITIALIZED)) | 539 | if (!(ch->asyncflags & ASYNC_INITIALIZED)) |
540 | return; | 540 | return; |
@@ -618,7 +618,7 @@ static int pc_write(struct tty_struct * tty, | |||
618 | struct channel *ch; | 618 | struct channel *ch; |
619 | unsigned long flags; | 619 | unsigned long flags; |
620 | int remain; | 620 | int remain; |
621 | struct board_chan *bc; | 621 | struct board_chan __iomem *bc; |
622 | 622 | ||
623 | /* ---------------------------------------------------------------- | 623 | /* ---------------------------------------------------------------- |
624 | pc_write is primarily called directly by the kernel routine | 624 | pc_write is primarily called directly by the kernel routine |
@@ -685,7 +685,7 @@ static int pc_write(struct tty_struct * tty, | |||
685 | ------------------------------------------------------------------- */ | 685 | ------------------------------------------------------------------- */ |
686 | 686 | ||
687 | dataLen = min(bytesAvailable, dataLen); | 687 | dataLen = min(bytesAvailable, dataLen); |
688 | memcpy(ch->txptr + head, buf, dataLen); | 688 | memcpy_toio(ch->txptr + head, buf, dataLen); |
689 | buf += dataLen; | 689 | buf += dataLen; |
690 | head += dataLen; | 690 | head += dataLen; |
691 | amountCopied += dataLen; | 691 | amountCopied += dataLen; |
@@ -726,7 +726,7 @@ static int pc_write_room(struct tty_struct *tty) | |||
726 | struct channel *ch; | 726 | struct channel *ch; |
727 | unsigned long flags; | 727 | unsigned long flags; |
728 | unsigned int head, tail; | 728 | unsigned int head, tail; |
729 | struct board_chan *bc; | 729 | struct board_chan __iomem *bc; |
730 | 730 | ||
731 | remain = 0; | 731 | remain = 0; |
732 | 732 | ||
@@ -773,7 +773,7 @@ static int pc_chars_in_buffer(struct tty_struct *tty) | |||
773 | int remain; | 773 | int remain; |
774 | unsigned long flags; | 774 | unsigned long flags; |
775 | struct channel *ch; | 775 | struct channel *ch; |
776 | struct board_chan *bc; | 776 | struct board_chan __iomem *bc; |
777 | 777 | ||
778 | /* --------------------------------------------------------- | 778 | /* --------------------------------------------------------- |
779 | verifyChannel returns the channel from the tty struct | 779 | verifyChannel returns the channel from the tty struct |
@@ -830,7 +830,7 @@ static void pc_flush_buffer(struct tty_struct *tty) | |||
830 | unsigned int tail; | 830 | unsigned int tail; |
831 | unsigned long flags; | 831 | unsigned long flags; |
832 | struct channel *ch; | 832 | struct channel *ch; |
833 | struct board_chan *bc; | 833 | struct board_chan __iomem *bc; |
834 | /* --------------------------------------------------------- | 834 | /* --------------------------------------------------------- |
835 | verifyChannel returns the channel from the tty struct | 835 | verifyChannel returns the channel from the tty struct |
836 | if it is valid. This serves as a sanity check. | 836 | if it is valid. This serves as a sanity check. |
@@ -976,7 +976,7 @@ static int pc_open(struct tty_struct *tty, struct file * filp) | |||
976 | struct channel *ch; | 976 | struct channel *ch; |
977 | unsigned long flags; | 977 | unsigned long flags; |
978 | int line, retval, boardnum; | 978 | int line, retval, boardnum; |
979 | struct board_chan *bc; | 979 | struct board_chan __iomem *bc; |
980 | unsigned int head; | 980 | unsigned int head; |
981 | 981 | ||
982 | line = tty->index; | 982 | line = tty->index; |
@@ -1041,7 +1041,7 @@ static int pc_open(struct tty_struct *tty, struct file * filp) | |||
1041 | ch->statusflags = 0; | 1041 | ch->statusflags = 0; |
1042 | 1042 | ||
1043 | /* Save boards current modem status */ | 1043 | /* Save boards current modem status */ |
1044 | ch->imodem = bc->mstat; | 1044 | ch->imodem = readb(&bc->mstat); |
1045 | 1045 | ||
1046 | /* ---------------------------------------------------------------- | 1046 | /* ---------------------------------------------------------------- |
1047 | Set receive head and tail ptrs to each other. This indicates | 1047 | Set receive head and tail ptrs to each other. This indicates |
@@ -1399,10 +1399,10 @@ static void post_fep_init(unsigned int crd) | |||
1399 | { /* Begin post_fep_init */ | 1399 | { /* Begin post_fep_init */ |
1400 | 1400 | ||
1401 | int i; | 1401 | int i; |
1402 | unsigned char *memaddr; | 1402 | void __iomem *memaddr; |
1403 | struct global_data *gd; | 1403 | struct global_data __iomem *gd; |
1404 | struct board_info *bd; | 1404 | struct board_info *bd; |
1405 | struct board_chan *bc; | 1405 | struct board_chan __iomem *bc; |
1406 | struct channel *ch; | 1406 | struct channel *ch; |
1407 | int shrinkmem = 0, lowwater ; | 1407 | int shrinkmem = 0, lowwater ; |
1408 | 1408 | ||
@@ -1461,7 +1461,7 @@ static void post_fep_init(unsigned int crd) | |||
1461 | 8 and 64 of these structures. | 1461 | 8 and 64 of these structures. |
1462 | -------------------------------------------------------------------- */ | 1462 | -------------------------------------------------------------------- */ |
1463 | 1463 | ||
1464 | bc = (struct board_chan *)(memaddr + CHANSTRUCT); | 1464 | bc = memaddr + CHANSTRUCT; |
1465 | 1465 | ||
1466 | /* ------------------------------------------------------------------- | 1466 | /* ------------------------------------------------------------------- |
1467 | The below assignment will set gd to point at the BEGINING of | 1467 | The below assignment will set gd to point at the BEGINING of |
@@ -1470,7 +1470,7 @@ static void post_fep_init(unsigned int crd) | |||
1470 | pointer begins at 0xd10. | 1470 | pointer begins at 0xd10. |
1471 | ---------------------------------------------------------------------- */ | 1471 | ---------------------------------------------------------------------- */ |
1472 | 1472 | ||
1473 | gd = (struct global_data *)(memaddr + GLOBAL); | 1473 | gd = memaddr + GLOBAL; |
1474 | 1474 | ||
1475 | /* -------------------------------------------------------------------- | 1475 | /* -------------------------------------------------------------------- |
1476 | XEPORTS (address 0xc22) points at the number of channels the | 1476 | XEPORTS (address 0xc22) points at the number of channels the |
@@ -1493,6 +1493,7 @@ static void post_fep_init(unsigned int crd) | |||
1493 | 1493 | ||
1494 | for (i = 0; i < bd->numports; i++, ch++, bc++) { /* Begin for each port */ | 1494 | for (i = 0; i < bd->numports; i++, ch++, bc++) { /* Begin for each port */ |
1495 | unsigned long flags; | 1495 | unsigned long flags; |
1496 | u16 tseg, rseg; | ||
1496 | 1497 | ||
1497 | ch->brdchan = bc; | 1498 | ch->brdchan = bc; |
1498 | ch->mailbox = gd; | 1499 | ch->mailbox = gd; |
@@ -1553,50 +1554,53 @@ static void post_fep_init(unsigned int crd) | |||
1553 | shrinkmem = 0; | 1554 | shrinkmem = 0; |
1554 | } | 1555 | } |
1555 | 1556 | ||
1557 | tseg = readw(&bc->tseg); | ||
1558 | rseg = readw(&bc->rseg); | ||
1559 | |||
1556 | switch (bd->type) { | 1560 | switch (bd->type) { |
1557 | 1561 | ||
1558 | case PCIXEM: | 1562 | case PCIXEM: |
1559 | case PCIXRJ: | 1563 | case PCIXRJ: |
1560 | case PCIXR: | 1564 | case PCIXR: |
1561 | /* Cover all the 2MEG cards */ | 1565 | /* Cover all the 2MEG cards */ |
1562 | ch->txptr = memaddr + (((bc->tseg) << 4) & 0x1fffff); | 1566 | ch->txptr = memaddr + ((tseg << 4) & 0x1fffff); |
1563 | ch->rxptr = memaddr + (((bc->rseg) << 4) & 0x1fffff); | 1567 | ch->rxptr = memaddr + ((rseg << 4) & 0x1fffff); |
1564 | ch->txwin = FEPWIN | ((bc->tseg) >> 11); | 1568 | ch->txwin = FEPWIN | (tseg >> 11); |
1565 | ch->rxwin = FEPWIN | ((bc->rseg) >> 11); | 1569 | ch->rxwin = FEPWIN | (rseg >> 11); |
1566 | break; | 1570 | break; |
1567 | 1571 | ||
1568 | case PCXEM: | 1572 | case PCXEM: |
1569 | case EISAXEM: | 1573 | case EISAXEM: |
1570 | /* Cover all the 32K windowed cards */ | 1574 | /* Cover all the 32K windowed cards */ |
1571 | /* Mask equal to window size - 1 */ | 1575 | /* Mask equal to window size - 1 */ |
1572 | ch->txptr = memaddr + (((bc->tseg) << 4) & 0x7fff); | 1576 | ch->txptr = memaddr + ((tseg << 4) & 0x7fff); |
1573 | ch->rxptr = memaddr + (((bc->rseg) << 4) & 0x7fff); | 1577 | ch->rxptr = memaddr + ((rseg << 4) & 0x7fff); |
1574 | ch->txwin = FEPWIN | ((bc->tseg) >> 11); | 1578 | ch->txwin = FEPWIN | (tseg >> 11); |
1575 | ch->rxwin = FEPWIN | ((bc->rseg) >> 11); | 1579 | ch->rxwin = FEPWIN | (rseg >> 11); |
1576 | break; | 1580 | break; |
1577 | 1581 | ||
1578 | case PCXEVE: | 1582 | case PCXEVE: |
1579 | case PCXE: | 1583 | case PCXE: |
1580 | ch->txptr = memaddr + (((bc->tseg - bd->memory_seg) << 4) & 0x1fff); | 1584 | ch->txptr = memaddr + (((tseg - bd->memory_seg) << 4) & 0x1fff); |
1581 | ch->txwin = FEPWIN | ((bc->tseg - bd->memory_seg) >> 9); | 1585 | ch->txwin = FEPWIN | ((tseg - bd->memory_seg) >> 9); |
1582 | ch->rxptr = memaddr + (((bc->rseg - bd->memory_seg) << 4) & 0x1fff); | 1586 | ch->rxptr = memaddr + (((rseg - bd->memory_seg) << 4) & 0x1fff); |
1583 | ch->rxwin = FEPWIN | ((bc->rseg - bd->memory_seg) >>9 ); | 1587 | ch->rxwin = FEPWIN | ((rseg - bd->memory_seg) >>9 ); |
1584 | break; | 1588 | break; |
1585 | 1589 | ||
1586 | case PCXI: | 1590 | case PCXI: |
1587 | case PC64XE: | 1591 | case PC64XE: |
1588 | ch->txptr = memaddr + ((bc->tseg - bd->memory_seg) << 4); | 1592 | ch->txptr = memaddr + ((tseg - bd->memory_seg) << 4); |
1589 | ch->rxptr = memaddr + ((bc->rseg - bd->memory_seg) << 4); | 1593 | ch->rxptr = memaddr + ((rseg - bd->memory_seg) << 4); |
1590 | ch->txwin = ch->rxwin = 0; | 1594 | ch->txwin = ch->rxwin = 0; |
1591 | break; | 1595 | break; |
1592 | 1596 | ||
1593 | } /* End switch bd->type */ | 1597 | } /* End switch bd->type */ |
1594 | 1598 | ||
1595 | ch->txbufhead = 0; | 1599 | ch->txbufhead = 0; |
1596 | ch->txbufsize = bc->tmax + 1; | 1600 | ch->txbufsize = readw(&bc->tmax) + 1; |
1597 | 1601 | ||
1598 | ch->rxbufhead = 0; | 1602 | ch->rxbufhead = 0; |
1599 | ch->rxbufsize = bc->rmax + 1; | 1603 | ch->rxbufsize = readw(&bc->rmax) + 1; |
1600 | 1604 | ||
1601 | lowwater = ch->txbufsize >= 2000 ? 1024 : (ch->txbufsize / 2); | 1605 | lowwater = ch->txbufsize >= 2000 ? 1024 : (ch->txbufsize / 2); |
1602 | 1606 | ||
@@ -1718,11 +1722,11 @@ static void epcapoll(unsigned long ignored) | |||
1718 | static void doevent(int crd) | 1722 | static void doevent(int crd) |
1719 | { /* Begin doevent */ | 1723 | { /* Begin doevent */ |
1720 | 1724 | ||
1721 | void *eventbuf; | 1725 | void __iomem *eventbuf; |
1722 | struct channel *ch, *chan0; | 1726 | struct channel *ch, *chan0; |
1723 | static struct tty_struct *tty; | 1727 | static struct tty_struct *tty; |
1724 | struct board_info *bd; | 1728 | struct board_info *bd; |
1725 | struct board_chan *bc; | 1729 | struct board_chan __iomem *bc; |
1726 | unsigned int tail, head; | 1730 | unsigned int tail, head; |
1727 | int event, channel; | 1731 | int event, channel; |
1728 | int mstat, lstat; | 1732 | int mstat, lstat; |
@@ -1817,7 +1821,7 @@ static void doevent(int crd) | |||
1817 | static void fepcmd(struct channel *ch, int cmd, int word_or_byte, | 1821 | static void fepcmd(struct channel *ch, int cmd, int word_or_byte, |
1818 | int byte2, int ncmds, int bytecmd) | 1822 | int byte2, int ncmds, int bytecmd) |
1819 | { /* Begin fepcmd */ | 1823 | { /* Begin fepcmd */ |
1820 | unchar *memaddr; | 1824 | unchar __iomem *memaddr; |
1821 | unsigned int head, cmdTail, cmdStart, cmdMax; | 1825 | unsigned int head, cmdTail, cmdStart, cmdMax; |
1822 | long count; | 1826 | long count; |
1823 | int n; | 1827 | int n; |
@@ -2000,7 +2004,7 @@ static void epcaparam(struct tty_struct *tty, struct channel *ch) | |||
2000 | 2004 | ||
2001 | unsigned int cmdHead; | 2005 | unsigned int cmdHead; |
2002 | struct termios *ts; | 2006 | struct termios *ts; |
2003 | struct board_chan *bc; | 2007 | struct board_chan __iomem *bc; |
2004 | unsigned mval, hflow, cflag, iflag; | 2008 | unsigned mval, hflow, cflag, iflag; |
2005 | 2009 | ||
2006 | bc = ch->brdchan; | 2010 | bc = ch->brdchan; |
@@ -2010,7 +2014,7 @@ static void epcaparam(struct tty_struct *tty, struct channel *ch) | |||
2010 | ts = tty->termios; | 2014 | ts = tty->termios; |
2011 | if ((ts->c_cflag & CBAUD) == 0) { /* Begin CBAUD detected */ | 2015 | if ((ts->c_cflag & CBAUD) == 0) { /* Begin CBAUD detected */ |
2012 | cmdHead = readw(&bc->rin); | 2016 | cmdHead = readw(&bc->rin); |
2013 | bc->rout = cmdHead; | 2017 | writew(cmdHead, &bc->rout); |
2014 | cmdHead = readw(&bc->tin); | 2018 | cmdHead = readw(&bc->tin); |
2015 | /* Changing baud in mid-stream transmission can be wonderful */ | 2019 | /* Changing baud in mid-stream transmission can be wonderful */ |
2016 | /* --------------------------------------------------------------- | 2020 | /* --------------------------------------------------------------- |
@@ -2116,7 +2120,7 @@ static void receive_data(struct channel *ch) | |||
2116 | unchar *rptr; | 2120 | unchar *rptr; |
2117 | struct termios *ts = NULL; | 2121 | struct termios *ts = NULL; |
2118 | struct tty_struct *tty; | 2122 | struct tty_struct *tty; |
2119 | struct board_chan *bc; | 2123 | struct board_chan __iomem *bc; |
2120 | int dataToRead, wrapgap, bytesAvailable; | 2124 | int dataToRead, wrapgap, bytesAvailable; |
2121 | unsigned int tail, head; | 2125 | unsigned int tail, head; |
2122 | unsigned int wrapmask; | 2126 | unsigned int wrapmask; |
@@ -2154,7 +2158,7 @@ static void receive_data(struct channel *ch) | |||
2154 | --------------------------------------------------------------------- */ | 2158 | --------------------------------------------------------------------- */ |
2155 | 2159 | ||
2156 | if (!tty || !ts || !(ts->c_cflag & CREAD)) { | 2160 | if (!tty || !ts || !(ts->c_cflag & CREAD)) { |
2157 | bc->rout = head; | 2161 | writew(head, &bc->rout); |
2158 | return; | 2162 | return; |
2159 | } | 2163 | } |
2160 | 2164 | ||
@@ -2270,7 +2274,7 @@ static int info_ioctl(struct tty_struct *tty, struct file * file, | |||
2270 | static int pc_tiocmget(struct tty_struct *tty, struct file *file) | 2274 | static int pc_tiocmget(struct tty_struct *tty, struct file *file) |
2271 | { | 2275 | { |
2272 | struct channel *ch = (struct channel *) tty->driver_data; | 2276 | struct channel *ch = (struct channel *) tty->driver_data; |
2273 | struct board_chan *bc; | 2277 | struct board_chan __iomem *bc; |
2274 | unsigned int mstat, mflag = 0; | 2278 | unsigned int mstat, mflag = 0; |
2275 | unsigned long flags; | 2279 | unsigned long flags; |
2276 | 2280 | ||
@@ -2351,7 +2355,7 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file, | |||
2351 | unsigned long flags; | 2355 | unsigned long flags; |
2352 | unsigned int mflag, mstat; | 2356 | unsigned int mflag, mstat; |
2353 | unsigned char startc, stopc; | 2357 | unsigned char startc, stopc; |
2354 | struct board_chan *bc; | 2358 | struct board_chan __iomem *bc; |
2355 | struct channel *ch = (struct channel *) tty->driver_data; | 2359 | struct channel *ch = (struct channel *) tty->driver_data; |
2356 | void __user *argp = (void __user *)arg; | 2360 | void __user *argp = (void __user *)arg; |
2357 | 2361 | ||
@@ -2633,7 +2637,7 @@ static void pc_start(struct tty_struct *tty) | |||
2633 | spin_lock_irqsave(&epca_lock, flags); | 2637 | spin_lock_irqsave(&epca_lock, flags); |
2634 | /* Just in case output was resumed because of a change in Digi-flow */ | 2638 | /* Just in case output was resumed because of a change in Digi-flow */ |
2635 | if (ch->statusflags & TXSTOPPED) { /* Begin transmit resume requested */ | 2639 | if (ch->statusflags & TXSTOPPED) { /* Begin transmit resume requested */ |
2636 | struct board_chan *bc; | 2640 | struct board_chan __iomem *bc; |
2637 | globalwinon(ch); | 2641 | globalwinon(ch); |
2638 | bc = ch->brdchan; | 2642 | bc = ch->brdchan; |
2639 | if (ch->statusflags & LOWWAIT) | 2643 | if (ch->statusflags & LOWWAIT) |
@@ -2727,7 +2731,7 @@ void digi_send_break(struct channel *ch, int msec) | |||
2727 | static void setup_empty_event(struct tty_struct *tty, struct channel *ch) | 2731 | static void setup_empty_event(struct tty_struct *tty, struct channel *ch) |
2728 | { /* Begin setup_empty_event */ | 2732 | { /* Begin setup_empty_event */ |
2729 | 2733 | ||
2730 | struct board_chan *bc = ch->brdchan; | 2734 | struct board_chan __iomem *bc = ch->brdchan; |
2731 | 2735 | ||
2732 | globalwinon(ch); | 2736 | globalwinon(ch); |
2733 | ch->statusflags |= EMPTYWAIT; | 2737 | ch->statusflags |= EMPTYWAIT; |
diff --git a/drivers/char/epca.h b/drivers/char/epca.h index 20eeb5a70e1a..456d6c8f94a8 100644 --- a/drivers/char/epca.h +++ b/drivers/char/epca.h | |||
@@ -128,17 +128,17 @@ struct channel | |||
128 | unsigned long c_cflag; | 128 | unsigned long c_cflag; |
129 | unsigned long c_lflag; | 129 | unsigned long c_lflag; |
130 | unsigned long c_oflag; | 130 | unsigned long c_oflag; |
131 | unsigned char *txptr; | 131 | unsigned char __iomem *txptr; |
132 | unsigned char *rxptr; | 132 | unsigned char __iomem *rxptr; |
133 | unsigned char *tmp_buf; | 133 | unsigned char *tmp_buf; |
134 | struct board_info *board; | 134 | struct board_info *board; |
135 | struct board_chan *brdchan; | 135 | struct board_chan __iomem *brdchan; |
136 | struct digi_struct digiext; | 136 | struct digi_struct digiext; |
137 | struct tty_struct *tty; | 137 | struct tty_struct *tty; |
138 | wait_queue_head_t open_wait; | 138 | wait_queue_head_t open_wait; |
139 | wait_queue_head_t close_wait; | 139 | wait_queue_head_t close_wait; |
140 | struct work_struct tqueue; | 140 | struct work_struct tqueue; |
141 | struct global_data *mailbox; | 141 | struct global_data __iomem *mailbox; |
142 | }; | 142 | }; |
143 | 143 | ||
144 | struct board_info | 144 | struct board_info |
@@ -149,8 +149,8 @@ struct board_info | |||
149 | unsigned short numports; | 149 | unsigned short numports; |
150 | unsigned long port; | 150 | unsigned long port; |
151 | unsigned long membase; | 151 | unsigned long membase; |
152 | unsigned char __iomem *re_map_port; | 152 | void __iomem *re_map_port; |
153 | unsigned char *re_map_membase; | 153 | void __iomem *re_map_membase; |
154 | unsigned long memory_seg; | 154 | unsigned long memory_seg; |
155 | void ( * memwinon ) (struct board_info *, unsigned int) ; | 155 | void ( * memwinon ) (struct board_info *, unsigned int) ; |
156 | void ( * memwinoff ) (struct board_info *, unsigned int) ; | 156 | void ( * memwinoff ) (struct board_info *, unsigned int) ; |
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c index de0379b6d502..c055bb630ffc 100644 --- a/drivers/char/hpet.c +++ b/drivers/char/hpet.c | |||
@@ -273,7 +273,6 @@ static int hpet_mmap(struct file *file, struct vm_area_struct *vma) | |||
273 | 273 | ||
274 | vma->vm_flags |= VM_IO; | 274 | vma->vm_flags |= VM_IO; |
275 | vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); | 275 | vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); |
276 | addr = __pa(addr); | ||
277 | 276 | ||
278 | if (io_remap_pfn_range(vma, vma->vm_start, addr >> PAGE_SHIFT, | 277 | if (io_remap_pfn_range(vma, vma->vm_start, addr >> PAGE_SHIFT, |
279 | PAGE_SIZE, vma->vm_page_prot)) { | 278 | PAGE_SIZE, vma->vm_page_prot)) { |
diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c index cddb789902db..f92177634677 100644 --- a/drivers/char/hvc_console.c +++ b/drivers/char/hvc_console.c | |||
@@ -839,9 +839,6 @@ int __init hvc_init(void) | |||
839 | hvc_driver->flags = TTY_DRIVER_REAL_RAW; | 839 | hvc_driver->flags = TTY_DRIVER_REAL_RAW; |
840 | tty_set_operations(hvc_driver, &hvc_ops); | 840 | tty_set_operations(hvc_driver, &hvc_ops); |
841 | 841 | ||
842 | if (tty_register_driver(hvc_driver)) | ||
843 | panic("Couldn't register hvc console driver\n"); | ||
844 | |||
845 | /* Always start the kthread because there can be hotplug vty adapters | 842 | /* Always start the kthread because there can be hotplug vty adapters |
846 | * added later. */ | 843 | * added later. */ |
847 | hvc_task = kthread_run(khvcd, NULL, "khvcd"); | 844 | hvc_task = kthread_run(khvcd, NULL, "khvcd"); |
@@ -851,6 +848,9 @@ int __init hvc_init(void) | |||
851 | return -EIO; | 848 | return -EIO; |
852 | } | 849 | } |
853 | 850 | ||
851 | if (tty_register_driver(hvc_driver)) | ||
852 | panic("Couldn't register hvc console driver\n"); | ||
853 | |||
854 | return 0; | 854 | return 0; |
855 | } | 855 | } |
856 | module_init(hvc_init); | 856 | module_init(hvc_init); |
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 463351d4f942..32fa82c78c73 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c | |||
@@ -2620,7 +2620,7 @@ void ipmi_smi_msg_received(ipmi_smi_t intf, | |||
2620 | spin_lock_irqsave(&(intf->waiting_msgs_lock), flags); | 2620 | spin_lock_irqsave(&(intf->waiting_msgs_lock), flags); |
2621 | if (!list_empty(&(intf->waiting_msgs))) { | 2621 | if (!list_empty(&(intf->waiting_msgs))) { |
2622 | list_add_tail(&(msg->link), &(intf->waiting_msgs)); | 2622 | list_add_tail(&(msg->link), &(intf->waiting_msgs)); |
2623 | spin_unlock(&(intf->waiting_msgs_lock)); | 2623 | spin_unlock_irqrestore(&(intf->waiting_msgs_lock), flags); |
2624 | goto out_unlock; | 2624 | goto out_unlock; |
2625 | } | 2625 | } |
2626 | spin_unlock_irqrestore(&(intf->waiting_msgs_lock), flags); | 2626 | spin_unlock_irqrestore(&(intf->waiting_msgs_lock), flags); |
@@ -2629,9 +2629,9 @@ void ipmi_smi_msg_received(ipmi_smi_t intf, | |||
2629 | if (rv > 0) { | 2629 | if (rv > 0) { |
2630 | /* Could not handle the message now, just add it to a | 2630 | /* Could not handle the message now, just add it to a |
2631 | list to handle later. */ | 2631 | list to handle later. */ |
2632 | spin_lock(&(intf->waiting_msgs_lock)); | 2632 | spin_lock_irqsave(&(intf->waiting_msgs_lock), flags); |
2633 | list_add_tail(&(msg->link), &(intf->waiting_msgs)); | 2633 | list_add_tail(&(msg->link), &(intf->waiting_msgs)); |
2634 | spin_unlock(&(intf->waiting_msgs_lock)); | 2634 | spin_unlock_irqrestore(&(intf->waiting_msgs_lock), flags); |
2635 | } else if (rv == 0) { | 2635 | } else if (rv == 0) { |
2636 | ipmi_free_smi_msg(msg); | 2636 | ipmi_free_smi_msg(msg); |
2637 | } | 2637 | } |
diff --git a/drivers/char/ipmi/ipmi_poweroff.c b/drivers/char/ipmi/ipmi_poweroff.c index e82a96ba396b..f66947722e12 100644 --- a/drivers/char/ipmi/ipmi_poweroff.c +++ b/drivers/char/ipmi/ipmi_poweroff.c | |||
@@ -55,7 +55,7 @@ extern void (*pm_power_off)(void); | |||
55 | static int poweroff_powercycle; | 55 | static int poweroff_powercycle; |
56 | 56 | ||
57 | /* parameter definition to allow user to flag power cycle */ | 57 | /* parameter definition to allow user to flag power cycle */ |
58 | module_param(poweroff_powercycle, int, 0); | 58 | module_param(poweroff_powercycle, int, 0644); |
59 | 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."); | 59 | 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."); |
60 | 60 | ||
61 | /* Stuff from the get device id command. */ | 61 | /* Stuff from the get device id command. */ |
diff --git a/drivers/char/n_r3964.c b/drivers/char/n_r3964.c index 2291a87e8ada..97d6dc24b800 100644 --- a/drivers/char/n_r3964.c +++ b/drivers/char/n_r3964.c | |||
@@ -229,8 +229,8 @@ static int __init r3964_init(void) | |||
229 | TRACE_L("line discipline %d registered", N_R3964); | 229 | TRACE_L("line discipline %d registered", N_R3964); |
230 | TRACE_L("flags=%x num=%x", tty_ldisc_N_R3964.flags, | 230 | TRACE_L("flags=%x num=%x", tty_ldisc_N_R3964.flags, |
231 | tty_ldisc_N_R3964.num); | 231 | tty_ldisc_N_R3964.num); |
232 | TRACE_L("open=%x", (int)tty_ldisc_N_R3964.open); | 232 | TRACE_L("open=%p", tty_ldisc_N_R3964.open); |
233 | TRACE_L("tty_ldisc_N_R3964 = %x", (int)&tty_ldisc_N_R3964); | 233 | TRACE_L("tty_ldisc_N_R3964 = %p", &tty_ldisc_N_R3964); |
234 | } | 234 | } |
235 | else | 235 | else |
236 | { | 236 | { |
@@ -267,8 +267,8 @@ static void add_tx_queue(struct r3964_info *pInfo, struct r3964_block_header *pH | |||
267 | 267 | ||
268 | spin_unlock_irqrestore(&pInfo->lock, flags); | 268 | spin_unlock_irqrestore(&pInfo->lock, flags); |
269 | 269 | ||
270 | TRACE_Q("add_tx_queue %x, length %d, tx_first = %x", | 270 | TRACE_Q("add_tx_queue %p, length %d, tx_first = %p", |
271 | (int)pHeader, pHeader->length, (int)pInfo->tx_first ); | 271 | pHeader, pHeader->length, pInfo->tx_first ); |
272 | } | 272 | } |
273 | 273 | ||
274 | static void remove_from_tx_queue(struct r3964_info *pInfo, int error_code) | 274 | static void remove_from_tx_queue(struct r3964_info *pInfo, int error_code) |
@@ -285,10 +285,10 @@ static void remove_from_tx_queue(struct r3964_info *pInfo, int error_code) | |||
285 | return; | 285 | return; |
286 | 286 | ||
287 | #ifdef DEBUG_QUEUE | 287 | #ifdef DEBUG_QUEUE |
288 | printk("r3964: remove_from_tx_queue: %x, length %d - ", | 288 | printk("r3964: remove_from_tx_queue: %p, length %u - ", |
289 | (int)pHeader, (int)pHeader->length ); | 289 | pHeader, pHeader->length ); |
290 | for(pDump=pHeader;pDump;pDump=pDump->next) | 290 | for(pDump=pHeader;pDump;pDump=pDump->next) |
291 | printk("%x ", (int)pDump); | 291 | printk("%p ", pDump); |
292 | printk("\n"); | 292 | printk("\n"); |
293 | #endif | 293 | #endif |
294 | 294 | ||
@@ -319,10 +319,10 @@ static void remove_from_tx_queue(struct r3964_info *pInfo, int error_code) | |||
319 | spin_unlock_irqrestore(&pInfo->lock, flags); | 319 | spin_unlock_irqrestore(&pInfo->lock, flags); |
320 | 320 | ||
321 | kfree(pHeader); | 321 | kfree(pHeader); |
322 | TRACE_M("remove_from_tx_queue - kfree %x",(int)pHeader); | 322 | TRACE_M("remove_from_tx_queue - kfree %p",pHeader); |
323 | 323 | ||
324 | TRACE_Q("remove_from_tx_queue: tx_first = %x, tx_last = %x", | 324 | TRACE_Q("remove_from_tx_queue: tx_first = %p, tx_last = %p", |
325 | (int)pInfo->tx_first, (int)pInfo->tx_last ); | 325 | pInfo->tx_first, pInfo->tx_last ); |
326 | } | 326 | } |
327 | 327 | ||
328 | static void add_rx_queue(struct r3964_info *pInfo, struct r3964_block_header *pHeader) | 328 | static void add_rx_queue(struct r3964_info *pInfo, struct r3964_block_header *pHeader) |
@@ -346,9 +346,9 @@ static void add_rx_queue(struct r3964_info *pInfo, struct r3964_block_header *pH | |||
346 | 346 | ||
347 | spin_unlock_irqrestore(&pInfo->lock, flags); | 347 | spin_unlock_irqrestore(&pInfo->lock, flags); |
348 | 348 | ||
349 | TRACE_Q("add_rx_queue: %x, length = %d, rx_first = %x, count = %d", | 349 | TRACE_Q("add_rx_queue: %p, length = %d, rx_first = %p, count = %d", |
350 | (int)pHeader, pHeader->length, | 350 | pHeader, pHeader->length, |
351 | (int)pInfo->rx_first, pInfo->blocks_in_rx_queue); | 351 | pInfo->rx_first, pInfo->blocks_in_rx_queue); |
352 | } | 352 | } |
353 | 353 | ||
354 | static void remove_from_rx_queue(struct r3964_info *pInfo, | 354 | static void remove_from_rx_queue(struct r3964_info *pInfo, |
@@ -360,10 +360,10 @@ static void remove_from_rx_queue(struct r3964_info *pInfo, | |||
360 | if(pHeader==NULL) | 360 | if(pHeader==NULL) |
361 | return; | 361 | return; |
362 | 362 | ||
363 | TRACE_Q("remove_from_rx_queue: rx_first = %x, rx_last = %x, count = %d", | 363 | TRACE_Q("remove_from_rx_queue: rx_first = %p, rx_last = %p, count = %d", |
364 | (int)pInfo->rx_first, (int)pInfo->rx_last, pInfo->blocks_in_rx_queue ); | 364 | pInfo->rx_first, pInfo->rx_last, pInfo->blocks_in_rx_queue ); |
365 | TRACE_Q("remove_from_rx_queue: %x, length %d", | 365 | TRACE_Q("remove_from_rx_queue: %p, length %u", |
366 | (int)pHeader, (int)pHeader->length ); | 366 | pHeader, pHeader->length ); |
367 | 367 | ||
368 | spin_lock_irqsave(&pInfo->lock, flags); | 368 | spin_lock_irqsave(&pInfo->lock, flags); |
369 | 369 | ||
@@ -401,10 +401,10 @@ static void remove_from_rx_queue(struct r3964_info *pInfo, | |||
401 | spin_unlock_irqrestore(&pInfo->lock, flags); | 401 | spin_unlock_irqrestore(&pInfo->lock, flags); |
402 | 402 | ||
403 | kfree(pHeader); | 403 | kfree(pHeader); |
404 | TRACE_M("remove_from_rx_queue - kfree %x",(int)pHeader); | 404 | TRACE_M("remove_from_rx_queue - kfree %p",pHeader); |
405 | 405 | ||
406 | TRACE_Q("remove_from_rx_queue: rx_first = %x, rx_last = %x, count = %d", | 406 | TRACE_Q("remove_from_rx_queue: rx_first = %p, rx_last = %p, count = %d", |
407 | (int)pInfo->rx_first, (int)pInfo->rx_last, pInfo->blocks_in_rx_queue ); | 407 | pInfo->rx_first, pInfo->rx_last, pInfo->blocks_in_rx_queue ); |
408 | } | 408 | } |
409 | 409 | ||
410 | static void put_char(struct r3964_info *pInfo, unsigned char ch) | 410 | static void put_char(struct r3964_info *pInfo, unsigned char ch) |
@@ -506,8 +506,8 @@ static void transmit_block(struct r3964_info *pInfo) | |||
506 | if(tty->driver->write_room) | 506 | if(tty->driver->write_room) |
507 | room=tty->driver->write_room(tty); | 507 | room=tty->driver->write_room(tty); |
508 | 508 | ||
509 | TRACE_PS("transmit_block %x, room %d, length %d", | 509 | TRACE_PS("transmit_block %p, room %d, length %d", |
510 | (int)pBlock, room, pBlock->length); | 510 | pBlock, room, pBlock->length); |
511 | 511 | ||
512 | while(pInfo->tx_position < pBlock->length) | 512 | while(pInfo->tx_position < pBlock->length) |
513 | { | 513 | { |
@@ -588,7 +588,7 @@ static void on_receive_block(struct r3964_info *pInfo) | |||
588 | 588 | ||
589 | /* prepare struct r3964_block_header: */ | 589 | /* prepare struct r3964_block_header: */ |
590 | pBlock = kmalloc(length+sizeof(struct r3964_block_header), GFP_KERNEL); | 590 | pBlock = kmalloc(length+sizeof(struct r3964_block_header), GFP_KERNEL); |
591 | TRACE_M("on_receive_block - kmalloc %x",(int)pBlock); | 591 | TRACE_M("on_receive_block - kmalloc %p",pBlock); |
592 | 592 | ||
593 | if(pBlock==NULL) | 593 | if(pBlock==NULL) |
594 | return; | 594 | return; |
@@ -868,11 +868,11 @@ static int enable_signals(struct r3964_info *pInfo, pid_t pid, int arg) | |||
868 | if(pMsg) | 868 | if(pMsg) |
869 | { | 869 | { |
870 | kfree(pMsg); | 870 | kfree(pMsg); |
871 | TRACE_M("enable_signals - msg kfree %x",(int)pMsg); | 871 | TRACE_M("enable_signals - msg kfree %p",pMsg); |
872 | } | 872 | } |
873 | } | 873 | } |
874 | kfree(pClient); | 874 | kfree(pClient); |
875 | TRACE_M("enable_signals - kfree %x",(int)pClient); | 875 | TRACE_M("enable_signals - kfree %p",pClient); |
876 | return 0; | 876 | return 0; |
877 | } | 877 | } |
878 | } | 878 | } |
@@ -890,7 +890,7 @@ static int enable_signals(struct r3964_info *pInfo, pid_t pid, int arg) | |||
890 | { | 890 | { |
891 | /* add client to client list */ | 891 | /* add client to client list */ |
892 | pClient=kmalloc(sizeof(struct r3964_client_info), GFP_KERNEL); | 892 | pClient=kmalloc(sizeof(struct r3964_client_info), GFP_KERNEL); |
893 | TRACE_M("enable_signals - kmalloc %x",(int)pClient); | 893 | TRACE_M("enable_signals - kmalloc %p",pClient); |
894 | if(pClient==NULL) | 894 | if(pClient==NULL) |
895 | return -ENOMEM; | 895 | return -ENOMEM; |
896 | 896 | ||
@@ -954,7 +954,7 @@ static void add_msg(struct r3964_client_info *pClient, int msg_id, int arg, | |||
954 | queue_the_message: | 954 | queue_the_message: |
955 | 955 | ||
956 | pMsg = kmalloc(sizeof(struct r3964_message), GFP_KERNEL); | 956 | pMsg = kmalloc(sizeof(struct r3964_message), GFP_KERNEL); |
957 | TRACE_M("add_msg - kmalloc %x",(int)pMsg); | 957 | TRACE_M("add_msg - kmalloc %p",pMsg); |
958 | if(pMsg==NULL) { | 958 | if(pMsg==NULL) { |
959 | return; | 959 | return; |
960 | } | 960 | } |
@@ -1067,11 +1067,11 @@ static int r3964_open(struct tty_struct *tty) | |||
1067 | struct r3964_info *pInfo; | 1067 | struct r3964_info *pInfo; |
1068 | 1068 | ||
1069 | TRACE_L("open"); | 1069 | TRACE_L("open"); |
1070 | TRACE_L("tty=%x, PID=%d, disc_data=%x", | 1070 | TRACE_L("tty=%p, PID=%d, disc_data=%p", |
1071 | (int)tty, current->pid, (int)tty->disc_data); | 1071 | tty, current->pid, tty->disc_data); |
1072 | 1072 | ||
1073 | pInfo=kmalloc(sizeof(struct r3964_info), GFP_KERNEL); | 1073 | pInfo=kmalloc(sizeof(struct r3964_info), GFP_KERNEL); |
1074 | TRACE_M("r3964_open - info kmalloc %x",(int)pInfo); | 1074 | TRACE_M("r3964_open - info kmalloc %p",pInfo); |
1075 | 1075 | ||
1076 | if(!pInfo) | 1076 | if(!pInfo) |
1077 | { | 1077 | { |
@@ -1080,26 +1080,26 @@ static int r3964_open(struct tty_struct *tty) | |||
1080 | } | 1080 | } |
1081 | 1081 | ||
1082 | pInfo->rx_buf = kmalloc(RX_BUF_SIZE, GFP_KERNEL); | 1082 | pInfo->rx_buf = kmalloc(RX_BUF_SIZE, GFP_KERNEL); |
1083 | TRACE_M("r3964_open - rx_buf kmalloc %x",(int)pInfo->rx_buf); | 1083 | TRACE_M("r3964_open - rx_buf kmalloc %p",pInfo->rx_buf); |
1084 | 1084 | ||
1085 | if(!pInfo->rx_buf) | 1085 | if(!pInfo->rx_buf) |
1086 | { | 1086 | { |
1087 | printk(KERN_ERR "r3964: failed to alloc receive buffer\n"); | 1087 | printk(KERN_ERR "r3964: failed to alloc receive buffer\n"); |
1088 | kfree(pInfo); | 1088 | kfree(pInfo); |
1089 | TRACE_M("r3964_open - info kfree %x",(int)pInfo); | 1089 | TRACE_M("r3964_open - info kfree %p",pInfo); |
1090 | return -ENOMEM; | 1090 | return -ENOMEM; |
1091 | } | 1091 | } |
1092 | 1092 | ||
1093 | pInfo->tx_buf = kmalloc(TX_BUF_SIZE, GFP_KERNEL); | 1093 | pInfo->tx_buf = kmalloc(TX_BUF_SIZE, GFP_KERNEL); |
1094 | TRACE_M("r3964_open - tx_buf kmalloc %x",(int)pInfo->tx_buf); | 1094 | TRACE_M("r3964_open - tx_buf kmalloc %p",pInfo->tx_buf); |
1095 | 1095 | ||
1096 | if(!pInfo->tx_buf) | 1096 | if(!pInfo->tx_buf) |
1097 | { | 1097 | { |
1098 | printk(KERN_ERR "r3964: failed to alloc transmit buffer\n"); | 1098 | printk(KERN_ERR "r3964: failed to alloc transmit buffer\n"); |
1099 | kfree(pInfo->rx_buf); | 1099 | kfree(pInfo->rx_buf); |
1100 | TRACE_M("r3964_open - rx_buf kfree %x",(int)pInfo->rx_buf); | 1100 | TRACE_M("r3964_open - rx_buf kfree %p",pInfo->rx_buf); |
1101 | kfree(pInfo); | 1101 | kfree(pInfo); |
1102 | TRACE_M("r3964_open - info kfree %x",(int)pInfo); | 1102 | TRACE_M("r3964_open - info kfree %p",pInfo); |
1103 | return -ENOMEM; | 1103 | return -ENOMEM; |
1104 | } | 1104 | } |
1105 | 1105 | ||
@@ -1154,11 +1154,11 @@ static void r3964_close(struct tty_struct *tty) | |||
1154 | if(pMsg) | 1154 | if(pMsg) |
1155 | { | 1155 | { |
1156 | kfree(pMsg); | 1156 | kfree(pMsg); |
1157 | TRACE_M("r3964_close - msg kfree %x",(int)pMsg); | 1157 | TRACE_M("r3964_close - msg kfree %p",pMsg); |
1158 | } | 1158 | } |
1159 | } | 1159 | } |
1160 | kfree(pClient); | 1160 | kfree(pClient); |
1161 | TRACE_M("r3964_close - client kfree %x",(int)pClient); | 1161 | TRACE_M("r3964_close - client kfree %p",pClient); |
1162 | pClient=pNext; | 1162 | pClient=pNext; |
1163 | } | 1163 | } |
1164 | /* Remove jobs from tx_queue: */ | 1164 | /* Remove jobs from tx_queue: */ |
@@ -1177,11 +1177,11 @@ static void r3964_close(struct tty_struct *tty) | |||
1177 | /* Free buffers: */ | 1177 | /* Free buffers: */ |
1178 | wake_up_interruptible(&pInfo->read_wait); | 1178 | wake_up_interruptible(&pInfo->read_wait); |
1179 | kfree(pInfo->rx_buf); | 1179 | kfree(pInfo->rx_buf); |
1180 | TRACE_M("r3964_close - rx_buf kfree %x",(int)pInfo->rx_buf); | 1180 | TRACE_M("r3964_close - rx_buf kfree %p",pInfo->rx_buf); |
1181 | kfree(pInfo->tx_buf); | 1181 | kfree(pInfo->tx_buf); |
1182 | TRACE_M("r3964_close - tx_buf kfree %x",(int)pInfo->tx_buf); | 1182 | TRACE_M("r3964_close - tx_buf kfree %p",pInfo->tx_buf); |
1183 | kfree(pInfo); | 1183 | kfree(pInfo); |
1184 | TRACE_M("r3964_close - info kfree %x",(int)pInfo); | 1184 | TRACE_M("r3964_close - info kfree %p",pInfo); |
1185 | } | 1185 | } |
1186 | 1186 | ||
1187 | static ssize_t r3964_read(struct tty_struct *tty, struct file *file, | 1187 | static ssize_t r3964_read(struct tty_struct *tty, struct file *file, |
@@ -1234,7 +1234,7 @@ repeat: | |||
1234 | count = sizeof(struct r3964_client_message); | 1234 | count = sizeof(struct r3964_client_message); |
1235 | 1235 | ||
1236 | kfree(pMsg); | 1236 | kfree(pMsg); |
1237 | TRACE_M("r3964_read - msg kfree %x",(int)pMsg); | 1237 | TRACE_M("r3964_read - msg kfree %p",pMsg); |
1238 | 1238 | ||
1239 | if (copy_to_user(buf,&theMsg, count)) | 1239 | if (copy_to_user(buf,&theMsg, count)) |
1240 | return -EFAULT; | 1240 | return -EFAULT; |
@@ -1279,7 +1279,7 @@ static ssize_t r3964_write(struct tty_struct * tty, struct file * file, | |||
1279 | * Allocate a buffer for the data and copy it from the buffer with header prepended | 1279 | * Allocate a buffer for the data and copy it from the buffer with header prepended |
1280 | */ | 1280 | */ |
1281 | new_data = kmalloc (count+sizeof(struct r3964_block_header), GFP_KERNEL); | 1281 | new_data = kmalloc (count+sizeof(struct r3964_block_header), GFP_KERNEL); |
1282 | TRACE_M("r3964_write - kmalloc %x",(int)new_data); | 1282 | TRACE_M("r3964_write - kmalloc %p",new_data); |
1283 | if (new_data == NULL) { | 1283 | if (new_data == NULL) { |
1284 | if (pInfo->flags & R3964_DEBUG) | 1284 | if (pInfo->flags & R3964_DEBUG) |
1285 | { | 1285 | { |
diff --git a/drivers/char/vt.c b/drivers/char/vt.c index 1e33cb032e07..e91268e86833 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c | |||
@@ -810,13 +810,14 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines) | |||
810 | * from the top and bottom of cursor position | 810 | * from the top and bottom of cursor position |
811 | */ | 811 | */ |
812 | old_origin += (vc->vc_y - new_rows/2) * old_row_size; | 812 | old_origin += (vc->vc_y - new_rows/2) * old_row_size; |
813 | end = old_origin + new_screen_size; | 813 | end = old_origin + (old_row_size * new_rows); |
814 | } | 814 | } |
815 | } else | 815 | } else |
816 | /* | 816 | /* |
817 | * Cursor near the top, copy contents from the top of buffer | 817 | * Cursor near the top, copy contents from the top of buffer |
818 | */ | 818 | */ |
819 | end = (old_rows > new_rows) ? old_origin + new_screen_size : | 819 | end = (old_rows > new_rows) ? old_origin + |
820 | (old_row_size * new_rows) : | ||
820 | vc->vc_scr_end; | 821 | vc->vc_scr_end; |
821 | 822 | ||
822 | update_attr(vc); | 823 | update_attr(vc); |
diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig index fa789ea36bbe..344001b45af9 100644 --- a/drivers/char/watchdog/Kconfig +++ b/drivers/char/watchdog/Kconfig | |||
@@ -84,6 +84,17 @@ config 977_WATCHDOG | |||
84 | 84 | ||
85 | Not sure? It's safe to say N. | 85 | Not sure? It's safe to say N. |
86 | 86 | ||
87 | config IXP2000_WATCHDOG | ||
88 | tristate "IXP2000 Watchdog" | ||
89 | depends on WATCHDOG && ARCH_IXP2000 | ||
90 | help | ||
91 | Say Y here if to include support for the watchdog timer | ||
92 | in the Intel IXP2000(2400, 2800, 2850) network processors. | ||
93 | This driver can be built as a module by choosing M. The module | ||
94 | will be called ixp2000_wdt. | ||
95 | |||
96 | Say N if you are unsure. | ||
97 | |||
87 | config IXP4XX_WATCHDOG | 98 | config IXP4XX_WATCHDOG |
88 | tristate "IXP4xx Watchdog" | 99 | tristate "IXP4xx Watchdog" |
89 | depends on WATCHDOG && ARCH_IXP4XX | 100 | depends on WATCHDOG && ARCH_IXP4XX |
@@ -100,17 +111,6 @@ config IXP4XX_WATCHDOG | |||
100 | 111 | ||
101 | Say N if you are unsure. | 112 | Say N if you are unsure. |
102 | 113 | ||
103 | config IXP2000_WATCHDOG | ||
104 | tristate "IXP2000 Watchdog" | ||
105 | depends on WATCHDOG && ARCH_IXP2000 | ||
106 | help | ||
107 | Say Y here if to include support for the watchdog timer | ||
108 | in the Intel IXP2000(2400, 2800, 2850) network processors. | ||
109 | This driver can be built as a module by choosing M. The module | ||
110 | will be called ixp2000_wdt. | ||
111 | |||
112 | Say N if you are unsure. | ||
113 | |||
114 | config S3C2410_WATCHDOG | 114 | config S3C2410_WATCHDOG |
115 | tristate "S3C2410 Watchdog" | 115 | tristate "S3C2410 Watchdog" |
116 | depends on WATCHDOG && ARCH_S3C2410 | 116 | depends on WATCHDOG && ARCH_S3C2410 |
@@ -233,6 +233,16 @@ config IB700_WDT | |||
233 | 233 | ||
234 | Most people will say N. | 234 | Most people will say N. |
235 | 235 | ||
236 | config IBMASR | ||
237 | tristate "IBM Automatic Server Restart" | ||
238 | depends on WATCHDOG && X86 | ||
239 | help | ||
240 | This is the driver for the IBM Automatic Server Restart watchdog | ||
241 | timer builtin into some eServer xSeries machines. | ||
242 | |||
243 | To compile this driver as a module, choose M here: the | ||
244 | module will be called ibmasr. | ||
245 | |||
236 | config WAFER_WDT | 246 | config WAFER_WDT |
237 | tristate "ICP Wafer 5823 Single Board Computer Watchdog" | 247 | tristate "ICP Wafer 5823 Single Board Computer Watchdog" |
238 | depends on WATCHDOG && X86 | 248 | depends on WATCHDOG && X86 |
@@ -243,6 +253,16 @@ config WAFER_WDT | |||
243 | To compile this driver as a module, choose M here: the | 253 | To compile this driver as a module, choose M here: the |
244 | module will be called wafer5823wdt. | 254 | module will be called wafer5823wdt. |
245 | 255 | ||
256 | config I6300ESB_WDT | ||
257 | tristate "Intel 6300ESB Timer/Watchdog" | ||
258 | depends on WATCHDOG && X86 && PCI | ||
259 | ---help--- | ||
260 | Hardware driver for the watchdog timer built into the Intel | ||
261 | 6300ESB controller hub. | ||
262 | |||
263 | To compile this driver as a module, choose M here: the | ||
264 | module will be called i6300esb. | ||
265 | |||
246 | config I8XX_TCO | 266 | config I8XX_TCO |
247 | tristate "Intel i8xx TCO Timer/Watchdog" | 267 | tristate "Intel i8xx TCO Timer/Watchdog" |
248 | depends on WATCHDOG && (X86 || IA64) && PCI | 268 | depends on WATCHDOG && (X86 || IA64) && PCI |
@@ -298,6 +318,19 @@ config 60XX_WDT | |||
298 | You can compile this driver directly into the kernel, or use | 318 | You can compile this driver directly into the kernel, or use |
299 | it as a module. The module will be called sbc60xxwdt. | 319 | it as a module. The module will be called sbc60xxwdt. |
300 | 320 | ||
321 | config SBC8360_WDT | ||
322 | tristate "SBC8360 Watchdog Timer" | ||
323 | depends on WATCHDOG && X86 | ||
324 | ---help--- | ||
325 | |||
326 | This is the driver for the hardware watchdog on the SBC8360 Single | ||
327 | Board Computer produced by Axiomtek Co., Ltd. (www.axiomtek.com). | ||
328 | |||
329 | To compile this driver as a module, choose M here: the | ||
330 | module will be called sbc8360.ko. | ||
331 | |||
332 | Most people will say N. | ||
333 | |||
301 | config CPU5_WDT | 334 | config CPU5_WDT |
302 | tristate "SMA CPU5 Watchdog" | 335 | tristate "SMA CPU5 Watchdog" |
303 | depends on WATCHDOG && X86 | 336 | depends on WATCHDOG && X86 |
@@ -336,6 +369,19 @@ config W83877F_WDT | |||
336 | 369 | ||
337 | Most people will say N. | 370 | Most people will say N. |
338 | 371 | ||
372 | config W83977F_WDT | ||
373 | tristate "W83977F (PCM-5335) Watchdog Timer" | ||
374 | depends on WATCHDOG && X86 | ||
375 | ---help--- | ||
376 | This is the driver for the hardware watchdog on the W83977F I/O chip | ||
377 | as used in AAEON's PCM-5335 SBC (and likely others). This | ||
378 | watchdog simply watches your kernel to make sure it doesn't freeze, | ||
379 | and if it does, it reboots your computer after a certain amount of | ||
380 | time. | ||
381 | |||
382 | To compile this driver as a module, choose M here: the | ||
383 | module will be called w83977f_wdt. | ||
384 | |||
339 | config MACHZ_WDT | 385 | config MACHZ_WDT |
340 | tristate "ZF MachZ Watchdog" | 386 | tristate "ZF MachZ Watchdog" |
341 | depends on WATCHDOG && X86 | 387 | depends on WATCHDOG && X86 |
@@ -355,6 +401,10 @@ config 8xx_WDT | |||
355 | tristate "MPC8xx Watchdog Timer" | 401 | tristate "MPC8xx Watchdog Timer" |
356 | depends on WATCHDOG && 8xx | 402 | depends on WATCHDOG && 8xx |
357 | 403 | ||
404 | config MV64X60_WDT | ||
405 | tristate "MV64X60 (Marvell Discovery) Watchdog Timer" | ||
406 | depends on WATCHDOG && MV64X60 | ||
407 | |||
358 | config BOOKE_WDT | 408 | config BOOKE_WDT |
359 | tristate "PowerPC Book-E Watchdog Timer" | 409 | tristate "PowerPC Book-E Watchdog Timer" |
360 | depends on WATCHDOG && (BOOKE || 4xx) | 410 | depends on WATCHDOG && (BOOKE || 4xx) |
@@ -362,6 +412,17 @@ config BOOKE_WDT | |||
362 | Please see Documentation/watchdog/watchdog-api.txt for | 412 | Please see Documentation/watchdog/watchdog-api.txt for |
363 | more information. | 413 | more information. |
364 | 414 | ||
415 | # PPC64 Architecture | ||
416 | |||
417 | config WATCHDOG_RTAS | ||
418 | tristate "RTAS watchdog" | ||
419 | depends on WATCHDOG && PPC_RTAS | ||
420 | help | ||
421 | This driver adds watchdog support for the RTAS watchdog. | ||
422 | |||
423 | To compile this driver as a module, choose M here. The module | ||
424 | will be called wdrtas. | ||
425 | |||
365 | # MIPS Architecture | 426 | # MIPS Architecture |
366 | 427 | ||
367 | config INDYDOG | 428 | config INDYDOG |
@@ -430,16 +491,6 @@ config WATCHDOG_RIO | |||
430 | machines. The watchdog timeout period is normally one minute but | 491 | machines. The watchdog timeout period is normally one minute but |
431 | can be changed with a boot-time parameter. | 492 | can be changed with a boot-time parameter. |
432 | 493 | ||
433 | # ppc64 RTAS watchdog | ||
434 | config WATCHDOG_RTAS | ||
435 | tristate "RTAS watchdog" | ||
436 | depends on WATCHDOG && PPC_RTAS | ||
437 | help | ||
438 | This driver adds watchdog support for the RTAS watchdog. | ||
439 | |||
440 | To compile this driver as a module, choose M here. The module | ||
441 | will be called wdrtas. | ||
442 | |||
443 | # | 494 | # |
444 | # ISA-based Watchdog Cards | 495 | # ISA-based Watchdog Cards |
445 | # | 496 | # |
diff --git a/drivers/char/watchdog/Makefile b/drivers/char/watchdog/Makefile index bc6f5fe88c8c..cfd0a3987710 100644 --- a/drivers/char/watchdog/Makefile +++ b/drivers/char/watchdog/Makefile | |||
@@ -39,22 +39,27 @@ obj-$(CONFIG_ALIM7101_WDT) += alim7101_wdt.o | |||
39 | obj-$(CONFIG_SC520_WDT) += sc520_wdt.o | 39 | obj-$(CONFIG_SC520_WDT) += sc520_wdt.o |
40 | obj-$(CONFIG_EUROTECH_WDT) += eurotechwdt.o | 40 | obj-$(CONFIG_EUROTECH_WDT) += eurotechwdt.o |
41 | obj-$(CONFIG_IB700_WDT) += ib700wdt.o | 41 | obj-$(CONFIG_IB700_WDT) += ib700wdt.o |
42 | obj-$(CONFIG_IBMASR) += ibmasr.o | ||
42 | obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o | 43 | obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o |
44 | obj-$(CONFIG_I6300ESB_WDT) += i6300esb.o | ||
43 | obj-$(CONFIG_I8XX_TCO) += i8xx_tco.o | 45 | obj-$(CONFIG_I8XX_TCO) += i8xx_tco.o |
44 | obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o | 46 | obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o |
45 | obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o | 47 | obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o |
46 | obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o | 48 | obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o |
49 | obj-$(CONFIG_SBC8360_WDT) += sbc8360.o | ||
47 | obj-$(CONFIG_CPU5_WDT) += cpu5wdt.o | 50 | obj-$(CONFIG_CPU5_WDT) += cpu5wdt.o |
48 | obj-$(CONFIG_W83627HF_WDT) += w83627hf_wdt.o | 51 | obj-$(CONFIG_W83627HF_WDT) += w83627hf_wdt.o |
49 | obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o | 52 | obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o |
53 | obj-$(CONFIG_W83977F_WDT) += w83977f_wdt.o | ||
50 | obj-$(CONFIG_MACHZ_WDT) += machzwd.o | 54 | obj-$(CONFIG_MACHZ_WDT) += machzwd.o |
51 | 55 | ||
52 | # PowerPC Architecture | 56 | # PowerPC Architecture |
53 | obj-$(CONFIG_8xx_WDT) += mpc8xx_wdt.o | 57 | obj-$(CONFIG_8xx_WDT) += mpc8xx_wdt.o |
58 | obj-$(CONFIG_MV64X60_WDT) += mv64x60_wdt.o | ||
59 | obj-$(CONFIG_BOOKE_WDT) += booke_wdt.o | ||
54 | 60 | ||
55 | # PPC64 Architecture | 61 | # PPC64 Architecture |
56 | obj-$(CONFIG_WATCHDOG_RTAS) += wdrtas.o | 62 | obj-$(CONFIG_WATCHDOG_RTAS) += wdrtas.o |
57 | obj-$(CONFIG_BOOKE_WDT) += booke_wdt.o | ||
58 | 63 | ||
59 | # MIPS Architecture | 64 | # MIPS Architecture |
60 | obj-$(CONFIG_INDYDOG) += indydog.o | 65 | obj-$(CONFIG_INDYDOG) += indydog.o |
diff --git a/drivers/char/watchdog/i6300esb.c b/drivers/char/watchdog/i6300esb.c new file mode 100644 index 000000000000..93785f13242e --- /dev/null +++ b/drivers/char/watchdog/i6300esb.c | |||
@@ -0,0 +1,527 @@ | |||
1 | /* | ||
2 | * i6300esb: Watchdog timer driver for Intel 6300ESB chipset | ||
3 | * | ||
4 | * (c) Copyright 2004 Google Inc. | ||
5 | * (c) Copyright 2005 David Härdeman <david@2gen.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * as published by the Free Software Foundation; either version | ||
10 | * 2 of the License, or (at your option) any later version. | ||
11 | * | ||
12 | * based on i810-tco.c which is in turn based on softdog.c | ||
13 | * | ||
14 | * The timer is implemented in the following I/O controller hubs: | ||
15 | * (See the intel documentation on http://developer.intel.com.) | ||
16 | * 6300ESB chip : document number 300641-003 | ||
17 | * | ||
18 | * 2004YYZZ Ross Biro | ||
19 | * Initial version 0.01 | ||
20 | * 2004YYZZ Ross Biro | ||
21 | * Version 0.02 | ||
22 | * 20050210 David Härdeman <david@2gen.com> | ||
23 | * Ported driver to kernel 2.6 | ||
24 | */ | ||
25 | |||
26 | /* | ||
27 | * Includes, defines, variables, module parameters, ... | ||
28 | */ | ||
29 | |||
30 | #include <linux/module.h> | ||
31 | #include <linux/types.h> | ||
32 | #include <linux/kernel.h> | ||
33 | #include <linux/fs.h> | ||
34 | #include <linux/mm.h> | ||
35 | #include <linux/miscdevice.h> | ||
36 | #include <linux/watchdog.h> | ||
37 | #include <linux/reboot.h> | ||
38 | #include <linux/init.h> | ||
39 | #include <linux/pci.h> | ||
40 | #include <linux/ioport.h> | ||
41 | |||
42 | #include <asm/uaccess.h> | ||
43 | #include <asm/io.h> | ||
44 | |||
45 | /* Module and version information */ | ||
46 | #define ESB_VERSION "0.03" | ||
47 | #define ESB_MODULE_NAME "i6300ESB timer" | ||
48 | #define ESB_DRIVER_NAME ESB_MODULE_NAME ", v" ESB_VERSION | ||
49 | #define PFX ESB_MODULE_NAME ": " | ||
50 | |||
51 | /* PCI configuration registers */ | ||
52 | #define ESB_CONFIG_REG 0x60 /* Config register */ | ||
53 | #define ESB_LOCK_REG 0x68 /* WDT lock register */ | ||
54 | |||
55 | /* Memory mapped registers */ | ||
56 | #define ESB_TIMER1_REG BASEADDR + 0x00 /* Timer1 value after each reset */ | ||
57 | #define ESB_TIMER2_REG BASEADDR + 0x04 /* Timer2 value after each reset */ | ||
58 | #define ESB_GINTSR_REG BASEADDR + 0x08 /* General Interrupt Status Register */ | ||
59 | #define ESB_RELOAD_REG BASEADDR + 0x0c /* Reload register */ | ||
60 | |||
61 | /* Lock register bits */ | ||
62 | #define ESB_WDT_FUNC ( 0x01 << 2 ) /* Watchdog functionality */ | ||
63 | #define ESB_WDT_ENABLE ( 0x01 << 1 ) /* Enable WDT */ | ||
64 | #define ESB_WDT_LOCK ( 0x01 << 0 ) /* Lock (nowayout) */ | ||
65 | |||
66 | /* Config register bits */ | ||
67 | #define ESB_WDT_REBOOT ( 0x01 << 5 ) /* Enable reboot on timeout */ | ||
68 | #define ESB_WDT_FREQ ( 0x01 << 2 ) /* Decrement frequency */ | ||
69 | #define ESB_WDT_INTTYPE ( 0x11 << 0 ) /* Interrupt type on timer1 timeout */ | ||
70 | |||
71 | /* Reload register bits */ | ||
72 | #define ESB_WDT_RELOAD ( 0x01 << 8 ) /* prevent timeout */ | ||
73 | |||
74 | /* Magic constants */ | ||
75 | #define ESB_UNLOCK1 0x80 /* Step 1 to unlock reset registers */ | ||
76 | #define ESB_UNLOCK2 0x86 /* Step 2 to unlock reset registers */ | ||
77 | |||
78 | /* internal variables */ | ||
79 | static void __iomem *BASEADDR; | ||
80 | static spinlock_t esb_lock; /* Guards the hardware */ | ||
81 | static unsigned long timer_alive; | ||
82 | static struct pci_dev *esb_pci; | ||
83 | static unsigned short triggered; /* The status of the watchdog upon boot */ | ||
84 | static char esb_expect_close; | ||
85 | |||
86 | /* module parameters */ | ||
87 | #define WATCHDOG_HEARTBEAT 30 /* 30 sec default heartbeat (1<heartbeat<2*1023) */ | ||
88 | static int heartbeat = WATCHDOG_HEARTBEAT; /* in seconds */ | ||
89 | module_param(heartbeat, int, 0); | ||
90 | MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (1<heartbeat<2046, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")"); | ||
91 | |||
92 | static int nowayout = WATCHDOG_NOWAYOUT; | ||
93 | module_param(nowayout, int, 0); | ||
94 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); | ||
95 | |||
96 | /* | ||
97 | * Some i6300ESB specific functions | ||
98 | */ | ||
99 | |||
100 | /* | ||
101 | * Prepare for reloading the timer by unlocking the proper registers. | ||
102 | * This is performed by first writing 0x80 followed by 0x86 to the | ||
103 | * reload register. After this the appropriate registers can be written | ||
104 | * to once before they need to be unlocked again. | ||
105 | */ | ||
106 | static inline void esb_unlock_registers(void) { | ||
107 | writeb(ESB_UNLOCK1, ESB_RELOAD_REG); | ||
108 | writeb(ESB_UNLOCK2, ESB_RELOAD_REG); | ||
109 | } | ||
110 | |||
111 | static void esb_timer_start(void) | ||
112 | { | ||
113 | u8 val; | ||
114 | |||
115 | /* Enable or Enable + Lock? */ | ||
116 | val = 0x02 | (nowayout ? 0x01 : 0x00); | ||
117 | |||
118 | pci_write_config_byte(esb_pci, ESB_LOCK_REG, val); | ||
119 | } | ||
120 | |||
121 | static int esb_timer_stop(void) | ||
122 | { | ||
123 | u8 val; | ||
124 | |||
125 | spin_lock(&esb_lock); | ||
126 | /* First, reset timers as suggested by the docs */ | ||
127 | esb_unlock_registers(); | ||
128 | writew(ESB_WDT_RELOAD, ESB_RELOAD_REG); | ||
129 | /* Then disable the WDT */ | ||
130 | pci_write_config_byte(esb_pci, ESB_LOCK_REG, 0x0); | ||
131 | pci_read_config_byte(esb_pci, ESB_LOCK_REG, &val); | ||
132 | spin_unlock(&esb_lock); | ||
133 | |||
134 | /* Returns 0 if the timer was disabled, non-zero otherwise */ | ||
135 | return (val & 0x01); | ||
136 | } | ||
137 | |||
138 | static void esb_timer_keepalive(void) | ||
139 | { | ||
140 | spin_lock(&esb_lock); | ||
141 | esb_unlock_registers(); | ||
142 | writew(ESB_WDT_RELOAD, ESB_RELOAD_REG); | ||
143 | /* FIXME: Do we need to flush anything here? */ | ||
144 | spin_unlock(&esb_lock); | ||
145 | } | ||
146 | |||
147 | static int esb_timer_set_heartbeat(int time) | ||
148 | { | ||
149 | u32 val; | ||
150 | |||
151 | if (time < 0x1 || time > (2 * 0x03ff)) | ||
152 | return -EINVAL; | ||
153 | |||
154 | spin_lock(&esb_lock); | ||
155 | |||
156 | /* We shift by 9, so if we are passed a value of 1 sec, | ||
157 | * val will be 1 << 9 = 512, then write that to two | ||
158 | * timers => 2 * 512 = 1024 (which is decremented at 1KHz) | ||
159 | */ | ||
160 | val = time << 9; | ||
161 | |||
162 | /* Write timer 1 */ | ||
163 | esb_unlock_registers(); | ||
164 | writel(val, ESB_TIMER1_REG); | ||
165 | |||
166 | /* Write timer 2 */ | ||
167 | esb_unlock_registers(); | ||
168 | writel(val, ESB_TIMER2_REG); | ||
169 | |||
170 | /* Reload */ | ||
171 | esb_unlock_registers(); | ||
172 | writew(ESB_WDT_RELOAD, ESB_RELOAD_REG); | ||
173 | |||
174 | /* FIXME: Do we need to flush everything out? */ | ||
175 | |||
176 | /* Done */ | ||
177 | heartbeat = time; | ||
178 | spin_unlock(&esb_lock); | ||
179 | return 0; | ||
180 | } | ||
181 | |||
182 | static int esb_timer_read (void) | ||
183 | { | ||
184 | u32 count; | ||
185 | |||
186 | /* This isn't documented, and doesn't take into | ||
187 | * acount which stage is running, but it looks | ||
188 | * like a 20 bit count down, so we might as well report it. | ||
189 | */ | ||
190 | pci_read_config_dword(esb_pci, 0x64, &count); | ||
191 | return (int)count; | ||
192 | } | ||
193 | |||
194 | /* | ||
195 | * /dev/watchdog handling | ||
196 | */ | ||
197 | |||
198 | static int esb_open (struct inode *inode, struct file *file) | ||
199 | { | ||
200 | /* /dev/watchdog can only be opened once */ | ||
201 | if (test_and_set_bit(0, &timer_alive)) | ||
202 | return -EBUSY; | ||
203 | |||
204 | /* Reload and activate timer */ | ||
205 | esb_timer_keepalive (); | ||
206 | esb_timer_start (); | ||
207 | |||
208 | return nonseekable_open(inode, file); | ||
209 | } | ||
210 | |||
211 | static int esb_release (struct inode *inode, struct file *file) | ||
212 | { | ||
213 | /* Shut off the timer. */ | ||
214 | if (esb_expect_close == 42) { | ||
215 | esb_timer_stop (); | ||
216 | } else { | ||
217 | printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); | ||
218 | esb_timer_keepalive (); | ||
219 | } | ||
220 | clear_bit(0, &timer_alive); | ||
221 | esb_expect_close = 0; | ||
222 | return 0; | ||
223 | } | ||
224 | |||
225 | static ssize_t esb_write (struct file *file, const char __user *data, | ||
226 | size_t len, loff_t * ppos) | ||
227 | { | ||
228 | /* See if we got the magic character 'V' and reload the timer */ | ||
229 | if (len) { | ||
230 | if (!nowayout) { | ||
231 | size_t i; | ||
232 | |||
233 | /* note: just in case someone wrote the magic character | ||
234 | * five months ago... */ | ||
235 | esb_expect_close = 0; | ||
236 | |||
237 | /* scan to see whether or not we got the magic character */ | ||
238 | for (i = 0; i != len; i++) { | ||
239 | char c; | ||
240 | if(get_user(c, data+i)) | ||
241 | return -EFAULT; | ||
242 | if (c == 'V') | ||
243 | esb_expect_close = 42; | ||
244 | } | ||
245 | } | ||
246 | |||
247 | /* someone wrote to us, we should reload the timer */ | ||
248 | esb_timer_keepalive (); | ||
249 | } | ||
250 | return len; | ||
251 | } | ||
252 | |||
253 | static int esb_ioctl (struct inode *inode, struct file *file, | ||
254 | unsigned int cmd, unsigned long arg) | ||
255 | { | ||
256 | int new_options, retval = -EINVAL; | ||
257 | int new_heartbeat; | ||
258 | void __user *argp = (void __user *)arg; | ||
259 | int __user *p = argp; | ||
260 | static struct watchdog_info ident = { | ||
261 | .options = WDIOF_SETTIMEOUT | | ||
262 | WDIOF_KEEPALIVEPING | | ||
263 | WDIOF_MAGICCLOSE, | ||
264 | .firmware_version = 0, | ||
265 | .identity = ESB_MODULE_NAME, | ||
266 | }; | ||
267 | |||
268 | switch (cmd) { | ||
269 | case WDIOC_GETSUPPORT: | ||
270 | return copy_to_user(argp, &ident, | ||
271 | sizeof (ident)) ? -EFAULT : 0; | ||
272 | |||
273 | case WDIOC_GETSTATUS: | ||
274 | return put_user (esb_timer_read(), p); | ||
275 | |||
276 | case WDIOC_GETBOOTSTATUS: | ||
277 | return put_user (triggered, p); | ||
278 | |||
279 | case WDIOC_KEEPALIVE: | ||
280 | esb_timer_keepalive (); | ||
281 | return 0; | ||
282 | |||
283 | case WDIOC_SETOPTIONS: | ||
284 | { | ||
285 | if (get_user (new_options, p)) | ||
286 | return -EFAULT; | ||
287 | |||
288 | if (new_options & WDIOS_DISABLECARD) { | ||
289 | esb_timer_stop (); | ||
290 | retval = 0; | ||
291 | } | ||
292 | |||
293 | if (new_options & WDIOS_ENABLECARD) { | ||
294 | esb_timer_keepalive (); | ||
295 | esb_timer_start (); | ||
296 | retval = 0; | ||
297 | } | ||
298 | |||
299 | return retval; | ||
300 | } | ||
301 | |||
302 | case WDIOC_SETTIMEOUT: | ||
303 | { | ||
304 | if (get_user(new_heartbeat, p)) | ||
305 | return -EFAULT; | ||
306 | |||
307 | if (esb_timer_set_heartbeat(new_heartbeat)) | ||
308 | return -EINVAL; | ||
309 | |||
310 | esb_timer_keepalive (); | ||
311 | /* Fall */ | ||
312 | } | ||
313 | |||
314 | case WDIOC_GETTIMEOUT: | ||
315 | return put_user(heartbeat, p); | ||
316 | |||
317 | default: | ||
318 | return -ENOIOCTLCMD; | ||
319 | } | ||
320 | } | ||
321 | |||
322 | /* | ||
323 | * Notify system | ||
324 | */ | ||
325 | |||
326 | static int esb_notify_sys (struct notifier_block *this, unsigned long code, void *unused) | ||
327 | { | ||
328 | if (code==SYS_DOWN || code==SYS_HALT) { | ||
329 | /* Turn the WDT off */ | ||
330 | esb_timer_stop (); | ||
331 | } | ||
332 | |||
333 | return NOTIFY_DONE; | ||
334 | } | ||
335 | |||
336 | /* | ||
337 | * Kernel Interfaces | ||
338 | */ | ||
339 | |||
340 | static struct file_operations esb_fops = { | ||
341 | .owner = THIS_MODULE, | ||
342 | .llseek = no_llseek, | ||
343 | .write = esb_write, | ||
344 | .ioctl = esb_ioctl, | ||
345 | .open = esb_open, | ||
346 | .release = esb_release, | ||
347 | }; | ||
348 | |||
349 | static struct miscdevice esb_miscdev = { | ||
350 | .minor = WATCHDOG_MINOR, | ||
351 | .name = "watchdog", | ||
352 | .fops = &esb_fops, | ||
353 | }; | ||
354 | |||
355 | static struct notifier_block esb_notifier = { | ||
356 | .notifier_call = esb_notify_sys, | ||
357 | }; | ||
358 | |||
359 | /* | ||
360 | * Data for PCI driver interface | ||
361 | * | ||
362 | * This data only exists for exporting the supported | ||
363 | * PCI ids via MODULE_DEVICE_TABLE. We do not actually | ||
364 | * register a pci_driver, because someone else might one day | ||
365 | * want to register another driver on the same PCI id. | ||
366 | */ | ||
367 | static struct pci_device_id esb_pci_tbl[] = { | ||
368 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_9), }, | ||
369 | { 0, }, /* End of list */ | ||
370 | }; | ||
371 | MODULE_DEVICE_TABLE (pci, esb_pci_tbl); | ||
372 | |||
373 | /* | ||
374 | * Init & exit routines | ||
375 | */ | ||
376 | |||
377 | static unsigned char __init esb_getdevice (void) | ||
378 | { | ||
379 | u8 val1; | ||
380 | unsigned short val2; | ||
381 | |||
382 | struct pci_dev *dev = NULL; | ||
383 | /* | ||
384 | * Find the PCI device | ||
385 | */ | ||
386 | |||
387 | for_each_pci_dev(dev) { | ||
388 | if (pci_match_id(esb_pci_tbl, dev)) { | ||
389 | esb_pci = dev; | ||
390 | break; | ||
391 | } | ||
392 | } | ||
393 | |||
394 | if (esb_pci) { | ||
395 | if (pci_enable_device(esb_pci)) { | ||
396 | printk (KERN_ERR PFX "failed to enable device\n"); | ||
397 | goto err_devput; | ||
398 | } | ||
399 | |||
400 | if (pci_request_region(esb_pci, 0, ESB_MODULE_NAME)) { | ||
401 | printk (KERN_ERR PFX "failed to request region\n"); | ||
402 | goto err_disable; | ||
403 | } | ||
404 | |||
405 | BASEADDR = ioremap(pci_resource_start(esb_pci, 0), | ||
406 | pci_resource_len(esb_pci, 0)); | ||
407 | if (BASEADDR == NULL) { | ||
408 | /* Something's wrong here, BASEADDR has to be set */ | ||
409 | printk (KERN_ERR PFX "failed to get BASEADDR\n"); | ||
410 | goto err_release; | ||
411 | } | ||
412 | |||
413 | /* | ||
414 | * The watchdog has two timers, it can be setup so that the | ||
415 | * expiry of timer1 results in an interrupt and the expiry of | ||
416 | * timer2 results in a reboot. We set it to not generate | ||
417 | * any interrupts as there is not much we can do with it | ||
418 | * right now. | ||
419 | * | ||
420 | * We also enable reboots and set the timer frequency to | ||
421 | * the PCI clock divided by 2^15 (approx 1KHz). | ||
422 | */ | ||
423 | pci_write_config_word(esb_pci, ESB_CONFIG_REG, 0x0003); | ||
424 | |||
425 | /* Check that the WDT isn't already locked */ | ||
426 | pci_read_config_byte(esb_pci, ESB_LOCK_REG, &val1); | ||
427 | if (val1 & ESB_WDT_LOCK) | ||
428 | printk (KERN_WARNING PFX "nowayout already set\n"); | ||
429 | |||
430 | /* Set the timer to watchdog mode and disable it for now */ | ||
431 | pci_write_config_byte(esb_pci, ESB_LOCK_REG, 0x00); | ||
432 | |||
433 | /* Check if the watchdog was previously triggered */ | ||
434 | esb_unlock_registers(); | ||
435 | val2 = readw(ESB_RELOAD_REG); | ||
436 | triggered = (val2 & (0x01 << 9) >> 9); | ||
437 | |||
438 | /* Reset trigger flag and timers */ | ||
439 | esb_unlock_registers(); | ||
440 | writew((0x11 << 8), ESB_RELOAD_REG); | ||
441 | |||
442 | /* Done */ | ||
443 | return 1; | ||
444 | |||
445 | err_release: | ||
446 | pci_release_region(esb_pci, 0); | ||
447 | err_disable: | ||
448 | pci_disable_device(esb_pci); | ||
449 | err_devput: | ||
450 | pci_dev_put(esb_pci); | ||
451 | } | ||
452 | return 0; | ||
453 | } | ||
454 | |||
455 | static int __init watchdog_init (void) | ||
456 | { | ||
457 | int ret; | ||
458 | |||
459 | spin_lock_init(&esb_lock); | ||
460 | |||
461 | /* Check whether or not the hardware watchdog is there */ | ||
462 | if (!esb_getdevice () || esb_pci == NULL) | ||
463 | return -ENODEV; | ||
464 | |||
465 | /* Check that the heartbeat value is within it's range ; if not reset to the default */ | ||
466 | if (esb_timer_set_heartbeat (heartbeat)) { | ||
467 | esb_timer_set_heartbeat (WATCHDOG_HEARTBEAT); | ||
468 | printk(KERN_INFO PFX "heartbeat value must be 1<heartbeat<2046, using %d\n", | ||
469 | heartbeat); | ||
470 | } | ||
471 | |||
472 | ret = register_reboot_notifier(&esb_notifier); | ||
473 | if (ret != 0) { | ||
474 | printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", | ||
475 | ret); | ||
476 | goto err_unmap; | ||
477 | } | ||
478 | |||
479 | ret = misc_register(&esb_miscdev); | ||
480 | if (ret != 0) { | ||
481 | printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", | ||
482 | WATCHDOG_MINOR, ret); | ||
483 | goto err_notifier; | ||
484 | } | ||
485 | |||
486 | esb_timer_stop (); | ||
487 | |||
488 | printk (KERN_INFO PFX "initialized (0x%p). heartbeat=%d sec (nowayout=%d)\n", | ||
489 | BASEADDR, heartbeat, nowayout); | ||
490 | |||
491 | return 0; | ||
492 | |||
493 | err_notifier: | ||
494 | unregister_reboot_notifier(&esb_notifier); | ||
495 | err_unmap: | ||
496 | iounmap(BASEADDR); | ||
497 | /* err_release: */ | ||
498 | pci_release_region(esb_pci, 0); | ||
499 | /* err_disable: */ | ||
500 | pci_disable_device(esb_pci); | ||
501 | /* err_devput: */ | ||
502 | pci_dev_put(esb_pci); | ||
503 | return ret; | ||
504 | } | ||
505 | |||
506 | static void __exit watchdog_cleanup (void) | ||
507 | { | ||
508 | /* Stop the timer before we leave */ | ||
509 | if (!nowayout) | ||
510 | esb_timer_stop (); | ||
511 | |||
512 | /* Deregister */ | ||
513 | misc_deregister(&esb_miscdev); | ||
514 | unregister_reboot_notifier(&esb_notifier); | ||
515 | iounmap(BASEADDR); | ||
516 | pci_release_region(esb_pci, 0); | ||
517 | pci_disable_device(esb_pci); | ||
518 | pci_dev_put(esb_pci); | ||
519 | } | ||
520 | |||
521 | module_init(watchdog_init); | ||
522 | module_exit(watchdog_cleanup); | ||
523 | |||
524 | MODULE_AUTHOR("Ross Biro and David Härdeman"); | ||
525 | MODULE_DESCRIPTION("Watchdog driver for Intel 6300ESB chipsets"); | ||
526 | MODULE_LICENSE("GPL"); | ||
527 | MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); | ||
diff --git a/drivers/char/watchdog/ibmasr.c b/drivers/char/watchdog/ibmasr.c new file mode 100644 index 000000000000..294c474ae485 --- /dev/null +++ b/drivers/char/watchdog/ibmasr.c | |||
@@ -0,0 +1,405 @@ | |||
1 | /* | ||
2 | * IBM Automatic Server Restart driver. | ||
3 | * | ||
4 | * Copyright (c) 2005 Andrey Panin <pazke@donpac.ru> | ||
5 | * | ||
6 | * Based on driver written by Pete Reynolds. | ||
7 | * Copyright (c) IBM Corporation, 1998-2004. | ||
8 | * | ||
9 | * This software may be used and distributed according to the terms | ||
10 | * of the GNU Public License, incorporated herein by reference. | ||
11 | */ | ||
12 | |||
13 | #include <linux/config.h> | ||
14 | #include <linux/fs.h> | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/slab.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/pci.h> | ||
19 | #include <linux/timer.h> | ||
20 | #include <linux/miscdevice.h> | ||
21 | #include <linux/watchdog.h> | ||
22 | #include <linux/dmi.h> | ||
23 | |||
24 | #include <asm/io.h> | ||
25 | #include <asm/uaccess.h> | ||
26 | |||
27 | |||
28 | enum { | ||
29 | ASMTYPE_UNKNOWN, | ||
30 | ASMTYPE_TOPAZ, | ||
31 | ASMTYPE_JASPER, | ||
32 | ASMTYPE_PEARL, | ||
33 | ASMTYPE_JUNIPER, | ||
34 | ASMTYPE_SPRUCE, | ||
35 | }; | ||
36 | |||
37 | #define PFX "ibmasr: " | ||
38 | |||
39 | #define TOPAZ_ASR_REG_OFFSET 4 | ||
40 | #define TOPAZ_ASR_TOGGLE 0x40 | ||
41 | #define TOPAZ_ASR_DISABLE 0x80 | ||
42 | |||
43 | /* PEARL ASR S/W REGISTER SUPERIO PORT ADDRESSES */ | ||
44 | #define PEARL_BASE 0xe04 | ||
45 | #define PEARL_WRITE 0xe06 | ||
46 | #define PEARL_READ 0xe07 | ||
47 | |||
48 | #define PEARL_ASR_DISABLE_MASK 0x80 /* bit 7: disable = 1, enable = 0 */ | ||
49 | #define PEARL_ASR_TOGGLE_MASK 0x40 /* bit 6: 0, then 1, then 0 */ | ||
50 | |||
51 | /* JASPER OFFSET FROM SIO BASE ADDR TO ASR S/W REGISTERS. */ | ||
52 | #define JASPER_ASR_REG_OFFSET 0x38 | ||
53 | |||
54 | #define JASPER_ASR_DISABLE_MASK 0x01 /* bit 0: disable = 1, enable = 0 */ | ||
55 | #define JASPER_ASR_TOGGLE_MASK 0x02 /* bit 1: 0, then 1, then 0 */ | ||
56 | |||
57 | #define JUNIPER_BASE_ADDRESS 0x54b /* Base address of Juniper ASR */ | ||
58 | #define JUNIPER_ASR_DISABLE_MASK 0x01 /* bit 0: disable = 1 enable = 0 */ | ||
59 | #define JUNIPER_ASR_TOGGLE_MASK 0x02 /* bit 1: 0, then 1, then 0 */ | ||
60 | |||
61 | #define SPRUCE_BASE_ADDRESS 0x118e /* Base address of Spruce ASR */ | ||
62 | #define SPRUCE_ASR_DISABLE_MASK 0x01 /* bit 1: disable = 1 enable = 0 */ | ||
63 | #define SPRUCE_ASR_TOGGLE_MASK 0x02 /* bit 0: 0, then 1, then 0 */ | ||
64 | |||
65 | |||
66 | static int nowayout = WATCHDOG_NOWAYOUT; | ||
67 | |||
68 | static unsigned long asr_is_open; | ||
69 | static char asr_expect_close; | ||
70 | |||
71 | static unsigned int asr_type, asr_base, asr_length; | ||
72 | static unsigned int asr_read_addr, asr_write_addr; | ||
73 | static unsigned char asr_toggle_mask, asr_disable_mask; | ||
74 | |||
75 | static void asr_toggle(void) | ||
76 | { | ||
77 | unsigned char reg = inb(asr_read_addr); | ||
78 | |||
79 | outb(reg & ~asr_toggle_mask, asr_write_addr); | ||
80 | reg = inb(asr_read_addr); | ||
81 | |||
82 | outb(reg | asr_toggle_mask, asr_write_addr); | ||
83 | reg = inb(asr_read_addr); | ||
84 | |||
85 | outb(reg & ~asr_toggle_mask, asr_write_addr); | ||
86 | reg = inb(asr_read_addr); | ||
87 | } | ||
88 | |||
89 | static void asr_enable(void) | ||
90 | { | ||
91 | unsigned char reg; | ||
92 | |||
93 | if (asr_type == ASMTYPE_TOPAZ) { | ||
94 | /* asr_write_addr == asr_read_addr */ | ||
95 | reg = inb(asr_read_addr); | ||
96 | outb(reg & ~(TOPAZ_ASR_TOGGLE | TOPAZ_ASR_DISABLE), | ||
97 | asr_read_addr); | ||
98 | } else { | ||
99 | /* | ||
100 | * First make sure the hardware timer is reset by toggling | ||
101 | * ASR hardware timer line. | ||
102 | */ | ||
103 | asr_toggle(); | ||
104 | |||
105 | reg = inb(asr_read_addr); | ||
106 | outb(reg & ~asr_disable_mask, asr_write_addr); | ||
107 | } | ||
108 | reg = inb(asr_read_addr); | ||
109 | } | ||
110 | |||
111 | static void asr_disable(void) | ||
112 | { | ||
113 | unsigned char reg = inb(asr_read_addr); | ||
114 | |||
115 | if (asr_type == ASMTYPE_TOPAZ) | ||
116 | /* asr_write_addr == asr_read_addr */ | ||
117 | outb(reg | TOPAZ_ASR_TOGGLE | TOPAZ_ASR_DISABLE, | ||
118 | asr_read_addr); | ||
119 | else { | ||
120 | outb(reg | asr_toggle_mask, asr_write_addr); | ||
121 | reg = inb(asr_read_addr); | ||
122 | |||
123 | outb(reg | asr_disable_mask, asr_write_addr); | ||
124 | } | ||
125 | reg = inb(asr_read_addr); | ||
126 | } | ||
127 | |||
128 | static int __init asr_get_base_address(void) | ||
129 | { | ||
130 | unsigned char low, high; | ||
131 | const char *type = ""; | ||
132 | |||
133 | asr_length = 1; | ||
134 | |||
135 | switch (asr_type) { | ||
136 | case ASMTYPE_TOPAZ: | ||
137 | /* SELECT SuperIO CHIP FOR QUERYING (WRITE 0x07 TO BOTH 0x2E and 0x2F) */ | ||
138 | outb(0x07, 0x2e); | ||
139 | outb(0x07, 0x2f); | ||
140 | |||
141 | /* SELECT AND READ THE HIGH-NIBBLE OF THE GPIO BASE ADDRESS */ | ||
142 | outb(0x60, 0x2e); | ||
143 | high = inb(0x2f); | ||
144 | |||
145 | /* SELECT AND READ THE LOW-NIBBLE OF THE GPIO BASE ADDRESS */ | ||
146 | outb(0x61, 0x2e); | ||
147 | low = inb(0x2f); | ||
148 | |||
149 | asr_base = (high << 16) | low; | ||
150 | asr_read_addr = asr_write_addr = | ||
151 | asr_base + TOPAZ_ASR_REG_OFFSET; | ||
152 | asr_length = 5; | ||
153 | |||
154 | break; | ||
155 | |||
156 | case ASMTYPE_JASPER: | ||
157 | type = "Jaspers "; | ||
158 | |||
159 | /* FIXME: need to use pci_config_lock here, but it's not exported */ | ||
160 | |||
161 | /* spin_lock_irqsave(&pci_config_lock, flags);*/ | ||
162 | |||
163 | /* Select the SuperIO chip in the PCI I/O port register */ | ||
164 | outl(0x8000f858, 0xcf8); | ||
165 | |||
166 | /* | ||
167 | * Read the base address for the SuperIO chip. | ||
168 | * Only the lower 16 bits are valid, but the address is word | ||
169 | * aligned so the last bit must be masked off. | ||
170 | */ | ||
171 | asr_base = inl(0xcfc) & 0xfffe; | ||
172 | |||
173 | /* spin_unlock_irqrestore(&pci_config_lock, flags);*/ | ||
174 | |||
175 | asr_read_addr = asr_write_addr = | ||
176 | asr_base + JASPER_ASR_REG_OFFSET; | ||
177 | asr_toggle_mask = JASPER_ASR_TOGGLE_MASK; | ||
178 | asr_disable_mask = JASPER_ASR_DISABLE_MASK; | ||
179 | asr_length = JASPER_ASR_REG_OFFSET + 1; | ||
180 | |||
181 | break; | ||
182 | |||
183 | case ASMTYPE_PEARL: | ||
184 | type = "Pearls "; | ||
185 | asr_base = PEARL_BASE; | ||
186 | asr_read_addr = PEARL_READ; | ||
187 | asr_write_addr = PEARL_WRITE; | ||
188 | asr_toggle_mask = PEARL_ASR_TOGGLE_MASK; | ||
189 | asr_disable_mask = PEARL_ASR_DISABLE_MASK; | ||
190 | asr_length = 4; | ||
191 | break; | ||
192 | |||
193 | case ASMTYPE_JUNIPER: | ||
194 | type = "Junipers "; | ||
195 | asr_base = JUNIPER_BASE_ADDRESS; | ||
196 | asr_read_addr = asr_write_addr = asr_base; | ||
197 | asr_toggle_mask = JUNIPER_ASR_TOGGLE_MASK; | ||
198 | asr_disable_mask = JUNIPER_ASR_DISABLE_MASK; | ||
199 | break; | ||
200 | |||
201 | case ASMTYPE_SPRUCE: | ||
202 | type = "Spruce's "; | ||
203 | asr_base = SPRUCE_BASE_ADDRESS; | ||
204 | asr_read_addr = asr_write_addr = asr_base; | ||
205 | asr_toggle_mask = SPRUCE_ASR_TOGGLE_MASK; | ||
206 | asr_disable_mask = SPRUCE_ASR_DISABLE_MASK; | ||
207 | break; | ||
208 | } | ||
209 | |||
210 | if (!request_region(asr_base, asr_length, "ibmasr")) { | ||
211 | printk(KERN_ERR PFX "address %#x already in use\n", | ||
212 | asr_base); | ||
213 | return -EBUSY; | ||
214 | } | ||
215 | |||
216 | printk(KERN_INFO PFX "found %sASR @ addr %#x\n", type, asr_base); | ||
217 | |||
218 | return 0; | ||
219 | } | ||
220 | |||
221 | |||
222 | static ssize_t asr_write(struct file *file, const char __user *buf, | ||
223 | size_t count, loff_t *ppos) | ||
224 | { | ||
225 | if (count) { | ||
226 | if (!nowayout) { | ||
227 | size_t i; | ||
228 | |||
229 | /* In case it was set long ago */ | ||
230 | asr_expect_close = 0; | ||
231 | |||
232 | for (i = 0; i != count; i++) { | ||
233 | char c; | ||
234 | if (get_user(c, buf + i)) | ||
235 | return -EFAULT; | ||
236 | if (c == 'V') | ||
237 | asr_expect_close = 42; | ||
238 | } | ||
239 | } | ||
240 | asr_toggle(); | ||
241 | } | ||
242 | return count; | ||
243 | } | ||
244 | |||
245 | static int asr_ioctl(struct inode *inode, struct file *file, | ||
246 | unsigned int cmd, unsigned long arg) | ||
247 | { | ||
248 | static const struct watchdog_info ident = { | ||
249 | .options = WDIOF_KEEPALIVEPING | | ||
250 | WDIOF_MAGICCLOSE, | ||
251 | .identity = "IBM ASR" | ||
252 | }; | ||
253 | void __user *argp = (void __user *)arg; | ||
254 | int __user *p = argp; | ||
255 | int heartbeat; | ||
256 | |||
257 | switch (cmd) { | ||
258 | case WDIOC_GETSUPPORT: | ||
259 | return copy_to_user(argp, &ident, sizeof(ident)) ? | ||
260 | -EFAULT : 0; | ||
261 | |||
262 | case WDIOC_GETSTATUS: | ||
263 | case WDIOC_GETBOOTSTATUS: | ||
264 | return put_user(0, p); | ||
265 | |||
266 | case WDIOC_KEEPALIVE: | ||
267 | asr_toggle(); | ||
268 | return 0; | ||
269 | |||
270 | /* | ||
271 | * The hardware has a fixed timeout value, so no WDIOC_SETTIMEOUT | ||
272 | * and WDIOC_GETTIMEOUT always returns 256. | ||
273 | */ | ||
274 | case WDIOC_GETTIMEOUT: | ||
275 | heartbeat = 256; | ||
276 | return put_user(heartbeat, p); | ||
277 | |||
278 | case WDIOC_SETOPTIONS: { | ||
279 | int new_options, retval = -EINVAL; | ||
280 | |||
281 | if (get_user(new_options, p)) | ||
282 | return -EFAULT; | ||
283 | |||
284 | if (new_options & WDIOS_DISABLECARD) { | ||
285 | asr_disable(); | ||
286 | retval = 0; | ||
287 | } | ||
288 | |||
289 | if (new_options & WDIOS_ENABLECARD) { | ||
290 | asr_enable(); | ||
291 | asr_toggle(); | ||
292 | retval = 0; | ||
293 | } | ||
294 | |||
295 | return retval; | ||
296 | } | ||
297 | } | ||
298 | |||
299 | return -ENOIOCTLCMD; | ||
300 | } | ||
301 | |||
302 | static int asr_open(struct inode *inode, struct file *file) | ||
303 | { | ||
304 | if(test_and_set_bit(0, &asr_is_open)) | ||
305 | return -EBUSY; | ||
306 | |||
307 | asr_toggle(); | ||
308 | asr_enable(); | ||
309 | |||
310 | return nonseekable_open(inode, file); | ||
311 | } | ||
312 | |||
313 | static int asr_release(struct inode *inode, struct file *file) | ||
314 | { | ||
315 | if (asr_expect_close == 42) | ||
316 | asr_disable(); | ||
317 | else { | ||
318 | printk(KERN_CRIT PFX "unexpected close, not stopping watchdog!\n"); | ||
319 | asr_toggle(); | ||
320 | } | ||
321 | clear_bit(0, &asr_is_open); | ||
322 | asr_expect_close = 0; | ||
323 | return 0; | ||
324 | } | ||
325 | |||
326 | static struct file_operations asr_fops = { | ||
327 | .owner = THIS_MODULE, | ||
328 | .llseek = no_llseek, | ||
329 | .write = asr_write, | ||
330 | .ioctl = asr_ioctl, | ||
331 | .open = asr_open, | ||
332 | .release = asr_release, | ||
333 | }; | ||
334 | |||
335 | static struct miscdevice asr_miscdev = { | ||
336 | .minor = WATCHDOG_MINOR, | ||
337 | .name = "watchdog", | ||
338 | .fops = &asr_fops, | ||
339 | }; | ||
340 | |||
341 | |||
342 | struct ibmasr_id { | ||
343 | const char *desc; | ||
344 | int type; | ||
345 | }; | ||
346 | |||
347 | static struct ibmasr_id __initdata ibmasr_id_table[] = { | ||
348 | { "IBM Automatic Server Restart - eserver xSeries 220", ASMTYPE_TOPAZ }, | ||
349 | { "IBM Automatic Server Restart - Machine Type 8673", ASMTYPE_PEARL }, | ||
350 | { "IBM Automatic Server Restart - Machine Type 8480", ASMTYPE_JASPER }, | ||
351 | { "IBM Automatic Server Restart - Machine Type 8482", ASMTYPE_JUNIPER }, | ||
352 | { "IBM Automatic Server Restart - Machine Type 8648", ASMTYPE_SPRUCE }, | ||
353 | { NULL } | ||
354 | }; | ||
355 | |||
356 | static int __init ibmasr_init(void) | ||
357 | { | ||
358 | struct ibmasr_id *id; | ||
359 | int rc; | ||
360 | |||
361 | for (id = ibmasr_id_table; id->desc; id++) { | ||
362 | if (dmi_find_device(DMI_DEV_TYPE_OTHER, id->desc, NULL)) { | ||
363 | asr_type = id->type; | ||
364 | break; | ||
365 | } | ||
366 | } | ||
367 | |||
368 | if (!asr_type) | ||
369 | return -ENODEV; | ||
370 | |||
371 | rc = misc_register(&asr_miscdev); | ||
372 | if (rc < 0) { | ||
373 | printk(KERN_ERR PFX "failed to register misc device\n"); | ||
374 | return rc; | ||
375 | } | ||
376 | |||
377 | rc = asr_get_base_address(); | ||
378 | if (rc) { | ||
379 | misc_deregister(&asr_miscdev); | ||
380 | return rc; | ||
381 | } | ||
382 | |||
383 | return 0; | ||
384 | } | ||
385 | |||
386 | static void __exit ibmasr_exit(void) | ||
387 | { | ||
388 | if (!nowayout) | ||
389 | asr_disable(); | ||
390 | |||
391 | misc_deregister(&asr_miscdev); | ||
392 | |||
393 | release_region(asr_base, asr_length); | ||
394 | } | ||
395 | |||
396 | module_init(ibmasr_init); | ||
397 | module_exit(ibmasr_exit); | ||
398 | |||
399 | module_param(nowayout, int, 0); | ||
400 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); | ||
401 | |||
402 | MODULE_DESCRIPTION("IBM Automatic Server Restart driver"); | ||
403 | MODULE_AUTHOR("Andrey Panin"); | ||
404 | MODULE_LICENSE("GPL"); | ||
405 | MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); | ||
diff --git a/drivers/char/watchdog/mpcore_wdt.c b/drivers/char/watchdog/mpcore_wdt.c index c694eee1fb24..75ca84ed4adf 100644 --- a/drivers/char/watchdog/mpcore_wdt.c +++ b/drivers/char/watchdog/mpcore_wdt.c | |||
@@ -30,6 +30,8 @@ | |||
30 | #include <linux/init.h> | 30 | #include <linux/init.h> |
31 | #include <linux/interrupt.h> | 31 | #include <linux/interrupt.h> |
32 | #include <linux/device.h> | 32 | #include <linux/device.h> |
33 | |||
34 | #include <asm/hardware/arm_twd.h> | ||
33 | #include <asm/uaccess.h> | 35 | #include <asm/uaccess.h> |
34 | 36 | ||
35 | struct mpcore_wdt { | 37 | struct mpcore_wdt { |
diff --git a/drivers/char/watchdog/mv64x60_wdt.c b/drivers/char/watchdog/mv64x60_wdt.c new file mode 100644 index 000000000000..6d3ff0836c44 --- /dev/null +++ b/drivers/char/watchdog/mv64x60_wdt.c | |||
@@ -0,0 +1,252 @@ | |||
1 | /* | ||
2 | * mv64x60_wdt.c - MV64X60 (Marvell Discovery) watchdog userspace interface | ||
3 | * | ||
4 | * Author: James Chapman <jchapman@katalix.com> | ||
5 | * | ||
6 | * Platform-specific setup code should configure the dog to generate | ||
7 | * interrupt or reset as required. This code only enables/disables | ||
8 | * and services the watchdog. | ||
9 | * | ||
10 | * Derived from mpc8xx_wdt.c, with the following copyright. | ||
11 | * | ||
12 | * 2002 (c) Florian Schirmer <jolt@tuxbox.org> This file is licensed under | ||
13 | * the terms of the GNU General Public License version 2. This program | ||
14 | * is licensed "as is" without any warranty of any kind, whether express | ||
15 | * or implied. | ||
16 | */ | ||
17 | |||
18 | #include <linux/config.h> | ||
19 | #include <linux/fs.h> | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/miscdevice.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/watchdog.h> | ||
25 | #include <asm/mv64x60.h> | ||
26 | #include <asm/uaccess.h> | ||
27 | #include <asm/io.h> | ||
28 | |||
29 | /* MV64x60 WDC (config) register access definitions */ | ||
30 | #define MV64x60_WDC_CTL1_MASK (3 << 24) | ||
31 | #define MV64x60_WDC_CTL1(val) ((val & 3) << 24) | ||
32 | #define MV64x60_WDC_CTL2_MASK (3 << 26) | ||
33 | #define MV64x60_WDC_CTL2(val) ((val & 3) << 26) | ||
34 | |||
35 | /* Flags bits */ | ||
36 | #define MV64x60_WDOG_FLAG_OPENED 0 | ||
37 | #define MV64x60_WDOG_FLAG_ENABLED 1 | ||
38 | |||
39 | static unsigned long wdt_flags; | ||
40 | static int wdt_status; | ||
41 | static void __iomem *mv64x60_regs; | ||
42 | static int mv64x60_wdt_timeout; | ||
43 | |||
44 | static void mv64x60_wdt_reg_write(u32 val) | ||
45 | { | ||
46 | /* Allow write only to CTL1 / CTL2 fields, retaining values in | ||
47 | * other fields. | ||
48 | */ | ||
49 | u32 data = readl(mv64x60_regs + MV64x60_WDT_WDC); | ||
50 | data &= ~(MV64x60_WDC_CTL1_MASK | MV64x60_WDC_CTL2_MASK); | ||
51 | data |= val; | ||
52 | writel(data, mv64x60_regs + MV64x60_WDT_WDC); | ||
53 | } | ||
54 | |||
55 | static void mv64x60_wdt_service(void) | ||
56 | { | ||
57 | /* Write 01 followed by 10 to CTL2 */ | ||
58 | mv64x60_wdt_reg_write(MV64x60_WDC_CTL2(0x01)); | ||
59 | mv64x60_wdt_reg_write(MV64x60_WDC_CTL2(0x02)); | ||
60 | } | ||
61 | |||
62 | static void mv64x60_wdt_handler_disable(void) | ||
63 | { | ||
64 | if (test_and_clear_bit(MV64x60_WDOG_FLAG_ENABLED, &wdt_flags)) { | ||
65 | /* Write 01 followed by 10 to CTL1 */ | ||
66 | mv64x60_wdt_reg_write(MV64x60_WDC_CTL1(0x01)); | ||
67 | mv64x60_wdt_reg_write(MV64x60_WDC_CTL1(0x02)); | ||
68 | printk(KERN_NOTICE "mv64x60_wdt: watchdog deactivated\n"); | ||
69 | } | ||
70 | } | ||
71 | |||
72 | static void mv64x60_wdt_handler_enable(void) | ||
73 | { | ||
74 | if (!test_and_set_bit(MV64x60_WDOG_FLAG_ENABLED, &wdt_flags)) { | ||
75 | /* Write 01 followed by 10 to CTL1 */ | ||
76 | mv64x60_wdt_reg_write(MV64x60_WDC_CTL1(0x01)); | ||
77 | mv64x60_wdt_reg_write(MV64x60_WDC_CTL1(0x02)); | ||
78 | printk(KERN_NOTICE "mv64x60_wdt: watchdog activated\n"); | ||
79 | } | ||
80 | } | ||
81 | |||
82 | static int mv64x60_wdt_open(struct inode *inode, struct file *file) | ||
83 | { | ||
84 | if (test_and_set_bit(MV64x60_WDOG_FLAG_OPENED, &wdt_flags)) | ||
85 | return -EBUSY; | ||
86 | |||
87 | mv64x60_wdt_service(); | ||
88 | mv64x60_wdt_handler_enable(); | ||
89 | |||
90 | nonseekable_open(inode, file); | ||
91 | |||
92 | return 0; | ||
93 | } | ||
94 | |||
95 | static int mv64x60_wdt_release(struct inode *inode, struct file *file) | ||
96 | { | ||
97 | mv64x60_wdt_service(); | ||
98 | |||
99 | #if !defined(CONFIG_WATCHDOG_NOWAYOUT) | ||
100 | mv64x60_wdt_handler_disable(); | ||
101 | #endif | ||
102 | |||
103 | clear_bit(MV64x60_WDOG_FLAG_OPENED, &wdt_flags); | ||
104 | |||
105 | return 0; | ||
106 | } | ||
107 | |||
108 | static ssize_t mv64x60_wdt_write(struct file *file, const char __user *data, | ||
109 | size_t len, loff_t * ppos) | ||
110 | { | ||
111 | if (len) | ||
112 | mv64x60_wdt_service(); | ||
113 | |||
114 | return len; | ||
115 | } | ||
116 | |||
117 | static int mv64x60_wdt_ioctl(struct inode *inode, struct file *file, | ||
118 | unsigned int cmd, unsigned long arg) | ||
119 | { | ||
120 | int timeout; | ||
121 | void __user *argp = (void __user *)arg; | ||
122 | static struct watchdog_info info = { | ||
123 | .options = WDIOF_KEEPALIVEPING, | ||
124 | .firmware_version = 0, | ||
125 | .identity = "MV64x60 watchdog", | ||
126 | }; | ||
127 | |||
128 | switch (cmd) { | ||
129 | case WDIOC_GETSUPPORT: | ||
130 | if (copy_to_user(argp, &info, sizeof(info))) | ||
131 | return -EFAULT; | ||
132 | break; | ||
133 | |||
134 | case WDIOC_GETSTATUS: | ||
135 | case WDIOC_GETBOOTSTATUS: | ||
136 | if (put_user(wdt_status, (int __user *)argp)) | ||
137 | return -EFAULT; | ||
138 | wdt_status &= ~WDIOF_KEEPALIVEPING; | ||
139 | break; | ||
140 | |||
141 | case WDIOC_GETTEMP: | ||
142 | return -EOPNOTSUPP; | ||
143 | |||
144 | case WDIOC_SETOPTIONS: | ||
145 | return -EOPNOTSUPP; | ||
146 | |||
147 | case WDIOC_KEEPALIVE: | ||
148 | mv64x60_wdt_service(); | ||
149 | wdt_status |= WDIOF_KEEPALIVEPING; | ||
150 | break; | ||
151 | |||
152 | case WDIOC_SETTIMEOUT: | ||
153 | return -EOPNOTSUPP; | ||
154 | |||
155 | case WDIOC_GETTIMEOUT: | ||
156 | timeout = mv64x60_wdt_timeout * HZ; | ||
157 | if (put_user(timeout, (int __user *)argp)) | ||
158 | return -EFAULT; | ||
159 | break; | ||
160 | |||
161 | default: | ||
162 | return -ENOIOCTLCMD; | ||
163 | } | ||
164 | |||
165 | return 0; | ||
166 | } | ||
167 | |||
168 | static struct file_operations mv64x60_wdt_fops = { | ||
169 | .owner = THIS_MODULE, | ||
170 | .llseek = no_llseek, | ||
171 | .write = mv64x60_wdt_write, | ||
172 | .ioctl = mv64x60_wdt_ioctl, | ||
173 | .open = mv64x60_wdt_open, | ||
174 | .release = mv64x60_wdt_release, | ||
175 | }; | ||
176 | |||
177 | static struct miscdevice mv64x60_wdt_miscdev = { | ||
178 | .minor = WATCHDOG_MINOR, | ||
179 | .name = "watchdog", | ||
180 | .fops = &mv64x60_wdt_fops, | ||
181 | }; | ||
182 | |||
183 | static int __devinit mv64x60_wdt_probe(struct device *dev) | ||
184 | { | ||
185 | struct platform_device *pd = to_platform_device(dev); | ||
186 | struct mv64x60_wdt_pdata *pdata = pd->dev.platform_data; | ||
187 | int bus_clk = 133; | ||
188 | |||
189 | mv64x60_wdt_timeout = 10; | ||
190 | if (pdata) { | ||
191 | mv64x60_wdt_timeout = pdata->timeout; | ||
192 | bus_clk = pdata->bus_clk; | ||
193 | } | ||
194 | |||
195 | mv64x60_regs = mv64x60_get_bridge_vbase(); | ||
196 | |||
197 | writel((mv64x60_wdt_timeout * (bus_clk * 1000000)) >> 8, | ||
198 | mv64x60_regs + MV64x60_WDT_WDC); | ||
199 | |||
200 | return misc_register(&mv64x60_wdt_miscdev); | ||
201 | } | ||
202 | |||
203 | static int __devexit mv64x60_wdt_remove(struct device *dev) | ||
204 | { | ||
205 | misc_deregister(&mv64x60_wdt_miscdev); | ||
206 | |||
207 | mv64x60_wdt_service(); | ||
208 | mv64x60_wdt_handler_disable(); | ||
209 | |||
210 | return 0; | ||
211 | } | ||
212 | |||
213 | static struct device_driver mv64x60_wdt_driver = { | ||
214 | .name = MV64x60_WDT_NAME, | ||
215 | .bus = &platform_bus_type, | ||
216 | .probe = mv64x60_wdt_probe, | ||
217 | .remove = __devexit_p(mv64x60_wdt_remove), | ||
218 | }; | ||
219 | |||
220 | static struct platform_device *mv64x60_wdt_dev; | ||
221 | |||
222 | static int __init mv64x60_wdt_init(void) | ||
223 | { | ||
224 | int ret; | ||
225 | |||
226 | printk(KERN_INFO "MV64x60 watchdog driver\n"); | ||
227 | |||
228 | mv64x60_wdt_dev = platform_device_register_simple(MV64x60_WDT_NAME, | ||
229 | -1, NULL, 0); | ||
230 | if (IS_ERR(mv64x60_wdt_dev)) { | ||
231 | ret = PTR_ERR(mv64x60_wdt_dev); | ||
232 | goto out; | ||
233 | } | ||
234 | |||
235 | ret = driver_register(&mv64x60_wdt_driver); | ||
236 | out: | ||
237 | return ret; | ||
238 | } | ||
239 | |||
240 | static void __exit mv64x60_wdt_exit(void) | ||
241 | { | ||
242 | driver_unregister(&mv64x60_wdt_driver); | ||
243 | platform_device_unregister(mv64x60_wdt_dev); | ||
244 | } | ||
245 | |||
246 | module_init(mv64x60_wdt_init); | ||
247 | module_exit(mv64x60_wdt_exit); | ||
248 | |||
249 | MODULE_AUTHOR("James Chapman <jchapman@katalix.com>"); | ||
250 | MODULE_DESCRIPTION("MV64x60 watchdog driver"); | ||
251 | MODULE_LICENSE("GPL"); | ||
252 | MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); | ||
diff --git a/drivers/char/watchdog/pcwd_pci.c b/drivers/char/watchdog/pcwd_pci.c index 2b13afb09c5d..5a80adbf8032 100644 --- a/drivers/char/watchdog/pcwd_pci.c +++ b/drivers/char/watchdog/pcwd_pci.c | |||
@@ -29,27 +29,29 @@ | |||
29 | * Includes, defines, variables, module parameters, ... | 29 | * Includes, defines, variables, module parameters, ... |
30 | */ | 30 | */ |
31 | 31 | ||
32 | #include <linux/config.h> | 32 | #include <linux/config.h> /* For CONFIG_WATCHDOG_NOWAYOUT/... */ |
33 | #include <linux/module.h> | 33 | #include <linux/module.h> /* For module specific items */ |
34 | #include <linux/moduleparam.h> | 34 | #include <linux/moduleparam.h> /* For new moduleparam's */ |
35 | #include <linux/types.h> | 35 | #include <linux/types.h> /* For standard types (like size_t) */ |
36 | #include <linux/delay.h> | 36 | #include <linux/errno.h> /* For the -ENODEV/... values */ |
37 | #include <linux/miscdevice.h> | 37 | #include <linux/kernel.h> /* For printk/panic/... */ |
38 | #include <linux/watchdog.h> | 38 | #include <linux/delay.h> /* For mdelay function */ |
39 | #include <linux/notifier.h> | 39 | #include <linux/miscdevice.h> /* For MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR) */ |
40 | #include <linux/reboot.h> | 40 | #include <linux/watchdog.h> /* For the watchdog specific items */ |
41 | #include <linux/init.h> | 41 | #include <linux/notifier.h> /* For notifier support */ |
42 | #include <linux/fs.h> | 42 | #include <linux/reboot.h> /* For reboot_notifier stuff */ |
43 | #include <linux/pci.h> | 43 | #include <linux/init.h> /* For __init/__exit/... */ |
44 | #include <linux/ioport.h> | 44 | #include <linux/fs.h> /* For file operations */ |
45 | #include <linux/spinlock.h> | 45 | #include <linux/pci.h> /* For pci functions */ |
46 | 46 | #include <linux/ioport.h> /* For io-port access */ | |
47 | #include <asm/uaccess.h> | 47 | #include <linux/spinlock.h> /* For spin_lock/spin_unlock/... */ |
48 | #include <asm/io.h> | 48 | |
49 | #include <asm/uaccess.h> /* For copy_to_user/put_user/... */ | ||
50 | #include <asm/io.h> /* For inb/outb/... */ | ||
49 | 51 | ||
50 | /* Module and version information */ | 52 | /* Module and version information */ |
51 | #define WATCHDOG_VERSION "1.01" | 53 | #define WATCHDOG_VERSION "1.01" |
52 | #define WATCHDOG_DATE "15 Mar 2005" | 54 | #define WATCHDOG_DATE "02 Sep 2005" |
53 | #define WATCHDOG_DRIVER_NAME "PCI-PC Watchdog" | 55 | #define WATCHDOG_DRIVER_NAME "PCI-PC Watchdog" |
54 | #define WATCHDOG_NAME "pcwd_pci" | 56 | #define WATCHDOG_NAME "pcwd_pci" |
55 | #define PFX WATCHDOG_NAME ": " | 57 | #define PFX WATCHDOG_NAME ": " |
@@ -335,12 +337,14 @@ static int pcipcwd_ioctl(struct inode *inode, struct file *file, | |||
335 | return -EFAULT; | 337 | return -EFAULT; |
336 | 338 | ||
337 | if (new_options & WDIOS_DISABLECARD) { | 339 | if (new_options & WDIOS_DISABLECARD) { |
338 | pcipcwd_stop(); | 340 | if (pcipcwd_stop()) |
341 | return -EIO; | ||
339 | retval = 0; | 342 | retval = 0; |
340 | } | 343 | } |
341 | 344 | ||
342 | if (new_options & WDIOS_ENABLECARD) { | 345 | if (new_options & WDIOS_ENABLECARD) { |
343 | pcipcwd_start(); | 346 | if (pcipcwd_start()) |
347 | return -EIO; | ||
344 | retval = 0; | 348 | retval = 0; |
345 | } | 349 | } |
346 | 350 | ||
diff --git a/drivers/char/watchdog/s3c2410_wdt.c b/drivers/char/watchdog/s3c2410_wdt.c index 8b292bf343c4..3625b2601b42 100644 --- a/drivers/char/watchdog/s3c2410_wdt.c +++ b/drivers/char/watchdog/s3c2410_wdt.c | |||
@@ -464,7 +464,7 @@ static void s3c2410wdt_shutdown(struct device *dev) | |||
464 | static unsigned long wtcon_save; | 464 | static unsigned long wtcon_save; |
465 | static unsigned long wtdat_save; | 465 | static unsigned long wtdat_save; |
466 | 466 | ||
467 | static int s3c2410wdt_suspend(struct device *dev, u32 state, u32 level) | 467 | static int s3c2410wdt_suspend(struct device *dev, pm_message_t state, u32 level) |
468 | { | 468 | { |
469 | if (level == SUSPEND_POWER_DOWN) { | 469 | if (level == SUSPEND_POWER_DOWN) { |
470 | /* Save watchdog state, and turn it off. */ | 470 | /* Save watchdog state, and turn it off. */ |
diff --git a/drivers/char/watchdog/sbc8360.c b/drivers/char/watchdog/sbc8360.c new file mode 100644 index 000000000000..c6cbf808d8c2 --- /dev/null +++ b/drivers/char/watchdog/sbc8360.c | |||
@@ -0,0 +1,414 @@ | |||
1 | /* | ||
2 | * SBC8360 Watchdog driver | ||
3 | * | ||
4 | * (c) Copyright 2005 Webcon, Inc. | ||
5 | * | ||
6 | * Based on ib700wdt.c, which is based on advantechwdt.c which is based | ||
7 | * on acquirewdt.c which is based on wdt.c. | ||
8 | * | ||
9 | * (c) Copyright 2001 Charles Howes <chowes@vsol.net> | ||
10 | * | ||
11 | * Based on advantechwdt.c which is based on acquirewdt.c which | ||
12 | * is based on wdt.c. | ||
13 | * | ||
14 | * (c) Copyright 2000-2001 Marek Michalkiewicz <marekm@linux.org.pl> | ||
15 | * | ||
16 | * Based on acquirewdt.c which is based on wdt.c. | ||
17 | * Original copyright messages: | ||
18 | * | ||
19 | * (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved. | ||
20 | * http://www.redhat.com | ||
21 | * | ||
22 | * This program is free software; you can redistribute it and/or | ||
23 | * modify it under the terms of the GNU General Public License | ||
24 | * as published by the Free Software Foundation; either version | ||
25 | * 2 of the License, or (at your option) any later version. | ||
26 | * | ||
27 | * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide | ||
28 | * warranty for any of this software. This material is provided | ||
29 | * "AS-IS" and at no charge. | ||
30 | * | ||
31 | * (c) Copyright 1995 Alan Cox <alan@redhat.com> | ||
32 | * | ||
33 | * 14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com> | ||
34 | * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT | ||
35 | * Added timeout module option to override default | ||
36 | * | ||
37 | */ | ||
38 | |||
39 | #include <linux/config.h> | ||
40 | #include <linux/module.h> | ||
41 | #include <linux/types.h> | ||
42 | #include <linux/miscdevice.h> | ||
43 | #include <linux/watchdog.h> | ||
44 | #include <linux/ioport.h> | ||
45 | #include <linux/delay.h> | ||
46 | #include <linux/notifier.h> | ||
47 | #include <linux/fs.h> | ||
48 | #include <linux/reboot.h> | ||
49 | #include <linux/init.h> | ||
50 | #include <linux/spinlock.h> | ||
51 | #include <linux/moduleparam.h> | ||
52 | |||
53 | #include <asm/io.h> | ||
54 | #include <asm/uaccess.h> | ||
55 | #include <asm/system.h> | ||
56 | |||
57 | static unsigned long sbc8360_is_open; | ||
58 | static spinlock_t sbc8360_lock; | ||
59 | static char expect_close; | ||
60 | |||
61 | #define PFX "sbc8360: " | ||
62 | |||
63 | /* | ||
64 | * | ||
65 | * Watchdog Timer Configuration | ||
66 | * | ||
67 | * The function of the watchdog timer is to reset the system automatically | ||
68 | * and is defined at I/O port 0120H and 0121H. To enable the watchdog timer | ||
69 | * and allow the system to reset, write appropriate values from the table | ||
70 | * below to I/O port 0120H and 0121H. To disable the timer, write a zero | ||
71 | * value to I/O port 0121H for the system to stop the watchdog function. | ||
72 | * | ||
73 | * The following describes how the timer should be programmed (according to | ||
74 | * the vendor documentation) | ||
75 | * | ||
76 | * Enabling Watchdog: | ||
77 | * MOV AX,000AH (enable, phase I) | ||
78 | * MOV DX,0120H | ||
79 | * OUT DX,AX | ||
80 | * MOV AX,000BH (enable, phase II) | ||
81 | * MOV DX,0120H | ||
82 | * OUT DX,AX | ||
83 | * MOV AX,000nH (set multiplier n, from 1-4) | ||
84 | * MOV DX,0120H | ||
85 | * OUT DX,AX | ||
86 | * MOV AX,000mH (set base timer m, from 0-F) | ||
87 | * MOV DX,0121H | ||
88 | * OUT DX,AX | ||
89 | * | ||
90 | * Reset timer: | ||
91 | * MOV AX,000mH (same as set base timer, above) | ||
92 | * MOV DX,0121H | ||
93 | * OUT DX,AX | ||
94 | * | ||
95 | * Disabling Watchdog: | ||
96 | * MOV AX,0000H (a zero value) | ||
97 | * MOV DX,0120H | ||
98 | * OUT DX,AX | ||
99 | * | ||
100 | * Watchdog timeout configuration values: | ||
101 | * N | ||
102 | * M | 1 2 3 4 | ||
103 | * --|---------------------------------- | ||
104 | * 0 | 0.5s 5s 50s 100s | ||
105 | * 1 | 1s 10s 100s 200s | ||
106 | * 2 | 1.5s 15s 150s 300s | ||
107 | * 3 | 2s 20s 200s 400s | ||
108 | * 4 | 2.5s 25s 250s 500s | ||
109 | * 5 | 3s 30s 300s 600s | ||
110 | * 6 | 3.5s 35s 350s 700s | ||
111 | * 7 | 4s 40s 400s 800s | ||
112 | * 8 | 4.5s 45s 450s 900s | ||
113 | * 9 | 5s 50s 500s 1000s | ||
114 | * A | 5.5s 55s 550s 1100s | ||
115 | * B | 6s 60s 600s 1200s | ||
116 | * C | 6.5s 65s 650s 1300s | ||
117 | * D | 7s 70s 700s 1400s | ||
118 | * E | 7.5s 75s 750s 1500s | ||
119 | * F | 8s 80s 800s 1600s | ||
120 | * | ||
121 | * Another way to say the same things is: | ||
122 | * For N=1, Timeout = (M+1) * 0.5s | ||
123 | * For N=2, Timeout = (M+1) * 5s | ||
124 | * For N=3, Timeout = (M+1) * 50s | ||
125 | * For N=4, Timeout = (M+1) * 100s | ||
126 | * | ||
127 | */ | ||
128 | |||
129 | static int wd_times[64][2] = { | ||
130 | {0, 1}, /* 0 = 0.5s */ | ||
131 | {1, 1}, /* 1 = 1s */ | ||
132 | {2, 1}, /* 2 = 1.5s */ | ||
133 | {3, 1}, /* 3 = 2s */ | ||
134 | {4, 1}, /* 4 = 2.5s */ | ||
135 | {5, 1}, /* 5 = 3s */ | ||
136 | {6, 1}, /* 6 = 3.5s */ | ||
137 | {7, 1}, /* 7 = 4s */ | ||
138 | {8, 1}, /* 8 = 4.5s */ | ||
139 | {9, 1}, /* 9 = 5s */ | ||
140 | {0xA, 1}, /* 10 = 5.5s */ | ||
141 | {0xB, 1}, /* 11 = 6s */ | ||
142 | {0xC, 1}, /* 12 = 6.5s */ | ||
143 | {0xD, 1}, /* 13 = 7s */ | ||
144 | {0xE, 1}, /* 14 = 7.5s */ | ||
145 | {0xF, 1}, /* 15 = 8s */ | ||
146 | {0, 2}, /* 16 = 5s */ | ||
147 | {1, 2}, /* 17 = 10s */ | ||
148 | {2, 2}, /* 18 = 15s */ | ||
149 | {3, 2}, /* 19 = 20s */ | ||
150 | {4, 2}, /* 20 = 25s */ | ||
151 | {5, 2}, /* 21 = 30s */ | ||
152 | {6, 2}, /* 22 = 35s */ | ||
153 | {7, 2}, /* 23 = 40s */ | ||
154 | {8, 2}, /* 24 = 45s */ | ||
155 | {9, 2}, /* 25 = 50s */ | ||
156 | {0xA, 2}, /* 26 = 55s */ | ||
157 | {0xB, 2}, /* 27 = 60s */ | ||
158 | {0xC, 2}, /* 28 = 65s */ | ||
159 | {0xD, 2}, /* 29 = 70s */ | ||
160 | {0xE, 2}, /* 30 = 75s */ | ||
161 | {0xF, 2}, /* 31 = 80s */ | ||
162 | {0, 3}, /* 32 = 50s */ | ||
163 | {1, 3}, /* 33 = 100s */ | ||
164 | {2, 3}, /* 34 = 150s */ | ||
165 | {3, 3}, /* 35 = 200s */ | ||
166 | {4, 3}, /* 36 = 250s */ | ||
167 | {5, 3}, /* 37 = 300s */ | ||
168 | {6, 3}, /* 38 = 350s */ | ||
169 | {7, 3}, /* 39 = 400s */ | ||
170 | {8, 3}, /* 40 = 450s */ | ||
171 | {9, 3}, /* 41 = 500s */ | ||
172 | {0xA, 3}, /* 42 = 550s */ | ||
173 | {0xB, 3}, /* 43 = 600s */ | ||
174 | {0xC, 3}, /* 44 = 650s */ | ||
175 | {0xD, 3}, /* 45 = 700s */ | ||
176 | {0xE, 3}, /* 46 = 750s */ | ||
177 | {0xF, 3}, /* 47 = 800s */ | ||
178 | {0, 4}, /* 48 = 100s */ | ||
179 | {1, 4}, /* 49 = 200s */ | ||
180 | {2, 4}, /* 50 = 300s */ | ||
181 | {3, 4}, /* 51 = 400s */ | ||
182 | {4, 4}, /* 52 = 500s */ | ||
183 | {5, 4}, /* 53 = 600s */ | ||
184 | {6, 4}, /* 54 = 700s */ | ||
185 | {7, 4}, /* 55 = 800s */ | ||
186 | {8, 4}, /* 56 = 900s */ | ||
187 | {9, 4}, /* 57 = 1000s */ | ||
188 | {0xA, 4}, /* 58 = 1100s */ | ||
189 | {0xB, 4}, /* 59 = 1200s */ | ||
190 | {0xC, 4}, /* 60 = 1300s */ | ||
191 | {0xD, 4}, /* 61 = 1400s */ | ||
192 | {0xE, 4}, /* 62 = 1500s */ | ||
193 | {0xF, 4} /* 63 = 1600s */ | ||
194 | }; | ||
195 | |||
196 | #define SBC8360_ENABLE 0x120 | ||
197 | #define SBC8360_BASETIME 0x121 | ||
198 | |||
199 | static int timeout = 27; | ||
200 | static int wd_margin = 0xB; | ||
201 | static int wd_multiplier = 2; | ||
202 | static int nowayout = WATCHDOG_NOWAYOUT; | ||
203 | |||
204 | module_param(timeout, int, 27); | ||
205 | MODULE_PARM_DESC(timeout, "Index into timeout table (0-63) (default=27 (60s))"); | ||
206 | module_param(nowayout, int, 0); | ||
207 | MODULE_PARM_DESC(nowayout, | ||
208 | "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); | ||
209 | |||
210 | /* | ||
211 | * Kernel methods. | ||
212 | */ | ||
213 | |||
214 | /* Activate and pre-configure watchdog */ | ||
215 | static void sbc8360_activate(void) | ||
216 | { | ||
217 | /* Enable the watchdog */ | ||
218 | outb(0x0A, SBC8360_ENABLE); | ||
219 | msleep_interruptible(100); | ||
220 | outb(0x0B, SBC8360_ENABLE); | ||
221 | msleep_interruptible(100); | ||
222 | /* Set timeout multiplier */ | ||
223 | outb(wd_multiplier, SBC8360_ENABLE); | ||
224 | msleep_interruptible(100); | ||
225 | /* Nothing happens until first sbc8360_ping() */ | ||
226 | } | ||
227 | |||
228 | /* Kernel pings watchdog */ | ||
229 | static void sbc8360_ping(void) | ||
230 | { | ||
231 | /* Write the base timer register */ | ||
232 | outb(wd_margin, SBC8360_BASETIME); | ||
233 | } | ||
234 | |||
235 | /* Userspace pings kernel driver, or requests clean close */ | ||
236 | static ssize_t sbc8360_write(struct file *file, const char __user * buf, | ||
237 | size_t count, loff_t * ppos) | ||
238 | { | ||
239 | if (count) { | ||
240 | if (!nowayout) { | ||
241 | size_t i; | ||
242 | |||
243 | /* In case it was set long ago */ | ||
244 | expect_close = 0; | ||
245 | |||
246 | for (i = 0; i != count; i++) { | ||
247 | char c; | ||
248 | if (get_user(c, buf + i)) | ||
249 | return -EFAULT; | ||
250 | if (c == 'V') | ||
251 | expect_close = 42; | ||
252 | } | ||
253 | } | ||
254 | sbc8360_ping(); | ||
255 | } | ||
256 | return count; | ||
257 | } | ||
258 | |||
259 | static int sbc8360_open(struct inode *inode, struct file *file) | ||
260 | { | ||
261 | spin_lock(&sbc8360_lock); | ||
262 | if (test_and_set_bit(0, &sbc8360_is_open)) { | ||
263 | spin_unlock(&sbc8360_lock); | ||
264 | return -EBUSY; | ||
265 | } | ||
266 | if (nowayout) | ||
267 | __module_get(THIS_MODULE); | ||
268 | |||
269 | /* Activate and ping once to start the countdown */ | ||
270 | spin_unlock(&sbc8360_lock); | ||
271 | sbc8360_activate(); | ||
272 | sbc8360_ping(); | ||
273 | return nonseekable_open(inode, file); | ||
274 | } | ||
275 | |||
276 | static int sbc8360_close(struct inode *inode, struct file *file) | ||
277 | { | ||
278 | spin_lock(&sbc8360_lock); | ||
279 | if (expect_close == 42) | ||
280 | outb(0, SBC8360_ENABLE); | ||
281 | else | ||
282 | printk(KERN_CRIT PFX | ||
283 | "SBC8360 device closed unexpectedly. SBC8360 will not stop!\n"); | ||
284 | |||
285 | clear_bit(0, &sbc8360_is_open); | ||
286 | expect_close = 0; | ||
287 | spin_unlock(&sbc8360_lock); | ||
288 | return 0; | ||
289 | } | ||
290 | |||
291 | /* | ||
292 | * Notifier for system down | ||
293 | */ | ||
294 | |||
295 | static int sbc8360_notify_sys(struct notifier_block *this, unsigned long code, | ||
296 | void *unused) | ||
297 | { | ||
298 | if (code == SYS_DOWN || code == SYS_HALT) { | ||
299 | /* Disable the SBC8360 Watchdog */ | ||
300 | outb(0, SBC8360_ENABLE); | ||
301 | } | ||
302 | return NOTIFY_DONE; | ||
303 | } | ||
304 | |||
305 | /* | ||
306 | * Kernel Interfaces | ||
307 | */ | ||
308 | |||
309 | static struct file_operations sbc8360_fops = { | ||
310 | .owner = THIS_MODULE, | ||
311 | .llseek = no_llseek, | ||
312 | .write = sbc8360_write, | ||
313 | .open = sbc8360_open, | ||
314 | .release = sbc8360_close, | ||
315 | }; | ||
316 | |||
317 | static struct miscdevice sbc8360_miscdev = { | ||
318 | .minor = WATCHDOG_MINOR, | ||
319 | .name = "watchdog", | ||
320 | .fops = &sbc8360_fops, | ||
321 | }; | ||
322 | |||
323 | /* | ||
324 | * The SBC8360 needs to learn about soft shutdowns in order to | ||
325 | * turn the timebomb registers off. | ||
326 | */ | ||
327 | |||
328 | static struct notifier_block sbc8360_notifier = { | ||
329 | .notifier_call = sbc8360_notify_sys, | ||
330 | }; | ||
331 | |||
332 | static int __init sbc8360_init(void) | ||
333 | { | ||
334 | int res; | ||
335 | unsigned long int mseconds = 60000; | ||
336 | |||
337 | spin_lock_init(&sbc8360_lock); | ||
338 | res = misc_register(&sbc8360_miscdev); | ||
339 | if (res) { | ||
340 | printk(KERN_ERR PFX "failed to register misc device\n"); | ||
341 | goto out_nomisc; | ||
342 | } | ||
343 | |||
344 | if (!request_region(SBC8360_ENABLE, 1, "SBC8360")) { | ||
345 | printk(KERN_ERR PFX "ENABLE method I/O %X is not available.\n", | ||
346 | SBC8360_ENABLE); | ||
347 | res = -EIO; | ||
348 | goto out_noenablereg; | ||
349 | } | ||
350 | if (!request_region(SBC8360_BASETIME, 1, "SBC8360")) { | ||
351 | printk(KERN_ERR PFX | ||
352 | "BASETIME method I/O %X is not available.\n", | ||
353 | SBC8360_BASETIME); | ||
354 | res = -EIO; | ||
355 | goto out_nobasetimereg; | ||
356 | } | ||
357 | |||
358 | res = register_reboot_notifier(&sbc8360_notifier); | ||
359 | if (res) { | ||
360 | printk(KERN_ERR PFX "Failed to register reboot notifier.\n"); | ||
361 | goto out_noreboot; | ||
362 | } | ||
363 | |||
364 | if (timeout < 0 || timeout > 63) { | ||
365 | printk(KERN_ERR PFX "Invalid timeout index (must be 0-63).\n"); | ||
366 | res = -EINVAL; | ||
367 | goto out_noreboot; | ||
368 | } | ||
369 | |||
370 | wd_margin = wd_times[timeout][0]; | ||
371 | wd_multiplier = wd_times[timeout][1]; | ||
372 | |||
373 | if (wd_multiplier == 1) | ||
374 | mseconds = (wd_margin + 1) * 500; | ||
375 | else if (wd_multiplier == 2) | ||
376 | mseconds = (wd_margin + 1) * 5000; | ||
377 | else if (wd_multiplier == 3) | ||
378 | mseconds = (wd_margin + 1) * 50000; | ||
379 | else if (wd_multiplier == 4) | ||
380 | mseconds = (wd_margin + 1) * 100000; | ||
381 | |||
382 | /* My kingdom for the ability to print "0.5 seconds" in the kernel! */ | ||
383 | printk(KERN_INFO PFX "Timeout set at %ld ms.\n", mseconds); | ||
384 | |||
385 | return 0; | ||
386 | |||
387 | out_noreboot: | ||
388 | release_region(SBC8360_ENABLE, 1); | ||
389 | release_region(SBC8360_BASETIME, 1); | ||
390 | out_noenablereg: | ||
391 | out_nobasetimereg: | ||
392 | misc_deregister(&sbc8360_miscdev); | ||
393 | out_nomisc: | ||
394 | return res; | ||
395 | } | ||
396 | |||
397 | static void __exit sbc8360_exit(void) | ||
398 | { | ||
399 | misc_deregister(&sbc8360_miscdev); | ||
400 | unregister_reboot_notifier(&sbc8360_notifier); | ||
401 | release_region(SBC8360_ENABLE, 1); | ||
402 | release_region(SBC8360_BASETIME, 1); | ||
403 | } | ||
404 | |||
405 | module_init(sbc8360_init); | ||
406 | module_exit(sbc8360_exit); | ||
407 | |||
408 | MODULE_AUTHOR("Ian E. Morgan <imorgan@webcon.ca>"); | ||
409 | MODULE_DESCRIPTION("SBC8360 watchdog driver"); | ||
410 | MODULE_LICENSE("GPL"); | ||
411 | MODULE_VERSION("1.0"); | ||
412 | MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); | ||
413 | |||
414 | /* end of sbc8360.c */ | ||
diff --git a/drivers/char/watchdog/w83977f_wdt.c b/drivers/char/watchdog/w83977f_wdt.c new file mode 100644 index 000000000000..a7ff64c8921f --- /dev/null +++ b/drivers/char/watchdog/w83977f_wdt.c | |||
@@ -0,0 +1,543 @@ | |||
1 | /* | ||
2 | * W83977F Watchdog Timer Driver for Winbond W83977F I/O Chip | ||
3 | * | ||
4 | * (c) Copyright 2005 Jose Goncalves <jose.goncalves@inov.pt> | ||
5 | * | ||
6 | * Based on w83877f_wdt.c by Scott Jennings, | ||
7 | * and wdt977.c by Woody Suwalski | ||
8 | * | ||
9 | * ----------------------- | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU General Public License | ||
13 | * as published by the Free Software Foundation; either version | ||
14 | * 2 of the License, or (at your option) any later version. | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #include <linux/module.h> | ||
19 | #include <linux/moduleparam.h> | ||
20 | #include <linux/config.h> | ||
21 | #include <linux/types.h> | ||
22 | #include <linux/kernel.h> | ||
23 | #include <linux/fs.h> | ||
24 | #include <linux/miscdevice.h> | ||
25 | #include <linux/init.h> | ||
26 | #include <linux/ioport.h> | ||
27 | #include <linux/watchdog.h> | ||
28 | #include <linux/notifier.h> | ||
29 | #include <linux/reboot.h> | ||
30 | |||
31 | #include <asm/io.h> | ||
32 | #include <asm/system.h> | ||
33 | #include <asm/uaccess.h> | ||
34 | |||
35 | #define WATCHDOG_VERSION "1.00" | ||
36 | #define WATCHDOG_NAME "W83977F WDT" | ||
37 | #define PFX WATCHDOG_NAME ": " | ||
38 | #define DRIVER_VERSION WATCHDOG_NAME " driver, v" WATCHDOG_VERSION "\n" | ||
39 | |||
40 | #define IO_INDEX_PORT 0x3F0 | ||
41 | #define IO_DATA_PORT (IO_INDEX_PORT+1) | ||
42 | |||
43 | #define UNLOCK_DATA 0x87 | ||
44 | #define LOCK_DATA 0xAA | ||
45 | #define DEVICE_REGISTER 0x07 | ||
46 | |||
47 | #define DEFAULT_TIMEOUT 45 /* default timeout in seconds */ | ||
48 | |||
49 | static int timeout = DEFAULT_TIMEOUT; | ||
50 | static int timeoutW; /* timeout in watchdog counter units */ | ||
51 | static unsigned long timer_alive; | ||
52 | static int testmode; | ||
53 | static char expect_close; | ||
54 | static spinlock_t spinlock; | ||
55 | |||
56 | module_param(timeout, int, 0); | ||
57 | MODULE_PARM_DESC(timeout,"Watchdog timeout in seconds (15..7635), default=" __MODULE_STRING(DEFAULT_TIMEOUT) ")"); | ||
58 | module_param(testmode, int, 0); | ||
59 | MODULE_PARM_DESC(testmode,"Watchdog testmode (1 = no reboot), default=0"); | ||
60 | |||
61 | static int nowayout = WATCHDOG_NOWAYOUT; | ||
62 | module_param(nowayout, int, 0); | ||
63 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); | ||
64 | |||
65 | /* | ||
66 | * Start the watchdog | ||
67 | */ | ||
68 | |||
69 | static int wdt_start(void) | ||
70 | { | ||
71 | unsigned long flags; | ||
72 | |||
73 | spin_lock_irqsave(&spinlock, flags); | ||
74 | |||
75 | /* Unlock the SuperIO chip */ | ||
76 | outb_p(UNLOCK_DATA,IO_INDEX_PORT); | ||
77 | outb_p(UNLOCK_DATA,IO_INDEX_PORT); | ||
78 | |||
79 | /* | ||
80 | * Select device Aux2 (device=8) to set watchdog regs F2, F3 and F4. | ||
81 | * F2 has the timeout in watchdog counter units. | ||
82 | * F3 is set to enable watchdog LED blink at timeout. | ||
83 | * F4 is used to just clear the TIMEOUT'ed state (bit 0). | ||
84 | */ | ||
85 | outb_p(DEVICE_REGISTER,IO_INDEX_PORT); | ||
86 | outb_p(0x08,IO_DATA_PORT); | ||
87 | outb_p(0xF2,IO_INDEX_PORT); | ||
88 | outb_p(timeoutW,IO_DATA_PORT); | ||
89 | outb_p(0xF3,IO_INDEX_PORT); | ||
90 | outb_p(0x08,IO_DATA_PORT); | ||
91 | outb_p(0xF4,IO_INDEX_PORT); | ||
92 | outb_p(0x00,IO_DATA_PORT); | ||
93 | |||
94 | /* Set device Aux2 active */ | ||
95 | outb_p(0x30,IO_INDEX_PORT); | ||
96 | outb_p(0x01,IO_DATA_PORT); | ||
97 | |||
98 | /* | ||
99 | * Select device Aux1 (dev=7) to set GP16 as the watchdog output | ||
100 | * (in reg E6) and GP13 as the watchdog LED output (in reg E3). | ||
101 | * Map GP16 at pin 119. | ||
102 | * In test mode watch the bit 0 on F4 to indicate "triggered" or | ||
103 | * check watchdog LED on SBC. | ||
104 | */ | ||
105 | outb_p(DEVICE_REGISTER,IO_INDEX_PORT); | ||
106 | outb_p(0x07,IO_DATA_PORT); | ||
107 | if (!testmode) | ||
108 | { | ||
109 | unsigned pin_map; | ||
110 | |||
111 | outb_p(0xE6,IO_INDEX_PORT); | ||
112 | outb_p(0x0A,IO_DATA_PORT); | ||
113 | outb_p(0x2C,IO_INDEX_PORT); | ||
114 | pin_map = inb_p(IO_DATA_PORT); | ||
115 | pin_map |= 0x10; | ||
116 | pin_map &= ~(0x20); | ||
117 | outb_p(0x2C,IO_INDEX_PORT); | ||
118 | outb_p(pin_map,IO_DATA_PORT); | ||
119 | } | ||
120 | outb_p(0xE3,IO_INDEX_PORT); | ||
121 | outb_p(0x08,IO_DATA_PORT); | ||
122 | |||
123 | /* Set device Aux1 active */ | ||
124 | outb_p(0x30,IO_INDEX_PORT); | ||
125 | outb_p(0x01,IO_DATA_PORT); | ||
126 | |||
127 | /* Lock the SuperIO chip */ | ||
128 | outb_p(LOCK_DATA,IO_INDEX_PORT); | ||
129 | |||
130 | spin_unlock_irqrestore(&spinlock, flags); | ||
131 | |||
132 | printk(KERN_INFO PFX "activated.\n"); | ||
133 | |||
134 | return 0; | ||
135 | } | ||
136 | |||
137 | /* | ||
138 | * Stop the watchdog | ||
139 | */ | ||
140 | |||
141 | static int wdt_stop(void) | ||
142 | { | ||
143 | unsigned long flags; | ||
144 | |||
145 | spin_lock_irqsave(&spinlock, flags); | ||
146 | |||
147 | /* Unlock the SuperIO chip */ | ||
148 | outb_p(UNLOCK_DATA,IO_INDEX_PORT); | ||
149 | outb_p(UNLOCK_DATA,IO_INDEX_PORT); | ||
150 | |||
151 | /* | ||
152 | * Select device Aux2 (device=8) to set watchdog regs F2, F3 and F4. | ||
153 | * F2 is reset to its default value (watchdog timer disabled). | ||
154 | * F3 is reset to its default state. | ||
155 | * F4 clears the TIMEOUT'ed state (bit 0) - back to default. | ||
156 | */ | ||
157 | outb_p(DEVICE_REGISTER,IO_INDEX_PORT); | ||
158 | outb_p(0x08,IO_DATA_PORT); | ||
159 | outb_p(0xF2,IO_INDEX_PORT); | ||
160 | outb_p(0xFF,IO_DATA_PORT); | ||
161 | outb_p(0xF3,IO_INDEX_PORT); | ||
162 | outb_p(0x00,IO_DATA_PORT); | ||
163 | outb_p(0xF4,IO_INDEX_PORT); | ||
164 | outb_p(0x00,IO_DATA_PORT); | ||
165 | outb_p(0xF2,IO_INDEX_PORT); | ||
166 | outb_p(0x00,IO_DATA_PORT); | ||
167 | |||
168 | /* | ||
169 | * Select device Aux1 (dev=7) to set GP16 (in reg E6) and | ||
170 | * Gp13 (in reg E3) as inputs. | ||
171 | */ | ||
172 | outb_p(DEVICE_REGISTER,IO_INDEX_PORT); | ||
173 | outb_p(0x07,IO_DATA_PORT); | ||
174 | if (!testmode) | ||
175 | { | ||
176 | outb_p(0xE6,IO_INDEX_PORT); | ||
177 | outb_p(0x01,IO_DATA_PORT); | ||
178 | } | ||
179 | outb_p(0xE3,IO_INDEX_PORT); | ||
180 | outb_p(0x01,IO_DATA_PORT); | ||
181 | |||
182 | /* Lock the SuperIO chip */ | ||
183 | outb_p(LOCK_DATA,IO_INDEX_PORT); | ||
184 | |||
185 | spin_unlock_irqrestore(&spinlock, flags); | ||
186 | |||
187 | printk(KERN_INFO PFX "shutdown.\n"); | ||
188 | |||
189 | return 0; | ||
190 | } | ||
191 | |||
192 | /* | ||
193 | * Send a keepalive ping to the watchdog | ||
194 | * This is done by simply re-writing the timeout to reg. 0xF2 | ||
195 | */ | ||
196 | |||
197 | static int wdt_keepalive(void) | ||
198 | { | ||
199 | unsigned long flags; | ||
200 | |||
201 | spin_lock_irqsave(&spinlock, flags); | ||
202 | |||
203 | /* Unlock the SuperIO chip */ | ||
204 | outb_p(UNLOCK_DATA,IO_INDEX_PORT); | ||
205 | outb_p(UNLOCK_DATA,IO_INDEX_PORT); | ||
206 | |||
207 | /* Select device Aux2 (device=8) to kick watchdog reg F2 */ | ||
208 | outb_p(DEVICE_REGISTER,IO_INDEX_PORT); | ||
209 | outb_p(0x08,IO_DATA_PORT); | ||
210 | outb_p(0xF2,IO_INDEX_PORT); | ||
211 | outb_p(timeoutW,IO_DATA_PORT); | ||
212 | |||
213 | /* Lock the SuperIO chip */ | ||
214 | outb_p(LOCK_DATA,IO_INDEX_PORT); | ||
215 | |||
216 | spin_unlock_irqrestore(&spinlock, flags); | ||
217 | |||
218 | return 0; | ||
219 | } | ||
220 | |||
221 | /* | ||
222 | * Set the watchdog timeout value | ||
223 | */ | ||
224 | |||
225 | static int wdt_set_timeout(int t) | ||
226 | { | ||
227 | int tmrval; | ||
228 | |||
229 | /* | ||
230 | * Convert seconds to watchdog counter time units, rounding up. | ||
231 | * On PCM-5335 watchdog units are 30 seconds/step with 15 sec startup | ||
232 | * value. This information is supplied in the PCM-5335 manual and was | ||
233 | * checked by me on a real board. This is a bit strange because W83977f | ||
234 | * datasheet says counter unit is in minutes! | ||
235 | */ | ||
236 | if (t < 15) | ||
237 | return -EINVAL; | ||
238 | |||
239 | tmrval = ((t + 15) + 29) / 30; | ||
240 | |||
241 | if (tmrval > 255) | ||
242 | return -EINVAL; | ||
243 | |||
244 | /* | ||
245 | * timeout is the timeout in seconds, | ||
246 | * timeoutW is the timeout in watchdog counter units. | ||
247 | */ | ||
248 | timeoutW = tmrval; | ||
249 | timeout = (timeoutW * 30) - 15; | ||
250 | return 0; | ||
251 | } | ||
252 | |||
253 | /* | ||
254 | * Get the watchdog status | ||
255 | */ | ||
256 | |||
257 | static int wdt_get_status(int *status) | ||
258 | { | ||
259 | int new_status; | ||
260 | unsigned long flags; | ||
261 | |||
262 | spin_lock_irqsave(&spinlock, flags); | ||
263 | |||
264 | /* Unlock the SuperIO chip */ | ||
265 | outb_p(UNLOCK_DATA,IO_INDEX_PORT); | ||
266 | outb_p(UNLOCK_DATA,IO_INDEX_PORT); | ||
267 | |||
268 | /* Select device Aux2 (device=8) to read watchdog reg F4 */ | ||
269 | outb_p(DEVICE_REGISTER,IO_INDEX_PORT); | ||
270 | outb_p(0x08,IO_DATA_PORT); | ||
271 | outb_p(0xF4,IO_INDEX_PORT); | ||
272 | new_status = inb_p(IO_DATA_PORT); | ||
273 | |||
274 | /* Lock the SuperIO chip */ | ||
275 | outb_p(LOCK_DATA,IO_INDEX_PORT); | ||
276 | |||
277 | spin_unlock_irqrestore(&spinlock, flags); | ||
278 | |||
279 | *status = 0; | ||
280 | if (new_status & 1) | ||
281 | *status |= WDIOF_CARDRESET; | ||
282 | |||
283 | return 0; | ||
284 | } | ||
285 | |||
286 | |||
287 | /* | ||
288 | * /dev/watchdog handling | ||
289 | */ | ||
290 | |||
291 | static int wdt_open(struct inode *inode, struct file *file) | ||
292 | { | ||
293 | /* If the watchdog is alive we don't need to start it again */ | ||
294 | if( test_and_set_bit(0, &timer_alive) ) | ||
295 | return -EBUSY; | ||
296 | |||
297 | if (nowayout) | ||
298 | __module_get(THIS_MODULE); | ||
299 | |||
300 | wdt_start(); | ||
301 | return nonseekable_open(inode, file); | ||
302 | } | ||
303 | |||
304 | static int wdt_release(struct inode *inode, struct file *file) | ||
305 | { | ||
306 | /* | ||
307 | * Shut off the timer. | ||
308 | * Lock it in if it's a module and we set nowayout | ||
309 | */ | ||
310 | if (expect_close == 42) | ||
311 | { | ||
312 | wdt_stop(); | ||
313 | clear_bit(0, &timer_alive); | ||
314 | } else { | ||
315 | wdt_keepalive(); | ||
316 | printk(KERN_CRIT PFX "unexpected close, not stopping watchdog!\n"); | ||
317 | } | ||
318 | expect_close = 0; | ||
319 | return 0; | ||
320 | } | ||
321 | |||
322 | /* | ||
323 | * wdt_write: | ||
324 | * @file: file handle to the watchdog | ||
325 | * @buf: buffer to write (unused as data does not matter here | ||
326 | * @count: count of bytes | ||
327 | * @ppos: pointer to the position to write. No seeks allowed | ||
328 | * | ||
329 | * A write to a watchdog device is defined as a keepalive signal. Any | ||
330 | * write of data will do, as we we don't define content meaning. | ||
331 | */ | ||
332 | |||
333 | static ssize_t wdt_write(struct file *file, const char __user *buf, | ||
334 | size_t count, loff_t *ppos) | ||
335 | { | ||
336 | /* See if we got the magic character 'V' and reload the timer */ | ||
337 | if(count) | ||
338 | { | ||
339 | if (!nowayout) | ||
340 | { | ||
341 | size_t ofs; | ||
342 | |||
343 | /* note: just in case someone wrote the magic character long ago */ | ||
344 | expect_close = 0; | ||
345 | |||
346 | /* scan to see whether or not we got the magic character */ | ||
347 | for(ofs = 0; ofs != count; ofs++) | ||
348 | { | ||
349 | char c; | ||
350 | if (get_user(c, buf + ofs)) | ||
351 | return -EFAULT; | ||
352 | if (c == 'V') { | ||
353 | expect_close = 42; | ||
354 | } | ||
355 | } | ||
356 | } | ||
357 | |||
358 | /* someone wrote to us, we should restart timer */ | ||
359 | wdt_keepalive(); | ||
360 | } | ||
361 | return count; | ||
362 | } | ||
363 | |||
364 | /* | ||
365 | * wdt_ioctl: | ||
366 | * @inode: inode of the device | ||
367 | * @file: file handle to the device | ||
368 | * @cmd: watchdog command | ||
369 | * @arg: argument pointer | ||
370 | * | ||
371 | * The watchdog API defines a common set of functions for all watchdogs | ||
372 | * according to their available features. | ||
373 | */ | ||
374 | |||
375 | static struct watchdog_info ident = { | ||
376 | .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING, | ||
377 | .firmware_version = 1, | ||
378 | .identity = WATCHDOG_NAME, | ||
379 | }; | ||
380 | |||
381 | static int wdt_ioctl(struct inode *inode, struct file *file, | ||
382 | unsigned int cmd, unsigned long arg) | ||
383 | { | ||
384 | int status; | ||
385 | int new_options, retval = -EINVAL; | ||
386 | int new_timeout; | ||
387 | union { | ||
388 | struct watchdog_info __user *ident; | ||
389 | int __user *i; | ||
390 | } uarg; | ||
391 | |||
392 | uarg.i = (int __user *)arg; | ||
393 | |||
394 | switch(cmd) | ||
395 | { | ||
396 | default: | ||
397 | return -ENOIOCTLCMD; | ||
398 | |||
399 | case WDIOC_GETSUPPORT: | ||
400 | return copy_to_user(uarg.ident, &ident, sizeof(ident)) ? -EFAULT : 0; | ||
401 | |||
402 | case WDIOC_GETSTATUS: | ||
403 | wdt_get_status(&status); | ||
404 | return put_user(status, uarg.i); | ||
405 | |||
406 | case WDIOC_GETBOOTSTATUS: | ||
407 | return put_user(0, uarg.i); | ||
408 | |||
409 | case WDIOC_KEEPALIVE: | ||
410 | wdt_keepalive(); | ||
411 | return 0; | ||
412 | |||
413 | case WDIOC_SETOPTIONS: | ||
414 | if (get_user (new_options, uarg.i)) | ||
415 | return -EFAULT; | ||
416 | |||
417 | if (new_options & WDIOS_DISABLECARD) { | ||
418 | wdt_stop(); | ||
419 | retval = 0; | ||
420 | } | ||
421 | |||
422 | if (new_options & WDIOS_ENABLECARD) { | ||
423 | wdt_start(); | ||
424 | retval = 0; | ||
425 | } | ||
426 | |||
427 | return retval; | ||
428 | |||
429 | case WDIOC_SETTIMEOUT: | ||
430 | if (get_user(new_timeout, uarg.i)) | ||
431 | return -EFAULT; | ||
432 | |||
433 | if (wdt_set_timeout(new_timeout)) | ||
434 | return -EINVAL; | ||
435 | |||
436 | wdt_keepalive(); | ||
437 | /* Fall */ | ||
438 | |||
439 | case WDIOC_GETTIMEOUT: | ||
440 | return put_user(timeout, uarg.i); | ||
441 | |||
442 | } | ||
443 | } | ||
444 | |||
445 | static int wdt_notify_sys(struct notifier_block *this, unsigned long code, | ||
446 | void *unused) | ||
447 | { | ||
448 | if (code==SYS_DOWN || code==SYS_HALT) | ||
449 | wdt_stop(); | ||
450 | return NOTIFY_DONE; | ||
451 | } | ||
452 | |||
453 | static struct file_operations wdt_fops= | ||
454 | { | ||
455 | .owner = THIS_MODULE, | ||
456 | .llseek = no_llseek, | ||
457 | .write = wdt_write, | ||
458 | .ioctl = wdt_ioctl, | ||
459 | .open = wdt_open, | ||
460 | .release = wdt_release, | ||
461 | }; | ||
462 | |||
463 | static struct miscdevice wdt_miscdev= | ||
464 | { | ||
465 | .minor = WATCHDOG_MINOR, | ||
466 | .name = "watchdog", | ||
467 | .fops = &wdt_fops, | ||
468 | }; | ||
469 | |||
470 | static struct notifier_block wdt_notifier = { | ||
471 | .notifier_call = wdt_notify_sys, | ||
472 | }; | ||
473 | |||
474 | static int __init w83977f_wdt_init(void) | ||
475 | { | ||
476 | int rc; | ||
477 | |||
478 | printk(KERN_INFO PFX DRIVER_VERSION); | ||
479 | |||
480 | spin_lock_init(&spinlock); | ||
481 | |||
482 | /* | ||
483 | * Check that the timeout value is within it's range ; | ||
484 | * if not reset to the default | ||
485 | */ | ||
486 | if (wdt_set_timeout(timeout)) { | ||
487 | wdt_set_timeout(DEFAULT_TIMEOUT); | ||
488 | printk(KERN_INFO PFX "timeout value must be 15<=timeout<=7635, using %d\n", | ||
489 | DEFAULT_TIMEOUT); | ||
490 | } | ||
491 | |||
492 | if (!request_region(IO_INDEX_PORT, 2, WATCHDOG_NAME)) | ||
493 | { | ||
494 | printk(KERN_ERR PFX "I/O address 0x%04x already in use\n", | ||
495 | IO_INDEX_PORT); | ||
496 | rc = -EIO; | ||
497 | goto err_out; | ||
498 | } | ||
499 | |||
500 | rc = misc_register(&wdt_miscdev); | ||
501 | if (rc) | ||
502 | { | ||
503 | printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", | ||
504 | wdt_miscdev.minor, rc); | ||
505 | goto err_out_region; | ||
506 | } | ||
507 | |||
508 | rc = register_reboot_notifier(&wdt_notifier); | ||
509 | if (rc) | ||
510 | { | ||
511 | printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", | ||
512 | rc); | ||
513 | goto err_out_miscdev; | ||
514 | } | ||
515 | |||
516 | printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d testmode=%d)\n", | ||
517 | timeout, nowayout, testmode); | ||
518 | |||
519 | return 0; | ||
520 | |||
521 | err_out_miscdev: | ||
522 | misc_deregister(&wdt_miscdev); | ||
523 | err_out_region: | ||
524 | release_region(IO_INDEX_PORT,2); | ||
525 | err_out: | ||
526 | return rc; | ||
527 | } | ||
528 | |||
529 | static void __exit w83977f_wdt_exit(void) | ||
530 | { | ||
531 | wdt_stop(); | ||
532 | misc_deregister(&wdt_miscdev); | ||
533 | unregister_reboot_notifier(&wdt_notifier); | ||
534 | release_region(IO_INDEX_PORT,2); | ||
535 | } | ||
536 | |||
537 | module_init(w83977f_wdt_init); | ||
538 | module_exit(w83977f_wdt_exit); | ||
539 | |||
540 | MODULE_AUTHOR("Jose Goncalves <jose.goncalves@inov.pt>"); | ||
541 | MODULE_DESCRIPTION("Driver for watchdog timer in W83977F I/O chip"); | ||
542 | MODULE_LICENSE("GPL"); | ||
543 | MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); | ||