xref: /openbsd/sys/arch/luna88k/cbus/i82365_cbus.c (revision aec57fdb)
1 /*	$OpenBSD: i82365_cbus.c,v 1.9 2024/06/01 00:48:16 aoyama Exp $	*/
2 /*	$NetBSD: i82365_isa.c,v 1.11 1998/06/09 07:25:00 thorpej 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 /*
34  * Driver for PC-9801-102 & PC-9821X[AE]-E01 PC Card slot adapter
35  *  based on OpenBSD:src/sys/dev/isa/i82365_isa{,subr}.c
36  */
37 
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/kernel.h>
41 #include <sys/device.h>
42 #include <sys/extent.h>
43 #include <sys/malloc.h>
44 
45 #include <machine/board.h>		/* PC_BASE */
46 #include <machine/bus.h>
47 #include <machine/intr.h>
48 
49 #include <arch/luna88k/cbus/cbusvar.h>
50 
51 #include <dev/pcmcia/pcmciareg.h>
52 #include <dev/pcmcia/pcmciavar.h>
53 #include <dev/pcmcia/pcmciachip.h>
54 
55 #include <dev/ic/i82365reg.h>
56 #include <dev/ic/i82365var.h>
57 
58 #ifdef PCICCBUSDEBUG
59 #define	DPRINTF(arg)	printf arg;
60 #else
61 #define	DPRINTF(arg)
62 #endif
63 
64 /*
65  * XXX:
66  * The C-bus expects edge-triggered interrupts, but some PC Cards and
67  * the controller itself produce level-triggered interrupts.  This causes
68  * spurious interrupts on C-bus.
69  * Then, we use CL-PD67XX 'pulse IRQ' feature in this driver.  This seems
70  * to solve stray interrupts on C-bus.
71  * (BTW, all NEC genuine C-bus PC Card slot adapters use CL-PD67XX)
72  */
73 
74 /* Cirrus Logic CL-PD67XX Misc Control register */
75 #define PCIC_CIRRUS_MISC_CTL_1			0x16
76 #define  PCIC_CIRRUS_MISC_CTL_1_PULSE_MGMT_INTR	0x04
77 #define  PCIC_CIRRUS_MISC_CTL_1_PULSE_SYS_IRQ	0x08
78 
79 /* prototypes */
80 void	*pcic_cbus_chip_intr_establish(pcmcia_chipset_handle_t,
81 	    struct pcmcia_function *, int, int (*) (void *), void *, char *);
82 void	pcic_cbus_chip_intr_disestablish(pcmcia_chipset_handle_t, void *);
83 const char *pcic_cbus_chip_intr_string(pcmcia_chipset_handle_t, void *);
84 int	pcic_cbus_intlevel_find(void);
85 int	pcic_cbus_chip_io_alloc(pcmcia_chipset_handle_t, bus_addr_t,
86 	    bus_size_t, bus_size_t, struct pcmcia_io_handle *);
87 void	pcic_cbus_chip_io_free(pcmcia_chipset_handle_t,
88 	    struct pcmcia_io_handle *);
89 
90 int	pcic_cbus_probe(struct device *, void *, void *);
91 void	pcic_cbus_attach(struct device *, struct device *, void *);
92 
93 /* bus space tag for pcic_cbus */
94 struct luna88k_bus_space_tag pcic_cbus_io_bst = {
95 	.bs_stride_1 = 0,
96 	.bs_stride_2 = 0,
97 	.bs_stride_4 = 0,
98 	.bs_stride_8 = 0,	/* not used */
99 	.bs_offset = PCEXIO_BASE,
100 	.bs_flags = TAG_LITTLE_ENDIAN
101 };
102 
103 struct luna88k_bus_space_tag pcic_cbus_mem_bst = {
104 	.bs_stride_1 = 0,
105 	.bs_stride_2 = 0,
106 	.bs_stride_4 = 0,
107 	.bs_stride_8 = 0,	/* not used */
108 	.bs_offset = PCEXMEM_BASE,
109 	.bs_flags = TAG_LITTLE_ENDIAN
110 };
111 
112 const struct cfattach pcic_cbus_ca = {
113 	sizeof(struct pcic_softc), pcic_cbus_probe, pcic_cbus_attach
114 };
115 
116 static struct pcmcia_chip_functions pcic_cbus_functions = {
117 	.mem_alloc	= pcic_chip_mem_alloc,
118 	.mem_free	= pcic_chip_mem_free,
119 	.mem_map	= pcic_chip_mem_map,
120 	.mem_unmap	= pcic_chip_mem_unmap,
121 
122 	.io_alloc	= pcic_cbus_chip_io_alloc,
123 	.io_free	= pcic_cbus_chip_io_free,
124 	.io_map		= pcic_chip_io_map,
125 	.io_unmap	= pcic_chip_io_unmap,
126 
127 	.intr_establish		= pcic_cbus_chip_intr_establish,
128 	.intr_disestablish	= pcic_cbus_chip_intr_disestablish,
129 	.intr_string		= pcic_cbus_chip_intr_string,
130 
131 	.socket_enable	= pcic_chip_socket_enable,
132 	.socket_disable	= pcic_chip_socket_disable,
133 };
134 
135 /*
136  * NEC PC-9801 architecture uses different IRQ notation from PC-AT
137  * architecture, so-called INT.  The MI pcic(4) driver internally uses
138  * IRQ, so here is a table to convert INT to IRQ.
139  */
140 static const int pcic_cbus_int2irq[NCBUSISR] = {
141 	PCIC_INTR_IRQ3,			/* INT 0 */
142 	PCIC_INTR_IRQ5,			/* INT 1 */
143 	PCIC_INTR_IRQ_RESERVED6,	/* INT 2 */
144 	PCIC_INTR_IRQ9,			/* INT 3 */
145 	PCIC_INTR_IRQ10,		/* INT 4(41) */
146 	PCIC_INTR_IRQ12,		/* INT 5 */
147 	PCIC_INTR_IRQ_RESERVED13	/* INT 6 */
148 };
149 
150 /* And, a table to convert IRQ to INT */
151 static const int pcic_cbus_irq2int[] = {
152 	-1, -1, -1,  0, -1,  1,  2, -1,	/* IRQ 0- 7 */
153 	-1,  3,  4, -1,  5,  6, -1, -1	/* IRQ 8-15 */
154 };
155 
156 struct pcic_ranges pcic_cbus_addr[] = {
157 	{ 0x340, 0x030 },
158 	{ 0x300, 0x030 },
159 	{ 0x390, 0x020 },
160 	{ 0x400, 0xbff },
161 	{ 0, 0},	/* terminator */
162 };
163 
164 int
pcic_cbus_probe(parent,match,aux)165 pcic_cbus_probe(parent, match, aux)
166 	struct device *parent;
167 	void *match, *aux;
168 {
169 	struct cfdata *cf = match;
170 	struct cbus_attach_args *caa = aux;
171 	bus_space_tag_t iot = &pcic_cbus_io_bst;
172 	bus_space_tag_t memt = &pcic_cbus_mem_bst;
173 	bus_space_handle_t ioh, memh;
174 	bus_size_t msize;
175 	int val, found;
176 
177 	if (strcmp(caa->ca_name, cf->cf_driver->cd_name) != 0)
178 		return (0);
179 
180 	SET_TAG_LITTLE_ENDIAN(iot);
181 	SET_TAG_LITTLE_ENDIAN(memt);
182 
183 	caa->ca_iobase = cf->cf_iobase;
184 	caa->ca_maddr  = cf->cf_maddr;
185 	caa->ca_msize  = cf->cf_msize;
186 	caa->ca_int    = cf->cf_int;
187 
188 	/* Disallow wildcarded i/o address. */
189 	if (caa->ca_iobase == -1)
190 		return (0);
191 
192 	if (bus_space_map(iot, caa->ca_iobase, PCIC_IOSIZE, 0, &ioh))
193 		return (0);
194 
195 	if (caa->ca_msize == -1)
196 		msize = PCIC_MEMSIZE;
197 	if (bus_space_map(memt, caa->ca_maddr, msize, 0, &memh))
198 		return (0);
199 
200 	found = 0;
201 
202 	/*
203 	 * this could be done with a loop, but it would violate the
204 	 * abstraction
205 	 */
206 
207 	bus_space_write_1(iot, ioh, PCIC_REG_INDEX, C0SA + PCIC_IDENT);
208 	val = bus_space_read_1(iot, ioh, PCIC_REG_DATA);
209 	if (pcic_ident_ok(val))
210 		found++;
211 
212 	bus_space_write_1(iot, ioh, PCIC_REG_INDEX, C0SB + PCIC_IDENT);
213 	val = bus_space_read_1(iot, ioh, PCIC_REG_DATA);
214 	if (pcic_ident_ok(val))
215 		found++;
216 
217 	bus_space_write_1(iot, ioh, PCIC_REG_INDEX, C1SA + PCIC_IDENT);
218 	val = bus_space_read_1(iot, ioh, PCIC_REG_DATA);
219 	if (pcic_ident_ok(val))
220 		found++;
221 
222 	bus_space_write_1(iot, ioh, PCIC_REG_INDEX, C1SB + PCIC_IDENT);
223 	val = bus_space_read_1(iot, ioh, PCIC_REG_DATA);
224 	if (pcic_ident_ok(val))
225 		found++;
226 
227 	bus_space_unmap(iot, ioh, PCIC_IOSIZE);
228 	bus_space_unmap(memt, memh, msize);
229 
230 	if (!found)
231 		return (0);
232 	caa->ca_iosize = PCIC_IOSIZE;
233 	caa->ca_msize = msize;
234 	return (1);
235 }
236 
237 void
pcic_cbus_attach(parent,self,aux)238 pcic_cbus_attach(parent, self, aux)
239 	struct device *parent, *self;
240 	void *aux;
241 {
242 	struct pcic_softc *sc = (void *)self;
243 	struct pcic_handle *h;
244 	struct cbus_attach_args *caa = aux;
245 	bus_space_tag_t iot = &pcic_cbus_io_bst;
246 	bus_space_tag_t memt = &pcic_cbus_mem_bst;
247 	bus_space_handle_t ioh;
248 	bus_space_handle_t memh;
249 	int intlevel, irq, i, reg;
250 
251 	SET_TAG_LITTLE_ENDIAN(iot);
252 	SET_TAG_LITTLE_ENDIAN(memt);
253 
254 	/* Map i/o space. */
255 	if (bus_space_map(iot, caa->ca_iobase, caa->ca_iosize, 0, &ioh)) {
256 		printf(": can't map i/o space\n");
257 		return;
258 	}
259 
260 	/* Map mem space. */
261 	if (bus_space_map(memt, caa->ca_maddr, caa->ca_msize, 0, &memh)) {
262 		printf(": can't map mem space\n");
263 		return;
264 	}
265 
266 	sc->membase = caa->ca_maddr;
267 	sc->subregionmask = (1 << (caa->ca_msize / PCIC_MEM_PAGESIZE)) - 1;
268 
269 	sc->intr_est = NULL;	/* not used on luna88k */
270 	sc->pct = (pcmcia_chipset_tag_t)&pcic_cbus_functions;
271 
272 	sc->iot = iot;
273 	sc->ioh = ioh;
274 	sc->memt = memt;
275 	sc->memh = memh;
276 
277 	printf("\n");
278 
279 	pcic_attach(sc);
280 
281 	sc->ranges = pcic_cbus_addr;
282 	sc->iobase = 0x0000;
283 	sc->iosize = 0x1000;
284 	DPRINTF(("%s: bus_space_alloc range 0x%04lx-0x%04lx\n",
285 	    sc->dev.dv_xname, (long) sc->iobase,
286 	    (long) sc->iobase + sc->iosize));
287 
288 	pcic_attach_sockets(sc);
289 
290 	/*
291 	 * Allocate an INT.  It will be used by both controllers.  We could
292 	 * use two different interrupts, but interrupts are relatively
293 	 * scarce, shareable, and for PCIC controllers, very infrequent.
294 	 */
295 	intlevel = pcic_cbus_intlevel_find();
296 	if (intlevel == -1) {
297 		printf("pcic_cbus_attach: no free int found\n");
298 		return;
299 	}
300 
301 	irq = pcic_cbus_int2irq[intlevel];
302 	cbus_isrlink(pcic_intr, sc, intlevel, IPL_TTY, sc->dev.dv_xname);
303 	sc->ih = (void *)pcic_intr;
304 	sc->irq = irq;
305 
306 	if (irq) {
307 		printf("%s: int %d (irq %d), ", sc->dev.dv_xname,
308 		    intlevel, irq);
309 
310 		/* Set up the pcic to interrupt on card detect. */
311 		for (i = 0; i < PCIC_NSLOTS; i++) {
312 			h = &sc->handle[i];
313 			if (h->flags & PCIC_FLAG_SOCKETP) {
314 				/* set 'pulse management interrupt' mode */
315 				reg = pcic_read(h, PCIC_CIRRUS_MISC_CTL_1);
316 				reg |= PCIC_CIRRUS_MISC_CTL_1_PULSE_MGMT_INTR;
317 				pcic_write(h, PCIC_CIRRUS_MISC_CTL_1, reg);
318 
319 				pcic_write(h, PCIC_CSC_INTR,
320 				    (sc->irq << PCIC_CSC_INTR_IRQ_SHIFT) |
321 				    PCIC_CSC_INTR_CD_ENABLE);
322 			}
323 		}
324 	} else
325 		printf("%s: no int, ", sc->dev.dv_xname);
326 
327 	printf("polling enabled\n");
328 	if (sc->poll_established == 0) {
329 		timeout_set(&sc->poll_timeout, pcic_poll_intr, sc);
330 		timeout_add_msec(&sc->poll_timeout, 500);
331 		sc->poll_established = 1;
332 	}
333 }
334 
335 void *
pcic_cbus_chip_intr_establish(pcmcia_chipset_handle_t pch,struct pcmcia_function * pf,int ipl,int (* fcl)(void *),void * arg,char * xname)336 pcic_cbus_chip_intr_establish(pcmcia_chipset_handle_t pch,
337 	struct pcmcia_function *pf, int ipl, int (*fcl)(void *),
338 	void *arg, char *xname)
339 {
340 	struct pcic_handle *h = (struct pcic_handle *)pch;
341 #ifdef PCICCBUSDEBUG
342 	struct pcic_softc *sc = (struct pcic_softc *)(h->ph_parent);
343 #endif
344 	int intlevel, irq, reg;
345 
346 #ifdef PCICCBUSDEBUG
347 	char buf[16];
348 	if (pf->cfe->flags & PCMCIA_CFE_IRQLEVEL)
349 		strlcpy(buf, "LEVEL", sizeof(buf));
350 	else if (pf->cfe->flags & PCMCIA_CFE_IRQPULSE)
351 		strlcpy(buf, "PULSE", sizeof(buf));
352 	else
353 		strlcpy(buf, "EDGE", sizeof(buf));
354 	printf("pcic_cbus_chip_intr_establish: IST_%s\n", buf);
355 #endif
356 
357 	/*
358 	 * If the PC Card has level-triggered interrupt property,
359 	 * we use CL-PD67XX 'pulse IRQ' feature.
360 	 */
361 	if (pf->cfe->flags & PCMCIA_CFE_IRQLEVEL) {
362 		reg = pcic_read(h, PCIC_CIRRUS_MISC_CTL_1);
363 		reg |= PCIC_CIRRUS_MISC_CTL_1_PULSE_SYS_IRQ;
364 		pcic_write(h, PCIC_CIRRUS_MISC_CTL_1, reg);
365 	}
366 
367 	intlevel = pcic_cbus_intlevel_find();
368 
369 	if (intlevel == -1) {
370 		printf("pcic_cbus_chip_intr_establish: no int found\n");
371 		return (NULL);
372 	}
373 
374 	irq = pcic_cbus_int2irq[intlevel];
375 	h->ih_irq = irq;
376 
377 	DPRINTF(("%s: pcic_cbus_chip_intr_establish int %d (irq %d)\n",
378 	    sc->dev.dv_xname, intlevel, h->ih_irq));
379 
380 	cbus_isrlink(fcl, arg, intlevel, ipl, h->pcmcia->dv_xname);
381 
382 	reg = pcic_read(h, PCIC_INTR);
383 	reg &= ~(PCIC_INTR_IRQ_MASK | PCIC_INTR_ENABLE);
384 	pcic_write(h, PCIC_INTR, reg | irq);
385 
386 	return (void *)fcl;
387 }
388 
389 void
pcic_cbus_chip_intr_disestablish(pcmcia_chipset_handle_t pch,void * ih)390 pcic_cbus_chip_intr_disestablish(pcmcia_chipset_handle_t pch, void *ih)
391 {
392 	struct pcic_handle *h = (struct pcic_handle *)pch;
393 #ifdef PCICCBUSDEBUG
394 	struct pcic_softc *sc = (struct pcic_softc *)(h->ph_parent);
395 #endif
396 	int intlevel, reg;
397 
398 	intlevel = pcic_cbus_irq2int[h->ih_irq];
399 
400 	DPRINTF(("%s: pcic_cbus_chip_intr_disestablish int %d (irq %d)\n",
401 	    sc->dev.dv_xname, intlevel, h->ih_irq));
402 
403 	if (intlevel == -1) {
404 		printf("pcic_cbus_chip_intr_disestablish: "
405 		    "strange int (irq = %d)\n", h->ih_irq);
406 		return;
407 	}
408 
409 	h->ih_irq = 0;
410 
411 	reg = pcic_read(h, PCIC_INTR);
412 	reg &= ~(PCIC_INTR_IRQ_MASK | PCIC_INTR_ENABLE);
413 	pcic_write(h, PCIC_INTR, reg);
414 
415 	cbus_isrunlink(ih, intlevel);
416 
417 	/* reset the 'pulse IRQ' mode */
418 	reg = pcic_read(h, PCIC_CIRRUS_MISC_CTL_1);
419 	reg &= ~PCIC_CIRRUS_MISC_CTL_1_PULSE_SYS_IRQ;
420 	pcic_write(h, PCIC_CIRRUS_MISC_CTL_1, reg);
421 }
422 
423 const char *
pcic_cbus_chip_intr_string(pcmcia_chipset_handle_t pch,void * ih)424 pcic_cbus_chip_intr_string(pcmcia_chipset_handle_t pch, void *ih)
425 {
426 	struct pcic_handle *h = (struct pcic_handle *)pch;
427 	static char irqstr[64];
428 
429 	if (ih == NULL)
430 		snprintf(irqstr, sizeof(irqstr),
431 		    "couldn't establish interrupt");
432 	else
433 		snprintf(irqstr, sizeof(irqstr), "int %d (irq %d)",
434 		    pcic_cbus_irq2int[h->ih_irq], h->ih_irq);
435 	return(irqstr);
436 }
437 
438 /*
439  * Find a free and pcic-compliant INT level; searching from highest
440  * (=small number) to lowest.
441  */
442 int
pcic_cbus_intlevel_find(void)443 pcic_cbus_intlevel_find(void)
444 {
445 	int intlevel, irq;
446 	u_int8_t cbus_not_used = ~cbus_intr_registered();
447 
448 	for (intlevel = 0; intlevel < NCBUSISR; intlevel++)
449 		if (cbus_not_used & (1 << (6 - intlevel))) {
450 			irq = pcic_cbus_int2irq[intlevel];
451 			if ((1 << irq) & PCIC_INTR_IRQ_VALIDMASK)
452 				break;
453 		}
454 
455 	if (intlevel == NCBUSISR)
456 		intlevel = -1;	/* not found */
457 
458 	return intlevel;
459 }
460 
461 /*
462  * LUNA specific pcic_cbus_chip_io_{alloc,free}
463  */
464 int
pcic_cbus_chip_io_alloc(pcmcia_chipset_handle_t pch,bus_addr_t start,bus_size_t size,bus_size_t align,struct pcmcia_io_handle * pcihp)465 pcic_cbus_chip_io_alloc(pcmcia_chipset_handle_t pch, bus_addr_t start,
466     bus_size_t size, bus_size_t align, struct pcmcia_io_handle *pcihp)
467 {
468 	struct pcic_handle *h = (struct pcic_handle *) pch;
469 	bus_space_tag_t iot;
470 	bus_space_handle_t ioh;
471 	bus_addr_t ioaddr, beg, fin;
472 	int flags = 0;
473 	struct pcic_softc *sc = (struct pcic_softc *)(h->ph_parent);
474 	struct pcic_ranges *range;
475 
476 	/*
477 	 * Allocate some arbitrary I/O space.
478 	 */
479 
480 	iot = sc->iot;
481 
482 	if (start) {
483 		ioaddr = start;
484 		if (bus_space_map(iot, start, size, 0, &ioh))
485 			return (1);
486 		DPRINTF(("pcic_cbus_chip_io_alloc map port %lx+%lx\n",
487 		    (u_long)ioaddr, (u_long)size));
488 	} else if (sc->ranges) {
489 		/*
490 		 * In this case, we know the "size" and "align" that
491 		 * we want.  So we need to start walking down
492 		 * sc->ranges, searching for a similar space that
493 		 * is (1) large enough for the size and alignment
494 		 * (2) then we need to try to allocate
495 		 * (3) if it fails to allocate, we try next range.
496 		 *
497 		 * We must also check that the start/size of each
498 		 * allocation we are about to do is within the bounds
499 		 * of "sc->iobase" and "sc->iosize".
500 		 * (Some pcmcia controllers handle a 12 bits of addressing,
501 		 * but we want to use the same range structure)
502 		 */
503 		for (range = sc->ranges; range->start; range++) {
504 			/* Potentially trim the range because of bounds. */
505 			beg = max(range->start, sc->iobase);
506 			fin = min(range->start + range->len,
507 			    sc->iobase + sc->iosize);
508 
509 			/* Short-circuit easy cases. */
510 			if (fin < beg || fin - beg < size)
511 				continue;
512 
513 			DPRINTF(("pcic_cbus_chip_io_alloc beg-fin %lx-%lx\n",
514 			    (u_long)beg, (u_long)fin));
515 			if (bus_space_map(iot, beg, size, 0, &ioh) == 0) {
516 				ioaddr = beg;
517 				break;
518 			}
519 		}
520 		if (range->start == 0)
521 			return (1);
522 		DPRINTF(("pcic_cbus_chip_io_alloc alloc port %lx+%lx\n",
523 		    (u_long)ioaddr, (u_long)size));
524 	} else {
525 		if (bus_space_map(iot, sc->iobase, size, 0, &ioh))
526 			return (1);
527 		ioaddr = sc->iobase;
528 		DPRINTF(("pcic_cbus_chip_io_alloc alloc port %lx+%lx\n",
529 		    (u_long)ioaddr, (u_long)size));
530 	}
531 
532 	pcihp->iot = iot;
533 	pcihp->ioh = ioh;
534 	pcihp->addr = ioaddr;
535 	pcihp->size = size;
536 	pcihp->flags = flags;
537 
538 	return (0);
539 }
540 
541 void
pcic_cbus_chip_io_free(pcmcia_chipset_handle_t pch,struct pcmcia_io_handle * pcihp)542 pcic_cbus_chip_io_free(pcmcia_chipset_handle_t pch,
543     struct pcmcia_io_handle *pcihp)
544 {
545 	bus_space_tag_t iot = pcihp->iot;
546 	bus_space_handle_t ioh = pcihp->ioh;
547 	bus_size_t size = pcihp->size;
548 
549 	bus_space_unmap(iot, ioh, size);
550 }
551