pccard.c revision 113078
166200Simp/* $NetBSD: pcmcia.c,v 1.23 2000/07/28 19:17:02 drochner Exp $ */ 252506Simp/* $FreeBSD: head/sys/dev/pccard/pccard.c 113078 2003-04-04 14:40:01Z sanpei $ */ 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); 86106362Simpstatic int pccard_detach_card(device_t dev); 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, 227111119Simp 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 262106362Simppccard_detach_card(device_t dev) 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); 280106896Simp device_delete_child(dev, pf->dev); 28152506Simp } 28282378Sjon if (sc->sc_enabled_count == 0) 28382378Sjon POWER_DISABLE_SOCKET(device_get_parent(dev), dev); 28482378Sjon 28582378Sjon while (NULL != (pf = STAILQ_FIRST(&sc->card.pf_head))) { 28682378Sjon while (NULL != (cfe = STAILQ_FIRST(&pf->cfe_head))) { 28782378Sjon STAILQ_REMOVE_HEAD(&pf->cfe_head, cfe_list); 28882378Sjon free(cfe, M_DEVBUF); 28982378Sjon } 29082378Sjon STAILQ_REMOVE_HEAD(&sc->card.pf_head, pf_list); 29182378Sjon free(pf, M_DEVBUF); 29282378Sjon } 29374632Simp return (0); 29452506Simp} 29552506Simp 29697613Stakawatastatic const struct pccard_product * 29797613Stakawatapccard_do_product_lookup(device_t bus, device_t dev, 298112359Simp const struct pccard_product *tab, size_t ent_size, 299112359Simp pccard_product_match_fn matchfn) 30066200Simp{ 30166200Simp const struct pccard_product *ent; 30266200Simp int matches; 30366200Simp u_int32_t fcn; 30466200Simp u_int32_t vendor; 30566200Simp u_int32_t prod; 30666200Simp char *vendorstr; 30766200Simp char *prodstr; 30866200Simp 30966200Simp#ifdef DIAGNOSTIC 31066200Simp if (sizeof *ent > ent_size) 311112359Simp panic("pccard_product_lookup: bogus ent_size %jd", 312112359Simp (intmax_t) ent_size); 31366200Simp#endif 31466200Simp if (pccard_get_vendor(dev, &vendor)) 31566200Simp return (NULL); 31666200Simp if (pccard_get_product(dev, &prod)) 31766200Simp return (NULL); 31866200Simp if (pccard_get_function_number(dev, &fcn)) 31966200Simp return (NULL); 32066200Simp if (pccard_get_vendor_str(dev, &vendorstr)) 32166200Simp return (NULL); 32266200Simp if (pccard_get_product_str(dev, &prodstr)) 32366200Simp return (NULL); 32482378Sjon for (ent = tab; ent->pp_name != NULL; ent = 32582378Sjon (const struct pccard_product *) ((const char *) ent + ent_size)) { 32666200Simp matches = 1; 32786642Simp if (ent->pp_vendor == PCCARD_VENDOR_ANY && 328113078Ssanpei ent->pp_product == PCCARD_PRODUCT_ANY && 32986642Simp ent->pp_cis[0] == NULL && 33086642Simp ent->pp_cis[1] == NULL) { 33186642Simp device_printf(dev, 33286642Simp "Total wildcard entry ignored for %s\n", 33386642Simp ent->pp_name); 33486642Simp continue; 33586642Simp } 33666200Simp if (matches && ent->pp_vendor != PCCARD_VENDOR_ANY && 33766200Simp vendor != ent->pp_vendor) 33866200Simp matches = 0; 33966200Simp if (matches && ent->pp_product != PCCARD_PRODUCT_ANY && 34066200Simp prod != ent->pp_product) 34166200Simp matches = 0; 34266200Simp if (matches && fcn != ent->pp_expfunc) 34366200Simp matches = 0; 34471322Simp if (matches && ent->pp_cis[0] && 34571322Simp strcmp(ent->pp_cis[0], vendorstr) != 0) 34666200Simp matches = 0; 34771322Simp if (matches && ent->pp_cis[1] && 34871322Simp strcmp(ent->pp_cis[1], prodstr) != 0) 34966200Simp matches = 0; 35071322Simp /* XXX need to match cis[2] and cis[3] also XXX */ 35166200Simp if (matchfn != NULL) 35266200Simp matches = (*matchfn)(dev, ent, matches); 35366200Simp if (matches) 35466200Simp return (ent); 35566200Simp } 35666200Simp return (NULL); 35766200Simp} 35866200Simp 35970715Sjonstatic int 36059193Simppccard_card_gettype(device_t dev, int *type) 36152506Simp{ 36264850Simp struct pccard_softc *sc = PCCARD_SOFTC(dev); 36352506Simp struct pccard_function *pf; 36452506Simp 36552506Simp /* 36652506Simp * set the iftype to memory if this card has no functions (not yet 36752506Simp * probed), or only one function, and that is not initialized yet or 36852506Simp * that is memory. 36952506Simp */ 37052506Simp pf = STAILQ_FIRST(&sc->card.pf_head); 37152506Simp if (pf == NULL || 37252506Simp (STAILQ_NEXT(pf, pf_list) == NULL && 37352506Simp (pf->cfe == NULL || pf->cfe->iftype == PCCARD_IFTYPE_MEMORY))) 37459193Simp *type = PCCARD_IFTYPE_MEMORY; 37552506Simp else 37659193Simp *type = PCCARD_IFTYPE_IO; 37774632Simp return (0); 37852506Simp} 37952506Simp 38052506Simp/* 38152506Simp * Initialize a PCCARD function. May be called as long as the function is 38252506Simp * disabled. 38382382Simp * 38482382Simp * Note: pccard_function_init should not keep resources allocated. It should 38582382Simp * only set them up ala isa pnp, set the values in the rl lists, and return. 38682382Simp * Any resource held after pccard_function_init is called is a bug. However, 38782382Simp * the bus routines to get the resources also assume that pccard_function_init 38882382Simp * does this, so they need to be fixed too. 38952506Simp */ 39082378Sjonstatic void 39170715Sjonpccard_function_init(struct pccard_function *pf) 39252506Simp{ 39365917Simp struct pccard_config_entry *cfe; 39467187Simp int i; 39567242Simp struct pccard_ivar *devi = PCCARD_IVAR(pf->dev); 39667242Simp struct resource_list *rl = &devi->resources; 39770762Simp struct resource_list_entry *rle; 39867242Simp struct resource *r = 0; 39967242Simp device_t bus; 40067424Simp int start; 40167424Simp int end; 40290897Simp int spaces; 40365917Simp 40470715Sjon if (pf->pf_flags & PFF_ENABLED) { 40570715Sjon printf("pccard_function_init: function is enabled"); 40670715Sjon return; 40770715Sjon } 40867242Simp bus = device_get_parent(pf->dev); 40952506Simp /* Remember which configuration entry we are using. */ 41072012Sphk STAILQ_FOREACH(cfe, &pf->cfe_head, cfe_list) { 41167187Simp for (i = 0; i < cfe->num_iospace; i++) 41267187Simp cfe->iores[i] = NULL; 41367187Simp cfe->irqres = NULL; 41490897Simp spaces = 0; 41567187Simp for (i = 0; i < cfe->num_iospace; i++) { 41667424Simp start = cfe->iospace[i].start; 41767424Simp if (start) 41867424Simp end = start + cfe->iospace[i].length - 1; 41967424Simp else 42067424Simp end = ~0; 42167187Simp cfe->iorid[i] = i; 42290897Simp DEVPRINTF((bus, "I/O rid %d start %x end %x\n", 42390897Simp i, start, end)); 42467242Simp r = cfe->iores[i] = bus_alloc_resource(bus, 42567424Simp SYS_RES_IOPORT, &cfe->iorid[i], start, end, 42670715Sjon cfe->iospace[i].length, 42767424Simp rman_make_alignment_flags(cfe->iospace[i].length)); 42876424Simp if (cfe->iores[i] == NULL) 42967187Simp goto not_this_one; 43067242Simp resource_list_add(rl, SYS_RES_IOPORT, cfe->iorid[i], 43167242Simp rman_get_start(r), rman_get_end(r), 43267242Simp cfe->iospace[i].length); 43376424Simp rle = resource_list_find(rl, SYS_RES_IOPORT, 43476424Simp cfe->iorid[i]); 43576424Simp rle->res = r; 43690897Simp spaces++; 43767187Simp } 43867187Simp if (cfe->num_memspace > 0) { 43982781Sshiba /* 44082781Sshiba * Not implement yet, Fix me. 44182781Sshiba */ 44290897Simp DEVPRINTF((bus, "Memory space not yet implemented.\n")); 44367187Simp } 44490897Simp if (spaces == 0) { 44590897Simp DEVPRINTF((bus, "Neither memory nor I/O mampped\n")); 44690897Simp goto not_this_one; 44790897Simp } 44867187Simp if (cfe->irqmask) { 44967187Simp cfe->irqrid = 0; 45067399Simp r = cfe->irqres = bus_alloc_resource(bus, SYS_RES_IRQ, 45167424Simp &cfe->irqrid, 0, ~0, 1, 0); 45276424Simp if (cfe->irqres == NULL) 45367187Simp goto not_this_one; 45467242Simp resource_list_add(rl, SYS_RES_IRQ, cfe->irqrid, 45567242Simp rman_get_start(r), rman_get_end(r), 1); 45676424Simp rle = resource_list_find(rl, SYS_RES_IRQ, 45776424Simp cfe->irqrid); 45876424Simp rle->res = r; 45967187Simp } 46067187Simp /* If we get to here, we've allocated all we need */ 46167167Simp pf->cfe = cfe; 46267187Simp break; 46367187Simp not_this_one:; 46467424Simp DEVPRVERBOSE((bus, "Allocation failed for cfe %d\n", 46567424Simp cfe->number)); 46667333Simp /* 46767333Simp * Release resources that we partially allocated 46867333Simp * from this config entry. 46967333Simp */ 47067187Simp for (i = 0; i < cfe->num_iospace; i++) { 47176424Simp if (cfe->iores[i] != NULL) { 47270715Sjon bus_release_resource(bus, SYS_RES_IOPORT, 47367187Simp cfe->iorid[i], cfe->iores[i]); 47482378Sjon rle = resource_list_find(rl, SYS_RES_IOPORT, 47576424Simp cfe->iorid[i]); 47676424Simp rle->res = NULL; 47776424Simp resource_list_delete(rl, SYS_RES_IOPORT, 47876424Simp cfe->iorid[i]); 47975756Simp } 48067187Simp cfe->iores[i] = NULL; 48167187Simp } 48276424Simp if (cfe->irqmask && cfe->irqres != NULL) { 48367242Simp bus_release_resource(bus, SYS_RES_IRQ, 48467187Simp cfe->irqrid, cfe->irqres); 48576424Simp rle = resource_list_find(rl, SYS_RES_IRQ, 48676424Simp cfe->irqrid); 48776424Simp rle->res = NULL; 48876424Simp resource_list_delete(rl, SYS_RES_IRQ, cfe->irqrid); 48967187Simp cfe->irqres = NULL; 49067187Simp } 49167167Simp } 49252506Simp} 49352506Simp 49482378Sjon/* 49582378Sjon * Free resources allocated by pccard_function_init(), May be called as long 49682378Sjon * as the function is disabled. 49782382Simp * 49882382Simp * NOTE: This function should be unnecessary. pccard_function_init should 49982382Simp * never keep resources initialized. 50082378Sjon */ 50182378Sjonstatic void 50282378Sjonpccard_function_free(struct pccard_function *pf) 50382378Sjon{ 50482378Sjon struct pccard_ivar *devi = PCCARD_IVAR(pf->dev); 50582378Sjon struct resource_list_entry *rle; 50682378Sjon 50782378Sjon if (pf->pf_flags & PFF_ENABLED) { 50882378Sjon printf("pccard_function_init: function is enabled"); 50982378Sjon return; 51082378Sjon } 51182378Sjon 51282378Sjon SLIST_FOREACH(rle, &devi->resources, link) { 51382378Sjon if (rle->res) { 51482378Sjon if (rle->res->r_dev != pf->sc->dev) 51582378Sjon device_printf(pf->sc->dev, 51682378Sjon "function_free: Resource still owned by " 51782378Sjon "child, oops. " 51882378Sjon "(type=%d, rid=%d, addr=%lx)\n", 51982378Sjon rle->type, rle->rid, 52082378Sjon rman_get_start(rle->res)); 52182378Sjon BUS_RELEASE_RESOURCE(device_get_parent(pf->sc->dev), 52282378Sjon rle->res->r_dev, rle->type, rle->rid, rle->res); 52382378Sjon rle->res = NULL; 52482378Sjon } 52582378Sjon } 52682378Sjon resource_list_free(&devi->resources); 52782378Sjon} 52882378Sjon 52952506Simp/* Enable a PCCARD function */ 53082378Sjonstatic int 53155720Simppccard_function_enable(struct pccard_function *pf) 53252506Simp{ 53352506Simp struct pccard_function *tmp; 53452506Simp int reg; 53555720Simp device_t dev = pf->sc->dev; 53670746Simp 53767333Simp if (pf->cfe == NULL) { 53867333Simp DEVPRVERBOSE((dev, "No config entry could be allocated.\n")); 53974632Simp return (ENOMEM); 54067333Simp } 54152506Simp 54252506Simp /* 54352506Simp * Increase the reference count on the socket, enabling power, if 54452506Simp * necessary. 54552506Simp */ 54682378Sjon pf->sc->sc_enabled_count++; 54752506Simp 54852506Simp if (pf->pf_flags & PFF_ENABLED) { 54952506Simp /* 55052506Simp * Don't do anything if we're already enabled. 55152506Simp */ 55252506Simp return (0); 55352506Simp } 55452506Simp 55552506Simp /* 55652506Simp * it's possible for different functions' CCRs to be in the same 55752506Simp * underlying page. Check for that. 55852506Simp */ 55952506Simp STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) { 56052506Simp if ((tmp->pf_flags & PFF_ENABLED) && 56152506Simp (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) && 56252506Simp ((pf->ccr_base + PCCARD_CCR_SIZE) <= 56382378Sjon (tmp->ccr_base - tmp->pf_ccr_offset + 56482378Sjon tmp->pf_ccr_realsize))) { 56552506Simp pf->pf_ccrt = tmp->pf_ccrt; 56652506Simp pf->pf_ccrh = tmp->pf_ccrh; 56752506Simp pf->pf_ccr_realsize = tmp->pf_ccr_realsize; 56852506Simp 56952506Simp /* 57052506Simp * pf->pf_ccr_offset = (tmp->pf_ccr_offset - 57152506Simp * tmp->ccr_base) + pf->ccr_base; 57252506Simp */ 57370715Sjon /* pf->pf_ccr_offset = 57452506Simp (tmp->pf_ccr_offset + pf->ccr_base) - 57570715Sjon tmp->ccr_base; */ 57652506Simp pf->pf_ccr_window = tmp->pf_ccr_window; 57752506Simp break; 57852506Simp } 57952506Simp } 58052506Simp if (tmp == NULL) { 58155720Simp pf->ccr_rid = 0; 58255720Simp pf->ccr_res = bus_alloc_resource(dev, SYS_RES_MEMORY, 58370715Sjon &pf->ccr_rid, 0, ~0, 1 << 10, RF_ACTIVE); 58470715Sjon if (!pf->ccr_res) 58552506Simp goto bad; 586106914Smux DEVPRINTF((dev, "ccr_res == %lx-%lx, base=%x\n", 58770746Simp rman_get_start(pf->ccr_res), rman_get_end(pf->ccr_res), 58870746Simp pf->ccr_base)); 58961788Simp CARD_SET_RES_FLAGS(device_get_parent(dev), dev, SYS_RES_MEMORY, 59061788Simp pf->ccr_rid, PCCARD_A_MEM_ATTR); 59170715Sjon CARD_SET_MEMORY_OFFSET(device_get_parent(dev), dev, 59270748Simp pf->ccr_rid, pf->ccr_base, &pf->pf_ccr_offset); 59355720Simp pf->pf_ccrt = rman_get_bustag(pf->ccr_res); 59455720Simp pf->pf_ccrh = rman_get_bushandle(pf->ccr_res); 59555720Simp pf->pf_ccr_realsize = 1; 59652506Simp } 59752506Simp 59852506Simp reg = (pf->cfe->number & PCCARD_CCR_OPTION_CFINDEX); 59952506Simp reg |= PCCARD_CCR_OPTION_LEVIREQ; 60052506Simp if (pccard_mfc(pf->sc)) { 60152506Simp reg |= (PCCARD_CCR_OPTION_FUNC_ENABLE | 60252506Simp PCCARD_CCR_OPTION_ADDR_DECODE); 60382383Simp /* PCCARD_CCR_OPTION_IRQ_ENABLE set elsewhere as needed */ 60452506Simp } 60552506Simp pccard_ccr_write(pf, PCCARD_CCR_OPTION, reg); 60652506Simp 60752506Simp reg = 0; 60852506Simp if ((pf->cfe->flags & PCCARD_CFE_IO16) == 0) 60952506Simp reg |= PCCARD_CCR_STATUS_IOIS8; 61052506Simp if (pf->cfe->flags & PCCARD_CFE_AUDIO) 61152506Simp reg |= PCCARD_CCR_STATUS_AUDIO; 61252506Simp pccard_ccr_write(pf, PCCARD_CCR_STATUS, reg); 61352506Simp 61452506Simp pccard_ccr_write(pf, PCCARD_CCR_SOCKETCOPY, 0); 61552506Simp 61652506Simp if (pccard_mfc(pf->sc)) { 61752506Simp long tmp, iosize; 61852506Simp 61952506Simp tmp = pf->pf_mfc_iomax - pf->pf_mfc_iobase; 62052506Simp /* round up to nearest (2^n)-1 */ 62152506Simp for (iosize = 1; iosize < tmp; iosize <<= 1) 62252506Simp ; 62352506Simp iosize--; 62452506Simp 62552506Simp pccard_ccr_write(pf, PCCARD_CCR_IOBASE0, 62652506Simp pf->pf_mfc_iobase & 0xff); 62752506Simp pccard_ccr_write(pf, PCCARD_CCR_IOBASE1, 62852506Simp (pf->pf_mfc_iobase >> 8) & 0xff); 62952506Simp pccard_ccr_write(pf, PCCARD_CCR_IOBASE2, 0); 63052506Simp pccard_ccr_write(pf, PCCARD_CCR_IOBASE3, 0); 63152506Simp 63252506Simp pccard_ccr_write(pf, PCCARD_CCR_IOSIZE, iosize); 63352506Simp } 63452506Simp 63552506Simp#ifdef PCCARDDEBUG 63652506Simp if (pccard_debug) { 63752506Simp STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) { 63870715Sjon device_printf(tmp->sc->dev, 63955500Simp "function %d CCR at %d offset %x: " 64055500Simp "%x %x %x %x, %x %x %x %x, %x\n", 64170715Sjon tmp->number, tmp->pf_ccr_window, 64255500Simp tmp->pf_ccr_offset, 64355500Simp pccard_ccr_read(tmp, 0x00), 64455500Simp pccard_ccr_read(tmp, 0x02), 64555500Simp pccard_ccr_read(tmp, 0x04), 64655500Simp pccard_ccr_read(tmp, 0x06), 64755500Simp pccard_ccr_read(tmp, 0x0A), 64870715Sjon pccard_ccr_read(tmp, 0x0C), 64955500Simp pccard_ccr_read(tmp, 0x0E), 65055500Simp pccard_ccr_read(tmp, 0x10), 65155500Simp pccard_ccr_read(tmp, 0x12)); 65252506Simp } 65352506Simp } 65452506Simp#endif 65552506Simp pf->pf_flags |= PFF_ENABLED; 65652506Simp return (0); 65752506Simp 65852506Simp bad: 65952506Simp /* 66052506Simp * Decrement the reference count, and power down the socket, if 66152506Simp * necessary. 66252506Simp */ 66382378Sjon pf->sc->sc_enabled_count--; 66465098Simp DEVPRINTF((dev, "bad --enabled_count = %d\n", pf->sc->sc_enabled_count)); 66552506Simp 66652506Simp return (1); 66752506Simp} 66852506Simp 66952506Simp/* Disable PCCARD function. */ 67082378Sjonstatic void 67155720Simppccard_function_disable(struct pccard_function *pf) 67252506Simp{ 67352506Simp struct pccard_function *tmp; 67455720Simp device_t dev = pf->sc->dev; 67552506Simp 67652506Simp if (pf->cfe == NULL) 67761788Simp panic("pccard_function_disable: function not initialized"); 67852506Simp 67952506Simp if ((pf->pf_flags & PFF_ENABLED) == 0) { 68052506Simp /* 68152506Simp * Don't do anything if we're already disabled. 68252506Simp */ 68352506Simp return; 68452506Simp } 68552506Simp 68670715Sjon if (pf->intr_handler != NULL) { 68782378Sjon struct pccard_ivar *devi = PCCARD_IVAR(pf->dev); 68882378Sjon struct resource_list_entry *rle = 68982378Sjon resource_list_find(&devi->resources, SYS_RES_IRQ, 0); 69082378Sjon BUS_TEARDOWN_INTR(dev, pf->dev, rle->res, 69182378Sjon pf->intr_handler_cookie); 69270715Sjon } 69370715Sjon 69452506Simp /* 69552506Simp * it's possible for different functions' CCRs to be in the same 69652506Simp * underlying page. Check for that. Note we mark us as disabled 69752506Simp * first to avoid matching ourself. 69852506Simp */ 69952506Simp 70052506Simp pf->pf_flags &= ~PFF_ENABLED; 70152506Simp STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) { 70252506Simp if ((tmp->pf_flags & PFF_ENABLED) && 70352506Simp (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) && 70452506Simp ((pf->ccr_base + PCCARD_CCR_SIZE) <= 70582378Sjon (tmp->ccr_base - tmp->pf_ccr_offset + 70682378Sjon tmp->pf_ccr_realsize))) 70752506Simp break; 70852506Simp } 70952506Simp 71052506Simp /* Not used by anyone else; unmap the CCR. */ 71152506Simp if (tmp == NULL) { 71270715Sjon bus_release_resource(dev, SYS_RES_MEMORY, pf->ccr_rid, 71355720Simp pf->ccr_res); 71455720Simp pf->ccr_res = NULL; 71552506Simp } 71652506Simp 71752506Simp /* 71852506Simp * Decrement the reference count, and power down the socket, if 71952506Simp * necessary. 72052506Simp */ 72182378Sjon pf->sc->sc_enabled_count--; 72252506Simp} 72352506Simp 72466058Simp/* 72566058Simp * simulate the old "probe" routine. In the new world order, the driver 72666058Simp * needs to grab devices while in the old they were assigned to the device by 72766058Simp * the pccardd process. These symbols are exported to the upper layers. 72866058Simp */ 72974636Simpstatic int 73074636Simppccard_compat_do_probe(device_t bus, device_t dev) 73166058Simp{ 73266058Simp return (CARD_COMPAT_MATCH(dev)); 73366058Simp} 73466058Simp 73574636Simpstatic int 73674636Simppccard_compat_do_attach(device_t bus, device_t dev) 73766058Simp{ 73866058Simp int err; 73966058Simp 74066058Simp err = CARD_COMPAT_PROBE(dev); 74166058Simp if (err == 0) 74266058Simp err = CARD_COMPAT_ATTACH(dev); 74366058Simp return (err); 74466058Simp} 74566058Simp 74653873Simp#define PCCARD_NPORT 2 74753873Simp#define PCCARD_NMEM 5 74853873Simp#define PCCARD_NIRQ 1 74953873Simp#define PCCARD_NDRQ 0 75053873Simp 75152506Simpstatic int 75252506Simppccard_add_children(device_t dev, int busno) 75352506Simp{ 75459193Simp /* Call parent to scan for any current children */ 75574632Simp return (0); 75652506Simp} 75752506Simp 75852506Simpstatic int 75952506Simppccard_probe(device_t dev) 76052506Simp{ 76167333Simp device_set_desc(dev, "16-bit PCCard bus"); 76274632Simp return (pccard_add_children(dev, device_get_unit(dev))); 76352506Simp} 76452506Simp 76559193Simpstatic int 76659193Simppccard_attach(device_t dev) 76759193Simp{ 76864850Simp struct pccard_softc *sc = PCCARD_SOFTC(dev); 76961788Simp 77059193Simp sc->dev = dev; 77161788Simp sc->sc_enabled_count = 0; 77274632Simp return (bus_generic_attach(dev)); 77359193Simp} 77459193Simp 77582378Sjonstatic int 77682378Sjonpccard_detach(device_t dev) 77782378Sjon{ 778106362Simp pccard_detach_card(dev); 77982378Sjon return 0; 78082378Sjon} 78182378Sjon 78287975Simpstatic int 78387975Simppccard_suspend(device_t self) 78487975Simp{ 785106362Simp pccard_detach_card(self); 78687975Simp return (0); 78787975Simp} 78887975Simp 78987975Simpstatic 79087975Simpint 79187975Simppccard_resume(device_t self) 79287975Simp{ 79387975Simp return (0); 79487975Simp} 79587975Simp 79653873Simpstatic void 79753873Simppccard_print_resources(struct resource_list *rl, const char *name, int type, 79853873Simp int count, const char *format) 79953873Simp{ 80053873Simp struct resource_list_entry *rle; 80153873Simp int printed; 80253873Simp int i; 80353873Simp 80453873Simp printed = 0; 80553873Simp for (i = 0; i < count; i++) { 80653873Simp rle = resource_list_find(rl, type, i); 80776424Simp if (rle != NULL) { 80853873Simp if (printed == 0) 80953873Simp printf(" %s ", name); 81053873Simp else if (printed > 0) 81153873Simp printf(","); 81253873Simp printed++; 81353873Simp printf(format, rle->start); 81453873Simp if (rle->count > 1) { 81553873Simp printf("-"); 81653873Simp printf(format, rle->start + rle->count - 1); 81753873Simp } 81853873Simp } else if (i > 3) { 81953873Simp /* check the first few regardless */ 82053873Simp break; 82153873Simp } 82253873Simp } 82353873Simp} 82453873Simp 82553873Simpstatic int 82653873Simppccard_print_child(device_t dev, device_t child) 82753873Simp{ 82866847Simp struct pccard_ivar *devi = PCCARD_IVAR(child); 82953873Simp struct resource_list *rl = &devi->resources; 83053873Simp int retval = 0; 83153873Simp 83253873Simp retval += bus_print_child_header(dev, child); 83353873Simp retval += printf(" at"); 83453873Simp 83576424Simp if (devi != NULL) { 83653873Simp pccard_print_resources(rl, "port", SYS_RES_IOPORT, 83753873Simp PCCARD_NPORT, "%#lx"); 83853873Simp pccard_print_resources(rl, "iomem", SYS_RES_MEMORY, 83953873Simp PCCARD_NMEM, "%#lx"); 84053873Simp pccard_print_resources(rl, "irq", SYS_RES_IRQ, PCCARD_NIRQ, 84153873Simp "%ld"); 84270715Sjon pccard_print_resources(rl, "drq", SYS_RES_DRQ, PCCARD_NDRQ, 84353873Simp "%ld"); 84467269Simp retval += printf(" function %d config %d", devi->fcn->number, 84567269Simp devi->fcn->cfe->number); 84653873Simp } 84753873Simp 84853873Simp retval += bus_print_child_footer(dev, child); 84953873Simp 85053873Simp return (retval); 85153873Simp} 85253873Simp 85353873Simpstatic int 85453873Simppccard_set_resource(device_t dev, device_t child, int type, int rid, 85553873Simp u_long start, u_long count) 85653873Simp{ 85766847Simp struct pccard_ivar *devi = PCCARD_IVAR(child); 85853873Simp struct resource_list *rl = &devi->resources; 85953873Simp 86053873Simp if (type != SYS_RES_IOPORT && type != SYS_RES_MEMORY 86153873Simp && type != SYS_RES_IRQ && type != SYS_RES_DRQ) 86274632Simp return (EINVAL); 86353873Simp if (rid < 0) 86474632Simp return (EINVAL); 86553873Simp if (type == SYS_RES_IOPORT && rid >= PCCARD_NPORT) 86674632Simp return (EINVAL); 86753873Simp if (type == SYS_RES_MEMORY && rid >= PCCARD_NMEM) 86874632Simp return (EINVAL); 86953873Simp if (type == SYS_RES_IRQ && rid >= PCCARD_NIRQ) 87074632Simp return (EINVAL); 87153873Simp if (type == SYS_RES_DRQ && rid >= PCCARD_NDRQ) 87274632Simp return (EINVAL); 87353873Simp 87453873Simp resource_list_add(rl, type, rid, start, start + count - 1, count); 87582378Sjon if (NULL != resource_list_alloc(rl, device_get_parent(dev), dev, 87682378Sjon type, &rid, start, start + count - 1, count, 0)) 87782378Sjon return 0; 87882378Sjon else 87982378Sjon return ENOMEM; 88053873Simp} 88153873Simp 88253873Simpstatic int 88353873Simppccard_get_resource(device_t dev, device_t child, int type, int rid, 88453873Simp u_long *startp, u_long *countp) 88553873Simp{ 88666847Simp struct pccard_ivar *devi = PCCARD_IVAR(child); 88753873Simp struct resource_list *rl = &devi->resources; 88853873Simp struct resource_list_entry *rle; 88953873Simp 89053873Simp rle = resource_list_find(rl, type, rid); 89176424Simp if (rle == NULL) 89274632Simp return (ENOENT); 89370715Sjon 89476424Simp if (startp != NULL) 89553873Simp *startp = rle->start; 89676424Simp if (countp != NULL) 89753873Simp *countp = rle->count; 89853873Simp 89974632Simp return (0); 90053873Simp} 90153873Simp 90253873Simpstatic void 90353873Simppccard_delete_resource(device_t dev, device_t child, int type, int rid) 90453873Simp{ 90566847Simp struct pccard_ivar *devi = PCCARD_IVAR(child); 90653873Simp struct resource_list *rl = &devi->resources; 90753873Simp resource_list_delete(rl, type, rid); 90853873Simp} 90953873Simp 91059193Simpstatic int 91159193Simppccard_set_res_flags(device_t dev, device_t child, int type, int rid, 91259193Simp u_int32_t flags) 91359193Simp{ 91474632Simp return (CARD_SET_RES_FLAGS(device_get_parent(dev), child, type, 91574632Simp rid, flags)); 91659193Simp} 91759193Simp 91859193Simpstatic int 91959193Simppccard_set_memory_offset(device_t dev, device_t child, int rid, 92082378Sjon u_int32_t offset, u_int32_t *deltap) 92170715Sjon 92259193Simp{ 92374632Simp return (CARD_SET_MEMORY_OFFSET(device_get_parent(dev), child, rid, 92474632Simp offset, deltap)); 92559193Simp} 92659193Simp 927104641Simpstatic void 928104641Simppccard_probe_nomatch(device_t bus, device_t child) 929104641Simp{ 930104641Simp struct pccard_ivar *devi = PCCARD_IVAR(child); 931104641Simp struct pccard_function *func = devi->fcn; 932104641Simp struct pccard_softc *sc = PCCARD_SOFTC(bus); 933104641Simp 934104641Simp device_printf(bus, "<unknown card>"); 935104641Simp printf(" (manufacturer=0x%04x, product=0x%04x) at function %d\n", 936104641Simp sc->card.manufacturer, sc->card.product, func->number); 937104641Simp device_printf(bus, " CIS info: %s, %s, %s\n", sc->card.cis1_info[0], 938104641Simp sc->card.cis1_info[1], sc->card.cis1_info[2]); 939104641Simp return; 940104641Simp} 941104641Simp 94266058Simpstatic int 943104641Simppccard_child_location_str(device_t bus, device_t child, char *buf, 944104641Simp size_t buflen) 945104641Simp{ 946104641Simp struct pccard_ivar *devi = PCCARD_IVAR(child); 947104641Simp struct pccard_function *func = devi->fcn; 948104641Simp 949104641Simp snprintf(buf, buflen, "function=%d", func->number); 950104641Simp return (0); 951104641Simp} 952104641Simp 953104641Simpstatic int 954104641Simppccard_child_pnpinfo_str(device_t bus, device_t child, char *buf, 955104641Simp size_t buflen) 956104641Simp{ 957104641Simp struct pccard_ivar *devi = PCCARD_IVAR(child); 958104641Simp struct pccard_function *func = devi->fcn; 959104641Simp struct pccard_softc *sc = PCCARD_SOFTC(bus); 960104641Simp 961104641Simp snprintf(buf, buflen, "manufacturer=0x%04x product=0x%04x " 962104641Simp "cisvendor=\"%s\" cisproduct=\"%s\" function_type=%d", 963104641Simp sc->card.manufacturer, sc->card.product, sc->card.cis1_info[0], 964104641Simp sc->card.cis1_info[1], func->function); 965104641Simp return (0); 966104641Simp} 967104641Simp 968104641Simpstatic int 96966058Simppccard_read_ivar(device_t bus, device_t child, int which, u_char *result) 97066058Simp{ 97166847Simp struct pccard_ivar *devi = PCCARD_IVAR(child); 97266779Simp struct pccard_function *func = devi->fcn; 97366779Simp struct pccard_softc *sc = PCCARD_SOFTC(bus); 97466779Simp 97566779Simp switch (which) { 97666779Simp default: 97766779Simp case PCCARD_IVAR_ETHADDR: 97882781Sshiba bcopy(func->pf_funce_lan_nid, result, ETHER_ADDR_LEN); 97966779Simp break; 98066779Simp case PCCARD_IVAR_VENDOR: 98166779Simp *(u_int32_t *) result = sc->card.manufacturer; 98266779Simp break; 98366779Simp case PCCARD_IVAR_PRODUCT: 98466779Simp *(u_int32_t *) result = sc->card.product; 98566779Simp break; 98690964Sshiba case PCCARD_IVAR_PRODEXT: 98790964Sshiba *(u_int16_t *) result = sc->card.prodext; 98890964Sshiba break; 98975761Simp case PCCARD_IVAR_FUNCTION: 99075761Simp *(u_int32_t *) result = func->function; 99175761Simp break; 99266779Simp case PCCARD_IVAR_FUNCTION_NUMBER: 99366847Simp if (!func) { 99466847Simp device_printf(bus, "No function number, bug!\n"); 99566847Simp return (ENOENT); 99666847Simp } 99766847Simp *(u_int32_t *) result = func->number; 99866779Simp break; 99966779Simp case PCCARD_IVAR_VENDOR_STR: 100066779Simp *(char **) result = sc->card.cis1_info[0]; 100166779Simp break; 100266779Simp case PCCARD_IVAR_PRODUCT_STR: 100366779Simp *(char **) result = sc->card.cis1_info[1]; 100466779Simp break; 100566779Simp case PCCARD_IVAR_CIS3_STR: 100666779Simp *(char **) result = sc->card.cis1_info[2]; 100766779Simp break; 100867167Simp case PCCARD_IVAR_CIS4_STR: 1009104610Simp *(char **) result = sc->card.cis1_info[3]; 101067167Simp break; 101166779Simp } 101266779Simp return (0); 101366058Simp} 101466058Simp 101566779Simpstatic void 101666779Simppccard_driver_added(device_t dev, driver_t *driver) 101766779Simp{ 101882378Sjon struct pccard_softc *sc = PCCARD_SOFTC(dev); 101982378Sjon struct pccard_function *pf; 102082378Sjon device_t child; 102182378Sjon 102282378Sjon STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) { 102382378Sjon if (STAILQ_EMPTY(&pf->cfe_head)) 102482378Sjon continue; 102582378Sjon child = pf->dev; 102682378Sjon if (device_get_state(child) != DS_NOTPRESENT) 102782378Sjon continue; 102882378Sjon if (pccard_function_enable(pf) == 0 && 102982378Sjon device_probe_and_attach(child) == 0) { 103082378Sjon DEVPRINTF((sc->dev, "function %d CCR at %d " 103182378Sjon "offset %x: %x %x %x %x, %x %x %x %x, %x\n", 103282378Sjon pf->number, pf->pf_ccr_window, pf->pf_ccr_offset, 103382378Sjon pccard_ccr_read(pf, 0x00), 103482378Sjon pccard_ccr_read(pf, 0x02), pccard_ccr_read(pf, 0x04), 103582378Sjon pccard_ccr_read(pf, 0x06), pccard_ccr_read(pf, 0x0A), 103682378Sjon pccard_ccr_read(pf, 0x0C), pccard_ccr_read(pf, 0x0E), 103782378Sjon pccard_ccr_read(pf, 0x10), pccard_ccr_read(pf, 0x12))); 103882378Sjon } else { 103986907Simp if (pf->cfe != NULL) 104086907Simp pccard_function_disable(pf); 104182378Sjon } 104282378Sjon } 104382378Sjon return; 104466779Simp} 104566058Simp 104667242Simpstatic struct resource * 104767242Simppccard_alloc_resource(device_t dev, device_t child, int type, int *rid, 104867242Simp u_long start, u_long end, u_long count, u_int flags) 104967242Simp{ 105082378Sjon struct pccard_ivar *dinfo; 105182378Sjon struct resource_list_entry *rle = 0; 105282378Sjon int passthrough = (device_get_parent(child) != dev); 1053104641Simp struct resource *r = NULL; 105467242Simp 105582378Sjon if (passthrough) { 105682378Sjon return (BUS_ALLOC_RESOURCE(device_get_parent(dev), child, 105782378Sjon type, rid, start, end, count, flags)); 105882378Sjon } 105970715Sjon 106082378Sjon dinfo = device_get_ivars(child); 106182378Sjon rle = resource_list_find(&dinfo->resources, type, *rid); 106270715Sjon 1063104641Simp if (rle == NULL) 1064104641Simp return (NULL); /* no resource of that type/rid */ 106570715Sjon 1066104641Simp if (rle->res == NULL) { 106782378Sjon switch(type) { 106882378Sjon case SYS_RES_IOPORT: 1069104641Simp r = bus_alloc_resource(dev, type, rid, start, end, 1070104641Simp count, rman_make_alignment_flags(count)); 1071104641Simp if (r == NULL) 1072104641Simp goto bad; 1073104641Simp resource_list_add(&dinfo->resources, type, *rid, 1074104641Simp rman_get_start(r), rman_get_end(r), count); 1075104641Simp rle = resource_list_find(&dinfo->resources, type, *rid); 1076104641Simp if (!rle) 1077104641Simp goto bad; 1078104641Simp rle->res = r; 1079104641Simp break; 108082378Sjon case SYS_RES_MEMORY: 108182378Sjon break; 108282378Sjon case SYS_RES_IRQ: 108382378Sjon break; 108482378Sjon } 108590897Simp return (rle->res); 108667269Simp } 1087104641Simp if (rle->res->r_dev != dev) 1088104641Simp return (NULL); 1089104641Simp bus_release_resource(dev, type, *rid, rle->res); 1090104641Simp rle->res = NULL; 1091104641Simp switch(type) { 1092104641Simp case SYS_RES_IOPORT: 1093104641Simp case SYS_RES_MEMORY: 1094104641Simp if (!(flags & RF_ALIGNMENT_MASK)) 1095104641Simp flags |= rman_make_alignment_flags(rle->count); 1096104641Simp break; 1097104641Simp case SYS_RES_IRQ: 1098104641Simp flags |= RF_SHAREABLE; 1099104641Simp break; 1100104641Simp } 1101104641Simp rle->res = resource_list_alloc(&dinfo->resources, dev, child, 1102104641Simp type, rid, rle->start, rle->end, rle->count, flags); 1103104641Simp return (rle->res); 1104104641Simpbad:; 1105104641Simp device_printf(dev, "WARNING: Resource not reserved by pccard\n"); 1106104641Simp return (NULL); 110767242Simp} 110867242Simp 110967242Simpstatic int 111067242Simppccard_release_resource(device_t dev, device_t child, int type, int rid, 111167242Simp struct resource *r) 111267242Simp{ 111382378Sjon struct pccard_ivar *dinfo; 111482378Sjon int passthrough = (device_get_parent(child) != dev); 111582378Sjon struct resource_list_entry *rle = 0; 111682378Sjon int ret; 111782378Sjon int flags; 111870715Sjon 111982378Sjon if (passthrough) 112082378Sjon return BUS_RELEASE_RESOURCE(device_get_parent(dev), child, 112182378Sjon type, rid, r); 112270715Sjon 112382378Sjon dinfo = device_get_ivars(child); 112470715Sjon 112582378Sjon rle = resource_list_find(&dinfo->resources, type, rid); 112670715Sjon 112782378Sjon if (!rle) { 112882378Sjon device_printf(dev, "Allocated resource not found, " 112982378Sjon "%d %x %lx %lx\n", 113082378Sjon type, rid, rman_get_start(r), rman_get_size(r)); 113182378Sjon return ENOENT; 113270715Sjon } 113382378Sjon if (!rle->res) { 113482378Sjon device_printf(dev, "Allocated resource not recorded\n"); 113582378Sjon return ENOENT; 113670715Sjon } 113770715Sjon 113882378Sjon ret = BUS_RELEASE_RESOURCE(device_get_parent(dev), child, 113982378Sjon type, rid, r); 114082378Sjon switch(type) { 114182378Sjon case SYS_RES_IOPORT: 114282378Sjon case SYS_RES_MEMORY: 114382378Sjon flags = rman_make_alignment_flags(rle->count); 114482378Sjon break; 114582378Sjon case SYS_RES_IRQ: 114682378Sjon flags = RF_SHAREABLE; 114782378Sjon break; 114882378Sjon default: 114982378Sjon flags = 0; 115070715Sjon } 115182378Sjon rle->res = bus_alloc_resource(dev, type, &rid, 115282378Sjon rle->start, rle->end, rle->count, flags); 115382378Sjon if (rle->res == NULL) 115482378Sjon device_printf(dev, "release_resource: " 115582378Sjon "unable to reaquire resource\n"); 115682378Sjon return ret; 115767242Simp} 115867242Simp 115967333Simpstatic void 116067333Simppccard_child_detached(device_t parent, device_t dev) 116167333Simp{ 116267333Simp struct pccard_ivar *ivar = PCCARD_IVAR(dev); 116382378Sjon struct pccard_function *pf = ivar->fcn; 116467333Simp 116582378Sjon pccard_function_disable(pf); 116667333Simp} 116767333Simp 116870715Sjonstatic void 116970762Simppccard_intr(void *arg) 117070762Simp{ 117182378Sjon struct pccard_function *pf = (struct pccard_function*) arg; 117282378Sjon int reg; 1173102923Simp int doisr = 1; 117482378Sjon 117582383Simp /* 1176102923Simp * MFC cards know if they interrupted, so we have to ack the 1177102923Simp * interrupt and call the ISR. Non-MFC cards don't have these 1178102923Simp * bits, so they always get called. Many non-MFC cards have 1179102923Simp * this bit set always upon read, but some do not. 1180102923Simp * 1181102923Simp * We always ack the interrupt, even if there's no ISR 1182102923Simp * for the card. This is done on the theory that acking 1183102923Simp * the interrupt will pacify the card enough to keep an 1184102923Simp * interrupt storm from happening. Of course this won't 1185102923Simp * help in the non-MFC case. 118682383Simp */ 1187102923Simp if (pccard_mfc(pf->sc)) { 1188102923Simp reg = pccard_ccr_read(pf, PCCARD_CCR_STATUS); 1189102923Simp if (reg & PCCARD_CCR_STATUS_INTR) 1190102923Simp pccard_ccr_write(pf, PCCARD_CCR_STATUS, 1191102923Simp reg & ~PCCARD_CCR_STATUS_INTR); 1192102923Simp else 1193102923Simp doisr = 0; 1194102923Simp } 1195102923Simp if (pf->intr_handler != NULL && doisr) 119682378Sjon pf->intr_handler(pf->intr_handler_arg); 119770715Sjon} 119870715Sjon 119970715Sjonstatic int 120070762Simppccard_setup_intr(device_t dev, device_t child, struct resource *irq, 120170762Simp int flags, driver_intr_t *intr, void *arg, void **cookiep) 120270715Sjon{ 1203102713Simp struct pccard_softc *sc = PCCARD_SOFTC(dev); 120470715Sjon struct pccard_ivar *ivar = PCCARD_IVAR(child); 120570715Sjon struct pccard_function *func = ivar->fcn; 120690445Simp int err; 120770715Sjon 120870715Sjon if (func->intr_handler != NULL) 1209101762Simp panic("Only one interrupt handler per function allowed"); 121090445Simp err = bus_generic_setup_intr(dev, child, irq, flags, pccard_intr, 121190445Simp func, cookiep); 121290445Simp if (err != 0) 121390445Simp return (err); 121470715Sjon func->intr_handler = intr; 121570715Sjon func->intr_handler_arg = arg; 121682378Sjon func->intr_handler_cookie = *cookiep; 1217102713Simp if (pccard_mfc(sc)) { 1218102713Simp pccard_ccr_write(func, PCCARD_CCR_OPTION, 1219102713Simp pccard_ccr_read(func, PCCARD_CCR_OPTION) | 1220102713Simp PCCARD_CCR_OPTION_IREQ_ENABLE); 1221102713Simp } 122274632Simp return (0); 122370715Sjon} 122470715Sjon 122570715Sjonstatic int 122670762Simppccard_teardown_intr(device_t dev, device_t child, struct resource *r, 122770762Simp void *cookie) 122870715Sjon{ 1229102713Simp struct pccard_softc *sc = PCCARD_SOFTC(dev); 123070715Sjon struct pccard_ivar *ivar = PCCARD_IVAR(child); 123170715Sjon struct pccard_function *func = ivar->fcn; 123282378Sjon int ret; 123370715Sjon 1234102713Simp if (pccard_mfc(sc)) { 1235102713Simp pccard_ccr_write(func, PCCARD_CCR_OPTION, 1236102713Simp pccard_ccr_read(func, PCCARD_CCR_OPTION) & 1237102713Simp ~PCCARD_CCR_OPTION_IREQ_ENABLE); 1238102713Simp } 123990445Simp ret = bus_generic_teardown_intr(dev, child, r, cookie); 124082378Sjon if (ret == 0) { 124182378Sjon func->intr_handler = NULL; 124282378Sjon func->intr_handler_arg = NULL; 124382378Sjon func->intr_handler_cookie = NULL; 124482378Sjon } 124570715Sjon 124682378Sjon return (ret); 124770715Sjon} 124870715Sjon 124952506Simpstatic device_method_t pccard_methods[] = { 125052506Simp /* Device interface */ 125152506Simp DEVMETHOD(device_probe, pccard_probe), 125259193Simp DEVMETHOD(device_attach, pccard_attach), 125382378Sjon DEVMETHOD(device_detach, pccard_detach), 125452506Simp DEVMETHOD(device_shutdown, bus_generic_shutdown), 125587975Simp DEVMETHOD(device_suspend, pccard_suspend), 125687975Simp DEVMETHOD(device_resume, pccard_resume), 125752506Simp 125852506Simp /* Bus interface */ 125952506Simp DEVMETHOD(bus_print_child, pccard_print_child), 126066779Simp DEVMETHOD(bus_driver_added, pccard_driver_added), 126167333Simp DEVMETHOD(bus_child_detached, pccard_child_detached), 126267242Simp DEVMETHOD(bus_alloc_resource, pccard_alloc_resource), 126367242Simp DEVMETHOD(bus_release_resource, pccard_release_resource), 126482378Sjon DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 126582378Sjon DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 126670715Sjon DEVMETHOD(bus_setup_intr, pccard_setup_intr), 126770715Sjon DEVMETHOD(bus_teardown_intr, pccard_teardown_intr), 126852506Simp DEVMETHOD(bus_set_resource, pccard_set_resource), 126952506Simp DEVMETHOD(bus_get_resource, pccard_get_resource), 127052506Simp DEVMETHOD(bus_delete_resource, pccard_delete_resource), 1271104641Simp DEVMETHOD(bus_probe_nomatch, pccard_probe_nomatch), 127266058Simp DEVMETHOD(bus_read_ivar, pccard_read_ivar), 1273104641Simp DEVMETHOD(bus_child_pnpinfo_str, pccard_child_pnpinfo_str), 1274104641Simp DEVMETHOD(bus_child_location_str, pccard_child_location_str), 127552506Simp 127659193Simp /* Card Interface */ 127759193Simp DEVMETHOD(card_set_res_flags, pccard_set_res_flags), 127859193Simp DEVMETHOD(card_set_memory_offset, pccard_set_memory_offset), 127959193Simp DEVMETHOD(card_get_type, pccard_card_gettype), 128059193Simp DEVMETHOD(card_attach_card, pccard_attach_card), 128159193Simp DEVMETHOD(card_detach_card, pccard_detach_card), 128274636Simp DEVMETHOD(card_compat_do_probe, pccard_compat_do_probe), 128374636Simp DEVMETHOD(card_compat_do_attach, pccard_compat_do_attach), 128497613Stakawata DEVMETHOD(card_do_product_lookup, pccard_do_product_lookup), 128559193Simp 128652506Simp { 0, 0 } 128752506Simp}; 128852506Simp 128952506Simpstatic driver_t pccard_driver = { 129052506Simp "pccard", 129152506Simp pccard_methods, 129264850Simp sizeof(struct pccard_softc) 129352506Simp}; 129452506Simp 129552506Simpdevclass_t pccard_devclass; 129652506Simp 1297101905Simp/* Maybe we need to have a slot device? */ 129853873SimpDRIVER_MODULE(pccard, pcic, pccard_driver, pccard_devclass, 0, 0); 129952506SimpDRIVER_MODULE(pccard, pc98pcic, pccard_driver, pccard_devclass, 0, 0); 1300101905SimpDRIVER_MODULE(pccard, cbb, pccard_driver, pccard_devclass, 0, 0); 130153873SimpDRIVER_MODULE(pccard, tcic, pccard_driver, pccard_devclass, 0, 0); 130264927SimpMODULE_VERSION(pccard, 1); 130370715Sjon/*MODULE_DEPEND(pccard, pcic, 1, 1, 1);*/ 1304