xref: /netbsd-src/sys/dev/pcmcia/pcmcia_cis.c (revision d47bcd296c8b39243dd81e9cc75ea86330d4eeaf)
1*d47bcd29Schs /*	$NetBSD: pcmcia_cis.c,v 1.57 2019/11/10 21:16:36 chs Exp $	*/
2c66b8643Sthorpej 
3c66b8643Sthorpej /*
4c66b8643Sthorpej  * Copyright (c) 1997 Marc Horowitz.  All rights reserved.
5c66b8643Sthorpej  *
6c66b8643Sthorpej  * Redistribution and use in source and binary forms, with or without
7c66b8643Sthorpej  * modification, are permitted provided that the following conditions
8c66b8643Sthorpej  * are met:
9c66b8643Sthorpej  * 1. Redistributions of source code must retain the above copyright
10c66b8643Sthorpej  *    notice, this list of conditions and the following disclaimer.
11c66b8643Sthorpej  * 2. Redistributions in binary form must reproduce the above copyright
12c66b8643Sthorpej  *    notice, this list of conditions and the following disclaimer in the
13c66b8643Sthorpej  *    documentation and/or other materials provided with the distribution.
14c66b8643Sthorpej  * 3. All advertising materials mentioning features or use of this software
15c66b8643Sthorpej  *    must display the following acknowledgement:
16c66b8643Sthorpej  *	This product includes software developed by Marc Horowitz.
17c66b8643Sthorpej  * 4. The name of the author may not be used to endorse or promote products
18c66b8643Sthorpej  *    derived from this software without specific prior written permission.
19c66b8643Sthorpej  *
20c66b8643Sthorpej  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21c66b8643Sthorpej  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22c66b8643Sthorpej  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23c66b8643Sthorpej  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24c66b8643Sthorpej  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25c66b8643Sthorpej  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26c66b8643Sthorpej  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27c66b8643Sthorpej  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28c66b8643Sthorpej  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29c66b8643Sthorpej  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30c66b8643Sthorpej  */
31c66b8643Sthorpej 
32ab5d9d2bSlukem #include <sys/cdefs.h>
33*d47bcd29Schs __KERNEL_RCSID(0, "$NetBSD: pcmcia_cis.c,v 1.57 2019/11/10 21:16:36 chs Exp $");
34ab5d9d2bSlukem 
35c66b8643Sthorpej #include <sys/param.h>
36c66b8643Sthorpej #include <sys/systm.h>
37c66b8643Sthorpej #include <sys/device.h>
38c66b8643Sthorpej #include <sys/malloc.h>
39c66b8643Sthorpej 
40c66b8643Sthorpej #include <dev/pcmcia/pcmciareg.h>
41c66b8643Sthorpej #include <dev/pcmcia/pcmciachip.h>
42c66b8643Sthorpej #include <dev/pcmcia/pcmciavar.h>
43c66b8643Sthorpej 
44c66b8643Sthorpej #ifdef PCMCIACISDEBUG
45c66b8643Sthorpej int	pcmciacis_debug = 0;
46c66b8643Sthorpej #define	DPRINTF(arg) if (pcmciacis_debug) printf arg
47c66b8643Sthorpej #else
48c66b8643Sthorpej #define	DPRINTF(arg)
49c66b8643Sthorpej #endif
50c66b8643Sthorpej 
51c66b8643Sthorpej #define	PCMCIA_CIS_SIZE		1024
52c66b8643Sthorpej 
53c66b8643Sthorpej struct cis_state {
54c66b8643Sthorpej 	int	count;
55c66b8643Sthorpej 	int	gotmfc;
56c66b8643Sthorpej 	struct pcmcia_config_entry temp_cfe;
57c66b8643Sthorpej 	struct pcmcia_config_entry *default_cfe;
58c66b8643Sthorpej 	struct pcmcia_card *card;
59c66b8643Sthorpej 	struct pcmcia_function *pf;
60c66b8643Sthorpej };
61c66b8643Sthorpej 
6218db93c7Sperry int	pcmcia_parse_cis_tuple(struct pcmcia_tuple *, void *);
6318db93c7Sperry static void create_pf(struct cis_state *);
648130f0ecShaya 
65c2909c51Schristos static void decode_end(struct pcmcia_tuple *, struct cis_state *);
66c2909c51Schristos static void decode_longlink_mfc(struct pcmcia_tuple *, struct cis_state *);
67c2909c51Schristos static void decode_device(struct pcmcia_tuple *, struct cis_state *);
68c2909c51Schristos static void decode_vers_1(struct pcmcia_tuple *, struct cis_state *);
69c2909c51Schristos static void decode_manfid(struct pcmcia_tuple *, struct cis_state *);
70c2909c51Schristos static void decode_funcid(struct pcmcia_tuple *, struct cis_state *);
71c2909c51Schristos static void decode_funce(struct pcmcia_tuple *, struct cis_state *);
72c2909c51Schristos static void decode_config(struct pcmcia_tuple *, struct cis_state *);
73c2909c51Schristos static void decode_cftable_entry(struct pcmcia_tuple *, struct cis_state *);
74c2909c51Schristos 
75c66b8643Sthorpej 
764251568aSchristos static void
create_pf(struct cis_state * state)774251568aSchristos create_pf(struct cis_state *state)
784251568aSchristos {
79*d47bcd29Schs 	state->pf = malloc(sizeof(*state->pf), M_DEVBUF, M_WAITOK|M_ZERO);
804251568aSchristos 	state->pf->number = state->count++;
814251568aSchristos 	state->pf->last_config_index = -1;
824251568aSchristos 	SIMPLEQ_INIT(&state->pf->cfe_head);
834251568aSchristos 	SIMPLEQ_INSERT_TAIL(&state->card->pf_head, state->pf, pf_list);
844251568aSchristos }
854251568aSchristos 
864251568aSchristos void
pcmcia_free_pf(struct pcmcia_function_head * pfhead)874251568aSchristos pcmcia_free_pf(struct pcmcia_function_head *pfhead)
884251568aSchristos {
89740cc023Senami 	struct pcmcia_function *pf, *npf;
90740cc023Senami 	struct pcmcia_config_entry *cfe, *ncfe;
914251568aSchristos 
92740cc023Senami 	for (pf = SIMPLEQ_FIRST(pfhead); pf != NULL; pf = npf) {
93740cc023Senami 		npf = SIMPLEQ_NEXT(pf, pf_list);
94740cc023Senami 		for (cfe = SIMPLEQ_FIRST(&pf->cfe_head); cfe != NULL;
95740cc023Senami 		    cfe = ncfe) {
96740cc023Senami 			ncfe = SIMPLEQ_NEXT(cfe, cfe_list);
97740cc023Senami 			free(cfe, M_DEVBUF);
984251568aSchristos 		}
99740cc023Senami 		free(pf, M_DEVBUF);
1004251568aSchristos 	}
1014251568aSchristos 
1024251568aSchristos 	SIMPLEQ_INIT(pfhead);
1034251568aSchristos }
1044251568aSchristos 
105c66b8643Sthorpej void
pcmcia_read_cis(struct pcmcia_softc * sc)106454af1c0Sdsl pcmcia_read_cis(struct pcmcia_softc *sc)
107c66b8643Sthorpej {
108c66b8643Sthorpej 	struct cis_state state;
109c66b8643Sthorpej 
110d4471177Scgd 	memset(&state, 0, sizeof state);
111c66b8643Sthorpej 
112c66b8643Sthorpej 	state.card = &sc->card;
113c66b8643Sthorpej 
114c66b8643Sthorpej 	state.card->error = 0;
115c66b8643Sthorpej 	state.card->cis1_major = -1;
116c66b8643Sthorpej 	state.card->cis1_minor = -1;
117c66b8643Sthorpej 	state.card->cis1_info[0] = NULL;
118c66b8643Sthorpej 	state.card->cis1_info[1] = NULL;
119c66b8643Sthorpej 	state.card->cis1_info[2] = NULL;
120c66b8643Sthorpej 	state.card->cis1_info[3] = NULL;
121e3bc2915Schristos 	state.card->manufacturer = PCMCIA_VENDOR_INVALID;
1224e304b8dSenami 	state.card->product = PCMCIA_PRODUCT_INVALID;
123c66b8643Sthorpej 	SIMPLEQ_INIT(&state.card->pf_head);
124c66b8643Sthorpej 
125c66b8643Sthorpej 	state.pf = NULL;
126c66b8643Sthorpej 
12702b7e019Sdrochner 	if (pcmcia_scan_cis(sc->dev, pcmcia_parse_cis_tuple,
12883449d89Schristos 	    &state) == -1)
129c66b8643Sthorpej 		state.card->error++;
130c66b8643Sthorpej }
131c66b8643Sthorpej 
132c66b8643Sthorpej int
pcmcia_scan_cis(device_t dev,int (* fct)(struct pcmcia_tuple *,void *),void * arg)1337cf29912Scegger pcmcia_scan_cis(device_t dev,
134d3189d35Scegger 	int (*fct)(struct pcmcia_tuple *, void *),
135d3189d35Scegger 	void *arg)
136c66b8643Sthorpej {
13702b7e019Sdrochner 	struct pcmcia_softc *sc = device_private(dev);
138c66b8643Sthorpej 	pcmcia_chipset_tag_t pct;
139c66b8643Sthorpej 	pcmcia_chipset_handle_t pch;
140c66b8643Sthorpej 	int window;
141c66b8643Sthorpej 	struct pcmcia_mem_handle pcmh;
142c66b8643Sthorpej 	struct pcmcia_tuple tuple;
143c66b8643Sthorpej 	int longlink_present;
144c66b8643Sthorpej 	int longlink_common;
145c66b8643Sthorpej 	u_long longlink_addr;
146c66b8643Sthorpej 	int mfc_count;
147c66b8643Sthorpej 	int mfc_index;
148c66b8643Sthorpej 	struct {
149c66b8643Sthorpej 		int	common;
150c66b8643Sthorpej 		u_long	addr;
151c66b8643Sthorpej 	} mfc[256 / 5];
152c66b8643Sthorpej 	int ret;
153c66b8643Sthorpej 
154c66b8643Sthorpej 	ret = 0;
155c66b8643Sthorpej 
156c66b8643Sthorpej 	pct = sc->pct;
157c66b8643Sthorpej 	pch = sc->pch;
158c66b8643Sthorpej 
159c66b8643Sthorpej 	/* allocate some memory */
160c66b8643Sthorpej 
161c66b8643Sthorpej 	if (pcmcia_chip_mem_alloc(pct, pch, PCMCIA_CIS_SIZE, &pcmh)) {
162c66b8643Sthorpej #ifdef DIAGNOSTIC
16302b7e019Sdrochner 		aprint_error_dev(sc->dev,
16402b7e019Sdrochner 				 "can't alloc memory to read attributes\n");
165c66b8643Sthorpej #endif
16683449d89Schristos 		return -1;
167c66b8643Sthorpej 	}
168c66b8643Sthorpej 	/* initialize state for the primary tuple chain */
169c66b8643Sthorpej 	if (pcmcia_chip_mem_map(pct, pch, PCMCIA_MEM_ATTR, 0,
170c66b8643Sthorpej 	    PCMCIA_CIS_SIZE, &pcmh, &tuple.ptr, &window)) {
171c66b8643Sthorpej 		pcmcia_chip_mem_free(pct, pch, &pcmh);
172c66b8643Sthorpej #ifdef DIAGNOSTIC
17302b7e019Sdrochner 		aprint_error_dev(sc->dev,
17402b7e019Sdrochner 				 "can't map memory to read attributes\n");
175c66b8643Sthorpej #endif
17683449d89Schristos 		return -1;
177c66b8643Sthorpej 	}
178d85c2b7eStoshii 	tuple.memt = pcmh.memt;
179d85c2b7eStoshii 	tuple.memh = pcmh.memh;
180d85c2b7eStoshii 
181c66b8643Sthorpej 	DPRINTF(("cis mem map %x\n", (unsigned int) tuple.memh));
182c66b8643Sthorpej 
183c66b8643Sthorpej 	tuple.mult = 2;
184c66b8643Sthorpej 
185c66b8643Sthorpej 	longlink_present = 1;
186c66b8643Sthorpej 	longlink_common = 1;
187c66b8643Sthorpej 	longlink_addr = 0;
188c66b8643Sthorpej 
189c66b8643Sthorpej 	mfc_count = 0;
190c66b8643Sthorpej 	mfc_index = 0;
191c66b8643Sthorpej 
19202b7e019Sdrochner 	DPRINTF(("%s: CIS tuple chain:\n", device_xname(sc->dev)));
193c66b8643Sthorpej 
194c66b8643Sthorpej 	while (1) {
1954343cdf0Smycroft 		DELAY(1000);
1964343cdf0Smycroft 
197c66b8643Sthorpej 		while (1) {
1980f210a88Sitohy 			/*
1990f210a88Sitohy 			 * Perform boundary check for insane cards.
2000f210a88Sitohy 			 * If CIS is too long, simulate CIS end.
2010f210a88Sitohy 			 * (This check may not be sufficient for
2020f210a88Sitohy 			 * malicious cards.)
2030f210a88Sitohy 			 */
2040f210a88Sitohy 			if (tuple.mult * tuple.ptr >= PCMCIA_CIS_SIZE - 1
2050f210a88Sitohy 			    - 32 /* ad hoc value */ ) {
2060f210a88Sitohy 				DPRINTF(("CISTPL_END (too long CIS)\n"));
2070f210a88Sitohy 				tuple.code = PCMCIA_CISTPL_END;
2080f210a88Sitohy 				goto cis_end;
2090f210a88Sitohy 			}
2100f210a88Sitohy 
211c66b8643Sthorpej 			/* get the tuple code */
212c66b8643Sthorpej 
213c66b8643Sthorpej 			tuple.code = pcmcia_cis_read_1(&tuple, tuple.ptr);
214c66b8643Sthorpej 
215c66b8643Sthorpej 			/* two special-case tuples */
216c66b8643Sthorpej 
217d663cd12Smarc 			if (tuple.code == PCMCIA_CISTPL_NULL) {
218ea0d4e37Smycroft 				DPRINTF((" 00\nCISTPL_NONE\n"));
219c66b8643Sthorpej 				tuple.ptr++;
220c66b8643Sthorpej 				continue;
221d663cd12Smarc 			} else if (tuple.code == PCMCIA_CISTPL_END) {
222ea0d4e37Smycroft 				DPRINTF((" ff\nCISTPL_END\n"));
2230f210a88Sitohy 			cis_end:
224d663cd12Smarc 				/* Call the function for the END tuple, since
225d663cd12Smarc 				   the CIS semantics depend on it */
226d663cd12Smarc 				if ((*fct) (&tuple, arg)) {
227d663cd12Smarc 					pcmcia_chip_mem_unmap(pct, pch,
228d663cd12Smarc 							      window);
229d663cd12Smarc 					ret = 1;
230d663cd12Smarc 					goto done;
231d663cd12Smarc 				}
232c66b8643Sthorpej 				tuple.ptr++;
233c66b8643Sthorpej 				break;
234c66b8643Sthorpej 			}
235ea0d4e37Smycroft 
236c66b8643Sthorpej 			/* now all the normal tuples */
237c66b8643Sthorpej 
238c66b8643Sthorpej 			tuple.length = pcmcia_cis_read_1(&tuple, tuple.ptr + 1);
2394343cdf0Smycroft #ifdef PCMCIACISDEBUG
2404343cdf0Smycroft 			/* print the tuple */
2414343cdf0Smycroft 			{
2424343cdf0Smycroft 				int i;
2434343cdf0Smycroft 
2444343cdf0Smycroft 				DPRINTF((" %02x %02x", tuple.code,
2454343cdf0Smycroft 				    tuple.length));
2464343cdf0Smycroft 
2474343cdf0Smycroft 				for (i = 0; i < tuple.length; i++) {
2484343cdf0Smycroft 					DPRINTF((" %02x",
2494343cdf0Smycroft 					    pcmcia_tuple_read_1(&tuple, i)));
2504343cdf0Smycroft 					if ((i % 16) == 13)
2514343cdf0Smycroft 						DPRINTF(("\n"));
2524343cdf0Smycroft 				}
2534343cdf0Smycroft 				if ((i % 16) != 14)
2544343cdf0Smycroft 					DPRINTF(("\n"));
2554343cdf0Smycroft 			}
2564343cdf0Smycroft #endif
257c66b8643Sthorpej 			switch (tuple.code) {
258c66b8643Sthorpej 			case PCMCIA_CISTPL_LONGLINK_A:
259c66b8643Sthorpej 			case PCMCIA_CISTPL_LONGLINK_C:
260c66b8643Sthorpej 				if (tuple.length < 4) {
261c66b8643Sthorpej 					DPRINTF(("CISTPL_LONGLINK_%s too "
262c66b8643Sthorpej 					    "short %d\n",
263c66b8643Sthorpej 					    longlink_common ? "C" : "A",
264c66b8643Sthorpej 					    tuple.length));
265c66b8643Sthorpej 					break;
266c66b8643Sthorpej 				}
267c66b8643Sthorpej 				longlink_present = 1;
268c66b8643Sthorpej 				longlink_common = (tuple.code ==
269c66b8643Sthorpej 				    PCMCIA_CISTPL_LONGLINK_C) ? 1 : 0;
270c66b8643Sthorpej 				longlink_addr = pcmcia_tuple_read_4(&tuple, 0);
271c66b8643Sthorpej 				DPRINTF(("CISTPL_LONGLINK_%s %lx\n",
272c66b8643Sthorpej 				    longlink_common ? "C" : "A",
273c66b8643Sthorpej 				    longlink_addr));
274c66b8643Sthorpej 				break;
275c66b8643Sthorpej 			case PCMCIA_CISTPL_NO_LINK:
276c66b8643Sthorpej 				longlink_present = 0;
277c66b8643Sthorpej 				DPRINTF(("CISTPL_NO_LINK\n"));
278c66b8643Sthorpej 				break;
279c66b8643Sthorpej 			case PCMCIA_CISTPL_CHECKSUM:
280c66b8643Sthorpej 				if (tuple.length < 5) {
281c66b8643Sthorpej 					DPRINTF(("CISTPL_CHECKSUM too "
282c66b8643Sthorpej 					    "short %d\n", tuple.length));
283c66b8643Sthorpej 					break;
284c66b8643Sthorpej 				} {
285c66b8643Sthorpej 					int16_t offset;
286c66b8643Sthorpej 					u_long addr, length;
287c66b8643Sthorpej 					u_int cksum, sum;
288c66b8643Sthorpej 					int i;
289c66b8643Sthorpej 
290c66b8643Sthorpej 					*((u_int16_t *) & offset) =
291c66b8643Sthorpej 					    pcmcia_tuple_read_2(&tuple, 0);
292c66b8643Sthorpej 					length = pcmcia_tuple_read_2(&tuple, 2);
293c66b8643Sthorpej 					cksum = pcmcia_tuple_read_1(&tuple, 4);
294c66b8643Sthorpej 
295c66b8643Sthorpej 					addr = tuple.ptr + offset;
296c66b8643Sthorpej 
297c66b8643Sthorpej 					DPRINTF(("CISTPL_CHECKSUM addr=%lx "
298c66b8643Sthorpej 					    "len=%lx cksum=%x",
299c66b8643Sthorpej 					    addr, length, cksum));
300c66b8643Sthorpej 
301c66b8643Sthorpej 					/*
302c66b8643Sthorpej 					 * XXX do more work to deal with
303c66b8643Sthorpej 					 * distant regions
304c66b8643Sthorpej 					 */
305c66b8643Sthorpej 					if ((addr >= PCMCIA_CIS_SIZE) ||
306bd4bd1bfSchristos #if 0
307c66b8643Sthorpej 					    ((addr + length) < 0) ||
308bd4bd1bfSchristos #endif
309c66b8643Sthorpej 					    ((addr + length) >=
310c66b8643Sthorpej 					      PCMCIA_CIS_SIZE)) {
311c66b8643Sthorpej 						DPRINTF((" skipped, "
312c66b8643Sthorpej 						    "too distant\n"));
313c66b8643Sthorpej 						break;
314c66b8643Sthorpej 					}
315c66b8643Sthorpej 					sum = 0;
316c66b8643Sthorpej 					for (i = 0; i < length; i++)
317c66b8643Sthorpej 						sum +=
318c66b8643Sthorpej 						    bus_space_read_1(tuple.memt,
319c66b8643Sthorpej 						    tuple.memh,
320c66b8643Sthorpej 						    addr + tuple.mult * i);
321c66b8643Sthorpej 					if (cksum != (sum & 0xff)) {
322c66b8643Sthorpej 						DPRINTF((" failed sum=%x\n",
323c66b8643Sthorpej 						    sum));
32402b7e019Sdrochner 						aprint_error_dev(sc->dev,
32502b7e019Sdrochner 						 "CIS checksum failed\n");
326c66b8643Sthorpej #if 0
327c66b8643Sthorpej 						/*
328c66b8643Sthorpej 						 * XXX Some working cards have
329c66b8643Sthorpej 						 * XXX bad checksums!!
330c66b8643Sthorpej 						 */
33183449d89Schristos 						ret = -1;
332c66b8643Sthorpej #endif
333c66b8643Sthorpej 					} else {
334c66b8643Sthorpej 						DPRINTF((" ok\n"));
335c66b8643Sthorpej 					}
336c66b8643Sthorpej 				}
337c66b8643Sthorpej 				break;
338c66b8643Sthorpej 			case PCMCIA_CISTPL_LONGLINK_MFC:
339c66b8643Sthorpej 				if (tuple.length < 1) {
340c66b8643Sthorpej 					DPRINTF(("CISTPL_LONGLINK_MFC too "
341c66b8643Sthorpej 					    "short %d\n", tuple.length));
342c66b8643Sthorpej 					break;
343c66b8643Sthorpej 				}
344d4471177Scgd 				if (((tuple.length - 1) % 5) != 0) {
345d4471177Scgd 					DPRINTF(("CISTPL_LONGLINK_MFC bogus "
346d4471177Scgd 					    "length %d\n", tuple.length));
347d4471177Scgd 					break;
348d4471177Scgd 				}
349c66b8643Sthorpej 				/*
350c66b8643Sthorpej 				 * this is kind of ad hoc, as I don't have
351c66b8643Sthorpej 				 * any real documentation
352c66b8643Sthorpej 				 */
353c66b8643Sthorpej 				{
354d4471177Scgd 					int i, tmp_count;
355c66b8643Sthorpej 
356d4471177Scgd 					/*
357d4471177Scgd 					 * put count into tmp var so that
358d4471177Scgd 					 * if we have to bail (because it's
359d4471177Scgd 					 * a bogus count) it won't be
360d4471177Scgd 					 * remembered for later use.
361d4471177Scgd 					 */
362d4471177Scgd 					tmp_count =
363c66b8643Sthorpej 					    pcmcia_tuple_read_1(&tuple, 0);
364c66b8643Sthorpej 					DPRINTF(("CISTPL_LONGLINK_MFC %d",
365d4471177Scgd 					    tmp_count));
366d4471177Scgd 
367d4471177Scgd 					/*
368d4471177Scgd 					 * make _sure_ it's the right size;
369d4471177Scgd 					 * if too short, it may be a weird
370d4471177Scgd 					 * (unknown/undefined) format
371d4471177Scgd 					 */
372d4471177Scgd 					if (tuple.length != (tmp_count*5 + 1)) {
373d4471177Scgd 						DPRINTF((" bogus length %d\n",
374d4471177Scgd 						    tuple.length));
375d4471177Scgd 						break;
376d4471177Scgd 					}
377d4471177Scgd 
378d4471177Scgd #ifdef PCMCIACISDEBUG	/* maybe enable all the time? */
379d4471177Scgd 					/*
380d4471177Scgd 					 * sanity check for a programming
381d4471177Scgd 					 * error which is difficult to find
382d4471177Scgd 					 * when debugging.
383d4471177Scgd 					 */
384d4471177Scgd 					if (tmp_count >
385d4471177Scgd 					    howmany(sizeof mfc, sizeof mfc[0]))
386d4471177Scgd 						panic("CISTPL_LONGLINK_MFC mfc "
387d4471177Scgd 						    "count would blow stack");
388d4471177Scgd #endif
389d4471177Scgd 
390d4471177Scgd 					mfc_count = tmp_count;
391c66b8643Sthorpej 					for (i = 0; i < mfc_count; i++) {
392c66b8643Sthorpej 						mfc[i].common =
393c66b8643Sthorpej 						    (pcmcia_tuple_read_1(&tuple,
394c66b8643Sthorpej 						    1 + 5 * i) ==
395c66b8643Sthorpej 						    PCMCIA_MFC_MEM_COMMON) ?
396c66b8643Sthorpej 						    1 : 0;
397c66b8643Sthorpej 						mfc[i].addr =
398c66b8643Sthorpej 						    pcmcia_tuple_read_4(&tuple,
399c66b8643Sthorpej 						    1 + 5 * i + 1);
400c66b8643Sthorpej 						DPRINTF((" %s:%lx",
401c66b8643Sthorpej 						    mfc[i].common ? "common" :
402c66b8643Sthorpej 						    "attr", mfc[i].addr));
403c66b8643Sthorpej 					}
404c66b8643Sthorpej 					DPRINTF(("\n"));
405c66b8643Sthorpej 				}
406c66b8643Sthorpej 				/*
407c66b8643Sthorpej 				 * for LONGLINK_MFC, fall through to the
408c66b8643Sthorpej 				 * function.  This tuple has structural and
409c66b8643Sthorpej 				 * semantic content.
410c66b8643Sthorpej 				 */
411fbffadb9Smrg 				/* FALLTHROUGH */
412c66b8643Sthorpej 			default:
413c66b8643Sthorpej 				{
414c66b8643Sthorpej 					if ((*fct) (&tuple, arg)) {
415c66b8643Sthorpej 						pcmcia_chip_mem_unmap(pct,
416c66b8643Sthorpej 						    pch, window);
41783449d89Schristos 						ret = 1;
418c66b8643Sthorpej 						goto done;
419c66b8643Sthorpej 					}
420c66b8643Sthorpej 				}
421c66b8643Sthorpej 				break;
422c66b8643Sthorpej 			}	/* switch */
423c66b8643Sthorpej 			/* skip to the next tuple */
424c66b8643Sthorpej 			tuple.ptr += 2 + tuple.length;
425c66b8643Sthorpej 		}
4269ada0bf4Smarc 
427c66b8643Sthorpej 		/*
428c66b8643Sthorpej 		 * the chain is done.  Clean up and move onto the next one,
429c66b8643Sthorpej 		 * if any.  The loop is here in the case that there is an MFC
430c66b8643Sthorpej 		 * card with no longlink (which defaults to existing, == 0).
431c66b8643Sthorpej 		 * In general, this means that if one pointer fails, it will
432c66b8643Sthorpej 		 * try the next one, instead of just bailing.
433c66b8643Sthorpej 		 */
434c66b8643Sthorpej 
435c66b8643Sthorpej 		while (1) {
436c66b8643Sthorpej 			pcmcia_chip_mem_unmap(pct, pch, window);
437c66b8643Sthorpej 
438c66b8643Sthorpej 			if (longlink_present) {
439c66b8643Sthorpej 				/*
440c66b8643Sthorpej 				 * if the longlink is to attribute memory,
441c66b8643Sthorpej 				 * then it is unindexed.  That is, if the
442c66b8643Sthorpej 				 * link value is 0x100, then the actual
443c66b8643Sthorpej 				 * memory address is 0x200.  This means that
444c66b8643Sthorpej 				 * we need to multiply by 2 before calling
445c66b8643Sthorpej 				 * mem_map, and then divide the resulting ptr
446c66b8643Sthorpej 				 * by 2 after.
447c66b8643Sthorpej 				 */
448c66b8643Sthorpej 
449c66b8643Sthorpej 				if (!longlink_common)
450c66b8643Sthorpej 					longlink_addr *= 2;
451c66b8643Sthorpej 
452c66b8643Sthorpej 				pcmcia_chip_mem_map(pct, pch, longlink_common ?
453d8595b9aSchopps 				    (PCMCIA_WIDTH_MEM8 | PCMCIA_MEM_COMMON) :
454d8595b9aSchopps 				    PCMCIA_MEM_ATTR,
455c66b8643Sthorpej 				    longlink_addr, PCMCIA_CIS_SIZE,
456c66b8643Sthorpej 				    &pcmh, &tuple.ptr, &window);
457c66b8643Sthorpej 
45839b794a4Sgdamore 				tuple.memt = pcmh.memt;
45939b794a4Sgdamore 				tuple.memh = pcmh.memh;
46039b794a4Sgdamore 
461c66b8643Sthorpej 				if (!longlink_common)
462c66b8643Sthorpej 					tuple.ptr /= 2;
463c66b8643Sthorpej 
464c66b8643Sthorpej 				DPRINTF(("cis mem map %x\n",
465c66b8643Sthorpej 				    (unsigned int) tuple.memh));
466c66b8643Sthorpej 
467c66b8643Sthorpej 				tuple.mult = longlink_common ? 1 : 2;
468c66b8643Sthorpej 				longlink_present = 0;
469c66b8643Sthorpej 				longlink_common = 1;
470c66b8643Sthorpej 				longlink_addr = 0;
471c66b8643Sthorpej 			} else if (mfc_count && (mfc_index < mfc_count)) {
472c66b8643Sthorpej 				if (!mfc[mfc_index].common)
473c66b8643Sthorpej 					mfc[mfc_index].addr *= 2;
474c66b8643Sthorpej 
475c66b8643Sthorpej 				pcmcia_chip_mem_map(pct, pch,
476c66b8643Sthorpej 				    mfc[mfc_index].common ?
47791026fe7Senami 				    (PCMCIA_WIDTH_MEM8 | PCMCIA_MEM_COMMON) :
47891026fe7Senami 				    PCMCIA_MEM_ATTR,
479c66b8643Sthorpej 				    mfc[mfc_index].addr, PCMCIA_CIS_SIZE,
480c66b8643Sthorpej 				    &pcmh, &tuple.ptr, &window);
481c66b8643Sthorpej 
482c66b8643Sthorpej 				if (!mfc[mfc_index].common)
483c66b8643Sthorpej 					tuple.ptr /= 2;
484c66b8643Sthorpej 
485c66b8643Sthorpej 				DPRINTF(("cis mem map %x\n",
486c66b8643Sthorpej 				    (unsigned int) tuple.memh));
487c66b8643Sthorpej 
488c66b8643Sthorpej 				/* set parse state, and point at the next one */
489c66b8643Sthorpej 
490c66b8643Sthorpej 				tuple.mult = mfc[mfc_index].common ? 1 : 2;
491c66b8643Sthorpej 
492c66b8643Sthorpej 				mfc_index++;
493c66b8643Sthorpej 			} else {
494c66b8643Sthorpej 				goto done;
495c66b8643Sthorpej 			}
496c66b8643Sthorpej 
497c66b8643Sthorpej 			/* make sure that the link is valid */
498c66b8643Sthorpej 			tuple.code = pcmcia_cis_read_1(&tuple, tuple.ptr);
499c66b8643Sthorpej 			if (tuple.code != PCMCIA_CISTPL_LINKTARGET) {
500c66b8643Sthorpej 				DPRINTF(("CISTPL_LINKTARGET expected, "
501c66b8643Sthorpej 				    "code %02x observed\n", tuple.code));
502c66b8643Sthorpej 				continue;
503c66b8643Sthorpej 			}
504c66b8643Sthorpej 			tuple.length = pcmcia_cis_read_1(&tuple, tuple.ptr + 1);
505c66b8643Sthorpej 			if (tuple.length < 3) {
506c66b8643Sthorpej 				DPRINTF(("CISTPL_LINKTARGET too short %d\n",
507c66b8643Sthorpej 				    tuple.length));
508c66b8643Sthorpej 				continue;
509c66b8643Sthorpej 			}
510c66b8643Sthorpej 			if ((pcmcia_tuple_read_1(&tuple, 0) != 'C') ||
511c66b8643Sthorpej 			    (pcmcia_tuple_read_1(&tuple, 1) != 'I') ||
512c66b8643Sthorpej 			    (pcmcia_tuple_read_1(&tuple, 2) != 'S')) {
513c66b8643Sthorpej 				DPRINTF(("CISTPL_LINKTARGET magic "
514c66b8643Sthorpej 				    "%02x%02x%02x incorrect\n",
515c66b8643Sthorpej 				    pcmcia_tuple_read_1(&tuple, 0),
516c66b8643Sthorpej 				    pcmcia_tuple_read_1(&tuple, 1),
517c66b8643Sthorpej 				    pcmcia_tuple_read_1(&tuple, 2)));
518c66b8643Sthorpej 				continue;
519c66b8643Sthorpej 			}
520c66b8643Sthorpej 			tuple.ptr += 2 + tuple.length;
521c66b8643Sthorpej 
522c66b8643Sthorpej 			break;
523c66b8643Sthorpej 		}
524c66b8643Sthorpej 	}
525c66b8643Sthorpej 
526c66b8643Sthorpej 	pcmcia_chip_mem_unmap(pct, pch, window);
527c66b8643Sthorpej 
528c66b8643Sthorpej done:
529c66b8643Sthorpej 	/* Last, free the allocated memory block */
530c66b8643Sthorpej 	pcmcia_chip_mem_free(pct, pch, &pcmh);
531c66b8643Sthorpej 
532c66b8643Sthorpej 	return (ret);
533c66b8643Sthorpej }
534c66b8643Sthorpej 
535c66b8643Sthorpej /* XXX this is incredibly verbose.  Not sure what trt is */
536c66b8643Sthorpej 
537c66b8643Sthorpej void
pcmcia_print_cis(struct pcmcia_softc * sc)538454af1c0Sdsl pcmcia_print_cis(struct pcmcia_softc *sc)
539c66b8643Sthorpej {
540c66b8643Sthorpej 	struct pcmcia_card *card = &sc->card;
541c66b8643Sthorpej 	struct pcmcia_function *pf;
542c66b8643Sthorpej 	struct pcmcia_config_entry *cfe;
543c66b8643Sthorpej 	int i;
544c66b8643Sthorpej 
54502b7e019Sdrochner 	printf("%s: CIS version ", device_xname(sc->dev));
5467734e0efSmsaitoh 	if (card->cis1_major == 4) {
5477734e0efSmsaitoh 		if (card->cis1_minor == 0)
5487734e0efSmsaitoh 			printf("PCMCIA 1.0\n");
5497734e0efSmsaitoh 		else if (card->cis1_minor == 1)
5507734e0efSmsaitoh 			printf("PCMCIA 2.0 or 2.1\n");
5517734e0efSmsaitoh 	} else if (card->cis1_major >= 5)
5527734e0efSmsaitoh 		printf("PC Card Standard %d.%d\n", card->cis1_major, card->cis1_minor);
553c66b8643Sthorpej 	else
554c66b8643Sthorpej 		printf("unknown (major=%d, minor=%d)\n",
555c66b8643Sthorpej 		    card->cis1_major, card->cis1_minor);
556c66b8643Sthorpej 
55702b7e019Sdrochner 	printf("%s: CIS info: ", device_xname(sc->dev));
558c66b8643Sthorpej 	for (i = 0; i < 4; i++) {
559c66b8643Sthorpej 		if (card->cis1_info[i] == NULL)
560c66b8643Sthorpej 			break;
561c66b8643Sthorpej 		if (i)
562c66b8643Sthorpej 			printf(", ");
563c66b8643Sthorpej 		printf("%s", card->cis1_info[i]);
564c66b8643Sthorpej 	}
565c66b8643Sthorpej 	printf("\n");
566c66b8643Sthorpej 
567c66b8643Sthorpej 	printf("%s: Manufacturer code 0x%x, product 0x%x\n",
56802b7e019Sdrochner 	       device_xname(sc->dev), card->manufacturer, card->product);
569c66b8643Sthorpej 
57006de4264Slukem 	SIMPLEQ_FOREACH(pf, &card->pf_head, pf_list) {
57102b7e019Sdrochner 		printf("%s: function %d: ", device_xname(sc->dev), pf->number);
572c66b8643Sthorpej 
573c66b8643Sthorpej 		switch (pf->function) {
574a461703dSnathanw 		case PCMCIA_FUNCTION_UNSPEC:
575a461703dSnathanw 			printf("unspecified");
576a461703dSnathanw 			break;
577a461703dSnathanw 		case PCMCIA_FUNCTION_MULTIFUNCTION:
578c66b8643Sthorpej 			printf("multi-function");
579c66b8643Sthorpej 			break;
580a461703dSnathanw 		case PCMCIA_FUNCTION_MEMORY:
581c66b8643Sthorpej 			printf("memory");
582c66b8643Sthorpej 			break;
583a461703dSnathanw 		case PCMCIA_FUNCTION_SERIAL:
584c66b8643Sthorpej 			printf("serial port");
585c66b8643Sthorpej 			break;
586a461703dSnathanw 		case PCMCIA_FUNCTION_PARALLEL:
587c66b8643Sthorpej 			printf("parallel port");
588c66b8643Sthorpej 			break;
589a461703dSnathanw 		case PCMCIA_FUNCTION_DISK:
590c66b8643Sthorpej 			printf("fixed disk");
5918130f0ecShaya 			switch (pf->pf_funce_disk_interface) {
5928130f0ecShaya 			case PCMCIA_TPLFE_DDI_PCCARD_ATA:
5938130f0ecShaya 				printf("(ata)");
5948130f0ecShaya 				break;
5958130f0ecShaya 			default:
5968130f0ecShaya 				break;
5978130f0ecShaya 			}
598c66b8643Sthorpej 			break;
599a461703dSnathanw 		case PCMCIA_FUNCTION_VIDEO:
600c66b8643Sthorpej 			printf("video adapter");
601c66b8643Sthorpej 			break;
602a461703dSnathanw 		case PCMCIA_FUNCTION_NETWORK:
603c66b8643Sthorpej 			printf("network adapter");
604c66b8643Sthorpej 			break;
605a461703dSnathanw 		case PCMCIA_FUNCTION_AIMS:
606c66b8643Sthorpej 			printf("auto incrementing mass storage");
607c66b8643Sthorpej 			break;
608a461703dSnathanw 		case PCMCIA_FUNCTION_SCSI:
60934b0df80Smsaitoh 			printf("SCSI bridge");
61034b0df80Smsaitoh 			break;
611a461703dSnathanw 		case PCMCIA_FUNCTION_SECURITY:
61234b0df80Smsaitoh 			printf("Security services");
61334b0df80Smsaitoh 			break;
614a461703dSnathanw 		case PCMCIA_FUNCTION_INSTRUMENT:
61534b0df80Smsaitoh 			printf("Instrument");
61634b0df80Smsaitoh 			break;
617c66b8643Sthorpej 		default:
618c66b8643Sthorpej 			printf("unknown (%d)", pf->function);
619c66b8643Sthorpej 			break;
620c66b8643Sthorpej 		}
621c66b8643Sthorpej 
622c66b8643Sthorpej 		printf(", ccr addr %lx mask %lx\n", pf->ccr_base, pf->ccr_mask);
623c66b8643Sthorpej 
62406de4264Slukem 		SIMPLEQ_FOREACH(cfe, &pf->cfe_head, cfe_list) {
625c66b8643Sthorpej 			printf("%s: function %d, config table entry %d: ",
62602b7e019Sdrochner 			    device_xname(sc->dev), pf->number, cfe->number);
627c66b8643Sthorpej 
628c66b8643Sthorpej 			switch (cfe->iftype) {
629c66b8643Sthorpej 			case PCMCIA_IFTYPE_MEMORY:
630c66b8643Sthorpej 				printf("memory card");
631c66b8643Sthorpej 				break;
632c66b8643Sthorpej 			case PCMCIA_IFTYPE_IO:
633c66b8643Sthorpej 				printf("I/O card");
634c66b8643Sthorpej 				break;
635c66b8643Sthorpej 			default:
636c66b8643Sthorpej 				printf("card type unknown");
637c66b8643Sthorpej 				break;
638c66b8643Sthorpej 			}
639c66b8643Sthorpej 
640c66b8643Sthorpej 			printf("; irq mask %x", cfe->irqmask);
641c66b8643Sthorpej 
642c66b8643Sthorpej 			if (cfe->num_iospace) {
643c66b8643Sthorpej 				printf("; iomask %lx, iospace", cfe->iomask);
644c66b8643Sthorpej 
6458567277aSenami 				for (i = 0; i < cfe->num_iospace; i++) {
6468567277aSenami 					printf(" %lx", cfe->iospace[i].start);
647c95ed3d2Sbad 					if (cfe->iospace[i].length)
648c95ed3d2Sbad 						printf("-%lx",
649c66b8643Sthorpej 						    cfe->iospace[i].start +
650c66b8643Sthorpej 						    cfe->iospace[i].length - 1);
651c66b8643Sthorpej 				}
6528567277aSenami 			}
653c66b8643Sthorpej 			if (cfe->num_memspace) {
654c66b8643Sthorpej 				printf("; memspace");
655c66b8643Sthorpej 
6568567277aSenami 				for (i = 0; i < cfe->num_memspace; i++) {
657c95ed3d2Sbad 					printf(" %lx",
658c95ed3d2Sbad 					    cfe->memspace[i].cardaddr);
659c95ed3d2Sbad 					if (cfe->memspace[i].length)
660c95ed3d2Sbad 						printf("-%lx",
661c66b8643Sthorpej 						    cfe->memspace[i].cardaddr +
662c95ed3d2Sbad 						    cfe->memspace[i].length - 1);
663c95ed3d2Sbad 					if (cfe->memspace[i].hostaddr)
664c95ed3d2Sbad 						printf("@%lx",
665c66b8643Sthorpej 						    cfe->memspace[i].hostaddr);
666c66b8643Sthorpej 				}
6678567277aSenami 			}
668c66b8643Sthorpej 			if (cfe->maxtwins)
669c66b8643Sthorpej 				printf("; maxtwins %d", cfe->maxtwins);
670c66b8643Sthorpej 
671c66b8643Sthorpej 			printf(";");
672c66b8643Sthorpej 
673c66b8643Sthorpej 			if (cfe->flags & PCMCIA_CFE_MWAIT_REQUIRED)
674c66b8643Sthorpej 				printf(" mwait_required");
675c66b8643Sthorpej 			if (cfe->flags & PCMCIA_CFE_RDYBSY_ACTIVE)
676c66b8643Sthorpej 				printf(" rdybsy_active");
677c66b8643Sthorpej 			if (cfe->flags & PCMCIA_CFE_WP_ACTIVE)
678c66b8643Sthorpej 				printf(" wp_active");
679c66b8643Sthorpej 			if (cfe->flags & PCMCIA_CFE_BVD_ACTIVE)
680c66b8643Sthorpej 				printf(" bvd_active");
681c66b8643Sthorpej 			if (cfe->flags & PCMCIA_CFE_IO8)
682c66b8643Sthorpej 				printf(" io8");
683c66b8643Sthorpej 			if (cfe->flags & PCMCIA_CFE_IO16)
684c66b8643Sthorpej 				printf(" io16");
685c66b8643Sthorpej 			if (cfe->flags & PCMCIA_CFE_IRQSHARE)
686c66b8643Sthorpej 				printf(" irqshare");
687c66b8643Sthorpej 			if (cfe->flags & PCMCIA_CFE_IRQPULSE)
688c66b8643Sthorpej 				printf(" irqpulse");
689c66b8643Sthorpej 			if (cfe->flags & PCMCIA_CFE_IRQLEVEL)
690c66b8643Sthorpej 				printf(" irqlevel");
691c66b8643Sthorpej 			if (cfe->flags & PCMCIA_CFE_POWERDOWN)
692c66b8643Sthorpej 				printf(" powerdown");
693c66b8643Sthorpej 			if (cfe->flags & PCMCIA_CFE_READONLY)
694c66b8643Sthorpej 				printf(" readonly");
695c66b8643Sthorpej 			if (cfe->flags & PCMCIA_CFE_AUDIO)
696c66b8643Sthorpej 				printf(" audio");
697c66b8643Sthorpej 
698c66b8643Sthorpej 			printf("\n");
699c66b8643Sthorpej 		}
700c66b8643Sthorpej 	}
701c66b8643Sthorpej 
702c66b8643Sthorpej 	if (card->error)
703c66b8643Sthorpej 		printf("%s: %d errors found while parsing CIS\n",
70402b7e019Sdrochner 		    device_xname(sc->dev), card->error);
705c66b8643Sthorpej }
706c66b8643Sthorpej 
707c66b8643Sthorpej int
pcmcia_parse_cis_tuple(struct pcmcia_tuple * tuple,void * arg)708454af1c0Sdsl pcmcia_parse_cis_tuple(struct pcmcia_tuple *tuple, void *arg)
709c66b8643Sthorpej {
710c66b8643Sthorpej 	struct cis_state *state = arg;
711c66b8643Sthorpej 
712c66b8643Sthorpej 	switch (tuple->code) {
713d663cd12Smarc 	case PCMCIA_CISTPL_END:
714c2909c51Schristos 		decode_end(tuple, state);
715c2909c51Schristos 		break;
716c2909c51Schristos 
717c2909c51Schristos 	case PCMCIA_CISTPL_LONGLINK_MFC:
718c2909c51Schristos 		decode_longlink_mfc(tuple, state);
719c2909c51Schristos 		break;
720c2909c51Schristos 
721c2909c51Schristos 	case PCMCIA_CISTPL_DEVICE:
722c2909c51Schristos 	case PCMCIA_CISTPL_DEVICE_A:
723c2909c51Schristos 		decode_device(tuple, state);
724c2909c51Schristos 		break;
725c2909c51Schristos 
726c2909c51Schristos 	case PCMCIA_CISTPL_VERS_1:
727c2909c51Schristos 		decode_vers_1(tuple, state);
728c2909c51Schristos 		break;
729c2909c51Schristos 
730c2909c51Schristos 	case PCMCIA_CISTPL_MANFID:
731c2909c51Schristos 		decode_manfid(tuple, state);
732c2909c51Schristos 		break;
733c2909c51Schristos 
734c2909c51Schristos 	case PCMCIA_CISTPL_FUNCID:
735c2909c51Schristos 		decode_funcid(tuple, state);
736c2909c51Schristos 		break;
737c2909c51Schristos 
738c2909c51Schristos 	case PCMCIA_CISTPL_FUNCE:
739c2909c51Schristos 		decode_funce(tuple, state);
740c2909c51Schristos 		break;
741c2909c51Schristos 
742c2909c51Schristos 	case PCMCIA_CISTPL_CONFIG:
743c2909c51Schristos 		decode_config(tuple, state);
744c2909c51Schristos 		break;
745c2909c51Schristos 
746c2909c51Schristos 	case PCMCIA_CISTPL_CFTABLE_ENTRY:
747c2909c51Schristos 		decode_cftable_entry(tuple, state);
748c2909c51Schristos 		break;
749c2909c51Schristos 	default:
750c2909c51Schristos 		DPRINTF(("unhandled CISTPL %x\n", tuple->code));
751c2909c51Schristos 		break;
752c2909c51Schristos 	}
753c2909c51Schristos 
754c2909c51Schristos 	return (0);
755c2909c51Schristos }
756c2909c51Schristos 
757c2909c51Schristos static void
decode_end(struct pcmcia_tuple * tuple,struct cis_state * state)758168cd830Schristos decode_end(struct pcmcia_tuple *tuple, struct cis_state *state)
759c2909c51Schristos {
760d663cd12Smarc 	/* if we've seen a LONGLINK_MFC, and this is the first
761d663cd12Smarc 	 * END after it, reset the function list.
762d663cd12Smarc 	 *
763d663cd12Smarc 	 * XXX This might also be the right place to start a
764d663cd12Smarc 	 * new function, but that assumes that a function
765d663cd12Smarc 	 * definition never crosses any longlink, and I'm not
766d663cd12Smarc 	 * sure about that.  This is probably safe for MFC
767d663cd12Smarc 	 * cards, but what we have now isn't broken, so I'd
768d663cd12Smarc 	 * rather not change it.
769c66b8643Sthorpej 	 */
770d663cd12Smarc 	if (state->gotmfc == 1) {
771d663cd12Smarc 		state->gotmfc = 2;
7724251568aSchristos 		state->count = 0;
773c66b8643Sthorpej 		state->pf = NULL;
7744251568aSchristos 
7754251568aSchristos 		pcmcia_free_pf(&state->card->pf_head);
776c66b8643Sthorpej 	}
777c2909c51Schristos }
778c2909c51Schristos 
779c2909c51Schristos static void
decode_longlink_mfc(struct pcmcia_tuple * tuple,struct cis_state * state)780168cd830Schristos decode_longlink_mfc(struct pcmcia_tuple *tuple,
7814d595fd7Schristos     struct cis_state *state)
782c2909c51Schristos {
783d663cd12Smarc 	/*
784d663cd12Smarc 	 * this tuple's structure was dealt with in scan_cis.  here,
785d663cd12Smarc 	 * record the fact that the MFC tuple was seen, so that
786d663cd12Smarc 	 * functions declared before the MFC link can be cleaned
787d663cd12Smarc 	 * up.
788d663cd12Smarc 	 */
7894251568aSchristos 	if (state->gotmfc == 0) {
790d663cd12Smarc 		state->gotmfc = 1;
7914251568aSchristos 	} else {
7924251568aSchristos 		DPRINTF(("got LONGLINK_MFC again!"));
7934251568aSchristos 	}
794c2909c51Schristos }
795c2909c51Schristos 
796c2909c51Schristos static void
decode_device(struct pcmcia_tuple * tuple,struct cis_state * state)797168cd830Schristos decode_device(struct pcmcia_tuple *tuple,
798168cd830Schristos     struct cis_state *state)
799c66b8643Sthorpej {
800c2909c51Schristos #ifdef PCMCIACISDEBUG
801c66b8643Sthorpej 	u_int reg, dtype, dspeed;
802c66b8643Sthorpej 
803c66b8643Sthorpej 	reg = pcmcia_tuple_read_1(tuple, 0);
804c66b8643Sthorpej 	dtype = reg & PCMCIA_DTYPE_MASK;
805c66b8643Sthorpej 	dspeed = reg & PCMCIA_DSPEED_MASK;
806c66b8643Sthorpej 
807c66b8643Sthorpej 	DPRINTF(("CISTPL_DEVICE%s type=",
808c66b8643Sthorpej 	(tuple->code == PCMCIA_CISTPL_DEVICE) ? "" : "_A"));
809c66b8643Sthorpej 	switch (dtype) {
810c66b8643Sthorpej 	case PCMCIA_DTYPE_NULL:
811c66b8643Sthorpej 		DPRINTF(("null"));
812c66b8643Sthorpej 		break;
813c66b8643Sthorpej 	case PCMCIA_DTYPE_ROM:
814c66b8643Sthorpej 		DPRINTF(("rom"));
815c66b8643Sthorpej 		break;
816c66b8643Sthorpej 	case PCMCIA_DTYPE_OTPROM:
817c66b8643Sthorpej 		DPRINTF(("otprom"));
818c66b8643Sthorpej 		break;
819c66b8643Sthorpej 	case PCMCIA_DTYPE_EPROM:
820c66b8643Sthorpej 		DPRINTF(("eprom"));
821c66b8643Sthorpej 		break;
822c66b8643Sthorpej 	case PCMCIA_DTYPE_EEPROM:
823c66b8643Sthorpej 		DPRINTF(("eeprom"));
824c66b8643Sthorpej 		break;
825c66b8643Sthorpej 	case PCMCIA_DTYPE_FLASH:
826c66b8643Sthorpej 		DPRINTF(("flash"));
827c66b8643Sthorpej 		break;
828c66b8643Sthorpej 	case PCMCIA_DTYPE_SRAM:
829c66b8643Sthorpej 		DPRINTF(("sram"));
830c66b8643Sthorpej 		break;
831c66b8643Sthorpej 	case PCMCIA_DTYPE_DRAM:
832c66b8643Sthorpej 		DPRINTF(("dram"));
833c66b8643Sthorpej 		break;
834c66b8643Sthorpej 	case PCMCIA_DTYPE_FUNCSPEC:
835c66b8643Sthorpej 		DPRINTF(("funcspec"));
836c66b8643Sthorpej 		break;
837c66b8643Sthorpej 	case PCMCIA_DTYPE_EXTEND:
838c66b8643Sthorpej 		DPRINTF(("extend"));
839c66b8643Sthorpej 		break;
840c66b8643Sthorpej 	default:
841c66b8643Sthorpej 		DPRINTF(("reserved"));
842c66b8643Sthorpej 		break;
843c66b8643Sthorpej 	}
844c66b8643Sthorpej 	DPRINTF((" speed="));
845c66b8643Sthorpej 	switch (dspeed) {
846c66b8643Sthorpej 	case PCMCIA_DSPEED_NULL:
847c66b8643Sthorpej 		DPRINTF(("null"));
848c66b8643Sthorpej 		break;
849c66b8643Sthorpej 	case PCMCIA_DSPEED_250NS:
850c66b8643Sthorpej 		DPRINTF(("250ns"));
851c66b8643Sthorpej 		break;
852c66b8643Sthorpej 	case PCMCIA_DSPEED_200NS:
853c66b8643Sthorpej 		DPRINTF(("200ns"));
854c66b8643Sthorpej 		break;
855c66b8643Sthorpej 	case PCMCIA_DSPEED_150NS:
856c66b8643Sthorpej 		DPRINTF(("150ns"));
857c66b8643Sthorpej 		break;
858c66b8643Sthorpej 	case PCMCIA_DSPEED_100NS:
859c66b8643Sthorpej 		DPRINTF(("100ns"));
860c66b8643Sthorpej 		break;
861c66b8643Sthorpej 	case PCMCIA_DSPEED_EXT:
862c66b8643Sthorpej 		DPRINTF(("ext"));
863c66b8643Sthorpej 		break;
864c66b8643Sthorpej 	default:
865c66b8643Sthorpej 		DPRINTF(("reserved"));
866c66b8643Sthorpej 		break;
867c66b8643Sthorpej 	}
868c66b8643Sthorpej 	DPRINTF(("\n"));
869c66b8643Sthorpej #endif
870c2909c51Schristos }
871c2909c51Schristos 
872c2909c51Schristos static void
decode_vers_1(struct pcmcia_tuple * tuple,struct cis_state * state)873c2909c51Schristos decode_vers_1(struct pcmcia_tuple *tuple, struct cis_state *state)
874c2909c51Schristos {
875c2909c51Schristos 	int start, i, ch, count;
876c2909c51Schristos 
877c66b8643Sthorpej 	if (tuple->length < 6) {
878c66b8643Sthorpej 		DPRINTF(("CISTPL_VERS_1 too short %d\n",
879c66b8643Sthorpej 		    tuple->length));
880c2909c51Schristos 		return;
881c2909c51Schristos 	}
882c66b8643Sthorpej 	state->card->cis1_major = pcmcia_tuple_read_1(tuple, 0);
883c66b8643Sthorpej 	state->card->cis1_minor = pcmcia_tuple_read_1(tuple, 1);
884c66b8643Sthorpej 
885c66b8643Sthorpej 	for (count = 0, start = 0, i = 0;
886c66b8643Sthorpej 	    (count < 4) && ((i + 4) < 256); i++) {
887c66b8643Sthorpej 		ch = pcmcia_tuple_read_1(tuple, 2 + i);
888ceafcbd8Sjun 		if (ch == 0xff) {
889ceafcbd8Sjun 			if (i > start) {
890ceafcbd8Sjun 				state->card->cis1_info_buf[i] = 0;
891ceafcbd8Sjun 				state->card->cis1_info[count] =
892ceafcbd8Sjun 				    state->card->cis1_info_buf + start;
893ceafcbd8Sjun 			}
894c66b8643Sthorpej 			break;
895ceafcbd8Sjun 		}
896c66b8643Sthorpej 		state->card->cis1_info_buf[i] = ch;
897c66b8643Sthorpej 		if (ch == 0) {
898c66b8643Sthorpej 			state->card->cis1_info[count] =
899c66b8643Sthorpej 			    state->card->cis1_info_buf + start;
900c66b8643Sthorpej 			start = i + 1;
901c66b8643Sthorpej 			count++;
902c66b8643Sthorpej 		}
903c66b8643Sthorpej 	}
904c66b8643Sthorpej 	DPRINTF(("CISTPL_VERS_1\n"));
905c66b8643Sthorpej }
906c2909c51Schristos 
907c2909c51Schristos static void
decode_manfid(struct pcmcia_tuple * tuple,struct cis_state * state)908c2909c51Schristos decode_manfid(struct pcmcia_tuple *tuple, struct cis_state *state)
909c2909c51Schristos {
910c66b8643Sthorpej 	if (tuple->length < 4) {
911c66b8643Sthorpej 		DPRINTF(("CISTPL_MANFID too short %d\n",
912c66b8643Sthorpej 		    tuple->length));
913c2909c51Schristos 		return;
914c66b8643Sthorpej 	}
915c66b8643Sthorpej 	state->card->manufacturer = pcmcia_tuple_read_2(tuple, 0);
916c66b8643Sthorpej 	state->card->product = pcmcia_tuple_read_2(tuple, 2);
917c66b8643Sthorpej 	DPRINTF(("CISTPL_MANFID\n"));
918c2909c51Schristos }
919c2909c51Schristos 
920c2909c51Schristos static void
decode_funcid(struct pcmcia_tuple * tuple,struct cis_state * state)921c2909c51Schristos decode_funcid(struct pcmcia_tuple *tuple, struct cis_state *state)
922c2909c51Schristos {
923c66b8643Sthorpej 	if (tuple->length < 1) {
924c66b8643Sthorpej 		DPRINTF(("CISTPL_FUNCID too short %d\n",
925c66b8643Sthorpej 		    tuple->length));
926c2909c51Schristos 		return;
927c66b8643Sthorpej 	}
928b495351fSbouyer 	if (state->pf) {
929b495351fSbouyer 		if (state->pf->function == PCMCIA_FUNCTION_UNSPEC) {
930b495351fSbouyer 			/*
931b495351fSbouyer 			 * This looks like a opportunistic function
932b495351fSbouyer 			 * created by a CONFIG tuple.  Just keep it.
933b495351fSbouyer 			 */
934b495351fSbouyer 		} else {
935b495351fSbouyer 			/*
936b495351fSbouyer 			 * A function is being defined, end it.
937b495351fSbouyer 			 */
938b495351fSbouyer 			state->pf = NULL;
939b495351fSbouyer 		}
940b495351fSbouyer 	}
9414251568aSchristos 	if (state->pf == NULL)
9424251568aSchristos 		create_pf(state);
943c66b8643Sthorpej 	state->pf->function = pcmcia_tuple_read_1(tuple, 0);
944c66b8643Sthorpej 
945c66b8643Sthorpej 	DPRINTF(("CISTPL_FUNCID\n"));
946c2909c51Schristos }
947c2909c51Schristos 
948c2909c51Schristos static void
decode_funce(struct pcmcia_tuple * tuple,struct cis_state * state)949c2909c51Schristos decode_funce(struct pcmcia_tuple *tuple, struct cis_state *state)
950c2909c51Schristos {
951c2909c51Schristos 	struct pcmcia_function *pf = state->pf;
952c2909c51Schristos 	int type = pcmcia_tuple_read_1(tuple, 0);
953c2909c51Schristos 
9548130f0ecShaya 	if (state->pf == NULL || state->pf->function <= 0) {
9558130f0ecShaya 		DPRINTF(("CISTPL_FUNCE is not followed by "
9568130f0ecShaya 		    "valid CISTPL_FUNCID\n"));
957c2909c51Schristos 		return;
9588130f0ecShaya 	}
959c2909c51Schristos 	if (tuple->length < 2)
960c2909c51Schristos 		return;
961c2909c51Schristos 	switch (pf->function) {
962c2909c51Schristos 	case PCMCIA_FUNCTION_DISK:
963c2909c51Schristos 		if (type == PCMCIA_TPLFE_TYPE_DISK_DEVICE_INTERFACE) {
964c2909c51Schristos 			pf->pf_funce_disk_interface
965c2909c51Schristos 			    = pcmcia_tuple_read_1(tuple, 1);
9668130f0ecShaya 		}
9678130f0ecShaya 		break;
968c2909c51Schristos 	case PCMCIA_FUNCTION_NETWORK:
969c2909c51Schristos 		if (type == PCMCIA_TPLFE_TYPE_LAN_NID) {
970c2909c51Schristos 			int i;
971c2909c51Schristos 			int len = pcmcia_tuple_read_1(tuple, 1);
972c2909c51Schristos 			if (tuple->length < 2 + len || len > 8) {
973c2909c51Schristos 				/* tuple length not enough or nid too long */
974c66b8643Sthorpej 				break;
975c2909c51Schristos 			}
976c2909c51Schristos 			for (i = 0; i < len; ++i) {
977c2909c51Schristos 				pf->pf_funce_lan_nid[i]
978c2909c51Schristos 				    = pcmcia_tuple_read_1(tuple, 2 + i);
979c2909c51Schristos 			}
980c2909c51Schristos 			pf->pf_funce_lan_nidlen = len;
981c2909c51Schristos 		}
982c2909c51Schristos 		break;
983c2909c51Schristos 	default:
984c2909c51Schristos 		break;
985c2909c51Schristos 	}
986c2909c51Schristos 
987c2909c51Schristos 	return;
988c2909c51Schristos }
989c2909c51Schristos 
990c2909c51Schristos static void
decode_config(struct pcmcia_tuple * tuple,struct cis_state * state)991c2909c51Schristos decode_config(struct pcmcia_tuple *tuple, struct cis_state *state)
992c2909c51Schristos {
993c66b8643Sthorpej 	u_int reg, rasz, rmsz, rfsz;
994c66b8643Sthorpej 	int i;
995c2909c51Schristos 	/* most of these are educated guesses */
996c2909c51Schristos 	static const struct pcmcia_config_entry init_cfe = {
9973cd45450Schristos 		.number	= -1,
9983cd45450Schristos 		.flags	= PCMCIA_CFE_RDYBSY_ACTIVE | PCMCIA_CFE_WP_ACTIVE |
9993cd45450Schristos 			  PCMCIA_CFE_BVD_ACTIVE,
10003cd45450Schristos 		.iftype	= PCMCIA_IFTYPE_MEMORY,
1001c2909c51Schristos 	};
1002c66b8643Sthorpej 
1003c2909c51Schristos 	if (tuple->length < 3) {
1004c2909c51Schristos 		DPRINTF(("CISTPL_CONFIG too short %d\n", tuple->length));
1005c2909c51Schristos 		return;
1006c2909c51Schristos 	}
1007c66b8643Sthorpej 	reg = pcmcia_tuple_read_1(tuple, 0);
1008c66b8643Sthorpej 	rasz = 1 + ((reg & PCMCIA_TPCC_RASZ_MASK) >>
1009c66b8643Sthorpej 	    PCMCIA_TPCC_RASZ_SHIFT);
1010c66b8643Sthorpej 	rmsz = 1 + ((reg & PCMCIA_TPCC_RMSZ_MASK) >>
1011c66b8643Sthorpej 	    PCMCIA_TPCC_RMSZ_SHIFT);
1012c66b8643Sthorpej 	rfsz = ((reg & PCMCIA_TPCC_RFSZ_MASK) >>
1013c66b8643Sthorpej 	    PCMCIA_TPCC_RFSZ_SHIFT);
1014c66b8643Sthorpej 
1015c66b8643Sthorpej 	if (tuple->length < (rasz + rmsz + rfsz)) {
1016c2909c51Schristos 		DPRINTF(("CISTPL_CONFIG (%d,%d,%d) too short %d\n",
1017c2909c51Schristos 		    rasz, rmsz, rfsz, tuple->length));
1018c2909c51Schristos 		return;
1019c66b8643Sthorpej 	}
1020c66b8643Sthorpej 	if (state->pf == NULL) {
10214251568aSchristos 		create_pf(state);
1022a461703dSnathanw 		state->pf->function = PCMCIA_FUNCTION_UNSPEC;
1023c66b8643Sthorpej 	}
1024c66b8643Sthorpej 	state->pf->last_config_index =
1025c66b8643Sthorpej 	    pcmcia_tuple_read_1(tuple, 1);
1026c66b8643Sthorpej 
1027c66b8643Sthorpej 	state->pf->ccr_base = 0;
1028c66b8643Sthorpej 	for (i = 0; i < rasz; i++)
1029c2909c51Schristos 		state->pf->ccr_base |= ((pcmcia_tuple_read_1(tuple, 2 + i)) <<
1030c66b8643Sthorpej 		    (i * 8));
1031c66b8643Sthorpej 
1032c66b8643Sthorpej 	state->pf->ccr_mask = 0;
1033c66b8643Sthorpej 	for (i = 0; i < rmsz; i++)
1034c2909c51Schristos 		state->pf->ccr_mask |= ((pcmcia_tuple_read_1(tuple,
1035c66b8643Sthorpej 		    2 + rasz + i)) << (i * 8));
1036c66b8643Sthorpej 
1037c66b8643Sthorpej 	/* skip the reserved area and subtuples */
1038c66b8643Sthorpej 
1039c66b8643Sthorpej 	/* reset the default cfe for each cfe list */
1040c66b8643Sthorpej 	state->temp_cfe = init_cfe;
1041c66b8643Sthorpej 	state->default_cfe = &state->temp_cfe;
1042c66b8643Sthorpej 	DPRINTF(("CISTPL_CONFIG\n"));
1043c2909c51Schristos }
1044c2909c51Schristos 
1045c2909c51Schristos static void
decode_cftable_entry(struct pcmcia_tuple * tuple,struct cis_state * state)1046c2909c51Schristos decode_cftable_entry(struct pcmcia_tuple *tuple, struct cis_state *state)
1047c66b8643Sthorpej {
1048c66b8643Sthorpej 	int idx, i, j;
1049c66b8643Sthorpej 	u_int reg, reg2;
1050c66b8643Sthorpej 	u_int intface, def, num;
1051c66b8643Sthorpej 	u_int power, timing, iospace, irq, memspace, misc;
1052c66b8643Sthorpej 	struct pcmcia_config_entry *cfe;
1053c66b8643Sthorpej 
1054c66b8643Sthorpej 	idx = 0;
1055c66b8643Sthorpej 
1056c66b8643Sthorpej 	reg = pcmcia_tuple_read_1(tuple, idx);
1057c66b8643Sthorpej 	idx++;
1058c66b8643Sthorpej 	intface = reg & PCMCIA_TPCE_INDX_INTFACE;
1059c66b8643Sthorpej 	def = reg & PCMCIA_TPCE_INDX_DEFAULT;
1060c66b8643Sthorpej 	num = reg & PCMCIA_TPCE_INDX_NUM_MASK;
1061c66b8643Sthorpej 
1062c66b8643Sthorpej 	/*
1063c66b8643Sthorpej 	 * this is a little messy.  Some cards have only a
1064c66b8643Sthorpej 	 * cfentry with the default bit set.  So, as we go
1065c66b8643Sthorpej 	 * through the list, we add new indexes to the queue,
1066c66b8643Sthorpej 	 * and keep a pointer to the last one with the
1067c66b8643Sthorpej 	 * default bit set.  if we see a record with the same
1068c66b8643Sthorpej 	 * index, as the default, we stash the default and
1069c66b8643Sthorpej 	 * replace the queue entry. otherwise, we just add
1070c66b8643Sthorpej 	 * new entries to the queue, pointing the default ptr
1071c66b8643Sthorpej 	 * at them if the default bit is set.  if we get to
1072c66b8643Sthorpej 	 * the end with the default pointer pointing at a
1073c66b8643Sthorpej 	 * record which hasn't had a matching index, that's
1074c66b8643Sthorpej 	 * ok; it just becomes a cfentry like any other.
1075c66b8643Sthorpej 	 */
1076c66b8643Sthorpej 
1077c66b8643Sthorpej 	/*
1078c66b8643Sthorpej 	 * if the index in the cis differs from the default
1079c66b8643Sthorpej 	 * cis, create new entry in the queue and start it
1080c66b8643Sthorpej 	 * with the current default
1081c66b8643Sthorpej 	 */
1082d4471177Scgd 	if (state->default_cfe == NULL) {
1083d4471177Scgd 		DPRINTF(("CISTPL_CFTABLE_ENTRY with no "
1084d4471177Scgd 		    "default\n"));
1085c2909c51Schristos 		return;
1086d4471177Scgd 	}
1087c66b8643Sthorpej 	if (num != state->default_cfe->number) {
1088*d47bcd29Schs 		cfe = malloc(sizeof(*cfe), M_DEVBUF, M_WAITOK);
1089c66b8643Sthorpej 		*cfe = *state->default_cfe;
1090c66b8643Sthorpej 
1091c2909c51Schristos 		SIMPLEQ_INSERT_TAIL(&state->pf->cfe_head, cfe, cfe_list);
1092c66b8643Sthorpej 
1093c66b8643Sthorpej 		cfe->number = num;
1094c66b8643Sthorpej 
1095c66b8643Sthorpej 		/*
1096c66b8643Sthorpej 		 * if the default bit is set in the cis, then
1097c66b8643Sthorpej 		 * point the new default at whatever is being
1098c66b8643Sthorpej 		 * filled in
1099c66b8643Sthorpej 		 */
1100c66b8643Sthorpej 		if (def)
1101c66b8643Sthorpej 			state->default_cfe = cfe;
1102c66b8643Sthorpej 	} else {
1103c66b8643Sthorpej 		/*
1104c66b8643Sthorpej 		 * the cis index matches the default index,
1105c66b8643Sthorpej 		 * fill in the default cfentry.  It is
1106c66b8643Sthorpej 		 * assumed that the cfdefault index is in the
1107c66b8643Sthorpej 		 * queue.  For it to be otherwise, the cis
1108c66b8643Sthorpej 		 * index would have to be -1 (initial
1109c66b8643Sthorpej 		 * condition) which is not possible, or there
1110c66b8643Sthorpej 		 * would have to be a preceding cis entry
1111c66b8643Sthorpej 		 * which had the same cis index and had the
1112c66b8643Sthorpej 		 * default bit unset. Neither condition
1113c66b8643Sthorpej 		 * should happen.  If it does, this cfentry
1114c66b8643Sthorpej 		 * is lost (written into temp space), which
1115c66b8643Sthorpej 		 * is an acceptable failure mode.
1116c66b8643Sthorpej 		 */
1117c66b8643Sthorpej 
1118c66b8643Sthorpej 		cfe = state->default_cfe;
1119c66b8643Sthorpej 
1120c66b8643Sthorpej 		/*
1121c66b8643Sthorpej 		 * if the cis entry does not have the default
1122c66b8643Sthorpej 		 * bit set, copy the default out of the way
1123c66b8643Sthorpej 		 * first.
1124c66b8643Sthorpej 		 */
1125c66b8643Sthorpej 		if (!def) {
1126c66b8643Sthorpej 			state->temp_cfe = *state->default_cfe;
1127c66b8643Sthorpej 			state->default_cfe = &state->temp_cfe;
1128c66b8643Sthorpej 		}
1129c66b8643Sthorpej 	}
1130c66b8643Sthorpej 
1131c66b8643Sthorpej 	if (intface) {
1132c66b8643Sthorpej 		reg = pcmcia_tuple_read_1(tuple, idx);
1133c66b8643Sthorpej 		idx++;
1134b5064330Schopps 		cfe->flags &= ~(PCMCIA_CFE_MWAIT_REQUIRED
1135b5064330Schopps 		    | PCMCIA_CFE_RDYBSY_ACTIVE
1136b5064330Schopps 		    | PCMCIA_CFE_WP_ACTIVE
1137b5064330Schopps 		    | PCMCIA_CFE_BVD_ACTIVE);
1138c66b8643Sthorpej 		if (reg & PCMCIA_TPCE_IF_MWAIT)
1139c66b8643Sthorpej 			cfe->flags |= PCMCIA_CFE_MWAIT_REQUIRED;
1140c66b8643Sthorpej 		if (reg & PCMCIA_TPCE_IF_RDYBSY)
1141c66b8643Sthorpej 			cfe->flags |= PCMCIA_CFE_RDYBSY_ACTIVE;
1142c66b8643Sthorpej 		if (reg & PCMCIA_TPCE_IF_WP)
1143c66b8643Sthorpej 			cfe->flags |= PCMCIA_CFE_WP_ACTIVE;
1144c66b8643Sthorpej 		if (reg & PCMCIA_TPCE_IF_BVD)
1145c66b8643Sthorpej 			cfe->flags |= PCMCIA_CFE_BVD_ACTIVE;
1146c66b8643Sthorpej 		cfe->iftype = reg & PCMCIA_TPCE_IF_IFTYPE;
1147c66b8643Sthorpej 	}
1148c66b8643Sthorpej 	reg = pcmcia_tuple_read_1(tuple, idx);
1149c66b8643Sthorpej 	idx++;
1150c66b8643Sthorpej 
1151c66b8643Sthorpej 	power = reg & PCMCIA_TPCE_FS_POWER_MASK;
1152c66b8643Sthorpej 	timing = reg & PCMCIA_TPCE_FS_TIMING;
1153c66b8643Sthorpej 	iospace = reg & PCMCIA_TPCE_FS_IOSPACE;
1154c66b8643Sthorpej 	irq = reg & PCMCIA_TPCE_FS_IRQ;
1155c66b8643Sthorpej 	memspace = reg & PCMCIA_TPCE_FS_MEMSPACE_MASK;
1156c66b8643Sthorpej 	misc = reg & PCMCIA_TPCE_FS_MISC;
1157c66b8643Sthorpej 
1158c66b8643Sthorpej 	if (power) {
1159c66b8643Sthorpej 		/* skip over power, don't save */
1160c66b8643Sthorpej 		/* for each parameter selection byte */
1161c66b8643Sthorpej 		for (i = 0; i < power; i++) {
1162c66b8643Sthorpej 			reg = pcmcia_tuple_read_1(tuple, idx);
1163c66b8643Sthorpej 			idx++;
1164c66b8643Sthorpej 			/* for each bit */
1165c66b8643Sthorpej 			for (j = 0; j < 7; j++) {
1166c66b8643Sthorpej 				/* if the bit is set */
1167c66b8643Sthorpej 				if ((reg >> j) & 0x01) {
1168c66b8643Sthorpej 					/* skip over bytes */
1169c66b8643Sthorpej 					do {
1170c66b8643Sthorpej 						reg2 = pcmcia_tuple_read_1(tuple, idx);
1171c66b8643Sthorpej 						idx++;
1172c66b8643Sthorpej 						/*
1173c66b8643Sthorpej 						 * until
1174e959b27dSmjl 						 * non-
1175e959b27dSmjl 						 * extension
1176e959b27dSmjl 						 * byte
1177c66b8643Sthorpej 						 */
1178c66b8643Sthorpej 					} while (reg2 & 0x80);
1179c66b8643Sthorpej 				}
1180c66b8643Sthorpej 			}
1181c66b8643Sthorpej 		}
1182c66b8643Sthorpej 	}
1183c66b8643Sthorpej 	if (timing) {
1184c66b8643Sthorpej 		/* skip over timing, don't save */
1185c66b8643Sthorpej 		reg = pcmcia_tuple_read_1(tuple, idx);
1186c66b8643Sthorpej 		idx++;
1187c66b8643Sthorpej 
1188c66b8643Sthorpej 		if ((reg & PCMCIA_TPCE_TD_RESERVED_MASK) !=
1189c66b8643Sthorpej 		    PCMCIA_TPCE_TD_RESERVED_MASK)
1190c66b8643Sthorpej 			idx++;
1191c66b8643Sthorpej 		if ((reg & PCMCIA_TPCE_TD_RDYBSY_MASK) !=
1192c66b8643Sthorpej 		    PCMCIA_TPCE_TD_RDYBSY_MASK)
1193c66b8643Sthorpej 			idx++;
1194c66b8643Sthorpej 		if ((reg & PCMCIA_TPCE_TD_WAIT_MASK) !=
1195c66b8643Sthorpej 		    PCMCIA_TPCE_TD_WAIT_MASK)
1196c66b8643Sthorpej 			idx++;
1197c66b8643Sthorpej 	}
1198c66b8643Sthorpej 	if (iospace) {
11999ada0bf4Smarc 		if (tuple->length <= idx) {
12009ada0bf4Smarc 			DPRINTF(("ran out of space before TCPE_IO\n"));
12019ada0bf4Smarc 			goto abort_cfe;
12029ada0bf4Smarc 		}
12039ada0bf4Smarc 
1204c66b8643Sthorpej 		reg = pcmcia_tuple_read_1(tuple, idx);
1205c66b8643Sthorpej 		idx++;
1206c66b8643Sthorpej 
1207b5064330Schopps 		cfe->flags &=
1208b5064330Schopps 		    ~(PCMCIA_CFE_IO8 | PCMCIA_CFE_IO16);
1209c66b8643Sthorpej 		if (reg & PCMCIA_TPCE_IO_BUSWIDTH_8BIT)
1210c66b8643Sthorpej 			cfe->flags |= PCMCIA_CFE_IO8;
1211c66b8643Sthorpej 		if (reg & PCMCIA_TPCE_IO_BUSWIDTH_16BIT)
1212c66b8643Sthorpej 			cfe->flags |= PCMCIA_CFE_IO16;
1213c66b8643Sthorpej 		cfe->iomask =
1214c66b8643Sthorpej 		    reg & PCMCIA_TPCE_IO_IOADDRLINES_MASK;
1215c66b8643Sthorpej 
1216c66b8643Sthorpej 		if (reg & PCMCIA_TPCE_IO_HASRANGE) {
1217c66b8643Sthorpej 			reg = pcmcia_tuple_read_1(tuple, idx);
1218c66b8643Sthorpej 			idx++;
1219c66b8643Sthorpej 
1220c66b8643Sthorpej 			cfe->num_iospace = 1 + (reg &
1221c66b8643Sthorpej 			    PCMCIA_TPCE_IO_RANGE_COUNT);
1222c66b8643Sthorpej 
1223c66b8643Sthorpej 			if (cfe->num_iospace >
1224c66b8643Sthorpej 			    (sizeof(cfe->iospace) /
1225c66b8643Sthorpej 			     sizeof(cfe->iospace[0]))) {
1226c66b8643Sthorpej 				DPRINTF(("too many io "
1227c66b8643Sthorpej 				    "spaces %d",
1228c66b8643Sthorpej 				    cfe->num_iospace));
1229c66b8643Sthorpej 				state->card->error++;
1230c2909c51Schristos 				return;
1231c66b8643Sthorpej 			}
1232c66b8643Sthorpej 			for (i = 0; i < cfe->num_iospace; i++) {
1233c66b8643Sthorpej 				switch (reg & PCMCIA_TPCE_IO_RANGE_ADDRSIZE_MASK) {
12340f8f9a1fSitojun 				case PCMCIA_TPCE_IO_RANGE_ADDRSIZE_NONE:
12350f8f9a1fSitojun 					cfe->iospace[i].start =
12360f8f9a1fSitojun 					    0;
12370f8f9a1fSitojun 					break;
1238c66b8643Sthorpej 				case PCMCIA_TPCE_IO_RANGE_ADDRSIZE_ONE:
1239c66b8643Sthorpej 					cfe->iospace[i].start =
1240c66b8643Sthorpej 						pcmcia_tuple_read_1(tuple, idx);
1241c66b8643Sthorpej 					idx++;
1242c66b8643Sthorpej 					break;
1243c66b8643Sthorpej 				case PCMCIA_TPCE_IO_RANGE_ADDRSIZE_TWO:
1244c66b8643Sthorpej 					cfe->iospace[i].start =
1245c66b8643Sthorpej 						pcmcia_tuple_read_2(tuple, idx);
1246c66b8643Sthorpej 					idx += 2;
1247c66b8643Sthorpej 					break;
1248c66b8643Sthorpej 				case PCMCIA_TPCE_IO_RANGE_ADDRSIZE_FOUR:
1249c66b8643Sthorpej 					cfe->iospace[i].start =
1250c66b8643Sthorpej 						pcmcia_tuple_read_4(tuple, idx);
1251c66b8643Sthorpej 					idx += 4;
1252c66b8643Sthorpej 					break;
1253c66b8643Sthorpej 				}
1254c66b8643Sthorpej 				switch (reg &
1255c66b8643Sthorpej 					PCMCIA_TPCE_IO_RANGE_LENGTHSIZE_MASK) {
12560f8f9a1fSitojun 				case PCMCIA_TPCE_IO_RANGE_LENGTHSIZE_NONE:
12570f8f9a1fSitojun 					cfe->iospace[i].length =
12580f8f9a1fSitojun 					    0;
12590f8f9a1fSitojun 					break;
1260c66b8643Sthorpej 				case PCMCIA_TPCE_IO_RANGE_LENGTHSIZE_ONE:
1261c66b8643Sthorpej 					cfe->iospace[i].length =
1262c66b8643Sthorpej 						pcmcia_tuple_read_1(tuple, idx);
1263c66b8643Sthorpej 					idx++;
1264c66b8643Sthorpej 					break;
1265c66b8643Sthorpej 				case PCMCIA_TPCE_IO_RANGE_LENGTHSIZE_TWO:
1266c66b8643Sthorpej 					cfe->iospace[i].length =
1267c66b8643Sthorpej 						pcmcia_tuple_read_2(tuple, idx);
1268c66b8643Sthorpej 					idx += 2;
1269c66b8643Sthorpej 					break;
1270c66b8643Sthorpej 				case PCMCIA_TPCE_IO_RANGE_LENGTHSIZE_FOUR:
1271c66b8643Sthorpej 					cfe->iospace[i].length =
1272c66b8643Sthorpej 						pcmcia_tuple_read_4(tuple, idx);
1273c66b8643Sthorpej 					idx += 4;
1274c66b8643Sthorpej 					break;
1275c66b8643Sthorpej 				}
1276c66b8643Sthorpej 				cfe->iospace[i].length++;
1277c66b8643Sthorpej 			}
1278c66b8643Sthorpej 		} else {
1279c66b8643Sthorpej 			cfe->num_iospace = 1;
1280c66b8643Sthorpej 			cfe->iospace[0].start = 0;
1281c66b8643Sthorpej 			cfe->iospace[0].length =
1282c66b8643Sthorpej 			    (1 << cfe->iomask);
1283c66b8643Sthorpej 		}
1284c66b8643Sthorpej 	}
1285c66b8643Sthorpej 	if (irq) {
12869ada0bf4Smarc 		if (tuple->length <= idx) {
12879ada0bf4Smarc 			DPRINTF(("ran out of space before TCPE_IR\n"));
12889ada0bf4Smarc 			goto abort_cfe;
12899ada0bf4Smarc 		}
12909ada0bf4Smarc 
1291c66b8643Sthorpej 		reg = pcmcia_tuple_read_1(tuple, idx);
1292c66b8643Sthorpej 		idx++;
1293c66b8643Sthorpej 
1294b5064330Schopps 		cfe->flags &= ~(PCMCIA_CFE_IRQSHARE
1295b5064330Schopps 		    | PCMCIA_CFE_IRQPULSE
1296b5064330Schopps 		    | PCMCIA_CFE_IRQLEVEL);
1297c66b8643Sthorpej 		if (reg & PCMCIA_TPCE_IR_SHARE)
1298c66b8643Sthorpej 			cfe->flags |= PCMCIA_CFE_IRQSHARE;
1299c66b8643Sthorpej 		if (reg & PCMCIA_TPCE_IR_PULSE)
1300c66b8643Sthorpej 			cfe->flags |= PCMCIA_CFE_IRQPULSE;
1301c66b8643Sthorpej 		if (reg & PCMCIA_TPCE_IR_LEVEL)
1302c66b8643Sthorpej 			cfe->flags |= PCMCIA_CFE_IRQLEVEL;
1303c66b8643Sthorpej 
1304c66b8643Sthorpej 		if (reg & PCMCIA_TPCE_IR_HASMASK) {
1305c66b8643Sthorpej 			/*
1306c66b8643Sthorpej 			 * it's legal to ignore the
1307c66b8643Sthorpej 			 * special-interrupt bits, so I will
1308c66b8643Sthorpej 			 */
1309c66b8643Sthorpej 
1310c66b8643Sthorpej 			cfe->irqmask =
1311c66b8643Sthorpej 			    pcmcia_tuple_read_2(tuple, idx);
1312c66b8643Sthorpej 			idx += 2;
1313c66b8643Sthorpej 		} else {
1314c66b8643Sthorpej 			cfe->irqmask =
1315c66b8643Sthorpej 			    (1 << (reg & PCMCIA_TPCE_IR_IRQ));
1316c66b8643Sthorpej 		}
1317c66b8643Sthorpej 	}
13184b5dc3b5Schristos 	if (memspace) {
13194b5dc3b5Schristos 		int lengthsize;
13204b5dc3b5Schristos 		int cardaddrsize;
13214b5dc3b5Schristos 		int hostaddrsize;
13224b5dc3b5Schristos 
1323abddbf01Srpaulo 		if (tuple->length <= idx) {
13249ada0bf4Smarc 			DPRINTF(("ran out of space before TCPE_MS\n"));
13259ada0bf4Smarc 			goto abort_cfe;
13269ada0bf4Smarc 		}
13279ada0bf4Smarc 
1328c2909c51Schristos 		switch (memspace) {
13294b5dc3b5Schristos #ifdef notdef	/* This is 0 */
1330c2909c51Schristos 		case PCMCIA_TPCE_FS_MEMSPACE_NONE:
13319ada0bf4Smarc 			cfe->num_memspace = 0;
1332c2909c51Schristos 			break;
13334b5dc3b5Schristos #endif
1334c2909c51Schristos 
1335c2909c51Schristos 		case PCMCIA_TPCE_FS_MEMSPACE_LENGTH:
1336c66b8643Sthorpej 			cfe->num_memspace = 1;
1337c66b8643Sthorpej 			cfe->memspace[0].length = 256 *
1338c66b8643Sthorpej 			    pcmcia_tuple_read_2(tuple, idx);
1339c66b8643Sthorpej 			idx += 2;
1340c66b8643Sthorpej 			cfe->memspace[0].cardaddr = 0;
1341c66b8643Sthorpej 			cfe->memspace[0].hostaddr = 0;
1342c2909c51Schristos 			break;
1343c2909c51Schristos 
1344c2909c51Schristos 		case PCMCIA_TPCE_FS_MEMSPACE_LENGTHADDR:
1345c66b8643Sthorpej 			cfe->num_memspace = 1;
1346c66b8643Sthorpej 			cfe->memspace[0].length = 256 *
1347c66b8643Sthorpej 			    pcmcia_tuple_read_2(tuple, idx);
1348c66b8643Sthorpej 			idx += 2;
1349c66b8643Sthorpej 			cfe->memspace[0].cardaddr = 256 *
1350c66b8643Sthorpej 			    pcmcia_tuple_read_2(tuple, idx);
1351c66b8643Sthorpej 			idx += 2;
1352c2909c51Schristos 			cfe->memspace[0].hostaddr =
1353c2909c51Schristos 			    cfe->memspace[0].cardaddr;
1354c2909c51Schristos 			break;
1355c2909c51Schristos 
1356c2909c51Schristos 		default:
1357c66b8643Sthorpej 			reg = pcmcia_tuple_read_1(tuple, idx);
1358c66b8643Sthorpej 			idx++;
1359c66b8643Sthorpej 
1360c2909c51Schristos 			cfe->num_memspace = (reg & PCMCIA_TPCE_MS_COUNT)
1361c2909c51Schristos 			    + 1;
1362c66b8643Sthorpej 
1363c66b8643Sthorpej 			if (cfe->num_memspace >
1364c66b8643Sthorpej 			    (sizeof(cfe->memspace) /
1365c66b8643Sthorpej 				sizeof(cfe->memspace[0]))) {
1366c2909c51Schristos 				DPRINTF(("too many mem spaces %d",
1367c66b8643Sthorpej 				    cfe->num_memspace));
1368c66b8643Sthorpej 				state->card->error++;
1369c2909c51Schristos 				return;
1370c66b8643Sthorpej 			}
1371c66b8643Sthorpej 			lengthsize =
1372c66b8643Sthorpej 			    ((reg & PCMCIA_TPCE_MS_LENGTH_SIZE_MASK) >>
1373c66b8643Sthorpej 				PCMCIA_TPCE_MS_LENGTH_SIZE_SHIFT);
1374c66b8643Sthorpej 			cardaddrsize =
1375c2909c51Schristos 			    ((reg &
1376c2909c51Schristos 				PCMCIA_TPCE_MS_CARDADDR_SIZE_MASK) >>
1377c66b8643Sthorpej 				  PCMCIA_TPCE_MS_CARDADDR_SIZE_SHIFT);
1378c66b8643Sthorpej 			hostaddrsize =
1379c2909c51Schristos 			    (reg & PCMCIA_TPCE_MS_HOSTADDR) ?
1380c2909c51Schristos 			    cardaddrsize : 0;
1381c66b8643Sthorpej 
1382c66b8643Sthorpej 			if (lengthsize == 0) {
1383c66b8643Sthorpej 				DPRINTF(("cfe memspace "
1384c66b8643Sthorpej 				    "lengthsize == 0"));
1385c66b8643Sthorpej 				state->card->error++;
1386c66b8643Sthorpej 			}
1387c66b8643Sthorpej 			for (i = 0; i < cfe->num_memspace; i++) {
1388c66b8643Sthorpej 				if (lengthsize) {
1389c2909c51Schristos 					cfe->memspace[i].length = 256 *
1390c2909c51Schristos 					    pcmcia_tuple_read_n(tuple,
1391c2909c51Schristos 						lengthsize, idx);
1392c66b8643Sthorpej 					idx += lengthsize;
1393c66b8643Sthorpej 				} else {
1394c66b8643Sthorpej 					cfe->memspace[i].length = 0;
1395c66b8643Sthorpej 				}
1396c66b8643Sthorpej 				if (cfe->memspace[i].length == 0) {
1397c2909c51Schristos 					DPRINTF(("cfe->memspace"
1398c2909c51Schristos 					    "[%d].length == 0", i));
1399c66b8643Sthorpej 					state->card->error++;
1400c66b8643Sthorpej 				}
1401c66b8643Sthorpej 				if (cardaddrsize) {
1402c66b8643Sthorpej 					cfe->memspace[i].cardaddr =
1403c2909c51Schristos 					    256 *
1404c2909c51Schristos 					    pcmcia_tuple_read_n(tuple,
1405c2909c51Schristos 						cardaddrsize, idx);
1406c66b8643Sthorpej 					idx += cardaddrsize;
1407c66b8643Sthorpej 				} else {
1408c66b8643Sthorpej 					cfe->memspace[i].cardaddr = 0;
1409c66b8643Sthorpej 				}
1410c66b8643Sthorpej 				if (hostaddrsize) {
1411c66b8643Sthorpej 					cfe->memspace[i].hostaddr =
1412c2909c51Schristos 					    256 *
1413c2909c51Schristos 					    pcmcia_tuple_read_n(tuple,
1414c2909c51Schristos 						hostaddrsize, idx);
1415c66b8643Sthorpej 					idx += hostaddrsize;
1416c66b8643Sthorpej 				} else {
1417c66b8643Sthorpej 					cfe->memspace[i].hostaddr = 0;
1418c66b8643Sthorpej 				}
1419c66b8643Sthorpej 			}
1420c66b8643Sthorpej 		}
14212fdcddedSrpaulo 	}
1422c2909c51Schristos 
1423c66b8643Sthorpej 	if (misc) {
14249ada0bf4Smarc 		if (tuple->length <= idx) {
14259ada0bf4Smarc 			DPRINTF(("ran out of space before TCPE_MI\n"));
14269ada0bf4Smarc 			goto abort_cfe;
14279ada0bf4Smarc 		}
14289ada0bf4Smarc 
1429c66b8643Sthorpej 		reg = pcmcia_tuple_read_1(tuple, idx);
1430c66b8643Sthorpej 		idx++;
1431c66b8643Sthorpej 
1432b5064330Schopps 		cfe->flags &= ~(PCMCIA_CFE_POWERDOWN
1433b5064330Schopps 		    | PCMCIA_CFE_READONLY
1434b5064330Schopps 		    | PCMCIA_CFE_AUDIO);
1435c66b8643Sthorpej 		if (reg & PCMCIA_TPCE_MI_PWRDOWN)
1436b7868a43Senami 			cfe->flags |= PCMCIA_CFE_POWERDOWN;
1437c66b8643Sthorpej 		if (reg & PCMCIA_TPCE_MI_READONLY)
1438b7868a43Senami 			cfe->flags |= PCMCIA_CFE_READONLY;
1439c66b8643Sthorpej 		if (reg & PCMCIA_TPCE_MI_AUDIO)
1440b7868a43Senami 			cfe->flags |= PCMCIA_CFE_AUDIO;
1441c66b8643Sthorpej 		cfe->maxtwins = reg & PCMCIA_TPCE_MI_MAXTWINS;
1442c66b8643Sthorpej 
1443c66b8643Sthorpej 		while (reg & PCMCIA_TPCE_MI_EXT) {
1444c66b8643Sthorpej 			reg = pcmcia_tuple_read_1(tuple, idx);
1445c66b8643Sthorpej 			idx++;
1446c66b8643Sthorpej 		}
1447c66b8643Sthorpej 	}
14489ada0bf4Smarc 
1449c2909c51Schristos 	/* skip all the subtuples */
14509ada0bf4Smarc abort_cfe:
1451c66b8643Sthorpej 	DPRINTF(("CISTPL_CFTABLE_ENTRY\n"));
14528130f0ecShaya }
1453