1 /* $NetBSD: esl_pcmcia.c,v 1.8 2002/10/02 16:52:06 thorpej Exp $ */
2
3 /*
4 * Copyright (c) 2000 Jared D. McNeill <jmcneill@invisible.yi.org>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Jared D. McNeill.
18 * 4. Neither the name of the author nor the names of any contributors may
19 * be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
34 */
35
36 #include <sys/cdefs.h>
37 __KERNEL_RCSID(0, "$NetBSD: esl_pcmcia.c,v 1.8 2002/10/02 16:52:06 thorpej Exp $");
38
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/device.h>
42 #include <sys/buf.h>
43 #include <sys/audioio.h>
44
45 #include <machine/bus.h>
46 #include <machine/intr.h>
47
48 #include <dev/audio_if.h>
49
50 #include <dev/pcmcia/pcmciareg.h>
51 #include <dev/pcmcia/pcmciavar.h>
52 #include <dev/pcmcia/pcmciadevs.h>
53
54 #include <dev/isa/essreg.h>
55 #include <dev/pcmcia/eslvar.h>
56
57 static const struct esl_pcmcia_product {
58 char *name;
59 int32_t manufacturer;
60 int32_t product;
61 char *cis_info[4];
62 int function;
63 } esl_pcmcia_products[] = {
64 { PCMCIA_STR_EIGERLABS_EPX_AA2000,
65 PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID,
66 PCMCIA_CIS_EIGERLABS_EPX_AA2000, 0 },
67
68 { NULL }
69 };
70
71 int esl_pcmcia_match(struct device *, struct cfdata *, void *);
72 void esl_pcmcia_attach(struct device *, struct device *, void *);
73 int esl_pcmcia_detach(struct device *, int);
74
75 int esl_pcmcia_enable(struct esl_pcmcia_softc *);
76 void esl_pcmcia_disable(struct esl_pcmcia_softc *);
77
78 CFATTACH_DECL(esl_pcmcia, sizeof(struct esl_pcmcia_softc),
79 esl_pcmcia_match, esl_pcmcia_attach, esl_pcmcia_detach, NULL);
80
81 #define ESL_NDEVS (sizeof(esl_pcmcia_products) / sizeof(esl_pcmcia_products[0]))
82
83 #define esl_pcmcia_product_lookup(card, fct, n) \
84 (((card)->manufacturer != PCMCIA_VENDOR_INVALID) && \
85 ((card)->product != PCMCIA_PRODUCT_INVALID) && \
86 (esl_pcmcia_products[(n)].cis_info[0]) && \
87 (esl_pcmcia_products[(n)].cis_info[1]) && \
88 (strcmp((card)->cis1_info[0], esl_pcmcia_products[(n)].cis_info[0]) \
89 == 0) && \
90 (strcmp((card)->cis1_info[1], esl_pcmcia_products[(n)].cis_info[1]) \
91 == 0) && \
92 ((fct) == esl_pcmcia_products[(n)].function) ? \
93 &esl_pcmcia_products[(n)] : NULL)
94
95 int
96 esl_pcmcia_match(struct device *parent, struct cfdata *match, void *aux)
97 {
98 struct pcmcia_attach_args *pa = aux;
99 int i;
100
101 for (i = 0; i < ESL_NDEVS; i++)
102 if (esl_pcmcia_product_lookup(pa->card, pa->pf->number, i))
103 return (2);
104
105 return (0);
106 }
107
108 void
109 esl_pcmcia_attach(struct device *parent, struct device *self, void *aux)
110 {
111 struct esl_pcmcia_softc *esc = (void *)self;
112 struct pcmcia_attach_args *pa = aux;
113 struct pcmcia_config_entry *cfe;
114 struct pcmcia_function *pf = pa->pf;
115 const struct esl_pcmcia_product *pp;
116 int i;
117
118 esc->sc_pf = pf;
119
120 SIMPLEQ_FOREACH(cfe, &pf->cfe_head, cfe_list) {
121 if (cfe->num_memspace != 0 ||
122 cfe->num_iospace != 1)
123 continue;
124
125 if (pcmcia_io_alloc(pa->pf, cfe->iospace[0].start,
126 cfe->iospace[0].length, 0, &esc->sc_pcioh) == 0)
127 break;
128 }
129
130 if (cfe == 0) {
131 printf(": can't alloc i/o space\n");
132 goto no_config_entry;
133 }
134
135 /* Setup power management hooks */
136 esc->sc_enable = esl_pcmcia_enable;
137 esc->sc_disable = esl_pcmcia_disable;
138
139 /* Enable the card. */
140 pcmcia_function_init(pf, cfe);
141 if (pcmcia_function_enable(pf)) {
142 printf(": function enable failed\n");
143 goto enable_failed;
144 }
145
146 /* Map in the I/O space */
147 if (pcmcia_io_map(pa->pf, PCMCIA_WIDTH_AUTO, 0, esc->sc_pcioh.size,
148 &esc->sc_pcioh, &esc->sc_io_window)) {
149 printf(": can't map i/o space\n");
150 goto iomap_failed;
151 }
152
153 pp = NULL;
154 for (i = 0; i < ESL_NDEVS; i++) {
155 pp = esl_pcmcia_product_lookup(pa->card, pa->pf->number, i);
156 if (pp != NULL)
157 break;
158 }
159
160 if (pp == NULL) {
161 printf("\n");
162 panic("esl_pcmcia_attach: impossible");
163 }
164
165 printf(": %s\n", pp->name);
166
167 if (esl_init(esc)) {
168 printf("esl_init: failed\n");
169 goto init_failed;
170 }
171
172 pcmcia_function_disable(esc->sc_pf);
173 return;
174
175 init_failed:
176 /* Unmap I/O space */
177 pcmcia_io_unmap(esc->sc_pf, esc->sc_io_window);
178
179 iomap_failed:
180 /* Disable the device. */
181 pcmcia_function_disable(esc->sc_pf);
182
183 enable_failed:
184 /* Free our I/O space. */
185 pcmcia_io_free(esc->sc_pf, &esc->sc_pcioh);
186
187 no_config_entry:
188 return;
189 }
190
191 int
192 esl_pcmcia_detach(struct device *self, int flags)
193 {
194 struct esl_pcmcia_softc *esc = (void *)self;
195 int rv = 0;
196
197 if (esc->sc_io_window == -1)
198 /* Nothing to detach */
199 return (0);
200
201 if (esc->sc_opldev != NULL)
202 config_detach(esc->sc_opldev, flags);
203 if (esc->sc_audiodev != NULL)
204 rv = config_detach(esc->sc_audiodev, flags);
205 if (rv)
206 return (rv);
207
208 /* unmap i/o window and i/o space */
209 pcmcia_io_unmap(esc->sc_pf, esc->sc_io_window);
210 pcmcia_io_free(esc->sc_pf, &esc->sc_pcioh);
211
212 return (rv);
213 }
214
215 int
216 esl_pcmcia_enable(struct esl_pcmcia_softc *sc)
217 {
218
219 /* Establish an interrupt */
220 sc->sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_AUDIO, esl_intr,
221 sc);
222 if (sc->sc_ih == NULL) {
223 printf("%s: couldn't establish interrupt\n",
224 sc->sc_esl.sc_dev.dv_xname);
225 goto fail_1;
226 }
227
228 if (pcmcia_function_enable(sc->sc_pf))
229 goto fail_2;
230
231 return (0);
232
233 fail_2:
234 pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih);
235 fail_1:
236 return (1);
237 }
238
239 void
240 esl_pcmcia_disable(struct esl_pcmcia_softc *sc)
241 {
242
243 pcmcia_function_disable(sc->sc_pf);
244 pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih);
245 }
Cache object: 4dbf8e9534d11e085adc25f188a2dbd4
|