pccard.c revision 104641
166200Simp/* $NetBSD: pcmcia.c,v 1.23 2000/07/28 19:17:02 drochner Exp $ */ 252506Simp/* $FreeBSD: head/sys/dev/pccard/pccard.c 104641 2002-10-07 23:05:33Z imp $ */ 352506Simp 452506Simp/* 552506Simp * Copyright (c) 1997 Marc Horowitz. All rights reserved. 652506Simp * 752506Simp * Redistribution and use in source and binary forms, with or without 852506Simp * modification, are permitted provided that the following conditions 952506Simp * are met: 1052506Simp * 1. Redistributions of source code must retain the above copyright 1152506Simp * notice, this list of conditions and the following disclaimer. 1252506Simp * 2. Redistributions in binary form must reproduce the above copyright 1352506Simp * notice, this list of conditions and the following disclaimer in the 1452506Simp * documentation and/or other materials provided with the distribution. 1552506Simp * 3. All advertising materials mentioning features or use of this software 1652506Simp * must display the following acknowledgement: 1752506Simp * This product includes software developed by Marc Horowitz. 1852506Simp * 4. The name of the author may not be used to endorse or promote products 1952506Simp * derived from this software without specific prior written permission. 2052506Simp * 2152506Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 2252506Simp * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2352506Simp * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2452506Simp * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2552506Simp * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2652506Simp * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2752506Simp * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2852506Simp * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2952506Simp * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 3052506Simp * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3152506Simp */ 3252506Simp 3352506Simp#include <sys/param.h> 3452506Simp#include <sys/systm.h> 3552506Simp#include <sys/malloc.h> 3652506Simp#include <sys/module.h> 3752506Simp#include <sys/kernel.h> 3852506Simp#include <sys/queue.h> 3991786Simp#include <sys/sysctl.h> 4052506Simp#include <sys/types.h> 4152506Simp 4252506Simp#include <sys/bus.h> 4352506Simp#include <machine/bus.h> 4452506Simp#include <sys/rman.h> 4552506Simp#include <machine/resource.h> 4652506Simp 4782781Sshiba#include <net/ethernet.h> 4882781Sshiba 4952506Simp#include <dev/pccard/pccardreg.h> 5052506Simp#include <dev/pccard/pccardvar.h> 5152506Simp 5255500Simp#include "power_if.h" 5359193Simp#include "card_if.h" 5455500Simp 5555500Simp#define PCCARDDEBUG 5655500Simp 5791786Simp/* sysctl vars */ 5891786SimpSYSCTL_NODE(_hw, OID_AUTO, pccard, CTLFLAG_RD, 0, "PCCARD parameters"); 5991786Simp 6091786Simpint pccard_debug = 0; 6191786SimpTUNABLE_INT("hw.pccard.debug", &pccard_debug); 6291786SimpSYSCTL_INT(_hw_pccard, OID_AUTO, debug, CTLFLAG_RW, 6391786Simp &pccard_debug, 0, 6491786Simp "pccard debug"); 6591786Simp 6691786Simpint pccard_cis_debug = 0; 6791786SimpTUNABLE_INT("hw.pccard.cis_debug", &pccard_cis_debug); 6891786SimpSYSCTL_INT(_hw_pccard, OID_AUTO, cis_debug, CTLFLAG_RW, 6991786Simp &pccard_cis_debug, 0, "pccard CIS debug"); 7091786Simp 7152506Simp#ifdef PCCARDDEBUG 7252506Simp#define DPRINTF(arg) if (pccard_debug) printf arg 7355500Simp#define DEVPRINTF(arg) if (pccard_debug) device_printf arg 7467333Simp#define PRVERBOSE(arg) printf arg 7567333Simp#define DEVPRVERBOSE(arg) device_printf arg 7652506Simp#else 7752506Simp#define DPRINTF(arg) 7855500Simp#define DEVPRINTF(arg) 7967333Simp#define PRVERBOSE(arg) if (bootverbose) printf arg 8067333Simp#define DEVPRVERBOSE(arg) if (bootverbose) device_printf arg 8152506Simp#endif 8252506Simp 8382378Sjonstatic int pccard_ccr_read(struct pccard_function *pf, int ccr); 8482378Sjonstatic void pccard_ccr_write(struct pccard_function *pf, int ccr, int val); 8582378Sjonstatic int pccard_attach_card(device_t dev); 8682378Sjonstatic int pccard_detach_card(device_t dev, int flags); 8782378Sjonstatic int pccard_card_gettype(device_t dev, int *type); 8882378Sjonstatic void pccard_function_init(struct pccard_function *pf); 8982378Sjonstatic void pccard_function_free(struct pccard_function *pf); 9082378Sjonstatic int pccard_function_enable(struct pccard_function *pf); 9182378Sjonstatic void pccard_function_disable(struct pccard_function *pf); 9282378Sjonstatic int pccard_compat_do_probe(device_t bus, device_t dev); 9382378Sjonstatic int pccard_compat_do_attach(device_t bus, device_t dev); 9482378Sjonstatic int pccard_add_children(device_t dev, int busno); 9582378Sjonstatic int pccard_probe(device_t dev); 9682378Sjonstatic int pccard_attach(device_t dev); 9782378Sjonstatic int pccard_detach(device_t dev); 9882378Sjonstatic void pccard_print_resources(struct resource_list *rl, 9982378Sjon const char *name, int type, int count, const char *format); 10082378Sjonstatic int pccard_print_child(device_t dev, device_t child); 10182378Sjonstatic int pccard_set_resource(device_t dev, device_t child, int type, 10282378Sjon int rid, u_long start, u_long count); 10382378Sjonstatic int pccard_get_resource(device_t dev, device_t child, int type, 10482378Sjon int rid, u_long *startp, u_long *countp); 10582378Sjonstatic void pccard_delete_resource(device_t dev, device_t child, int type, 10682378Sjon int rid); 10782378Sjonstatic int pccard_set_res_flags(device_t dev, device_t child, int type, 10882378Sjon int rid, u_int32_t flags); 10982378Sjonstatic int pccard_set_memory_offset(device_t dev, device_t child, int rid, 11082378Sjon u_int32_t offset, u_int32_t *deltap); 111104641Simpstatic void pccard_probe_nomatch(device_t cbdev, device_t child); 11282378Sjonstatic int pccard_read_ivar(device_t bus, device_t child, int which, 11382378Sjon u_char *result); 11482378Sjonstatic void pccard_driver_added(device_t dev, driver_t *driver); 11582378Sjonstatic struct resource *pccard_alloc_resource(device_t dev, 11682378Sjon device_t child, int type, int *rid, u_long start, 11782378Sjon u_long end, u_long count, u_int flags); 11882378Sjonstatic int pccard_release_resource(device_t dev, device_t child, int type, 11982378Sjon int rid, struct resource *r); 12082378Sjonstatic void pccard_child_detached(device_t parent, device_t dev); 12182378Sjonstatic void pccard_intr(void *arg); 12282378Sjonstatic int pccard_setup_intr(device_t dev, device_t child, 12382378Sjon struct resource *irq, int flags, driver_intr_t *intr, 12482378Sjon void *arg, void **cookiep); 12582378Sjonstatic int pccard_teardown_intr(device_t dev, device_t child, 12682378Sjon struct resource *r, void *cookie); 12752506Simp 12897613Stakawatastatic const struct pccard_product * 12997613Stakawatapccard_do_product_lookup(device_t bus, device_t dev, 13097613Stakawata const struct pccard_product *tab, size_t ent_size, 13197613Stakawata pccard_product_match_fn matchfn); 13297613Stakawata 13397613Stakawata 13482378Sjonstatic int 13574632Simppccard_ccr_read(struct pccard_function *pf, int ccr) 13652506Simp{ 13752506Simp return (bus_space_read_1(pf->pf_ccrt, pf->pf_ccrh, 13852506Simp pf->pf_ccr_offset + ccr)); 13952506Simp} 14052506Simp 14182378Sjonstatic void 14274632Simppccard_ccr_write(struct pccard_function *pf, int ccr, int val) 14352506Simp{ 14452506Simp if ((pf->ccr_mask) & (1 << (ccr / 2))) { 14552506Simp bus_space_write_1(pf->pf_ccrt, pf->pf_ccrh, 14652506Simp pf->pf_ccr_offset + ccr, val); 14752506Simp } 14852506Simp} 14952506Simp 15059193Simpstatic int 15159193Simppccard_attach_card(device_t dev) 15252506Simp{ 15364850Simp struct pccard_softc *sc = PCCARD_SOFTC(dev); 15452506Simp struct pccard_function *pf; 15565917Simp struct pccard_ivar *ivar; 15661788Simp device_t child; 157102713Simp int i; 15852506Simp 15952506Simp /* 16052506Simp * this is here so that when socket_enable calls gettype, trt happens 16152506Simp */ 16252506Simp STAILQ_INIT(&sc->card.pf_head); 16352506Simp 16455500Simp DEVPRINTF((dev, "chip_socket_enable\n")); 16555500Simp POWER_ENABLE_SOCKET(device_get_parent(dev), dev); 16652506Simp 16755500Simp DEVPRINTF((dev, "read_cis\n")); 16852506Simp pccard_read_cis(sc); 16952506Simp 17055500Simp DEVPRINTF((dev, "check_cis_quirks\n")); 17152506Simp pccard_check_cis_quirks(dev); 17252506Simp 17352506Simp /* 17452506Simp * bail now if the card has no functions, or if there was an error in 17552506Simp * the cis. 17652506Simp */ 17752506Simp 17870715Sjon if (sc->card.error) { 179102713Simp device_printf(dev, "CARD ERROR!\n"); 18052506Simp return (1); 18170715Sjon } 18270715Sjon if (STAILQ_EMPTY(&sc->card.pf_head)) { 183102713Simp device_printf(dev, "Card has no functions!\n"); 18452506Simp return (1); 18570715Sjon } 18652506Simp 18790436Simp if (bootverbose || pccard_debug) 18852506Simp pccard_print_cis(dev); 18952506Simp 19055500Simp DEVPRINTF((dev, "functions scanning\n")); 191102713Simp i = -1; 19252506Simp STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) { 193102713Simp i++; 194102713Simp if (STAILQ_EMPTY(&pf->cfe_head)) { 195102713Simp device_printf(dev, 196102713Simp "Function %d has no config entries.!\n", i); 19752506Simp continue; 198102713Simp } 19952506Simp pf->sc = sc; 20052506Simp pf->cfe = NULL; 20164927Simp pf->dev = NULL; 20252506Simp } 203104641Simp DEVPRINTF((dev, "Card has %d functions. pccard_mfc is %d\n", i + 1, 204102713Simp pccard_mfc(sc))); 20582378Sjon 20652506Simp STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) { 20752506Simp if (STAILQ_EMPTY(&pf->cfe_head)) 20852506Simp continue; 20961788Simp /* 21061788Simp * In NetBSD, the drivers are responsible for activating 21161788Simp * each function of a card. I think that in FreeBSD we 21261788Simp * want to activate them enough for the usual bus_*_resource 21361788Simp * routines will do the right thing. This many mean a 21461788Simp * departure from the current NetBSD model. 21561788Simp * 216104641Simp * This seems to work well in practice for most cards. 217104641Simp * However, there are two cases that are problematic. 218104641Simp * If a driver wishes to pick and chose which config 219104641Simp * entry to use, then this method falls down. These 220104641Simp * are usually older cards. In addition, there are 221104641Simp * some cards that have multiple hardware units on the 222104641Simp * cards, but presents only one CIS chain. These cards 223104641Simp * are combination cards, but only one of these units 224104641Simp * can be on at a time. 22561788Simp */ 22667897Sdwmalone ivar = malloc(sizeof(struct pccard_ivar), M_DEVBUF, 22767897Sdwmalone M_WAITOK | M_ZERO); 22861788Simp child = device_add_child(dev, NULL, -1); 22965917Simp device_set_ivars(child, ivar); 23066847Simp ivar->fcn = pf; 23167187Simp pf->dev = child; 23267167Simp /* 23367167Simp * XXX We might want to move the next two lines into 23467167Simp * XXX the pccard interface layer. For the moment, this 23567167Simp * XXX is OK, but some drivers want to pick the config 23667167Simp * XXX entry to use as well as some address tweaks (mostly 23767167Simp * XXX due to bugs in decode logic that makes some 23867167Simp * XXX addresses illegal or broken). 23967167Simp */ 24065917Simp pccard_function_init(pf); 24182378Sjon if (sc->sc_enabled_count == 0) 24282378Sjon POWER_ENABLE_SOCKET(device_get_parent(dev), dev); 24367333Simp if (pccard_function_enable(pf) == 0 && 24467333Simp device_probe_and_attach(child) == 0) { 24555500Simp DEVPRINTF((sc->dev, "function %d CCR at %d " 24667167Simp "offset %x: %x %x %x %x, %x %x %x %x, %x\n", 24767167Simp pf->number, pf->pf_ccr_window, pf->pf_ccr_offset, 24867167Simp pccard_ccr_read(pf, 0x00), 24952506Simp pccard_ccr_read(pf, 0x02), pccard_ccr_read(pf, 0x04), 25052506Simp pccard_ccr_read(pf, 0x06), pccard_ccr_read(pf, 0x0A), 25152506Simp pccard_ccr_read(pf, 0x0C), pccard_ccr_read(pf, 0x0E), 25252506Simp pccard_ccr_read(pf, 0x10), pccard_ccr_read(pf, 0x12))); 25367167Simp } else { 25486907Simp if (pf->cfe != NULL) 25586907Simp pccard_function_disable(pf); 25652506Simp } 25752506Simp } 25874632Simp return (0); 25952506Simp} 26052506Simp 26159193Simpstatic int 26259193Simppccard_detach_card(device_t dev, int flags) 26352506Simp{ 26464850Simp struct pccard_softc *sc = PCCARD_SOFTC(dev); 26552506Simp struct pccard_function *pf; 26682378Sjon struct pccard_config_entry *cfe; 26752506Simp 26852506Simp /* 26952506Simp * We are running on either the PCCARD socket's event thread 27052506Simp * or in user context detaching a device by user request. 27152506Simp */ 27252506Simp STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) { 27382378Sjon int state = device_get_state(pf->dev); 27461788Simp 27582378Sjon if (state == DS_ATTACHED || state == DS_BUSY) 27682378Sjon device_detach(pf->dev); 27786907Simp if (pf->cfe != NULL) 27886907Simp pccard_function_disable(pf); 27982378Sjon pccard_function_free(pf); 28076424Simp if (pf->dev != NULL) 28164927Simp device_delete_child(dev, pf->dev); 28252506Simp } 28382378Sjon if (sc->sc_enabled_count == 0) 28482378Sjon POWER_DISABLE_SOCKET(device_get_parent(dev), dev); 28582378Sjon 28682378Sjon while (NULL != (pf = STAILQ_FIRST(&sc->card.pf_head))) { 28782378Sjon while (NULL != (cfe = STAILQ_FIRST(&pf->cfe_head))) { 28882378Sjon STAILQ_REMOVE_HEAD(&pf->cfe_head, cfe_list); 28982378Sjon free(cfe, M_DEVBUF); 29082378Sjon } 29182378Sjon STAILQ_REMOVE_HEAD(&sc->card.pf_head, pf_list); 29282378Sjon free(pf, M_DEVBUF); 29382378Sjon } 29474632Simp return (0); 29552506Simp} 29652506Simp 29797613Stakawatastatic const struct pccard_product * 29897613Stakawatapccard_do_product_lookup(device_t bus, device_t dev, 29997613Stakawata const struct pccard_product *tab, size_t ent_size, 30097613Stakawata pccard_product_match_fn matchfn) 30166200Simp{ 30266200Simp const struct pccard_product *ent; 30366200Simp int matches; 30466200Simp u_int32_t fcn; 30566200Simp u_int32_t vendor; 30666200Simp u_int32_t prod; 30766200Simp char *vendorstr; 30866200Simp char *prodstr; 30966200Simp 31066200Simp#ifdef DIAGNOSTIC 31166200Simp if (sizeof *ent > ent_size) 31270715Sjon panic("pccard_product_lookup: bogus ent_size %ld", 31366200Simp (long) ent_size); 31466200Simp#endif 31566200Simp if (pccard_get_vendor(dev, &vendor)) 31666200Simp return (NULL); 31766200Simp if (pccard_get_product(dev, &prod)) 31866200Simp return (NULL); 31966200Simp if (pccard_get_function_number(dev, &fcn)) 32066200Simp return (NULL); 32166200Simp if (pccard_get_vendor_str(dev, &vendorstr)) 32266200Simp return (NULL); 32366200Simp if (pccard_get_product_str(dev, &prodstr)) 32466200Simp return (NULL); 32582378Sjon for (ent = tab; ent->pp_name != NULL; ent = 32682378Sjon (const struct pccard_product *) ((const char *) ent + ent_size)) { 32766200Simp matches = 1; 32886642Simp if (ent->pp_vendor == PCCARD_VENDOR_ANY && 32986642Simp ent->pp_product == PCCARD_VENDOR_ANY && 33086642Simp ent->pp_cis[0] == NULL && 33186642Simp ent->pp_cis[1] == NULL) { 33286642Simp device_printf(dev, 33386642Simp "Total wildcard entry ignored for %s\n", 33486642Simp ent->pp_name); 33586642Simp continue; 33686642Simp } 33766200Simp if (matches && ent->pp_vendor != PCCARD_VENDOR_ANY && 33866200Simp vendor != ent->pp_vendor) 33966200Simp matches = 0; 34066200Simp if (matches && ent->pp_product != PCCARD_PRODUCT_ANY && 34166200Simp prod != ent->pp_product) 34266200Simp matches = 0; 34366200Simp if (matches && fcn != ent->pp_expfunc) 34466200Simp matches = 0; 34571322Simp if (matches && ent->pp_cis[0] && 34671322Simp strcmp(ent->pp_cis[0], vendorstr) != 0) 34766200Simp matches = 0; 34871322Simp if (matches && ent->pp_cis[1] && 34971322Simp strcmp(ent->pp_cis[1], prodstr) != 0) 35066200Simp matches = 0; 35171322Simp /* XXX need to match cis[2] and cis[3] also XXX */ 35266200Simp if (matchfn != NULL) 35366200Simp matches = (*matchfn)(dev, ent, matches); 35466200Simp if (matches) 35566200Simp return (ent); 35666200Simp } 35766200Simp return (NULL); 35866200Simp} 35966200Simp 36070715Sjonstatic int 36159193Simppccard_card_gettype(device_t dev, int *type) 36252506Simp{ 36364850Simp struct pccard_softc *sc = PCCARD_SOFTC(dev); 36452506Simp struct pccard_function *pf; 36552506Simp 36652506Simp /* 36752506Simp * set the iftype to memory if this card has no functions (not yet 36852506Simp * probed), or only one function, and that is not initialized yet or 36952506Simp * that is memory. 37052506Simp */ 37152506Simp pf = STAILQ_FIRST(&sc->card.pf_head); 37252506Simp if (pf == NULL || 37352506Simp (STAILQ_NEXT(pf, pf_list) == NULL && 37452506Simp (pf->cfe == NULL || pf->cfe->iftype == PCCARD_IFTYPE_MEMORY))) 37559193Simp *type = PCCARD_IFTYPE_MEMORY; 37652506Simp else 37759193Simp *type = PCCARD_IFTYPE_IO; 37874632Simp return (0); 37952506Simp} 38052506Simp 38152506Simp/* 38252506Simp * Initialize a PCCARD function. May be called as long as the function is 38352506Simp * disabled. 38482382Simp * 38582382Simp * Note: pccard_function_init should not keep resources allocated. It should 38682382Simp * only set them up ala isa pnp, set the values in the rl lists, and return. 38782382Simp * Any resource held after pccard_function_init is called is a bug. However, 38882382Simp * the bus routines to get the resources also assume that pccard_function_init 38982382Simp * does this, so they need to be fixed too. 39052506Simp */ 39182378Sjonstatic void 39270715Sjonpccard_function_init(struct pccard_function *pf) 39352506Simp{ 39465917Simp struct pccard_config_entry *cfe; 39567187Simp int i; 39667242Simp struct pccard_ivar *devi = PCCARD_IVAR(pf->dev); 39767242Simp struct resource_list *rl = &devi->resources; 39870762Simp struct resource_list_entry *rle; 39967242Simp struct resource *r = 0; 40067242Simp device_t bus; 40167424Simp int start; 40267424Simp int end; 40390897Simp int spaces; 40465917Simp 40570715Sjon if (pf->pf_flags & PFF_ENABLED) { 40670715Sjon printf("pccard_function_init: function is enabled"); 40770715Sjon return; 40870715Sjon } 40967242Simp bus = device_get_parent(pf->dev); 41052506Simp /* Remember which configuration entry we are using. */ 41172012Sphk STAILQ_FOREACH(cfe, &pf->cfe_head, cfe_list) { 41267187Simp for (i = 0; i < cfe->num_iospace; i++) 41367187Simp cfe->iores[i] = NULL; 41467187Simp cfe->irqres = NULL; 41590897Simp spaces = 0; 41667187Simp for (i = 0; i < cfe->num_iospace; i++) { 41767424Simp start = cfe->iospace[i].start; 41867424Simp if (start) 41967424Simp end = start + cfe->iospace[i].length - 1; 42067424Simp else 42167424Simp end = ~0; 42267187Simp cfe->iorid[i] = i; 42390897Simp DEVPRINTF((bus, "I/O rid %d start %x end %x\n", 42490897Simp i, start, end)); 42567242Simp r = cfe->iores[i] = bus_alloc_resource(bus, 42667424Simp SYS_RES_IOPORT, &cfe->iorid[i], start, end, 42770715Sjon cfe->iospace[i].length, 42867424Simp rman_make_alignment_flags(cfe->iospace[i].length)); 42976424Simp if (cfe->iores[i] == NULL) 43067187Simp goto not_this_one; 43167242Simp resource_list_add(rl, SYS_RES_IOPORT, cfe->iorid[i], 43267242Simp rman_get_start(r), rman_get_end(r), 43367242Simp cfe->iospace[i].length); 43476424Simp rle = resource_list_find(rl, SYS_RES_IOPORT, 43576424Simp cfe->iorid[i]); 43676424Simp rle->res = r; 43790897Simp spaces++; 43867187Simp } 43967187Simp if (cfe->num_memspace > 0) { 44082781Sshiba /* 44182781Sshiba * Not implement yet, Fix me. 44282781Sshiba */ 44390897Simp DEVPRINTF((bus, "Memory space not yet implemented.\n")); 44467187Simp } 44590897Simp if (spaces == 0) { 44690897Simp DEVPRINTF((bus, "Neither memory nor I/O mampped\n")); 44790897Simp goto not_this_one; 44890897Simp } 44967187Simp if (cfe->irqmask) { 45067187Simp cfe->irqrid = 0; 45167399Simp r = cfe->irqres = bus_alloc_resource(bus, SYS_RES_IRQ, 45267424Simp &cfe->irqrid, 0, ~0, 1, 0); 45376424Simp if (cfe->irqres == NULL) 45467187Simp goto not_this_one; 45567242Simp resource_list_add(rl, SYS_RES_IRQ, cfe->irqrid, 45667242Simp rman_get_start(r), rman_get_end(r), 1); 45776424Simp rle = resource_list_find(rl, SYS_RES_IRQ, 45876424Simp cfe->irqrid); 45976424Simp rle->res = r; 46067187Simp } 46167187Simp /* If we get to here, we've allocated all we need */ 46267167Simp pf->cfe = cfe; 46367187Simp break; 46467187Simp not_this_one:; 46567424Simp DEVPRVERBOSE((bus, "Allocation failed for cfe %d\n", 46667424Simp cfe->number)); 46767333Simp /* 46867333Simp * Release resources that we partially allocated 46967333Simp * from this config entry. 47067333Simp */ 47167187Simp for (i = 0; i < cfe->num_iospace; i++) { 47276424Simp if (cfe->iores[i] != NULL) { 47370715Sjon bus_release_resource(bus, SYS_RES_IOPORT, 47467187Simp cfe->iorid[i], cfe->iores[i]); 47582378Sjon rle = resource_list_find(rl, SYS_RES_IOPORT, 47676424Simp cfe->iorid[i]); 47776424Simp rle->res = NULL; 47876424Simp resource_list_delete(rl, SYS_RES_IOPORT, 47976424Simp cfe->iorid[i]); 48075756Simp } 48167187Simp cfe->iores[i] = NULL; 48267187Simp } 48376424Simp if (cfe->irqmask && cfe->irqres != NULL) { 48467242Simp bus_release_resource(bus, SYS_RES_IRQ, 48567187Simp cfe->irqrid, cfe->irqres); 48676424Simp rle = resource_list_find(rl, SYS_RES_IRQ, 48776424Simp cfe->irqrid); 48876424Simp rle->res = NULL; 48976424Simp resource_list_delete(rl, SYS_RES_IRQ, cfe->irqrid); 49067187Simp cfe->irqres = NULL; 49167187Simp } 49267167Simp } 49352506Simp} 49452506Simp 49582378Sjon/* 49682378Sjon * Free resources allocated by pccard_function_init(), May be called as long 49782378Sjon * as the function is disabled. 49882382Simp * 49982382Simp * NOTE: This function should be unnecessary. pccard_function_init should 50082382Simp * never keep resources initialized. 50182378Sjon */ 50282378Sjonstatic void 50382378Sjonpccard_function_free(struct pccard_function *pf) 50482378Sjon{ 50582378Sjon struct pccard_ivar *devi = PCCARD_IVAR(pf->dev); 50682378Sjon struct resource_list_entry *rle; 50782378Sjon 50882378Sjon if (pf->pf_flags & PFF_ENABLED) { 50982378Sjon printf("pccard_function_init: function is enabled"); 51082378Sjon return; 51182378Sjon } 51282378Sjon 51382378Sjon SLIST_FOREACH(rle, &devi->resources, link) { 51482378Sjon if (rle->res) { 51582378Sjon if (rle->res->r_dev != pf->sc->dev) 51682378Sjon device_printf(pf->sc->dev, 51782378Sjon "function_free: Resource still owned by " 51882378Sjon "child, oops. " 51982378Sjon "(type=%d, rid=%d, addr=%lx)\n", 52082378Sjon rle->type, rle->rid, 52182378Sjon rman_get_start(rle->res)); 52282378Sjon BUS_RELEASE_RESOURCE(device_get_parent(pf->sc->dev), 52382378Sjon rle->res->r_dev, rle->type, rle->rid, rle->res); 52482378Sjon rle->res = NULL; 52582378Sjon } 52682378Sjon } 52782378Sjon resource_list_free(&devi->resources); 52882378Sjon} 52982378Sjon 53052506Simp/* Enable a PCCARD function */ 53182378Sjonstatic int 53255720Simppccard_function_enable(struct pccard_function *pf) 53352506Simp{ 53452506Simp struct pccard_function *tmp; 53552506Simp int reg; 53655720Simp device_t dev = pf->sc->dev; 53770746Simp 53867333Simp if (pf->cfe == NULL) { 53967333Simp DEVPRVERBOSE((dev, "No config entry could be allocated.\n")); 54074632Simp return (ENOMEM); 54167333Simp } 54252506Simp 54352506Simp /* 54452506Simp * Increase the reference count on the socket, enabling power, if 54552506Simp * necessary. 54652506Simp */ 54782378Sjon pf->sc->sc_enabled_count++; 54852506Simp 54952506Simp if (pf->pf_flags & PFF_ENABLED) { 55052506Simp /* 55152506Simp * Don't do anything if we're already enabled. 55252506Simp */ 55352506Simp return (0); 55452506Simp } 55552506Simp 55652506Simp /* 55752506Simp * it's possible for different functions' CCRs to be in the same 55852506Simp * underlying page. Check for that. 55952506Simp */ 56052506Simp STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) { 56152506Simp if ((tmp->pf_flags & PFF_ENABLED) && 56252506Simp (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) && 56352506Simp ((pf->ccr_base + PCCARD_CCR_SIZE) <= 56482378Sjon (tmp->ccr_base - tmp->pf_ccr_offset + 56582378Sjon tmp->pf_ccr_realsize))) { 56652506Simp pf->pf_ccrt = tmp->pf_ccrt; 56752506Simp pf->pf_ccrh = tmp->pf_ccrh; 56852506Simp pf->pf_ccr_realsize = tmp->pf_ccr_realsize; 56952506Simp 57052506Simp /* 57152506Simp * pf->pf_ccr_offset = (tmp->pf_ccr_offset - 57252506Simp * tmp->ccr_base) + pf->ccr_base; 57352506Simp */ 57470715Sjon /* pf->pf_ccr_offset = 57552506Simp (tmp->pf_ccr_offset + pf->ccr_base) - 57670715Sjon tmp->ccr_base; */ 57752506Simp pf->pf_ccr_window = tmp->pf_ccr_window; 57852506Simp break; 57952506Simp } 58052506Simp } 58152506Simp if (tmp == NULL) { 58255720Simp pf->ccr_rid = 0; 58355720Simp pf->ccr_res = bus_alloc_resource(dev, SYS_RES_MEMORY, 58470715Sjon &pf->ccr_rid, 0, ~0, 1 << 10, RF_ACTIVE); 58570715Sjon if (!pf->ccr_res) 58652506Simp goto bad; 58770746Simp DEVPRINTF((dev, "ccr_res == %lx-%lx, base=%lx\n", 58870746Simp rman_get_start(pf->ccr_res), rman_get_end(pf->ccr_res), 58970746Simp pf->ccr_base)); 59061788Simp CARD_SET_RES_FLAGS(device_get_parent(dev), dev, SYS_RES_MEMORY, 59161788Simp pf->ccr_rid, PCCARD_A_MEM_ATTR); 59270715Sjon CARD_SET_MEMORY_OFFSET(device_get_parent(dev), dev, 59370748Simp pf->ccr_rid, pf->ccr_base, &pf->pf_ccr_offset); 59455720Simp pf->pf_ccrt = rman_get_bustag(pf->ccr_res); 59555720Simp pf->pf_ccrh = rman_get_bushandle(pf->ccr_res); 59655720Simp pf->pf_ccr_realsize = 1; 59752506Simp } 59852506Simp 59952506Simp reg = (pf->cfe->number & PCCARD_CCR_OPTION_CFINDEX); 60052506Simp reg |= PCCARD_CCR_OPTION_LEVIREQ; 60152506Simp if (pccard_mfc(pf->sc)) { 60252506Simp reg |= (PCCARD_CCR_OPTION_FUNC_ENABLE | 60352506Simp PCCARD_CCR_OPTION_ADDR_DECODE); 60482383Simp /* PCCARD_CCR_OPTION_IRQ_ENABLE set elsewhere as needed */ 60552506Simp } 60652506Simp pccard_ccr_write(pf, PCCARD_CCR_OPTION, reg); 60752506Simp 60852506Simp reg = 0; 60952506Simp if ((pf->cfe->flags & PCCARD_CFE_IO16) == 0) 61052506Simp reg |= PCCARD_CCR_STATUS_IOIS8; 61152506Simp if (pf->cfe->flags & PCCARD_CFE_AUDIO) 61252506Simp reg |= PCCARD_CCR_STATUS_AUDIO; 61352506Simp pccard_ccr_write(pf, PCCARD_CCR_STATUS, reg); 61452506Simp 61552506Simp pccard_ccr_write(pf, PCCARD_CCR_SOCKETCOPY, 0); 61652506Simp 61752506Simp if (pccard_mfc(pf->sc)) { 61852506Simp long tmp, iosize; 61952506Simp 62052506Simp tmp = pf->pf_mfc_iomax - pf->pf_mfc_iobase; 62152506Simp /* round up to nearest (2^n)-1 */ 62252506Simp for (iosize = 1; iosize < tmp; iosize <<= 1) 62352506Simp ; 62452506Simp iosize--; 62552506Simp 62652506Simp pccard_ccr_write(pf, PCCARD_CCR_IOBASE0, 62752506Simp pf->pf_mfc_iobase & 0xff); 62852506Simp pccard_ccr_write(pf, PCCARD_CCR_IOBASE1, 62952506Simp (pf->pf_mfc_iobase >> 8) & 0xff); 63052506Simp pccard_ccr_write(pf, PCCARD_CCR_IOBASE2, 0); 63152506Simp pccard_ccr_write(pf, PCCARD_CCR_IOBASE3, 0); 63252506Simp 63352506Simp pccard_ccr_write(pf, PCCARD_CCR_IOSIZE, iosize); 63452506Simp } 63552506Simp 63652506Simp#ifdef PCCARDDEBUG 63752506Simp if (pccard_debug) { 63852506Simp STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) { 63970715Sjon device_printf(tmp->sc->dev, 64055500Simp "function %d CCR at %d offset %x: " 64155500Simp "%x %x %x %x, %x %x %x %x, %x\n", 64270715Sjon tmp->number, tmp->pf_ccr_window, 64355500Simp tmp->pf_ccr_offset, 64455500Simp pccard_ccr_read(tmp, 0x00), 64555500Simp pccard_ccr_read(tmp, 0x02), 64655500Simp pccard_ccr_read(tmp, 0x04), 64755500Simp pccard_ccr_read(tmp, 0x06), 64855500Simp pccard_ccr_read(tmp, 0x0A), 64970715Sjon pccard_ccr_read(tmp, 0x0C), 65055500Simp pccard_ccr_read(tmp, 0x0E), 65155500Simp pccard_ccr_read(tmp, 0x10), 65255500Simp pccard_ccr_read(tmp, 0x12)); 65352506Simp } 65452506Simp } 65552506Simp#endif 65652506Simp pf->pf_flags |= PFF_ENABLED; 65752506Simp return (0); 65852506Simp 65952506Simp bad: 66052506Simp /* 66152506Simp * Decrement the reference count, and power down the socket, if 66252506Simp * necessary. 66352506Simp */ 66482378Sjon pf->sc->sc_enabled_count--; 66565098Simp DEVPRINTF((dev, "bad --enabled_count = %d\n", pf->sc->sc_enabled_count)); 66652506Simp 66752506Simp return (1); 66852506Simp} 66952506Simp 67052506Simp/* Disable PCCARD function. */ 67182378Sjonstatic void 67255720Simppccard_function_disable(struct pccard_function *pf) 67352506Simp{ 67452506Simp struct pccard_function *tmp; 67555720Simp device_t dev = pf->sc->dev; 67652506Simp 67752506Simp if (pf->cfe == NULL) 67861788Simp panic("pccard_function_disable: function not initialized"); 67952506Simp 68052506Simp if ((pf->pf_flags & PFF_ENABLED) == 0) { 68152506Simp /* 68252506Simp * Don't do anything if we're already disabled. 68352506Simp */ 68452506Simp return; 68552506Simp } 68652506Simp 68770715Sjon if (pf->intr_handler != NULL) { 68882378Sjon struct pccard_ivar *devi = PCCARD_IVAR(pf->dev); 68982378Sjon struct resource_list_entry *rle = 69082378Sjon resource_list_find(&devi->resources, SYS_RES_IRQ, 0); 69182378Sjon BUS_TEARDOWN_INTR(dev, pf->dev, rle->res, 69282378Sjon pf->intr_handler_cookie); 69370715Sjon } 69470715Sjon 69552506Simp /* 69652506Simp * it's possible for different functions' CCRs to be in the same 69752506Simp * underlying page. Check for that. Note we mark us as disabled 69852506Simp * first to avoid matching ourself. 69952506Simp */ 70052506Simp 70152506Simp pf->pf_flags &= ~PFF_ENABLED; 70252506Simp STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) { 70352506Simp if ((tmp->pf_flags & PFF_ENABLED) && 70452506Simp (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) && 70552506Simp ((pf->ccr_base + PCCARD_CCR_SIZE) <= 70682378Sjon (tmp->ccr_base - tmp->pf_ccr_offset + 70782378Sjon tmp->pf_ccr_realsize))) 70852506Simp break; 70952506Simp } 71052506Simp 71152506Simp /* Not used by anyone else; unmap the CCR. */ 71252506Simp if (tmp == NULL) { 71370715Sjon bus_release_resource(dev, SYS_RES_MEMORY, pf->ccr_rid, 71455720Simp pf->ccr_res); 71555720Simp pf->ccr_res = NULL; 71652506Simp } 71752506Simp 71852506Simp /* 71952506Simp * Decrement the reference count, and power down the socket, if 72052506Simp * necessary. 72152506Simp */ 72282378Sjon pf->sc->sc_enabled_count--; 72352506Simp} 72452506Simp 72566058Simp/* 72666058Simp * simulate the old "probe" routine. In the new world order, the driver 72766058Simp * needs to grab devices while in the old they were assigned to the device by 72866058Simp * the pccardd process. These symbols are exported to the upper layers. 72966058Simp */ 73074636Simpstatic int 73174636Simppccard_compat_do_probe(device_t bus, device_t dev) 73266058Simp{ 73366058Simp return (CARD_COMPAT_MATCH(dev)); 73466058Simp} 73566058Simp 73674636Simpstatic int 73774636Simppccard_compat_do_attach(device_t bus, device_t dev) 73866058Simp{ 73966058Simp int err; 74066058Simp 74166058Simp err = CARD_COMPAT_PROBE(dev); 74266058Simp if (err == 0) 74366058Simp err = CARD_COMPAT_ATTACH(dev); 74466058Simp return (err); 74566058Simp} 74666058Simp 74753873Simp#define PCCARD_NPORT 2 74853873Simp#define PCCARD_NMEM 5 74953873Simp#define PCCARD_NIRQ 1 75053873Simp#define PCCARD_NDRQ 0 75153873Simp 75252506Simpstatic int 75352506Simppccard_add_children(device_t dev, int busno) 75452506Simp{ 75559193Simp /* Call parent to scan for any current children */ 75674632Simp return (0); 75752506Simp} 75852506Simp 75952506Simpstatic int 76052506Simppccard_probe(device_t dev) 76152506Simp{ 76267333Simp device_set_desc(dev, "16-bit PCCard bus"); 76374632Simp return (pccard_add_children(dev, device_get_unit(dev))); 76452506Simp} 76552506Simp 76659193Simpstatic int 76759193Simppccard_attach(device_t dev) 76859193Simp{ 76964850Simp struct pccard_softc *sc = PCCARD_SOFTC(dev); 77061788Simp 77159193Simp sc->dev = dev; 77261788Simp sc->sc_enabled_count = 0; 77374632Simp return (bus_generic_attach(dev)); 77459193Simp} 77559193Simp 77682378Sjonstatic int 77782378Sjonpccard_detach(device_t dev) 77882378Sjon{ 77982378Sjon pccard_detach_card(dev, 0); 78082378Sjon return 0; 78182378Sjon} 78282378Sjon 78387975Simpstatic int 78487975Simppccard_suspend(device_t self) 78587975Simp{ 78687975Simp pccard_detach_card(self, 0); 78787975Simp return (0); 78887975Simp} 78987975Simp 79087975Simpstatic 79187975Simpint 79287975Simppccard_resume(device_t self) 79387975Simp{ 79487975Simp return (0); 79587975Simp} 79687975Simp 79753873Simpstatic void 79853873Simppccard_print_resources(struct resource_list *rl, const char *name, int type, 79953873Simp int count, const char *format) 80053873Simp{ 80153873Simp struct resource_list_entry *rle; 80253873Simp int printed; 80353873Simp int i; 80453873Simp 80553873Simp printed = 0; 80653873Simp for (i = 0; i < count; i++) { 80753873Simp rle = resource_list_find(rl, type, i); 80876424Simp if (rle != NULL) { 80953873Simp if (printed == 0) 81053873Simp printf(" %s ", name); 81153873Simp else if (printed > 0) 81253873Simp printf(","); 81353873Simp printed++; 81453873Simp printf(format, rle->start); 81553873Simp if (rle->count > 1) { 81653873Simp printf("-"); 81753873Simp printf(format, rle->start + rle->count - 1); 81853873Simp } 81953873Simp } else if (i > 3) { 82053873Simp /* check the first few regardless */ 82153873Simp break; 82253873Simp } 82353873Simp } 82453873Simp} 82553873Simp 82653873Simpstatic int 82753873Simppccard_print_child(device_t dev, device_t child) 82853873Simp{ 82966847Simp struct pccard_ivar *devi = PCCARD_IVAR(child); 83053873Simp struct resource_list *rl = &devi->resources; 83153873Simp int retval = 0; 83253873Simp 83353873Simp retval += bus_print_child_header(dev, child); 83453873Simp retval += printf(" at"); 83553873Simp 83676424Simp if (devi != NULL) { 83753873Simp pccard_print_resources(rl, "port", SYS_RES_IOPORT, 83853873Simp PCCARD_NPORT, "%#lx"); 83953873Simp pccard_print_resources(rl, "iomem", SYS_RES_MEMORY, 84053873Simp PCCARD_NMEM, "%#lx"); 84153873Simp pccard_print_resources(rl, "irq", SYS_RES_IRQ, PCCARD_NIRQ, 84253873Simp "%ld"); 84370715Sjon pccard_print_resources(rl, "drq", SYS_RES_DRQ, PCCARD_NDRQ, 84453873Simp "%ld"); 84567269Simp retval += printf(" function %d config %d", devi->fcn->number, 84667269Simp devi->fcn->cfe->number); 84753873Simp } 84853873Simp 84953873Simp retval += bus_print_child_footer(dev, child); 85053873Simp 85153873Simp return (retval); 85253873Simp} 85353873Simp 85453873Simpstatic int 85553873Simppccard_set_resource(device_t dev, device_t child, int type, int rid, 85653873Simp u_long start, u_long count) 85753873Simp{ 85866847Simp struct pccard_ivar *devi = PCCARD_IVAR(child); 85953873Simp struct resource_list *rl = &devi->resources; 86053873Simp 86153873Simp if (type != SYS_RES_IOPORT && type != SYS_RES_MEMORY 86253873Simp && type != SYS_RES_IRQ && type != SYS_RES_DRQ) 86374632Simp return (EINVAL); 86453873Simp if (rid < 0) 86574632Simp return (EINVAL); 86653873Simp if (type == SYS_RES_IOPORT && rid >= PCCARD_NPORT) 86774632Simp return (EINVAL); 86853873Simp if (type == SYS_RES_MEMORY && rid >= PCCARD_NMEM) 86974632Simp return (EINVAL); 87053873Simp if (type == SYS_RES_IRQ && rid >= PCCARD_NIRQ) 87174632Simp return (EINVAL); 87253873Simp if (type == SYS_RES_DRQ && rid >= PCCARD_NDRQ) 87374632Simp return (EINVAL); 87453873Simp 87553873Simp resource_list_add(rl, type, rid, start, start + count - 1, count); 87682378Sjon if (NULL != resource_list_alloc(rl, device_get_parent(dev), dev, 87782378Sjon type, &rid, start, start + count - 1, count, 0)) 87882378Sjon return 0; 87982378Sjon else 88082378Sjon return ENOMEM; 88153873Simp} 88253873Simp 88353873Simpstatic int 88453873Simppccard_get_resource(device_t dev, device_t child, int type, int rid, 88553873Simp u_long *startp, u_long *countp) 88653873Simp{ 88766847Simp struct pccard_ivar *devi = PCCARD_IVAR(child); 88853873Simp struct resource_list *rl = &devi->resources; 88953873Simp struct resource_list_entry *rle; 89053873Simp 89153873Simp rle = resource_list_find(rl, type, rid); 89276424Simp if (rle == NULL) 89374632Simp return (ENOENT); 89470715Sjon 89576424Simp if (startp != NULL) 89653873Simp *startp = rle->start; 89776424Simp if (countp != NULL) 89853873Simp *countp = rle->count; 89953873Simp 90074632Simp return (0); 90153873Simp} 90253873Simp 90353873Simpstatic void 90453873Simppccard_delete_resource(device_t dev, device_t child, int type, int rid) 90553873Simp{ 90666847Simp struct pccard_ivar *devi = PCCARD_IVAR(child); 90753873Simp struct resource_list *rl = &devi->resources; 90853873Simp resource_list_delete(rl, type, rid); 90953873Simp} 91053873Simp 91159193Simpstatic int 91259193Simppccard_set_res_flags(device_t dev, device_t child, int type, int rid, 91359193Simp u_int32_t flags) 91459193Simp{ 91574632Simp return (CARD_SET_RES_FLAGS(device_get_parent(dev), child, type, 91674632Simp rid, flags)); 91759193Simp} 91859193Simp 91959193Simpstatic int 92059193Simppccard_set_memory_offset(device_t dev, device_t child, int rid, 92182378Sjon u_int32_t offset, u_int32_t *deltap) 92270715Sjon 92359193Simp{ 92474632Simp return (CARD_SET_MEMORY_OFFSET(device_get_parent(dev), child, rid, 92574632Simp offset, deltap)); 92659193Simp} 92759193Simp 928104641Simpstatic void 929104641Simppccard_probe_nomatch(device_t bus, device_t child) 930104641Simp{ 931104641Simp struct pccard_ivar *devi = PCCARD_IVAR(child); 932104641Simp struct pccard_function *func = devi->fcn; 933104641Simp struct pccard_softc *sc = PCCARD_SOFTC(bus); 934104641Simp 935104641Simp device_printf(bus, "<unknown card>"); 936104641Simp printf(" (manufacturer=0x%04x, product=0x%04x) at function %d\n", 937104641Simp sc->card.manufacturer, sc->card.product, func->number); 938104641Simp device_printf(bus, " CIS info: %s, %s, %s\n", sc->card.cis1_info[0], 939104641Simp sc->card.cis1_info[1], sc->card.cis1_info[2]); 940104641Simp return; 941104641Simp} 942104641Simp 94366058Simpstatic int 944104641Simppccard_child_location_str(device_t bus, device_t child, char *buf, 945104641Simp size_t buflen) 946104641Simp{ 947104641Simp struct pccard_ivar *devi = PCCARD_IVAR(child); 948104641Simp struct pccard_function *func = devi->fcn; 949104641Simp 950104641Simp snprintf(buf, buflen, "function=%d", func->number); 951104641Simp return (0); 952104641Simp} 953104641Simp 954104641Simpstatic int 955104641Simppccard_child_pnpinfo_str(device_t bus, device_t child, char *buf, 956104641Simp size_t buflen) 957104641Simp{ 958104641Simp struct pccard_ivar *devi = PCCARD_IVAR(child); 959104641Simp struct pccard_function *func = devi->fcn; 960104641Simp struct pccard_softc *sc = PCCARD_SOFTC(bus); 961104641Simp 962104641Simp snprintf(buf, buflen, "manufacturer=0x%04x product=0x%04x " 963104641Simp "cisvendor=\"%s\" cisproduct=\"%s\" function_type=%d", 964104641Simp sc->card.manufacturer, sc->card.product, sc->card.cis1_info[0], 965104641Simp sc->card.cis1_info[1], func->function); 966104641Simp return (0); 967104641Simp} 968104641Simp 969104641Simpstatic int 97066058Simppccard_read_ivar(device_t bus, device_t child, int which, u_char *result) 97166058Simp{ 97266847Simp struct pccard_ivar *devi = PCCARD_IVAR(child); 97366779Simp struct pccard_function *func = devi->fcn; 97466779Simp struct pccard_softc *sc = PCCARD_SOFTC(bus); 97566779Simp 97666779Simp switch (which) { 97766779Simp default: 97866779Simp case PCCARD_IVAR_ETHADDR: 97982781Sshiba bcopy(func->pf_funce_lan_nid, result, ETHER_ADDR_LEN); 98066779Simp break; 98166779Simp case PCCARD_IVAR_VENDOR: 98266779Simp *(u_int32_t *) result = sc->card.manufacturer; 98366779Simp break; 98466779Simp case PCCARD_IVAR_PRODUCT: 98566779Simp *(u_int32_t *) result = sc->card.product; 98666779Simp break; 98790964Sshiba case PCCARD_IVAR_PRODEXT: 98890964Sshiba *(u_int16_t *) result = sc->card.prodext; 98990964Sshiba break; 99075761Simp case PCCARD_IVAR_FUNCTION: 99175761Simp *(u_int32_t *) result = func->function; 99275761Simp break; 99366779Simp case PCCARD_IVAR_FUNCTION_NUMBER: 99466847Simp if (!func) { 99566847Simp device_printf(bus, "No function number, bug!\n"); 99666847Simp return (ENOENT); 99766847Simp } 99866847Simp *(u_int32_t *) result = func->number; 99966779Simp break; 100066779Simp case PCCARD_IVAR_VENDOR_STR: 100166779Simp *(char **) result = sc->card.cis1_info[0]; 100266779Simp break; 100366779Simp case PCCARD_IVAR_PRODUCT_STR: 100466779Simp *(char **) result = sc->card.cis1_info[1]; 100566779Simp break; 100666779Simp case PCCARD_IVAR_CIS3_STR: 100766779Simp *(char **) result = sc->card.cis1_info[2]; 100866779Simp break; 100967167Simp case PCCARD_IVAR_CIS4_STR: 1010104610Simp *(char **) result = sc->card.cis1_info[3]; 101167167Simp break; 101266779Simp } 101366779Simp return (0); 101466058Simp} 101566058Simp 101666779Simpstatic void 101766779Simppccard_driver_added(device_t dev, driver_t *driver) 101866779Simp{ 101982378Sjon struct pccard_softc *sc = PCCARD_SOFTC(dev); 102082378Sjon struct pccard_function *pf; 102182378Sjon device_t child; 102282378Sjon 102382378Sjon STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) { 102482378Sjon if (STAILQ_EMPTY(&pf->cfe_head)) 102582378Sjon continue; 102682378Sjon child = pf->dev; 102782378Sjon if (device_get_state(child) != DS_NOTPRESENT) 102882378Sjon continue; 102982378Sjon if (pccard_function_enable(pf) == 0 && 103082378Sjon device_probe_and_attach(child) == 0) { 103182378Sjon DEVPRINTF((sc->dev, "function %d CCR at %d " 103282378Sjon "offset %x: %x %x %x %x, %x %x %x %x, %x\n", 103382378Sjon pf->number, pf->pf_ccr_window, pf->pf_ccr_offset, 103482378Sjon pccard_ccr_read(pf, 0x00), 103582378Sjon pccard_ccr_read(pf, 0x02), pccard_ccr_read(pf, 0x04), 103682378Sjon pccard_ccr_read(pf, 0x06), pccard_ccr_read(pf, 0x0A), 103782378Sjon pccard_ccr_read(pf, 0x0C), pccard_ccr_read(pf, 0x0E), 103882378Sjon pccard_ccr_read(pf, 0x10), pccard_ccr_read(pf, 0x12))); 103982378Sjon } else { 104086907Simp if (pf->cfe != NULL) 104186907Simp pccard_function_disable(pf); 104282378Sjon } 104382378Sjon } 104482378Sjon return; 104566779Simp} 104666058Simp 104767242Simpstatic struct resource * 104867242Simppccard_alloc_resource(device_t dev, device_t child, int type, int *rid, 104967242Simp u_long start, u_long end, u_long count, u_int flags) 105067242Simp{ 105182378Sjon struct pccard_ivar *dinfo; 105282378Sjon struct resource_list_entry *rle = 0; 105382378Sjon int passthrough = (device_get_parent(child) != dev); 1054104641Simp struct resource *r = NULL; 105567242Simp 105682378Sjon if (passthrough) { 105782378Sjon return (BUS_ALLOC_RESOURCE(device_get_parent(dev), child, 105882378Sjon type, rid, start, end, count, flags)); 105982378Sjon } 106070715Sjon 106182378Sjon dinfo = device_get_ivars(child); 106282378Sjon rle = resource_list_find(&dinfo->resources, type, *rid); 106370715Sjon 1064104641Simp if (rle == NULL) 1065104641Simp return (NULL); /* no resource of that type/rid */ 106670715Sjon 1067104641Simp if (rle->res == NULL) { 106882378Sjon switch(type) { 106982378Sjon case SYS_RES_IOPORT: 1070104641Simp r = bus_alloc_resource(dev, type, rid, start, end, 1071104641Simp count, rman_make_alignment_flags(count)); 1072104641Simp if (r == NULL) 1073104641Simp goto bad; 1074104641Simp resource_list_add(&dinfo->resources, type, *rid, 1075104641Simp rman_get_start(r), rman_get_end(r), count); 1076104641Simp rle = resource_list_find(&dinfo->resources, type, *rid); 1077104641Simp if (!rle) 1078104641Simp goto bad; 1079104641Simp rle->res = r; 1080104641Simp break; 108182378Sjon case SYS_RES_MEMORY: 108282378Sjon break; 108382378Sjon case SYS_RES_IRQ: 108482378Sjon break; 108582378Sjon } 108690897Simp return (rle->res); 108767269Simp } 1088104641Simp if (rle->res->r_dev != dev) 1089104641Simp return (NULL); 1090104641Simp bus_release_resource(dev, type, *rid, rle->res); 1091104641Simp rle->res = NULL; 1092104641Simp switch(type) { 1093104641Simp case SYS_RES_IOPORT: 1094104641Simp case SYS_RES_MEMORY: 1095104641Simp if (!(flags & RF_ALIGNMENT_MASK)) 1096104641Simp flags |= rman_make_alignment_flags(rle->count); 1097104641Simp break; 1098104641Simp case SYS_RES_IRQ: 1099104641Simp flags |= RF_SHAREABLE; 1100104641Simp break; 1101104641Simp } 1102104641Simp rle->res = resource_list_alloc(&dinfo->resources, dev, child, 1103104641Simp type, rid, rle->start, rle->end, rle->count, flags); 1104104641Simp return (rle->res); 1105104641Simpbad:; 1106104641Simp device_printf(dev, "WARNING: Resource not reserved by pccard\n"); 1107104641Simp return (NULL); 110867242Simp} 110967242Simp 111067242Simpstatic int 111167242Simppccard_release_resource(device_t dev, device_t child, int type, int rid, 111267242Simp struct resource *r) 111367242Simp{ 111482378Sjon struct pccard_ivar *dinfo; 111582378Sjon int passthrough = (device_get_parent(child) != dev); 111682378Sjon struct resource_list_entry *rle = 0; 111782378Sjon int ret; 111882378Sjon int flags; 111970715Sjon 112082378Sjon if (passthrough) 112182378Sjon return BUS_RELEASE_RESOURCE(device_get_parent(dev), child, 112282378Sjon type, rid, r); 112370715Sjon 112482378Sjon dinfo = device_get_ivars(child); 112570715Sjon 112682378Sjon rle = resource_list_find(&dinfo->resources, type, rid); 112770715Sjon 112882378Sjon if (!rle) { 112982378Sjon device_printf(dev, "Allocated resource not found, " 113082378Sjon "%d %x %lx %lx\n", 113182378Sjon type, rid, rman_get_start(r), rman_get_size(r)); 113282378Sjon return ENOENT; 113370715Sjon } 113482378Sjon if (!rle->res) { 113582378Sjon device_printf(dev, "Allocated resource not recorded\n"); 113682378Sjon return ENOENT; 113770715Sjon } 113870715Sjon 113982378Sjon ret = BUS_RELEASE_RESOURCE(device_get_parent(dev), child, 114082378Sjon type, rid, r); 114182378Sjon switch(type) { 114282378Sjon case SYS_RES_IOPORT: 114382378Sjon case SYS_RES_MEMORY: 114482378Sjon flags = rman_make_alignment_flags(rle->count); 114582378Sjon break; 114682378Sjon case SYS_RES_IRQ: 114782378Sjon flags = RF_SHAREABLE; 114882378Sjon break; 114982378Sjon default: 115082378Sjon flags = 0; 115170715Sjon } 115282378Sjon rle->res = bus_alloc_resource(dev, type, &rid, 115382378Sjon rle->start, rle->end, rle->count, flags); 115482378Sjon if (rle->res == NULL) 115582378Sjon device_printf(dev, "release_resource: " 115682378Sjon "unable to reaquire resource\n"); 115782378Sjon return ret; 115867242Simp} 115967242Simp 116067333Simpstatic void 116167333Simppccard_child_detached(device_t parent, device_t dev) 116267333Simp{ 116367333Simp struct pccard_ivar *ivar = PCCARD_IVAR(dev); 116482378Sjon struct pccard_function *pf = ivar->fcn; 116567333Simp 116682378Sjon pccard_function_disable(pf); 116767333Simp} 116867333Simp 116970715Sjonstatic void 117070762Simppccard_intr(void *arg) 117170762Simp{ 117282378Sjon struct pccard_function *pf = (struct pccard_function*) arg; 117382378Sjon int reg; 1174102923Simp int doisr = 1; 117582378Sjon 117682383Simp /* 1177102923Simp * MFC cards know if they interrupted, so we have to ack the 1178102923Simp * interrupt and call the ISR. Non-MFC cards don't have these 1179102923Simp * bits, so they always get called. Many non-MFC cards have 1180102923Simp * this bit set always upon read, but some do not. 1181102923Simp * 1182102923Simp * We always ack the interrupt, even if there's no ISR 1183102923Simp * for the card. This is done on the theory that acking 1184102923Simp * the interrupt will pacify the card enough to keep an 1185102923Simp * interrupt storm from happening. Of course this won't 1186102923Simp * help in the non-MFC case. 118782383Simp */ 1188102923Simp if (pccard_mfc(pf->sc)) { 1189102923Simp reg = pccard_ccr_read(pf, PCCARD_CCR_STATUS); 1190102923Simp if (reg & PCCARD_CCR_STATUS_INTR) 1191102923Simp pccard_ccr_write(pf, PCCARD_CCR_STATUS, 1192102923Simp reg & ~PCCARD_CCR_STATUS_INTR); 1193102923Simp else 1194102923Simp doisr = 0; 1195102923Simp } 1196102923Simp if (pf->intr_handler != NULL && doisr) 119782378Sjon pf->intr_handler(pf->intr_handler_arg); 119870715Sjon} 119970715Sjon 120070715Sjonstatic int 120170762Simppccard_setup_intr(device_t dev, device_t child, struct resource *irq, 120270762Simp int flags, driver_intr_t *intr, void *arg, void **cookiep) 120370715Sjon{ 1204102713Simp struct pccard_softc *sc = PCCARD_SOFTC(dev); 120570715Sjon struct pccard_ivar *ivar = PCCARD_IVAR(child); 120670715Sjon struct pccard_function *func = ivar->fcn; 120790445Simp int err; 120870715Sjon 120970715Sjon if (func->intr_handler != NULL) 1210101762Simp panic("Only one interrupt handler per function allowed"); 121190445Simp err = bus_generic_setup_intr(dev, child, irq, flags, pccard_intr, 121290445Simp func, cookiep); 121390445Simp if (err != 0) 121490445Simp return (err); 121570715Sjon func->intr_handler = intr; 121670715Sjon func->intr_handler_arg = arg; 121782378Sjon func->intr_handler_cookie = *cookiep; 1218102713Simp if (pccard_mfc(sc)) { 1219102713Simp pccard_ccr_write(func, PCCARD_CCR_OPTION, 1220102713Simp pccard_ccr_read(func, PCCARD_CCR_OPTION) | 1221102713Simp PCCARD_CCR_OPTION_IREQ_ENABLE); 1222102713Simp } 122374632Simp return (0); 122470715Sjon} 122570715Sjon 122670715Sjonstatic int 122770762Simppccard_teardown_intr(device_t dev, device_t child, struct resource *r, 122870762Simp void *cookie) 122970715Sjon{ 1230102713Simp struct pccard_softc *sc = PCCARD_SOFTC(dev); 123170715Sjon struct pccard_ivar *ivar = PCCARD_IVAR(child); 123270715Sjon struct pccard_function *func = ivar->fcn; 123382378Sjon int ret; 123470715Sjon 1235102713Simp if (pccard_mfc(sc)) { 1236102713Simp pccard_ccr_write(func, PCCARD_CCR_OPTION, 1237102713Simp pccard_ccr_read(func, PCCARD_CCR_OPTION) & 1238102713Simp ~PCCARD_CCR_OPTION_IREQ_ENABLE); 1239102713Simp } 124090445Simp ret = bus_generic_teardown_intr(dev, child, r, cookie); 124182378Sjon if (ret == 0) { 124282378Sjon func->intr_handler = NULL; 124382378Sjon func->intr_handler_arg = NULL; 124482378Sjon func->intr_handler_cookie = NULL; 124582378Sjon } 124670715Sjon 124782378Sjon return (ret); 124870715Sjon} 124970715Sjon 125052506Simpstatic device_method_t pccard_methods[] = { 125152506Simp /* Device interface */ 125252506Simp DEVMETHOD(device_probe, pccard_probe), 125359193Simp DEVMETHOD(device_attach, pccard_attach), 125482378Sjon DEVMETHOD(device_detach, pccard_detach), 125552506Simp DEVMETHOD(device_shutdown, bus_generic_shutdown), 125687975Simp DEVMETHOD(device_suspend, pccard_suspend), 125787975Simp DEVMETHOD(device_resume, pccard_resume), 125852506Simp 125952506Simp /* Bus interface */ 126052506Simp DEVMETHOD(bus_print_child, pccard_print_child), 126166779Simp DEVMETHOD(bus_driver_added, pccard_driver_added), 126267333Simp DEVMETHOD(bus_child_detached, pccard_child_detached), 126367242Simp DEVMETHOD(bus_alloc_resource, pccard_alloc_resource), 126467242Simp DEVMETHOD(bus_release_resource, pccard_release_resource), 126582378Sjon DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 126682378Sjon DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 126770715Sjon DEVMETHOD(bus_setup_intr, pccard_setup_intr), 126870715Sjon DEVMETHOD(bus_teardown_intr, pccard_teardown_intr), 126952506Simp DEVMETHOD(bus_set_resource, pccard_set_resource), 127052506Simp DEVMETHOD(bus_get_resource, pccard_get_resource), 127152506Simp DEVMETHOD(bus_delete_resource, pccard_delete_resource), 1272104641Simp DEVMETHOD(bus_probe_nomatch, pccard_probe_nomatch), 127366058Simp DEVMETHOD(bus_read_ivar, pccard_read_ivar), 1274104641Simp DEVMETHOD(bus_child_pnpinfo_str, pccard_child_pnpinfo_str), 1275104641Simp DEVMETHOD(bus_child_location_str, pccard_child_location_str), 127652506Simp 127759193Simp /* Card Interface */ 127859193Simp DEVMETHOD(card_set_res_flags, pccard_set_res_flags), 127959193Simp DEVMETHOD(card_set_memory_offset, pccard_set_memory_offset), 128059193Simp DEVMETHOD(card_get_type, pccard_card_gettype), 128159193Simp DEVMETHOD(card_attach_card, pccard_attach_card), 128259193Simp DEVMETHOD(card_detach_card, pccard_detach_card), 128374636Simp DEVMETHOD(card_compat_do_probe, pccard_compat_do_probe), 128474636Simp DEVMETHOD(card_compat_do_attach, pccard_compat_do_attach), 128597613Stakawata DEVMETHOD(card_do_product_lookup, pccard_do_product_lookup), 128659193Simp 128752506Simp { 0, 0 } 128852506Simp}; 128952506Simp 129052506Simpstatic driver_t pccard_driver = { 129152506Simp "pccard", 129252506Simp pccard_methods, 129364850Simp sizeof(struct pccard_softc) 129452506Simp}; 129552506Simp 129652506Simpdevclass_t pccard_devclass; 129752506Simp 1298101905Simp/* Maybe we need to have a slot device? */ 129953873SimpDRIVER_MODULE(pccard, pcic, pccard_driver, pccard_devclass, 0, 0); 130052506SimpDRIVER_MODULE(pccard, pc98pcic, pccard_driver, pccard_devclass, 0, 0); 1301101905SimpDRIVER_MODULE(pccard, cbb, pccard_driver, pccard_devclass, 0, 0); 130253873SimpDRIVER_MODULE(pccard, tcic, pccard_driver, pccard_devclass, 0, 0); 130364927SimpMODULE_VERSION(pccard, 1); 130470715Sjon/*MODULE_DEPEND(pccard, pcic, 1, 1, 1);*/ 1305