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