xref: /openbsd/sys/dev/pcmcia/pcmcia.c (revision 0f9e9ec2)
1 /*	$OpenBSD: pcmcia.c,v 1.51 2024/05/13 01:15:51 jsg Exp $	*/
2 /*	$NetBSD: pcmcia.c,v 1.9 1998/08/13 02:10:55 eeh Exp $	*/
3 
4 /*
5  * Copyright (c) 1997 Marc Horowitz.  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 Marc Horowitz.
18  * 4. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/device.h>
36 #include <sys/malloc.h>
37 
38 #include <dev/pcmcia/pcmciareg.h>
39 #include <dev/pcmcia/pcmciachip.h>
40 #include <dev/pcmcia/pcmciavar.h>
41 
42 #ifdef PCMCIADEBUG
43 #define	DPRINTF(arg) printf arg
44 #else
45 #define	DPRINTF(arg)
46 #endif
47 
48 #ifdef PCMCIAVERBOSE
49 int	pcmcia_verbose = 1;
50 #else
51 int	pcmcia_verbose = 0;
52 #endif
53 
54 int	pcmcia_match(struct device *, void *, void *);
55 int	pcmcia_submatch(struct device *, void *, void *);
56 void	pcmcia_attach(struct device *, struct device *, void *);
57 int	pcmcia_activate(struct device *, int);
58 int	pcmcia_print(void *, const char *);
59 int	pcmcia_card_intr(void *);
60 
61 struct cfdriver pcmcia_cd = {
62 	NULL, "pcmcia", DV_DULL
63 };
64 
65 const struct cfattach pcmcia_ca = {
66 	sizeof(struct pcmcia_softc), pcmcia_match, pcmcia_attach, NULL,
67 	pcmcia_activate
68 };
69 
70 int
pcmcia_ccr_read(struct pcmcia_function * pf,int ccr)71 pcmcia_ccr_read(struct pcmcia_function *pf, int ccr)
72 {
73 
74 	return (bus_space_read_1(pf->pf_ccrt, pf->pf_ccrh,
75 	    pf->pf_ccr_offset + ccr));
76 }
77 
78 void
pcmcia_ccr_write(struct pcmcia_function * pf,int ccr,int val)79 pcmcia_ccr_write(struct pcmcia_function *pf, int ccr, int val)
80 {
81 
82 	if ((pf->ccr_mask) & (1 << (ccr / 2))) {
83 		bus_space_write_1(pf->pf_ccrt, pf->pf_ccrh,
84 		    pf->pf_ccr_offset + ccr, val);
85 	}
86 }
87 
88 int
pcmcia_match(struct device * parent,void * match,void * aux)89 pcmcia_match(struct device *parent, void *match, void *aux)
90 {
91 	struct cfdata *cf = match;
92 	struct pcmciabus_attach_args *paa = aux;
93 
94 	if (strcmp(paa->paa_busname, cf->cf_driver->cd_name))
95 		return 0;
96 
97 	/* If the autoconfiguration got this far, there's a socket here. */
98 	return (1);
99 }
100 
101 void
pcmcia_attach(struct device * parent,struct device * self,void * aux)102 pcmcia_attach(struct device *parent, struct device *self, void *aux)
103 {
104 	struct pcmciabus_attach_args *paa = aux;
105 	struct pcmcia_softc *sc = (struct pcmcia_softc *) self;
106 
107 	printf("\n");
108 
109 	sc->pct = paa->pct;
110 	sc->pch = paa->pch;
111 	sc->iobase = paa->iobase;
112 	sc->iosize = paa->iosize;
113 
114 	sc->ih = NULL;
115 }
116 
117 int
pcmcia_activate(struct device * self,int act)118 pcmcia_activate(struct device *self, int act)
119 {
120 	struct pcmcia_softc *sc = (struct pcmcia_softc *)self;
121 	struct pcmcia_function *pf;
122 
123 	switch (act) {
124 	case DVACT_QUIESCE:
125 	case DVACT_SUSPEND:
126 	case DVACT_POWERDOWN:
127 	case DVACT_RESUME:
128 		for (pf = SIMPLEQ_FIRST(&sc->card.pf_head); pf != NULL;
129 		     pf = SIMPLEQ_NEXT(pf, pf_list)) {
130 			if (SIMPLEQ_FIRST(&pf->cfe_head) == NULL ||
131 			    pf->child == NULL)
132 				continue;
133 			config_suspend(pf->child, act);
134 		}
135 		break;
136 	case DVACT_DEACTIVATE:
137 		for (pf = SIMPLEQ_FIRST(&sc->card.pf_head); pf != NULL;
138 		     pf = SIMPLEQ_NEXT(pf, pf_list)) {
139 			if (SIMPLEQ_FIRST(&pf->cfe_head) == NULL ||
140 			    pf->child == NULL)
141 				continue;
142 			config_deactivate(pf->child);
143 		}
144 		break;
145 	}
146 	return (0);
147 }
148 
149 int
pcmcia_card_attach(struct device * dev)150 pcmcia_card_attach(struct device *dev)
151 {
152 	struct pcmcia_softc *sc = (struct pcmcia_softc *) dev;
153 	struct pcmcia_function *pf;
154 	struct pcmcia_attach_args paa;
155 	int attached;
156 
157 	/*
158 	 * this is here so that when socket_enable calls gettype, trt happens
159 	 */
160 	SIMPLEQ_FIRST(&sc->card.pf_head) = NULL;
161 
162 	pcmcia_chip_socket_enable(sc->pct, sc->pch);
163 
164 	pcmcia_read_cis(sc);
165 
166 	pcmcia_chip_socket_disable(sc->pct, sc->pch);
167 
168 	pcmcia_check_cis_quirks(sc);
169 
170 	/*
171 	 * Bail now if there was an error in the CIS.
172 	 */
173 
174 	if (sc->card.error)
175 		return (1);
176 
177 #if 0
178 	if (SIMPLEQ_EMPTY(&sc->card.pf_head))
179 		return (1);
180 #endif
181 
182 	if (pcmcia_verbose)
183 		pcmcia_print_cis(sc);
184 
185 	/*
186 	 * If there was no function, this might be CIS-less card we still
187 	 * want to probe.  Fixup a function element for it.
188 	 */
189 	if (SIMPLEQ_FIRST(&sc->card.pf_head) == NULL) {
190 		pf = malloc(sizeof *pf, M_DEVBUF, M_NOWAIT | M_ZERO);
191 		if (pf == NULL)
192 			panic("pcmcia_card_attach");
193 		pf->number = 0;
194 		pf->pf_flags = PFF_FAKE;
195 		pf->last_config_index = -1;
196 		SIMPLEQ_INIT(&pf->cfe_head);
197 		SIMPLEQ_INSERT_TAIL(&sc->card.pf_head, pf, pf_list);
198 	}
199 
200 	attached = 0;
201 
202 	for (pf = SIMPLEQ_FIRST(&sc->card.pf_head); pf != NULL;
203 	    pf = SIMPLEQ_NEXT(pf, pf_list)) {
204 		pf->sc = sc;
205 		pf->child = NULL;
206 		pf->cfe = NULL;
207 		pf->ih_fct = NULL;
208 		pf->ih_arg = NULL;
209 	}
210 
211 	for (pf = SIMPLEQ_FIRST(&sc->card.pf_head); pf != NULL;
212 	    pf = SIMPLEQ_NEXT(pf, pf_list)) {
213 		paa.manufacturer = sc->card.manufacturer;
214 		paa.product = sc->card.product;
215 		paa.card = &sc->card;
216 		paa.pf = pf;
217 
218 		pf->child = config_found_sm(&sc->dev, &paa, pcmcia_print,
219 		    pcmcia_submatch);
220 		if (pf->child) {
221 			attached++;
222 
223 			if ((pf->pf_flags & (PFF_FAKE | PFF_ENABLED)) ==
224 			    PFF_ENABLED)
225 				DPRINTF(("%s: function %d CCR at %d offset %lx"
226 					": %x %x %x %x, %x %x %x %x, %x\n",
227 					sc->dev.dv_xname, pf->number,
228 					pf->pf_ccr_window, pf->pf_ccr_offset,
229 					pcmcia_ccr_read(pf, 0x00),
230 					pcmcia_ccr_read(pf, 0x02),
231 					pcmcia_ccr_read(pf, 0x04),
232 					pcmcia_ccr_read(pf, 0x06),
233 					pcmcia_ccr_read(pf, 0x0A),
234 					pcmcia_ccr_read(pf, 0x0C),
235 					pcmcia_ccr_read(pf, 0x0E),
236 					pcmcia_ccr_read(pf, 0x10),
237 					pcmcia_ccr_read(pf, 0x12)));
238 		}
239 	}
240 	return (attached ? 0 : 1);
241 }
242 
243 void
pcmcia_card_detach(struct device * dev,int flags)244 pcmcia_card_detach(struct device *dev, int flags)
245 {
246 	struct pcmcia_softc *sc = (struct pcmcia_softc *) dev;
247 	struct pcmcia_function *pf;
248 	int error;
249 
250 	/*
251 	 * We are running on either the PCMCIA socket's event thread
252 	 * or in user context detaching a device by user request.
253 	 */
254 	for (pf = SIMPLEQ_FIRST(&sc->card.pf_head); pf != NULL;
255 	     pf = SIMPLEQ_NEXT(pf, pf_list)) {
256 		if (SIMPLEQ_FIRST(&pf->cfe_head) == NULL)
257 			continue;
258 		if (pf->child == NULL)
259 			continue;
260 		DPRINTF(("%s: detaching %s (function %d)\n",
261 		    sc->dev.dv_xname, pf->child->dv_xname, pf->number));
262 		if ((error = config_detach(pf->child, flags)) != 0) {
263 			printf("%s: error %d detaching %s (function %d)\n",
264 			    sc->dev.dv_xname, error, pf->child->dv_xname,
265 			    pf->number);
266 		} else
267 			pf->child = NULL;
268 	}
269 }
270 
271 void
pcmcia_card_deactivate(struct device * dev)272 pcmcia_card_deactivate(struct device *dev)
273 {
274 	struct pcmcia_softc *sc = (struct pcmcia_softc *) dev;
275 	struct pcmcia_function *pf;
276 
277 	/*
278 	 * We're in the chip's card removal interrupt handler.
279 	 * Deactivate the child driver.  The PCMCIA socket's
280 	 * event thread will run later to finish the detach.
281 	 */
282 	for (pf = SIMPLEQ_FIRST(&sc->card.pf_head); pf != NULL;
283 	     pf = SIMPLEQ_NEXT(pf, pf_list)) {
284 		if (SIMPLEQ_FIRST(&pf->cfe_head) == NULL ||
285 		    pf->child == NULL)
286 			continue;
287 		DPRINTF(("%s: deactivating %s (function %d)\n",
288 		    sc->dev.dv_xname, pf->child->dv_xname, pf->number));
289 		config_deactivate(pf->child);
290 	}
291 }
292 
293 int
pcmcia_submatch(struct device * parent,void * match,void * aux)294 pcmcia_submatch(struct device *parent, void *match, void *aux)
295 {
296 	struct cfdata *cf = match;
297 	struct pcmcia_attach_args *paa = aux;
298 
299 	if (cf->cf_loc[0 /* PCMCIACF_FUNCTION */] !=
300 	    -1 /* PCMCIACF_FUNCTION_DEFAULT */ &&
301 	    cf->cf_loc[0 /* PCMCIACF_FUNCTION */] != paa->pf->number)
302 		return (0);
303 
304 	return ((*cf->cf_attach->ca_match)(parent, cf, aux));
305 }
306 
307 int
pcmcia_print(void * arg,const char * pnp)308 pcmcia_print(void *arg, const char *pnp)
309 {
310 	struct pcmcia_attach_args *pa = arg;
311 	struct pcmcia_softc *sc = pa->pf->sc;
312 	struct pcmcia_card *card = &sc->card;
313 	int i;
314 
315 	if (pnp) {
316 		for (i = 0; i < 4 && card->cis1_info[i]; i++)
317 			printf("%s%s", i ? ", " : "\"", card->cis1_info[i]);
318 		if (i != 0)
319 			printf("\"");
320 
321 		if (card->manufacturer != PCMCIA_VENDOR_INVALID &&
322 		    card->product != PCMCIA_PRODUCT_INVALID) {
323 			if (i != 0)
324 				printf(" ");
325 			printf("(");
326 			if (card->manufacturer != PCMCIA_VENDOR_INVALID)
327 				printf("manufacturer 0x%x%s",
328 				    card->manufacturer,
329 				    card->product == PCMCIA_PRODUCT_INVALID ?
330 				    "" : ", ");
331 			if (card->product != PCMCIA_PRODUCT_INVALID)
332 				printf("product 0x%x",
333 				    card->product);
334 			printf(")");
335 		}
336 		if (i != 0)
337 			printf(" ");
338 		printf("at %s", pnp);
339 	}
340 	printf(" function %d", pa->pf->number);
341 
342 	if (!pnp) {
343 		for (i = 0; i < 3 && card->cis1_info[i]; i++)
344 			printf("%s%s", i ? ", " : " \"", card->cis1_info[i]);
345 		if (i != 0)
346 			printf("\"");
347 	}
348 
349 	return (UNCONF);
350 }
351 
352 int
pcmcia_card_gettype(struct device * dev)353 pcmcia_card_gettype(struct device *dev)
354 {
355 	struct pcmcia_softc *sc = (struct pcmcia_softc *)dev;
356 	struct pcmcia_function *pf;
357 
358 	/*
359 	 * Set the iftype to memory if this card has no functions (not yet
360 	 * probed), or only one function, and that is not initialized yet or
361 	 * that is memory.
362 	 */
363 	pf = SIMPLEQ_FIRST(&sc->card.pf_head);
364 	if (pf == NULL || (SIMPLEQ_NEXT(pf, pf_list) == NULL &&
365 	    ((pf->pf_flags & PFF_FAKE) ||
366 	    pf->cfe == NULL || pf->cfe->iftype == PCMCIA_IFTYPE_MEMORY)))
367 		return (PCMCIA_IFTYPE_MEMORY);
368 	else
369 		return (PCMCIA_IFTYPE_IO);
370 }
371 
372 /*
373  * Initialize a PCMCIA function.  May be called as long as the function is
374  * disabled.
375  */
376 void
pcmcia_function_init(struct pcmcia_function * pf,struct pcmcia_config_entry * cfe)377 pcmcia_function_init(struct pcmcia_function *pf,
378     struct pcmcia_config_entry *cfe)
379 {
380 	if (pf->pf_flags & PFF_ENABLED)
381 		panic("pcmcia_function_init: function is enabled");
382 
383 	/* Remember which configuration entry we are using. */
384 	pf->cfe = cfe;
385 }
386 
387 /* Enable a PCMCIA function */
388 int
pcmcia_function_enable(struct pcmcia_function * pf)389 pcmcia_function_enable(struct pcmcia_function *pf)
390 {
391 	struct pcmcia_function *tmp;
392 	int reg;
393 
394 	if (pf->cfe == NULL)
395 		panic("pcmcia_function_enable: function not initialized");
396 
397 	/*
398 	 * Increase the reference count on the socket, enabling power, if
399 	 * necessary.
400 	 */
401 	if (pf->sc->sc_enabled_count++ == 0)
402 		pcmcia_chip_socket_enable(pf->sc->pct, pf->sc->pch);
403 	DPRINTF(("%s: ++enabled_count = %d\n", pf->sc->dev.dv_xname,
404 		 pf->sc->sc_enabled_count));
405 
406 	if (pf->pf_flags & PFF_ENABLED) {
407 		/*
408 		 * Don't do anything if we're already enabled.
409 		 */
410 		DPRINTF(("%s: pcmcia_function_enable on enabled func\n",
411 		    pf->sc->dev.dv_xname));
412 		return (0);
413 	}
414 
415 	/* If there was no CIS don't mess with CCR */
416 	if (pf->pf_flags & PFF_FAKE)
417 		goto done;
418 
419 	/*
420 	 * It's possible for different functions' CCRs to be in the same
421 	 * underlying page.  Check for that.
422 	 */
423 	SIMPLEQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) {
424 		if ((tmp->pf_flags & PFF_ENABLED) &&
425 		    (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) &&
426 		    ((pf->ccr_base + PCMCIA_CCR_SIZE) <=
427 		     (tmp->ccr_base - tmp->pf_ccr_offset +
428 		      tmp->pf_ccr_realsize))) {
429 			pf->pf_ccrt = tmp->pf_ccrt;
430 			pf->pf_ccrh = tmp->pf_ccrh;
431 			pf->pf_ccr_realsize = tmp->pf_ccr_realsize;
432 
433 			/*
434 			 * pf->pf_ccr_offset = (tmp->pf_ccr_offset -
435 			 * tmp->ccr_base) + pf->ccr_base;
436 			 */
437 			pf->pf_ccr_offset =
438 			    (tmp->pf_ccr_offset + pf->ccr_base) -
439 			    tmp->ccr_base;
440 			pf->pf_ccr_window = tmp->pf_ccr_window;
441 			break;
442 		}
443 	}
444 
445 	if (tmp == NULL) {
446 		if (pcmcia_mem_alloc(pf, PCMCIA_CCR_SIZE, &pf->pf_pcmh))
447 			goto bad;
448 
449 		if (pcmcia_mem_map(pf, PCMCIA_MEM_ATTR, pf->ccr_base,
450 		    PCMCIA_CCR_SIZE, &pf->pf_pcmh, &pf->pf_ccr_offset,
451 		    &pf->pf_ccr_window)) {
452 			pcmcia_mem_free(pf, &pf->pf_pcmh);
453 			goto bad;
454 		}
455 	}
456 
457 	reg = (pf->cfe->number & PCMCIA_CCR_OPTION_CFINDEX);
458 	reg |= PCMCIA_CCR_OPTION_LEVIREQ;
459 	if (pcmcia_mfc(pf->sc)) {
460 		reg |= PCMCIA_CCR_OPTION_FUNC_ENABLE;
461 		if (pf->ccr_mask & (1 << (PCMCIA_CCR_IOBASE0 / 2)))
462 			reg |= PCMCIA_CCR_OPTION_ADDR_DECODE;
463 		if (pf->ih_fct)
464 			reg |= PCMCIA_CCR_OPTION_IREQ_ENABLE;
465 
466 	}
467 
468 	pcmcia_ccr_write(pf, PCMCIA_CCR_OPTION, reg);
469 
470 	reg = 0;
471 
472 	if ((pf->cfe->flags & PCMCIA_CFE_IO16) == 0)
473 		reg |= PCMCIA_CCR_STATUS_IOIS8;
474 	if (pf->cfe->flags & PCMCIA_CFE_AUDIO)
475 		reg |= PCMCIA_CCR_STATUS_AUDIO;
476 	pcmcia_ccr_write(pf, PCMCIA_CCR_STATUS, reg);
477 
478 	pcmcia_ccr_write(pf, PCMCIA_CCR_SOCKETCOPY, 0);
479 
480 	if (pcmcia_mfc(pf->sc)) {
481 		pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE0,
482 				 (pf->pf_mfc_iobase >>  0) & 0xff);
483 		pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE1,
484 				 (pf->pf_mfc_iobase >>  8) & 0xff);
485 		pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE2,
486 				 (pf->pf_mfc_iobase >> 16) & 0xff);
487 		pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE3,
488 				 (pf->pf_mfc_iobase >> 24) & 0xff);
489 		pcmcia_ccr_write(pf, PCMCIA_CCR_IOSIZE,
490 				 pf->pf_mfc_iomax - pf->pf_mfc_iobase);
491 	}
492 
493 #ifdef PCMCIADEBUG
494 	SIMPLEQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) {
495 		printf("%s: function %d CCR at %d offset %lx: "
496 		       "%x %x %x %x, %x %x %x %x, %x\n",
497 		       tmp->sc->dev.dv_xname, tmp->number,
498 		       tmp->pf_ccr_window, tmp->pf_ccr_offset,
499 		       pcmcia_ccr_read(tmp, 0x00),
500 		       pcmcia_ccr_read(tmp, 0x02),
501 		       pcmcia_ccr_read(tmp, 0x04),
502 		       pcmcia_ccr_read(tmp, 0x06),
503 
504 		       pcmcia_ccr_read(tmp, 0x0A),
505 		       pcmcia_ccr_read(tmp, 0x0C),
506 		       pcmcia_ccr_read(tmp, 0x0E),
507 		       pcmcia_ccr_read(tmp, 0x10),
508 
509 		       pcmcia_ccr_read(tmp, 0x12));
510 	}
511 #endif
512 
513  done:
514 	pf->pf_flags |= PFF_ENABLED;
515 	delay(1000);
516 	return (0);
517 
518  bad:
519 	/*
520 	 * Decrement the reference count, and power down the socket, if
521 	 * necessary.
522 	 */
523 	if (--pf->sc->sc_enabled_count == 0)
524 		pcmcia_chip_socket_disable(pf->sc->pct, pf->sc->pch);
525 	DPRINTF(("%s: --enabled_count = %d\n", pf->sc->dev.dv_xname,
526 		 pf->sc->sc_enabled_count));
527 
528 	return (1);
529 }
530 
531 /* Disable PCMCIA function. */
532 void
pcmcia_function_disable(struct pcmcia_function * pf)533 pcmcia_function_disable(struct pcmcia_function *pf)
534 {
535 	struct pcmcia_function *tmp;
536 
537 	if (pf->cfe == NULL)
538 		panic("pcmcia_function_enable: function not initialized");
539 
540 	if ((pf->pf_flags & PFF_ENABLED) == 0) {
541 		/*
542 		 * Don't do anything if we're already disabled.
543 		 */
544 		return;
545 	}
546 
547 	/* If there was no CIS don't mess with CCR */
548 	if (pf->pf_flags & PFF_FAKE) {
549 		pf->pf_flags &= ~PFF_ENABLED;
550 		goto done;
551 	}
552 
553 	/*
554 	 * it's possible for different functions' CCRs to be in the same
555 	 * underlying page.  Check for that.  Note we mark us as disabled
556 	 * first to avoid matching ourself.
557 	 */
558 	pf->pf_flags &= ~PFF_ENABLED;
559 	SIMPLEQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) {
560 		if ((tmp->pf_flags & PFF_ENABLED) &&
561 		    (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) &&
562 		    ((pf->ccr_base + PCMCIA_CCR_SIZE) <=
563 		(tmp->ccr_base - tmp->pf_ccr_offset + tmp->pf_ccr_realsize)))
564 			break;
565 	}
566 
567 	/* Not used by anyone else; unmap the CCR. */
568 	if (tmp == NULL) {
569 		pcmcia_mem_unmap(pf, pf->pf_ccr_window);
570 		pcmcia_mem_free(pf, &pf->pf_pcmh);
571 	}
572 
573  done:
574 	/*
575 	 * Decrement the reference count, and power down the socket, if
576 	 * necessary.
577 	 */
578 	if (--pf->sc->sc_enabled_count == 0)
579 		pcmcia_chip_socket_disable(pf->sc->pct, pf->sc->pch);
580 	DPRINTF(("%s: --enabled_count = %d\n", pf->sc->dev.dv_xname,
581 		 pf->sc->sc_enabled_count));
582 }
583 
584 int
pcmcia_io_map(struct pcmcia_function * pf,int width,bus_addr_t offset,bus_size_t size,struct pcmcia_io_handle * pcihp,int * windowp)585 pcmcia_io_map(struct pcmcia_function *pf, int width, bus_addr_t offset,
586     bus_size_t size, struct pcmcia_io_handle *pcihp, int *windowp)
587 {
588 	int reg;
589 
590 	if (pcmcia_chip_io_map(pf->sc->pct, pf->sc->pch,
591 	    width, offset, size, pcihp, windowp))
592 		return (1);
593 
594 	/*
595 	 * XXX In the multifunction multi-iospace-per-function case, this
596 	 * needs to cooperate with io_alloc to make sure that the spaces
597 	 * don't overlap, and that the ccr's are set correctly.
598 	 */
599 
600 	if (pcmcia_mfc(pf->sc) &&
601 	    (pf->ccr_mask & (1 << (PCMCIA_CCR_IOBASE0 / 2)))) {
602 		bus_addr_t iobase = pcihp->addr;
603 		bus_addr_t iomax = pcihp->addr + pcihp->size - 1;
604 
605 		if (pf->pf_mfc_iomax == 0) {
606 			pf->pf_mfc_iobase = iobase;
607 			pf->pf_mfc_iomax = iomax;
608 		} else {
609 			if (iobase < pf->pf_mfc_iobase)
610 				pf->pf_mfc_iobase = iobase;
611 			if (iomax > pf->pf_mfc_iomax)
612 				pf->pf_mfc_iomax = iomax;
613 		}
614 
615 		pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE0,
616 				 (pf->pf_mfc_iobase >>  0) & 0xff);
617 		pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE1,
618 				 (pf->pf_mfc_iobase >>  8) & 0xff);
619 		pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE2,
620 				 (pf->pf_mfc_iobase >> 16) & 0xff);
621 		pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE3,
622 				 (pf->pf_mfc_iobase >> 24) & 0xff);
623 		pcmcia_ccr_write(pf, PCMCIA_CCR_IOSIZE,
624 				 pf->pf_mfc_iomax - pf->pf_mfc_iobase);
625 
626 		reg = pcmcia_ccr_read(pf, PCMCIA_CCR_OPTION);
627 		reg |= PCMCIA_CCR_OPTION_ADDR_DECODE;
628 		pcmcia_ccr_write(pf, PCMCIA_CCR_OPTION, reg);
629 	}
630 	return (0);
631 }
632 
633 void *
pcmcia_intr_establish(struct pcmcia_function * pf,int ipl,int (* ih_fct)(void *),void * ih_arg,char * xname)634 pcmcia_intr_establish(struct pcmcia_function *pf, int ipl,
635     int (*ih_fct)(void *), void *ih_arg, char *xname)
636 {
637 	void *ret;
638 	int s, ihcnt, hiipl, reg;
639 	struct pcmcia_function *pf2;
640 
641 	/* Behave differently if this is a multifunction card. */
642 	if (pcmcia_mfc(pf->sc)) {
643 		/*
644 		 * Mask all the ipl's which are already used by this card,
645 		 * and find the highest ipl number (lowest priority).
646 		 */
647 		ihcnt = 0;
648 		SIMPLEQ_FOREACH(pf2, &pf->sc->card.pf_head, pf_list) {
649 			if (pf2->ih_fct) {
650 				DPRINTF(("%s: function %d has ih_fct %p\n",
651 				    pf->sc->dev.dv_xname, pf2->number,
652 				    pf2->ih_fct));
653 
654 				if (ihcnt == 0)
655 					hiipl = pf2->ih_ipl;
656 				else if (pf2->ih_ipl > hiipl)
657 					hiipl = pf2->ih_ipl;
658 
659 				ihcnt++;
660 			}
661 		}
662 
663 		/*
664 		 * Establish the real interrupt, changing the ipl if
665 		 * necessary.
666 		 */
667 		if (ihcnt == 0) {
668 #ifdef DIAGNOSTIC
669 			if (pf->sc->ih != NULL)
670 				panic("card has intr handler, "
671 				    "but no function does");
672 #endif
673 			s = spltty();
674 
675 			/* Set up the handler for the new function. */
676 			pf->ih_fct = ih_fct;
677 			pf->ih_arg = ih_arg;
678 			pf->ih_ipl = ipl;
679 
680 			pf->sc->ih = pcmcia_chip_intr_establish(pf->sc->pct,
681 			    pf->sc->pch, pf, ipl, pcmcia_card_intr, pf->sc,
682 			    xname);
683 			splx(s);
684 		} else if (ipl > hiipl) {
685 #ifdef DIAGNOSTIC
686 			if (pf->sc->ih == NULL)
687 				panic("functions have ih, "
688 				    "but the card does not");
689 #endif
690 
691 			s = spltty();
692 
693 			pcmcia_chip_intr_disestablish(pf->sc->pct, pf->sc->pch,
694 			    pf->sc->ih);
695 
696 			/* set up the handler for the new function */
697 			pf->ih_fct = ih_fct;
698 			pf->ih_arg = ih_arg;
699 			pf->ih_ipl = ipl;
700 
701 			pf->sc->ih = pcmcia_chip_intr_establish(pf->sc->pct,
702 			    pf->sc->pch, pf, ipl, pcmcia_card_intr, pf->sc,
703 			    xname);
704 
705 			splx(s);
706 		} else {
707 			s = spltty();
708 
709 			/* Set up the handler for the new function. */
710 			pf->ih_fct = ih_fct;
711 			pf->ih_arg = ih_arg;
712 			pf->ih_ipl = ipl;
713 
714 			splx(s);
715 		}
716 
717 		ret = pf->sc->ih;
718 
719 		if (ret != NULL) {
720 			reg = pcmcia_ccr_read(pf, PCMCIA_CCR_OPTION);
721 			reg |= PCMCIA_CCR_OPTION_IREQ_ENABLE;
722 			pcmcia_ccr_write(pf, PCMCIA_CCR_OPTION, reg);
723 
724 			reg = pcmcia_ccr_read(pf, PCMCIA_CCR_STATUS);
725 			reg |= PCMCIA_CCR_STATUS_INTRACK;
726 			pcmcia_ccr_write(pf, PCMCIA_CCR_STATUS, reg);
727 		}
728 	} else
729 		ret = pcmcia_chip_intr_establish(pf->sc->pct, pf->sc->pch,
730 		    pf, ipl, ih_fct, ih_arg, xname);
731 
732 	return (ret);
733 }
734 
735 void
pcmcia_intr_disestablish(struct pcmcia_function * pf,void * ih)736 pcmcia_intr_disestablish(struct pcmcia_function *pf, void *ih)
737 {
738 	int s, reg, ihcnt, hiipl;
739 	struct pcmcia_function *pf2;
740 
741 	/* Behave differently if this is a multifunction card.  */
742 	if (pcmcia_mfc(pf->sc)) {
743 		/*
744 		 * Mask all the ipl's which are already used by this card,
745 		 * and find the highest ipl number (lowest priority).  Skip
746 		 * the current function.
747 		 */
748 		ihcnt = 0;
749 		SIMPLEQ_FOREACH(pf2, &pf->sc->card.pf_head, pf_list) {
750 			if (pf2 == pf)
751 				continue;
752 
753 			if (pf2->ih_fct) {
754 				if (ihcnt == 0)
755 					hiipl = pf2->ih_ipl;
756 				else if (pf2->ih_ipl > hiipl)
757 					hiipl = pf2->ih_ipl;
758 				ihcnt++;
759 			}
760 		}
761 
762 		/*
763 		 * If the ih being removed is lower priority than the lowest
764 		 * priority remaining interrupt, up the priority.
765 		 */
766 
767 		/*
768 		 * ihcnt is the number of interrupt handlers *not* including
769 		 * the one about to be removed.
770 		 */
771 		if (ihcnt == 0) {
772 #ifdef DIAGNOSTIC
773 			if (pf->sc->ih == NULL)
774 				panic("disestablishing last function, but card has no ih");
775 #endif
776 			pcmcia_chip_intr_disestablish(pf->sc->pct, pf->sc->pch,
777 			    pf->sc->ih);
778 
779 			reg = pcmcia_ccr_read(pf, PCMCIA_CCR_OPTION);
780 			reg &= ~PCMCIA_CCR_OPTION_IREQ_ENABLE;
781 			pcmcia_ccr_write(pf, PCMCIA_CCR_OPTION, reg);
782 
783 			pf->ih_fct = NULL;
784 			pf->ih_arg = NULL;
785 
786 			pf->sc->ih = NULL;
787 		} else if (pf->ih_ipl > hiipl) {
788 #ifdef DIAGNOSTIC
789 			if (pf->sc->ih == NULL)
790 				panic("changing ih ipl, but card has no ih");
791 #endif
792 			s = spltty();
793 
794 			pcmcia_chip_intr_disestablish(pf->sc->pct, pf->sc->pch,
795 			    pf->sc->ih);
796 			pf->sc->ih = pcmcia_chip_intr_establish(pf->sc->pct,
797 			    pf->sc->pch, pf, hiipl, pcmcia_card_intr, pf->sc,
798 			    NULL);
799 
800 			/* Null out the handler for this function. */
801 			pf->ih_fct = NULL;
802 			pf->ih_arg = NULL;
803 
804 			splx(s);
805 		} else {
806 			s = spltty();
807 
808 			pf->ih_fct = NULL;
809 			pf->ih_arg = NULL;
810 
811 			splx(s);
812 		}
813 	} else
814 		pcmcia_chip_intr_disestablish(pf->sc->pct, pf->sc->pch, ih);
815 }
816 
817 const char *
pcmcia_intr_string(struct pcmcia_function * pf,void * ih)818 pcmcia_intr_string(struct pcmcia_function *pf, void *ih)
819 {
820 	return pcmcia_chip_intr_string(pf->sc->pct, pf->sc->pch, ih);
821 }
822 
823 int
pcmcia_card_intr(void * arg)824 pcmcia_card_intr(void *arg)
825 {
826 	struct pcmcia_softc *sc = arg;
827 	struct pcmcia_function *pf;
828 	int reg, ret, ret2;
829 
830 	ret = 0;
831 
832 	for (pf = SIMPLEQ_FIRST(&sc->card.pf_head); pf != NULL;
833 	    pf = SIMPLEQ_NEXT(pf, pf_list)) {
834 #ifdef PCMCIADEBUG
835 		printf("%s: intr flags=%x fct=%d cor=%02x csr=%02x pin=%02x",
836 		       sc->dev.dv_xname, pf->pf_flags, pf->number,
837 		       pcmcia_ccr_read(pf, PCMCIA_CCR_OPTION),
838 		       pcmcia_ccr_read(pf, PCMCIA_CCR_STATUS),
839 		       pcmcia_ccr_read(pf, PCMCIA_CCR_PIN));
840 #endif
841 		if (pf->ih_fct != NULL &&
842 		    (pf->ccr_mask & (1 << (PCMCIA_CCR_STATUS / 2)))) {
843 			reg = pcmcia_ccr_read(pf, PCMCIA_CCR_STATUS);
844 			if (reg & PCMCIA_CCR_STATUS_INTR) {
845 				ret2 = (*pf->ih_fct)(pf->ih_arg);
846 				if (ret2 != 0 && ret == 0)
847 					ret = ret2;
848 				reg = pcmcia_ccr_read(pf, PCMCIA_CCR_STATUS);
849 #ifdef PCMCIADEBUG
850 				printf("; csr %02x->%02x",
851 				    reg, reg & ~PCMCIA_CCR_STATUS_INTR);
852 #endif
853 				pcmcia_ccr_write(pf, PCMCIA_CCR_STATUS,
854 				    reg & ~PCMCIA_CCR_STATUS_INTR);
855 			}
856 		}
857 #ifdef PCMCIADEBUG
858 		printf("\n");
859 #endif
860 	}
861 
862 	return (ret);
863 }
864