pcmcia.c revision 1.1.2.8 1 1.1.2.1 marc #define PCMCIADEBUG
2 1.1.2.1 marc
3 1.1.2.1 marc #include <sys/types.h>
4 1.1.2.1 marc #include <sys/param.h>
5 1.1.2.1 marc #include <sys/systm.h>
6 1.1.2.1 marc #include <sys/device.h>
7 1.1.2.1 marc
8 1.1.2.1 marc /* XXX only needed for intr debugging */
9 1.1.2.1 marc #include <vm/vm.h>
10 1.1.2.1 marc
11 1.1.2.1 marc #include <dev/pcmcia/pcmciareg.h>
12 1.1.2.1 marc #include <dev/pcmcia/pcmciachip.h>
13 1.1.2.1 marc #include <dev/pcmcia/pcmciavar.h>
14 1.1.2.1 marc
15 1.1.2.1 marc #ifdef PCMCIADEBUG
16 1.1.2.3 thorpej int pcmcia_debug = 0;
17 1.1.2.3 thorpej #define DPRINTF(arg) if (pcmcia_debug) printf arg
18 1.1.2.1 marc #else
19 1.1.2.1 marc #define DPRINTF(arg)
20 1.1.2.1 marc #endif
21 1.1.2.1 marc
22 1.1.2.5 thorpej #ifdef PCMCIAVERBOSE
23 1.1.2.5 thorpej int pcmcia_verbose = 1;
24 1.1.2.5 thorpej #else
25 1.1.2.5 thorpej int pcmcia_verbose = 0;
26 1.1.2.5 thorpej #endif
27 1.1.2.5 thorpej
28 1.1.2.1 marc #ifdef __BROKEN_INDIRECT_CONFIG
29 1.1.2.1 marc int pcmcia_match __P((struct device *, void *, void *));
30 1.1.2.1 marc int pcmcia_submatch __P((struct device *, void *, void *));
31 1.1.2.1 marc #else
32 1.1.2.1 marc int pcmcia_match __P((struct device *, struct cfdata *, void *));
33 1.1.2.1 marc int pcmcia_submatch __P((struct device *, struct cfdata *, void *));
34 1.1.2.1 marc #endif
35 1.1.2.1 marc void pcmcia_attach __P((struct device *, struct device *, void *));
36 1.1.2.1 marc int pcmcia_print __P((void *, const char *));
37 1.1.2.1 marc
38 1.1.2.1 marc int pcmcia_card_intr __P((void *));
39 1.1.2.1 marc
40 1.1.2.1 marc struct cfdriver pcmcia_cd = {
41 1.1.2.1 marc NULL, "pcmcia", DV_DULL
42 1.1.2.1 marc };
43 1.1.2.1 marc
44 1.1.2.1 marc struct cfattach pcmcia_ca = {
45 1.1.2.1 marc sizeof(struct pcmcia_softc), pcmcia_match, pcmcia_attach
46 1.1.2.1 marc };
47 1.1.2.1 marc
48 1.1.2.1 marc int
49 1.1.2.1 marc pcmcia_ccr_read(pf, ccr)
50 1.1.2.1 marc struct pcmcia_function *pf;
51 1.1.2.1 marc int ccr;
52 1.1.2.1 marc {
53 1.1.2.5 thorpej return(bus_space_read_1(pf->pf_ccrt, pf->pf_ccrh,
54 1.1.2.5 thorpej pf->pf_ccr_offset + ccr));
55 1.1.2.1 marc }
56 1.1.2.1 marc
57 1.1.2.1 marc void
58 1.1.2.1 marc pcmcia_ccr_write(pf, ccr, val)
59 1.1.2.1 marc struct pcmcia_function *pf;
60 1.1.2.1 marc int ccr;
61 1.1.2.1 marc int val;
62 1.1.2.1 marc {
63 1.1.2.5 thorpej if ((pf->ccr_mask) & (1 << (ccr / 2))) {
64 1.1.2.5 thorpej bus_space_write_1(pf->pf_ccrt, pf->pf_ccrh,
65 1.1.2.5 thorpej pf->pf_ccr_offset + ccr, val);
66 1.1.2.1 marc }
67 1.1.2.1 marc }
68 1.1.2.1 marc
69 1.1.2.1 marc int
70 1.1.2.1 marc pcmcia_match(parent, match, aux)
71 1.1.2.1 marc struct device *parent;
72 1.1.2.1 marc #ifdef __BROKEN_INDIRECT_CONFIG
73 1.1.2.1 marc void *match;
74 1.1.2.1 marc #else
75 1.1.2.1 marc struct cfdata *match;
76 1.1.2.1 marc #endif
77 1.1.2.1 marc void *aux;
78 1.1.2.1 marc {
79 1.1.2.1 marc /* if the autoconfiguration got this far, there's a socket here */
80 1.1.2.1 marc
81 1.1.2.1 marc return(1);
82 1.1.2.1 marc }
83 1.1.2.1 marc
84 1.1.2.1 marc void
85 1.1.2.1 marc pcmcia_attach(parent, self, aux)
86 1.1.2.1 marc struct device *parent, *self;
87 1.1.2.1 marc void *aux;
88 1.1.2.1 marc {
89 1.1.2.1 marc struct pcmciabus_attach_args *paa = (struct pcmciabus_attach_args *) aux;
90 1.1.2.1 marc struct pcmcia_softc *sc = (struct pcmcia_softc *) self;
91 1.1.2.1 marc
92 1.1.2.1 marc printf("\n");
93 1.1.2.1 marc
94 1.1.2.1 marc sc->pct = paa->pct;
95 1.1.2.1 marc sc->pch = paa->pch;
96 1.1.2.1 marc
97 1.1.2.1 marc sc->ih = NULL;
98 1.1.2.1 marc }
99 1.1.2.1 marc
100 1.1.2.1 marc int
101 1.1.2.8 marc pcmcia_card_attach(dev)
102 1.1.2.1 marc struct device *dev;
103 1.1.2.1 marc {
104 1.1.2.1 marc struct pcmcia_softc *sc = (struct pcmcia_softc *) dev;
105 1.1.2.1 marc struct pcmcia_function *pf;
106 1.1.2.1 marc struct pcmcia_attach_args paa;
107 1.1.2.1 marc int attached;
108 1.1.2.1 marc
109 1.1.2.8 marc /* this is here so that when socket_enable calls gettype, trt happens */
110 1.1.2.8 marc sc->card.pf_head.sqh_first = NULL;
111 1.1.2.8 marc
112 1.1.2.8 marc pcmcia_chip_socket_enable(sc->pct, sc->pch);
113 1.1.2.8 marc
114 1.1.2.1 marc pcmcia_read_cis(sc);
115 1.1.2.1 marc
116 1.1.2.8 marc pcmcia_chip_socket_disable(sc->pct, sc->pch);
117 1.1.2.8 marc
118 1.1.2.1 marc /* bail now if the card has no functions, or if there was an error
119 1.1.2.1 marc in the cis. */
120 1.1.2.1 marc
121 1.1.2.1 marc if (sc->card.error)
122 1.1.2.1 marc return(1);
123 1.1.2.1 marc if (!sc->card.pf_head.sqh_first)
124 1.1.2.1 marc return(1);
125 1.1.2.1 marc
126 1.1.2.5 thorpej if (pcmcia_verbose)
127 1.1.2.5 thorpej pcmcia_print_cis(sc);
128 1.1.2.1 marc
129 1.1.2.1 marc attached = 0;
130 1.1.2.1 marc
131 1.1.2.1 marc for (pf = sc->card.pf_head.sqh_first; pf; pf = pf->pf_list.sqe_next) {
132 1.1.2.1 marc if (pf->cfe_head.sqh_first == NULL)
133 1.1.2.1 marc continue;
134 1.1.2.1 marc
135 1.1.2.1 marc pf->sc = sc;
136 1.1.2.1 marc pf->cfe = NULL;
137 1.1.2.1 marc pf->ih_fct = NULL;
138 1.1.2.1 marc pf->ih_arg = NULL;
139 1.1.2.1 marc }
140 1.1.2.1 marc
141 1.1.2.1 marc for (pf = sc->card.pf_head.sqh_first; pf; pf = pf->pf_list.sqe_next) {
142 1.1.2.1 marc if (pf->cfe_head.sqh_first == NULL)
143 1.1.2.1 marc continue;
144 1.1.2.1 marc
145 1.1.2.1 marc paa.manufacturer = sc->card.manufacturer;
146 1.1.2.1 marc paa.product = sc->card.product;
147 1.1.2.1 marc paa.card = &sc->card;
148 1.1.2.1 marc paa.pf = pf;
149 1.1.2.1 marc
150 1.1.2.1 marc if (config_found_sm(&sc->dev, &paa, pcmcia_print, pcmcia_submatch)) {
151 1.1.2.1 marc attached++;
152 1.1.2.1 marc
153 1.1.2.1 marc DPRINTF(("%s: function %d CCR at %d offset %lx: %x %x %x %x, %x %x %x %x, %x\n",
154 1.1.2.1 marc sc->dev.dv_xname, pf->number,
155 1.1.2.5 thorpej pf->pf_ccr_window, pf->pf_ccr_offset,
156 1.1.2.1 marc pcmcia_ccr_read(pf, 0x00),
157 1.1.2.1 marc pcmcia_ccr_read(pf, 0x02), pcmcia_ccr_read(pf, 0x04),
158 1.1.2.1 marc pcmcia_ccr_read(pf, 0x06), pcmcia_ccr_read(pf, 0x0A),
159 1.1.2.1 marc pcmcia_ccr_read(pf, 0x0C), pcmcia_ccr_read(pf, 0x0E),
160 1.1.2.1 marc pcmcia_ccr_read(pf, 0x10), pcmcia_ccr_read(pf, 0x12)));
161 1.1.2.1 marc }
162 1.1.2.1 marc }
163 1.1.2.1 marc
164 1.1.2.1 marc return(attached?0:1);
165 1.1.2.1 marc }
166 1.1.2.1 marc
167 1.1.2.1 marc void
168 1.1.2.8 marc pcmcia_card_detach(dev)
169 1.1.2.1 marc struct device *dev;
170 1.1.2.1 marc {
171 1.1.2.1 marc /* struct pcmcia_softc *sc = (struct pcmcia_softc *) dev; */
172 1.1.2.1 marc /* don't do anything yet */
173 1.1.2.1 marc }
174 1.1.2.1 marc
175 1.1.2.1 marc int
176 1.1.2.1 marc #ifdef __BROKEN_INDIRECT_CONFIG
177 1.1.2.1 marc pcmcia_submatch(parent, match, aux)
178 1.1.2.1 marc #else
179 1.1.2.1 marc pcmcia_submatch(parent, cf, aux)
180 1.1.2.1 marc #endif
181 1.1.2.1 marc struct device *parent;
182 1.1.2.1 marc #ifdef __BROKEN_INDIRECT_CONFIG
183 1.1.2.1 marc void *match;
184 1.1.2.1 marc #else
185 1.1.2.1 marc struct cfdata *cf;
186 1.1.2.1 marc #endif
187 1.1.2.1 marc void *aux;
188 1.1.2.1 marc {
189 1.1.2.1 marc #ifdef __BROKEN_INDIRECT_CONFIG
190 1.1.2.1 marc struct cfdata *cf = match;
191 1.1.2.1 marc #endif
192 1.1.2.1 marc
193 1.1.2.1 marc struct pcmcia_attach_args *paa = (struct pcmcia_attach_args *) aux;
194 1.1.2.1 marc
195 1.1.2.1 marc if (cf->cf_loc[0] != -1 && cf->cf_loc[0] != paa->pf->number)
196 1.1.2.1 marc return(0);
197 1.1.2.1 marc
198 1.1.2.1 marc return ((*cf->cf_attach->ca_match)(parent, cf, aux));
199 1.1.2.1 marc }
200 1.1.2.1 marc
201 1.1.2.1 marc int
202 1.1.2.1 marc pcmcia_print(arg, pnp)
203 1.1.2.1 marc void *arg;
204 1.1.2.1 marc const char *pnp;
205 1.1.2.1 marc {
206 1.1.2.5 thorpej struct pcmcia_attach_args *pa = (struct pcmcia_attach_args *) arg;
207 1.1.2.5 thorpej struct pcmcia_softc *sc = pa->pf->sc;
208 1.1.2.5 thorpej struct pcmcia_card *card = &sc->card;
209 1.1.2.5 thorpej int i;
210 1.1.2.5 thorpej
211 1.1.2.5 thorpej if (pnp) {
212 1.1.2.5 thorpej for (i = 0; i < 4; i++) {
213 1.1.2.5 thorpej if (!card->cis1_info[i])
214 1.1.2.5 thorpej break;
215 1.1.2.5 thorpej if (i)
216 1.1.2.5 thorpej printf(", ");
217 1.1.2.5 thorpej printf("%s", card->cis1_info[i]);
218 1.1.2.5 thorpej }
219 1.1.2.5 thorpej if (i)
220 1.1.2.5 thorpej printf(" ");
221 1.1.2.5 thorpej printf("(manufacturer 0x%x, product 0x%x)", card->manufacturer,
222 1.1.2.5 thorpej card->product);
223 1.1.2.5 thorpej }
224 1.1.2.1 marc
225 1.1.2.5 thorpej printf(" function %d", pa->pf->number);
226 1.1.2.1 marc
227 1.1.2.1 marc return(UNCONF);
228 1.1.2.1 marc }
229 1.1.2.1 marc
230 1.1.2.8 marc int pcmcia_card_gettype(dev)
231 1.1.2.8 marc struct device *dev;
232 1.1.2.8 marc {
233 1.1.2.8 marc struct pcmcia_softc *sc = (struct pcmcia_softc *) dev;
234 1.1.2.8 marc
235 1.1.2.8 marc /* set the iftype to memory if this card has no functions (not yet
236 1.1.2.8 marc probed), or only one function, and that is memory. */
237 1.1.2.8 marc if (!sc->card.pf_head.sqh_first ||
238 1.1.2.8 marc (sc->card.pf_head.sqh_first &&
239 1.1.2.8 marc !sc->card.pf_head.sqh_first->pf_list.sqe_next &&
240 1.1.2.8 marc (sc->card.pf_head.sqh_first->cfe_head.sqh_first->iftype ==
241 1.1.2.8 marc PCMCIA_IFTYPE_MEMORY)))
242 1.1.2.8 marc return(PCMCIA_IFTYPE_MEMORY);
243 1.1.2.8 marc else
244 1.1.2.8 marc return(PCMCIA_IFTYPE_IO);
245 1.1.2.8 marc }
246 1.1.2.8 marc
247 1.1.2.7 thorpej /* Initialize a PCMCIA function. May be called as long as the function
248 1.1.2.7 thorpej is disabled. */
249 1.1.2.7 thorpej void
250 1.1.2.7 thorpej pcmcia_function_init(pf, cfe)
251 1.1.2.1 marc struct pcmcia_function *pf;
252 1.1.2.1 marc struct pcmcia_config_entry *cfe;
253 1.1.2.1 marc {
254 1.1.2.7 thorpej
255 1.1.2.7 thorpej if (pf->pf_flags & PFF_ENABLED)
256 1.1.2.7 thorpej panic("pcmcia_function_init: function is enabled");
257 1.1.2.7 thorpej
258 1.1.2.7 thorpej /* Remember which configuration entry we are using. */
259 1.1.2.7 thorpej pf->cfe = cfe;
260 1.1.2.7 thorpej }
261 1.1.2.7 thorpej
262 1.1.2.7 thorpej /* Enable a PCMCIA function */
263 1.1.2.7 thorpej int
264 1.1.2.7 thorpej pcmcia_function_enable(pf)
265 1.1.2.7 thorpej struct pcmcia_function *pf;
266 1.1.2.7 thorpej {
267 1.1.2.1 marc struct pcmcia_function *tmp;
268 1.1.2.1 marc int reg;
269 1.1.2.1 marc
270 1.1.2.7 thorpej if (pf->cfe == NULL)
271 1.1.2.7 thorpej panic("pcmcia_function_enable: function not initialized");
272 1.1.2.7 thorpej if (pf->pf_flags & PFF_ENABLED)
273 1.1.2.7 thorpej panic("pcmcia_function_enable: function already enabled");
274 1.1.2.7 thorpej
275 1.1.2.7 thorpej /* Increase the reference count on the socket, enabling power,
276 1.1.2.7 thorpej if necessary. */
277 1.1.2.7 thorpej if (pf->sc->sc_enabled_count++ == 0)
278 1.1.2.7 thorpej pcmcia_chip_socket_enable(pf->sc->pct, pf->sc->pch);
279 1.1.2.1 marc
280 1.1.2.1 marc /* it's possible for different functions' CCRs to be in the same
281 1.1.2.1 marc underlying page. Check for that. */
282 1.1.2.1 marc
283 1.1.2.1 marc for (tmp = pf->sc->card.pf_head.sqh_first;
284 1.1.2.1 marc tmp;
285 1.1.2.1 marc tmp = tmp->pf_list.sqe_next) {
286 1.1.2.7 thorpej if ((tmp->pf_flags & PFF_ENABLED) &&
287 1.1.2.5 thorpej (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) &&
288 1.1.2.1 marc ((pf->ccr_base+PCMCIA_CCR_SIZE) <=
289 1.1.2.5 thorpej (tmp->ccr_base - tmp->pf_ccr_offset + tmp->pf_ccr_realsize))) {
290 1.1.2.5 thorpej pf->pf_ccrt = tmp->pf_ccrt;
291 1.1.2.5 thorpej pf->pf_ccrh = tmp->pf_ccrh;
292 1.1.2.5 thorpej pf->pf_ccr_realsize = tmp->pf_ccr_realsize;
293 1.1.2.5 thorpej
294 1.1.2.5 thorpej /* pf->pf_ccr_offset =
295 1.1.2.5 thorpej (tmp->pf_ccr_offset - tmp->ccr_base) + pf->ccr_base; */
296 1.1.2.5 thorpej pf->pf_ccr_offset =
297 1.1.2.5 thorpej (tmp->pf_ccr_offset + pf->ccr_base) - tmp->ccr_base;
298 1.1.2.5 thorpej pf->pf_ccr_window = tmp->pf_ccr_window;
299 1.1.2.1 marc break;
300 1.1.2.1 marc }
301 1.1.2.1 marc }
302 1.1.2.1 marc
303 1.1.2.1 marc if (tmp == NULL) {
304 1.1.2.5 thorpej if (pcmcia_mem_alloc(pf, PCMCIA_CCR_SIZE, &pf->pf_pcmh))
305 1.1.2.7 thorpej goto bad;
306 1.1.2.1 marc
307 1.1.2.5 thorpej if (pcmcia_mem_map(pf, PCMCIA_MEM_ATTR, pf->ccr_base,
308 1.1.2.5 thorpej PCMCIA_CCR_SIZE, &pf->pf_pcmh,
309 1.1.2.7 thorpej &pf->pf_ccr_offset, &pf->pf_ccr_window)) {
310 1.1.2.7 thorpej pcmcia_mem_free(pf, &pf->pf_pcmh);
311 1.1.2.7 thorpej goto bad;
312 1.1.2.7 thorpej }
313 1.1.2.1 marc }
314 1.1.2.1 marc
315 1.1.2.1 marc DPRINTF(("%s: function %d CCR at %d offset %lx: %x %x %x %x, %x %x %x %x, %x\n",
316 1.1.2.1 marc pf->sc->dev.dv_xname, pf->number,
317 1.1.2.5 thorpej pf->pf_ccr_window, pf->pf_ccr_offset,
318 1.1.2.1 marc pcmcia_ccr_read(pf, 0x00),
319 1.1.2.1 marc pcmcia_ccr_read(pf, 0x02), pcmcia_ccr_read(pf, 0x04),
320 1.1.2.1 marc pcmcia_ccr_read(pf, 0x06), pcmcia_ccr_read(pf, 0x0A),
321 1.1.2.1 marc pcmcia_ccr_read(pf, 0x0C), pcmcia_ccr_read(pf, 0x0E),
322 1.1.2.1 marc pcmcia_ccr_read(pf, 0x10), pcmcia_ccr_read(pf, 0x12)));
323 1.1.2.1 marc
324 1.1.2.1 marc reg = (pf->cfe->number & PCMCIA_CCR_OPTION_CFINDEX);
325 1.1.2.1 marc reg |= PCMCIA_CCR_OPTION_LEVIREQ;
326 1.1.2.1 marc if (pcmcia_mfc(pf->sc))
327 1.1.2.1 marc reg |= PCMCIA_CCR_OPTION_FUNC_ENABLE;
328 1.1.2.1 marc pcmcia_ccr_write(pf, PCMCIA_CCR_OPTION, reg);
329 1.1.2.1 marc
330 1.1.2.1 marc reg = 0;
331 1.1.2.8 marc
332 1.1.2.1 marc if ((pf->cfe->flags & PCMCIA_CFE_IO16) == 0)
333 1.1.2.1 marc reg |= PCMCIA_CCR_STATUS_IOIS8;
334 1.1.2.1 marc if (pf->cfe->flags & PCMCIA_CFE_AUDIO)
335 1.1.2.1 marc reg |= PCMCIA_CCR_STATUS_AUDIO;
336 1.1.2.7 thorpej /* Not really needed, since we start with 0. */
337 1.1.2.7 thorpej if (pf->cfe->flags & PCMCIA_CFE_POWERDOWN)
338 1.1.2.7 thorpej reg &= ~PCMCIA_CCR_STATUS_PWRDWN;
339 1.1.2.1 marc pcmcia_ccr_write(pf, PCMCIA_CCR_STATUS, reg);
340 1.1.2.1 marc
341 1.1.2.1 marc pcmcia_ccr_write(pf, PCMCIA_CCR_SOCKETCOPY, 0);
342 1.1.2.1 marc
343 1.1.2.7 thorpej pf->pf_flags |= PFF_ENABLED;
344 1.1.2.1 marc return(0);
345 1.1.2.7 thorpej
346 1.1.2.7 thorpej bad:
347 1.1.2.8 marc /* Decrement the reference count, and power down the socket,
348 1.1.2.7 thorpej if necessary. */
349 1.1.2.7 thorpej if (pf->sc->sc_enabled_count-- == 1)
350 1.1.2.7 thorpej pcmcia_chip_socket_disable(pf->sc->pct, pf->sc->pch);
351 1.1.2.7 thorpej return (1);
352 1.1.2.7 thorpej }
353 1.1.2.7 thorpej
354 1.1.2.7 thorpej /* Disable PCMCIA function. */
355 1.1.2.7 thorpej void
356 1.1.2.7 thorpej pcmcia_function_disable(pf)
357 1.1.2.7 thorpej struct pcmcia_function *pf;
358 1.1.2.7 thorpej {
359 1.1.2.7 thorpej struct pcmcia_function *tmp;
360 1.1.2.7 thorpej int reg;
361 1.1.2.7 thorpej
362 1.1.2.7 thorpej if (pf->cfe == NULL)
363 1.1.2.7 thorpej panic("pcmcia_function_enable: function not initialized");
364 1.1.2.7 thorpej
365 1.1.2.7 thorpej /* Power down the function if the card supports it. */
366 1.1.2.7 thorpej if (pf->cfe->flags & PCMCIA_CFE_POWERDOWN) {
367 1.1.2.7 thorpej reg = pcmcia_ccr_read(pf, PCMCIA_CCR_STATUS);
368 1.1.2.7 thorpej reg |= PCMCIA_CCR_STATUS_PWRDWN;
369 1.1.2.7 thorpej pcmcia_ccr_write(pf, PCMCIA_CCR_STATUS, reg);
370 1.1.2.7 thorpej }
371 1.1.2.7 thorpej
372 1.1.2.7 thorpej /* it's possible for different functions' CCRs to be in the same
373 1.1.2.7 thorpej underlying page. Check for that. Note we mark us as disabled
374 1.1.2.7 thorpej first to avoid matching ourself. */
375 1.1.2.7 thorpej
376 1.1.2.7 thorpej pf->pf_flags &= ~PFF_ENABLED;
377 1.1.2.7 thorpej for (tmp = pf->sc->card.pf_head.sqh_first;
378 1.1.2.7 thorpej tmp;
379 1.1.2.7 thorpej tmp = tmp->pf_list.sqe_next) {
380 1.1.2.7 thorpej if ((tmp->pf_flags & PFF_ENABLED) &&
381 1.1.2.7 thorpej (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) &&
382 1.1.2.7 thorpej ((pf->ccr_base+PCMCIA_CCR_SIZE) <=
383 1.1.2.7 thorpej (tmp->ccr_base - tmp->pf_ccr_offset + tmp->pf_ccr_realsize)))
384 1.1.2.7 thorpej break;
385 1.1.2.7 thorpej }
386 1.1.2.7 thorpej
387 1.1.2.7 thorpej /* Not used by anyone else; unmap the CCR. */
388 1.1.2.7 thorpej if (tmp == NULL) {
389 1.1.2.7 thorpej pcmcia_mem_unmap(pf, pf->pf_ccr_window);
390 1.1.2.7 thorpej pcmcia_mem_free(pf, &pf->pf_pcmh);
391 1.1.2.7 thorpej }
392 1.1.2.7 thorpej
393 1.1.2.8 marc /* Decrement the reference count, and power down the socket,
394 1.1.2.7 thorpej if necessary. */
395 1.1.2.8 marc if (--pf->sc->sc_enabled_count == 0)
396 1.1.2.7 thorpej pcmcia_chip_socket_disable(pf->sc->pct, pf->sc->pch);
397 1.1.2.1 marc }
398 1.1.2.1 marc
399 1.1.2.1 marc int
400 1.1.2.5 thorpej pcmcia_io_map(pf, width, offset, size, pcihp, windowp)
401 1.1.2.1 marc struct pcmcia_function *pf;
402 1.1.2.1 marc int width;
403 1.1.2.5 thorpej bus_addr_t offset;
404 1.1.2.1 marc bus_size_t size;
405 1.1.2.5 thorpej struct pcmcia_io_handle *pcihp;
406 1.1.2.1 marc int *windowp;
407 1.1.2.1 marc {
408 1.1.2.5 thorpej bus_addr_t ioaddr;
409 1.1.2.1 marc int reg;
410 1.1.2.1 marc
411 1.1.2.1 marc if (pcmcia_chip_io_map(pf->sc->pct, pf->sc->pch,
412 1.1.2.5 thorpej width, offset, size, pcihp, windowp))
413 1.1.2.1 marc return(1);
414 1.1.2.1 marc
415 1.1.2.5 thorpej ioaddr = pcihp->addr + offset;
416 1.1.2.5 thorpej
417 1.1.2.1 marc /* XXX in the multifunction multi-iospace-per-function case, this
418 1.1.2.1 marc needs to cooperate with io_alloc to make sure that the spaces
419 1.1.2.1 marc don't overlap, and that the ccr's are set correctly */
420 1.1.2.1 marc
421 1.1.2.1 marc if (pcmcia_mfc(pf->sc)) {
422 1.1.2.5 thorpej pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE0, ioaddr & 0xff);
423 1.1.2.5 thorpej pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE1, (ioaddr >> 8) & 0xff);
424 1.1.2.1 marc pcmcia_ccr_write(pf, PCMCIA_CCR_IOSIZE, size - 1);
425 1.1.2.1 marc
426 1.1.2.1 marc reg = pcmcia_ccr_read(pf, PCMCIA_CCR_OPTION);
427 1.1.2.1 marc reg |= PCMCIA_CCR_OPTION_ADDR_DECODE;
428 1.1.2.1 marc pcmcia_ccr_write(pf, PCMCIA_CCR_OPTION, reg);
429 1.1.2.1 marc }
430 1.1.2.1 marc
431 1.1.2.1 marc return(0);
432 1.1.2.1 marc }
433 1.1.2.1 marc
434 1.1.2.1 marc void *
435 1.1.2.1 marc pcmcia_intr_establish(pf, ipl, ih_fct, ih_arg)
436 1.1.2.1 marc struct pcmcia_function *pf;
437 1.1.2.1 marc int ipl;
438 1.1.2.1 marc int (*ih_fct) __P((void *));
439 1.1.2.1 marc void *ih_arg;
440 1.1.2.1 marc {
441 1.1.2.1 marc void *ret;
442 1.1.2.1 marc
443 1.1.2.1 marc /* behave differently if this is a multifunction card */
444 1.1.2.1 marc
445 1.1.2.1 marc if (pcmcia_mfc(pf->sc)) {
446 1.1.2.1 marc int s, ihcnt, hiipl, reg;
447 1.1.2.1 marc struct pcmcia_function *pf2;
448 1.1.2.1 marc
449 1.1.2.1 marc /* mask all the ipl's which are already used by this card,
450 1.1.2.1 marc and find the highest ipl number (lowest priority) */
451 1.1.2.1 marc
452 1.1.2.1 marc ihcnt = 0;
453 1.1.2.1 marc s = 0; /* this is only here to keep the compipler happy */
454 1.1.2.1 marc hiipl = 0; /* this is only here to keep the compipler happy */
455 1.1.2.1 marc
456 1.1.2.1 marc for (pf2 = pf->sc->card.pf_head.sqh_first; pf2;
457 1.1.2.1 marc pf2 = pf2->pf_list.sqe_next) {
458 1.1.2.1 marc if (pf2->ih_fct) {
459 1.1.2.1 marc if (!ihcnt) {
460 1.1.2.1 marc s = splraise(pf2->ih_ipl);
461 1.1.2.1 marc hiipl = pf2->ih_ipl;
462 1.1.2.1 marc ihcnt++;
463 1.1.2.1 marc } else {
464 1.1.2.1 marc splraise(pf2->ih_ipl);
465 1.1.2.1 marc if (pf2->ih_ipl > hiipl)
466 1.1.2.1 marc hiipl = pf2->ih_ipl;
467 1.1.2.1 marc }
468 1.1.2.1 marc }
469 1.1.2.1 marc }
470 1.1.2.1 marc
471 1.1.2.1 marc /* set up the handler for the new function */
472 1.1.2.1 marc
473 1.1.2.1 marc pf->ih_fct = ih_fct;
474 1.1.2.1 marc pf->ih_arg = ih_arg;
475 1.1.2.1 marc pf->ih_ipl = ipl;
476 1.1.2.1 marc
477 1.1.2.1 marc /* establish the real interrupt, changing the ipl if necessary */
478 1.1.2.1 marc
479 1.1.2.1 marc if (ihcnt == 0) {
480 1.1.2.1 marc #ifdef DIAGNOSTIC
481 1.1.2.1 marc if (pf->sc->ih)
482 1.1.2.1 marc panic("card has intr handler, but no function does");
483 1.1.2.1 marc #endif
484 1.1.2.1 marc
485 1.1.2.1 marc pf->sc->ih = pcmcia_chip_intr_establish(pf->sc->pct, pf->sc->pch,
486 1.1.2.6 thorpej pf, ipl,
487 1.1.2.4 thorpej pcmcia_card_intr, pf->sc);
488 1.1.2.1 marc } else if (ipl > hiipl) {
489 1.1.2.1 marc #ifdef DIAGNOSTIC
490 1.1.2.1 marc if (! pf->sc->ih)
491 1.1.2.1 marc panic("functions have ih, but the card does not");
492 1.1.2.1 marc #endif
493 1.1.2.1 marc
494 1.1.2.1 marc pcmcia_chip_intr_disestablish(pf->sc->pct, pf->sc->pch,
495 1.1.2.1 marc pf->sc->ih);
496 1.1.2.1 marc pf->sc->ih = pcmcia_chip_intr_establish(pf->sc->pct, pf->sc->pch,
497 1.1.2.6 thorpej pf, ipl,
498 1.1.2.4 thorpej pcmcia_card_intr, pf->sc);
499 1.1.2.1 marc }
500 1.1.2.1 marc
501 1.1.2.1 marc if (ihcnt)
502 1.1.2.1 marc splx(s);
503 1.1.2.1 marc
504 1.1.2.1 marc ret = pf->sc->ih;
505 1.1.2.1 marc
506 1.1.2.1 marc if (ret) {
507 1.1.2.1 marc reg = pcmcia_ccr_read(pf, PCMCIA_CCR_OPTION);
508 1.1.2.1 marc reg |= PCMCIA_CCR_OPTION_IREQ_ENABLE;
509 1.1.2.1 marc pcmcia_ccr_write(pf, PCMCIA_CCR_OPTION, reg);
510 1.1.2.1 marc
511 1.1.2.1 marc reg = pcmcia_ccr_read(pf, PCMCIA_CCR_STATUS);
512 1.1.2.1 marc reg |= PCMCIA_CCR_STATUS_INTRACK;
513 1.1.2.1 marc pcmcia_ccr_write(pf, PCMCIA_CCR_STATUS, reg);
514 1.1.2.1 marc }
515 1.1.2.1 marc } else {
516 1.1.2.1 marc ret = pcmcia_chip_intr_establish(pf->sc->pct, pf->sc->pch,
517 1.1.2.6 thorpej pf, ipl, ih_fct, ih_arg);
518 1.1.2.1 marc }
519 1.1.2.1 marc
520 1.1.2.1 marc return(ret);
521 1.1.2.1 marc }
522 1.1.2.1 marc
523 1.1.2.1 marc void
524 1.1.2.1 marc pcmcia_intr_disestablish(pf, ih)
525 1.1.2.1 marc struct pcmcia_function *pf;
526 1.1.2.1 marc void *ih;
527 1.1.2.1 marc {
528 1.1.2.4 thorpej
529 1.1.2.1 marc /* behave differently if this is a multifunction card */
530 1.1.2.1 marc
531 1.1.2.1 marc if (pcmcia_mfc(pf->sc)) {
532 1.1.2.1 marc int s, ihcnt, hiipl;
533 1.1.2.1 marc struct pcmcia_function *pf2;
534 1.1.2.1 marc
535 1.1.2.1 marc /* mask all the ipl's which are already used by this card,
536 1.1.2.1 marc and find the highest ipl number (lowest priority). Skip
537 1.1.2.1 marc the current function. */
538 1.1.2.1 marc
539 1.1.2.1 marc ihcnt = 0;
540 1.1.2.1 marc s = 0; /* this is only here to keep the compipler happy */
541 1.1.2.1 marc hiipl = 0; /* this is only here to keep the compipler happy */
542 1.1.2.1 marc
543 1.1.2.1 marc for (pf2 = pf->sc->card.pf_head.sqh_first; pf2;
544 1.1.2.1 marc pf2 = pf2->pf_list.sqe_next) {
545 1.1.2.1 marc if (pf2 == pf)
546 1.1.2.1 marc continue;
547 1.1.2.1 marc
548 1.1.2.1 marc if (pf2->ih_fct) {
549 1.1.2.1 marc if (!ihcnt) {
550 1.1.2.1 marc s = splraise(pf2->ih_ipl);
551 1.1.2.1 marc hiipl = pf2->ih_ipl;
552 1.1.2.1 marc ihcnt++;
553 1.1.2.1 marc } else {
554 1.1.2.1 marc splraise(pf2->ih_ipl);
555 1.1.2.1 marc if (pf2->ih_ipl > hiipl)
556 1.1.2.1 marc hiipl = pf2->ih_ipl;
557 1.1.2.1 marc }
558 1.1.2.1 marc }
559 1.1.2.1 marc }
560 1.1.2.1 marc
561 1.1.2.1 marc /* null out the handler for this function */
562 1.1.2.1 marc
563 1.1.2.1 marc pf->ih_fct = NULL;
564 1.1.2.1 marc pf->ih_arg = NULL;
565 1.1.2.1 marc
566 1.1.2.1 marc /* if the ih being removed is lower priority than the lowest
567 1.1.2.1 marc priority remaining interrupt, up the priority. */
568 1.1.2.1 marc
569 1.1.2.1 marc #ifdef DIAGNOSTIC
570 1.1.2.1 marc if (ihcnt == 0) {
571 1.1.2.1 marc panic("can't remove a handler from a card which has none");
572 1.1.2.1 marc } else
573 1.1.2.1 marc #endif
574 1.1.2.1 marc if (ihcnt == 1) {
575 1.1.2.1 marc #ifdef DIAGNOSTIC
576 1.1.2.1 marc if (!pf->sc->ih)
577 1.1.2.1 marc panic("disestablishing last function, but card has no ih");
578 1.1.2.1 marc #endif
579 1.1.2.1 marc pcmcia_chip_intr_disestablish(pf->sc->pct, pf->sc->pch,
580 1.1.2.1 marc pf->sc->ih);
581 1.1.2.1 marc pf->sc->ih = NULL;
582 1.1.2.1 marc } else if (pf->ih_ipl > hiipl) {
583 1.1.2.1 marc #ifdef DIAGNOSTIC
584 1.1.2.1 marc if (!pf->sc->ih)
585 1.1.2.1 marc panic("changing ih ipl, but card has no ih");
586 1.1.2.1 marc #endif
587 1.1.2.1 marc pcmcia_chip_intr_disestablish(pf->sc->pct, pf->sc->pch,
588 1.1.2.1 marc pf->sc->ih);
589 1.1.2.1 marc pf->sc->ih = pcmcia_chip_intr_establish(pf->sc->pct, pf->sc->pch,
590 1.1.2.6 thorpej pf, hiipl,
591 1.1.2.4 thorpej pcmcia_card_intr, pf->sc);
592 1.1.2.1 marc }
593 1.1.2.1 marc
594 1.1.2.1 marc if (ihcnt)
595 1.1.2.1 marc splx(s);
596 1.1.2.1 marc } else {
597 1.1.2.1 marc pcmcia_chip_intr_disestablish(pf->sc->pct, pf->sc->pch, ih);
598 1.1.2.1 marc }
599 1.1.2.1 marc }
600 1.1.2.1 marc
601 1.1.2.1 marc int pcmcia_card_intr(arg)
602 1.1.2.1 marc void *arg;
603 1.1.2.1 marc {
604 1.1.2.1 marc struct pcmcia_softc *sc = (struct pcmcia_softc *) arg;
605 1.1.2.1 marc struct pcmcia_function *pf;
606 1.1.2.1 marc int reg, ret, ret2;
607 1.1.2.1 marc
608 1.1.2.1 marc ret = 0;
609 1.1.2.1 marc
610 1.1.2.1 marc for (pf = sc->card.pf_head.sqh_first; pf; pf = pf->pf_list.sqe_next) {
611 1.1.2.1 marc #if 0
612 1.1.2.1 marc printf("%s: intr fct=%d physaddr=%lx cor=%02x csr=%02x pin=%02x",
613 1.1.2.1 marc sc->dev.dv_xname, pf->number,
614 1.1.2.1 marc pmap_extract(pmap_kernel(), (vm_offset_t) pf->ccrh) + pf->ccr_offset,
615 1.1.2.5 thorpej bus_space_read_1(pf->pf_ccrt, pf->pf_ccrh,
616 1.1.2.5 thorpej pf->pf_ccr_offset+PCMCIA_CCR_OPTION),
617 1.1.2.5 thorpej bus_space_read_1(pf->pf_ccrt, pf->pf_ccrh,
618 1.1.2.5 thorpej pf->pf_ccr_offset+PCMCIA_CCR_STATUS),
619 1.1.2.5 thorpej bus_space_read_1(pf->pf_ccrt, pf->pf_ccrh,
620 1.1.2.5 thorpej pf->pf_ccr_offset+PCMCIA_CCR_PIN));
621 1.1.2.1 marc #endif
622 1.1.2.1 marc if (pf->ih_fct &&
623 1.1.2.1 marc (pf->ccr_mask & (1<<(PCMCIA_CCR_STATUS/2)))) {
624 1.1.2.1 marc reg = pcmcia_ccr_read(pf, PCMCIA_CCR_STATUS);
625 1.1.2.1 marc if (reg & PCMCIA_CCR_STATUS_INTR) {
626 1.1.2.1 marc ret2 = (*pf->ih_fct)(pf->ih_arg);
627 1.1.2.1 marc if (ret2 && !ret)
628 1.1.2.1 marc ret = ret2;
629 1.1.2.1 marc reg = pcmcia_ccr_read(pf, PCMCIA_CCR_STATUS);
630 1.1.2.1 marc #if 0
631 1.1.2.1 marc printf("; csr %02x->%02x", reg, reg & ~PCMCIA_CCR_STATUS_INTR);
632 1.1.2.1 marc #endif
633 1.1.2.1 marc pcmcia_ccr_write(pf, PCMCIA_CCR_STATUS,
634 1.1.2.1 marc reg & ~PCMCIA_CCR_STATUS_INTR);
635 1.1.2.1 marc }
636 1.1.2.1 marc }
637 1.1.2.1 marc #if 0
638 1.1.2.1 marc printf("\n");
639 1.1.2.1 marc #endif
640 1.1.2.1 marc }
641 1.1.2.1 marc
642 1.1.2.1 marc return(ret);
643 1.1.2.1 marc }
644