ncr53c500_pccard.c revision 127135
112657Skvn/*	$NecBSD: ncr53c500_pisa.c,v 1.28 1998/11/26 01:59:11 honda Exp $	*/
212657Skvn/*	$NetBSD$	*/
312657Skvn
412657Skvn/*
512657Skvn * [Ported for FreeBSD]
612657Skvn *  Copyright (c) 2000
712657Skvn *      Noriaki Mitsunaga, Mitsuru Iwasaki and Takanori Watanabe.
812657Skvn *      All rights reserved.
912657Skvn * [NetBSD for NEC PC-98 series]
1012657Skvn *  Copyright (c) 1995, 1996, 1997, 1998
1112657Skvn *	NetBSD/pc98 porting staff. All rights reserved.
1212657Skvn *  Copyright (c) 1995, 1996, 1997, 1998
1312657Skvn *	Naofumi HONDA. All rights reserved.
1412657Skvn *
1512657Skvn *  Redistribution and use in source and binary forms, with or without
1612657Skvn *  modification, are permitted provided that the following conditions
1712657Skvn *  are met:
1812657Skvn *  1. Redistributions of source code must retain the above copyright
1912657Skvn *     notice, this list of conditions and the following disclaimer.
2012657Skvn *  2. Redistributions in binary form must reproduce the above copyright
2112657Skvn *     notice, this list of conditions and the following disclaimer in the
2212657Skvn *     documentation and/or other materials provided with the distribution.
2312657Skvn *  3. The name of the author may not be used to endorse or promote products
2412657Skvn *     derived from this software without specific prior written permission.
2512657Skvn *
2612657Skvn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2712657Skvn * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
2812657Skvn * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2912657Skvn * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
3012657Skvn * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
3112657Skvn * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
3212657Skvn * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3312657Skvn * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
3412657Skvn * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
3512657Skvn * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3612657Skvn * POSSIBILITY OF SUCH DAMAGE.
3712657Skvn */
3812657Skvn
3912657Skvn#include <sys/cdefs.h>
4012657Skvn__FBSDID("$FreeBSD: head/sys/dev/ncv/ncr53c500_pccard.c 127135 2004-03-17 17:50:55Z njl $");
4112657Skvn
4212657Skvn#include <sys/param.h>
4312657Skvn#include <sys/systm.h>
4412657Skvn#include <sys/malloc.h>
4512657Skvn#include <sys/errno.h>
4612657Skvn
4712657Skvn#include <machine/bus.h>
4812657Skvn#include <machine/bus_pio.h>
4912657Skvn#include <compat/netbsd/dvcfg.h>
5012657Skvn
5112657Skvn#include <sys/device_port.h>
5212657Skvn
5312657Skvn#include <dev/pccard/pccarddevs.h>
5412657Skvn#include <dev/pccard/pccardvar.h>
5512657Skvn
5612657Skvn#include <cam/scsi/scsi_low.h>
5712657Skvn#include <cam/scsi/scsi_low_pisa.h>
5812657Skvn
5912657Skvn#include <dev/ncv/ncr53c500reg.h>
6012657Skvn#include <dev/ncv/ncr53c500hw.h>
6112657Skvn#include <dev/ncv/ncr53c500var.h>
6212657Skvn
6312657Skvn#define KME_KXLC004_01 0x100
6412657Skvn#define OFFSET_KME_KXLC004_01 0x10
6512657Skvn
6612657Skvn#include	<sys/kernel.h>
6712657Skvn#include	<sys/module.h>
6812657Skvn#if !defined(__FreeBSD__) || __FreeBSD_version < 500014
6912657Skvn#include	<sys/select.h>
7012657Skvn#endif
7112657Skvn#include	<pccard/cardinfo.h>
7212657Skvn#include	<pccard/slot.h>
7312657Skvn
7412657Skvnstatic int ncvprobe(DEVPORT_PDEVICE devi);
7512657Skvnstatic int ncvattach(DEVPORT_PDEVICE devi);
7612657Skvn
7712657Skvnstatic void	ncv_card_unload(DEVPORT_PDEVICE);
7812657Skvn
7912657Skvnstatic const struct ncv_product {
8012657Skvn	struct pccard_product	prod;
8112657Skvn	int flags;
8212657Skvn} ncv_products[] = {
8312657Skvn	{ PCMCIA_CARD(EPSON, SC200, 0), 0},
8412657Skvn	{ PCMCIA_CARD(PANASONIC, KXLC002, 0), 0xb4d00000 },
8512657Skvn	{ PCMCIA_CARD(PANASONIC, KXLC004, 0), 0xb4d00100 },
8612657Skvn	{ PCMCIA_CARD(MACNICA, MPS100, 0), 0xb6250000 },
8712657Skvn	{ PCMCIA_CARD(MACNICA, MPS110, 0), 0 },
8812657Skvn	{ PCMCIA_CARD(NEC, PC9801N_J03R, 0), 0 },
8912657Skvn	{ PCMCIA_CARD(NEWMEDIA, BASICS_SCSI, 0), 0 },
9012657Skvn	{ PCMCIA_CARD(QLOGIC, PC05, 0), 0x84d00000 },
9112657Skvn#define FLAGS_REX5572 0x84d00000
9212657Skvn	{ PCMCIA_CARD(RATOC, REX5572, 0), FLAGS_REX5572 },
9312657Skvn	{ PCMCIA_CARD(RATOC, REX9530, 0), 0x84d00000 },
9412657Skvn	{ { NULL }, 0 }
9512657Skvn};
9612657Skvn
9712657Skvn/*
9812657Skvn * Additional code for FreeBSD new-bus PCCard frontend
9912657Skvn */
10012657Skvn
10112657Skvnstatic void
10212657Skvnncv_pccard_intr(void * arg)
10312657Skvn{
10412657Skvn	ncvintr(arg);
10512657Skvn}
10612657Skvn
10712657Skvnstatic void
10812657Skvnncv_release_resource(DEVPORT_PDEVICE dev)
10912657Skvn{
11012657Skvn	struct ncv_softc	*sc = device_get_softc(dev);
11112657Skvn
11212657Skvn	if (sc->ncv_intrhand) {
11312657Skvn		bus_teardown_intr(dev, sc->irq_res, sc->ncv_intrhand);
11412657Skvn	}
11512657Skvn
11612657Skvn	if (sc->port_res) {
11712657Skvn		bus_release_resource(dev, SYS_RES_IOPORT,
11812657Skvn				     sc->port_rid, sc->port_res);
11912657Skvn	}
12012657Skvn
12112657Skvn	if (sc->port_res_dmy) {
12212657Skvn		bus_release_resource(dev, SYS_RES_IOPORT,
12312657Skvn				     sc->port_rid_dmy, sc->port_res_dmy);
12412657Skvn	}
12512657Skvn
12612657Skvn	if (sc->irq_res) {
12712657Skvn		bus_release_resource(dev, SYS_RES_IRQ,
12812657Skvn				     sc->irq_rid, sc->irq_res);
12912657Skvn	}
13012657Skvn
13112657Skvn	if (sc->mem_res) {
13212657Skvn		bus_release_resource(dev, SYS_RES_MEMORY,
13312657Skvn				     sc->mem_rid, sc->mem_res);
13412657Skvn	}
13512657Skvn}
13612657Skvn
13712657Skvnstatic int
13812657Skvnncv_alloc_resource(DEVPORT_PDEVICE dev)
13912657Skvn{
14012657Skvn	struct ncv_softc	*sc = device_get_softc(dev);
14112657Skvn	u_int32_t		flags = DEVPORT_PDEVFLAGS(dev);
14212657Skvn	u_long			ioaddr, iosize, maddr, msize;
14312657Skvn	int			error;
14412657Skvn	bus_addr_t		offset = 0;
14512657Skvn
14612657Skvn	if(flags & KME_KXLC004_01)
14712657Skvn		offset = OFFSET_KME_KXLC004_01;
14812657Skvn
14912657Skvn	error = bus_get_resource(dev, SYS_RES_IOPORT, 0, &ioaddr, &iosize);
15012657Skvn	if (error || (iosize < (offset + NCVIOSZ))) {
15112657Skvn		return(ENOMEM);
15212657Skvn	}
15312657Skvn
15412657Skvn	sc->port_rid = 0;
15512657Skvn	sc->port_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->port_rid,
15612657Skvn					  ioaddr+offset, ioaddr+iosize-offset,
15712657Skvn					  iosize-offset, RF_ACTIVE);
15812657Skvn	if (sc->port_res == NULL) {
15912657Skvn		ncv_release_resource(dev);
16012657Skvn		return(ENOMEM);
16112657Skvn	}
16212657Skvn
16312657Skvn	if (offset != 0) {
16412657Skvn		sc->port_rid_dmy = 0;
16512657Skvn		sc->port_res_dmy = bus_alloc_resource(dev, SYS_RES_IOPORT,
16612657Skvn						&sc->port_rid_dmy,
16712657Skvn						ioaddr, ioaddr+offset, offset,
16812657Skvn						RF_ACTIVE);
16912657Skvn		if (sc->port_res_dmy == NULL) {
17012657Skvn			printf("Warning: cannot allocate IOPORT partially.\n");
17112657Skvn		}
17212657Skvn	} else {
17312657Skvn		sc->port_rid_dmy = 0;
17412657Skvn		sc->port_res_dmy = NULL;
17512657Skvn	}
17612657Skvn
17712657Skvn	sc->irq_rid = 0;
17812657Skvn	sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid,
17912657Skvn					     RF_ACTIVE);
18012657Skvn	if (sc->irq_res == NULL) {
18112657Skvn		ncv_release_resource(dev);
18212657Skvn		return(ENOMEM);
18312657Skvn	}
18412657Skvn
18512657Skvn	error = bus_get_resource(dev, SYS_RES_MEMORY, 0, &maddr, &msize);
18612657Skvn	if (error) {
18712657Skvn		return(0);	/* XXX */
18812657Skvn	}
18912657Skvn
19012657Skvn	/* no need to allocate memory if not configured */
19112657Skvn	if (maddr == 0 || msize == 0) {
19212657Skvn		return(0);
19312657Skvn	}
19412657Skvn
19512657Skvn	sc->mem_rid = 0;
19612657Skvn	sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->mem_rid,
19712657Skvn					     RF_ACTIVE);
19812657Skvn	if (sc->mem_res == NULL) {
19912657Skvn		ncv_release_resource(dev);
20012657Skvn		return(ENOMEM);
20112657Skvn	}
20212657Skvn
20312657Skvn	return(0);
20412657Skvn}
20512657Skvn
20612657Skvnstatic int ncv_pccard_match(device_t dev)
20712657Skvn{
20812657Skvn	const struct ncv_product *pp;
20912657Skvn	const char *vendorstr;
21012657Skvn	const char *prodstr;
21112657Skvn
21212657Skvn	if ((pp = (const struct ncv_product *) pccard_product_lookup(dev,
21312657Skvn	    (const struct pccard_product *) ncv_products,
21412657Skvn	    sizeof(ncv_products[0]), NULL)) != NULL) {
21512657Skvn		if (pp->prod.pp_name != NULL)
21612657Skvn			device_set_desc(dev, pp->prod.pp_name);
21712657Skvn		device_set_flags(dev, pp->flags);
21812657Skvn		return(0);
21912657Skvn	}
22012657Skvn	if (pccard_get_vendor_str(dev, &vendorstr))
22112657Skvn		return(EIO);
22212657Skvn	if (pccard_get_product_str(dev, &prodstr))
22312657Skvn		return(EIO);
22412657Skvn	if (strcmp(vendorstr, "RATOC System Inc.") == 0 &&
22512657Skvn		strncmp(prodstr, "SOUND/SCSI2 CARD", 16) == 0) {
22612657Skvn		device_set_desc(dev, "RATOC REX-5572");
22712657Skvn		device_set_flags(dev, FLAGS_REX5572);
22812657Skvn		return (0);
22912657Skvn	}
23012657Skvn	return(EIO);
23112657Skvn}
23212657Skvn
23312657Skvnstatic int
23412657Skvnncv_pccard_probe(DEVPORT_PDEVICE dev)
23512657Skvn{
23612657Skvn	struct ncv_softc	*sc = device_get_softc(dev);
23712657Skvn	int			error;
23812657Skvn
23912657Skvn	bzero(sc, sizeof(struct ncv_softc));
24012657Skvn
24112657Skvn	error = ncv_alloc_resource(dev);
24212657Skvn	if (error) {
24312657Skvn		return(error);
24412657Skvn	}
24512657Skvn
24612657Skvn	if (ncvprobe(dev) == 0) {
24712657Skvn		ncv_release_resource(dev);
24812657Skvn		return(ENXIO);
24912657Skvn	}
25012657Skvn
25112657Skvn	ncv_release_resource(dev);
25212657Skvn
25312657Skvn	return(0);
25412657Skvn}
25512657Skvn
25612657Skvnstatic int
25712657Skvnncv_pccard_attach(DEVPORT_PDEVICE dev)
25812657Skvn{
25912657Skvn	struct ncv_softc	*sc = device_get_softc(dev);
26012657Skvn	int			error;
26112657Skvn
26212657Skvn	error = ncv_alloc_resource(dev);
26312657Skvn	if (error) {
26412657Skvn		return(error);
26512657Skvn	}
26612657Skvn
26712657Skvn	error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_CAM | INTR_ENTROPY,
26812657Skvn			       ncv_pccard_intr, (void *)sc, &sc->ncv_intrhand);
26912657Skvn	if (error) {
27012657Skvn		ncv_release_resource(dev);
27112657Skvn		return(error);
27212657Skvn	}
27312657Skvn
27412657Skvn	if (ncvattach(dev) == 0) {
27512657Skvn		ncv_release_resource(dev);
27612657Skvn		return(ENXIO);
27712657Skvn	}
27812657Skvn
27912657Skvn	return(0);
28012657Skvn}
28112657Skvn
28212657Skvnstatic	void
28312657Skvnncv_pccard_detach(DEVPORT_PDEVICE dev)
28412657Skvn{
28512657Skvn	ncv_card_unload(dev);
28612657Skvn	ncv_release_resource(dev);
28712657Skvn}
28812657Skvn
28912657Skvnstatic device_method_t ncv_pccard_methods[] = {
29012657Skvn	/* Device interface */
29112657Skvn	DEVMETHOD(device_probe,		pccard_compat_probe),
29212657Skvn	DEVMETHOD(device_attach,	pccard_compat_attach),
29312657Skvn	DEVMETHOD(device_detach,	ncv_pccard_detach),
29412657Skvn
29512657Skvn	/* Card interface */
29612657Skvn	DEVMETHOD(card_compat_match,	ncv_pccard_match),
29712657Skvn	DEVMETHOD(card_compat_probe,	ncv_pccard_probe),
29812657Skvn	DEVMETHOD(card_compat_attach,	ncv_pccard_attach),
29912657Skvn
30012657Skvn	{ 0, 0 }
30112657Skvn};
30212657Skvn
30312657Skvnstatic driver_t ncv_pccard_driver = {
30412657Skvn	"ncv",
30512657Skvn	ncv_pccard_methods,
30612657Skvn	sizeof(struct ncv_softc),
30712657Skvn};
30812657Skvn
30912657Skvnstatic devclass_t ncv_devclass;
31012657Skvn
31112657SkvnMODULE_DEPEND(ncv, scsi_low, 1, 1, 1);
31212657SkvnDRIVER_MODULE(ncv, pccard, ncv_pccard_driver, ncv_devclass, 0, 0);
31312657Skvn
31412657Skvnstatic void
31512657Skvnncv_card_unload(DEVPORT_PDEVICE devi)
31612657Skvn{
31712657Skvn	struct ncv_softc *sc = DEVPORT_PDEVGET_SOFTC(devi);
31812657Skvn	intrmask_t s;
31912657Skvn
32012657Skvn	printf("%s: unload\n", sc->sc_sclow.sl_xname);
32112657Skvn	s = splcam();
32212657Skvn	scsi_low_deactivate((struct scsi_low_softc *)sc);
32312657Skvn        scsi_low_dettach(&sc->sc_sclow);
32412657Skvn	splx(s);
32512657Skvn}
32612657Skvn
32712657Skvnstatic int
32812657Skvnncvprobe(DEVPORT_PDEVICE devi)
32912657Skvn{
33012657Skvn	int rv;
33112657Skvn	struct ncv_softc *sc = device_get_softc(devi);
33212657Skvn	u_int32_t flags = DEVPORT_PDEVFLAGS(devi);
33312657Skvn
33412657Skvn	rv = ncvprobesubr(rman_get_bustag(sc->port_res),
33512657Skvn			  rman_get_bushandle(sc->port_res),
33612657Skvn			  flags, NCV_HOSTID);
33712657Skvn
33812657Skvn	return rv;
33912657Skvn}
34012657Skvn
34112657Skvnstatic int
34212657Skvnncvattach(DEVPORT_PDEVICE devi)
34312657Skvn{
34412657Skvn	struct ncv_softc *sc;
34512657Skvn	struct scsi_low_softc *slp;
34612657Skvn	u_int32_t flags = DEVPORT_PDEVFLAGS(devi);
34712657Skvn	intrmask_t s;
34812657Skvn	char dvname[16]; /* SCSI_LOW_DVNAME_LEN */
34912657Skvn
35012657Skvn	strcpy(dvname, "ncv");
35112657Skvn
35212657Skvn	sc = DEVPORT_PDEVALLOC_SOFTC(devi);
35312657Skvn	if (sc == NULL) {
35412657Skvn		return(0);
35512657Skvn	}
35612657Skvn
35712657Skvn	slp = &sc->sc_sclow;
35812657Skvn	slp->sl_dev = devi;
35912657Skvn	sc->sc_iot = rman_get_bustag(sc->port_res);
36012657Skvn	sc->sc_ioh = rman_get_bushandle(sc->port_res);
36112657Skvn
36212657Skvn	slp->sl_hostid = NCV_HOSTID;
36312657Skvn	slp->sl_cfgflags = flags;
36412657Skvn
36512657Skvn	s = splcam();
36612657Skvn	ncvattachsubr(sc);
36712657Skvn	splx(s);
36812657Skvn
36912657Skvn	return(NCVIOSZ);
37012657Skvn}
37112657Skvn