165483Simp/*	$NetBSD: pcmcia_cis_quirks.c,v 1.6 2000/04/12 21:07:55 scw Exp $ */
252506Simp
3119418Sobrien#include <sys/cdefs.h>
4119418Sobrien__FBSDID("$FreeBSD$");
5119418Sobrien
652506Simp#define	PCCARDDEBUG
752506Simp
8139749Simp/*-
952506Simp * Copyright (c) 1998 Marc Horowitz.  All rights reserved.
1052506Simp *
1152506Simp * Redistribution and use in source and binary forms, with or without
1252506Simp * modification, are permitted provided that the following conditions
1352506Simp * are met:
1452506Simp * 1. Redistributions of source code must retain the above copyright
1552506Simp *    notice, this list of conditions and the following disclaimer.
1652506Simp * 2. Redistributions in binary form must reproduce the above copyright
1752506Simp *    notice, this list of conditions and the following disclaimer in the
1852506Simp *    documentation and/or other materials provided with the distribution.
1952506Simp * 3. All advertising materials mentioning features or use of this software
2052506Simp *    must display the following acknowledgement:
2152506Simp *	This product includes software developed by Marc Horowitz.
2252506Simp * 4. The name of the author may not be used to endorse or promote products
2352506Simp *    derived from this software without specific prior written permission.
2452506Simp *
2552506Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2652506Simp * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2752506Simp * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2852506Simp * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2952506Simp * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
3052506Simp * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3152506Simp * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3252506Simp * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3352506Simp * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
3452506Simp * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3552506Simp */
3652506Simp
3752506Simp#include <sys/param.h>
38129762Simp#include <sys/bus.h>
39129781Simp#include <sys/malloc.h>
4052506Simp#include <sys/systm.h>
4152506Simp
4252506Simp#include <machine/bus.h>
4352506Simp
44129762Simp#include <dev/pccard/pccard_cis.h>
45129762Simp#include <dev/pccard/pccardvar.h>
46150371Sglebius#include <dev/pccard/pccardvarp.h>
47129781Simp
48129740Simp#include "pccarddevs.h"
4952506Simp
5052506Simp/* There are cards out there whose CIS flat-out lies.  This file
5152506Simp   contains struct pccard_function chains for those devices. */
5252506Simp
5352506Simp/* these structures are just static templates which are then copied
5452506Simp   into "live" allocated structures */
5552506Simp
5652506Simpstruct pccard_function pccard_3cxem556_func0 = {
5752506Simp	0,			/* function number */
5852506Simp	PCCARD_FUNCTION_NETWORK,
5952506Simp	0x07,			/* last cfe number */
6052506Simp	0x800,			/* ccr_base */
6152506Simp	0x63,			/* ccr_mask */
6252506Simp};
6352506Simp
6452506Simpstruct pccard_config_entry pccard_3cxem556_func0_cfe0 = {
6552506Simp	0x07,			/* cfe number */
6652506Simp	PCCARD_CFE_IO8 | PCCARD_CFE_IO16 | PCCARD_CFE_IRQLEVEL,
6752506Simp	PCCARD_IFTYPE_IO,
6852506Simp	1,			/* num_iospace */
6952506Simp	4,			/* iomask */
7052506Simp	{ { 0x0010, 0 } },	/* iospace */
7152506Simp	0xffff,			/* irqmask */
7252506Simp	0,			/* num_memspace */
7352506Simp	{ },			/* memspace */
7452506Simp	0,			/* maxtwins */
7552506Simp};
7652506Simp
7752506Simpstatic struct pccard_function pccard_3cxem556_func1 = {
7852506Simp	1,			/* function number */
7952506Simp	PCCARD_FUNCTION_SERIAL,
8052506Simp	0x27,			/* last cfe number */
8152506Simp	0x900,			/* ccr_base */
8252506Simp	0x63,			/* ccr_mask */
8352506Simp};
8452506Simp
8552506Simpstatic struct pccard_config_entry pccard_3cxem556_func1_cfe0 = {
8652506Simp	0x27,			/* cfe number */
8752506Simp	PCCARD_CFE_IO8 | PCCARD_CFE_IRQLEVEL,
8852506Simp	PCCARD_IFTYPE_IO,
8952506Simp	1,			/* num_iospace */
9052506Simp	3,			/* iomask */
9152506Simp	{ { 0x0008, 0 } },	/* iospace */
9252506Simp	0xffff,			/* irqmask */
9352506Simp	0,			/* num_memspace */
9452506Simp	{ },			/* memspace */
9552506Simp	0,			/* maxtwins */
9652506Simp};
9752506Simp
9853813Simpstatic struct pccard_function pccard_3ccfem556bi_func0 = {
9953813Simp	0,			/* function number */
10053813Simp	PCCARD_FUNCTION_NETWORK,
10153813Simp	0x07,			/* last cfe number */
10253813Simp	0x1000,			/* ccr_base */
10353813Simp	0x267,			/* ccr_mask */
10453813Simp};
10553813Simp
10653813Simpstatic struct pccard_config_entry pccard_3ccfem556bi_func0_cfe0 = {
10753813Simp	0x07,			/* cfe number */
10853813Simp	PCCARD_CFE_IO8 | PCCARD_CFE_IO16 | PCCARD_CFE_IRQLEVEL,
10953813Simp	PCCARD_IFTYPE_IO,
11053813Simp	1,			/* num_iospace */
11153813Simp	5,			/* iomask */
11253813Simp	{ { 0x0020, 0 } },	/* iospace */
11353813Simp	0xffff,			/* irqmask */
11453813Simp	0,			/* num_memspace */
11553813Simp	{ },			/* memspace */
11653813Simp	0,			/* maxtwins */
11753813Simp};
11853813Simp
11953813Simpstatic struct pccard_function pccard_3ccfem556bi_func1 = {
12053813Simp	1,			/* function number */
12153813Simp	PCCARD_FUNCTION_SERIAL,
12253813Simp	0x27,			/* last cfe number */
12353813Simp	0x1100,			/* ccr_base */
12453813Simp	0x277,			/* ccr_mask */
12553813Simp};
12653813Simp
12753813Simpstatic struct pccard_config_entry pccard_3ccfem556bi_func1_cfe0 = {
12853813Simp	0x27,			/* cfe number */
12953813Simp	PCCARD_CFE_IO8 | PCCARD_CFE_IRQLEVEL,
13053813Simp	PCCARD_IFTYPE_IO,
13153813Simp	1,			/* num_iospace */
13253813Simp	3,			/* iomask */
13353813Simp	{ { 0x0008, 0 } },	/* iospace */
13453813Simp	0xffff,			/* irqmask */
13553813Simp	0,			/* num_memspace */
13653813Simp	{ },			/* memspace */
13753813Simp	0,			/* maxtwins */
13853813Simp};
13953813Simp
140182142Simpstatic struct pccard_function pccard_3c1_func0 = {
141182142Simp	0,			/* function number */
142182142Simp	PCCARD_FUNCTION_NETWORK,
143182142Simp	0x05,			/* last cfe number */
144182142Simp	0x400,			/* ccr_base */
145182142Simp	0x267,			/* ccr_mask */
146182142Simp};
147182142Simp
148182142Simpstatic struct pccard_config_entry pccard_3c1_func0_cfe0 = {
149182142Simp	0x05,			/* cfe number */
150182142Simp	PCCARD_CFE_IO8 | PCCARD_CFE_IO16 | PCCARD_CFE_IRQLEVEL,
151182142Simp	PCCARD_IFTYPE_IO,
152182142Simp	1,			/* num_iospace */
153182142Simp	5,			/* iomask */
154182142Simp	{ { 0x0010, 0 } },	/* iospace */
155182142Simp	0xffff,			/* irqmask */
156182142Simp	0,			/* num_memspace */
157182142Simp	{ },			/* memspace */
158182142Simp	0,			/* maxtwins */
159182142Simp};
160182142Simp
16152506Simpstatic struct pccard_function pccard_sveclancard_func0 = {
16252506Simp	0,			/* function number */
16352506Simp	PCCARD_FUNCTION_NETWORK,
16452506Simp	0x1,			/* last cfe number */
16552506Simp	0x100,			/* ccr_base */
16652506Simp	0x1,			/* ccr_mask */
16752506Simp};
16852506Simp
16952506Simpstatic struct pccard_config_entry pccard_sveclancard_func0_cfe0 = {
17052506Simp	0x1,			/* cfe number */
17152506Simp	PCCARD_CFE_MWAIT_REQUIRED | PCCARD_CFE_RDYBSY_ACTIVE |
17252506Simp	PCCARD_CFE_WP_ACTIVE | PCCARD_CFE_BVD_ACTIVE | PCCARD_CFE_IO16,
17352506Simp	PCCARD_IFTYPE_IO,
17452506Simp	1,			/* num_iospace */
17552506Simp	5,			/* iomask */
17652506Simp	{ { 0x20, 0x300 } },	/* iospace */
17752506Simp	0xdeb8,			/* irqmask */
17852506Simp	0,			/* num_memspace */
17952506Simp	{ },			/* memspace */
18052506Simp	0,			/* maxtwins */
18152506Simp};
18252506Simp
18365483Simpstatic struct pccard_function pccard_ndc_nd5100_func0 = {
18465483Simp	0,			/* function number */
18565483Simp	PCCARD_FUNCTION_NETWORK,
18665483Simp	0x23,			/* last cfe number */
18765483Simp	0x3f8,			/* ccr_base */
18865483Simp	0x3,			/* ccr_mask */
18965483Simp};
19065483Simp
19165483Simpstatic struct pccard_config_entry pccard_ndc_nd5100_func0_cfe0 = {
19265483Simp	0x20,			/* cfe number */
19365483Simp	PCCARD_CFE_MWAIT_REQUIRED | PCCARD_CFE_IO16 | PCCARD_CFE_IRQLEVEL,
19465483Simp	PCCARD_IFTYPE_IO,
19565483Simp	1,			/* num_iospace */
19665483Simp	5,			/* iomask */
19765483Simp	{ { 0x20, 0x300 } },	/* iospace */
19865483Simp	0xdeb8,			/* irqmask */
19965483Simp	0,			/* num_memspace */
20065483Simp	{ },			/* memspace */
20165483Simp	0,			/* maxtwins */
20265483Simp};
20365483Simp
204172572Sremkostatic struct pccard_function pccard_sierra_a555_func1 = {
205172572Sremko	1,			/* function number */
206172572Sremko	PCCARD_FUNCTION_SERIAL,
207172572Sremko	0x24,			/* last cfe number */
208172572Sremko	0x700,			/* ccr_base */
209172572Sremko	0x73,			/* ccr_mask */
210172572Sremko};
211172572Sremko
212172572Sremkostatic struct pccard_config_entry pccard_sierra_a555_func1_cfe0 = {
213172572Sremko	0x22,			/* cfe number */
214172572Sremko	PCCARD_CFE_IO8 | PCCARD_CFE_IRQLEVEL,
215172572Sremko	PCCARD_IFTYPE_IO,
216172572Sremko	1,			/* num_iospace */
217172572Sremko	0,			/* iomask */
218172572Sremko	{ { 0x0008, 0x3e8 } },	/* iospace */
219172572Sremko	0x3fbc,			/* irqmask */
220172572Sremko	0,			/* num_memspace */
221172572Sremko	{ },			/* memspace */
222172572Sremko	0,			/* maxtwins */
223172572Sremko};
224172572Sremko
22552506Simpstatic struct pccard_cis_quirk pccard_cis_quirks[] = {
22686272Simp	{ PCMCIA_VENDOR_3COM, PCMCIA_PRODUCT_3COM_3CXEM556, PCMCIA_CIS_INVALID,
22752506Simp	  &pccard_3cxem556_func0, &pccard_3cxem556_func0_cfe0 },
22886272Simp	{ PCMCIA_VENDOR_3COM, PCMCIA_PRODUCT_3COM_3CXEM556, PCMCIA_CIS_INVALID,
22952506Simp	  &pccard_3cxem556_func1, &pccard_3cxem556_func1_cfe0 },
23086272Simp	{ PCMCIA_VENDOR_3COM, PCMCIA_PRODUCT_3COM_3CXEM556INT, PCMCIA_CIS_INVALID,
23153813Simp	  &pccard_3cxem556_func0, &pccard_3cxem556_func0_cfe0 },
23286272Simp	{ PCMCIA_VENDOR_3COM, PCMCIA_PRODUCT_3COM_3CXEM556INT, PCMCIA_CIS_INVALID,
23353813Simp	  &pccard_3cxem556_func1, &pccard_3cxem556_func1_cfe0 },
23486272Simp	{ PCMCIA_VENDOR_3COM, PCMCIA_PRODUCT_3COM_3CCFEM556BI,
23586272Simp	  PCMCIA_CIS_INVALID,
23653813Simp	  &pccard_3ccfem556bi_func0, &pccard_3ccfem556bi_func0_cfe0 },
23786272Simp	{ PCMCIA_VENDOR_3COM, PCMCIA_PRODUCT_3COM_3CCFEM556BI,
23886272Simp	  PCMCIA_CIS_INVALID,
23953813Simp	  &pccard_3ccfem556bi_func1, &pccard_3ccfem556bi_func1_cfe0 },
240172572Sremko	{ PCMCIA_VENDOR_SIERRA, PCMCIA_PRODUCT_SIERRA_A550,
241172572Sremko	  PCMCIA_CIS_INVALID,
242172572Sremko	  &pccard_sierra_a555_func1, &pccard_sierra_a555_func1_cfe0 },
243172572Sremko	{ PCMCIA_VENDOR_SIERRA, PCMCIA_PRODUCT_SIERRA_A555,
244172572Sremko	  PCMCIA_CIS_INVALID,
245172572Sremko	  &pccard_sierra_a555_func1, &pccard_sierra_a555_func1_cfe0 },
246172572Sremko	{ PCMCIA_VENDOR_SIERRA, PCMCIA_PRODUCT_SIERRA_A710,
247172572Sremko	  PCMCIA_CIS_INVALID,
248172572Sremko	  &pccard_sierra_a555_func1, &pccard_sierra_a555_func1_cfe0 },
249172572Sremko	{ PCMCIA_VENDOR_SIERRA, PCMCIA_PRODUCT_SIERRA_AC710,
250172572Sremko	  PCMCIA_CIS_INVALID,
251172572Sremko	  &pccard_sierra_a555_func1, &pccard_sierra_a555_func1_cfe0 },
252182142Simp	{ PCMCIA_VENDOR_3COM, PCMCIA_PRODUCT_3COM_3C1, PCMCIA_CIS_INVALID,
253182142Simp	  &pccard_3c1_func0, &pccard_3c1_func0_cfe0 },
25486272Simp	{ PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID, PCMCIA_CIS_SVEC_LANCARD,
25552506Simp	  &pccard_sveclancard_func0, &pccard_sveclancard_func0_cfe0 },
25686272Simp	{ PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID, PCMCIA_CIS_NDC_ND5100_E,
25765483Simp	  &pccard_ndc_nd5100_func0, &pccard_ndc_nd5100_func0_cfe0 },
25852506Simp};
25952506Simp
260120849Simpstatic int
261120849Simppccard_cis_quirk_match(struct pccard_softc *sc, struct pccard_cis_quirk *q)
262120849Simp{
263120849Simp	if ((sc->card.manufacturer == q->manufacturer) &&
264120849Simp		(sc->card.product == q->product) &&
265120849Simp		(((sc->card.manufacturer != PCMCIA_VENDOR_INVALID) &&
266120849Simp		  (sc->card.product != PCMCIA_PRODUCT_INVALID)) ||
267120849Simp		 ((sc->card.manufacturer == PCMCIA_VENDOR_INVALID) &&
268120849Simp		  (sc->card.product == PCMCIA_PRODUCT_INVALID) &&
269120849Simp		  sc->card.cis1_info[0] &&
270120849Simp		  (strcmp(sc->card.cis1_info[0], q->cis1_info[0]) == 0) &&
271120849Simp		  sc->card.cis1_info[1] &&
272120849Simp		  (strcmp(sc->card.cis1_info[1], q->cis1_info[1]) == 0))))
273120849Simp		return (1);
274120849Simp	return (0);
275120849Simp}
276120849Simp
27752506Simpvoid pccard_check_cis_quirks(device_t dev)
27852506Simp{
27964850Simp	struct pccard_softc *sc = PCCARD_SOFTC(dev);
28052506Simp	int wiped = 0;
28152506Simp	int i, j;
28252506Simp	struct pccard_function *pf, *pf_next, *pf_last;
28352506Simp	struct pccard_config_entry *cfe, *cfe_next;
284120849Simp	struct pccard_cis_quirk *q;
28552506Simp
28652506Simp	pf = NULL;
28752506Simp	pf_last = NULL;
28852506Simp
289298411Spfg	for (i = 0; i < nitems(pccard_cis_quirks); i++) {
290120849Simp		q = &pccard_cis_quirks[i];
291120849Simp		if (!pccard_cis_quirk_match(sc, q))
292120849Simp			continue;
293120849Simp		if (!wiped) {
294120849Simp			if (bootverbose) {
295120849Simp				device_printf(dev, "using CIS quirks for ");
296120849Simp				for (j = 0; j < 4; j++) {
297120849Simp					if (sc->card.cis1_info[j] == NULL)
298120849Simp						break;
299120849Simp					if (j)
300120849Simp						printf(", ");
301120849Simp					printf("%s", sc->card.cis1_info[j]);
30252506Simp				}
303120849Simp				printf("\n");
304120849Simp			}
30552506Simp
306120849Simp			for (pf = STAILQ_FIRST(&sc->card.pf_head); pf != NULL;
307120849Simp			     pf = pf_next) {
308120849Simp				for (cfe = STAILQ_FIRST(&pf->cfe_head); cfe != NULL;
309120849Simp				     cfe = cfe_next) {
310120849Simp					cfe_next = STAILQ_NEXT(cfe, cfe_list);
311120849Simp					free(cfe, M_DEVBUF);
31252506Simp				}
313120849Simp				pf_next = STAILQ_NEXT(pf, pf_list);
314120849Simp				free(pf, M_DEVBUF);
31552506Simp			}
31652506Simp
317120849Simp			STAILQ_INIT(&sc->card.pf_head);
318120849Simp			wiped = 1;
319120849Simp		}
32052506Simp
321120849Simp		if (pf_last == q->pf) {
322120849Simp			cfe = malloc(sizeof(*cfe), M_DEVBUF, M_NOWAIT);
323144158Ssam			if (cfe == NULL) {
324144158Ssam				device_printf(dev, "no memory for quirk (1)\n");
325144158Ssam				continue;
326144158Ssam			}
327120849Simp			*cfe = *q->cfe;
328120849Simp			STAILQ_INSERT_TAIL(&pf->cfe_head, cfe, cfe_list);
329120849Simp		} else {
330120849Simp			pf = malloc(sizeof(*pf), M_DEVBUF, M_NOWAIT);
331144158Ssam			if (pf == NULL) {
332144158Ssam				device_printf(dev,
333144158Ssam					"no memory for pccard function\n");
334144158Ssam				continue;
335144158Ssam			}
336120849Simp			*pf = *q->pf;
337120849Simp			STAILQ_INIT(&pf->cfe_head);
338120849Simp			cfe = malloc(sizeof(*cfe), M_DEVBUF, M_NOWAIT);
339144158Ssam			if (cfe == NULL) {
340144158Ssam				free(pf, M_DEVBUF);
341144158Ssam				device_printf(dev, "no memory for quirk (2)\n");
342144158Ssam				continue;
343144158Ssam			}
344120849Simp			*cfe = *q->cfe;
345120849Simp			STAILQ_INSERT_TAIL(&pf->cfe_head, cfe, cfe_list);
346120849Simp			STAILQ_INSERT_TAIL(&sc->card.pf_head, pf, pf_list);
347120849Simp			pf_last = q->pf;
34852506Simp		}
34952506Simp	}
35052506Simp}
351