diff options
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); | ||
