int geode_mfgpt_set_irq(int timer, int cmp, int irq, int enable) { u32 val, dummy; int offset; if (timer < 0 || timer >= MFGPT_MAX_TIMERS) return -EIO; if (geode_mfgpt_toggle_event(timer, cmp, MFGPT_EVENT_IRQ, enable)) return -EIO; rdmsr(MSR_PIC_ZSEL_LOW, val, dummy); offset = (timer % 4) * 4; val &= ~((0xF << offset) | (0xF << (offset + 16))); if (enable) { val |= (irq & 0x0F) << (offset); val |= (irq & 0x0F) << (offset + 16); } wrmsr(MSR_PIC_ZSEL_LOW, val, dummy); return 0; }
static long geodewdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { void __user *argp = (void __user *)arg; int __user *p = argp; int interval; static struct watchdog_info ident = { .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, .firmware_version = 1, .identity = WATCHDOG_NAME, }; switch (cmd) { case WDIOC_GETSUPPORT: return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0; break; case WDIOC_GETSTATUS: case WDIOC_GETBOOTSTATUS: return put_user(0, p); case WDIOC_SETOPTIONS: { int options, ret = -EINVAL; if (get_user(options, p)) return -EFAULT; if (options & WDIOS_DISABLECARD) { geodewdt_disable(); ret = 0; } if (options & WDIOS_ENABLECARD) { geodewdt_ping(); ret = 0; } return ret; } case WDIOC_KEEPALIVE: geodewdt_ping(); return 0; case WDIOC_SETTIMEOUT: if (get_user(interval, p)) return -EFAULT; if (geodewdt_set_heartbeat(interval)) return -EINVAL; /* Fall through */ case WDIOC_GETTIMEOUT: return put_user(timeout, p); default: return -ENOTTY; } return 0; } static const struct file_operations geodewdt_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .write = geodewdt_write, .unlocked_ioctl = geodewdt_ioctl, .open = geodewdt_open, .release = geodewdt_release, }; static struct miscdevice geodewdt_miscdev = { .minor = WATCHDOG_MINOR, .name = "watchdog", .fops = &geodewdt_fops, }; static int __devinit geodewdt_probe(struct platform_device *dev) { int ret, timer; timer = geode_mfgpt_alloc_timer(MFGPT_TIMER_ANY, MFGPT_DOMAIN_WORKING); if (timer == -1) { printk(KERN_ERR "geodewdt: No timers were available\n"); return -ENODEV; } wdt_timer = timer; /* Set up the timer */ geode_mfgpt_write(wdt_timer, MFGPT_REG_SETUP, GEODEWDT_SCALE | (3 << 8)); /* Set up comparator 2 to reset when the event fires */ geode_mfgpt_toggle_event(wdt_timer, MFGPT_CMP2, MFGPT_EVENT_RESET, 1); /* Set up the initial timeout */ geode_mfgpt_write(wdt_timer, MFGPT_REG_CMP2, timeout * GEODEWDT_HZ); ret = misc_register(&geodewdt_miscdev); return ret; } static int __devexit geodewdt_remove(struct platform_device *dev) { misc_deregister(&geodewdt_miscdev); return 0; }