No empty .Rs/.Re
[netbsd-mini2440.git] / sys / dev / isa / toaster.c
blobb48d4ce67d09386affe90360893320771b6442a5
1 /* $NetBSD: toaster.c,v 1.9 2009/05/12 08:44:20 cegger Exp $ */
3 /*-
4 * Copyright (c) 1998 The NetBSD Foundation, Inc.
5 * All rights reserved.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jesse Off.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
31 #include <sys/cdefs.h>
32 __KERNEL_RCSID(0, "$NetBSD: toaster.c,v 1.9 2009/05/12 08:44:20 cegger Exp $");
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/sysctl.h>
37 #include <sys/proc.h>
38 #include <sys/poll.h>
39 #include <sys/conf.h>
40 #include <sys/uio.h>
41 #include <sys/types.h>
42 #include <sys/kernel.h>
43 #include <sys/device.h>
44 #include <sys/callout.h>
45 #include <sys/select.h>
47 #include <sys/bus.h>
48 #include <machine/autoconf.h>
50 #include <dev/isa/tsdiovar.h>
51 #include <dev/isa/tsdioreg.h>
53 struct toaster_softc {
54 struct device sc_dev;
55 bus_space_tag_t sc_iot;
56 bus_space_handle_t sc_gpioh;
57 u_int32_t latch;
58 u_int32_t burner;
59 u_int32_t led_width[4];
60 u_int32_t led_duty[4];
61 u_int32_t led_width_sysctl[4];
62 u_int32_t led_duty_sysctl[4];
63 callout_t led_callout[4];
66 static int toaster_match(device_t, cfdata_t, void *);
67 static void toaster_attach(device_t, device_t, void *);
69 extern struct cfdriver toaster_cd;
71 CFATTACH_DECL(toaster, sizeof(struct toaster_softc),
72 toaster_match, toaster_attach, NULL, NULL);
74 static struct toaster_softc *toaster_sc = NULL;
76 static int
77 toaster_match(device_t parent, cfdata_t match, void *aux)
79 /* No more than one toaster per system */
80 if (toaster_sc == NULL)
81 return 1;
82 else
83 return 0;
86 #define TSDIO_GET(x) bus_space_read_1(sc->sc_iot, sc->sc_gpioh, \
87 (TSDIO_ ## x))
89 #define TSDIO_SET(x, y) bus_space_write_1(sc->sc_iot, sc->sc_gpioh, \
90 (TSDIO_ ## x), (y))
92 #define TSDIO_SETBITS(x, y) bus_space_write_1(sc->sc_iot, sc->sc_gpioh, \
93 (TSDIO_ ## x), TSDIO_GET(x) | (y))
95 #define TSDIO_CLEARBITS(x, y) bus_space_write_1(sc->sc_iot, sc->sc_gpioh, \
96 (TSDIO_ ## x), TSDIO_GET(x) & (~(y)))
98 #define LEDCALLOUT_DECL(x) static void led ## x ## _on(void *); \
99 static void led ## x ## _off(void *); \
100 static void \
101 led ## x ## _on(arg) \
102 void *arg; \
104 struct toaster_softc *sc = arg; \
106 if (sc->led_duty[(x)]) { \
107 TSDIO_CLEARBITS(PBDR, (1 << (4 + (x)))); \
108 callout_reset(&sc->led_callout[(x)], \
109 sc->led_duty[(x)], led ## x ## _off, arg); \
110 } else { \
111 TSDIO_SETBITS(PBDR, (1 << (4 + (x)))); \
115 static void \
116 led ## x ## _off(arg) \
117 void *arg; \
119 struct toaster_softc *sc = arg; \
120 int offtime = sc->led_width[(x)] - sc->led_duty[(x)]; \
122 if (offtime > 0) { \
123 TSDIO_SETBITS(PBDR, (1 << (4 + (x)))); \
124 callout_reset(&sc->led_callout[(x)], offtime, \
125 led ## x ## _on, arg); \
129 LEDCALLOUT_DECL(0)
130 LEDCALLOUT_DECL(1)
131 LEDCALLOUT_DECL(2)
132 LEDCALLOUT_DECL(3)
134 static int
135 led_sysctl(SYSCTLFN_ARGS)
137 int error, t;
138 struct sysctlnode node;
139 struct toaster_softc *sc = toaster_sc;
141 node = *rnode;
142 t = *(int*)rnode->sysctl_data;
143 node.sysctl_data = &t;
144 error = sysctl_lookup(SYSCTLFN_CALL(&node));
145 if (error || newp == NULL)
146 return (error);
148 if (t < 0) return EINVAL;
150 *(int*)rnode->sysctl_data = t;
152 if (node.sysctl_num == sc->led_width_sysctl[0] ||
153 node.sysctl_num == sc->led_duty_sysctl[0])
154 led0_on(sc);
155 if (node.sysctl_num == sc->led_width_sysctl[1] ||
156 node.sysctl_num == sc->led_duty_sysctl[1])
157 led1_on(sc);
158 if (node.sysctl_num == sc->led_width_sysctl[2] ||
159 node.sysctl_num == sc->led_duty_sysctl[2])
160 led2_on(sc);
161 if (node.sysctl_num == sc->led_width_sysctl[3] ||
162 node.sysctl_num == sc->led_duty_sysctl[3])
163 led3_on(sc);
165 return (0);
168 static int
169 latch_sysctl(SYSCTLFN_ARGS)
171 int error, t;
172 struct sysctlnode node;
173 struct toaster_softc *sc = toaster_sc;
175 node = *rnode;
176 t = *(int*)rnode->sysctl_data;
177 node.sysctl_data = &t;
178 error = sysctl_lookup(SYSCTLFN_CALL(&node));
179 if (error || newp == NULL)
180 return (error);
182 if (t != 0 && t != 1) return EINVAL;
184 *(int*)rnode->sysctl_data = t;
186 if (t)
187 TSDIO_SETBITS(PADR, 0x1);
188 else
189 TSDIO_CLEARBITS(PADR, 0x1);
191 return (0);
194 static int
195 burner_sysctl(SYSCTLFN_ARGS)
197 int error, t;
198 struct sysctlnode node;
199 struct toaster_softc *sc = toaster_sc;
201 node = *rnode;
202 t = *(int*)rnode->sysctl_data;
203 node.sysctl_data = &t;
204 error = sysctl_lookup(SYSCTLFN_CALL(&node));
205 if (error || newp == NULL)
206 return (error);
208 if (t != 0 && t != 1) return EINVAL;
210 *(int*)rnode->sysctl_data = t;
212 if (t)
213 TSDIO_SETBITS(PADR, 0x2);
214 else
215 TSDIO_CLEARBITS(PADR, 0x2);
217 return (0);
221 static void
222 toaster_attach(device_t parent, device_t self, void *aux)
224 struct toaster_softc *sc = (void *)self;
225 struct tsdio_attach_args *taa = aux;
226 const struct sysctlnode *node, *datnode;
227 int i;
229 toaster_sc = sc;
230 sc->sc_iot = taa->ta_iot;
231 sc->sc_gpioh = taa->ta_ioh;
233 TSDIO_SETBITS(DDR, 0x2); /* Port B as outputs */
234 TSDIO_SETBITS(PBDR, 0xf0); /* Turn off LED's */
236 aprint_normal(": internal toaster control outputs\n");
237 aprint_normal_dev(&sc->sc_dev, "using port B, bits 4-7 for front panel LEDs\n");
238 aprint_normal_dev(&sc->sc_dev, "using port A, bit 0 for magnetic latch\n");
239 aprint_normal_dev(&sc->sc_dev, "using port A, bit 1 for burner element\n");
241 callout_init(&sc->led_callout[0], 0);
242 callout_init(&sc->led_callout[1], 0);
243 callout_init(&sc->led_callout[2], 0);
244 callout_init(&sc->led_callout[3], 0);
245 sc->led_duty[0] = sc->led_width[0] = 0;
246 sc->led_duty[1] = sc->led_width[1] = 0;
247 sc->led_duty[2] = sc->led_width[2] = 0;
248 sc->led_duty[3] = sc->led_width[3] = 0;
250 sc->burner = 0;
251 sc->latch = 0;
253 if (sysctl_createv(NULL, 0, NULL, NULL,
254 CTLFLAG_PERMANENT, CTLTYPE_NODE, "hw",
255 NULL, NULL, 0, NULL, 0,
256 CTL_HW, CTL_EOL) != 0) {
257 aprint_error_dev(&sc->sc_dev, "could not create sysctl\n");
258 return;
260 if (sysctl_createv(NULL, 0, NULL, &node,
261 0, CTLTYPE_NODE, device_xname(&sc->sc_dev),
262 NULL,
263 NULL, 0, NULL, 0,
264 CTL_HW, CTL_CREATE, CTL_EOL) != 0) {
265 aprint_error_dev(&sc->sc_dev, "could not create sysctl\n");
266 return;
269 #define LEDSYSCTL_SETUP(x) if ((i = sysctl_createv(NULL, \
270 0, NULL, &datnode, \
271 CTLFLAG_READWRITE|CTLFLAG_ANYWRITE, \
272 CTLTYPE_INT, \
273 "led" #x "_duty", \
274 SYSCTL_DESCR( \
275 "LED duty cycle in HZ tick units"), \
276 led_sysctl, 0, &sc->led_duty[(x)], 0, \
277 CTL_HW, node->sysctl_num, \
278 CTL_CREATE, CTL_EOL)) \
279 != 0) { \
280 aprint_error_dev(&sc->sc_dev, "could not create sysctl\n"); \
281 return; \
283 sc->led_duty_sysctl[(x)] = datnode->sysctl_num; \
285 if ((i = sysctl_createv(NULL, 0, NULL, &datnode, \
286 CTLFLAG_READWRITE|CTLFLAG_ANYWRITE, \
287 CTLTYPE_INT, \
288 "led" #x "_width", \
289 SYSCTL_DESCR( \
290 "LED cycle width in HZ tick units"), \
291 led_sysctl, 0, &sc->led_width[(x)], 0, \
292 CTL_HW, node->sysctl_num, \
293 CTL_CREATE, CTL_EOL)) \
294 != 0) { \
295 aprint_error_dev(&sc->sc_dev, "could not create sysctl\n"); \
296 return; \
298 sc->led_width_sysctl[(x)] = datnode->sysctl_num;
300 LEDSYSCTL_SETUP(0);
301 LEDSYSCTL_SETUP(1);
302 LEDSYSCTL_SETUP(2);
303 LEDSYSCTL_SETUP(3);
305 if ((i = sysctl_createv(NULL, 0, NULL, &datnode,
306 CTLFLAG_READWRITE|CTLFLAG_ANYWRITE,
307 CTLTYPE_INT,
308 "magnetic_latch",
309 SYSCTL_DESCR(
310 "magnetic latch that holds the toast down"),
311 latch_sysctl, 0, &sc->latch, 0,
312 CTL_HW, node->sysctl_num,
313 CTL_CREATE, CTL_EOL))
314 != 0) {
315 aprint_error_dev(&sc->sc_dev, "could not create sysctl\n");
316 return;
319 if ((i = sysctl_createv(NULL, 0, NULL, &datnode,
320 CTLFLAG_READWRITE, CTLTYPE_INT,
321 "burner_element",
322 SYSCTL_DESCR(
323 "800-watt burner element control for toasting"),
324 burner_sysctl, 0, &sc->burner, 0,
325 CTL_HW, node->sysctl_num,
326 CTL_CREATE, CTL_EOL))
327 != 0) {
328 aprint_error_dev(&sc->sc_dev, "could not create sysctl\n");
329 return;