1107492Sobrien/* $NetBSD: pcmcia_cis.c,v 1.17 2000/02/10 09:01:52 chopps Exp $ */
2107492Sobrien/* $FreeBSD$ */
3107492Sobrien
4107492Sobrien/*-
5107492Sobrien * Copyright (c) 1997 Marc Horowitz.  All rights reserved.
6107492Sobrien *
7107492Sobrien * Redistribution and use in source and binary forms, with or without
8107492Sobrien * modification, are permitted provided that the following conditions
9107492Sobrien * are met:
10107492Sobrien * 1. Redistributions of source code must retain the above copyright
11107492Sobrien *    notice, this list of conditions and the following disclaimer.
12107492Sobrien * 2. Redistributions in binary form must reproduce the above copyright
13107492Sobrien *    notice, this list of conditions and the following disclaimer in the
14107492Sobrien *    documentation and/or other materials provided with the distribution.
15107492Sobrien * 3. All advertising materials mentioning features or use of this software
16107492Sobrien *    must display the following acknowledgement:
17107492Sobrien *	This product includes software developed by Marc Horowitz.
18107492Sobrien * 4. The name of the author may not be used to endorse or promote products
19107492Sobrien *    derived from this software without specific prior written permission.
20107492Sobrien *
21107492Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22107492Sobrien * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23107492Sobrien * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24107492Sobrien * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25107492Sobrien * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26107492Sobrien * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27107492Sobrien * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28107492Sobrien * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29107492Sobrien * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30107492Sobrien * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31107492Sobrien */
32107492Sobrien
33107492Sobrien#include <sys/param.h>
34107492Sobrien#include <sys/systm.h>
35107492Sobrien#include <sys/malloc.h>
36107492Sobrien#include <sys/module.h>
37107492Sobrien#include <sys/kernel.h>
38107492Sobrien#include <sys/queue.h>
39107492Sobrien#include <sys/types.h>
40107492Sobrien
41107492Sobrien#include <sys/bus.h>
42107492Sobrien#include <machine/bus.h>
43107492Sobrien#include <sys/rman.h>
44107492Sobrien#include <machine/resource.h>
45107492Sobrien
46107492Sobrien#include <dev/pccard/pccardreg.h>
47107492Sobrien#include <dev/pccard/pccardvar.h>
48107492Sobrien#include <dev/pccard/pccardvarp.h>
49107492Sobrien#include <dev/pccard/pccard_cis.h>
50107492Sobrien
51107492Sobrien#include "card_if.h"
52107492Sobrien
53107492Sobrienextern int	pccard_cis_debug;
54107492Sobrien
55107492Sobrien#define PCCARDCISDEBUG
56107492Sobrien#ifdef PCCARDCISDEBUG
57107492Sobrien#define	DPRINTF(arg) do { if (pccard_cis_debug) printf arg; } while (0)
58107492Sobrien#define	DEVPRINTF(arg) do { if (pccard_cis_debug) device_printf arg; } while (0)
59107492Sobrien#else
60107492Sobrien#define	DPRINTF(arg)
61107492Sobrien#define	DEVPRINTF(arg)
62107492Sobrien#endif
63107492Sobrien
64107492Sobrien#define	PCCARD_CIS_SIZE		4096
65107492Sobrien
66107492Sobrienstruct cis_state {
67107492Sobrien	int	count;
68107492Sobrien	int	gotmfc;
69107492Sobrien	struct pccard_config_entry temp_cfe;
70107492Sobrien	struct pccard_config_entry *default_cfe;
71107492Sobrien	struct pccard_card *card;
72107492Sobrien	struct pccard_function *pf;
73107492Sobrien};
74107492Sobrien
75107492Sobrienstatic int pccard_parse_cis_tuple(const struct pccard_tuple *, void *);
76107492Sobrienstatic int decode_funce(const struct pccard_tuple *, struct pccard_function *);
77107492Sobrien
78107492Sobrienvoid
79107492Sobrienpccard_read_cis(struct pccard_softc *sc)
80107492Sobrien{
81107492Sobrien	struct cis_state state;
82107492Sobrien
83107492Sobrien	bzero(&state, sizeof state);
84107492Sobrien	state.card = &sc->card;
85107492Sobrien	state.card->error = 0;
86107492Sobrien	state.card->cis1_major = -1;
87107492Sobrien	state.card->cis1_minor = -1;
88107492Sobrien	state.card->cis1_info[0] = NULL;
89104834Sobrien	state.card->cis1_info[1] = NULL;
90104834Sobrien	state.card->cis1_info[2] = NULL;
91104834Sobrien	state.card->cis1_info[3] = NULL;
92104834Sobrien	state.card->manufacturer = PCMCIA_VENDOR_INVALID;
93104834Sobrien	state.card->product = PCMCIA_PRODUCT_INVALID;
94104834Sobrien	STAILQ_INIT(&state.card->pf_head);
95104834Sobrien	state.pf = NULL;
96104834Sobrien
97104834Sobrien	/*
98104834Sobrien	 * XXX The following shouldn't be needed, but some slow cards
99104834Sobrien	 * XXX seem to need it still.  Need to investigate if there's
100104834Sobrien	 * XXX a way to tell if the card is 'ready' or not rather than
101104834Sobrien	 * XXX sleeping like this.  We're called just after the power
102104834Sobrien	 * XXX up of the socket.  The standard timing diagrams don't
103104834Sobrien	 * XXX seem to indicate that a delay is required.  The old
104104834Sobrien	 * XXX delay was 1s.  This delay is .1s.
105104834Sobrien	 */
106104834Sobrien	pause("pccard", hz / 10);
107104834Sobrien	if (pccard_scan_cis(device_get_parent(sc->dev), sc->dev,
108104834Sobrien	    pccard_parse_cis_tuple, &state) == -1)
109104834Sobrien		state.card->error++;
110104834Sobrien}
111104834Sobrien
112104834Sobrienint
113104834Sobrienpccard_scan_cis(device_t bus, device_t dev, pccard_scan_t fct, void *arg)
114104834Sobrien{
115104834Sobrien	struct resource *res;
116104834Sobrien	int rid;
117104834Sobrien	struct pccard_tuple tuple;
118104834Sobrien	int longlink_present;
119104834Sobrien	int longlink_common;
120104834Sobrien	u_long longlink_addr;		/* Type suspect */
121104834Sobrien	int mfc_count;
122104834Sobrien	int mfc_index;
123104834Sobrien#ifdef PCCARDCISDEBUG
124104834Sobrien	int cis_none_cnt = 10;	/* Only report 10 CIS_NONEs */
125104834Sobrien#endif
126104834Sobrien	struct {
127104834Sobrien		int	common;
128104834Sobrien		u_long	addr;
129104834Sobrien	} mfc[256 / 5];
130104834Sobrien	int ret;
131104834Sobrien
132104834Sobrien	ret = 0;
133104834Sobrien
134104834Sobrien	/* allocate some memory */
135104834Sobrien
136104834Sobrien	/*
137104834Sobrien	 * Some reports from the field suggest that a 64k memory boundary
138104834Sobrien	 * helps card CIS being able to be read.  Try it here and see what
139104834Sobrien	 * the results actually are.  I'm not sure I understand why this
140104834Sobrien	 * would make cards work better, but it is easy enough to test.
141104834Sobrien	 */
142104834Sobrien	rid = 0;
143104834Sobrien	res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 0, ~0,
144104834Sobrien	    PCCARD_CIS_SIZE, RF_ACTIVE | rman_make_alignment_flags(64*1024));
145104834Sobrien	if (res == NULL) {
146104834Sobrien		device_printf(dev, "can't alloc memory to read attributes\n");
147104834Sobrien		return -1;
148104834Sobrien	}
149104834Sobrien	CARD_SET_RES_FLAGS(bus, dev, SYS_RES_MEMORY, rid, PCCARD_A_MEM_ATTR);
150104834Sobrien	tuple.memt = rman_get_bustag(res);
151104834Sobrien	tuple.memh = rman_get_bushandle(res);
152104834Sobrien	tuple.ptr = 0;
153104834Sobrien
154104834Sobrien	DPRINTF(("cis mem map %#x (resource: %#lx)\n",
155104834Sobrien	    (unsigned int) tuple.memh, rman_get_start(res)));
156104834Sobrien
157104834Sobrien	tuple.mult = 2;
158104834Sobrien
159104834Sobrien	longlink_present = 1;
160104834Sobrien	longlink_common = 1;
161104834Sobrien	longlink_addr = 0;
162104834Sobrien
163104834Sobrien	mfc_count = 0;
164104834Sobrien	mfc_index = 0;
165104834Sobrien
166104834Sobrien	DEVPRINTF((dev, "CIS tuple chain:\n"));
167104834Sobrien
168104834Sobrien	while (1) {
169104834Sobrien		while (1) {
170104834Sobrien			/*
171104834Sobrien			 * Perform boundary check for insane cards.
172104834Sobrien			 * If CIS is too long, simulate CIS end.
173104834Sobrien			 * (This check may not be sufficient for
174104834Sobrien			 * malicious cards.)
175104834Sobrien			 */
176104834Sobrien			if (tuple.mult * tuple.ptr >= PCCARD_CIS_SIZE - 1
177104834Sobrien			    - 32 /* ad hoc value */ ) {
178104834Sobrien				printf("CIS is too long -- truncating\n");
179104834Sobrien				tuple.code = CISTPL_END;
180104834Sobrien			} else {
181104834Sobrien				/* get the tuple code */
182104834Sobrien				tuple.code = pccard_cis_read_1(&tuple, tuple.ptr);
183104834Sobrien			}
184104834Sobrien
185104834Sobrien			/* two special-case tuples */
186104834Sobrien
187104834Sobrien			if (tuple.code == CISTPL_NULL) {
188104834Sobrien#ifdef PCCARDCISDEBUG
189104834Sobrien				if (cis_none_cnt > 0)
190104834Sobrien					DPRINTF(("CISTPL_NONE\n 00\n"));
191104834Sobrien				else if (cis_none_cnt == 0)
192104834Sobrien					DPRINTF(("TOO MANY CIS_NONE\n"));
193104834Sobrien				cis_none_cnt--;
194104834Sobrien#endif
195104834Sobrien				if ((*fct)(&tuple, arg)) {
196104834Sobrien					ret = 1;
197104834Sobrien					goto done;
198104834Sobrien				}
199104834Sobrien				tuple.ptr++;
200104834Sobrien				continue;
201104834Sobrien			} else if (tuple.code == CISTPL_END) {
202104834Sobrien				DPRINTF(("CISTPL_END\n ff\n"));
203104834Sobrien				/* Call the function for the END tuple, since
204104834Sobrien				   the CIS semantics depend on it */
205104834Sobrien				if ((*fct)(&tuple, arg)) {
206104834Sobrien					ret = 1;
207104834Sobrien					goto done;
208104834Sobrien				}
209104834Sobrien				tuple.ptr++;
210104834Sobrien				break;
211104834Sobrien			}
212104834Sobrien			/* now all the normal tuples */
213104834Sobrien
214104834Sobrien			tuple.length = pccard_cis_read_1(&tuple, tuple.ptr + 1);
215104834Sobrien			switch (tuple.code) {
216104834Sobrien			case CISTPL_LONGLINK_A:
217104834Sobrien			case CISTPL_LONGLINK_C:
218104834Sobrien				if ((*fct)(&tuple, arg)) {
219104834Sobrien					ret = 1;
220104834Sobrien					goto done;
221104834Sobrien				}
222104834Sobrien				if (tuple.length < 4) {
223104834Sobrien					DPRINTF(("CISTPL_LONGLINK_%s too "
224104834Sobrien					    "short %d\n",
225104834Sobrien					    longlink_common ? "C" : "A",
226104834Sobrien					    tuple.length));
227104834Sobrien					break;
228104834Sobrien				}
229104834Sobrien				longlink_present = 1;
230104834Sobrien				longlink_common = (tuple.code ==
231104834Sobrien				    CISTPL_LONGLINK_C) ? 1 : 0;
232104834Sobrien				longlink_addr = pccard_tuple_read_4(&tuple, 0);
233104834Sobrien				DPRINTF(("CISTPL_LONGLINK_%s %#lx\n",
234104834Sobrien				    longlink_common ? "C" : "A",
235104834Sobrien				    longlink_addr));
236104834Sobrien				break;
237104834Sobrien			case CISTPL_NO_LINK:
238104834Sobrien				if ((*fct)(&tuple, arg)) {
239104834Sobrien					ret = 1;
240104834Sobrien					goto done;
241104834Sobrien				}
242104834Sobrien				longlink_present = 0;
243104834Sobrien				DPRINTF(("CISTPL_NO_LINK\n"));
244104834Sobrien				break;
245104834Sobrien			case CISTPL_CHECKSUM:
246104834Sobrien				if ((*fct)(&tuple, arg)) {
247104834Sobrien					ret = 1;
248104834Sobrien					goto done;
249104834Sobrien				}
250104834Sobrien				if (tuple.length < 5) {
251104834Sobrien					DPRINTF(("CISTPL_CHECKSUM too "
252104834Sobrien					    "short %d\n", tuple.length));
253104834Sobrien					break;
254104834Sobrien				} {
255104834Sobrien					int16_t offset;
256104834Sobrien					u_long addr, length;
257104834Sobrien					u_int cksum, sum;
258104834Sobrien					int i;
259104834Sobrien
260104834Sobrien					offset = (uint16_t)
261104834Sobrien					    pccard_tuple_read_2(&tuple, 0);
262104834Sobrien					length = pccard_tuple_read_2(&tuple, 2);
263104834Sobrien					cksum = pccard_tuple_read_1(&tuple, 4);
264104834Sobrien
265104834Sobrien					addr = tuple.ptr + offset;
266104834Sobrien
267104834Sobrien					DPRINTF(("CISTPL_CHECKSUM addr=%#lx "
268104834Sobrien					    "len=%#lx cksum=%#x",
269104834Sobrien					    addr, length, cksum));
270104834Sobrien
271104834Sobrien					/*
272104834Sobrien					 * XXX do more work to deal with
273104834Sobrien					 * distant regions
274104834Sobrien					 */
275104834Sobrien					if ((addr >= PCCARD_CIS_SIZE) ||
276104834Sobrien					    ((addr + length) >=
277104834Sobrien					    PCCARD_CIS_SIZE)) {
278104834Sobrien						DPRINTF((" skipped, "
279104834Sobrien						    "too distant\n"));
280104834Sobrien						break;
281104834Sobrien					}
282104834Sobrien					sum = 0;
283104834Sobrien					for (i = 0; i < length; i++)
284104834Sobrien						sum +=
285104834Sobrien						    bus_space_read_1(tuple.memt,
286104834Sobrien						    tuple.memh,
287104834Sobrien						    addr + tuple.mult * i);
288104834Sobrien					if (cksum != (sum & 0xff)) {
289104834Sobrien						DPRINTF((" failed sum=%#x\n",
290104834Sobrien						    sum));
291104834Sobrien						device_printf(dev,
292104834Sobrien						    "CIS checksum failed\n");
293104834Sobrien#if 0
294104834Sobrien						/*
295104834Sobrien						 * XXX Some working cards have
296104834Sobrien						 * XXX bad checksums!!
297104834Sobrien						 */
298104834Sobrien						ret = -1;
299104834Sobrien#endif
300104834Sobrien					} else {
301104834Sobrien						DPRINTF((" ok\n"));
302104834Sobrien					}
303104834Sobrien				}
304104834Sobrien				break;
305104834Sobrien			case CISTPL_LONGLINK_MFC:
306104834Sobrien				if (tuple.length < 1) {
307104834Sobrien					DPRINTF(("CISTPL_LONGLINK_MFC too "
308104834Sobrien					    "short %d\n", tuple.length));
309104834Sobrien					break;
310104834Sobrien				}
311104834Sobrien				if (((tuple.length - 1) % 5) != 0) {
312104834Sobrien					DPRINTF(("CISTPL_LONGLINK_MFC bogus "
313104834Sobrien					    "length %d\n", tuple.length));
314104834Sobrien					break;
315104834Sobrien				}
316104834Sobrien				/*
317104834Sobrien				 * this is kind of ad hoc, as I don't have
318104834Sobrien				 * any real documentation
319104834Sobrien				 */
320104834Sobrien				{
321104834Sobrien					int i, tmp_count;
322104834Sobrien
323104834Sobrien					/*
324104834Sobrien					 * put count into tmp var so that
325104834Sobrien					 * if we have to bail (because it's
326104834Sobrien					 * a bogus count) it won't be
327104834Sobrien					 * remembered for later use.
328104834Sobrien					 */
329104834Sobrien					tmp_count =
330104834Sobrien					    pccard_tuple_read_1(&tuple, 0);
331104834Sobrien
332104834Sobrien					DPRINTF(("CISTPL_LONGLINK_MFC %d",
333104834Sobrien					    tmp_count));
334104834Sobrien
335104834Sobrien					/*
336104834Sobrien					 * make _sure_ it's the right size;
337104834Sobrien					 * if too short, it may be a weird
338104834Sobrien					 * (unknown/undefined) format
339104834Sobrien					 */
340104834Sobrien					if (tuple.length != (tmp_count*5 + 1)) {
341104834Sobrien						DPRINTF((" bogus length %d\n",
342104834Sobrien						    tuple.length));
343104834Sobrien						break;
344104834Sobrien					}
345104834Sobrien					/*
346104834Sobrien					 * sanity check for a programming
347104834Sobrien					 * error which is difficult to find
348104834Sobrien					 * when debugging.
349104834Sobrien					 */
350104834Sobrien					if (tmp_count >
351104834Sobrien					    howmany(sizeof mfc, sizeof mfc[0]))
352104834Sobrien						panic("CISTPL_LONGLINK_MFC mfc "
353104834Sobrien						    "count would blow stack");
354104834Sobrien                                        mfc_count = tmp_count;
355104834Sobrien					for (i = 0; i < mfc_count; i++) {
356104834Sobrien						mfc[i].common =
357104834Sobrien						    (pccard_tuple_read_1(&tuple,
358104834Sobrien						    1 + 5 * i) ==
359104834Sobrien						    PCCARD_MFC_MEM_COMMON) ?
360104834Sobrien						    1 : 0;
361104834Sobrien						mfc[i].addr =
362104834Sobrien						    pccard_tuple_read_4(&tuple,
363104834Sobrien						    1 + 5 * i + 1);
364104834Sobrien						DPRINTF((" %s:%#lx",
365104834Sobrien						    mfc[i].common ? "common" :
366104834Sobrien						    "attr", mfc[i].addr));
367104834Sobrien					}
368104834Sobrien					DPRINTF(("\n"));
369104834Sobrien				}
370104834Sobrien				/*
371104834Sobrien				 * for LONGLINK_MFC, fall through to the
372104834Sobrien				 * function.  This tuple has structural and
373104834Sobrien				 * semantic content.
374104834Sobrien				 */
375104834Sobrien			default:
376104834Sobrien				{
377104834Sobrien					if ((*fct)(&tuple, arg)) {
378104834Sobrien						ret = 1;
379104834Sobrien						goto done;
380104834Sobrien					}
381104834Sobrien				}
382104834Sobrien				break;
383104834Sobrien			}	/* switch */
384104834Sobrien#ifdef PCCARDCISDEBUG
385104834Sobrien			/* print the tuple */
386104834Sobrien			{
387104834Sobrien				int i;
388104834Sobrien
389104834Sobrien				DPRINTF((" %#02x %#02x", tuple.code,
390104834Sobrien				    tuple.length));
391104834Sobrien
392104834Sobrien				for (i = 0; i < tuple.length; i++) {
393104834Sobrien					DPRINTF((" %#02x",
394104834Sobrien					    pccard_tuple_read_1(&tuple, i)));
395104834Sobrien					if ((i % 16) == 13)
396104834Sobrien						DPRINTF(("\n"));
397104834Sobrien				}
398104834Sobrien
399104834Sobrien				if ((i % 16) != 14)
400104834Sobrien					DPRINTF(("\n"));
401104834Sobrien			}
402104834Sobrien#endif
403104834Sobrien			/* skip to the next tuple */
404104834Sobrien			tuple.ptr += 2 + tuple.length;
405104834Sobrien		}
406104834Sobrien
407104834Sobrien		/*
408104834Sobrien		 * the chain is done.  Clean up and move onto the next one,
409104834Sobrien		 * if any.  The loop is here in the case that there is an MFC
410104834Sobrien		 * card with no longlink (which defaults to existing, == 0).
411104834Sobrien		 * In general, this means that if one pointer fails, it will
412104834Sobrien		 * try the next one, instead of just bailing.
413104834Sobrien		 */
414104834Sobrien		while (1) {
415104834Sobrien			if (longlink_present) {
416104834Sobrien				CARD_SET_RES_FLAGS(bus, dev, SYS_RES_MEMORY,
417104834Sobrien				    rid, longlink_common ?
418104834Sobrien				    PCCARD_A_MEM_COM : PCCARD_A_MEM_ATTR);
419104834Sobrien				DPRINTF(("cis mem map %#x\n",
420104834Sobrien				    (unsigned int) tuple.memh));
421104834Sobrien				tuple.mult = longlink_common ? 1 : 2;
422104834Sobrien				tuple.ptr = longlink_addr;
423104834Sobrien				longlink_present = 0;
424104834Sobrien				longlink_common = 1;
425104834Sobrien				longlink_addr = 0;
426104834Sobrien			} else if (mfc_count && (mfc_index < mfc_count)) {
427104834Sobrien				CARD_SET_RES_FLAGS(bus, dev, SYS_RES_MEMORY,
428104834Sobrien				    rid, mfc[mfc_index].common ?
429104834Sobrien				    PCCARD_A_MEM_COM : PCCARD_A_MEM_ATTR);
430104834Sobrien				DPRINTF(("cis mem map %#x\n",
431104834Sobrien				    (unsigned int) tuple.memh));
432104834Sobrien				/* set parse state, and point at the next one */
433104834Sobrien				tuple.mult = mfc[mfc_index].common ? 1 : 2;
434104834Sobrien				tuple.ptr = mfc[mfc_index].addr;
435104834Sobrien				mfc_index++;
436104834Sobrien			} else {
437104834Sobrien				goto done;
438104834Sobrien			}
439104834Sobrien
440104834Sobrien			/* make sure that the link is valid */
441104834Sobrien			tuple.code = pccard_cis_read_1(&tuple, tuple.ptr);
442104834Sobrien			if (tuple.code != CISTPL_LINKTARGET) {
443104834Sobrien				DPRINTF(("CISTPL_LINKTARGET expected, "
444104834Sobrien				    "code %#02x observed\n", tuple.code));
445104834Sobrien				continue;
446104834Sobrien			}
447104834Sobrien			tuple.length = pccard_cis_read_1(&tuple, tuple.ptr + 1);
448104834Sobrien			if (tuple.length < 3) {
449104834Sobrien				DPRINTF(("CISTPL_LINKTARGET too short %d\n",
450104834Sobrien				    tuple.length));
451104834Sobrien				continue;
452104834Sobrien			}
453104834Sobrien			if ((pccard_tuple_read_1(&tuple, 0) != 'C') ||
454104834Sobrien			    (pccard_tuple_read_1(&tuple, 1) != 'I') ||
455104834Sobrien			    (pccard_tuple_read_1(&tuple, 2) != 'S')) {
456104834Sobrien				DPRINTF(("CISTPL_LINKTARGET magic "
457104834Sobrien				    "%02x%02x%02x incorrect\n",
458104834Sobrien				    pccard_tuple_read_1(&tuple, 0),
459104834Sobrien				    pccard_tuple_read_1(&tuple, 1),
460104834Sobrien				    pccard_tuple_read_1(&tuple, 2)));
461104834Sobrien				continue;
462104834Sobrien			}
463104834Sobrien			tuple.ptr += 2 + tuple.length;
464104834Sobrien			break;
465104834Sobrien		}
466104834Sobrien	}
467104834Sobrien
468104834Sobriendone:
469104834Sobrien	bus_release_resource(dev, SYS_RES_MEMORY, rid, res);
470104834Sobrien
471104834Sobrien	return (ret);
472104834Sobrien}
473104834Sobrien
474104834Sobrien/* XXX this is incredibly verbose.  Not sure what trt is */
475104834Sobrien
476104834Sobrienvoid
477104834Sobrienpccard_print_cis(device_t dev)
478104834Sobrien{
479104834Sobrien	struct pccard_softc *sc = PCCARD_SOFTC(dev);
480104834Sobrien	struct pccard_card *card = &sc->card;
481104834Sobrien	struct pccard_function *pf;
482104834Sobrien	struct pccard_config_entry *cfe;
483104834Sobrien	int i;
484104834Sobrien
485104834Sobrien	device_printf(dev, "CIS version ");
486104834Sobrien	if (card->cis1_major == 4) {
487104834Sobrien		if (card->cis1_minor == 0)
488104834Sobrien			printf("PCCARD 1.0\n");
489104834Sobrien		else if (card->cis1_minor == 1)
490104834Sobrien			printf("PCCARD 2.0 or 2.1\n");
491104834Sobrien	} else if (card->cis1_major >= 5)
492104834Sobrien		printf("PC Card Standard %d.%d\n", card->cis1_major, card->cis1_minor);
493104834Sobrien	else
494104834Sobrien		printf("unknown (major=%d, minor=%d)\n",
495104834Sobrien		    card->cis1_major, card->cis1_minor);
496104834Sobrien
497104834Sobrien	device_printf(dev, "CIS info: ");
498104834Sobrien	for (i = 0; i < 4; i++) {
499104834Sobrien		if (card->cis1_info[i] == NULL)
500104834Sobrien			break;
501104834Sobrien		if (i)
502104834Sobrien			printf(", ");
503104834Sobrien		printf("%s", card->cis1_info[i]);
504104834Sobrien	}
505104834Sobrien	printf("\n");
506104834Sobrien
507104834Sobrien	device_printf(dev, "Manufacturer code %#x, product %#x\n",
508104834Sobrien	    card->manufacturer, card->product);
509104834Sobrien
510104834Sobrien	STAILQ_FOREACH(pf, &card->pf_head, pf_list) {
511104834Sobrien		device_printf(dev, "function %d: ", pf->number);
512104834Sobrien
513104834Sobrien		switch (pf->function) {
514104834Sobrien		case PCCARD_FUNCTION_UNSPEC:
515104834Sobrien			printf("unspecified");
516104834Sobrien			break;
517104834Sobrien		case PCCARD_FUNCTION_MULTIFUNCTION:
518104834Sobrien			printf("multi-function");
519104834Sobrien			break;
520104834Sobrien		case PCCARD_FUNCTION_MEMORY:
521104834Sobrien			printf("memory");
522104834Sobrien			break;
523104834Sobrien		case PCCARD_FUNCTION_SERIAL:
524104834Sobrien			printf("serial port");
525104834Sobrien			break;
526104834Sobrien		case PCCARD_FUNCTION_PARALLEL:
527104834Sobrien			printf("parallel port");
528104834Sobrien			break;
529104834Sobrien		case PCCARD_FUNCTION_DISK:
530104834Sobrien			printf("fixed disk");
531104834Sobrien			break;
532104834Sobrien		case PCCARD_FUNCTION_VIDEO:
533104834Sobrien			printf("video adapter");
534104834Sobrien			break;
535104834Sobrien		case PCCARD_FUNCTION_NETWORK:
536104834Sobrien			printf("network adapter");
537104834Sobrien			break;
538104834Sobrien		case PCCARD_FUNCTION_AIMS:
539104834Sobrien			printf("auto incrementing mass storage");
540104834Sobrien			break;
541104834Sobrien		case PCCARD_FUNCTION_SCSI:
542104834Sobrien			printf("SCSI bridge");
543104834Sobrien			break;
544104834Sobrien		case PCCARD_FUNCTION_SECURITY:
545104834Sobrien			printf("Security services");
546104834Sobrien			break;
547104834Sobrien		case PCCARD_FUNCTION_INSTRUMENT:
548104834Sobrien			printf("Instrument");
549104834Sobrien			break;
550104834Sobrien		default:
551104834Sobrien			printf("unknown (%d)", pf->function);
552104834Sobrien			break;
553104834Sobrien		}
554104834Sobrien
555104834Sobrien		printf(", ccr addr %#x mask %#x\n", pf->ccr_base, pf->ccr_mask);
556104834Sobrien
557104834Sobrien		STAILQ_FOREACH(cfe, &pf->cfe_head, cfe_list) {
558104834Sobrien			device_printf(dev, "function %d, config table entry "
559104834Sobrien			    "%d: ", pf->number, cfe->number);
560104834Sobrien
561104834Sobrien			switch (cfe->iftype) {
562104834Sobrien			case PCCARD_IFTYPE_MEMORY:
563104834Sobrien				printf("memory card");
564104834Sobrien				break;
565104834Sobrien			case PCCARD_IFTYPE_IO:
566104834Sobrien				printf("I/O card");
567104834Sobrien				break;
568104834Sobrien			default:
569104834Sobrien				printf("card type unknown");
570104834Sobrien				break;
571104834Sobrien			}
572104834Sobrien
573104834Sobrien			printf("; irq mask %#x", cfe->irqmask);
574104834Sobrien
575104834Sobrien			if (cfe->num_iospace) {
576104834Sobrien				printf("; iomask %#lx, iospace", cfe->iomask);
577104834Sobrien
578104834Sobrien				for (i = 0; i < cfe->num_iospace; i++) {
579104834Sobrien					printf(" %#lx", cfe->iospace[i].start);
580104834Sobrien					if (cfe->iospace[i].length)
581104834Sobrien						printf("-%#lx",
582104834Sobrien						    cfe->iospace[i].start +
583104834Sobrien						    cfe->iospace[i].length - 1);
584104834Sobrien				}
585104834Sobrien			}
586104834Sobrien			if (cfe->num_memspace) {
587104834Sobrien				printf("; memspace");
588104834Sobrien
589104834Sobrien				for (i = 0; i < cfe->num_memspace; i++) {
590104834Sobrien					printf(" %#lx",
591104834Sobrien					    cfe->memspace[i].cardaddr);
592104834Sobrien					if (cfe->memspace[i].length)
593104834Sobrien						printf("-%#lx",
594104834Sobrien						    cfe->memspace[i].cardaddr +
595104834Sobrien						    cfe->memspace[i].length - 1);
596104834Sobrien					if (cfe->memspace[i].hostaddr)
597104834Sobrien						printf("@%#lx",
598104834Sobrien						    cfe->memspace[i].hostaddr);
599104834Sobrien				}
600104834Sobrien			}
601104834Sobrien			if (cfe->maxtwins)
602104834Sobrien				printf("; maxtwins %d", cfe->maxtwins);
603104834Sobrien
604104834Sobrien			printf(";");
605104834Sobrien
606104834Sobrien			if (cfe->flags & PCCARD_CFE_MWAIT_REQUIRED)
607104834Sobrien				printf(" mwait_required");
608104834Sobrien			if (cfe->flags & PCCARD_CFE_RDYBSY_ACTIVE)
609104834Sobrien				printf(" rdybsy_active");
610104834Sobrien			if (cfe->flags & PCCARD_CFE_WP_ACTIVE)
611104834Sobrien				printf(" wp_active");
612104834Sobrien			if (cfe->flags & PCCARD_CFE_BVD_ACTIVE)
613104834Sobrien				printf(" bvd_active");
614104834Sobrien			if (cfe->flags & PCCARD_CFE_IO8)
615104834Sobrien				printf(" io8");
616104834Sobrien			if (cfe->flags & PCCARD_CFE_IO16)
617104834Sobrien				printf(" io16");
618104834Sobrien			if (cfe->flags & PCCARD_CFE_IRQSHARE)
619104834Sobrien				printf(" irqshare");
620104834Sobrien			if (cfe->flags & PCCARD_CFE_IRQPULSE)
621104834Sobrien				printf(" irqpulse");
622104834Sobrien			if (cfe->flags & PCCARD_CFE_IRQLEVEL)
623104834Sobrien				printf(" irqlevel");
624104834Sobrien			if (cfe->flags & PCCARD_CFE_POWERDOWN)
625104834Sobrien				printf(" powerdown");
626104834Sobrien			if (cfe->flags & PCCARD_CFE_READONLY)
627104834Sobrien				printf(" readonly");
628104834Sobrien			if (cfe->flags & PCCARD_CFE_AUDIO)
629104834Sobrien				printf(" audio");
630104834Sobrien
631104834Sobrien			printf("\n");
632104834Sobrien		}
633104834Sobrien	}
634104834Sobrien
635104834Sobrien	if (card->error)
636104834Sobrien		device_printf(dev, "%d errors found while parsing CIS\n",
637104834Sobrien		    card->error);
638104834Sobrien}
639104834Sobrien
640104834Sobrienstatic int
641104834Sobrienpccard_parse_cis_tuple(const struct pccard_tuple *tuple, void *arg)
642104834Sobrien{
643104834Sobrien	/* most of these are educated guesses */
644104834Sobrien	static struct pccard_config_entry init_cfe = {
645104834Sobrien		-1, PCCARD_CFE_RDYBSY_ACTIVE | PCCARD_CFE_WP_ACTIVE |
646104834Sobrien		PCCARD_CFE_BVD_ACTIVE, PCCARD_IFTYPE_MEMORY,
647104834Sobrien	};
648104834Sobrien
649104834Sobrien	struct cis_state *state = arg;
650104834Sobrien
651104834Sobrien	switch (tuple->code) {
652104834Sobrien	case CISTPL_END:
653104834Sobrien		/* if we've seen a LONGLINK_MFC, and this is the first
654104834Sobrien		 * END after it, reset the function list.
655104834Sobrien		 *
656104834Sobrien		 * XXX This might also be the right place to start a
657104834Sobrien		 * new function, but that assumes that a function
658104834Sobrien		 * definition never crosses any longlink, and I'm not
659104834Sobrien		 * sure about that.  This is probably safe for MFC
660104834Sobrien		 * cards, but what we have now isn't broken, so I'd
661104834Sobrien		 * rather not change it.
662104834Sobrien		 */
663104834Sobrien		if (state->gotmfc == 1) {
664104834Sobrien			struct pccard_function *pf, *pfnext;
665104834Sobrien
666104834Sobrien			for (pf = STAILQ_FIRST(&state->card->pf_head);
667104834Sobrien			     pf != NULL; pf = pfnext) {
668104834Sobrien				pfnext = STAILQ_NEXT(pf, pf_list);
669104834Sobrien				free(pf, M_DEVBUF);
670104834Sobrien			}
671104834Sobrien
672104834Sobrien			STAILQ_INIT(&state->card->pf_head);
673104834Sobrien
674104834Sobrien			state->count = 0;
675104834Sobrien			state->gotmfc = 2;
676104834Sobrien			state->pf = NULL;
677104834Sobrien		}
678104834Sobrien		break;
679104834Sobrien	case CISTPL_LONGLINK_MFC:
680104834Sobrien		/*
681104834Sobrien		 * this tuple's structure was dealt with in scan_cis.  here,
682104834Sobrien		 * record the fact that the MFC tuple was seen, so that
683104834Sobrien		 * functions declared before the MFC link can be cleaned
684104834Sobrien		 * up.
685104834Sobrien		 */
686104834Sobrien		state->gotmfc = 1;
687104834Sobrien		break;
688104834Sobrien#ifdef PCCARDCISDEBUG
689104834Sobrien	case CISTPL_DEVICE:
690104834Sobrien	case CISTPL_DEVICE_A:
691104834Sobrien		{
692104834Sobrien			u_int reg, dtype, dspeed;
693104834Sobrien
694104834Sobrien			reg = pccard_tuple_read_1(tuple, 0);
695104834Sobrien			dtype = reg & PCCARD_DTYPE_MASK;
696104834Sobrien			dspeed = reg & PCCARD_DSPEED_MASK;
697104834Sobrien
698104834Sobrien			DPRINTF(("CISTPL_DEVICE%s type=",
699104834Sobrien			(tuple->code == CISTPL_DEVICE) ? "" : "_A"));
700104834Sobrien			switch (dtype) {
701104834Sobrien			case PCCARD_DTYPE_NULL:
702104834Sobrien				DPRINTF(("null"));
703104834Sobrien				break;
704104834Sobrien			case PCCARD_DTYPE_ROM:
705104834Sobrien				DPRINTF(("rom"));
706104834Sobrien				break;
707104834Sobrien			case PCCARD_DTYPE_OTPROM:
708104834Sobrien				DPRINTF(("otprom"));
709104834Sobrien				break;
710104834Sobrien			case PCCARD_DTYPE_EPROM:
711104834Sobrien				DPRINTF(("eprom"));
712104834Sobrien				break;
713104834Sobrien			case PCCARD_DTYPE_EEPROM:
714104834Sobrien				DPRINTF(("eeprom"));
715104834Sobrien				break;
716104834Sobrien			case PCCARD_DTYPE_FLASH:
717104834Sobrien				DPRINTF(("flash"));
718104834Sobrien				break;
719104834Sobrien			case PCCARD_DTYPE_SRAM:
720104834Sobrien				DPRINTF(("sram"));
721104834Sobrien				break;
722104834Sobrien			case PCCARD_DTYPE_DRAM:
723104834Sobrien				DPRINTF(("dram"));
724104834Sobrien				break;
725104834Sobrien			case PCCARD_DTYPE_FUNCSPEC:
726104834Sobrien				DPRINTF(("funcspec"));
727104834Sobrien				break;
728104834Sobrien			case PCCARD_DTYPE_EXTEND:
729104834Sobrien				DPRINTF(("extend"));
730104834Sobrien				break;
731104834Sobrien			default:
732104834Sobrien				DPRINTF(("reserved"));
733104834Sobrien				break;
734104834Sobrien			}
735104834Sobrien			DPRINTF((" speed="));
736104834Sobrien			switch (dspeed) {
737104834Sobrien			case PCCARD_DSPEED_NULL:
738104834Sobrien				DPRINTF(("null"));
739104834Sobrien				break;
740104834Sobrien			case PCCARD_DSPEED_250NS:
741104834Sobrien				DPRINTF(("250ns"));
742104834Sobrien				break;
743104834Sobrien			case PCCARD_DSPEED_200NS:
744104834Sobrien				DPRINTF(("200ns"));
745104834Sobrien				break;
746104834Sobrien			case PCCARD_DSPEED_150NS:
747104834Sobrien				DPRINTF(("150ns"));
748104834Sobrien				break;
749104834Sobrien			case PCCARD_DSPEED_100NS:
750104834Sobrien				DPRINTF(("100ns"));
751104834Sobrien				break;
752104834Sobrien			case PCCARD_DSPEED_EXT:
753104834Sobrien				DPRINTF(("ext"));
754104834Sobrien				break;
755104834Sobrien			default:
756104834Sobrien				DPRINTF(("reserved"));
757104834Sobrien				break;
758104834Sobrien			}
759104834Sobrien		}
760104834Sobrien		DPRINTF(("\n"));
761104834Sobrien		break;
762104834Sobrien#endif
763104834Sobrien	case CISTPL_VERS_1:
764104834Sobrien		if (tuple->length < 6) {
765104834Sobrien			DPRINTF(("CISTPL_VERS_1 too short %d\n",
766104834Sobrien			    tuple->length));
767104834Sobrien			break;
768104834Sobrien		} {
769104834Sobrien			int start, i, ch, count;
770104834Sobrien
771104834Sobrien			state->card->cis1_major = pccard_tuple_read_1(tuple, 0);
772104834Sobrien			state->card->cis1_minor = pccard_tuple_read_1(tuple, 1);
773104834Sobrien
774104834Sobrien			for (count = 0, start = 0, i = 0;
775104834Sobrien			    (count < 4) && ((i + 4) < 256); i++) {
776104834Sobrien				ch = pccard_tuple_read_1(tuple, 2 + i);
777104834Sobrien				if (ch == 0xff)
778104834Sobrien					break;
779104834Sobrien				state->card->cis1_info_buf[i] = ch;
780104834Sobrien				if (ch == 0) {
781104834Sobrien					state->card->cis1_info[count] =
782104834Sobrien					    state->card->cis1_info_buf + start;
783104834Sobrien					start = i + 1;
784104834Sobrien					count++;
785104834Sobrien				}
786104834Sobrien			}
787104834Sobrien			DPRINTF(("CISTPL_VERS_1\n"));
788104834Sobrien		}
789104834Sobrien		break;
790104834Sobrien	case CISTPL_MANFID:
791104834Sobrien		if (tuple->length < 4) {
792104834Sobrien			DPRINTF(("CISTPL_MANFID too short %d\n",
793104834Sobrien			    tuple->length));
794104834Sobrien			break;
795104834Sobrien		}
796104834Sobrien		state->card->manufacturer = pccard_tuple_read_2(tuple, 0);
797104834Sobrien		state->card->product = pccard_tuple_read_2(tuple, 2);
798104834Sobrien		/*
799104834Sobrien		 * This is for xe driver. But not limited to that driver.
800104834Sobrien		 * In PC Card Standard,
801104834Sobrien		 * Manufacturer ID: 2byte.
802104834Sobrien		 * Product ID: typically 2bytes, but there's no limit on its
803104834Sobrien		 * size.  prodext is a two byte field, so maybe we should
804104834Sobrien		 * also handle the '6' case.  So far no cards have surfaced
805104834Sobrien		 * with a length of '6'.
806104834Sobrien		 */
807104834Sobrien		if (tuple->length == 5 )
808104834Sobrien			state->card->prodext = pccard_tuple_read_1(tuple, 4);
809104834Sobrien		DPRINTF(("CISTPL_MANFID\n"));
810104834Sobrien		break;
811104834Sobrien	case CISTPL_FUNCID:
812104834Sobrien		if (tuple->length < 1) {
813104834Sobrien			DPRINTF(("CISTPL_FUNCID too short %d\n",
814104834Sobrien			    tuple->length));
815104834Sobrien			break;
816104834Sobrien		}
817104834Sobrien		if ((state->pf == NULL) || (state->gotmfc == 2)) {
818104834Sobrien			state->pf = malloc(sizeof(*state->pf), M_DEVBUF,
819104834Sobrien			    M_NOWAIT | M_ZERO);
820104834Sobrien			state->pf->number = state->count++;
821104834Sobrien			state->pf->last_config_index = -1;
822104834Sobrien			STAILQ_INIT(&state->pf->cfe_head);
823104834Sobrien
824104834Sobrien			STAILQ_INSERT_TAIL(&state->card->pf_head, state->pf,
825104834Sobrien			    pf_list);
826104834Sobrien		}
827104834Sobrien		state->pf->function = pccard_tuple_read_1(tuple, 0);
828104834Sobrien
829104834Sobrien		DPRINTF(("CISTPL_FUNCID\n"));
830104834Sobrien		break;
831104834Sobrien        case CISTPL_FUNCE:
832104834Sobrien                if (state->pf == NULL || state->pf->function <= 0) {
833104834Sobrien                        DPRINTF(("CISTPL_FUNCE is not followed by "
834104834Sobrien                                "valid CISTPL_FUNCID\n"));
835104834Sobrien                        break;
836104834Sobrien                }
837104834Sobrien                if (tuple->length >= 2)
838104834Sobrien                        decode_funce(tuple, state->pf);
839104834Sobrien                DPRINTF(("CISTPL_FUNCE\n"));
840104834Sobrien                break;
841104834Sobrien	case CISTPL_CONFIG:
842104834Sobrien		if (tuple->length < 3) {
843104834Sobrien			DPRINTF(("CISTPL_CONFIG too short %d\n",
844104834Sobrien			    tuple->length));
845104834Sobrien			break;
846104834Sobrien		} {
847104834Sobrien			u_int reg, rasz, rmsz, rfsz;
848104834Sobrien			int i;
849104834Sobrien
850104834Sobrien			reg = pccard_tuple_read_1(tuple, 0);
851104834Sobrien			rasz = 1 + ((reg & PCCARD_TPCC_RASZ_MASK) >>
852104834Sobrien			    PCCARD_TPCC_RASZ_SHIFT);
853104834Sobrien			rmsz = 1 + ((reg & PCCARD_TPCC_RMSZ_MASK) >>
854104834Sobrien			    PCCARD_TPCC_RMSZ_SHIFT);
855104834Sobrien			rfsz = ((reg & PCCARD_TPCC_RFSZ_MASK) >>
856104834Sobrien			    PCCARD_TPCC_RFSZ_SHIFT);
857104834Sobrien
858104834Sobrien			if (tuple->length < (rasz + rmsz + rfsz)) {
859104834Sobrien				DPRINTF(("CISTPL_CONFIG (%d,%d,%d) too "
860104834Sobrien				    "short %d\n", rasz, rmsz, rfsz,
861104834Sobrien				    tuple->length));
862104834Sobrien				break;
863104834Sobrien			}
864104834Sobrien			if (state->pf == NULL) {
865104834Sobrien				state->pf = malloc(sizeof(*state->pf),
866104834Sobrien				    M_DEVBUF, M_NOWAIT | M_ZERO);
867104834Sobrien				state->pf->number = state->count++;
868104834Sobrien				state->pf->last_config_index = -1;
869104834Sobrien				STAILQ_INIT(&state->pf->cfe_head);
870104834Sobrien
871104834Sobrien				STAILQ_INSERT_TAIL(&state->card->pf_head,
872104834Sobrien				    state->pf, pf_list);
873104834Sobrien
874104834Sobrien				state->pf->function = PCCARD_FUNCTION_UNSPEC;
875104834Sobrien			}
876104834Sobrien			state->pf->last_config_index =
877104834Sobrien			    pccard_tuple_read_1(tuple, 1);
878104834Sobrien
879104834Sobrien			state->pf->ccr_base = 0;
880104834Sobrien			for (i = 0; i < rasz; i++)
881104834Sobrien				state->pf->ccr_base |=
882104834Sobrien				    ((pccard_tuple_read_1(tuple, 2 + i)) <<
883104834Sobrien				    (i * 8));
884104834Sobrien
885104834Sobrien			state->pf->ccr_mask = 0;
886104834Sobrien			for (i = 0; i < rmsz; i++)
887104834Sobrien				state->pf->ccr_mask |=
888104834Sobrien				    ((pccard_tuple_read_1(tuple,
889104834Sobrien				    2 + rasz + i)) << (i * 8));
890104834Sobrien
891104834Sobrien			/* skip the reserved area and subtuples */
892104834Sobrien
893104834Sobrien			/* reset the default cfe for each cfe list */
894104834Sobrien			state->temp_cfe = init_cfe;
895104834Sobrien			state->default_cfe = &state->temp_cfe;
896104834Sobrien		}
897104834Sobrien		DPRINTF(("CISTPL_CONFIG\n"));
898104834Sobrien		break;
899104834Sobrien	case CISTPL_CFTABLE_ENTRY:
900104834Sobrien		{
901104834Sobrien			int idx, i;
902104834Sobrien			u_int reg, reg2;
903104834Sobrien			u_int intface, def, num;
904104834Sobrien			u_int power, timing, iospace, irq, memspace, misc;
905104834Sobrien			struct pccard_config_entry *cfe;
906104834Sobrien
907104834Sobrien			idx = 0;
908104834Sobrien
909104834Sobrien			reg = pccard_tuple_read_1(tuple, idx++);
910104834Sobrien			intface = reg & PCCARD_TPCE_INDX_INTFACE;
911104834Sobrien			def = reg & PCCARD_TPCE_INDX_DEFAULT;
912104834Sobrien			num = reg & PCCARD_TPCE_INDX_NUM_MASK;
913104834Sobrien
914104834Sobrien			/*
915104834Sobrien			 * this is a little messy.  Some cards have only a
916104834Sobrien			 * cfentry with the default bit set.  So, as we go
917104834Sobrien			 * through the list, we add new indexes to the queue,
918104834Sobrien			 * and keep a pointer to the last one with the
919104834Sobrien			 * default bit set.  if we see a record with the same
920104834Sobrien			 * index, as the default, we stash the default and
921104834Sobrien			 * replace the queue entry. otherwise, we just add
922104834Sobrien			 * new entries to the queue, pointing the default ptr
923104834Sobrien			 * at them if the default bit is set.  if we get to
924104834Sobrien			 * the end with the default pointer pointing at a
925104834Sobrien			 * record which hasn't had a matching index, that's
926104834Sobrien			 * ok; it just becomes a cfentry like any other.
927104834Sobrien			 */
928104834Sobrien
929104834Sobrien			/*
930104834Sobrien			 * if the index in the cis differs from the default
931104834Sobrien			 * cis, create new entry in the queue and start it
932104834Sobrien			 * with the current default
933104834Sobrien			 */
934104834Sobrien			if (num != state->default_cfe->number) {
935104834Sobrien				cfe = (struct pccard_config_entry *)
936104834Sobrien				    malloc(sizeof(*cfe), M_DEVBUF, M_NOWAIT);
937104834Sobrien				if (cfe == NULL) {
938104834Sobrien					DPRINTF(("no memory for config entry\n"));
939104834Sobrien					goto abort_cfe;
940104834Sobrien				}
941104834Sobrien				*cfe = *state->default_cfe;
942104834Sobrien
943104834Sobrien				STAILQ_INSERT_TAIL(&state->pf->cfe_head,
944104834Sobrien				    cfe, cfe_list);
945104834Sobrien
946104834Sobrien				cfe->number = num;
947104834Sobrien
948104834Sobrien				/*
949104834Sobrien				 * if the default bit is set in the cis, then
950104834Sobrien				 * point the new default at whatever is being
951104834Sobrien				 * filled in
952104834Sobrien				 */
953104834Sobrien				if (def)
954104834Sobrien					state->default_cfe = cfe;
955104834Sobrien			} else {
956104834Sobrien				/*
957104834Sobrien				 * the cis index matches the default index,
958104834Sobrien				 * fill in the default cfentry.  It is
959104834Sobrien				 * assumed that the cfdefault index is in the
960104834Sobrien				 * queue.  For it to be otherwise, the cis
961104834Sobrien				 * index would have to be -1 (initial
962104834Sobrien				 * condition) which is not possible, or there
963104834Sobrien				 * would have to be a preceding cis entry
964104834Sobrien				 * which had the same cis index and had the
965104834Sobrien				 * default bit unset. Neither condition
966104834Sobrien				 * should happen.  If it does, this cfentry
967104834Sobrien				 * is lost (written into temp space), which
968104834Sobrien				 * is an acceptable failure mode.
969104834Sobrien				 */
970104834Sobrien
971104834Sobrien				cfe = state->default_cfe;
972104834Sobrien
973104834Sobrien				/*
974104834Sobrien				 * if the cis entry does not have the default
975104834Sobrien				 * bit set, copy the default out of the way
976104834Sobrien				 * first.
977104834Sobrien				 */
978104834Sobrien				if (!def) {
979104834Sobrien					state->temp_cfe = *state->default_cfe;
980104834Sobrien					state->default_cfe = &state->temp_cfe;
981104834Sobrien				}
982104834Sobrien			}
983104834Sobrien
984104834Sobrien			if (intface) {
985104834Sobrien				reg = pccard_tuple_read_1(tuple, idx++);
986104834Sobrien				cfe->flags &= ~(PCCARD_CFE_MWAIT_REQUIRED
987104834Sobrien				    | PCCARD_CFE_RDYBSY_ACTIVE
988104834Sobrien				    | PCCARD_CFE_WP_ACTIVE
989104834Sobrien				    | PCCARD_CFE_BVD_ACTIVE);
990104834Sobrien				if (reg & PCCARD_TPCE_IF_MWAIT)
991104834Sobrien					cfe->flags |= PCCARD_CFE_MWAIT_REQUIRED;
992104834Sobrien				if (reg & PCCARD_TPCE_IF_RDYBSY)
993104834Sobrien					cfe->flags |= PCCARD_CFE_RDYBSY_ACTIVE;
994104834Sobrien				if (reg & PCCARD_TPCE_IF_WP)
995104834Sobrien					cfe->flags |= PCCARD_CFE_WP_ACTIVE;
996104834Sobrien				if (reg & PCCARD_TPCE_IF_BVD)
997104834Sobrien					cfe->flags |= PCCARD_CFE_BVD_ACTIVE;
998104834Sobrien				cfe->iftype = reg & PCCARD_TPCE_IF_IFTYPE;
999104834Sobrien			}
1000104834Sobrien			reg = pccard_tuple_read_1(tuple, idx++);
1001104834Sobrien
1002104834Sobrien			power = reg & PCCARD_TPCE_FS_POWER_MASK;
1003104834Sobrien			timing = reg & PCCARD_TPCE_FS_TIMING;
1004104834Sobrien			iospace = reg & PCCARD_TPCE_FS_IOSPACE;
1005104834Sobrien			irq = reg & PCCARD_TPCE_FS_IRQ;
1006104834Sobrien			memspace = reg & PCCARD_TPCE_FS_MEMSPACE_MASK;
1007104834Sobrien			misc = reg & PCCARD_TPCE_FS_MISC;
1008104834Sobrien
1009104834Sobrien			if (power) {
1010104834Sobrien				/* skip over power, don't save */
1011104834Sobrien				/* for each parameter selection byte */
1012104834Sobrien				for (i = 0; i < power; i++) {
1013104834Sobrien					reg = pccard_tuple_read_1(tuple, idx++);
1014104834Sobrien					for (; reg; reg >>= 1)
1015104834Sobrien					{
1016104834Sobrien						/* set bit -> read */
101799461Sobrien						if ((reg & 1) == 0)
101899461Sobrien							continue;
1019104834Sobrien						/* skip over bytes */
1020104834Sobrien						do {
1021104834Sobrien							reg2 = pccard_tuple_read_1(tuple, idx++);
1022104834Sobrien							/*
1023104834Sobrien							 * until non-extension
1024104834Sobrien							 * byte
102599461Sobrien							 */
102699461Sobrien						} while (reg2 & 0x80);
102799461Sobrien					}
1028104834Sobrien				}
1029104834Sobrien			}
1030104834Sobrien			if (timing) {
1031104834Sobrien				/* skip over timing, don't save */
103299461Sobrien				reg = pccard_tuple_read_1(tuple, idx++);
103399461Sobrien
103499461Sobrien				if ((reg & PCCARD_TPCE_TD_RESERVED_MASK) !=
103599461Sobrien				    PCCARD_TPCE_TD_RESERVED_MASK)
103699461Sobrien					idx++;
103799461Sobrien				if ((reg & PCCARD_TPCE_TD_RDYBSY_MASK) !=
103899461Sobrien				    PCCARD_TPCE_TD_RDYBSY_MASK)
103999461Sobrien					idx++;
104099461Sobrien				if ((reg & PCCARD_TPCE_TD_WAIT_MASK) !=
104199461Sobrien				    PCCARD_TPCE_TD_WAIT_MASK)
104299461Sobrien					idx++;
104399461Sobrien			}
104499461Sobrien			if (iospace) {
1045104834Sobrien				if (tuple->length <= idx) {
1046104834Sobrien					DPRINTF(("ran out of space before TCPE_IO\n"));
1047104834Sobrien					goto abort_cfe;
1048104834Sobrien				}
1049104834Sobrien
1050104834Sobrien				reg = pccard_tuple_read_1(tuple, idx++);
1051104834Sobrien				cfe->flags &=
1052104834Sobrien				    ~(PCCARD_CFE_IO8 | PCCARD_CFE_IO16);
1053104834Sobrien				if (reg & PCCARD_TPCE_IO_BUSWIDTH_8BIT)
1054104834Sobrien					cfe->flags |= PCCARD_CFE_IO8;
1055104834Sobrien				if (reg & PCCARD_TPCE_IO_BUSWIDTH_16BIT)
1056104834Sobrien					cfe->flags |= PCCARD_CFE_IO16;
1057104834Sobrien				cfe->iomask =
1058104834Sobrien				    reg & PCCARD_TPCE_IO_IOADDRLINES_MASK;
1059104834Sobrien
1060104834Sobrien				if (reg & PCCARD_TPCE_IO_HASRANGE) {
1061104834Sobrien					reg = pccard_tuple_read_1(tuple, idx++);
1062104834Sobrien					cfe->num_iospace = 1 + (reg &
1063104834Sobrien					    PCCARD_TPCE_IO_RANGE_COUNT);
1064104834Sobrien
1065104834Sobrien					if (cfe->num_iospace >
1066104834Sobrien					    (sizeof(cfe->iospace) /
1067104834Sobrien					     sizeof(cfe->iospace[0]))) {
1068104834Sobrien						DPRINTF(("too many io "
1069104834Sobrien						    "spaces %d",
1070104834Sobrien						    cfe->num_iospace));
1071104834Sobrien						state->card->error++;
1072104834Sobrien						break;
1073104834Sobrien					}
1074104834Sobrien					for (i = 0; i < cfe->num_iospace; i++) {
1075104834Sobrien						switch (reg & PCCARD_TPCE_IO_RANGE_ADDRSIZE_MASK) {
1076104834Sobrien						case PCCARD_TPCE_IO_RANGE_ADDRSIZE_ONE:
107799461Sobrien							cfe->iospace[i].start =
107899461Sobrien								pccard_tuple_read_1(tuple, idx++);
107999461Sobrien							break;
108099461Sobrien						case PCCARD_TPCE_IO_RANGE_ADDRSIZE_TWO:
108199461Sobrien							cfe->iospace[i].start =
1082104834Sobrien								pccard_tuple_read_2(tuple, idx);
1083104834Sobrien							idx += 2;
108499461Sobrien							break;
108599461Sobrien						case PCCARD_TPCE_IO_RANGE_ADDRSIZE_FOUR:
108699461Sobrien							cfe->iospace[i].start =
1087104834Sobrien								pccard_tuple_read_4(tuple, idx);
108899461Sobrien							idx += 4;
1089104834Sobrien							break;
1090104834Sobrien						}
109199461Sobrien						switch (reg &
1092104834Sobrien							PCCARD_TPCE_IO_RANGE_LENGTHSIZE_MASK) {
109399461Sobrien						case PCCARD_TPCE_IO_RANGE_LENGTHSIZE_ONE:
1094104834Sobrien							cfe->iospace[i].length =
1095104834Sobrien								pccard_tuple_read_1(tuple, idx++);
1096104834Sobrien							break;
1097104834Sobrien						case PCCARD_TPCE_IO_RANGE_LENGTHSIZE_TWO:
1098104834Sobrien							cfe->iospace[i].length =
1099104834Sobrien								pccard_tuple_read_2(tuple, idx);
1100104834Sobrien							idx += 2;
1101104834Sobrien							break;
1102104834Sobrien						case PCCARD_TPCE_IO_RANGE_LENGTHSIZE_FOUR:
1103104834Sobrien							cfe->iospace[i].length =
1104104834Sobrien								pccard_tuple_read_4(tuple, idx);
1105104834Sobrien							idx += 4;
1106104834Sobrien							break;
1107104834Sobrien						}
1108104834Sobrien						cfe->iospace[i].length++;
1109104834Sobrien					}
1110104834Sobrien				} else {
1111104834Sobrien					cfe->num_iospace = 1;
1112104834Sobrien					cfe->iospace[0].start = 0;
1113104834Sobrien					cfe->iospace[0].length =
1114104834Sobrien					    (1 << cfe->iomask);
1115104834Sobrien				}
111699461Sobrien			}
111799461Sobrien			if (irq) {
111899461Sobrien				if (tuple->length <= idx) {
111999461Sobrien					DPRINTF(("ran out of space before TCPE_IR\n"));
112099461Sobrien					goto abort_cfe;
1121104834Sobrien				}
1122104834Sobrien
1123104834Sobrien				reg = pccard_tuple_read_1(tuple, idx++);
1124104834Sobrien				cfe->flags &= ~(PCCARD_CFE_IRQSHARE
1125104834Sobrien				    | PCCARD_CFE_IRQPULSE
1126104834Sobrien				    | PCCARD_CFE_IRQLEVEL);
1127104834Sobrien				if (reg & PCCARD_TPCE_IR_SHARE)
1128104834Sobrien					cfe->flags |= PCCARD_CFE_IRQSHARE;
1129104834Sobrien				if (reg & PCCARD_TPCE_IR_PULSE)
1130104834Sobrien					cfe->flags |= PCCARD_CFE_IRQPULSE;
1131104834Sobrien				if (reg & PCCARD_TPCE_IR_LEVEL)
1132104834Sobrien					cfe->flags |= PCCARD_CFE_IRQLEVEL;
1133104834Sobrien
1134104834Sobrien				if (reg & PCCARD_TPCE_IR_HASMASK) {
1135104834Sobrien					/*
1136104834Sobrien					 * it's legal to ignore the
1137104834Sobrien					 * special-interrupt bits, so I will
1138104834Sobrien					 */
1139104834Sobrien
1140104834Sobrien					cfe->irqmask =
1141104834Sobrien					    pccard_tuple_read_2(tuple, idx);
1142104834Sobrien					idx += 2;
1143104834Sobrien				} else {
114499461Sobrien					cfe->irqmask =
114599461Sobrien					    (1 << (reg & PCCARD_TPCE_IR_IRQ));
114699461Sobrien				}
114799461Sobrien			} else {
114899461Sobrien				cfe->irqmask = 0xffff;
1149104834Sobrien			}
115099461Sobrien			if (memspace) {
1151104834Sobrien				if (tuple->length <= idx) {
1152104834Sobrien					DPRINTF(("ran out of space before TCPE_MS\n"));
115399461Sobrien					goto abort_cfe;
1154104834Sobrien				}
115599461Sobrien
1156104834Sobrien				if (memspace == PCCARD_TPCE_FS_MEMSPACE_LENGTH) {
115799461Sobrien					cfe->num_memspace = 1;
1158104834Sobrien					cfe->memspace[0].length = 256 *
115999461Sobrien					    pccard_tuple_read_2(tuple, idx);
1160104834Sobrien					idx += 2;
1161104834Sobrien					cfe->memspace[0].cardaddr = 0;
116299461Sobrien					cfe->memspace[0].hostaddr = 0;
1163104834Sobrien				} else if (memspace ==
1164104834Sobrien				    PCCARD_TPCE_FS_MEMSPACE_LENGTHADDR) {
1165104834Sobrien					cfe->num_memspace = 1;
1166104834Sobrien					cfe->memspace[0].length = 256 *
1167104834Sobrien					    pccard_tuple_read_2(tuple, idx);
1168104834Sobrien					idx += 2;
1169104834Sobrien					cfe->memspace[0].cardaddr = 256 *
1170104834Sobrien					    pccard_tuple_read_2(tuple, idx);
1171104834Sobrien					idx += 2;
1172104834Sobrien					cfe->memspace[0].hostaddr = cfe->memspace[0].cardaddr;
1173104834Sobrien				} else {
1174104834Sobrien					int lengthsize;
1175104834Sobrien					int cardaddrsize;
1176104834Sobrien					int hostaddrsize;
1177104834Sobrien
1178104834Sobrien					reg = pccard_tuple_read_1(tuple, idx++);
1179104834Sobrien					cfe->num_memspace = (reg &
1180104834Sobrien					    PCCARD_TPCE_MS_COUNT) + 1;
1181104834Sobrien					if (cfe->num_memspace >
1182104834Sobrien					    (sizeof(cfe->memspace) /
1183104834Sobrien					     sizeof(cfe->memspace[0]))) {
1184104834Sobrien						DPRINTF(("too many mem "
1185104834Sobrien						    "spaces %d",
1186104834Sobrien						    cfe->num_memspace));
118799461Sobrien						state->card->error++;
118899461Sobrien						break;
118999461Sobrien					}
119099461Sobrien					lengthsize =
119199461Sobrien						((reg & PCCARD_TPCE_MS_LENGTH_SIZE_MASK) >>
119299461Sobrien						 PCCARD_TPCE_MS_LENGTH_SIZE_SHIFT);
119399461Sobrien					cardaddrsize =
119499461Sobrien						((reg & PCCARD_TPCE_MS_CARDADDR_SIZE_MASK) >>
1195104834Sobrien						 PCCARD_TPCE_MS_CARDADDR_SIZE_SHIFT);
1196104834Sobrien					hostaddrsize =
1197104834Sobrien						(reg & PCCARD_TPCE_MS_HOSTADDR) ? cardaddrsize : 0;
1198104834Sobrien
1199104834Sobrien					if (lengthsize == 0) {
1200104834Sobrien						DPRINTF(("cfe memspace "
1201104834Sobrien						    "lengthsize == 0\n"));
1202104834Sobrien					}
1203104834Sobrien					for (i = 0; i < cfe->num_memspace; i++) {
1204104834Sobrien						if (lengthsize) {
1205104834Sobrien							cfe->memspace[i].length =
1206104834Sobrien								256 * pccard_tuple_read_n(tuple, lengthsize,
1207104834Sobrien								       idx);
1208104834Sobrien							idx += lengthsize;
1209104834Sobrien						} else {
1210104834Sobrien							cfe->memspace[i].length = 0;
1211104834Sobrien						}
1212104834Sobrien						if (cfe->memspace[i].length == 0) {
1213104834Sobrien							DPRINTF(("cfe->memspace[%d].length == 0\n",
1214104834Sobrien								 i));
1215104834Sobrien						}
1216104834Sobrien						if (cardaddrsize) {
1217104834Sobrien							cfe->memspace[i].cardaddr =
1218104834Sobrien								256 * pccard_tuple_read_n(tuple, cardaddrsize,
1219104834Sobrien								       idx);
1220104834Sobrien							idx += cardaddrsize;
1221104834Sobrien						} else {
1222104834Sobrien							cfe->memspace[i].cardaddr = 0;
1223104834Sobrien						}
1224104834Sobrien						if (hostaddrsize) {
1225104834Sobrien							cfe->memspace[i].hostaddr =
1226104834Sobrien								256 * pccard_tuple_read_n(tuple, hostaddrsize,
1227104834Sobrien								       idx);
1228104834Sobrien							idx += hostaddrsize;
1229104834Sobrien						} else {
1230104834Sobrien							cfe->memspace[i].hostaddr = 0;
123194536Sobrien						}
123294536Sobrien					}
123394536Sobrien				}
123494536Sobrien			} else
123594536Sobrien				cfe->num_memspace = 0;
123694536Sobrien			if (misc) {
1237104834Sobrien				if (tuple->length <= idx) {
1238104834Sobrien					DPRINTF(("ran out of space before TCPE_MI\n"));
1239104834Sobrien					goto abort_cfe;
1240104834Sobrien				}
1241104834Sobrien
1242104834Sobrien				reg = pccard_tuple_read_1(tuple, idx++);
1243104834Sobrien				cfe->flags &= ~(PCCARD_CFE_POWERDOWN
1244104834Sobrien				    | PCCARD_CFE_READONLY
124594536Sobrien				    | PCCARD_CFE_AUDIO);
124694536Sobrien				if (reg & PCCARD_TPCE_MI_PWRDOWN)
124794536Sobrien					cfe->flags |= PCCARD_CFE_POWERDOWN;
124894536Sobrien				if (reg & PCCARD_TPCE_MI_READONLY)
124994536Sobrien					cfe->flags |= PCCARD_CFE_READONLY;
125094536Sobrien				if (reg & PCCARD_TPCE_MI_AUDIO)
125194536Sobrien					cfe->flags |= PCCARD_CFE_AUDIO;
1252104834Sobrien				cfe->maxtwins = reg & PCCARD_TPCE_MI_MAXTWINS;
1253104834Sobrien
1254104834Sobrien				while (reg & PCCARD_TPCE_MI_EXT) {
1255104834Sobrien					reg = pccard_tuple_read_1(tuple, idx++);
1256104834Sobrien				}
1257104834Sobrien			}
1258104834Sobrien			/* skip all the subtuples */
1259104834Sobrien		}
1260104834Sobrien
1261104834Sobrien	abort_cfe:
1262104834Sobrien		DPRINTF(("CISTPL_CFTABLE_ENTRY\n"));
1263104834Sobrien		break;
1264104834Sobrien	default:
1265104834Sobrien		DPRINTF(("unhandled CISTPL %#x\n", tuple->code));
1266104834Sobrien		break;
1267104834Sobrien	}
1268104834Sobrien
1269104834Sobrien	return (0);
1270104834Sobrien}
1271104834Sobrien
1272104834Sobrienstatic int
1273104834Sobriendecode_funce(const struct pccard_tuple *tuple, struct pccard_function *pf)
1274104834Sobrien{
1275104834Sobrien	int i;
1276104834Sobrien	int len;
1277104834Sobrien	int type = pccard_tuple_read_1(tuple, 0);
1278104834Sobrien
1279104834Sobrien	switch (pf->function) {
1280104834Sobrien	case PCCARD_FUNCTION_DISK:
1281104834Sobrien		if (type == PCCARD_TPLFE_TYPE_DISK_DEVICE_INTERFACE) {
1282104834Sobrien			pf->pf_funce_disk_interface
1283104834Sobrien				= pccard_tuple_read_1(tuple, 1);
1284104834Sobrien			pf->pf_funce_disk_power
1285104834Sobrien				= pccard_tuple_read_1(tuple, 2);
1286104834Sobrien		}
1287104834Sobrien		break;
1288104834Sobrien	case PCCARD_FUNCTION_NETWORK:
1289104834Sobrien		if (type == PCCARD_TPLFE_TYPE_LAN_NID) {
1290104834Sobrien			len = pccard_tuple_read_1(tuple, 1);
1291104834Sobrien			if (tuple->length < 2 + len || len > 8) {
1292104834Sobrien				/* tuple length not enough or nid too long */
1293104834Sobrien				break;
1294104834Sobrien                        }
1295104834Sobrien			for (i = 0; i < len; i++) {
1296104834Sobrien				pf->pf_funce_lan_nid[i]
1297104834Sobrien					= pccard_tuple_read_1(tuple, i + 2);
1298104834Sobrien			}
1299104834Sobrien			pf->pf_funce_lan_nidlen = len;
130094536Sobrien		}
130194536Sobrien		break;
130294536Sobrien	default:
130394536Sobrien		break;
130494536Sobrien	}
1305104834Sobrien	return 0;
130694536Sobrien}
1307104834Sobrien