Mercurial > vordog
comparison 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 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:71475f5afa92 |
---|---|
1 #include <sys/param.h> | |
2 #include <sys/bus.h> | |
3 #include <sys/conf.h> | |
4 #include <sys/kernel.h> | |
5 #include <sys/module.h> | |
6 #include <sys/systm.h> | |
7 #include <sys/proc.h> | |
8 #include <sys/ioccom.h> | |
9 #include <sys/types.h> | |
10 #include <sys/malloc.h> | |
11 #include "vordog.h" | |
12 | |
13 #if 1 | |
14 #undef __FreeBSD_version | |
15 #define __FreeBSD_version 800029 | |
16 #endif | |
17 | |
18 #define VD_STATUS 0x841 | |
19 #define VD_INITVAL 0x84a | |
20 #define VD_CTR 0x84b | |
21 | |
22 typedef struct vd_softc { | |
23 struct cdev *_cdev; | |
24 device_t dev; | |
25 int open_cnt; | |
26 int init_val; | |
27 } *vd_softc_t; | |
28 | |
29 #define CDEV_2_SOFTC(_cdev) ((_cdev)->si_drv1) | |
30 | |
31 static int | |
32 vordog_open(struct cdev *dev, int oflags, int devtype, struct thread *td) { | |
33 vd_softc_t sc; | |
34 | |
35 printf("vordog_open\n"); | |
36 sc = CDEV_2_SOFTC(dev); | |
37 sc->open_cnt++; | |
38 | |
39 return 0; | |
40 } | |
41 | |
42 static int | |
43 vordog_close(struct cdev *dev, int fflag, int devtype, struct thread *td) { | |
44 vd_softc_t sc; | |
45 | |
46 printf("vordog_close\n"); | |
47 sc = CDEV_2_SOFTC(dev); | |
48 sc->open_cnt--; | |
49 | |
50 return 0; | |
51 } | |
52 | |
53 static int | |
54 vordog_go_detach(void) { | |
55 devclass_t vd_dc; | |
56 device_t vd_dev, nexus_dev; | |
57 int r; | |
58 | |
59 printf("go_detach 1\n"); | |
60 vd_dc = devclass_find("vordog"); | |
61 if(vd_dc == NULL) | |
62 return EINVAL; | |
63 | |
64 printf("go_detach 2\n"); | |
65 vd_dev = devclass_get_device(vd_dc, 0); | |
66 if(vd_dev == NULL) | |
67 return EINVAL; | |
68 | |
69 printf("go_detach 3\n"); | |
70 nexus_dev = device_get_parent(vd_dev); | |
71 if(nexus_dev == NULL) | |
72 return EINVAL; | |
73 | |
74 printf("go_detach 4\n"); | |
75 r = device_delete_child(nexus_dev, vd_dev); | |
76 return r; | |
77 } | |
78 | |
79 static void | |
80 setup_timer(vordog_cfg_t cfg) { | |
81 int val; | |
82 #define VD_TIMER_RST 0xc | |
83 | |
84 #if 0 | |
85 outb(VD_STATUS, 0xc0); /* Clear events or it would be reset | |
86 * immediately, since it is setted | |
87 * by last timeout before PCIRST. | |
88 */ | |
89 #endif | |
90 val = cfg->init_val & 0xff; | |
91 printf("setup_timer 1 (%x)\n", val); | |
92 pause("vordog setup", hz); | |
93 outb(VD_INITVAL, val); | |
94 printf("setup_timer 2\n"); | |
95 val = 0x80 | ((cfg->unit & 0x3) << 4) | VD_TIMER_RST; | |
96 printf("setup_timer 3 (%x)\n", val); | |
97 pause("vordog setup", hz); | |
98 outb(VD_CTR, val); | |
99 printf("setup_timer 4\n"); | |
100 } | |
101 | |
102 static void | |
103 reset_timer(int init_val) { | |
104 #if 0 | |
105 printf("reset_timer 1\n"); | |
106 pause("vordog setup", hz); | |
107 outb(VD_INITVAL, init_val); | |
108 #endif | |
109 printf("reset_timer 2\n"); | |
110 pause("vordog setup", hz); | |
111 outb(VD_STATUS, 0xc0); | |
112 printf("reset_timer 3\n"); | |
113 pause("vordog setup", hz); | |
114 } | |
115 | |
116 static void | |
117 disable_timer(void) { | |
118 outb(VD_CTR, 0); | |
119 outb(VD_STATUS, 0xc0); | |
120 } | |
121 | |
122 static int | |
123 vordog_ioctl(struct cdev *dev, u_long cmd, caddr_t data, | |
124 int fflag, struct thread *td) { | |
125 int r = 0; | |
126 vd_softc_t sc; | |
127 vordog_cfg_t cfg; | |
128 | |
129 sc = CDEV_2_SOFTC(dev); | |
130 switch(cmd) { | |
131 case VDCTL_ENABLE: | |
132 printf("VDCTL_ENABLE\n"); | |
133 cfg = (vordog_cfg_t)data; | |
134 sc->init_val = cfg->init_val & 0xff; | |
135 setup_timer(cfg); | |
136 break; | |
137 case VDCTL_RESET: | |
138 printf("VDCTL_RESET\n"); | |
139 reset_timer(sc->init_val); | |
140 break; | |
141 case VDCTL_DISABLE: | |
142 printf("VDCTL_DISABLE\n"); | |
143 disable_timer(); | |
144 break; | |
145 default: | |
146 r = EINVAL; | |
147 } | |
148 return r; | |
149 } | |
150 | |
151 struct cdevsw vordog_cdevsw = { | |
152 .d_version = D_VERSION, | |
153 .d_open = vordog_open, | |
154 .d_close = vordog_close, | |
155 .d_ioctl = vordog_ioctl, | |
156 .d_name = "vordog", | |
157 }; | |
158 | |
159 static void vordog_identify(driver_t *driver, device_t parent) { | |
160 device_t vordog; | |
161 | |
162 /* make sure vordog device is not in the bus. */ | |
163 vordog = device_find_child(parent, "vordog", 0); | |
164 if(vordog != NULL) { | |
165 printf("vordog is still existing!"); | |
166 return; | |
167 } | |
168 vordog = BUS_ADD_CHILD(parent, 10, "vordog", 0); | |
169 printf("vordog_identify\n"); | |
170 } | |
171 | |
172 static int vordog_probe(device_t dev) { | |
173 int b; | |
174 | |
175 printf("vordog_probe\n"); | |
176 b = inb(VD_INITVAL); | |
177 printf("init val: %x\n", b); | |
178 b = inb(VD_CTR); | |
179 printf("ctr: %x\n", b); | |
180 b = inb(VD_STATUS); | |
181 printf("status: %x\n", b); | |
182 return 0; | |
183 } | |
184 | |
185 static int vordog_attach(device_t dev) { | |
186 vd_softc_t sc; | |
187 struct cdev *_cdev; | |
188 | |
189 printf("vordog_attach 1\n"); | |
190 | |
191 sc = (vd_softc_t)malloc(sizeof(struct vd_softc), M_TEMP, M_WAITOK); | |
192 if(sc == NULL) | |
193 return ENOMEM; | |
194 | |
195 printf("vordog_attach 2\n"); | |
196 _cdev = make_dev(&vordog_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "vordog0"); | |
197 if(_cdev == NULL) { | |
198 free(sc, M_TEMP); | |
199 return EINVAL; | |
200 } | |
201 | |
202 sc->_cdev = _cdev; | |
203 sc->dev = dev; | |
204 | |
205 printf("vordog_attach 3\n"); | |
206 device_set_softc(dev, sc); | |
207 CDEV_2_SOFTC(_cdev) = sc; | |
208 | |
209 sc->open_cnt = 0; | |
210 sc->init_val = 0; | |
211 | |
212 return 0; | |
213 } | |
214 | |
215 static int vordog_detach(device_t dev) { | |
216 vd_softc_t sc; | |
217 struct cdev *_cdev; | |
218 | |
219 printf("vordog_detach 1\n"); | |
220 sc = device_get_softc(dev); | |
221 if(sc->open_cnt != 0) | |
222 return EBUSY; | |
223 | |
224 printf("vordog_detach 2\n"); | |
225 _cdev = sc->_cdev; | |
226 | |
227 printf("vordog_detach 3\n"); | |
228 destroy_dev(_cdev); | |
229 printf("vordog_detach 4\n"); | |
230 | |
231 free(sc, M_TEMP); | |
232 | |
233 return 0; | |
234 } | |
235 | |
236 static device_method_t vordog_methods[] = { | |
237 DEVMETHOD(device_identify, vordog_identify), | |
238 DEVMETHOD(device_probe, vordog_probe), | |
239 DEVMETHOD(device_attach, vordog_attach), | |
240 DEVMETHOD(device_detach, vordog_detach), | |
241 {0, 0} | |
242 }; | |
243 | |
244 static driver_t vordog_driver = { | |
245 "vordog", | |
246 vordog_methods, | |
247 0, | |
248 }; | |
249 | |
250 static int | |
251 vordog_evh(module_t mod, int cmd, void *arg) { | |
252 int r = 0; | |
253 | |
254 switch(cmd) { | |
255 case MOD_LOAD: | |
256 printf("MOD_LOAD\n"); | |
257 break; | |
258 case MOD_UNLOAD: | |
259 printf("MOD_UNLOAD\n"); | |
260 vordog_go_detach(); /* remove device from parent */ | |
261 break; | |
262 case MOD_SHUTDOWN: | |
263 printf("MOD_SHUTDOWN\n"); | |
264 break; | |
265 default: | |
266 r = EINVAL; | |
267 break; | |
268 } | |
269 return r; | |
270 } | |
271 | |
272 static devclass_t vordog_devclass; | |
273 | |
274 DRIVER_MODULE(vordog, nexus, vordog_driver, vordog_devclass, | |
275 vordog_evh, NULL); |