pccard_cis_quirks.c revision 64850
155714Skris/*	$NetBSD: pcmcia_cis_quirks.c,v 1.5 1999/10/11 17:50:21 thorpej Exp $	*/
255714Skris/* $FreeBSD: head/sys/dev/pccard/pccard_cis_quirks.c 64850 2000-08-19 19:22:04Z imp $ */
355714Skris
455714Skris#define	PCCARDDEBUG
555714Skris
655714Skris/*
755714Skris * Copyright (c) 1998 Marc Horowitz.  All rights reserved.
855714Skris *
955714Skris * Redistribution and use in source and binary forms, with or without
1055714Skris * modification, are permitted provided that the following conditions
1159191Skris * are met:
1255714Skris * 1. Redistributions of source code must retain the above copyright
13142425Snectar *    notice, this list of conditions and the following disclaimer.
1455714Skris * 2. Redistributions in binary form must reproduce the above copyright
1555714Skris *    notice, this list of conditions and the following disclaimer in the
1655714Skris *    documentation and/or other materials provided with the distribution.
1755714Skris * 3. All advertising materials mentioning features or use of this software
1855714Skris *    must display the following acknowledgement:
1955714Skris *	This product includes software developed by Marc Horowitz.
2055714Skris * 4. The name of the author may not be used to endorse or promote products
21142425Snectar *    derived from this software without specific prior written permission.
2255714Skris *
2355714Skris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2455714Skris * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2555714Skris * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2655714Skris * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27109998Smarkm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2855714Skris * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2955714Skris * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3055714Skris * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3155714Skris * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
3255714Skris * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3355714Skris */
3455714Skris
3555714Skris#include <sys/param.h>
3655714Skris#include <sys/systm.h>
3755714Skris#include <sys/malloc.h>
3855714Skris#include <sys/module.h>
3955714Skris#include <sys/kernel.h>
4055714Skris#include <sys/queue.h>
41109998Smarkm#include <sys/types.h>
4255714Skris
4355714Skris#include <sys/bus.h>
4455714Skris#include <machine/bus.h>
4555714Skris#include <sys/rman.h>
4655714Skris#include <machine/resource.h>
4755714Skris
4855714Skris#include <dev/pccard/pccarddevs.h>
4955714Skris#include <dev/pccard/pccardreg.h>
5055714Skris#include <dev/pccard/pccardvar.h>
5155714Skris
5255714Skris/* There are cards out there whose CIS flat-out lies.  This file
5355714Skris   contains struct pccard_function chains for those devices. */
5455714Skris
5555714Skris/* these structures are just static templates which are then copied
5655714Skris   into "live" allocated structures */
5768651Skris
5868651Skrisstruct pccard_function pccard_3cxem556_func0 = {
59109998Smarkm	0,			/* function number */
60109998Smarkm	PCCARD_FUNCTION_NETWORK,
6155714Skris	0x07,			/* last cfe number */
6255714Skris	0x800,			/* ccr_base */
6355714Skris	0x63,			/* ccr_mask */
6455714Skris};
65109998Smarkm
66109998Smarkmstruct pccard_config_entry pccard_3cxem556_func0_cfe0 = {
67111147Snectar	0x07,			/* cfe number */
68111147Snectar	PCCARD_CFE_IO8 | PCCARD_CFE_IO16 | PCCARD_CFE_IRQLEVEL,
6955714Skris	PCCARD_IFTYPE_IO,
7059191Skris	1,			/* num_iospace */
7155714Skris	4,			/* iomask */
7255714Skris	{ { 0x0010, 0 } },	/* iospace */
7355714Skris	0xffff,			/* irqmask */
7455714Skris	0,			/* num_memspace */
7568651Skris	{ },			/* memspace */
7655714Skris	0,			/* maxtwins */
7755714Skris};
7855714Skris
7955714Skrisstatic struct pccard_function pccard_3cxem556_func1 = {
8055714Skris	1,			/* function number */
8155714Skris	PCCARD_FUNCTION_SERIAL,
8255714Skris	0x27,			/* last cfe number */
8355714Skris	0x900,			/* ccr_base */
8455714Skris	0x63,			/* ccr_mask */
8555714Skris};
8655714Skris
8755714Skrisstatic struct pccard_config_entry pccard_3cxem556_func1_cfe0 = {
8855714Skris	0x27,			/* cfe number */
89109998Smarkm	PCCARD_CFE_IO8 | PCCARD_CFE_IRQLEVEL,
9055714Skris	PCCARD_IFTYPE_IO,
9155714Skris	1,			/* num_iospace */
9255714Skris	3,			/* iomask */
9355714Skris	{ { 0x0008, 0 } },	/* iospace */
9455714Skris	0xffff,			/* irqmask */
9555714Skris	0,			/* num_memspace */
9655714Skris	{ },			/* memspace */
9755714Skris	0,			/* maxtwins */
9855714Skris};
99109998Smarkm
10055714Skrisstatic struct pccard_function pccard_3ccfem556bi_func0 = {
10155714Skris	0,			/* function number */
10255714Skris	PCCARD_FUNCTION_NETWORK,
10355714Skris	0x07,			/* last cfe number */
10455714Skris	0x1000,			/* ccr_base */
10555714Skris	0x267,			/* ccr_mask */
106100936Snectar};
10755714Skris
10855714Skrisstatic struct pccard_config_entry pccard_3ccfem556bi_func0_cfe0 = {
10955714Skris	0x07,			/* cfe number */
11055714Skris	PCCARD_CFE_IO8 | PCCARD_CFE_IO16 | PCCARD_CFE_IRQLEVEL,
11155714Skris	PCCARD_IFTYPE_IO,
11255714Skris	1,			/* num_iospace */
11355714Skris	5,			/* iomask */
11455714Skris	{ { 0x0020, 0 } },	/* iospace */
11555714Skris	0xffff,			/* irqmask */
11655714Skris	0,			/* num_memspace */
11755714Skris	{ },			/* memspace */
11855714Skris	0,			/* maxtwins */
11955714Skris};
12055714Skris
12155714Skrisstatic struct pccard_function pccard_3ccfem556bi_func1 = {
12255714Skris	1,			/* function number */
12355714Skris	PCCARD_FUNCTION_SERIAL,
12455714Skris	0x27,			/* last cfe number */
12555714Skris	0x1100,			/* ccr_base */
12655714Skris	0x277,			/* ccr_mask */
12755714Skris};
12855714Skris
12955714Skrisstatic struct pccard_config_entry pccard_3ccfem556bi_func1_cfe0 = {
13055714Skris	0x27,			/* cfe number */
13155714Skris	PCCARD_CFE_IO8 | PCCARD_CFE_IRQLEVEL,
13255714Skris	PCCARD_IFTYPE_IO,
13355714Skris	1,			/* num_iospace */
13455714Skris	3,			/* iomask */
13555714Skris	{ { 0x0008, 0 } },	/* iospace */
13655714Skris	0xffff,			/* irqmask */
13755714Skris	0,			/* num_memspace */
13855714Skris	{ },			/* memspace */
13955714Skris	0,			/* maxtwins */
14055714Skris};
14155714Skris
14255714Skrisstatic struct pccard_function pccard_sveclancard_func0 = {
143109998Smarkm	0,			/* function number */
144109998Smarkm	PCCARD_FUNCTION_NETWORK,
145109998Smarkm	0x1,			/* last cfe number */
146109998Smarkm	0x100,			/* ccr_base */
14755714Skris	0x1,			/* ccr_mask */
14855714Skris};
14955714Skris
15055714Skrisstatic struct pccard_config_entry pccard_sveclancard_func0_cfe0 = {
15155714Skris	0x1,			/* cfe number */
15255714Skris	PCCARD_CFE_MWAIT_REQUIRED | PCCARD_CFE_RDYBSY_ACTIVE |
15355714Skris	PCCARD_CFE_WP_ACTIVE | PCCARD_CFE_BVD_ACTIVE | PCCARD_CFE_IO16,
15455714Skris	PCCARD_IFTYPE_IO,
15555714Skris	1,			/* num_iospace */
15655714Skris	5,			/* iomask */
15755714Skris	{ { 0x20, 0x300 } },	/* iospace */
15855714Skris	0xdeb8,			/* irqmask */
15955714Skris	0,			/* num_memspace */
16055714Skris	{ },			/* memspace */
16155714Skris	0,			/* maxtwins */
16255714Skris};
16355714Skris
16455714Skrisstatic struct pccard_cis_quirk pccard_cis_quirks[] = {
16555714Skris	{ PCCARD_VENDOR_3COM, PCCARD_PRODUCT_3COM_3CXEM556, PCCARD_CIS_INVALID,
16655714Skris	  &pccard_3cxem556_func0, &pccard_3cxem556_func0_cfe0 },
16755714Skris	{ PCCARD_VENDOR_3COM, PCCARD_PRODUCT_3COM_3CXEM556, PCCARD_CIS_INVALID,
16855714Skris	  &pccard_3cxem556_func1, &pccard_3cxem556_func1_cfe0 },
16955714Skris	{ PCCARD_VENDOR_3COM, PCCARD_PRODUCT_3COM_3CXEM556INT, PCCARD_CIS_INVALID,
17055714Skris	  &pccard_3cxem556_func0, &pccard_3cxem556_func0_cfe0 },
17155714Skris	{ PCCARD_VENDOR_3COM, PCCARD_PRODUCT_3COM_3CXEM556INT, PCCARD_CIS_INVALID,
17255714Skris	  &pccard_3cxem556_func1, &pccard_3cxem556_func1_cfe0 },
17355714Skris	{ PCCARD_VENDOR_3COM, PCCARD_PRODUCT_3COM_3CCFEM556BI,
17455714Skris	  PCCARD_CIS_INVALID,
17555714Skris	  &pccard_3ccfem556bi_func0, &pccard_3ccfem556bi_func0_cfe0 },
17655714Skris	{ PCCARD_VENDOR_3COM, PCCARD_PRODUCT_3COM_3CCFEM556BI,
17755714Skris	  PCCARD_CIS_INVALID,
17855714Skris	  &pccard_3ccfem556bi_func1, &pccard_3ccfem556bi_func1_cfe0 },
17955714Skris	{ PCCARD_VENDOR_INVALID, PCCARD_PRODUCT_INVALID, PCCARD_CIS_SVEC_LANCARD,
18055714Skris	  &pccard_sveclancard_func0, &pccard_sveclancard_func0_cfe0 },
18155714Skris};
18255714Skris
18355714Skrisstatic int n_pccard_cis_quirks =
18455714Skris	sizeof(pccard_cis_quirks)/sizeof(pccard_cis_quirks[0]);
18555714Skris
18655714Skrisvoid pccard_check_cis_quirks(device_t dev)
18755714Skris{
18855714Skris	struct pccard_softc *sc = PCCARD_SOFTC(dev);
18955714Skris	int wiped = 0;
19055714Skris	int i, j;
19155714Skris	struct pccard_function *pf, *pf_next, *pf_last;
19255714Skris	struct pccard_config_entry *cfe, *cfe_next;
19355714Skris
194109998Smarkm	pf = NULL;
195109998Smarkm	pf_last = NULL;
196109998Smarkm
197109998Smarkm	for (i=0; i<n_pccard_cis_quirks; i++) {
198109998Smarkm		if ((sc->card.manufacturer == pccard_cis_quirks[i].manufacturer) &&
19955714Skris			(sc->card.product == pccard_cis_quirks[i].product) &&
20055714Skris			(((sc->card.manufacturer != PCCARD_VENDOR_INVALID) &&
20155714Skris			  (sc->card.product != PCCARD_PRODUCT_INVALID)) ||
20255714Skris			 ((sc->card.manufacturer == PCCARD_VENDOR_INVALID) &&
20355714Skris			  (sc->card.product == PCCARD_PRODUCT_INVALID) &&
20455714Skris			  sc->card.cis1_info[0] &&
20555714Skris			  (strcmp(sc->card.cis1_info[0],
20655714Skris					  pccard_cis_quirks[i].cis1_info[0]) == 0) &&
20755714Skris			  sc->card.cis1_info[1] &&
20855714Skris			  (strcmp(sc->card.cis1_info[1],
20955714Skris					  pccard_cis_quirks[i].cis1_info[1]) == 0)))) {
21055714Skris			if (!wiped) {
21155714Skris				if (pccard_verbose) {
21255714Skris					device_printf(dev, "using CIS quirks for ");
213109998Smarkm					for (j = 0; j < 4; j++) {
214109998Smarkm						if (sc->card.cis1_info[j] == NULL)
215109998Smarkm							break;
216109998Smarkm						if (j)
217109998Smarkm							printf(", ");
218109998Smarkm						printf("%s", sc->card.cis1_info[j]);
219109998Smarkm					}
220109998Smarkm					printf("\n");
221109998Smarkm				}
222109998Smarkm
223111147Snectar				for (pf = STAILQ_FIRST(&sc->card.pf_head); pf != NULL;
224109998Smarkm				     pf = pf_next) {
225142425Snectar					for (cfe = STAILQ_FIRST(&pf->cfe_head); cfe != NULL;
226109998Smarkm					     cfe = cfe_next) {
227109998Smarkm						cfe_next = STAILQ_NEXT(cfe, cfe_list);
228109998Smarkm						free(cfe, M_DEVBUF);
229109998Smarkm					}
230109998Smarkm					pf_next = STAILQ_NEXT(pf, pf_list);
231109998Smarkm					free(pf, M_DEVBUF);
232109998Smarkm				}
233109998Smarkm
234109998Smarkm				STAILQ_INIT(&sc->card.pf_head);
235109998Smarkm				wiped = 1;
236109998Smarkm			}
237111147Snectar
238111147Snectar			if (pf_last == pccard_cis_quirks[i].pf) {
239142425Snectar				cfe = malloc(sizeof(*cfe), M_DEVBUF, M_NOWAIT);
240109998Smarkm				*cfe = *pccard_cis_quirks[i].cfe;
24155714Skris
24268651Skris				STAILQ_INSERT_TAIL(&pf->cfe_head, cfe, cfe_list);
24368651Skris			} else {
24468651Skris				pf = malloc(sizeof(*pf), M_DEVBUF, M_NOWAIT);
24568651Skris				*pf = *pccard_cis_quirks[i].pf;
24655714Skris				STAILQ_INIT(&pf->cfe_head);
24755714Skris
24855714Skris				cfe = malloc(sizeof(*cfe), M_DEVBUF, M_NOWAIT);
249109998Smarkm				*cfe = *pccard_cis_quirks[i].cfe;
250109998Smarkm
251109998Smarkm				STAILQ_INSERT_TAIL(&pf->cfe_head, cfe, cfe_list);
25255714Skris				STAILQ_INSERT_TAIL(&sc->card.pf_head, pf, pf_list);
25355714Skris
25455714Skris				pf_last = pccard_cis_quirks[i].pf;
25555714Skris			}
25655714Skris		}
25755714Skris	}
25855714Skris}
25955714Skris