1666d2603SJoerg Sonnenberger /* $NetBSD: pcmcia_cis_quirks.c,v 1.6 2000/04/12 21:07:55 scw Exp $ */
23aef8050SSepherosa Ziehau /* $FreeBSD: src/sys/dev/pccard/pccard_cis_quirks.c,v 1.15 2005/03/26 21:30:49 sam Exp $ */
3666d2603SJoerg Sonnenberger
4666d2603SJoerg Sonnenberger #define PCCARDDEBUG
5666d2603SJoerg Sonnenberger
63aef8050SSepherosa Ziehau /*-
7666d2603SJoerg Sonnenberger * Copyright (c) 1998 Marc Horowitz. All rights reserved.
8666d2603SJoerg Sonnenberger *
9666d2603SJoerg Sonnenberger * Redistribution and use in source and binary forms, with or without
10666d2603SJoerg Sonnenberger * modification, are permitted provided that the following conditions
11666d2603SJoerg Sonnenberger * are met:
12666d2603SJoerg Sonnenberger * 1. Redistributions of source code must retain the above copyright
13666d2603SJoerg Sonnenberger * notice, this list of conditions and the following disclaimer.
14666d2603SJoerg Sonnenberger * 2. Redistributions in binary form must reproduce the above copyright
15666d2603SJoerg Sonnenberger * notice, this list of conditions and the following disclaimer in the
16666d2603SJoerg Sonnenberger * documentation and/or other materials provided with the distribution.
17666d2603SJoerg Sonnenberger * 3. All advertising materials mentioning features or use of this software
18666d2603SJoerg Sonnenberger * must display the following acknowledgement:
19666d2603SJoerg Sonnenberger * This product includes software developed by Marc Horowitz.
20666d2603SJoerg Sonnenberger * 4. The name of the author may not be used to endorse or promote products
21666d2603SJoerg Sonnenberger * derived from this software without specific prior written permission.
22666d2603SJoerg Sonnenberger *
23666d2603SJoerg Sonnenberger * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24666d2603SJoerg Sonnenberger * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25666d2603SJoerg Sonnenberger * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26666d2603SJoerg Sonnenberger * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27666d2603SJoerg Sonnenberger * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28666d2603SJoerg Sonnenberger * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29666d2603SJoerg Sonnenberger * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30666d2603SJoerg Sonnenberger * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31666d2603SJoerg Sonnenberger * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32666d2603SJoerg Sonnenberger * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33666d2603SJoerg Sonnenberger */
34666d2603SJoerg Sonnenberger
35666d2603SJoerg Sonnenberger #include <sys/param.h>
36666d2603SJoerg Sonnenberger #include <sys/bus.h>
373aef8050SSepherosa Ziehau #include <sys/malloc.h>
383aef8050SSepherosa Ziehau #include <sys/systm.h>
39666d2603SJoerg Sonnenberger
403aef8050SSepherosa Ziehau #include <bus/pccard/pccard_cis.h>
41666d2603SJoerg Sonnenberger #include <bus/pccard/pccardvar.h>
42*dcb4b80dSSascha Wildner
43*dcb4b80dSSascha Wildner #include "pccarddevs.h"
44666d2603SJoerg Sonnenberger
45666d2603SJoerg Sonnenberger /* There are cards out there whose CIS flat-out lies. This file
46666d2603SJoerg Sonnenberger contains struct pccard_function chains for those devices. */
47666d2603SJoerg Sonnenberger
48666d2603SJoerg Sonnenberger /* these structures are just static templates which are then copied
49666d2603SJoerg Sonnenberger into "live" allocated structures */
50666d2603SJoerg Sonnenberger
51666d2603SJoerg Sonnenberger struct pccard_function pccard_3cxem556_func0 = {
52666d2603SJoerg Sonnenberger 0, /* function number */
53666d2603SJoerg Sonnenberger PCCARD_FUNCTION_NETWORK,
54666d2603SJoerg Sonnenberger 0x07, /* last cfe number */
55666d2603SJoerg Sonnenberger 0x800, /* ccr_base */
56666d2603SJoerg Sonnenberger 0x63, /* ccr_mask */
57666d2603SJoerg Sonnenberger };
58666d2603SJoerg Sonnenberger
59666d2603SJoerg Sonnenberger struct pccard_config_entry pccard_3cxem556_func0_cfe0 = {
60666d2603SJoerg Sonnenberger 0x07, /* cfe number */
61666d2603SJoerg Sonnenberger PCCARD_CFE_IO8 | PCCARD_CFE_IO16 | PCCARD_CFE_IRQLEVEL,
62666d2603SJoerg Sonnenberger PCCARD_IFTYPE_IO,
63666d2603SJoerg Sonnenberger 1, /* num_iospace */
64666d2603SJoerg Sonnenberger 4, /* iomask */
65666d2603SJoerg Sonnenberger { { 0x0010, 0 } }, /* iospace */
66666d2603SJoerg Sonnenberger 0xffff, /* irqmask */
67666d2603SJoerg Sonnenberger 0, /* num_memspace */
68666d2603SJoerg Sonnenberger { }, /* memspace */
69666d2603SJoerg Sonnenberger 0, /* maxtwins */
70666d2603SJoerg Sonnenberger };
71666d2603SJoerg Sonnenberger
72666d2603SJoerg Sonnenberger static struct pccard_function pccard_3cxem556_func1 = {
73666d2603SJoerg Sonnenberger 1, /* function number */
74666d2603SJoerg Sonnenberger PCCARD_FUNCTION_SERIAL,
75666d2603SJoerg Sonnenberger 0x27, /* last cfe number */
76666d2603SJoerg Sonnenberger 0x900, /* ccr_base */
77666d2603SJoerg Sonnenberger 0x63, /* ccr_mask */
78666d2603SJoerg Sonnenberger };
79666d2603SJoerg Sonnenberger
80666d2603SJoerg Sonnenberger static struct pccard_config_entry pccard_3cxem556_func1_cfe0 = {
81666d2603SJoerg Sonnenberger 0x27, /* cfe number */
82666d2603SJoerg Sonnenberger PCCARD_CFE_IO8 | PCCARD_CFE_IRQLEVEL,
83666d2603SJoerg Sonnenberger PCCARD_IFTYPE_IO,
84666d2603SJoerg Sonnenberger 1, /* num_iospace */
85666d2603SJoerg Sonnenberger 3, /* iomask */
86666d2603SJoerg Sonnenberger { { 0x0008, 0 } }, /* iospace */
87666d2603SJoerg Sonnenberger 0xffff, /* irqmask */
88666d2603SJoerg Sonnenberger 0, /* num_memspace */
89666d2603SJoerg Sonnenberger { }, /* memspace */
90666d2603SJoerg Sonnenberger 0, /* maxtwins */
91666d2603SJoerg Sonnenberger };
92666d2603SJoerg Sonnenberger
93666d2603SJoerg Sonnenberger static struct pccard_function pccard_3ccfem556bi_func0 = {
94666d2603SJoerg Sonnenberger 0, /* function number */
95666d2603SJoerg Sonnenberger PCCARD_FUNCTION_NETWORK,
96666d2603SJoerg Sonnenberger 0x07, /* last cfe number */
97666d2603SJoerg Sonnenberger 0x1000, /* ccr_base */
98666d2603SJoerg Sonnenberger 0x267, /* ccr_mask */
99666d2603SJoerg Sonnenberger };
100666d2603SJoerg Sonnenberger
101666d2603SJoerg Sonnenberger static struct pccard_config_entry pccard_3ccfem556bi_func0_cfe0 = {
102666d2603SJoerg Sonnenberger 0x07, /* cfe number */
103666d2603SJoerg Sonnenberger PCCARD_CFE_IO8 | PCCARD_CFE_IO16 | PCCARD_CFE_IRQLEVEL,
104666d2603SJoerg Sonnenberger PCCARD_IFTYPE_IO,
105666d2603SJoerg Sonnenberger 1, /* num_iospace */
106666d2603SJoerg Sonnenberger 5, /* iomask */
107666d2603SJoerg Sonnenberger { { 0x0020, 0 } }, /* iospace */
108666d2603SJoerg Sonnenberger 0xffff, /* irqmask */
109666d2603SJoerg Sonnenberger 0, /* num_memspace */
110666d2603SJoerg Sonnenberger { }, /* memspace */
111666d2603SJoerg Sonnenberger 0, /* maxtwins */
112666d2603SJoerg Sonnenberger };
113666d2603SJoerg Sonnenberger
114666d2603SJoerg Sonnenberger static struct pccard_function pccard_3ccfem556bi_func1 = {
115666d2603SJoerg Sonnenberger 1, /* function number */
116666d2603SJoerg Sonnenberger PCCARD_FUNCTION_SERIAL,
117666d2603SJoerg Sonnenberger 0x27, /* last cfe number */
118666d2603SJoerg Sonnenberger 0x1100, /* ccr_base */
119666d2603SJoerg Sonnenberger 0x277, /* ccr_mask */
120666d2603SJoerg Sonnenberger };
121666d2603SJoerg Sonnenberger
122666d2603SJoerg Sonnenberger static struct pccard_config_entry pccard_3ccfem556bi_func1_cfe0 = {
123666d2603SJoerg Sonnenberger 0x27, /* cfe number */
124666d2603SJoerg Sonnenberger PCCARD_CFE_IO8 | PCCARD_CFE_IRQLEVEL,
125666d2603SJoerg Sonnenberger PCCARD_IFTYPE_IO,
126666d2603SJoerg Sonnenberger 1, /* num_iospace */
127666d2603SJoerg Sonnenberger 3, /* iomask */
128666d2603SJoerg Sonnenberger { { 0x0008, 0 } }, /* iospace */
129666d2603SJoerg Sonnenberger 0xffff, /* irqmask */
130666d2603SJoerg Sonnenberger 0, /* num_memspace */
131666d2603SJoerg Sonnenberger { }, /* memspace */
132666d2603SJoerg Sonnenberger 0, /* maxtwins */
133666d2603SJoerg Sonnenberger };
134666d2603SJoerg Sonnenberger
135666d2603SJoerg Sonnenberger static struct pccard_function pccard_sveclancard_func0 = {
136666d2603SJoerg Sonnenberger 0, /* function number */
137666d2603SJoerg Sonnenberger PCCARD_FUNCTION_NETWORK,
138666d2603SJoerg Sonnenberger 0x1, /* last cfe number */
139666d2603SJoerg Sonnenberger 0x100, /* ccr_base */
140666d2603SJoerg Sonnenberger 0x1, /* ccr_mask */
141666d2603SJoerg Sonnenberger };
142666d2603SJoerg Sonnenberger
143666d2603SJoerg Sonnenberger static struct pccard_config_entry pccard_sveclancard_func0_cfe0 = {
144666d2603SJoerg Sonnenberger 0x1, /* cfe number */
145666d2603SJoerg Sonnenberger PCCARD_CFE_MWAIT_REQUIRED | PCCARD_CFE_RDYBSY_ACTIVE |
146666d2603SJoerg Sonnenberger PCCARD_CFE_WP_ACTIVE | PCCARD_CFE_BVD_ACTIVE | PCCARD_CFE_IO16,
147666d2603SJoerg Sonnenberger PCCARD_IFTYPE_IO,
148666d2603SJoerg Sonnenberger 1, /* num_iospace */
149666d2603SJoerg Sonnenberger 5, /* iomask */
150666d2603SJoerg Sonnenberger { { 0x20, 0x300 } }, /* iospace */
151666d2603SJoerg Sonnenberger 0xdeb8, /* irqmask */
152666d2603SJoerg Sonnenberger 0, /* num_memspace */
153666d2603SJoerg Sonnenberger { }, /* memspace */
154666d2603SJoerg Sonnenberger 0, /* maxtwins */
155666d2603SJoerg Sonnenberger };
156666d2603SJoerg Sonnenberger
157666d2603SJoerg Sonnenberger static struct pccard_function pccard_ndc_nd5100_func0 = {
158666d2603SJoerg Sonnenberger 0, /* function number */
159666d2603SJoerg Sonnenberger PCCARD_FUNCTION_NETWORK,
160666d2603SJoerg Sonnenberger 0x23, /* last cfe number */
161666d2603SJoerg Sonnenberger 0x3f8, /* ccr_base */
162666d2603SJoerg Sonnenberger 0x3, /* ccr_mask */
163666d2603SJoerg Sonnenberger };
164666d2603SJoerg Sonnenberger
165666d2603SJoerg Sonnenberger static struct pccard_config_entry pccard_ndc_nd5100_func0_cfe0 = {
166666d2603SJoerg Sonnenberger 0x20, /* cfe number */
167666d2603SJoerg Sonnenberger PCCARD_CFE_MWAIT_REQUIRED | PCCARD_CFE_IO16 | PCCARD_CFE_IRQLEVEL,
168666d2603SJoerg Sonnenberger PCCARD_IFTYPE_IO,
169666d2603SJoerg Sonnenberger 1, /* num_iospace */
170666d2603SJoerg Sonnenberger 5, /* iomask */
171666d2603SJoerg Sonnenberger { { 0x20, 0x300 } }, /* iospace */
172666d2603SJoerg Sonnenberger 0xdeb8, /* irqmask */
173666d2603SJoerg Sonnenberger 0, /* num_memspace */
174666d2603SJoerg Sonnenberger { }, /* memspace */
175666d2603SJoerg Sonnenberger 0, /* maxtwins */
176666d2603SJoerg Sonnenberger };
177666d2603SJoerg Sonnenberger
178666d2603SJoerg Sonnenberger static struct pccard_cis_quirk pccard_cis_quirks[] = {
179666d2603SJoerg Sonnenberger { PCMCIA_VENDOR_3COM, PCMCIA_PRODUCT_3COM_3CXEM556, PCMCIA_CIS_INVALID,
180666d2603SJoerg Sonnenberger &pccard_3cxem556_func0, &pccard_3cxem556_func0_cfe0 },
181666d2603SJoerg Sonnenberger { PCMCIA_VENDOR_3COM, PCMCIA_PRODUCT_3COM_3CXEM556, PCMCIA_CIS_INVALID,
182666d2603SJoerg Sonnenberger &pccard_3cxem556_func1, &pccard_3cxem556_func1_cfe0 },
183666d2603SJoerg Sonnenberger { PCMCIA_VENDOR_3COM, PCMCIA_PRODUCT_3COM_3CXEM556INT, PCMCIA_CIS_INVALID,
184666d2603SJoerg Sonnenberger &pccard_3cxem556_func0, &pccard_3cxem556_func0_cfe0 },
185666d2603SJoerg Sonnenberger { PCMCIA_VENDOR_3COM, PCMCIA_PRODUCT_3COM_3CXEM556INT, PCMCIA_CIS_INVALID,
186666d2603SJoerg Sonnenberger &pccard_3cxem556_func1, &pccard_3cxem556_func1_cfe0 },
187666d2603SJoerg Sonnenberger { PCMCIA_VENDOR_3COM, PCMCIA_PRODUCT_3COM_3CCFEM556BI,
188666d2603SJoerg Sonnenberger PCMCIA_CIS_INVALID,
189666d2603SJoerg Sonnenberger &pccard_3ccfem556bi_func0, &pccard_3ccfem556bi_func0_cfe0 },
190666d2603SJoerg Sonnenberger { PCMCIA_VENDOR_3COM, PCMCIA_PRODUCT_3COM_3CCFEM556BI,
191666d2603SJoerg Sonnenberger PCMCIA_CIS_INVALID,
192666d2603SJoerg Sonnenberger &pccard_3ccfem556bi_func1, &pccard_3ccfem556bi_func1_cfe0 },
193666d2603SJoerg Sonnenberger { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID, PCMCIA_CIS_SVEC_LANCARD,
194666d2603SJoerg Sonnenberger &pccard_sveclancard_func0, &pccard_sveclancard_func0_cfe0 },
195666d2603SJoerg Sonnenberger { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID, PCMCIA_CIS_NDC_ND5100_E,
196666d2603SJoerg Sonnenberger &pccard_ndc_nd5100_func0, &pccard_ndc_nd5100_func0_cfe0 },
197666d2603SJoerg Sonnenberger };
198666d2603SJoerg Sonnenberger
199c157ff7aSSascha Wildner static int n_pccard_cis_quirks = NELEM(pccard_cis_quirks);
200666d2603SJoerg Sonnenberger
2013aef8050SSepherosa Ziehau static int
pccard_cis_quirk_match(struct pccard_softc * sc,struct pccard_cis_quirk * q)2023aef8050SSepherosa Ziehau pccard_cis_quirk_match(struct pccard_softc *sc, struct pccard_cis_quirk *q)
2033aef8050SSepherosa Ziehau {
2043aef8050SSepherosa Ziehau if ((sc->card.manufacturer == q->manufacturer) &&
2053aef8050SSepherosa Ziehau (sc->card.product == q->product) &&
2063aef8050SSepherosa Ziehau (((sc->card.manufacturer != PCMCIA_VENDOR_INVALID) &&
2073aef8050SSepherosa Ziehau (sc->card.product != PCMCIA_PRODUCT_INVALID)) ||
2083aef8050SSepherosa Ziehau ((sc->card.manufacturer == PCMCIA_VENDOR_INVALID) &&
2093aef8050SSepherosa Ziehau (sc->card.product == PCMCIA_PRODUCT_INVALID) &&
2103aef8050SSepherosa Ziehau sc->card.cis1_info[0] &&
2113aef8050SSepherosa Ziehau (strcmp(sc->card.cis1_info[0], q->cis1_info[0]) == 0) &&
2123aef8050SSepherosa Ziehau sc->card.cis1_info[1] &&
2133aef8050SSepherosa Ziehau (strcmp(sc->card.cis1_info[1], q->cis1_info[1]) == 0))))
2143aef8050SSepherosa Ziehau return (1);
2153aef8050SSepherosa Ziehau return (0);
2163aef8050SSepherosa Ziehau }
2173aef8050SSepherosa Ziehau
2180e224b5dSSascha Wildner void
pccard_check_cis_quirks(device_t dev)2190e224b5dSSascha Wildner pccard_check_cis_quirks(device_t dev)
220666d2603SJoerg Sonnenberger {
221666d2603SJoerg Sonnenberger struct pccard_softc *sc = PCCARD_SOFTC(dev);
222666d2603SJoerg Sonnenberger int wiped = 0;
223666d2603SJoerg Sonnenberger int i, j;
224666d2603SJoerg Sonnenberger struct pccard_function *pf, *pf_next, *pf_last;
225666d2603SJoerg Sonnenberger struct pccard_config_entry *cfe, *cfe_next;
2263aef8050SSepherosa Ziehau struct pccard_cis_quirk *q;
227666d2603SJoerg Sonnenberger
228666d2603SJoerg Sonnenberger pf = NULL;
229666d2603SJoerg Sonnenberger pf_last = NULL;
230666d2603SJoerg Sonnenberger
231666d2603SJoerg Sonnenberger for (i=0; i<n_pccard_cis_quirks; i++) {
2323aef8050SSepherosa Ziehau q = &pccard_cis_quirks[i];
2333aef8050SSepherosa Ziehau if (!pccard_cis_quirk_match(sc, q))
2343aef8050SSepherosa Ziehau continue;
235666d2603SJoerg Sonnenberger if (!wiped) {
236666d2603SJoerg Sonnenberger if (bootverbose) {
237666d2603SJoerg Sonnenberger device_printf(dev, "using CIS quirks for ");
238666d2603SJoerg Sonnenberger for (j = 0; j < 4; j++) {
239666d2603SJoerg Sonnenberger if (sc->card.cis1_info[j] == NULL)
240666d2603SJoerg Sonnenberger break;
241666d2603SJoerg Sonnenberger if (j)
24285f8e2eaSSascha Wildner kprintf(", ");
24385f8e2eaSSascha Wildner kprintf("%s", sc->card.cis1_info[j]);
244666d2603SJoerg Sonnenberger }
24585f8e2eaSSascha Wildner kprintf("\n");
246666d2603SJoerg Sonnenberger }
247666d2603SJoerg Sonnenberger
248666d2603SJoerg Sonnenberger for (pf = STAILQ_FIRST(&sc->card.pf_head); pf != NULL;
249666d2603SJoerg Sonnenberger pf = pf_next) {
250666d2603SJoerg Sonnenberger for (cfe = STAILQ_FIRST(&pf->cfe_head); cfe != NULL;
251666d2603SJoerg Sonnenberger cfe = cfe_next) {
252666d2603SJoerg Sonnenberger cfe_next = STAILQ_NEXT(cfe, cfe_list);
253efda3bd0SMatthew Dillon kfree(cfe, M_DEVBUF);
254666d2603SJoerg Sonnenberger }
255666d2603SJoerg Sonnenberger pf_next = STAILQ_NEXT(pf, pf_list);
256efda3bd0SMatthew Dillon kfree(pf, M_DEVBUF);
257666d2603SJoerg Sonnenberger }
258666d2603SJoerg Sonnenberger
259666d2603SJoerg Sonnenberger STAILQ_INIT(&sc->card.pf_head);
260666d2603SJoerg Sonnenberger wiped = 1;
261666d2603SJoerg Sonnenberger }
262666d2603SJoerg Sonnenberger
2633aef8050SSepherosa Ziehau if (pf_last == q->pf) {
2643aef8050SSepherosa Ziehau cfe = kmalloc(sizeof(*cfe), M_DEVBUF, M_NOWAIT);
2653aef8050SSepherosa Ziehau if (cfe == NULL) {
2663aef8050SSepherosa Ziehau device_printf(dev, "no memory for quirk (1)\n");
2673aef8050SSepherosa Ziehau continue;
2683aef8050SSepherosa Ziehau }
2693aef8050SSepherosa Ziehau *cfe = *q->cfe;
270666d2603SJoerg Sonnenberger STAILQ_INSERT_TAIL(&pf->cfe_head, cfe, cfe_list);
271666d2603SJoerg Sonnenberger } else {
2723aef8050SSepherosa Ziehau pf = kmalloc(sizeof(*pf), M_DEVBUF, M_NOWAIT);
2733aef8050SSepherosa Ziehau if (pf == NULL) {
2743aef8050SSepherosa Ziehau device_printf(dev,
2753aef8050SSepherosa Ziehau "no memory for pccard function\n");
2763aef8050SSepherosa Ziehau continue;
2773aef8050SSepherosa Ziehau }
2783aef8050SSepherosa Ziehau *pf = *q->pf;
279666d2603SJoerg Sonnenberger STAILQ_INIT(&pf->cfe_head);
2803aef8050SSepherosa Ziehau cfe = kmalloc(sizeof(*cfe), M_DEVBUF, M_NOWAIT);
2813aef8050SSepherosa Ziehau if (cfe == NULL) {
2823aef8050SSepherosa Ziehau kfree(pf, M_DEVBUF);
2833aef8050SSepherosa Ziehau device_printf(dev, "no memory for quirk (2)\n");
2843aef8050SSepherosa Ziehau continue;
2853aef8050SSepherosa Ziehau }
2863aef8050SSepherosa Ziehau *cfe = *q->cfe;
287666d2603SJoerg Sonnenberger STAILQ_INSERT_TAIL(&pf->cfe_head, cfe, cfe_list);
288666d2603SJoerg Sonnenberger STAILQ_INSERT_TAIL(&sc->card.pf_head, pf, pf_list);
2893aef8050SSepherosa Ziehau pf_last = q->pf;
290666d2603SJoerg Sonnenberger }
291666d2603SJoerg Sonnenberger }
292666d2603SJoerg Sonnenberger }
293