Mercurial > vordog
comparison vordog.c @ 6:76ce6e6624b8
Make vordog compatible with watchdog(9).
author | Thinker K.F. Li <thinker@branda.to> |
---|---|
date | Tue, 08 Jul 2008 14:41:47 +0800 |
parents | e59963b503cb |
children | 5a281ce7453c |
comparison
equal
deleted
inserted
replaced
5:e59963b503cb | 6:76ce6e6624b8 |
---|---|
31 #include <sys/systm.h> | 31 #include <sys/systm.h> |
32 #include <sys/proc.h> | 32 #include <sys/proc.h> |
33 #include <sys/ioccom.h> | 33 #include <sys/ioccom.h> |
34 #include <sys/types.h> | 34 #include <sys/types.h> |
35 #include <sys/malloc.h> | 35 #include <sys/malloc.h> |
36 #include <sys/watchdog.h> | |
36 #include "vordog.h" | 37 #include "vordog.h" |
37 | 38 |
38 #if 0 | 39 #if 0 |
39 #undef __FreeBSD_version | 40 #undef __FreeBSD_version |
40 #define __FreeBSD_version 800029 | 41 #define __FreeBSD_version 800029 |
41 #endif | 42 #endif |
42 | 43 |
43 #define VD_STATUS 0x841 | 44 #define VD_STATUS 0x841 |
44 #define VD_INITVAL 0x84a | 45 #define VD_INITVAL 0x84a |
45 #define VD_CTR 0x84b | 46 #define VD_CTR 0x84b |
47 /* trigger PCIRST */ | |
48 #define VD_TIMER_RST 0xc | |
46 | 49 |
47 typedef struct vd_softc { | 50 typedef struct vd_softc { |
48 struct cdev *_cdev; | 51 struct cdev *_cdev; |
49 device_t dev; | 52 device_t dev; |
50 int open_cnt; | 53 int open_cnt; |
51 int init_val; | 54 u_int init_val; |
55 eventhandler_tag wd9_tag; | |
52 } *vd_softc_t; | 56 } *vd_softc_t; |
53 | 57 |
54 #define CDEV_2_SOFTC(_cdev) ((_cdev)->si_drv1) | 58 #define CDEV_2_SOFTC(_cdev) ((_cdev)->si_drv1) |
55 | 59 |
56 static int | 60 static int |
96 } | 100 } |
97 | 101 |
98 static void | 102 static void |
99 setup_timer(vordog_cfg_t cfg) { | 103 setup_timer(vordog_cfg_t cfg) { |
100 int val; | 104 int val; |
101 #define VD_TIMER_RST 0xc | |
102 | 105 |
103 val = cfg->init_val & 0xff; | 106 val = cfg->init_val & 0xff; |
104 outb(VD_INITVAL, val); | 107 outb(VD_INITVAL, val); |
105 val = 0x80 | ((cfg->unit & 0x3) << 4) | VD_TIMER_RST; | 108 val = 0x80 | ((cfg->unit & 0x3) << 4) | VD_TIMER_RST; |
106 outb(VD_CTR, val); | 109 outb(VD_CTR, val); |
107 } | 110 } |
108 | 111 |
109 static void | 112 static void |
110 reset_timer(int init_val) { | 113 reset_timer(void) { |
111 outb(VD_STATUS, 0xc0); | 114 outb(VD_STATUS, 0xc0); |
112 } | 115 } |
113 | 116 |
114 static void | 117 static void |
115 disable_timer(void) { | 118 disable_timer(void) { |
121 vordog_ioctl(struct cdev *dev, u_long cmd, caddr_t data, | 124 vordog_ioctl(struct cdev *dev, u_long cmd, caddr_t data, |
122 int fflag, struct thread *td) { | 125 int fflag, struct thread *td) { |
123 int r = 0; | 126 int r = 0; |
124 vd_softc_t sc; | 127 vd_softc_t sc; |
125 vordog_cfg_t cfg; | 128 vordog_cfg_t cfg; |
129 static const u_int unit_factors[] = {0, 1, 60, 360}; | |
126 | 130 |
127 sc = CDEV_2_SOFTC(dev); | 131 sc = CDEV_2_SOFTC(dev); |
128 switch(cmd) { | 132 switch(cmd) { |
129 case VDCTL_ENABLE: | 133 case VDCTL_ENABLE: |
130 cfg = (vordog_cfg_t)data; | 134 cfg = (vordog_cfg_t)data; |
131 sc->init_val = cfg->init_val & 0xff; | 135 sc->init_val = (cfg->init_val & 0xff) * unit_factors[cfg->unit]; |
132 setup_timer(cfg); | 136 setup_timer(cfg); |
133 break; | 137 break; |
134 case VDCTL_RESET: | 138 case VDCTL_RESET: |
135 reset_timer(sc->init_val); | 139 reset_timer(); |
136 break; | 140 break; |
137 case VDCTL_DISABLE: | 141 case VDCTL_DISABLE: |
138 disable_timer(); | 142 disable_timer(); |
139 break; | 143 break; |
140 default: | 144 default: |
148 .d_open = vordog_open, | 152 .d_open = vordog_open, |
149 .d_close = vordog_close, | 153 .d_close = vordog_close, |
150 .d_ioctl = vordog_ioctl, | 154 .d_ioctl = vordog_ioctl, |
151 .d_name = "vordog", | 155 .d_name = "vordog", |
152 }; | 156 }; |
157 | |
158 /* Implements watchdog(9) compatible driver. */ | |
159 static int | |
160 vordog_wd9_init(int timeout) { | |
161 int val; | |
162 | |
163 if(timeout < 0 || timeout > 255) | |
164 return EINVAL; | |
165 | |
166 outb(VD_INITVAL, timeout & 0xff); | |
167 val = 0x80 | (VDT_1S << 4) | VD_TIMER_RST; | |
168 outb(VD_CTR, val); | |
169 return 0; | |
170 } | |
171 | |
172 static void | |
173 vordog_wd9_reset(void) { | |
174 outb(VD_STATUS, 0xc0); | |
175 } | |
176 | |
177 static void | |
178 vordog_wd9_disable(void) { | |
179 outb(VD_CTR, 0); | |
180 outb(VD_STATUS, 0xc0); | |
181 } | |
182 | |
183 static void | |
184 vordog_wd9_evh(void *private, u_int cmd, int *error) { | |
185 vd_softc_t sc; | |
186 u_int timeout, u; | |
187 static const int timeouts[] = { 1, 2, 3, 5, 9, 18, 35, 69, 138}; | |
188 | |
189 sc = (vd_softc_t)private; | |
190 | |
191 u = cmd & WD_INTERVAL; | |
192 if(u < 31 || u > 39) { | |
193 vordog_wd9_disable(); | |
194 sc->init_val = 0; | |
195 return; | |
196 } | |
197 | |
198 timeout = timeouts[u - 31]; | |
199 if(timeout != sc->init_val) { | |
200 vordog_wd9_init(timeout); | |
201 sc->init_val = timeout; | |
202 } else { | |
203 vordog_wd9_reset(); | |
204 } | |
205 } | |
206 | |
207 static void | |
208 vordog_wd9_register(vd_softc_t sc) { | |
209 sc->wd9_tag = \ | |
210 EVENTHANDLER_REGISTER(watchdog_list, vordog_wd9_evh, sc, 0); | |
211 } | |
212 | |
213 static void | |
214 vordog_wd9_unregister(vd_softc_t sc) { | |
215 EVENTHANDLER_DEREGISTER(watchdog_list, sc->wd9_tag); | |
216 } | |
217 | |
153 | 218 |
154 /* Following implements a new bus device. | 219 /* Following implements a new bus device. |
155 * It is attached under nexus bus, an on board device as `vordog0'. | 220 * It is attached under nexus bus, an on board device as `vordog0'. |
156 */ | 221 */ |
157 | 222 |
200 device_set_softc(dev, sc); | 265 device_set_softc(dev, sc); |
201 CDEV_2_SOFTC(_cdev) = sc; | 266 CDEV_2_SOFTC(_cdev) = sc; |
202 | 267 |
203 sc->open_cnt = 0; | 268 sc->open_cnt = 0; |
204 sc->init_val = 0; | 269 sc->init_val = 0; |
270 sc->wd9_tag = NULL; | |
205 | 271 |
206 device_set_desc(dev, "Watchdog of Vortex86 SoC"); | 272 device_set_desc(dev, "Watchdog of Vortex86 SoC"); |
207 device_printf(dev, "<Vortex86 SoC watchdog> at port 0x%x\n", VD_STATUS); | 273 device_printf(dev, "<Vortex86 SoC watchdog> at port 0x%x\n", VD_STATUS); |
274 | |
275 vordog_wd9_register(sc); | |
208 | 276 |
209 return 0; | 277 return 0; |
210 } | 278 } |
211 | 279 |
212 static int vordog_detach(device_t dev) { | 280 static int vordog_detach(device_t dev) { |
215 | 283 |
216 sc = device_get_softc(dev); | 284 sc = device_get_softc(dev); |
217 if(sc->open_cnt != 0) | 285 if(sc->open_cnt != 0) |
218 return EBUSY; | 286 return EBUSY; |
219 | 287 |
288 disable_timer(); | |
289 | |
290 vordog_wd9_unregister(sc); | |
291 | |
220 _cdev = sc->_cdev; | 292 _cdev = sc->_cdev; |
221 | 293 |
222 destroy_dev(_cdev); | 294 destroy_dev(_cdev); |
223 | 295 |
224 free(sc, M_TEMP); | 296 free(sc, M_TEMP); |