Mercurial > vordog
view vordog.c @ 0:71475f5afa92
Watchdog for Vortex86 6071 on FreeBSD
author | Thinker K.F. Li <thinker@branda.to> |
---|---|
date | Tue, 08 Jul 2008 09:57:54 +0800 |
parents | |
children | 0b9854adb86c |
line wrap: on
line source
#include <sys/param.h> #include <sys/bus.h> #include <sys/conf.h> #include <sys/kernel.h> #include <sys/module.h> #include <sys/systm.h> #include <sys/proc.h> #include <sys/ioccom.h> #include <sys/types.h> #include <sys/malloc.h> #include "vordog.h" #if 1 #undef __FreeBSD_version #define __FreeBSD_version 800029 #endif #define VD_STATUS 0x841 #define VD_INITVAL 0x84a #define VD_CTR 0x84b typedef struct vd_softc { struct cdev *_cdev; device_t dev; int open_cnt; int init_val; } *vd_softc_t; #define CDEV_2_SOFTC(_cdev) ((_cdev)->si_drv1) static int vordog_open(struct cdev *dev, int oflags, int devtype, struct thread *td) { vd_softc_t sc; printf("vordog_open\n"); sc = CDEV_2_SOFTC(dev); sc->open_cnt++; return 0; } static int vordog_close(struct cdev *dev, int fflag, int devtype, struct thread *td) { vd_softc_t sc; printf("vordog_close\n"); sc = CDEV_2_SOFTC(dev); sc->open_cnt--; return 0; } static int vordog_go_detach(void) { devclass_t vd_dc; device_t vd_dev, nexus_dev; int r; printf("go_detach 1\n"); vd_dc = devclass_find("vordog"); if(vd_dc == NULL) return EINVAL; printf("go_detach 2\n"); vd_dev = devclass_get_device(vd_dc, 0); if(vd_dev == NULL) return EINVAL; printf("go_detach 3\n"); nexus_dev = device_get_parent(vd_dev); if(nexus_dev == NULL) return EINVAL; printf("go_detach 4\n"); r = device_delete_child(nexus_dev, vd_dev); return r; } static void setup_timer(vordog_cfg_t cfg) { int val; #define VD_TIMER_RST 0xc #if 0 outb(VD_STATUS, 0xc0); /* Clear events or it would be reset * immediately, since it is setted * by last timeout before PCIRST. */ #endif val = cfg->init_val & 0xff; printf("setup_timer 1 (%x)\n", val); pause("vordog setup", hz); outb(VD_INITVAL, val); printf("setup_timer 2\n"); val = 0x80 | ((cfg->unit & 0x3) << 4) | VD_TIMER_RST; printf("setup_timer 3 (%x)\n", val); pause("vordog setup", hz); outb(VD_CTR, val); printf("setup_timer 4\n"); } static void reset_timer(int init_val) { #if 0 printf("reset_timer 1\n"); pause("vordog setup", hz); outb(VD_INITVAL, init_val); #endif printf("reset_timer 2\n"); pause("vordog setup", hz); outb(VD_STATUS, 0xc0); printf("reset_timer 3\n"); pause("vordog setup", hz); } static void disable_timer(void) { outb(VD_CTR, 0); outb(VD_STATUS, 0xc0); } static int vordog_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread *td) { int r = 0; vd_softc_t sc; vordog_cfg_t cfg; sc = CDEV_2_SOFTC(dev); switch(cmd) { case VDCTL_ENABLE: printf("VDCTL_ENABLE\n"); cfg = (vordog_cfg_t)data; sc->init_val = cfg->init_val & 0xff; setup_timer(cfg); break; case VDCTL_RESET: printf("VDCTL_RESET\n"); reset_timer(sc->init_val); break; case VDCTL_DISABLE: printf("VDCTL_DISABLE\n"); disable_timer(); break; default: r = EINVAL; } return r; } struct cdevsw vordog_cdevsw = { .d_version = D_VERSION, .d_open = vordog_open, .d_close = vordog_close, .d_ioctl = vordog_ioctl, .d_name = "vordog", }; static void vordog_identify(driver_t *driver, device_t parent) { device_t vordog; /* make sure vordog device is not in the bus. */ vordog = device_find_child(parent, "vordog", 0); if(vordog != NULL) { printf("vordog is still existing!"); return; } vordog = BUS_ADD_CHILD(parent, 10, "vordog", 0); printf("vordog_identify\n"); } static int vordog_probe(device_t dev) { int b; printf("vordog_probe\n"); b = inb(VD_INITVAL); printf("init val: %x\n", b); b = inb(VD_CTR); printf("ctr: %x\n", b); b = inb(VD_STATUS); printf("status: %x\n", b); return 0; } static int vordog_attach(device_t dev) { vd_softc_t sc; struct cdev *_cdev; printf("vordog_attach 1\n"); sc = (vd_softc_t)malloc(sizeof(struct vd_softc), M_TEMP, M_WAITOK); if(sc == NULL) return ENOMEM; printf("vordog_attach 2\n"); _cdev = make_dev(&vordog_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "vordog0"); if(_cdev == NULL) { free(sc, M_TEMP); return EINVAL; } sc->_cdev = _cdev; sc->dev = dev; printf("vordog_attach 3\n"); device_set_softc(dev, sc); CDEV_2_SOFTC(_cdev) = sc; sc->open_cnt = 0; sc->init_val = 0; return 0; } static int vordog_detach(device_t dev) { vd_softc_t sc; struct cdev *_cdev; printf("vordog_detach 1\n"); sc = device_get_softc(dev); if(sc->open_cnt != 0) return EBUSY; printf("vordog_detach 2\n"); _cdev = sc->_cdev; printf("vordog_detach 3\n"); destroy_dev(_cdev); printf("vordog_detach 4\n"); free(sc, M_TEMP); return 0; } static device_method_t vordog_methods[] = { DEVMETHOD(device_identify, vordog_identify), DEVMETHOD(device_probe, vordog_probe), DEVMETHOD(device_attach, vordog_attach), DEVMETHOD(device_detach, vordog_detach), {0, 0} }; static driver_t vordog_driver = { "vordog", vordog_methods, 0, }; static int vordog_evh(module_t mod, int cmd, void *arg) { int r = 0; switch(cmd) { case MOD_LOAD: printf("MOD_LOAD\n"); break; case MOD_UNLOAD: printf("MOD_UNLOAD\n"); vordog_go_detach(); /* remove device from parent */ break; case MOD_SHUTDOWN: printf("MOD_SHUTDOWN\n"); break; default: r = EINVAL; break; } return r; } static devclass_t vordog_devclass; DRIVER_MODULE(vordog, nexus, vordog_driver, vordog_devclass, vordog_evh, NULL);