Home | History | Annotate | Line # | Download | only in dev
mediabay.c revision 1.4
      1 /*	$NetBSD: mediabay.c,v 1.4 2001/07/22 11:29:46 wiz Exp $	*/
      2 
      3 /*-
      4  * Copyright (C) 1999 Tsubai Masanari.  All rights reserved.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  * 3. The name of the author may not be used to endorse or promote products
     15  *    derived from this software without specific prior written permission.
     16  *
     17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27  */
     28 
     29 #include <sys/param.h>
     30 #include <sys/device.h>
     31 #include <sys/kernel.h>
     32 #include <sys/kthread.h>
     33 #include <sys/systm.h>
     34 
     35 #include <dev/ofw/openfirm.h>
     36 
     37 #include <machine/autoconf.h>
     38 #include <machine/pio.h>
     39 
     40 struct mediabay_softc {
     41 	struct device sc_dev;
     42 	int sc_node;
     43 	u_int *sc_addr;
     44 	u_int *sc_fcr;
     45 	u_int sc_baseaddr;
     46 	struct device *sc_content;
     47 	struct proc *sc_kthread;
     48 };
     49 
     50 void mediabay_attach __P((struct device *, struct device *, void *));
     51 int mediabay_match __P((struct device *, struct cfdata *, void *));
     52 int mediabay_print __P((void *, const char *));
     53 void mediabay_attach_content __P((struct mediabay_softc *));
     54 int mediabay_intr __P((void *));
     55 void mediabay_create_kthread __P((void *));
     56 void mediabay_kthread __P((void *));
     57 
     58 struct cfattach mediabay_ca = {
     59 	sizeof(struct mediabay_softc), mediabay_match, mediabay_attach
     60 };
     61 
     62 #ifdef MEDIABAY_DEBUG
     63 # define DPRINTF printf
     64 #else
     65 # define DPRINTF while (0) printf
     66 #endif
     67 
     68 #define FCR_MEDIABAY_RESET	0x00000002
     69 #define FCR_MEDIABAY_IDE_ENABLE	0x00000008
     70 #define FCR_MEDIABAY_FD_ENABLE	0x00000010
     71 #define FCR_MEDIABAY_ENABLE	0x00000080
     72 #define FCR_MEDIABAY_CD_POWER	0x00800000
     73 
     74 #define MEDIABAY_ID(x)		(((x) >> 12) & 0xf)
     75 #define MEDIABAY_ID_FD		0
     76 #define MEDIABAY_ID_CD		3
     77 #define MEDIABAY_ID_NONE	7
     78 
     79 int
     80 mediabay_match(parent, cf, aux)
     81 	struct device *parent;
     82 	struct cfdata *cf;
     83 	void *aux;
     84 {
     85 	struct confargs *ca = aux;
     86 
     87 	if (strcmp(ca->ca_name, "media-bay") == 0)
     88 		return 1;
     89 
     90 	return 0;
     91 }
     92 
     93 /*
     94  * Attach all the sub-devices we can find
     95  */
     96 void
     97 mediabay_attach(parent, self, aux)
     98 	struct device *parent, *self;
     99 	void *aux;
    100 {
    101 	struct mediabay_softc *sc = (struct mediabay_softc *)self;
    102 	struct confargs *ca = aux;
    103 	int irq, type;
    104 
    105 	ca->ca_reg[0] += ca->ca_baseaddr;
    106 
    107 	sc->sc_addr = mapiodev(ca->ca_reg[0], NBPG);
    108 	sc->sc_fcr = sc->sc_addr + 1;
    109 	sc->sc_node = ca->ca_node;
    110 	sc->sc_baseaddr = ca->ca_baseaddr;
    111 	irq = ca->ca_intr[0];
    112 	type = IST_LEVEL;
    113 
    114 	if (ca->ca_nintr == 8 && ca->ca_intr[1] == 0)
    115 		type = IST_EDGE;
    116 
    117 	printf(" irq %d %s\n", irq, intr_typename(type));
    118 	intr_establish(irq, type, IPL_BIO, mediabay_intr, sc);
    119 
    120 	kthread_create(mediabay_create_kthread, sc);
    121 
    122 	sc->sc_content = NULL;
    123 
    124 	if (MEDIABAY_ID(in32rb(sc->sc_addr)) != MEDIABAY_ID_NONE)
    125 		mediabay_attach_content(sc);
    126 }
    127 
    128 void
    129 mediabay_attach_content(sc)
    130 	struct mediabay_softc *sc;
    131 {
    132 	int child;
    133 	u_int fcr;
    134 	struct device *content;
    135 	struct confargs ca;
    136 	u_int reg[20], intr[5];
    137 	char name[32];
    138 
    139 	fcr = in32rb(sc->sc_fcr);
    140 	fcr |= FCR_MEDIABAY_ENABLE | FCR_MEDIABAY_RESET;
    141 	out32rb(sc->sc_fcr, fcr);
    142 	delay(50000);
    143 
    144 	fcr &= ~FCR_MEDIABAY_RESET;
    145 	out32rb(sc->sc_fcr, fcr);
    146 	delay(50000);
    147 
    148 	fcr |= FCR_MEDIABAY_IDE_ENABLE | FCR_MEDIABAY_CD_POWER;
    149 	out32rb(sc->sc_fcr, fcr);
    150 	delay(50000);
    151 
    152 	for (child = OF_child(sc->sc_node); child; child = OF_peer(child)) {
    153 		memset(name, 0, sizeof(name));
    154 		if (OF_getprop(child, "name", name, sizeof(name)) == -1)
    155 			continue;
    156 		ca.ca_name = name;
    157 		ca.ca_node = child;
    158 		ca.ca_baseaddr = sc->sc_baseaddr;
    159 
    160 		ca.ca_nreg  = OF_getprop(child, "reg", reg, sizeof(reg));
    161 		ca.ca_nintr = OF_getprop(child, "AAPL,interrupts", intr,
    162 				sizeof(intr));
    163 		if (ca.ca_nintr == -1)
    164 			ca.ca_nintr = OF_getprop(child, "interrupts", intr,
    165 					sizeof(intr));
    166 		ca.ca_reg = reg;
    167 		ca.ca_intr = intr;
    168 
    169 		content = config_found(&sc->sc_dev, &ca, mediabay_print);
    170 		if (content) {
    171 			sc->sc_content = content;
    172 			return;
    173 		}
    174 	}
    175 
    176 	/* No devices found.  Disable media-bay. */
    177 	fcr &= ~(FCR_MEDIABAY_ENABLE | FCR_MEDIABAY_IDE_ENABLE |
    178 		 FCR_MEDIABAY_CD_POWER | FCR_MEDIABAY_FD_ENABLE);
    179 	out32rb(sc->sc_fcr, fcr);
    180 }
    181 
    182 int
    183 mediabay_print(aux, mediabay)
    184 	void *aux;
    185 	const char *mediabay;
    186 {
    187 	struct confargs *ca = aux;
    188 
    189 	if (mediabay == NULL && ca->ca_nreg > 0)
    190 		printf(" offset 0x%x", ca->ca_reg[0]);
    191 
    192 	return QUIET;
    193 }
    194 
    195 int
    196 mediabay_intr(v)
    197 	void *v;
    198 {
    199 	struct mediabay_softc *sc = v;
    200 
    201 	wakeup(&sc->sc_kthread);
    202 	return 1;
    203 }
    204 
    205 void
    206 mediabay_create_kthread(v)
    207 	void *v;
    208 {
    209 	struct mediabay_softc *sc = v;
    210 
    211 	kthread_create1(mediabay_kthread, sc, &sc->sc_kthread, "media-bay");
    212 }
    213 
    214 void
    215 mediabay_kthread(v)
    216 	void *v;
    217 {
    218 	struct mediabay_softc *sc = v;
    219 	u_int x, fcr;
    220 
    221 sleep:
    222 	tsleep(&sc->sc_kthread, PRIBIO, "mbayev", 0);
    223 
    224 	/* sleep 0.25 sec */
    225 	tsleep(mediabay_kthread, PRIBIO, "mbayev", hz/4);
    226 
    227 	DPRINTF("%s: ", sc->sc_dev.dv_xname);
    228 	x = in32rb(sc->sc_addr);
    229 
    230 	switch (MEDIABAY_ID(x)) {
    231 	case MEDIABAY_ID_NONE:
    232 		DPRINTF("removed\n");
    233 		if (sc->sc_content != NULL) {
    234 			config_detach(sc->sc_content, DETACH_FORCE);
    235 			DPRINTF("%s: detach done\n", sc->sc_dev.dv_xname);
    236 			sc->sc_content = NULL;
    237 
    238 			/* disable media-bay */
    239 			fcr = in32rb(sc->sc_fcr);
    240 			fcr &= ~(FCR_MEDIABAY_ENABLE |
    241 				 FCR_MEDIABAY_IDE_ENABLE |
    242 				 FCR_MEDIABAY_CD_POWER |
    243 				 FCR_MEDIABAY_FD_ENABLE);
    244 			out32rb(sc->sc_fcr, fcr);
    245 		}
    246 		break;
    247 	case MEDIABAY_ID_FD:
    248 		DPRINTF("FD inserted\n");
    249 		break;
    250 	case MEDIABAY_ID_CD:
    251 		DPRINTF("CD inserted\n");
    252 
    253 		if (sc->sc_content == NULL)
    254 			mediabay_attach_content(sc);
    255 		break;
    256 	default:
    257 		printf("unknown event (0x%x)\n", x);
    258 	}
    259 
    260 	goto sleep;
    261 }
    262 
    263 /* PBG3: 0x7025X0c0 */
    264 /* 2400: 0x0070X0a8 */
    265