Annotation of src/sys/dev/isa/toaster.c, Revision 1.1
1.1 ! joff 1: /* $NetBSD: toaster.c,v 1.4 2005/02/04 06:02:36 joff Exp $ */
! 2:
! 3: /*-
! 4: * Copyright (c) 1998 The NetBSD Foundation, Inc.
! 5: * All rights reserved.
! 6: *
! 7: * This code is derived from software contributed to The NetBSD Foundation
! 8: * by Jesse Off.
! 9: *
! 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.
! 18: * 3. All advertising materials mentioning features or use of this software
! 19: * must display the following acknowledgement:
! 20: * This product includes software developed by the NetBSD
! 21: * Foundation, Inc. and its contributors.
! 22: * 4. Neither the name of The NetBSD Foundation nor the names of its
! 23: * contributors may be used to endorse or promote products derived
! 24: * from this software without specific prior written permission.
! 25: *
! 26: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
! 27: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
! 28: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
! 29: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
! 30: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! 31: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
! 32: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
! 33: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! 34: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 35: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 36: * POSSIBILITY OF SUCH DAMAGE.
! 37: */
! 38: #include <sys/cdefs.h>
! 39: __KERNEL_RCSID(0, "$NetBSD: toaster.c,v 1.4 2005/02/04 06:02:36 joff Exp $");
! 40:
! 41: #include <sys/param.h>
! 42: #include <sys/systm.h>
! 43: #include <sys/sysctl.h>
! 44: #include <sys/proc.h>
! 45: #include <sys/poll.h>
! 46: #include <sys/conf.h>
! 47: #include <sys/uio.h>
! 48: #include <sys/types.h>
! 49: #include <sys/kernel.h>
! 50: #include <sys/device.h>
! 51: #include <sys/callout.h>
! 52: #include <sys/select.h>
! 53: #include <sys/conf.h>
! 54:
! 55: #include <machine/bus.h>
! 56: #include <machine/autoconf.h>
! 57:
! 58: #include <dev/isa/tsdiovar.h>
! 59: #include <dev/isa/tsdioreg.h>
! 60:
! 61: struct toaster_softc {
! 62: struct device sc_dev;
! 63: bus_space_tag_t sc_iot;
! 64: bus_space_handle_t sc_gpioh;
! 65: u_int32_t latch;
! 66: u_int32_t burner;
! 67: u_int32_t led_width[4];
! 68: u_int32_t led_duty[4];
! 69: u_int32_t led_width_sysctl[4];
! 70: u_int32_t led_duty_sysctl[4];
! 71: struct callout led_callout[4];
! 72: };
! 73:
! 74: static int toaster_match(struct device *, struct cfdata *, void *);
! 75: static void toaster_attach(struct device *, struct device *, void *);
! 76:
! 77: extern struct cfdriver toaster_cd;
! 78:
! 79: CFATTACH_DECL(toaster, sizeof(struct toaster_softc),
! 80: toaster_match, toaster_attach, NULL, NULL);
! 81:
! 82: static struct toaster_softc *toaster_sc = NULL;
! 83:
! 84: static int
! 85: toaster_match(parent, match, aux)
! 86: struct device *parent;
! 87: struct cfdata *match;
! 88: void *aux;
! 89: {
! 90: /* No more than one toaster per system */
! 91: if (toaster_sc == NULL)
! 92: return 1;
! 93: else
! 94: return 0;
! 95: }
! 96:
! 97: #define TSDIO_GET(x) bus_space_read_1(sc->sc_iot, sc->sc_gpioh, \
! 98: (TSDIO_ ## x))
! 99:
! 100: #define TSDIO_SET(x, y) bus_space_write_1(sc->sc_iot, sc->sc_gpioh, \
! 101: (TSDIO_ ## x), (y))
! 102:
! 103: #define TSDIO_SETBITS(x, y) bus_space_write_1(sc->sc_iot, sc->sc_gpioh, \
! 104: (TSDIO_ ## x), TSDIO_GET(x) | (y))
! 105:
! 106: #define TSDIO_CLEARBITS(x, y) bus_space_write_1(sc->sc_iot, sc->sc_gpioh, \
! 107: (TSDIO_ ## x), TSDIO_GET(x) & (~(y)))
! 108:
! 109: #define LEDCALLOUT_DECL(x) static void led ## x ## _on(void *); \
! 110: static void led ## x ## _off(void *); \
! 111: static void \
! 112: led ## x ## _on(arg) \
! 113: void *arg; \
! 114: { \
! 115: struct toaster_softc *sc = arg; \
! 116: \
! 117: if (sc->led_duty[(x)]) { \
! 118: TSDIO_CLEARBITS(PBDR, (1 << (4 + (x)))); \
! 119: callout_reset(&sc->led_callout[(x)], \
! 120: sc->led_duty[(x)], led ## x ## _off, arg); \
! 121: } else { \
! 122: TSDIO_SETBITS(PBDR, (1 << (4 + (x)))); \
! 123: } \
! 124: } \
! 125: \
! 126: static void \
! 127: led ## x ## _off(arg) \
! 128: void *arg; \
! 129: { \
! 130: struct toaster_softc *sc = arg; \
! 131: int offtime = sc->led_width[(x)] - sc->led_duty[(x)]; \
! 132: \
! 133: if (offtime > 0) { \
! 134: TSDIO_SETBITS(PBDR, (1 << (4 + (x)))); \
! 135: callout_reset(&sc->led_callout[(x)], offtime, \
! 136: led ## x ## _on, arg); \
! 137: } \
! 138: }
! 139:
! 140: LEDCALLOUT_DECL(0)
! 141: LEDCALLOUT_DECL(1)
! 142: LEDCALLOUT_DECL(2)
! 143: LEDCALLOUT_DECL(3)
! 144:
! 145: static int
! 146: led_sysctl(SYSCTLFN_ARGS)
! 147: {
! 148: int error, t;
! 149: struct sysctlnode node;
! 150: struct toaster_softc *sc = toaster_sc;
! 151:
! 152: node = *rnode;
! 153: t = *(int*)rnode->sysctl_data;
! 154: node.sysctl_data = &t;
! 155: error = sysctl_lookup(SYSCTLFN_CALL(&node));
! 156: if (error || newp == NULL)
! 157: return (error);
! 158:
! 159: if (t < 0) return EINVAL;
! 160:
! 161: *(int*)rnode->sysctl_data = t;
! 162:
! 163: if (node.sysctl_num == sc->led_width_sysctl[0] ||
! 164: node.sysctl_num == sc->led_duty_sysctl[0])
! 165: led0_on(sc);
! 166: if (node.sysctl_num == sc->led_width_sysctl[1] ||
! 167: node.sysctl_num == sc->led_duty_sysctl[1])
! 168: led1_on(sc);
! 169: if (node.sysctl_num == sc->led_width_sysctl[2] ||
! 170: node.sysctl_num == sc->led_duty_sysctl[2])
! 171: led2_on(sc);
! 172: if (node.sysctl_num == sc->led_width_sysctl[3] ||
! 173: node.sysctl_num == sc->led_duty_sysctl[3])
! 174: led3_on(sc);
! 175:
! 176: return (0);
! 177: }
! 178:
! 179: static int
! 180: latch_sysctl(SYSCTLFN_ARGS)
! 181: {
! 182: int error, t;
! 183: struct sysctlnode node;
! 184: struct toaster_softc *sc = toaster_sc;
! 185:
! 186: node = *rnode;
! 187: t = *(int*)rnode->sysctl_data;
! 188: node.sysctl_data = &t;
! 189: error = sysctl_lookup(SYSCTLFN_CALL(&node));
! 190: if (error || newp == NULL)
! 191: return (error);
! 192:
! 193: if (t != 0 && t != 1) return EINVAL;
! 194:
! 195: *(int*)rnode->sysctl_data = t;
! 196:
! 197: if (t)
! 198: TSDIO_SETBITS(PADR, 0x1);
! 199: else
! 200: TSDIO_CLEARBITS(PADR, 0x1);
! 201:
! 202: return (0);
! 203: }
! 204:
! 205: static int
! 206: burner_sysctl(SYSCTLFN_ARGS)
! 207: {
! 208: int error, t;
! 209: struct sysctlnode node;
! 210: struct toaster_softc *sc = toaster_sc;
! 211:
! 212: node = *rnode;
! 213: t = *(int*)rnode->sysctl_data;
! 214: node.sysctl_data = &t;
! 215: error = sysctl_lookup(SYSCTLFN_CALL(&node));
! 216: if (error || newp == NULL)
! 217: return (error);
! 218:
! 219: if (t != 0 && t != 1) return EINVAL;
! 220:
! 221: *(int*)rnode->sysctl_data = t;
! 222:
! 223: if (t)
! 224: TSDIO_SETBITS(PADR, 0x2);
! 225: else
! 226: TSDIO_CLEARBITS(PADR, 0x2);
! 227:
! 228: return (0);
! 229: }
! 230:
! 231:
! 232: static void
! 233: toaster_attach(parent, self, aux)
! 234: struct device *parent;
! 235: struct device *self;
! 236: void *aux;
! 237: {
! 238: struct toaster_softc *sc = (void *)self;
! 239: struct tsdio_attach_args *taa = aux;
! 240: const struct sysctlnode *node, *datnode;
! 241: int i;
! 242:
! 243: toaster_sc = sc;
! 244: sc->sc_iot = taa->ta_iot;
! 245: sc->sc_gpioh = taa->ta_ioh;
! 246:
! 247: TSDIO_SETBITS(DDR, 0x2); /* Port B as outputs */
! 248: TSDIO_SETBITS(PBDR, 0xf0); /* Turn off LED's */
! 249:
! 250: aprint_normal(": internal toaster control outputs\n");
! 251: aprint_normal("%s: using port B, bits 4-7 for front panel LEDs\n", sc->sc_dev.dv_xname);
! 252: aprint_normal("%s: using port A, bit 0 for magnetic latch\n", sc->sc_dev.dv_xname);
! 253: aprint_normal("%s: using port A, bit 1 for burner element\n", sc->sc_dev.dv_xname);
! 254:
! 255: callout_init(&sc->led_callout[0]);
! 256: callout_init(&sc->led_callout[1]);
! 257: callout_init(&sc->led_callout[2]);
! 258: callout_init(&sc->led_callout[3]);
! 259: sc->led_duty[0] = sc->led_width[0] = 0;
! 260: sc->led_duty[1] = sc->led_width[1] = 0;
! 261: sc->led_duty[2] = sc->led_width[2] = 0;
! 262: sc->led_duty[3] = sc->led_width[3] = 0;
! 263:
! 264: sc->burner = 0;
! 265: sc->latch = 0;
! 266:
! 267: if (sysctl_createv(NULL, 0, NULL, NULL,
! 268: CTLFLAG_PERMANENT, CTLTYPE_NODE, "hw",
! 269: NULL, NULL, 0, NULL, 0,
! 270: CTL_HW, CTL_EOL) != 0) {
! 271: printf("%s: could not create sysctl\n",
! 272: sc->sc_dev.dv_xname);
! 273: return;
! 274: }
! 275: if (sysctl_createv(NULL, 0, NULL, &node,
! 276: 0, CTLTYPE_NODE, sc->sc_dev.dv_xname,
! 277: NULL,
! 278: NULL, 0, NULL, 0,
! 279: CTL_HW, CTL_CREATE, CTL_EOL) != 0) {
! 280: printf("%s: could not create sysctl\n",
! 281: sc->sc_dev.dv_xname);
! 282: return;
! 283: }
! 284:
! 285: #define LEDSYSCTL_SETUP(x) if ((i = sysctl_createv(NULL, \
! 286: 0, NULL, &datnode, \
! 287: CTLFLAG_READWRITE|CTLFLAG_ANYWRITE, \
! 288: CTLTYPE_INT, \
! 289: "led" #x "_duty", \
! 290: SYSCTL_DESCR( \
! 291: "LED duty cycle in HZ tick units"), \
! 292: led_sysctl, 0, &sc->led_duty[(x)], 0, \
! 293: CTL_HW, node->sysctl_num, \
! 294: CTL_CREATE, CTL_EOL)) \
! 295: != 0) { \
! 296: printf("%s: could not create sysctl\n", \
! 297: sc->sc_dev.dv_xname); \
! 298: return; \
! 299: } \
! 300: sc->led_duty_sysctl[(x)] = datnode->sysctl_num; \
! 301: \
! 302: if ((i = sysctl_createv(NULL, 0, NULL, &datnode, \
! 303: CTLFLAG_READWRITE|CTLFLAG_ANYWRITE, \
! 304: CTLTYPE_INT, \
! 305: "led" #x "_width", \
! 306: SYSCTL_DESCR( \
! 307: "LED cycle width in HZ tick units"), \
! 308: led_sysctl, 0, &sc->led_width[(x)], 0, \
! 309: CTL_HW, node->sysctl_num, \
! 310: CTL_CREATE, CTL_EOL)) \
! 311: != 0) { \
! 312: printf("%s: could not create sysctl\n", \
! 313: sc->sc_dev.dv_xname); \
! 314: return; \
! 315: } \
! 316: sc->led_width_sysctl[(x)] = datnode->sysctl_num;
! 317:
! 318: LEDSYSCTL_SETUP(0);
! 319: LEDSYSCTL_SETUP(1);
! 320: LEDSYSCTL_SETUP(2);
! 321: LEDSYSCTL_SETUP(3);
! 322:
! 323: if ((i = sysctl_createv(NULL, 0, NULL, &datnode,
! 324: CTLFLAG_READWRITE|CTLFLAG_ANYWRITE,
! 325: CTLTYPE_INT,
! 326: "magnetic_latch",
! 327: SYSCTL_DESCR(
! 328: "magnetic latch that holds the toast down"),
! 329: latch_sysctl, 0, &sc->latch, 0,
! 330: CTL_HW, node->sysctl_num,
! 331: CTL_CREATE, CTL_EOL))
! 332: != 0) {
! 333: printf("%s: could not create sysctl\n",
! 334: sc->sc_dev.dv_xname);
! 335: return;
! 336: }
! 337:
! 338: if ((i = sysctl_createv(NULL, 0, NULL, &datnode,
! 339: CTLFLAG_READWRITE, CTLTYPE_INT,
! 340: "burner_element",
! 341: SYSCTL_DESCR(
! 342: "800-watt burner element control for toasting"),
! 343: burner_sysctl, 0, &sc->burner, 0,
! 344: CTL_HW, node->sysctl_num,
! 345: CTL_CREATE, CTL_EOL))
! 346: != 0) {
! 347: printf("%s: could not create sysctl\n",
! 348: sc->sc_dev.dv_xname);
! 349: return;
! 350: }
! 351:
! 352:
! 353: }
CVSweb <webmaster@jp.NetBSD.org>