pccard.c revision 166901
1229997Sken/* $NetBSD: pcmcia.c,v 1.23 2000/07/28 19:17:02 drochner Exp $ */ 2229997Sken 3229997Sken/*- 4229997Sken * Copyright (c) 1997 Marc Horowitz. All rights reserved. 5229997Sken * 6229997Sken * Redistribution and use in source and binary forms, with or without 7229997Sken * modification, are permitted provided that the following conditions 8229997Sken * are met: 9229997Sken * 1. Redistributions of source code must retain the above copyright 10229997Sken * notice, this list of conditions and the following disclaimer. 11229997Sken * 2. Redistributions in binary form must reproduce the above copyright 12229997Sken * notice, this list of conditions and the following disclaimer in the 13229997Sken * documentation and/or other materials provided with the distribution. 14229997Sken * 3. All advertising materials mentioning features or use of this software 15229997Sken * must display the following acknowledgement: 16229997Sken * This product includes software developed by Marc Horowitz. 17229997Sken * 4. The name of the author may not be used to endorse or promote products 18229997Sken * derived from this software without specific prior written permission. 19229997Sken * 20229997Sken * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21229997Sken * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22229997Sken * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23229997Sken * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24229997Sken * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25229997Sken * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26229997Sken * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27229997Sken * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28229997Sken * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29229997Sken * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30229997Sken */ 31229997Sken 32229997Sken#include <sys/cdefs.h> 33229997Sken__FBSDID("$FreeBSD: head/sys/dev/pccard/pccard.c 166901 2007-02-23 12:19:07Z piso $"); 34229997Sken 35229997Sken#include <sys/param.h> 36229997Sken#include <sys/systm.h> 37229997Sken#include <sys/malloc.h> 38229997Sken#include <sys/module.h> 39229997Sken#include <sys/kernel.h> 40229997Sken#include <sys/queue.h> 41229997Sken#include <sys/sysctl.h> 42229997Sken#include <sys/types.h> 43229997Sken 44229997Sken#include <sys/bus.h> 45229997Sken#include <machine/bus.h> 46229997Sken#include <sys/rman.h> 47229997Sken#include <machine/resource.h> 48229997Sken 49229997Sken#include <net/ethernet.h> 50229997Sken 51229997Sken#include <dev/pccard/pccardreg.h> 52229997Sken#include <dev/pccard/pccardvar.h> 53229997Sken#include <dev/pccard/pccardvarp.h> 54229997Sken#include <dev/pccard/pccard_cis.h> 55229997Sken 56229997Sken#include "power_if.h" 57229997Sken#include "card_if.h" 58229997Sken 59229997Sken#define PCCARDDEBUG 60229997Sken 61229997Sken/* sysctl vars */ 62229997SkenSYSCTL_NODE(_hw, OID_AUTO, pccard, CTLFLAG_RD, 0, "PCCARD parameters"); 63229997Sken 64229997Skenint pccard_debug = 0; 65229997SkenTUNABLE_INT("hw.pccard.debug", &pccard_debug); 66229997SkenSYSCTL_INT(_hw_pccard, OID_AUTO, debug, CTLFLAG_RW, 67229997Sken &pccard_debug, 0, 68229997Sken "pccard debug"); 69229997Sken 70229997Skenint pccard_cis_debug = 0; 71229997SkenTUNABLE_INT("hw.pccard.cis_debug", &pccard_cis_debug); 72229997SkenSYSCTL_INT(_hw_pccard, OID_AUTO, cis_debug, CTLFLAG_RW, 73229997Sken &pccard_cis_debug, 0, "pccard CIS debug"); 74229997Sken 75229997Sken#ifdef PCCARDDEBUG 76229997Sken#define DPRINTF(arg) if (pccard_debug) printf arg 77229997Sken#define DEVPRINTF(arg) if (pccard_debug) device_printf arg 78229997Sken#define PRVERBOSE(arg) printf arg 79229997Sken#define DEVPRVERBOSE(arg) device_printf arg 80229997Sken#else 81229997Sken#define DPRINTF(arg) 82229997Sken#define DEVPRINTF(arg) 83229997Sken#define PRVERBOSE(arg) if (bootverbose) printf arg 84229997Sken#define DEVPRVERBOSE(arg) if (bootverbose) device_printf arg 85229997Sken#endif 86229997Sken 87229997Skenstatic int pccard_ccr_read(struct pccard_function *pf, int ccr); 88229997Skenstatic void pccard_ccr_write(struct pccard_function *pf, int ccr, int val); 89229997Skenstatic int pccard_attach_card(device_t dev); 90229997Skenstatic int pccard_detach_card(device_t dev); 91229997Skenstatic void pccard_function_init(struct pccard_function *pf); 92229997Skenstatic void pccard_function_free(struct pccard_function *pf); 93229997Skenstatic int pccard_function_enable(struct pccard_function *pf); 94229997Skenstatic void pccard_function_disable(struct pccard_function *pf); 95229997Skenstatic int pccard_probe(device_t dev); 96229997Skenstatic int pccard_attach(device_t dev); 97229997Skenstatic int pccard_detach(device_t dev); 98229997Skenstatic void pccard_print_resources(struct resource_list *rl, 99229997Sken const char *name, int type, int count, const char *format); 100229997Skenstatic int pccard_print_child(device_t dev, device_t child); 101229997Skenstatic int pccard_set_resource(device_t dev, device_t child, int type, 102229997Sken int rid, u_long start, u_long count); 103229997Skenstatic int pccard_get_resource(device_t dev, device_t child, int type, 104229997Sken int rid, u_long *startp, u_long *countp); 105229997Skenstatic void pccard_delete_resource(device_t dev, device_t child, int type, 106229997Sken int rid); 107229997Skenstatic int pccard_set_res_flags(device_t dev, device_t child, int type, 108229997Sken int rid, uint32_t flags); 109229997Skenstatic int pccard_set_memory_offset(device_t dev, device_t child, int rid, 110229997Sken uint32_t offset, uint32_t *deltap); 111229997Skenstatic void pccard_probe_nomatch(device_t cbdev, device_t child); 112229997Skenstatic int pccard_read_ivar(device_t bus, device_t child, int which, 113229997Sken u_char *result); 114229997Skenstatic void pccard_driver_added(device_t dev, driver_t *driver); 115229997Skenstatic struct resource *pccard_alloc_resource(device_t dev, 116229997Sken device_t child, int type, int *rid, u_long start, 117229997Sken u_long end, u_long count, u_int flags); 118229997Skenstatic int pccard_release_resource(device_t dev, device_t child, int type, 119229997Sken int rid, struct resource *r); 120229997Skenstatic void pccard_child_detached(device_t parent, device_t dev); 121229997Skenstatic int pccard_intr(void *arg); 122229997Skenstatic int pccard_setup_intr(device_t dev, device_t child, 123229997Sken struct resource *irq, int flags, driver_filter_t *filt, 124229997Sken driver_intr_t *intr, void *arg, void **cookiep); 125229997Skenstatic int pccard_teardown_intr(device_t dev, device_t child, 126229997Sken struct resource *r, void *cookie); 127229997Sken 128229997Skenstatic const struct pccard_product * 129229997Skenpccard_do_product_lookup(device_t bus, device_t dev, 130229997Sken const struct pccard_product *tab, size_t ent_size, 131229997Sken pccard_product_match_fn matchfn); 132229997Sken 133229997Sken 134229997Skenstatic int 135229997Skenpccard_ccr_read(struct pccard_function *pf, int ccr) 136229997Sken{ 137229997Sken return (bus_space_read_1(pf->pf_ccrt, pf->pf_ccrh, 138229997Sken pf->pf_ccr_offset + ccr)); 139229997Sken} 140229997Sken 141229997Skenstatic void 142229997Skenpccard_ccr_write(struct pccard_function *pf, int ccr, int val) 143229997Sken{ 144229997Sken if ((pf->ccr_mask) & (1 << (ccr / 2))) { 145229997Sken bus_space_write_1(pf->pf_ccrt, pf->pf_ccrh, 146229997Sken pf->pf_ccr_offset + ccr, val); 147229997Sken } 148229997Sken} 149229997Sken 150229997Skenstatic int 151229997Skenpccard_set_default_descr(device_t dev) 152229997Sken{ 153229997Sken const char *vendorstr, *prodstr; 154229997Sken uint32_t vendor, prod; 155229997Sken char *str; 156229997Sken 157229997Sken if (pccard_get_vendor_str(dev, &vendorstr)) 158229997Sken return (0); 159229997Sken if (pccard_get_product_str(dev, &prodstr)) 160229997Sken return (0); 161229997Sken if (vendorstr != NULL && prodstr != NULL) { 162229997Sken str = malloc(strlen(vendorstr) + strlen(prodstr) + 2, M_DEVBUF, 163229997Sken M_WAITOK); 164229997Sken sprintf(str, "%s %s", vendorstr, prodstr); 165229997Sken device_set_desc_copy(dev, str); 166229997Sken free(str, M_DEVBUF); 167229997Sken } else { 168229997Sken if (pccard_get_vendor(dev, &vendor)) 169229997Sken return (0); 170229997Sken if (pccard_get_product(dev, &prod)) 171229997Sken return (0); 172229997Sken str = malloc(100, M_DEVBUF, M_WAITOK); 173229997Sken snprintf(str, 100, "vendor=0x%x product=0x%x", vendor, prod); 174229997Sken device_set_desc_copy(dev, str); 175229997Sken free(str, M_DEVBUF); 176229997Sken } 177229997Sken return (0); 178229997Sken} 179229997Sken 180229997Skenstatic int 181229997Skenpccard_attach_card(device_t dev) 182229997Sken{ 183229997Sken struct pccard_softc *sc = PCCARD_SOFTC(dev); 184229997Sken struct pccard_function *pf; 185229997Sken struct pccard_ivar *ivar; 186229997Sken device_t child; 187229997Sken int i; 188229997Sken 189229997Sken if (!STAILQ_EMPTY(&sc->card.pf_head)) { 190229997Sken if (bootverbose || pccard_debug) 191229997Sken device_printf(dev, "Card already inserted.\n"); 192229997Sken } 193229997Sken 194229997Sken DEVPRINTF((dev, "chip_socket_enable\n")); 195229997Sken POWER_ENABLE_SOCKET(device_get_parent(dev), dev); 196229997Sken 197229997Sken DEVPRINTF((dev, "read_cis\n")); 198229997Sken pccard_read_cis(sc); 199229997Sken 200229997Sken DEVPRINTF((dev, "check_cis_quirks\n")); 201229997Sken pccard_check_cis_quirks(dev); 202229997Sken 203229997Sken /* 204229997Sken * bail now if the card has no functions, or if there was an error in 205229997Sken * the cis. 206229997Sken */ 207229997Sken 208229997Sken if (sc->card.error) { 209229997Sken device_printf(dev, "CARD ERROR!\n"); 210229997Sken return (1); 211229997Sken } 212229997Sken if (STAILQ_EMPTY(&sc->card.pf_head)) { 213229997Sken device_printf(dev, "Card has no functions!\n"); 214229997Sken return (1); 215229997Sken } 216229997Sken 217229997Sken if (bootverbose || pccard_debug) 218229997Sken pccard_print_cis(dev); 219229997Sken 220229997Sken DEVPRINTF((dev, "functions scanning\n")); 221229997Sken i = -1; 222229997Sken STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) { 223229997Sken i++; 224229997Sken if (STAILQ_EMPTY(&pf->cfe_head)) { 225229997Sken device_printf(dev, 226229997Sken "Function %d has no config entries.!\n", i); 227229997Sken continue; 228229997Sken } 229229997Sken pf->sc = sc; 230229997Sken pf->cfe = NULL; 231229997Sken pf->dev = NULL; 232229997Sken } 233229997Sken DEVPRINTF((dev, "Card has %d functions. pccard_mfc is %d\n", i + 1, 234229997Sken pccard_mfc(sc))); 235229997Sken 236229997Sken STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) { 237229997Sken if (STAILQ_EMPTY(&pf->cfe_head)) 238229997Sken continue; 239229997Sken /* 240229997Sken * In NetBSD, the drivers are responsible for activating 241229997Sken * each function of a card. I think that in FreeBSD we 242229997Sken * want to activate them enough for the usual bus_*_resource 243229997Sken * routines will do the right thing. This many mean a 244229997Sken * departure from the current NetBSD model. 245229997Sken * 246229997Sken * This seems to work well in practice for most cards. 247229997Sken * However, there are two cases that are problematic. 248229997Sken * If a driver wishes to pick and chose which config 249229997Sken * entry to use, then this method falls down. These 250229997Sken * are usually older cards. In addition, there are 251229997Sken * some cards that have multiple hardware units on the 252229997Sken * cards, but presents only one CIS chain. These cards 253229997Sken * are combination cards, but only one of these units 254229997Sken * can be on at a time. 255229997Sken */ 256229997Sken ivar = malloc(sizeof(struct pccard_ivar), M_DEVBUF, 257229997Sken M_WAITOK | M_ZERO); 258229997Sken resource_list_init(&ivar->resources); 259229997Sken child = device_add_child(dev, NULL, -1); 260229997Sken device_set_ivars(child, ivar); 261229997Sken ivar->pf = pf; 262229997Sken pf->dev = child; 263229997Sken /* 264229997Sken * XXX We might want to move the next three lines into 265229997Sken * XXX the pccard interface layer. For the moment, this 266229997Sken * XXX is OK, but some drivers want to pick the config 267229997Sken * XXX entry to use as well as some address tweaks (mostly 268229997Sken * XXX due to bugs in decode logic that makes some 269229997Sken * XXX addresses illegal or broken). 270229997Sken */ 271229997Sken pccard_function_init(pf); 272229997Sken if (sc->sc_enabled_count == 0) 273229997Sken POWER_ENABLE_SOCKET(device_get_parent(dev), dev); 274229997Sken if (pccard_function_enable(pf) == 0 && 275229997Sken pccard_set_default_descr(child) == 0 && 276229997Sken device_probe_and_attach(child) == 0) { 277229997Sken DEVPRINTF((sc->dev, "function %d CCR at %d " 278229997Sken "offset %x mask %x: " 279229997Sken "%x %x %x %x, %x %x %x %x, %x\n", 280229997Sken pf->number, pf->pf_ccr_window, pf->pf_ccr_offset, 281229997Sken pf->ccr_mask, pccard_ccr_read(pf, 0x00), 282229997Sken pccard_ccr_read(pf, 0x02), pccard_ccr_read(pf, 0x04), 283229997Sken pccard_ccr_read(pf, 0x06), pccard_ccr_read(pf, 0x0A), 284229997Sken pccard_ccr_read(pf, 0x0C), pccard_ccr_read(pf, 0x0E), 285229997Sken pccard_ccr_read(pf, 0x10), pccard_ccr_read(pf, 0x12))); 286229997Sken } else { 287229997Sken if (pf->cfe != NULL) 288229997Sken pccard_function_disable(pf); 289229997Sken } 290229997Sken } 291229997Sken return (0); 292229997Sken} 293229997Sken 294229997Skenstatic int 295229997Skenpccard_detach_card(device_t dev) 296229997Sken{ 297229997Sken struct pccard_softc *sc = PCCARD_SOFTC(dev); 298229997Sken struct pccard_function *pf; 299229997Sken struct pccard_config_entry *cfe; 300229997Sken struct pccard_ivar *devi; 301229997Sken int state; 302229997Sken 303229997Sken /* 304229997Sken * We are running on either the PCCARD socket's event thread 305229997Sken * or in user context detaching a device by user request. 306229997Sken */ 307229997Sken STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) { 308230033Sken if (pf->dev == NULL) 309229997Sken continue; 310229997Sken state = device_get_state(pf->dev); 311230033Sken if (state == DS_ATTACHED || state == DS_BUSY) 312229997Sken device_detach(pf->dev); 313229997Sken if (pf->cfe != NULL) 314229997Sken pccard_function_disable(pf); 315229997Sken pccard_function_free(pf); 316229997Sken devi = PCCARD_IVAR(pf->dev); 317229997Sken device_delete_child(dev, pf->dev); 318229997Sken free(devi, M_DEVBUF); 319229997Sken } 320229997Sken if (sc->sc_enabled_count == 0) 321229997Sken POWER_DISABLE_SOCKET(device_get_parent(dev), dev); 322229997Sken 323229997Sken while (NULL != (pf = STAILQ_FIRST(&sc->card.pf_head))) { 324229997Sken while (NULL != (cfe = STAILQ_FIRST(&pf->cfe_head))) { 325229997Sken STAILQ_REMOVE_HEAD(&pf->cfe_head, cfe_list); 326229997Sken free(cfe, M_DEVBUF); 327229997Sken } 328229997Sken STAILQ_REMOVE_HEAD(&sc->card.pf_head, pf_list); 329229997Sken free(pf, M_DEVBUF); 330229997Sken } 331229997Sken STAILQ_INIT(&sc->card.pf_head); 332229997Sken return (0); 333229997Sken} 334229997Sken 335229997Skenstatic const struct pccard_product * 336229997Skenpccard_do_product_lookup(device_t bus, device_t dev, 337229997Sken const struct pccard_product *tab, size_t ent_size, 338229997Sken pccard_product_match_fn matchfn) 339229997Sken{ 340229997Sken const struct pccard_product *ent; 341229997Sken int matches; 342229997Sken uint32_t vendor; 343229997Sken uint32_t prod; 344229997Sken const char *vendorstr; 345229997Sken const char *prodstr; 346229997Sken const char *cis3str; 347229997Sken const char *cis4str; 348229997Sken 349229997Sken#ifdef DIAGNOSTIC 350229997Sken if (sizeof *ent > ent_size) 351229997Sken panic("pccard_product_lookup: bogus ent_size %jd", 352229997Sken (intmax_t) ent_size); 353229997Sken#endif 354229997Sken if (pccard_get_vendor(dev, &vendor)) 355229997Sken return (NULL); 356229997Sken if (pccard_get_product(dev, &prod)) 357229997Sken return (NULL); 358229997Sken if (pccard_get_vendor_str(dev, &vendorstr)) 359229997Sken return (NULL); 360229997Sken if (pccard_get_product_str(dev, &prodstr)) 361229997Sken return (NULL); 362229997Sken if (pccard_get_cis3_str(dev, &cis3str)) 363229997Sken return (NULL); 364229997Sken if (pccard_get_cis4_str(dev, &cis4str)) 365229997Sken return (NULL); 366229997Sken for (ent = tab; ent->pp_vendor != 0; ent = 367229997Sken (const struct pccard_product *) ((const char *) ent + ent_size)) { 368229997Sken matches = 1; 369229997Sken if (ent->pp_vendor == PCCARD_VENDOR_ANY && 370229997Sken ent->pp_product == PCCARD_PRODUCT_ANY && 371229997Sken ent->pp_cis[0] == NULL && 372229997Sken ent->pp_cis[1] == NULL) { 373229997Sken if (ent->pp_name) 374229997Sken device_printf(dev, 375229997Sken "Total wildcard entry ignored for %s\n", 376229997Sken ent->pp_name); 377229997Sken continue; 378229997Sken } 379229997Sken if (matches && ent->pp_vendor != PCCARD_VENDOR_ANY && 380229997Sken vendor != ent->pp_vendor) 381229997Sken matches = 0; 382229997Sken if (matches && ent->pp_product != PCCARD_PRODUCT_ANY && 383229997Sken prod != ent->pp_product) 384229997Sken matches = 0; 385229997Sken if (matches && ent->pp_cis[0] && 386229997Sken (vendorstr == NULL || 387229997Sken strcmp(ent->pp_cis[0], vendorstr) != 0)) 388229997Sken matches = 0; 389229997Sken if (matches && ent->pp_cis[1] && 390229997Sken (prodstr == NULL || 391229997Sken strcmp(ent->pp_cis[1], prodstr) != 0)) 392229997Sken matches = 0; 393229997Sken if (matches && ent->pp_cis[2] && 394229997Sken (cis3str == NULL || 395229997Sken strcmp(ent->pp_cis[2], cis3str) != 0)) 396229997Sken matches = 0; 397229997Sken if (matches && ent->pp_cis[3] && 398229997Sken (cis4str == NULL || 399229997Sken strcmp(ent->pp_cis[3], cis4str) != 0)) 400229997Sken matches = 0; 401229997Sken if (matchfn != NULL) 402229997Sken matches = (*matchfn)(dev, ent, matches); 403229997Sken if (matches) 404229997Sken return (ent); 405229997Sken } 406229997Sken return (NULL); 407229997Sken} 408229997Sken 409229997Sken/* 410229997Sken * Initialize a PCCARD function. May be called as long as the function is 411229997Sken * disabled. 412229997Sken * 413229997Sken * Note: pccard_function_init should not keep resources allocated. It should 414229997Sken * only set them up ala isa pnp, set the values in the rl lists, and return. 415229997Sken * Any resource held after pccard_function_init is called is a bug. However, 416229997Sken * the bus routines to get the resources also assume that pccard_function_init 417229997Sken * does this, so they need to be fixed too. 418229997Sken */ 419229997Skenstatic void 420229997Skenpccard_function_init(struct pccard_function *pf) 421229997Sken{ 422229997Sken struct pccard_config_entry *cfe; 423229997Sken struct pccard_ivar *devi = PCCARD_IVAR(pf->dev); 424229997Sken struct resource_list *rl = &devi->resources; 425229997Sken struct resource_list_entry *rle; 426230033Sken struct resource *r = 0; 427229997Sken device_t bus; 428229997Sken u_long start, end, len; 429230033Sken int i, rid, spaces; 430229997Sken 431229997Sken if (pf->pf_flags & PFF_ENABLED) { 432229997Sken printf("pccard_function_init: function is enabled"); 433229997Sken return; 434229997Sken } 435229997Sken bus = device_get_parent(pf->dev); 436229997Sken /* Remember which configuration entry we are using. */ 437229997Sken STAILQ_FOREACH(cfe, &pf->cfe_head, cfe_list) { 438229997Sken if (cfe->iftype != PCCARD_IFTYPE_IO) 439229997Sken continue; 440229997Sken spaces = 0; 441229997Sken for (i = 0; i < cfe->num_iospace; i++) { 442229997Sken start = cfe->iospace[i].start; 443229997Sken if (start) 444229997Sken end = start + cfe->iospace[i].length - 1; 445229997Sken else 446229997Sken end = ~0UL; 447229997Sken DEVPRINTF((bus, "I/O rid %d start %lx end %lx\n", 448229997Sken i, start, end)); 449229997Sken rid = i; 450229997Sken len = cfe->iospace[i].length; 451229997Sken r = bus_alloc_resource(bus, SYS_RES_IOPORT, &rid, 452229997Sken start, end, len, rman_make_alignment_flags(len)); 453229997Sken if (r == NULL) 454229997Sken goto not_this_one; 455229997Sken rle = resource_list_add(rl, SYS_RES_IOPORT, 456229997Sken rid, rman_get_start(r), rman_get_end(r), 457229997Sken cfe->iospace[i].length); 458229997Sken if (rle == NULL) 459229997Sken panic("Cannot add resource rid %d IOPORT", rid); 460229997Sken rle->res = r; 461229997Sken spaces++; 462229997Sken } 463229997Sken for (i = 0; i < cfe->num_memspace; i++) { 464229997Sken start = cfe->memspace[i].hostaddr; 465229997Sken if (start) 466229997Sken end = start + cfe->memspace[i].length - 1; 467229997Sken else 468229997Sken end = ~0UL; 469229997Sken DEVPRINTF((bus, "Memory rid %d start %lx end %lx\n", 470229997Sken i, start, end)); 471229997Sken rid = i; 472229997Sken len = cfe->memspace[i].length; 473229997Sken r = bus_alloc_resource(bus, SYS_RES_MEMORY, &rid, 474229997Sken start, end, len, rman_make_alignment_flags(len)); 475229997Sken if (r == NULL) 476229997Sken goto not_this_one; 477229997Sken rle = resource_list_add(rl, SYS_RES_MEMORY, 478229997Sken rid, rman_get_start(r), rman_get_end(r), 479229997Sken cfe->memspace[i].length); 480229997Sken if (rle == NULL) 481229997Sken panic("Cannot add resource rid %d MEM", rid); 482229997Sken rle->res = r; 483229997Sken spaces++; 484229997Sken } 485229997Sken if (spaces == 0) { 486229997Sken DEVPRINTF((bus, "Neither memory nor I/O mapped\n")); 487229997Sken goto not_this_one; 488229997Sken } 489229997Sken if (cfe->irqmask) { 490229997Sken rid = 0; 491229997Sken r = bus_alloc_resource_any(bus, SYS_RES_IRQ, &rid, 492229997Sken RF_SHAREABLE); 493236426Smjacob if (r == NULL) 494229997Sken goto not_this_one; 495229997Sken rle = resource_list_add(rl, SYS_RES_IRQ, rid, 496229997Sken rman_get_start(r), rman_get_end(r), 1); 497229997Sken if (rle == NULL) 498229997Sken panic("Cannot add resource rid %d IRQ", rid); 499229997Sken rle->res = r; 500229997Sken } 501229997Sken /* If we get to here, we've allocated all we need */ 502229997Sken pf->cfe = cfe; 503229997Sken break; 504229997Sken not_this_one:; 505229997Sken DEVPRVERBOSE((bus, "Allocation failed for cfe %d\n", 506229997Sken cfe->number)); 507229997Sken resource_list_purge(rl); 508229997Sken } 509229997Sken} 510229997Sken 511229997Sken/* 512229997Sken * Free resources allocated by pccard_function_init(), May be called as long 513229997Sken * as the function is disabled. 514229997Sken * 515229997Sken * NOTE: This function should be unnecessary. pccard_function_init should 516229997Sken * never keep resources initialized. 517229997Sken */ 518229997Skenstatic void 519229997Skenpccard_function_free(struct pccard_function *pf) 520229997Sken{ 521229997Sken struct pccard_ivar *devi = PCCARD_IVAR(pf->dev); 522229997Sken struct resource_list_entry *rle; 523229997Sken 524229997Sken if (pf->pf_flags & PFF_ENABLED) { 525229997Sken printf("pccard_function_init: function is enabled"); 526229997Sken return; 527229997Sken } 528229997Sken 529229997Sken STAILQ_FOREACH(rle, &devi->resources, link) { 530229997Sken if (rle->res) { 531229997Sken if (rman_get_device(rle->res) != pf->sc->dev) 532229997Sken device_printf(pf->sc->dev, 533229997Sken "function_free: Resource still owned by " 534229997Sken "child, oops. " 535229997Sken "(type=%d, rid=%d, addr=%lx)\n", 536229997Sken rle->type, rle->rid, 537229997Sken rman_get_start(rle->res)); 538229997Sken BUS_RELEASE_RESOURCE(device_get_parent(pf->sc->dev), 539229997Sken pf->sc->dev, rle->type, rle->rid, rle->res); 540229997Sken rle->res = NULL; 541229997Sken } 542229997Sken } 543229997Sken resource_list_free(&devi->resources); 544229997Sken} 545229997Sken 546229997Skenstatic void 547229997Skenpccard_mfc_adjust_iobase(struct pccard_function *pf, bus_addr_t addr, 548229997Sken bus_addr_t offset, bus_size_t size) 549229997Sken{ 550229997Sken bus_size_t iosize, tmp; 551229997Sken 552229997Sken if (addr != 0) { 553229997Sken if (pf->pf_mfc_iomax == 0) { 554229997Sken pf->pf_mfc_iobase = addr + offset; 555229997Sken pf->pf_mfc_iomax = pf->pf_mfc_iobase + size; 556229997Sken } else { 557229997Sken /* this makes the assumption that nothing overlaps */ 558229997Sken if (pf->pf_mfc_iobase > addr + offset) 559229997Sken pf->pf_mfc_iobase = addr + offset; 560229997Sken if (pf->pf_mfc_iomax < addr + offset + size) 561229997Sken pf->pf_mfc_iomax = addr + offset + size; 562229997Sken } 563229997Sken } 564229997Sken 565229997Sken tmp = pf->pf_mfc_iomax - pf->pf_mfc_iobase; 566229997Sken /* round up to nearest (2^n)-1 */ 567229997Sken for (iosize = 1; iosize < tmp; iosize <<= 1) 568229997Sken ; 569229997Sken iosize--; 570229997Sken 571229997Sken DEVPRINTF((pf->dev, "MFC: I/O base %#jx IOSIZE %#jx\n", 572229997Sken (uintmax_t)pf->pf_mfc_iobase, (uintmax_t)(iosize + 1))); 573229997Sken pccard_ccr_write(pf, PCCARD_CCR_IOBASE0, 574229997Sken pf->pf_mfc_iobase & 0xff); 575229997Sken pccard_ccr_write(pf, PCCARD_CCR_IOBASE1, 576229997Sken (pf->pf_mfc_iobase >> 8) & 0xff); 577229997Sken pccard_ccr_write(pf, PCCARD_CCR_IOBASE2, 0); 578229997Sken pccard_ccr_write(pf, PCCARD_CCR_IOBASE3, 0); 579229997Sken pccard_ccr_write(pf, PCCARD_CCR_IOSIZE, iosize); 580229997Sken} 581229997Sken 582229997Sken/* Enable a PCCARD function */ 583229997Skenstatic int 584229997Skenpccard_function_enable(struct pccard_function *pf) 585236426Smjacob{ 586229997Sken struct pccard_function *tmp; 587229997Sken int reg; 588229997Sken device_t dev = pf->sc->dev; 589229997Sken 590229997Sken if (pf->cfe == NULL) { 591229997Sken DEVPRVERBOSE((dev, "No config entry could be allocated.\n")); 592229997Sken return (ENOMEM); 593229997Sken } 594229997Sken 595229997Sken /* 596229997Sken * Increase the reference count on the socket, enabling power, if 597229997Sken * necessary. 598229997Sken */ 599229997Sken pf->sc->sc_enabled_count++; 600229997Sken 601229997Sken if (pf->pf_flags & PFF_ENABLED) { 602229997Sken /* 603229997Sken * Don't do anything if we're already enabled. 604229997Sken */ 605229997Sken return (0); 606229997Sken } 607229997Sken 608229997Sken /* 609229997Sken * it's possible for different functions' CCRs to be in the same 610229997Sken * underlying page. Check for that. 611229997Sken */ 612229997Sken STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) { 613229997Sken if ((tmp->pf_flags & PFF_ENABLED) && 614229997Sken (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) && 615229997Sken ((pf->ccr_base + PCCARD_CCR_SIZE) <= 616229997Sken (tmp->ccr_base - tmp->pf_ccr_offset + 617229997Sken tmp->pf_ccr_realsize))) { 618229997Sken pf->pf_ccrt = tmp->pf_ccrt; 619236426Smjacob pf->pf_ccrh = tmp->pf_ccrh; 620229997Sken pf->pf_ccr_realsize = tmp->pf_ccr_realsize; 621229997Sken 622229997Sken /* 623229997Sken * pf->pf_ccr_offset = (tmp->pf_ccr_offset - 624229997Sken * tmp->ccr_base) + pf->ccr_base; 625229997Sken */ 626229997Sken /* pf->pf_ccr_offset = 627229997Sken (tmp->pf_ccr_offset + pf->ccr_base) - 628229997Sken tmp->ccr_base; */ 629229997Sken pf->pf_ccr_window = tmp->pf_ccr_window; 630229997Sken break; 631229997Sken } 632229997Sken } 633229997Sken if (tmp == NULL) { 634229997Sken pf->ccr_rid = 0; 635229997Sken pf->ccr_res = bus_alloc_resource(dev, SYS_RES_MEMORY, 636229997Sken &pf->ccr_rid, 0, ~0, PCCARD_MEM_PAGE_SIZE, RF_ACTIVE); 637229997Sken if (!pf->ccr_res) 638229997Sken goto bad; 639229997Sken DEVPRINTF((dev, "ccr_res == %lx-%lx, base=%x\n", 640229997Sken rman_get_start(pf->ccr_res), rman_get_end(pf->ccr_res), 641229997Sken pf->ccr_base)); 642229997Sken CARD_SET_RES_FLAGS(device_get_parent(dev), dev, SYS_RES_MEMORY, 643229997Sken pf->ccr_rid, PCCARD_A_MEM_ATTR); 644229997Sken CARD_SET_MEMORY_OFFSET(device_get_parent(dev), dev, 645229997Sken pf->ccr_rid, pf->ccr_base, &pf->pf_ccr_offset); 646229997Sken pf->pf_ccrt = rman_get_bustag(pf->ccr_res); 647229997Sken pf->pf_ccrh = rman_get_bushandle(pf->ccr_res); 648229997Sken pf->pf_ccr_realsize = 1; 649229997Sken } 650229997Sken 651229997Sken reg = (pf->cfe->number & PCCARD_CCR_OPTION_CFINDEX); 652229997Sken reg |= PCCARD_CCR_OPTION_LEVIREQ; 653229997Sken if (pccard_mfc(pf->sc)) { 654229997Sken reg |= (PCCARD_CCR_OPTION_FUNC_ENABLE | 655229997Sken PCCARD_CCR_OPTION_ADDR_DECODE); 656229997Sken /* PCCARD_CCR_OPTION_IRQ_ENABLE set elsewhere as needed */ 657229997Sken } 658229997Sken pccard_ccr_write(pf, PCCARD_CCR_OPTION, reg); 659229997Sken 660229997Sken reg = 0; 661229997Sken if ((pf->cfe->flags & PCCARD_CFE_IO16) == 0) 662229997Sken reg |= PCCARD_CCR_STATUS_IOIS8; 663229997Sken if (pf->cfe->flags & PCCARD_CFE_AUDIO) 664229997Sken reg |= PCCARD_CCR_STATUS_AUDIO; 665229997Sken pccard_ccr_write(pf, PCCARD_CCR_STATUS, reg); 666229997Sken 667229997Sken pccard_ccr_write(pf, PCCARD_CCR_SOCKETCOPY, 0); 668229997Sken 669229997Sken if (pccard_mfc(pf->sc)) 670229997Sken pccard_mfc_adjust_iobase(pf, 0, 0, 0); 671229997Sken 672229997Sken#ifdef PCCARDDEBUG 673229997Sken if (pccard_debug) { 674229997Sken STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) { 675229997Sken device_printf(tmp->sc->dev, 676229997Sken "function %d CCR at %d offset %x: " 677229997Sken "%x %x %x %x, %x %x %x %x, %x\n", 678229997Sken tmp->number, tmp->pf_ccr_window, 679229997Sken tmp->pf_ccr_offset, 680229997Sken pccard_ccr_read(tmp, 0x00), 681229997Sken pccard_ccr_read(tmp, 0x02), 682229997Sken pccard_ccr_read(tmp, 0x04), 683229997Sken pccard_ccr_read(tmp, 0x06), 684229997Sken pccard_ccr_read(tmp, 0x0A), 685229997Sken pccard_ccr_read(tmp, 0x0C), 686229997Sken pccard_ccr_read(tmp, 0x0E), 687229997Sken pccard_ccr_read(tmp, 0x10), 688229997Sken pccard_ccr_read(tmp, 0x12)); 689229997Sken } 690229997Sken } 691229997Sken#endif 692229997Sken pf->pf_flags |= PFF_ENABLED; 693229997Sken return (0); 694229997Sken 695229997Sken bad: 696229997Sken /* 697229997Sken * Decrement the reference count, and power down the socket, if 698229997Sken * necessary. 699229997Sken */ 700229997Sken pf->sc->sc_enabled_count--; 701229997Sken DEVPRINTF((dev, "bad --enabled_count = %d\n", pf->sc->sc_enabled_count)); 702229997Sken 703229997Sken return (1); 704229997Sken} 705229997Sken 706229997Sken/* Disable PCCARD function. */ 707229997Skenstatic void 708229997Skenpccard_function_disable(struct pccard_function *pf) 709229997Sken{ 710229997Sken struct pccard_function *tmp; 711229997Sken device_t dev = pf->sc->dev; 712229997Sken 713229997Sken if (pf->cfe == NULL) 714229997Sken panic("pccard_function_disable: function not initialized"); 715229997Sken 716229997Sken if ((pf->pf_flags & PFF_ENABLED) == 0) { 717229997Sken /* 718229997Sken * Don't do anything if we're already disabled. 719229997Sken */ 720229997Sken return; 721229997Sken } 722229997Sken 723229997Sken if (pf->intr_handler != NULL) { 724229997Sken struct pccard_ivar *devi = PCCARD_IVAR(pf->dev); 725229997Sken struct resource_list_entry *rle = 726229997Sken resource_list_find(&devi->resources, SYS_RES_IRQ, 0); 727229997Sken if (rle == NULL) 728229997Sken panic("Can't disable an interrupt with no IRQ res\n"); 729229997Sken BUS_TEARDOWN_INTR(dev, pf->dev, rle->res, 730229997Sken pf->intr_handler_cookie); 731229997Sken } 732229997Sken 733229997Sken /* 734229997Sken * it's possible for different functions' CCRs to be in the same 735229997Sken * underlying page. Check for that. Note we mark us as disabled 736229997Sken * first to avoid matching ourself. 737229997Sken */ 738229997Sken 739229997Sken pf->pf_flags &= ~PFF_ENABLED; 740229997Sken STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) { 741229997Sken if ((tmp->pf_flags & PFF_ENABLED) && 742229997Sken (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) && 743229997Sken ((pf->ccr_base + PCCARD_CCR_SIZE) <= 744229997Sken (tmp->ccr_base - tmp->pf_ccr_offset + 745229997Sken tmp->pf_ccr_realsize))) 746229997Sken break; 747229997Sken } 748229997Sken 749229997Sken /* Not used by anyone else; unmap the CCR. */ 750229997Sken if (tmp == NULL) { 751229997Sken bus_release_resource(dev, SYS_RES_MEMORY, pf->ccr_rid, 752229997Sken pf->ccr_res); 753229997Sken pf->ccr_res = NULL; 754229997Sken } 755229997Sken 756229997Sken /* 757229997Sken * Decrement the reference count, and power down the socket, if 758229997Sken * necessary. 759229997Sken */ 760229997Sken pf->sc->sc_enabled_count--; 761229997Sken} 762229997Sken 763229997Sken#define PCCARD_NPORT 2 764229997Sken#define PCCARD_NMEM 5 765229997Sken#define PCCARD_NIRQ 1 766229997Sken#define PCCARD_NDRQ 0 767229997Sken 768229997Skenstatic int 769229997Skenpccard_probe(device_t dev) 770229997Sken{ 771229997Sken device_set_desc(dev, "16-bit PCCard bus"); 772229997Sken return (0); 773229997Sken} 774229997Sken 775229997Skenstatic int 776229997Skenpccard_attach(device_t dev) 777229997Sken{ 778229997Sken struct pccard_softc *sc = PCCARD_SOFTC(dev); 779229997Sken int err; 780229997Sken 781229997Sken sc->dev = dev; 782229997Sken sc->sc_enabled_count = 0; 783229997Sken if ((err = pccard_device_create(sc)) != 0) 784229997Sken return (err); 785229997Sken STAILQ_INIT(&sc->card.pf_head); 786229997Sken return (bus_generic_attach(dev)); 787229997Sken} 788229997Sken 789229997Skenstatic int 790229997Skenpccard_detach(device_t dev) 791229997Sken{ 792229997Sken pccard_detach_card(dev); 793229997Sken pccard_device_destroy(device_get_softc(dev)); 794229997Sken return (0); 795229997Sken} 796229997Sken 797229997Skenstatic int 798229997Skenpccard_suspend(device_t self) 799229997Sken{ 800229997Sken pccard_detach_card(self); 801229997Sken return (0); 802229997Sken} 803229997Sken 804229997Skenstatic 805229997Skenint 806229997Skenpccard_resume(device_t self) 807229997Sken{ 808229997Sken return (0); 809229997Sken} 810229997Sken 811229997Skenstatic void 812229997Skenpccard_print_resources(struct resource_list *rl, const char *name, int type, 813229997Sken int count, const char *format) 814229997Sken{ 815229997Sken struct resource_list_entry *rle; 816229997Sken int printed; 817229997Sken int i; 818229997Sken 819229997Sken printed = 0; 820229997Sken for (i = 0; i < count; i++) { 821229997Sken rle = resource_list_find(rl, type, i); 822229997Sken if (rle != NULL) { 823229997Sken if (printed == 0) 824229997Sken printf(" %s ", name); 825229997Sken else if (printed > 0) 826229997Sken printf(","); 827229997Sken printed++; 828229997Sken printf(format, rle->start); 829229997Sken if (rle->count > 1) { 830229997Sken printf("-"); 831229997Sken printf(format, rle->start + rle->count - 1); 832229997Sken } 833229997Sken } else if (i > 3) { 834229997Sken /* check the first few regardless */ 835229997Sken break; 836229997Sken } 837229997Sken } 838229997Sken} 839229997Sken 840229997Skenstatic int 841229997Skenpccard_print_child(device_t dev, device_t child) 842229997Sken{ 843229997Sken struct pccard_ivar *devi = PCCARD_IVAR(child); 844229997Sken struct resource_list *rl = &devi->resources; 845229997Sken int retval = 0; 846229997Sken 847229997Sken retval += bus_print_child_header(dev, child); 848229997Sken retval += printf(" at"); 849229997Sken 850229997Sken if (devi != NULL) { 851229997Sken pccard_print_resources(rl, "port", SYS_RES_IOPORT, 852229997Sken PCCARD_NPORT, "%#lx"); 853229997Sken pccard_print_resources(rl, "iomem", SYS_RES_MEMORY, 854229997Sken PCCARD_NMEM, "%#lx"); 855229997Sken pccard_print_resources(rl, "irq", SYS_RES_IRQ, PCCARD_NIRQ, 856229997Sken "%ld"); 857229997Sken pccard_print_resources(rl, "drq", SYS_RES_DRQ, PCCARD_NDRQ, 858229997Sken "%ld"); 859229997Sken retval += printf(" function %d config %d", devi->pf->number, 860229997Sken devi->pf->cfe->number); 861229997Sken } 862229997Sken 863229997Sken retval += bus_print_child_footer(dev, child); 864229997Sken 865229997Sken return (retval); 866229997Sken} 867229997Sken 868229997Skenstatic int 869229997Skenpccard_set_resource(device_t dev, device_t child, int type, int rid, 870229997Sken u_long start, u_long count) 871229997Sken{ 872229997Sken struct pccard_ivar *devi = PCCARD_IVAR(child); 873229997Sken struct resource_list *rl = &devi->resources; 874229997Sken 875229997Sken if (type != SYS_RES_IOPORT && type != SYS_RES_MEMORY 876229997Sken && type != SYS_RES_IRQ && type != SYS_RES_DRQ) 877229997Sken return (EINVAL); 878229997Sken if (rid < 0) 879229997Sken return (EINVAL); 880229997Sken if (type == SYS_RES_IOPORT && rid >= PCCARD_NPORT) 881229997Sken return (EINVAL); 882229997Sken if (type == SYS_RES_MEMORY && rid >= PCCARD_NMEM) 883229997Sken return (EINVAL); 884229997Sken if (type == SYS_RES_IRQ && rid >= PCCARD_NIRQ) 885229997Sken return (EINVAL); 886229997Sken if (type == SYS_RES_DRQ && rid >= PCCARD_NDRQ) 887229997Sken return (EINVAL); 888229997Sken 889229997Sken resource_list_add(rl, type, rid, start, start + count - 1, count); 890229997Sken if (NULL != resource_list_alloc(rl, device_get_parent(dev), dev, 891229997Sken type, &rid, start, start + count - 1, count, 0)) 892229997Sken return 0; 893229997Sken else 894229997Sken return ENOMEM; 895229997Sken} 896229997Sken 897229997Skenstatic int 898229997Skenpccard_get_resource(device_t dev, device_t child, int type, int rid, 899229997Sken u_long *startp, u_long *countp) 900229997Sken{ 901229997Sken struct pccard_ivar *devi = PCCARD_IVAR(child); 902229997Sken struct resource_list *rl = &devi->resources; 903229997Sken struct resource_list_entry *rle; 904229997Sken 905229997Sken rle = resource_list_find(rl, type, rid); 906229997Sken if (rle == NULL) 907229997Sken return (ENOENT); 908229997Sken 909229997Sken if (startp != NULL) 910229997Sken *startp = rle->start; 911229997Sken if (countp != NULL) 912229997Sken *countp = rle->count; 913229997Sken 914229997Sken return (0); 915229997Sken} 916229997Sken 917229997Skenstatic void 918229997Skenpccard_delete_resource(device_t dev, device_t child, int type, int rid) 919229997Sken{ 920229997Sken struct pccard_ivar *devi = PCCARD_IVAR(child); 921229997Sken struct resource_list *rl = &devi->resources; 922229997Sken resource_list_delete(rl, type, rid); 923229997Sken} 924229997Sken 925229997Skenstatic int 926229997Skenpccard_set_res_flags(device_t dev, device_t child, int type, int rid, 927229997Sken uint32_t flags) 928229997Sken{ 929229997Sken return (CARD_SET_RES_FLAGS(device_get_parent(dev), child, type, 930229997Sken rid, flags)); 931229997Sken} 932229997Sken 933229997Skenstatic int 934229997Skenpccard_set_memory_offset(device_t dev, device_t child, int rid, 935229997Sken uint32_t offset, uint32_t *deltap) 936229997Sken 937229997Sken{ 938229997Sken return (CARD_SET_MEMORY_OFFSET(device_get_parent(dev), child, rid, 939229997Sken offset, deltap)); 940229997Sken} 941229997Sken 942229997Skenstatic void 943229997Skenpccard_probe_nomatch(device_t bus, device_t child) 944229997Sken{ 945229997Sken struct pccard_ivar *devi = PCCARD_IVAR(child); 946229997Sken struct pccard_function *pf = devi->pf; 947229997Sken struct pccard_softc *sc = PCCARD_SOFTC(bus); 948229997Sken int i; 949229997Sken 950229997Sken device_printf(bus, "<unknown card>"); 951229997Sken printf(" (manufacturer=0x%04x, product=0x%04x, function_type=%d) " 952229997Sken "at function %d\n", sc->card.manufacturer, sc->card.product, 953229997Sken pf->function, pf->number); 954229997Sken device_printf(bus, " CIS info: "); 955229997Sken for (i = 0; sc->card.cis1_info[i] != NULL && i < 4; i++) 956229997Sken printf("%s%s", i > 0 ? ", " : "", sc->card.cis1_info[i]); 957229997Sken printf("\n"); 958229997Sken return; 959229997Sken} 960229997Sken 961229997Skenstatic int 962229997Skenpccard_child_location_str(device_t bus, device_t child, char *buf, 963229997Sken size_t buflen) 964229997Sken{ 965229997Sken struct pccard_ivar *devi = PCCARD_IVAR(child); 966229997Sken struct pccard_function *pf = devi->pf; 967229997Sken 968229997Sken snprintf(buf, buflen, "function=%d", pf->number); 969229997Sken return (0); 970229997Sken} 971229997Sken 972229997Sken/* XXX Maybe this should be in subr_bus? */ 973229997Skenstatic void 974229997Skenpccard_safe_quote(char *dst, const char *src, size_t len) 975229997Sken{ 976229997Sken char *walker = dst, *ep = dst + len - 1; 977229997Sken 978229997Sken if (len == 0) 979229997Sken return; 980229997Sken while (src != NULL && walker < ep) 981229997Sken { 982229997Sken if (*src == '"') { 983229997Sken if (ep - walker < 2) 984229997Sken break; 985229997Sken *walker++ = '\\'; 986229997Sken } 987229997Sken *walker++ = *src++; 988229997Sken } 989229997Sken *walker = '\0'; 990229997Sken} 991229997Sken 992229997Skenstatic int 993229997Skenpccard_child_pnpinfo_str(device_t bus, device_t child, char *buf, 994229997Sken size_t buflen) 995229997Sken{ 996229997Sken struct pccard_ivar *devi = PCCARD_IVAR(child); 997229997Sken struct pccard_function *pf = devi->pf; 998229997Sken struct pccard_softc *sc = PCCARD_SOFTC(bus); 999229997Sken char cis0[128], cis1[128]; 1000229997Sken 1001229997Sken pccard_safe_quote(cis0, sc->card.cis1_info[0], sizeof(cis0)); 1002229997Sken pccard_safe_quote(cis1, sc->card.cis1_info[1], sizeof(cis1)); 1003229997Sken snprintf(buf, buflen, "manufacturer=0x%04x product=0x%04x " 1004229997Sken "cisvendor=\"%s\" cisproduct=\"%s\" function_type=%d", 1005229997Sken sc->card.manufacturer, sc->card.product, cis0, cis1, pf->function); 1006229997Sken return (0); 1007229997Sken} 1008229997Sken 1009229997Skenstatic int 1010229997Skenpccard_read_ivar(device_t bus, device_t child, int which, u_char *result) 1011229997Sken{ 1012229997Sken struct pccard_ivar *devi = PCCARD_IVAR(child); 1013229997Sken struct pccard_function *pf = devi->pf; 1014229997Sken struct pccard_softc *sc = PCCARD_SOFTC(bus); 1015229997Sken 1016229997Sken if (!pf) 1017229997Sken panic("No pccard function pointer"); 1018229997Sken switch (which) { 1019229997Sken default: 1020229997Sken return (EINVAL); 1021229997Sken case PCCARD_IVAR_ETHADDR: 1022229997Sken bcopy(pf->pf_funce_lan_nid, result, ETHER_ADDR_LEN); 1023229997Sken break; 1024229997Sken case PCCARD_IVAR_VENDOR: 1025229997Sken *(uint32_t *)result = sc->card.manufacturer; 1026229997Sken break; 1027229997Sken case PCCARD_IVAR_PRODUCT: 1028229997Sken *(uint32_t *)result = sc->card.product; 1029229997Sken break; 1030229997Sken case PCCARD_IVAR_PRODEXT: 1031229997Sken *(uint16_t *)result = sc->card.prodext; 1032229997Sken break; 1033229997Sken case PCCARD_IVAR_FUNCTION: 1034229997Sken *(uint32_t *)result = pf->function; 1035229997Sken break; 1036229997Sken case PCCARD_IVAR_FUNCTION_NUMBER: 1037229997Sken *(uint32_t *)result = pf->number; 1038229997Sken break; 1039229997Sken case PCCARD_IVAR_VENDOR_STR: 1040229997Sken *(const char **)result = sc->card.cis1_info[0]; 1041229997Sken break; 1042229997Sken case PCCARD_IVAR_PRODUCT_STR: 1043229997Sken *(const char **)result = sc->card.cis1_info[1]; 1044229997Sken break; 1045229997Sken case PCCARD_IVAR_CIS3_STR: 1046229997Sken *(const char **)result = sc->card.cis1_info[2]; 1047229997Sken break; 1048229997Sken case PCCARD_IVAR_CIS4_STR: 1049229997Sken *(const char **)result = sc->card.cis1_info[3]; 1050229997Sken break; 1051229997Sken } 1052229997Sken return (0); 1053229997Sken} 1054229997Sken 1055229997Skenstatic void 1056229997Skenpccard_driver_added(device_t dev, driver_t *driver) 1057229997Sken{ 1058229997Sken struct pccard_softc *sc = PCCARD_SOFTC(dev); 1059229997Sken struct pccard_function *pf; 1060229997Sken device_t child; 1061229997Sken 1062229997Sken STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) { 1063229997Sken if (STAILQ_EMPTY(&pf->cfe_head)) 1064229997Sken continue; 1065229997Sken child = pf->dev; 1066229997Sken if (device_get_state(child) != DS_NOTPRESENT) 1067229997Sken continue; 1068229997Sken if (pccard_function_enable(pf) == 0 && 1069229997Sken device_probe_and_attach(child) == 0) { 1070229997Sken DEVPRINTF((sc->dev, "function %d CCR at %d " 1071229997Sken "offset %x: %x %x %x %x, %x %x %x %x, %x\n", 1072229997Sken pf->number, pf->pf_ccr_window, pf->pf_ccr_offset, 1073229997Sken pccard_ccr_read(pf, 0x00), 1074229997Sken pccard_ccr_read(pf, 0x02), pccard_ccr_read(pf, 0x04), 1075229997Sken pccard_ccr_read(pf, 0x06), pccard_ccr_read(pf, 0x0A), 1076229997Sken pccard_ccr_read(pf, 0x0C), pccard_ccr_read(pf, 0x0E), 1077229997Sken pccard_ccr_read(pf, 0x10), pccard_ccr_read(pf, 0x12))); 1078229997Sken } else { 1079229997Sken if (pf->cfe != NULL) 1080229997Sken pccard_function_disable(pf); 1081229997Sken } 1082229997Sken } 1083229997Sken return; 1084229997Sken} 1085229997Sken 1086229997Skenstatic struct resource * 1087229997Skenpccard_alloc_resource(device_t dev, device_t child, int type, int *rid, 1088229997Sken u_long start, u_long end, u_long count, u_int flags) 1089229997Sken{ 1090229997Sken struct pccard_ivar *dinfo; 1091229997Sken struct resource_list_entry *rle = 0; 1092229997Sken int passthrough = (device_get_parent(child) != dev); 1093229997Sken int isdefault = (start == 0 && end == ~0UL && count == 1); 1094229997Sken struct resource *r = NULL; 1095229997Sken 1096229997Sken /* XXX I'm no longer sure this is right */ 1097229997Sken if (passthrough) { 1098229997Sken return (BUS_ALLOC_RESOURCE(device_get_parent(dev), child, 1099229997Sken type, rid, start, end, count, flags)); 1100229997Sken } 1101229997Sken 1102229997Sken dinfo = device_get_ivars(child); 1103229997Sken rle = resource_list_find(&dinfo->resources, type, *rid); 1104229997Sken 1105229997Sken if (rle == NULL && isdefault) 1106229997Sken return (NULL); /* no resource of that type/rid */ 1107229997Sken if (rle == NULL || rle->res == NULL) { 1108229997Sken /* XXX Need to adjust flags */ 1109229997Sken r = bus_alloc_resource(dev, type, rid, start, end, 1110229997Sken count, flags); 1111229997Sken if (r == NULL) 1112229997Sken goto bad; 1113229997Sken resource_list_add(&dinfo->resources, type, *rid, 1114229997Sken rman_get_start(r), rman_get_end(r), count); 1115229997Sken rle = resource_list_find(&dinfo->resources, type, *rid); 1116229997Sken if (!rle) 1117229997Sken goto bad; 1118229997Sken rle->res = r; 1119229997Sken } 1120229997Sken /* 1121229997Sken * If dev doesn't own the device, then we can't give this device 1122229997Sken * out. 1123229997Sken */ 1124229997Sken if (rman_get_device(rle->res) != dev) 1125229997Sken return (NULL); 1126229997Sken rman_set_device(rle->res, child); 1127229997Sken if (flags & RF_ACTIVE) 1128229997Sken BUS_ACTIVATE_RESOURCE(dev, child, type, *rid, rle->res); 1129229997Sken return (rle->res); 1130229997Skenbad:; 1131229997Sken device_printf(dev, "WARNING: Resource not reserved by pccard\n"); 1132229997Sken return (NULL); 1133229997Sken} 1134229997Sken 1135229997Skenstatic int 1136229997Skenpccard_release_resource(device_t dev, device_t child, int type, int rid, 1137229997Sken struct resource *r) 1138229997Sken{ 1139229997Sken struct pccard_ivar *dinfo; 1140229997Sken int passthrough = (device_get_parent(child) != dev); 1141229997Sken struct resource_list_entry *rle = 0; 1142229997Sken 1143229997Sken if (passthrough) 1144229997Sken return BUS_RELEASE_RESOURCE(device_get_parent(dev), child, 1145229997Sken type, rid, r); 1146229997Sken 1147229997Sken dinfo = device_get_ivars(child); 1148229997Sken 1149229997Sken rle = resource_list_find(&dinfo->resources, type, rid); 1150229997Sken 1151229997Sken if (!rle) { 1152229997Sken device_printf(dev, "Allocated resource not found, " 1153229997Sken "%d %x %lx %lx\n", 1154229997Sken type, rid, rman_get_start(r), rman_get_size(r)); 1155229997Sken return ENOENT; 1156229997Sken } 1157229997Sken if (!rle->res) { 1158229997Sken device_printf(dev, "Allocated resource not recorded\n"); 1159229997Sken return ENOENT; 1160229997Sken } 1161229997Sken /* 1162229997Sken * Deactivate the resource (since it is being released), and 1163229997Sken * assign it to the bus. 1164229997Sken */ 1165229997Sken BUS_DEACTIVATE_RESOURCE(dev, child, type, rid, rle->res); 1166229997Sken rman_set_device(rle->res, dev); 1167229997Sken return (0); 1168229997Sken} 1169229997Sken 1170229997Skenstatic void 1171229997Skenpccard_child_detached(device_t parent, device_t dev) 1172229997Sken{ 1173229997Sken struct pccard_ivar *ivar = PCCARD_IVAR(dev); 1174229997Sken struct pccard_function *pf = ivar->pf; 1175229997Sken 1176229997Sken pccard_function_disable(pf); 1177229997Sken} 1178229997Sken 1179229997Skenstatic int 1180229997Skenpccard_intr(void *arg) 1181229997Sken{ 1182229997Sken struct pccard_function *pf = (struct pccard_function*) arg; 1183229997Sken int reg; 1184229997Sken int doisr = 1; 1185229997Sken 1186229997Sken /* 1187229997Sken * MFC cards know if they interrupted, so we have to ack the 1188229997Sken * interrupt and call the ISR. Non-MFC cards don't have these 1189229997Sken * bits, so they always get called. Many non-MFC cards have 1190229997Sken * this bit set always upon read, but some do not. 1191229997Sken * 1192229997Sken * We always ack the interrupt, even if there's no ISR 1193229997Sken * for the card. This is done on the theory that acking 1194229997Sken * the interrupt will pacify the card enough to keep an 1195229997Sken * interrupt storm from happening. Of course this won't 1196229997Sken * help in the non-MFC case. 1197229997Sken * 1198229997Sken * This has no impact for MPSAFEness of the client drivers. 1199229997Sken * We register this with whatever flags the intr_handler 1200229997Sken * was registered with. All these functions are MPSAFE. 1201229997Sken */ 1202229997Sken if (pccard_mfc(pf->sc)) { 1203229997Sken reg = pccard_ccr_read(pf, PCCARD_CCR_STATUS); 1204229997Sken if (reg & PCCARD_CCR_STATUS_INTR) 1205229997Sken pccard_ccr_write(pf, PCCARD_CCR_STATUS, 1206229997Sken reg & ~PCCARD_CCR_STATUS_INTR); 1207229997Sken else 1208229997Sken doisr = 0; 1209229997Sken } 1210229997Sken if (doisr) { 1211229997Sken if (pf->filt_handler != NULL) 1212229997Sken pf->filt_handler(pf->intr_handler_arg); 1213229997Sken else 1214229997Sken pf->intr_handler(pf->intr_handler_arg); 1215229997Sken } 1216229997Sken return (FILTER_HANDLED); 1217229997Sken} 1218229997Sken 1219229997Skenstatic int 1220229997Skenpccard_setup_intr(device_t dev, device_t child, struct resource *irq, 1221229997Sken int flags, driver_filter_t *filt, driver_intr_t *intr, void *arg, 1222229997Sken void **cookiep) 1223229997Sken{ 1224229997Sken struct pccard_softc *sc = PCCARD_SOFTC(dev); 1225229997Sken struct pccard_ivar *ivar = PCCARD_IVAR(child); 1226229997Sken struct pccard_function *pf = ivar->pf; 1227229997Sken int err; 1228229997Sken 1229229997Sken if (pf->intr_handler != NULL) 1230229997Sken panic("Only one interrupt handler per function allowed"); 1231229997Sken if (filt != NULL && intr != NULL) 1232229997Sken return (EINVAL); 1233229997Sken if (filt != NULL) 1234229997Sken err = bus_generic_setup_intr(dev, child, irq, flags, 1235229997Sken pccard_intr, NULL, pf, cookiep); 1236229997Sken else 1237229997Sken err = bus_generic_setup_intr(dev, child, irq, flags, 1238229997Sken NULL, (driver_intr_t *)pccard_intr, pf, cookiep); 1239229997Sken if (err != 0) 1240229997Sken return (err); 1241229997Sken pf->filt_handler = filt; 1242229997Sken pf->intr_handler = intr; 1243229997Sken pf->intr_handler_arg = arg; 1244229997Sken pf->intr_handler_cookie = *cookiep; 1245229997Sken if (pccard_mfc(sc)) { 1246229997Sken pccard_ccr_write(pf, PCCARD_CCR_OPTION, 1247229997Sken pccard_ccr_read(pf, PCCARD_CCR_OPTION) | 1248229997Sken PCCARD_CCR_OPTION_IREQ_ENABLE); 1249229997Sken } 1250229997Sken return (0); 1251229997Sken} 1252229997Sken 1253229997Skenstatic int 1254229997Skenpccard_teardown_intr(device_t dev, device_t child, struct resource *r, 1255229997Sken void *cookie) 1256229997Sken{ 1257229997Sken struct pccard_softc *sc = PCCARD_SOFTC(dev); 1258229997Sken struct pccard_ivar *ivar = PCCARD_IVAR(child); 1259229997Sken struct pccard_function *pf = ivar->pf; 1260229997Sken int ret; 1261229997Sken 1262229997Sken if (pccard_mfc(sc)) { 1263229997Sken pccard_ccr_write(pf, PCCARD_CCR_OPTION, 1264229997Sken pccard_ccr_read(pf, PCCARD_CCR_OPTION) & 1265229997Sken ~PCCARD_CCR_OPTION_IREQ_ENABLE); 1266229997Sken } 1267229997Sken ret = bus_generic_teardown_intr(dev, child, r, cookie); 1268229997Sken if (ret == 0) { 1269229997Sken pf->intr_handler = NULL; 1270229997Sken pf->intr_handler_arg = NULL; 1271229997Sken pf->intr_handler_cookie = NULL; 1272229997Sken } 1273229997Sken 1274229997Sken return (ret); 1275229997Sken} 1276229997Sken 1277229997Skenstatic int 1278229997Skenpccard_activate_resource(device_t brdev, device_t child, int type, int rid, 1279229997Sken struct resource *r) 1280229997Sken{ 1281229997Sken struct pccard_ivar *ivar = PCCARD_IVAR(child); 1282229997Sken struct pccard_function *pf = ivar->pf; 1283229997Sken 1284229997Sken switch(type) { 1285229997Sken case SYS_RES_IOPORT: 1286229997Sken /* 1287229997Sken * We need to adjust IOBASE[01] and IOSIZE if we're an MFC 1288229997Sken * card. 1289229997Sken */ 1290229997Sken if (pccard_mfc(pf->sc)) 1291229997Sken pccard_mfc_adjust_iobase(pf, rman_get_start(r), 0, 1292229997Sken rman_get_size(r)); 1293229997Sken break; 1294229997Sken default: 1295229997Sken break; 1296229997Sken } 1297229997Sken return (bus_generic_activate_resource(brdev, child, type, rid, r)); 1298229997Sken} 1299229997Sken 1300229997Skenstatic int 1301229997Skenpccard_deactivate_resource(device_t brdev, device_t child, int type, 1302229997Sken int rid, struct resource *r) 1303229997Sken{ 1304229997Sken /* XXX undo pccard_activate_resource? XXX */ 1305229997Sken return (bus_generic_deactivate_resource(brdev, child, type, rid, r)); 1306229997Sken} 1307229997Sken 1308229997Skenstatic int 1309229997Skenpccard_attr_read_impl(device_t brdev, device_t child, uint32_t offset, 1310229997Sken uint8_t *val) 1311229997Sken{ 1312229997Sken struct pccard_ivar *devi = PCCARD_IVAR(child); 1313229997Sken struct pccard_function *pf = devi->pf; 1314229997Sken 1315229997Sken /* 1316229997Sken * Optimization. Most of the time, devices want to access 1317229997Sken * the same page of the attribute memory that the CCR is in. 1318229997Sken * We take advantage of this fact here. 1319229997Sken */ 1320229997Sken if (offset / PCCARD_MEM_PAGE_SIZE == 1321229997Sken pf->ccr_base / PCCARD_MEM_PAGE_SIZE) 1322229997Sken *val = bus_space_read_1(pf->pf_ccrt, pf->pf_ccrh, 1323229997Sken offset % PCCARD_MEM_PAGE_SIZE); 1324229997Sken else { 1325229997Sken CARD_SET_MEMORY_OFFSET(brdev, child, pf->ccr_rid, offset, 1326229997Sken &offset); 1327229997Sken *val = bus_space_read_1(pf->pf_ccrt, pf->pf_ccrh, offset); 1328229997Sken CARD_SET_MEMORY_OFFSET(brdev, child, pf->ccr_rid, pf->ccr_base, 1329229997Sken &offset); 1330229997Sken } 1331229997Sken return 0; 1332229997Sken} 1333229997Sken 1334229997Skenstatic int 1335229997Skenpccard_attr_write_impl(device_t brdev, device_t child, uint32_t offset, 1336229997Sken uint8_t val) 1337229997Sken{ 1338229997Sken struct pccard_ivar *devi = PCCARD_IVAR(child); 1339229997Sken struct pccard_function *pf = devi->pf; 1340229997Sken 1341229997Sken /* 1342229997Sken * Optimization. Most of the time, devices want to access 1343229997Sken * the same page of the attribute memory that the CCR is in. 1344229997Sken * We take advantage of this fact here. 1345229997Sken */ 1346229997Sken if (offset / PCCARD_MEM_PAGE_SIZE == 1347229997Sken pf->ccr_base / PCCARD_MEM_PAGE_SIZE) 1348229997Sken bus_space_write_1(pf->pf_ccrt, pf->pf_ccrh, 1349229997Sken offset % PCCARD_MEM_PAGE_SIZE, val); 1350229997Sken else { 1351229997Sken CARD_SET_MEMORY_OFFSET(brdev, child, pf->ccr_rid, offset, 1352229997Sken &offset); 1353229997Sken bus_space_write_1(pf->pf_ccrt, pf->pf_ccrh, offset, val); 1354229997Sken CARD_SET_MEMORY_OFFSET(brdev, child, pf->ccr_rid, pf->ccr_base, 1355229997Sken &offset); 1356229997Sken } 1357229997Sken 1358229997Sken return 0; 1359229997Sken} 1360229997Sken 1361229997Skenstatic int 1362229997Skenpccard_ccr_read_impl(device_t brdev, device_t child, uint32_t offset, 1363229997Sken uint8_t *val) 1364229997Sken{ 1365229997Sken struct pccard_ivar *devi = PCCARD_IVAR(child); 1366229997Sken 1367229997Sken *val = pccard_ccr_read(devi->pf, offset); 1368229997Sken device_printf(child, "ccr_read of %#x (%#x) is %#x\n", offset, 1369229997Sken devi->pf->pf_ccr_offset, *val); 1370229997Sken return 0; 1371229997Sken} 1372229997Sken 1373229997Skenstatic int 1374229997Skenpccard_ccr_write_impl(device_t brdev, device_t child, uint32_t offset, 1375229997Sken uint8_t val) 1376229997Sken{ 1377229997Sken struct pccard_ivar *devi = PCCARD_IVAR(child); 1378229997Sken struct pccard_function *pf = devi->pf; 1379229997Sken 1380229997Sken /* 1381229997Sken * Can't use pccard_ccr_write since client drivers may access 1382229997Sken * registers not contained in the 'mask' if they are non-standard. 1383229997Sken */ 1384229997Sken device_printf(child, "ccr_write of %#x to %#x (%#x)\n", val, offset, 1385229997Sken devi->pf->pf_ccr_offset); 1386229997Sken bus_space_write_1(pf->pf_ccrt, pf->pf_ccrh, pf->pf_ccr_offset + offset, 1387229997Sken val); 1388229997Sken return 0; 1389229997Sken} 1390229997Sken 1391229997Sken 1392229997Skenstatic device_method_t pccard_methods[] = { 1393229997Sken /* Device interface */ 1394229997Sken DEVMETHOD(device_probe, pccard_probe), 1395229997Sken DEVMETHOD(device_attach, pccard_attach), 1396229997Sken DEVMETHOD(device_detach, pccard_detach), 1397229997Sken DEVMETHOD(device_shutdown, bus_generic_shutdown), 1398229997Sken DEVMETHOD(device_suspend, pccard_suspend), 1399229997Sken DEVMETHOD(device_resume, pccard_resume), 1400229997Sken 1401229997Sken /* Bus interface */ 1402229997Sken DEVMETHOD(bus_print_child, pccard_print_child), 1403229997Sken DEVMETHOD(bus_driver_added, pccard_driver_added), 1404229997Sken DEVMETHOD(bus_child_detached, pccard_child_detached), 1405229997Sken DEVMETHOD(bus_alloc_resource, pccard_alloc_resource), 1406229997Sken DEVMETHOD(bus_release_resource, pccard_release_resource), 1407229997Sken DEVMETHOD(bus_activate_resource, pccard_activate_resource), 1408229997Sken DEVMETHOD(bus_deactivate_resource, pccard_deactivate_resource), 1409229997Sken DEVMETHOD(bus_setup_intr, pccard_setup_intr), 1410229997Sken DEVMETHOD(bus_teardown_intr, pccard_teardown_intr), 1411229997Sken DEVMETHOD(bus_set_resource, pccard_set_resource), 1412229997Sken DEVMETHOD(bus_get_resource, pccard_get_resource), 1413229997Sken DEVMETHOD(bus_delete_resource, pccard_delete_resource), 1414229997Sken DEVMETHOD(bus_probe_nomatch, pccard_probe_nomatch), 1415229997Sken DEVMETHOD(bus_read_ivar, pccard_read_ivar), 1416229997Sken DEVMETHOD(bus_child_pnpinfo_str, pccard_child_pnpinfo_str), 1417229997Sken DEVMETHOD(bus_child_location_str, pccard_child_location_str), 1418229997Sken 1419229997Sken /* Card Interface */ 1420229997Sken DEVMETHOD(card_set_res_flags, pccard_set_res_flags), 1421229997Sken DEVMETHOD(card_set_memory_offset, pccard_set_memory_offset), 1422229997Sken DEVMETHOD(card_attach_card, pccard_attach_card), 1423229997Sken DEVMETHOD(card_detach_card, pccard_detach_card), 1424229997Sken DEVMETHOD(card_do_product_lookup, pccard_do_product_lookup), 1425229997Sken DEVMETHOD(card_cis_scan, pccard_scan_cis), 1426229997Sken DEVMETHOD(card_attr_read, pccard_attr_read_impl), 1427229997Sken DEVMETHOD(card_attr_write, pccard_attr_write_impl), 1428229997Sken DEVMETHOD(card_ccr_read, pccard_ccr_read_impl), 1429229997Sken DEVMETHOD(card_ccr_write, pccard_ccr_write_impl), 1430229997Sken 1431229997Sken { 0, 0 } 1432229997Sken}; 1433229997Sken 1434229997Skenstatic driver_t pccard_driver = { 1435229997Sken "pccard", 1436229997Sken pccard_methods, 1437229997Sken sizeof(struct pccard_softc) 1438229997Sken}; 1439229997Sken 1440229997Skendevclass_t pccard_devclass; 1441229997Sken 1442229997Sken/* Maybe we need to have a slot device? */ 1443229997SkenDRIVER_MODULE(pccard, pcic, pccard_driver, pccard_devclass, 0, 0); 1444229997SkenDRIVER_MODULE(pccard, cbb, pccard_driver, pccard_devclass, 0, 0); 1445229997SkenMODULE_VERSION(pccard, 1); 1446229997Sken