NetBSD/sys/dev/cardbus/uhci_cardbus.c
drochner 36b6bc746c clean up the cardbus interrupt stuff:
There were cardbus_intr_line_t and cardbus_intr_handle_t used intermixed
for the same variable, and that variable is pretty much useless because
cardbus doesn't follow the PCI interrupt swizzling etc scheme.
Useless interrupt numbers were printed on cardbus device attach.
So as a first step to sanity, kill cardbus_intr_handle_t and poison
cardbus_intr_line_t to discourage printing it as a %d.
Use cardbus_intr_line_t consistently throughout the code.
Remove the "interrupting at foo" messages because the information
is misleading. We could come up with a better interrupt vector
information, but because cardbus interrupts are mediated by pccbb
it would still be misleading.
2008-06-24 19:44:51 +00:00

224 lines
6.7 KiB
C

/* $NetBSD: uhci_cardbus.c,v 1.11 2008/06/24 19:44:52 drochner Exp $ */
/*
* Copyright (c) 1998-2005 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Lennart Augustsson (lennart@augustsson.net) at
* Carlstedt Research & Technology.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: uhci_cardbus.c,v 1.11 2008/06/24 19:44:52 drochner Exp $");
#include "ehci_cardbus.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/device.h>
#include <sys/proc.h>
#include <sys/queue.h>
#include <sys/bus.h>
#include <dev/cardbus/cardbusvar.h>
#include <dev/cardbus/usb_cardbus.h>
#include <dev/usb/usb.h>
#include <dev/usb/usbdi.h>
#include <dev/usb/usbdivar.h>
#include <dev/usb/usb_mem.h>
#include <dev/usb/uhcireg.h>
#include <dev/usb/uhcivar.h>
struct uhci_cardbus_softc {
uhci_softc_t sc;
#if NEHCI_CARDBUS > 0
struct usb_cardbus sc_cardbus;
#endif
cardbus_chipset_tag_t sc_cc;
cardbus_function_tag_t sc_cf;
cardbus_devfunc_t sc_ct;
cardbustag_t sc_tag;
void *sc_ih; /* interrupt vectoring */
};
static int uhci_cardbus_match(device_t, struct cfdata *, void *);
static void uhci_cardbus_attach(device_t, device_t, void *);
static int uhci_cardbus_detach(device_t, int);
CFATTACH_DECL_NEW(uhci_cardbus, sizeof(struct uhci_cardbus_softc),
uhci_cardbus_match, uhci_cardbus_attach, uhci_cardbus_detach, uhci_activate);
#define CARDBUS_INTERFACE_UHCI PCI_INTERFACE_UHCI
#define CARDBUS_CBIO PCI_CBIO
#define cardbus_findvendor pci_findvendor
#define cardbus_devinfo pci_devinfo
static int
uhci_cardbus_match(device_t parent, struct cfdata *match, void *aux)
{
struct cardbus_attach_args *ca = (struct cardbus_attach_args *)aux;
if (CARDBUS_CLASS(ca->ca_class) == CARDBUS_CLASS_SERIALBUS &&
CARDBUS_SUBCLASS(ca->ca_class) == CARDBUS_SUBCLASS_SERIALBUS_USB &&
CARDBUS_INTERFACE(ca->ca_class) == CARDBUS_INTERFACE_UHCI)
return (1);
return (0);
}
static void
uhci_cardbus_attach(device_t parent, device_t self,
void *aux)
{
struct uhci_cardbus_softc *sc = device_private(self);
struct cardbus_attach_args *ca = (struct cardbus_attach_args *)aux;
cardbus_devfunc_t ct = ca->ca_ct;
cardbus_chipset_tag_t cc = ct->ct_cc;
cardbus_function_tag_t cf = ct->ct_cf;
cardbustag_t tag = ca->ca_tag;
cardbusreg_t csr;
const char *vendor;
const char *devname = device_xname(self);
char devinfo[256];
usbd_status r;
sc->sc.sc_dev = self;
sc->sc.sc_bus.hci_private = sc;
cardbus_devinfo(ca->ca_id, ca->ca_class, 0, devinfo, sizeof(devinfo));
printf(": %s (rev. 0x%02x)\n", devinfo, CARDBUS_REVISION(ca->ca_class));
/* Map I/O registers */
if (Cardbus_mapreg_map(ct, CARDBUS_CBIO, CARDBUS_MAPREG_TYPE_IO, 0,
&sc->sc.iot, &sc->sc.ioh, NULL, &sc->sc.sc_size)) {
printf("%s: can't map i/o space\n", devname);
return;
}
/* Disable interrupts, so we don't get any spurious ones. */
bus_space_write_2(sc->sc.iot, sc->sc.ioh, UHCI_INTR, 0);
sc->sc_cc = cc;
sc->sc_cf = cf;
sc->sc_ct = ct;
sc->sc_tag = tag;
sc->sc.sc_bus.dmatag = ca->ca_dmat;
#if rbus
#else
XXX (ct->ct_cf->cardbus_io_open)(cc, 0, iob, iob + 0x40);
#endif
(ct->ct_cf->cardbus_ctrl)(cc, CARDBUS_IO_ENABLE);
(ct->ct_cf->cardbus_ctrl)(cc, CARDBUS_BM_ENABLE);
/* Enable the device. */
csr = cardbus_conf_read(cc, cf, tag, CARDBUS_COMMAND_STATUS_REG);
cardbus_conf_write(cc, cf, tag, CARDBUS_COMMAND_STATUS_REG,
csr | CARDBUS_COMMAND_MASTER_ENABLE
| CARDBUS_COMMAND_IO_ENABLE);
/* Map and establish the interrupt. */
sc->sc_ih = cardbus_intr_establish(cc, cf, ca->ca_intrline,
IPL_USB, uhci_intr, sc);
if (sc->sc_ih == NULL) {
printf("%s: couldn't establish interrupt\n", devname);
return;
}
/* Set LEGSUP register to its default value. */
cardbus_conf_write(cc, cf, tag, PCI_LEGSUP, PCI_LEGSUP_USBPIRQDEN);
switch(cardbus_conf_read(cc, cf, tag, PCI_USBREV) & PCI_USBREV_MASK) {
case PCI_USBREV_PRE_1_0:
sc->sc.sc_bus.usbrev = USBREV_PRE_1_0;
break;
case PCI_USBREV_1_0:
sc->sc.sc_bus.usbrev = USBREV_1_0;
break;
case PCI_USBREV_1_1:
sc->sc.sc_bus.usbrev = USBREV_1_1;
break;
default:
sc->sc.sc_bus.usbrev = USBREV_UNKNOWN;
break;
}
/* Figure out vendor for root hub descriptor. */
vendor = cardbus_findvendor(ca->ca_id);
sc->sc.sc_id_vendor = CARDBUS_VENDOR(ca->ca_id);
if (vendor)
strlcpy(sc->sc.sc_vendor, vendor, sizeof(sc->sc.sc_vendor));
else
snprintf(sc->sc.sc_vendor, sizeof(sc->sc.sc_vendor),
"vendor 0x%04x", CARDBUS_VENDOR(ca->ca_id));
r = uhci_init(&sc->sc);
if (r != USBD_NORMAL_COMPLETION) {
printf("%s: init failed, error=%d\n", devname, r);
/* Avoid spurious interrupts. */
cardbus_intr_disestablish(sc->sc_cc, sc->sc_cf, sc->sc_ih);
sc->sc_ih = NULL;
return;
}
#if NEHCI_CARDBUS > 0
usb_cardbus_add(&sc->sc_cardbus, ca, self);
#endif
/* Attach usb device. */
sc->sc.sc_child = config_found(self, &sc->sc.sc_bus, usbctlprint);
}
static int
uhci_cardbus_detach(device_t self, int flags)
{
struct uhci_cardbus_softc *sc = device_private(self);
struct cardbus_devfunc *ct = sc->sc_ct;
int rv;
rv = uhci_detach(&sc->sc, flags);
if (rv)
return (rv);
if (sc->sc_ih != NULL) {
cardbus_intr_disestablish(sc->sc_cc, sc->sc_cf, sc->sc_ih);
sc->sc_ih = NULL;
}
if (sc->sc.sc_size) {
Cardbus_mapreg_unmap(ct, CARDBUS_CBIO, sc->sc.iot,
sc->sc.ioh, sc->sc.sc_size);
sc->sc.sc_size = 0;
}
#if NEHCI_CARDBUS > 0
usb_cardbus_rem(&sc->sc_cardbus);
#endif
return (0);
}