![drochner](/assets/img/avatar_default.png)
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.
224 lines
6.7 KiB
C
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);
|
|
}
|