Home | History | Annotate | Line # | Download | only in ic
mpu.c revision 1.15.16.1
      1 /*	$NetBSD: mpu.c,v 1.15.16.1 2008/04/03 12:42:41 mjf 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 Lennart Augustsson (augustss (at) NetBSD.org).
      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 
     39 #include <sys/cdefs.h>
     40 __KERNEL_RCSID(0, "$NetBSD: mpu.c,v 1.15.16.1 2008/04/03 12:42:41 mjf Exp $");
     41 
     42 #include <sys/param.h>
     43 #include <sys/systm.h>
     44 #include <sys/errno.h>
     45 #include <sys/ioctl.h>
     46 #include <sys/syslog.h>
     47 #include <sys/device.h>
     48 #include <sys/proc.h>
     49 #include <sys/buf.h>
     50 
     51 #include <sys/cpu.h>
     52 #include <sys/intr.h>
     53 #include <sys/bus.h>
     54 
     55 #include <dev/midi_if.h>
     56 
     57 #include <dev/ic/mpuvar.h>
     58 
     59 #ifdef AUDIO_DEBUG
     60 #define DPRINTF(x)	if (mpudebug) printf x
     61 #define DPRINTFN(n,x)	if (mpudebug >= (n)) printf x
     62 int	mpudebug = 0;
     63 #else
     64 #define DPRINTF(x)
     65 #define DPRINTFN(n,x)
     66 #endif
     67 
     68 #define MPU_DATA		0
     69 #define MPU_COMMAND	1
     70 #define  MPU_RESET	0xff
     71 #define  MPU_UART_MODE	0x3f
     72 #define  MPU_ACK		0xfe
     73 #define MPU_STATUS	1
     74 #define  MPU_OUTPUT_BUSY	0x40
     75 #define  MPU_INPUT_EMPTY	0x80
     76 
     77 #define MPU_MAXWAIT	10000	/* usec/10 to wait */
     78 
     79 #define MPU_GETSTATUS(iot, ioh) (bus_space_read_1(iot, ioh, MPU_STATUS))
     80 
     81 static int 		mpu_reset(struct mpu_softc *);
     82 static	inline int mpu_waitready(struct mpu_softc *);
     83 static void		mpu_readinput(struct mpu_softc *);
     84 
     85 static int	mpu_open(void *, int,
     86 			 void (*iintr)(void *, int),
     87 			 void (*ointr)(void *), void *arg);
     88 static void	mpu_close(void *);
     89 static int	mpu_output(void *, int);
     90 static void	mpu_getinfo(void *, struct midi_info *);
     91 
     92 const struct midi_hw_if mpu_midi_hw_if = {
     93 	mpu_open,
     94 	mpu_close,
     95 	mpu_output,
     96 	mpu_getinfo,
     97 	0,			/* ioctl */
     98 };
     99 
    100 int
    101 mpu_find(struct mpu_softc *sc)
    102 {
    103 	if (MPU_GETSTATUS(sc->iot, sc->ioh) == 0xff) {
    104 		DPRINTF(("%s: No status\n", __func__));
    105 		goto bad;
    106 	}
    107 	sc->open = 0;
    108 	sc->intr = 0;
    109 	if (mpu_reset(sc) == 0)
    110 		return 1;
    111 bad:
    112 	return 0;
    113 }
    114 
    115 void
    116 mpu_attach(struct mpu_softc *sc)
    117 {
    118 	midi_attach_mi(&mpu_midi_hw_if, sc, sc->sc_dev);
    119 }
    120 
    121 static inline int
    122 mpu_waitready(struct mpu_softc *sc)
    123 {
    124 	int i;
    125 
    126 	for(i = 0; i < MPU_MAXWAIT; i++) {
    127 		if (!(MPU_GETSTATUS(sc->iot, sc->ioh) & MPU_OUTPUT_BUSY))
    128 			return 0;
    129 		delay(10);
    130 	}
    131 	return 1;
    132 }
    133 
    134 static int
    135 mpu_reset(struct mpu_softc *sc)
    136 {
    137 	bus_space_tag_t iot = sc->iot;
    138 	bus_space_handle_t ioh = sc->ioh;
    139 	int i;
    140 	int s;
    141 
    142 	if (mpu_waitready(sc)) {
    143 		DPRINTF(("%s: not ready\n", __func__));
    144 		return EIO;
    145 	}
    146 	s = splaudio();		/* Don't let the interrupt get our ACK. */
    147 	bus_space_write_1(iot, ioh, MPU_COMMAND, MPU_RESET);
    148 	for(i = 0; i < 2*MPU_MAXWAIT; i++) {
    149 		if (!(MPU_GETSTATUS(iot, ioh) & MPU_INPUT_EMPTY) &&
    150 		    bus_space_read_1(iot, ioh, MPU_DATA) == MPU_ACK) {
    151 			splx(s);
    152 			return 0;
    153 		}
    154 	}
    155 	splx(s);
    156 	DPRINTF(("%s: No ACK\n", __func__));
    157 	return EIO;
    158 }
    159 
    160 static int
    161 mpu_open(void *addr, int flags, void (*iintr)(void *, int),
    162     void (*ointr)(void *), void *arg)
    163 {
    164 	struct mpu_softc *sc = addr;
    165 
    166         DPRINTF(("%s: sc=%p\n", __func__, sc));
    167 
    168 	if (sc->open)
    169 		return EBUSY;
    170 #ifndef AUDIO_NO_POWER_CTL
    171 	if (sc->powerctl)
    172 		sc->powerctl(sc->powerarg, 1);
    173 #endif
    174 	if (mpu_reset(sc) != 0) {
    175 #ifndef AUDIO_NO_POWER_CTL
    176 		if (sc->powerctl)
    177 			sc->powerctl(sc->powerarg, 0);
    178 #endif
    179 		return EIO;
    180 	}
    181 
    182 	bus_space_write_1(sc->iot, sc->ioh, MPU_COMMAND, MPU_UART_MODE);
    183 	sc->open = 1;
    184 	sc->intr = iintr;
    185 	sc->arg = arg;
    186 	return 0;
    187 }
    188 
    189 static void
    190 mpu_close(void *addr)
    191 {
    192 	struct mpu_softc *sc = addr;
    193 
    194         DPRINTF(("%s: sc=%p\n", __func__, sc));
    195 
    196 	sc->open = 0;
    197 	sc->intr = 0;
    198 	mpu_reset(sc); /* exit UART mode */
    199 
    200 #ifndef AUDIO_NO_POWER_CTL
    201 	if (sc->powerctl)
    202 		sc->powerctl(sc->powerarg, 0);
    203 #endif
    204 }
    205 
    206 static void
    207 mpu_readinput(struct mpu_softc *sc)
    208 {
    209 	bus_space_tag_t iot = sc->iot;
    210 	bus_space_handle_t ioh = sc->ioh;
    211 	int data;
    212 
    213 	while(!(MPU_GETSTATUS(iot, ioh) & MPU_INPUT_EMPTY)) {
    214 		data = bus_space_read_1(iot, ioh, MPU_DATA);
    215 		DPRINTFN(3, ("%s: sc=%p 0x%02x\n", __func__, sc, data));
    216 		if (sc->intr)
    217 			sc->intr(sc->arg, data);
    218 	}
    219 }
    220 
    221 static int
    222 mpu_output(void *addr, int d)
    223 {
    224 	struct mpu_softc *sc = addr;
    225 	int s;
    226 
    227 	DPRINTFN(3, ("%s: sc=%p 0x%02x\n", __func__, sc, d));
    228 	if (!(MPU_GETSTATUS(sc->iot, sc->ioh) & MPU_INPUT_EMPTY)) {
    229 		s = splaudio();
    230 		mpu_readinput(sc);
    231 		splx(s);
    232 	}
    233 	if (mpu_waitready(sc)) {
    234 		DPRINTF(("%s:: not ready\n", __func__));
    235 		return EIO;
    236 	}
    237 	bus_space_write_1(sc->iot, sc->ioh, MPU_DATA, d);
    238 	return 0;
    239 }
    240 
    241 static void
    242 mpu_getinfo(void *addr, struct midi_info *mi)
    243 {
    244 	struct mpu_softc *sc = addr;
    245 
    246 	mi->name = sc->model;
    247 	mi->props = 0;
    248 }
    249 
    250 int
    251 mpu_intr(void *addr)
    252 {
    253 	struct mpu_softc *sc = addr;
    254 
    255 	if (MPU_GETSTATUS(sc->iot, sc->ioh) & MPU_INPUT_EMPTY) {
    256 		DPRINTF(("%s: no data\n", __func__));
    257 		return 0;
    258 	} else {
    259 		mpu_readinput(sc);
    260 		return 1;
    261 	}
    262 }
    263