pccard.c revision 141959
166200Simp/* $NetBSD: pcmcia.c,v 1.23 2000/07/28 19:17:02 drochner Exp $ */ 252506Simp 3139749Simp/*- 452506Simp * Copyright (c) 1997 Marc Horowitz. All rights reserved. 552506Simp * 652506Simp * Redistribution and use in source and binary forms, with or without 752506Simp * modification, are permitted provided that the following conditions 852506Simp * are met: 952506Simp * 1. Redistributions of source code must retain the above copyright 1052506Simp * notice, this list of conditions and the following disclaimer. 1152506Simp * 2. Redistributions in binary form must reproduce the above copyright 1252506Simp * notice, this list of conditions and the following disclaimer in the 1352506Simp * documentation and/or other materials provided with the distribution. 1452506Simp * 3. All advertising materials mentioning features or use of this software 1552506Simp * must display the following acknowledgement: 1652506Simp * This product includes software developed by Marc Horowitz. 1752506Simp * 4. The name of the author may not be used to endorse or promote products 1852506Simp * derived from this software without specific prior written permission. 1952506Simp * 2052506Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 2152506Simp * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2252506Simp * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2352506Simp * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2452506Simp * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2552506Simp * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2652506Simp * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2752506Simp * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2852506Simp * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2952506Simp * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3052506Simp */ 3152506Simp 32119418Sobrien#include <sys/cdefs.h> 33119418Sobrien__FBSDID("$FreeBSD: head/sys/dev/pccard/pccard.c 141959 2005-02-16 01:03:30Z imp $"); 34119418Sobrien 3552506Simp#include <sys/param.h> 3652506Simp#include <sys/systm.h> 3752506Simp#include <sys/malloc.h> 3852506Simp#include <sys/module.h> 3952506Simp#include <sys/kernel.h> 4052506Simp#include <sys/queue.h> 4191786Simp#include <sys/sysctl.h> 4252506Simp#include <sys/types.h> 4352506Simp 4452506Simp#include <sys/bus.h> 4552506Simp#include <machine/bus.h> 4652506Simp#include <sys/rman.h> 4752506Simp#include <machine/resource.h> 4852506Simp 4982781Sshiba#include <net/ethernet.h> 5082781Sshiba 5152506Simp#include <dev/pccard/pccardreg.h> 5252506Simp#include <dev/pccard/pccardvar.h> 5352506Simp 5455500Simp#include "power_if.h" 5559193Simp#include "card_if.h" 5655500Simp 5755500Simp#define PCCARDDEBUG 5855500Simp 5991786Simp/* sysctl vars */ 6091786SimpSYSCTL_NODE(_hw, OID_AUTO, pccard, CTLFLAG_RD, 0, "PCCARD parameters"); 6191786Simp 6291786Simpint pccard_debug = 0; 6391786SimpTUNABLE_INT("hw.pccard.debug", &pccard_debug); 6491786SimpSYSCTL_INT(_hw_pccard, OID_AUTO, debug, CTLFLAG_RW, 6591786Simp &pccard_debug, 0, 6691786Simp "pccard debug"); 6791786Simp 6891786Simpint pccard_cis_debug = 0; 6991786SimpTUNABLE_INT("hw.pccard.cis_debug", &pccard_cis_debug); 7091786SimpSYSCTL_INT(_hw_pccard, OID_AUTO, cis_debug, CTLFLAG_RW, 7191786Simp &pccard_cis_debug, 0, "pccard CIS debug"); 7291786Simp 7352506Simp#ifdef PCCARDDEBUG 7452506Simp#define DPRINTF(arg) if (pccard_debug) printf arg 7555500Simp#define DEVPRINTF(arg) if (pccard_debug) device_printf arg 7667333Simp#define PRVERBOSE(arg) printf arg 7767333Simp#define DEVPRVERBOSE(arg) device_printf arg 7852506Simp#else 7952506Simp#define DPRINTF(arg) 8055500Simp#define DEVPRINTF(arg) 8167333Simp#define PRVERBOSE(arg) if (bootverbose) printf arg 8267333Simp#define DEVPRVERBOSE(arg) if (bootverbose) device_printf arg 8352506Simp#endif 8452506Simp 8582378Sjonstatic int pccard_ccr_read(struct pccard_function *pf, int ccr); 8682378Sjonstatic void pccard_ccr_write(struct pccard_function *pf, int ccr, int val); 8782378Sjonstatic int pccard_attach_card(device_t dev); 88106362Simpstatic int pccard_detach_card(device_t dev); 8982378Sjonstatic void pccard_function_init(struct pccard_function *pf); 9082378Sjonstatic void pccard_function_free(struct pccard_function *pf); 9182378Sjonstatic int pccard_function_enable(struct pccard_function *pf); 9282378Sjonstatic void pccard_function_disable(struct pccard_function *pf); 9382378Sjonstatic int pccard_compat_do_probe(device_t bus, device_t dev); 9482378Sjonstatic int pccard_compat_do_attach(device_t bus, device_t dev); 9582378Sjonstatic int pccard_add_children(device_t dev, int busno); 9682378Sjonstatic int pccard_probe(device_t dev); 9782378Sjonstatic int pccard_attach(device_t dev); 9882378Sjonstatic int pccard_detach(device_t dev); 9982378Sjonstatic void pccard_print_resources(struct resource_list *rl, 10082378Sjon const char *name, int type, int count, const char *format); 10182378Sjonstatic int pccard_print_child(device_t dev, device_t child); 10282378Sjonstatic int pccard_set_resource(device_t dev, device_t child, int type, 10382378Sjon int rid, u_long start, u_long count); 10482378Sjonstatic int pccard_get_resource(device_t dev, device_t child, int type, 10582378Sjon int rid, u_long *startp, u_long *countp); 10682378Sjonstatic void pccard_delete_resource(device_t dev, device_t child, int type, 10782378Sjon int rid); 10882378Sjonstatic int pccard_set_res_flags(device_t dev, device_t child, int type, 109140692Simp int rid, uint32_t flags); 11082378Sjonstatic int pccard_set_memory_offset(device_t dev, device_t child, int rid, 111140692Simp uint32_t offset, uint32_t *deltap); 112104641Simpstatic void pccard_probe_nomatch(device_t cbdev, device_t child); 11382378Sjonstatic int pccard_read_ivar(device_t bus, device_t child, int which, 11482378Sjon u_char *result); 11582378Sjonstatic void pccard_driver_added(device_t dev, driver_t *driver); 11682378Sjonstatic struct resource *pccard_alloc_resource(device_t dev, 11782378Sjon device_t child, int type, int *rid, u_long start, 11882378Sjon u_long end, u_long count, u_int flags); 11982378Sjonstatic int pccard_release_resource(device_t dev, device_t child, int type, 12082378Sjon int rid, struct resource *r); 12182378Sjonstatic void pccard_child_detached(device_t parent, device_t dev); 12282378Sjonstatic void pccard_intr(void *arg); 12382378Sjonstatic int pccard_setup_intr(device_t dev, device_t child, 12482378Sjon struct resource *irq, int flags, driver_intr_t *intr, 12582378Sjon void *arg, void **cookiep); 12682378Sjonstatic int pccard_teardown_intr(device_t dev, device_t child, 12782378Sjon struct resource *r, void *cookie); 12852506Simp 12997613Stakawatastatic const struct pccard_product * 13097613Stakawatapccard_do_product_lookup(device_t bus, device_t dev, 13197613Stakawata const struct pccard_product *tab, size_t ent_size, 13297613Stakawata pccard_product_match_fn matchfn); 13397613Stakawata 13497613Stakawata 13582378Sjonstatic int 13674632Simppccard_ccr_read(struct pccard_function *pf, int ccr) 13752506Simp{ 13852506Simp return (bus_space_read_1(pf->pf_ccrt, pf->pf_ccrh, 13952506Simp pf->pf_ccr_offset + ccr)); 14052506Simp} 14152506Simp 14282378Sjonstatic void 14374632Simppccard_ccr_write(struct pccard_function *pf, int ccr, int val) 14452506Simp{ 14552506Simp if ((pf->ccr_mask) & (1 << (ccr / 2))) { 14652506Simp bus_space_write_1(pf->pf_ccrt, pf->pf_ccrh, 14752506Simp pf->pf_ccr_offset + ccr, val); 14852506Simp } 14952506Simp} 15052506Simp 15159193Simpstatic int 152113242Simppccard_set_default_descr(device_t dev) 153113242Simp{ 154121521Simp const char *vendorstr, *prodstr; 155133865Simp uint32_t vendor, prod; 156121521Simp char *str; 157113242Simp 158113242Simp if (pccard_get_vendor_str(dev, &vendorstr)) 159113242Simp return (0); 160113242Simp if (pccard_get_product_str(dev, &prodstr)) 161113242Simp return (0); 162133865Simp if (vendorstr != NULL && prodstr != NULL) { 163133865Simp str = malloc(strlen(vendorstr) + strlen(prodstr) + 2, M_DEVBUF, 164133865Simp M_WAITOK); 165133865Simp sprintf(str, "%s %s", vendorstr, prodstr); 166133865Simp device_set_desc_copy(dev, str); 167133865Simp free(str, M_DEVBUF); 168133865Simp } else { 169133865Simp if (pccard_get_vendor(dev, &vendor)) 170133865Simp return (0); 171133865Simp if (pccard_get_product(dev, &prod)) 172133865Simp return (0); 173133865Simp str = malloc(100, M_DEVBUF, M_WAITOK); 174133865Simp snprintf(str, 100, "vendor=0x%x product=0x%x", vendor, prod); 175133865Simp device_set_desc_copy(dev, str); 176133865Simp free(str, M_DEVBUF); 177133865Simp } 178113242Simp return (0); 179113242Simp} 180113242Simp 181113242Simpstatic int 18259193Simppccard_attach_card(device_t dev) 18352506Simp{ 18464850Simp struct pccard_softc *sc = PCCARD_SOFTC(dev); 18552506Simp struct pccard_function *pf; 18665917Simp struct pccard_ivar *ivar; 18761788Simp device_t child; 188102713Simp int i; 18952506Simp 19052506Simp /* 19152506Simp * this is here so that when socket_enable calls gettype, trt happens 19252506Simp */ 19352506Simp STAILQ_INIT(&sc->card.pf_head); 19452506Simp 19555500Simp DEVPRINTF((dev, "chip_socket_enable\n")); 19655500Simp POWER_ENABLE_SOCKET(device_get_parent(dev), dev); 19752506Simp 19855500Simp DEVPRINTF((dev, "read_cis\n")); 19952506Simp pccard_read_cis(sc); 20052506Simp 20155500Simp DEVPRINTF((dev, "check_cis_quirks\n")); 20252506Simp pccard_check_cis_quirks(dev); 20352506Simp 20452506Simp /* 20552506Simp * bail now if the card has no functions, or if there was an error in 20652506Simp * the cis. 20752506Simp */ 20852506Simp 20970715Sjon if (sc->card.error) { 210102713Simp device_printf(dev, "CARD ERROR!\n"); 21152506Simp return (1); 21270715Sjon } 21370715Sjon if (STAILQ_EMPTY(&sc->card.pf_head)) { 214102713Simp device_printf(dev, "Card has no functions!\n"); 21552506Simp return (1); 21670715Sjon } 21752506Simp 21890436Simp if (bootverbose || pccard_debug) 21952506Simp pccard_print_cis(dev); 22052506Simp 22155500Simp DEVPRINTF((dev, "functions scanning\n")); 222102713Simp i = -1; 22352506Simp STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) { 224102713Simp i++; 225102713Simp if (STAILQ_EMPTY(&pf->cfe_head)) { 226102713Simp device_printf(dev, 227102713Simp "Function %d has no config entries.!\n", i); 22852506Simp continue; 229102713Simp } 23052506Simp pf->sc = sc; 23152506Simp pf->cfe = NULL; 23264927Simp pf->dev = NULL; 23352506Simp } 234104641Simp DEVPRINTF((dev, "Card has %d functions. pccard_mfc is %d\n", i + 1, 235102713Simp pccard_mfc(sc))); 23682378Sjon 23752506Simp STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) { 23852506Simp if (STAILQ_EMPTY(&pf->cfe_head)) 23952506Simp continue; 24061788Simp /* 24161788Simp * In NetBSD, the drivers are responsible for activating 24261788Simp * each function of a card. I think that in FreeBSD we 24361788Simp * want to activate them enough for the usual bus_*_resource 24461788Simp * routines will do the right thing. This many mean a 24561788Simp * departure from the current NetBSD model. 24661788Simp * 247104641Simp * This seems to work well in practice for most cards. 248104641Simp * However, there are two cases that are problematic. 249104641Simp * If a driver wishes to pick and chose which config 250104641Simp * entry to use, then this method falls down. These 251104641Simp * are usually older cards. In addition, there are 252104641Simp * some cards that have multiple hardware units on the 253104641Simp * cards, but presents only one CIS chain. These cards 254104641Simp * are combination cards, but only one of these units 255104641Simp * can be on at a time. 25661788Simp */ 25767897Sdwmalone ivar = malloc(sizeof(struct pccard_ivar), M_DEVBUF, 258111119Simp M_WAITOK | M_ZERO); 25961788Simp child = device_add_child(dev, NULL, -1); 26065917Simp device_set_ivars(child, ivar); 26166847Simp ivar->fcn = pf; 26267187Simp pf->dev = child; 26367167Simp /* 26467167Simp * XXX We might want to move the next two lines into 26567167Simp * XXX the pccard interface layer. For the moment, this 26667167Simp * XXX is OK, but some drivers want to pick the config 26767167Simp * XXX entry to use as well as some address tweaks (mostly 26867167Simp * XXX due to bugs in decode logic that makes some 26967167Simp * XXX addresses illegal or broken). 27067167Simp */ 27165917Simp pccard_function_init(pf); 27282378Sjon if (sc->sc_enabled_count == 0) 27382378Sjon POWER_ENABLE_SOCKET(device_get_parent(dev), dev); 27467333Simp if (pccard_function_enable(pf) == 0 && 275113242Simp pccard_set_default_descr(child) == 0 && 27667333Simp device_probe_and_attach(child) == 0) { 27755500Simp DEVPRINTF((sc->dev, "function %d CCR at %d " 278121905Simp "offset %x mask %x: " 279121905Simp "%x %x %x %x, %x %x %x %x, %x\n", 28067167Simp pf->number, pf->pf_ccr_window, pf->pf_ccr_offset, 281121905Simp pf->ccr_mask, pccard_ccr_read(pf, 0x00), 28252506Simp pccard_ccr_read(pf, 0x02), pccard_ccr_read(pf, 0x04), 28352506Simp pccard_ccr_read(pf, 0x06), pccard_ccr_read(pf, 0x0A), 28452506Simp pccard_ccr_read(pf, 0x0C), pccard_ccr_read(pf, 0x0E), 28552506Simp pccard_ccr_read(pf, 0x10), pccard_ccr_read(pf, 0x12))); 28667167Simp } else { 28786907Simp if (pf->cfe != NULL) 28886907Simp pccard_function_disable(pf); 28952506Simp } 29052506Simp } 29174632Simp return (0); 29252506Simp} 29352506Simp 29459193Simpstatic int 295106362Simppccard_detach_card(device_t dev) 29652506Simp{ 29764850Simp struct pccard_softc *sc = PCCARD_SOFTC(dev); 29852506Simp struct pccard_function *pf; 29982378Sjon struct pccard_config_entry *cfe; 300119755Simp int state; 30152506Simp 30252506Simp /* 30352506Simp * We are running on either the PCCARD socket's event thread 30452506Simp * or in user context detaching a device by user request. 30552506Simp */ 30652506Simp STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) { 307119755Simp if (pf->dev == NULL) 308119755Simp continue; 309119755Simp state = device_get_state(pf->dev); 31082378Sjon if (state == DS_ATTACHED || state == DS_BUSY) 31182378Sjon device_detach(pf->dev); 31286907Simp if (pf->cfe != NULL) 31386907Simp pccard_function_disable(pf); 31482378Sjon pccard_function_free(pf); 315106896Simp device_delete_child(dev, pf->dev); 31652506Simp } 31782378Sjon if (sc->sc_enabled_count == 0) 31882378Sjon POWER_DISABLE_SOCKET(device_get_parent(dev), dev); 31982378Sjon 32082378Sjon while (NULL != (pf = STAILQ_FIRST(&sc->card.pf_head))) { 32182378Sjon while (NULL != (cfe = STAILQ_FIRST(&pf->cfe_head))) { 32282378Sjon STAILQ_REMOVE_HEAD(&pf->cfe_head, cfe_list); 32382378Sjon free(cfe, M_DEVBUF); 32482378Sjon } 32582378Sjon STAILQ_REMOVE_HEAD(&sc->card.pf_head, pf_list); 32682378Sjon free(pf, M_DEVBUF); 32782378Sjon } 32874632Simp return (0); 32952506Simp} 33052506Simp 33197613Stakawatastatic const struct pccard_product * 33297613Stakawatapccard_do_product_lookup(device_t bus, device_t dev, 333112359Simp const struct pccard_product *tab, size_t ent_size, 334112359Simp pccard_product_match_fn matchfn) 33566200Simp{ 33666200Simp const struct pccard_product *ent; 33766200Simp int matches; 338140692Simp uint32_t vendor; 339140692Simp uint32_t prod; 340121521Simp const char *vendorstr; 341121521Simp const char *prodstr; 342140366Simp const char *cis3str; 343140366Simp const char *cis4str; 34466200Simp 34566200Simp#ifdef DIAGNOSTIC 34666200Simp if (sizeof *ent > ent_size) 347112359Simp panic("pccard_product_lookup: bogus ent_size %jd", 348112359Simp (intmax_t) ent_size); 34966200Simp#endif 35066200Simp if (pccard_get_vendor(dev, &vendor)) 35166200Simp return (NULL); 35266200Simp if (pccard_get_product(dev, &prod)) 35366200Simp return (NULL); 35466200Simp if (pccard_get_vendor_str(dev, &vendorstr)) 35566200Simp return (NULL); 35666200Simp if (pccard_get_product_str(dev, &prodstr)) 35766200Simp return (NULL); 358140366Simp if (pccard_get_cis3_str(dev, &cis3str)) 359140366Simp return (NULL); 360140366Simp if (pccard_get_cis4_str(dev, &cis4str)) 361140366Simp return (NULL); 362113313Simp for (ent = tab; ent->pp_vendor != 0; ent = 36382378Sjon (const struct pccard_product *) ((const char *) ent + ent_size)) { 36466200Simp matches = 1; 36586642Simp if (ent->pp_vendor == PCCARD_VENDOR_ANY && 366113078Ssanpei ent->pp_product == PCCARD_PRODUCT_ANY && 36786642Simp ent->pp_cis[0] == NULL && 36886642Simp ent->pp_cis[1] == NULL) { 369113300Simp if (ent->pp_name) 370113300Simp device_printf(dev, 371113300Simp "Total wildcard entry ignored for %s\n", 372113300Simp ent->pp_name); 37386642Simp continue; 37486642Simp } 37566200Simp if (matches && ent->pp_vendor != PCCARD_VENDOR_ANY && 37666200Simp vendor != ent->pp_vendor) 37766200Simp matches = 0; 37866200Simp if (matches && ent->pp_product != PCCARD_PRODUCT_ANY && 37966200Simp prod != ent->pp_product) 38066200Simp matches = 0; 38171322Simp if (matches && ent->pp_cis[0] && 382133865Simp (vendorstr == NULL || 383133865Simp strcmp(ent->pp_cis[0], vendorstr) != 0)) 38466200Simp matches = 0; 38571322Simp if (matches && ent->pp_cis[1] && 386133865Simp (prodstr == NULL || 387133865Simp strcmp(ent->pp_cis[1], prodstr) != 0)) 38866200Simp matches = 0; 389140366Simp if (matches && ent->pp_cis[2] && 390140366Simp (cis3str == NULL || 391140366Simp strcmp(ent->pp_cis[2], cis3str) != 0)) 392140366Simp matches = 0; 393140366Simp if (matches && ent->pp_cis[3] && 394140366Simp (cis4str == NULL || 395140366Simp strcmp(ent->pp_cis[3], cis4str) != 0)) 396140366Simp matches = 0; 39766200Simp if (matchfn != NULL) 39866200Simp matches = (*matchfn)(dev, ent, matches); 39966200Simp if (matches) 40066200Simp return (ent); 40166200Simp } 40266200Simp return (NULL); 40366200Simp} 40466200Simp 40552506Simp/* 40652506Simp * Initialize a PCCARD function. May be called as long as the function is 40752506Simp * disabled. 40882382Simp * 40982382Simp * Note: pccard_function_init should not keep resources allocated. It should 41082382Simp * only set them up ala isa pnp, set the values in the rl lists, and return. 41182382Simp * Any resource held after pccard_function_init is called is a bug. However, 41282382Simp * the bus routines to get the resources also assume that pccard_function_init 41382382Simp * does this, so they need to be fixed too. 41452506Simp */ 41582378Sjonstatic void 41670715Sjonpccard_function_init(struct pccard_function *pf) 41752506Simp{ 41865917Simp struct pccard_config_entry *cfe; 41967187Simp int i; 42067242Simp struct pccard_ivar *devi = PCCARD_IVAR(pf->dev); 42167242Simp struct resource_list *rl = &devi->resources; 42270762Simp struct resource_list_entry *rle; 42367242Simp struct resource *r = 0; 42467242Simp device_t bus; 42567424Simp int start; 42667424Simp int end; 42790897Simp int spaces; 42865917Simp 42970715Sjon if (pf->pf_flags & PFF_ENABLED) { 43070715Sjon printf("pccard_function_init: function is enabled"); 43170715Sjon return; 43270715Sjon } 43367242Simp bus = device_get_parent(pf->dev); 43452506Simp /* Remember which configuration entry we are using. */ 43572012Sphk STAILQ_FOREACH(cfe, &pf->cfe_head, cfe_list) { 43667187Simp for (i = 0; i < cfe->num_iospace; i++) 43767187Simp cfe->iores[i] = NULL; 43867187Simp cfe->irqres = NULL; 43990897Simp spaces = 0; 44067187Simp for (i = 0; i < cfe->num_iospace; i++) { 44167424Simp start = cfe->iospace[i].start; 44267424Simp if (start) 44367424Simp end = start + cfe->iospace[i].length - 1; 44467424Simp else 44567424Simp end = ~0; 44667187Simp cfe->iorid[i] = i; 44790897Simp DEVPRINTF((bus, "I/O rid %d start %x end %x\n", 44890897Simp i, start, end)); 44967242Simp r = cfe->iores[i] = bus_alloc_resource(bus, 45067424Simp SYS_RES_IOPORT, &cfe->iorid[i], start, end, 45170715Sjon cfe->iospace[i].length, 45267424Simp rman_make_alignment_flags(cfe->iospace[i].length)); 45376424Simp if (cfe->iores[i] == NULL) 45467187Simp goto not_this_one; 45567242Simp resource_list_add(rl, SYS_RES_IOPORT, cfe->iorid[i], 45667242Simp rman_get_start(r), rman_get_end(r), 45767242Simp cfe->iospace[i].length); 45876424Simp rle = resource_list_find(rl, SYS_RES_IOPORT, 45976424Simp cfe->iorid[i]); 46076424Simp rle->res = r; 46190897Simp spaces++; 46267187Simp } 46367187Simp if (cfe->num_memspace > 0) { 46482781Sshiba /* 46582781Sshiba * Not implement yet, Fix me. 46682781Sshiba */ 46790897Simp DEVPRINTF((bus, "Memory space not yet implemented.\n")); 46867187Simp } 46990897Simp if (spaces == 0) { 470140488Simp DEVPRINTF((bus, "Neither memory nor I/O mapped\n")); 47190897Simp goto not_this_one; 47290897Simp } 47367187Simp if (cfe->irqmask) { 47467187Simp cfe->irqrid = 0; 475127135Snjl r = cfe->irqres = bus_alloc_resource_any(bus, 476127135Snjl SYS_RES_IRQ, &cfe->irqrid, 0); 47776424Simp if (cfe->irqres == NULL) 47867187Simp goto not_this_one; 47967242Simp resource_list_add(rl, SYS_RES_IRQ, cfe->irqrid, 48067242Simp rman_get_start(r), rman_get_end(r), 1); 48176424Simp rle = resource_list_find(rl, SYS_RES_IRQ, 48276424Simp cfe->irqrid); 48376424Simp rle->res = r; 48467187Simp } 48567187Simp /* If we get to here, we've allocated all we need */ 48667167Simp pf->cfe = cfe; 48767187Simp break; 48867187Simp not_this_one:; 48967424Simp DEVPRVERBOSE((bus, "Allocation failed for cfe %d\n", 49067424Simp cfe->number)); 49167333Simp /* 49267333Simp * Release resources that we partially allocated 49367333Simp * from this config entry. 49467333Simp */ 49567187Simp for (i = 0; i < cfe->num_iospace; i++) { 49676424Simp if (cfe->iores[i] != NULL) { 49770715Sjon bus_release_resource(bus, SYS_RES_IOPORT, 49867187Simp cfe->iorid[i], cfe->iores[i]); 49982378Sjon rle = resource_list_find(rl, SYS_RES_IOPORT, 50076424Simp cfe->iorid[i]); 50176424Simp rle->res = NULL; 50276424Simp resource_list_delete(rl, SYS_RES_IOPORT, 50376424Simp cfe->iorid[i]); 50475756Simp } 50567187Simp cfe->iores[i] = NULL; 50667187Simp } 50776424Simp if (cfe->irqmask && cfe->irqres != NULL) { 50867242Simp bus_release_resource(bus, SYS_RES_IRQ, 50967187Simp cfe->irqrid, cfe->irqres); 51076424Simp rle = resource_list_find(rl, SYS_RES_IRQ, 51176424Simp cfe->irqrid); 51276424Simp rle->res = NULL; 51376424Simp resource_list_delete(rl, SYS_RES_IRQ, cfe->irqrid); 51467187Simp cfe->irqres = NULL; 51567187Simp } 51667167Simp } 51752506Simp} 51852506Simp 51982378Sjon/* 52082378Sjon * Free resources allocated by pccard_function_init(), May be called as long 52182378Sjon * as the function is disabled. 52282382Simp * 52382382Simp * NOTE: This function should be unnecessary. pccard_function_init should 52482382Simp * never keep resources initialized. 52582378Sjon */ 52682378Sjonstatic void 52782378Sjonpccard_function_free(struct pccard_function *pf) 52882378Sjon{ 52982378Sjon struct pccard_ivar *devi = PCCARD_IVAR(pf->dev); 53082378Sjon struct resource_list_entry *rle; 53182378Sjon 53282378Sjon if (pf->pf_flags & PFF_ENABLED) { 53382378Sjon printf("pccard_function_init: function is enabled"); 53482378Sjon return; 53582378Sjon } 53682378Sjon 53782378Sjon SLIST_FOREACH(rle, &devi->resources, link) { 53882378Sjon if (rle->res) { 539113242Simp if (rman_get_device(rle->res) != pf->sc->dev) 54082378Sjon device_printf(pf->sc->dev, 54182378Sjon "function_free: Resource still owned by " 54282378Sjon "child, oops. " 54382378Sjon "(type=%d, rid=%d, addr=%lx)\n", 54482378Sjon rle->type, rle->rid, 54582378Sjon rman_get_start(rle->res)); 54682378Sjon BUS_RELEASE_RESOURCE(device_get_parent(pf->sc->dev), 547113242Simp pf->sc->dev, rle->type, rle->rid, rle->res); 54882378Sjon rle->res = NULL; 54982378Sjon } 55082378Sjon } 55182378Sjon resource_list_free(&devi->resources); 55282378Sjon} 55382378Sjon 554121905Simpstatic void 555121905Simppccard_mfc_adjust_iobase(struct pccard_function *pf, bus_addr_t addr, 556121905Simp bus_addr_t offset, bus_size_t size) 557121905Simp{ 558121958Simp bus_size_t iosize, tmp; 559121905Simp 560121905Simp if (addr != 0) { 561121905Simp if (pf->pf_mfc_iomax == 0) { 562121905Simp pf->pf_mfc_iobase = addr + offset; 563121905Simp pf->pf_mfc_iomax = pf->pf_mfc_iobase + size; 564121905Simp } else { 565121905Simp /* this makes the assumption that nothing overlaps */ 566121905Simp if (pf->pf_mfc_iobase > addr + offset) 567121905Simp pf->pf_mfc_iobase = addr + offset; 568121905Simp if (pf->pf_mfc_iomax < addr + offset + size) 569121905Simp pf->pf_mfc_iomax = addr + offset + size; 570121905Simp } 571121905Simp } 572121905Simp 573121905Simp tmp = pf->pf_mfc_iomax - pf->pf_mfc_iobase; 574121905Simp /* round up to nearest (2^n)-1 */ 575121905Simp for (iosize = 1; iosize < tmp; iosize <<= 1) 576121905Simp ; 577121905Simp iosize--; 578121905Simp 579122032Simp DEVPRINTF((pf->dev, "MFC: I/O base %#jx IOSIZE %#jx\n", 580122032Simp (uintmax_t)pf->pf_mfc_iobase, (uintmax_t)(iosize + 1))); 581121905Simp pccard_ccr_write(pf, PCCARD_CCR_IOBASE0, 582121905Simp pf->pf_mfc_iobase & 0xff); 583121905Simp pccard_ccr_write(pf, PCCARD_CCR_IOBASE1, 584121905Simp (pf->pf_mfc_iobase >> 8) & 0xff); 585121905Simp pccard_ccr_write(pf, PCCARD_CCR_IOBASE2, 0); 586121905Simp pccard_ccr_write(pf, PCCARD_CCR_IOBASE3, 0); 587121905Simp pccard_ccr_write(pf, PCCARD_CCR_IOSIZE, iosize); 588121905Simp} 589121905Simp 59052506Simp/* Enable a PCCARD function */ 59182378Sjonstatic int 59255720Simppccard_function_enable(struct pccard_function *pf) 59352506Simp{ 59452506Simp struct pccard_function *tmp; 59552506Simp int reg; 59655720Simp device_t dev = pf->sc->dev; 59770746Simp 59867333Simp if (pf->cfe == NULL) { 59967333Simp DEVPRVERBOSE((dev, "No config entry could be allocated.\n")); 60074632Simp return (ENOMEM); 60167333Simp } 60252506Simp 60352506Simp /* 60452506Simp * Increase the reference count on the socket, enabling power, if 60552506Simp * necessary. 60652506Simp */ 60782378Sjon pf->sc->sc_enabled_count++; 60852506Simp 60952506Simp if (pf->pf_flags & PFF_ENABLED) { 61052506Simp /* 61152506Simp * Don't do anything if we're already enabled. 61252506Simp */ 61352506Simp return (0); 61452506Simp } 61552506Simp 61652506Simp /* 61752506Simp * it's possible for different functions' CCRs to be in the same 61852506Simp * underlying page. Check for that. 61952506Simp */ 62052506Simp STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) { 62152506Simp if ((tmp->pf_flags & PFF_ENABLED) && 62252506Simp (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) && 62352506Simp ((pf->ccr_base + PCCARD_CCR_SIZE) <= 62482378Sjon (tmp->ccr_base - tmp->pf_ccr_offset + 62582378Sjon tmp->pf_ccr_realsize))) { 62652506Simp pf->pf_ccrt = tmp->pf_ccrt; 62752506Simp pf->pf_ccrh = tmp->pf_ccrh; 62852506Simp pf->pf_ccr_realsize = tmp->pf_ccr_realsize; 62952506Simp 63052506Simp /* 63152506Simp * pf->pf_ccr_offset = (tmp->pf_ccr_offset - 63252506Simp * tmp->ccr_base) + pf->ccr_base; 63352506Simp */ 63470715Sjon /* pf->pf_ccr_offset = 63552506Simp (tmp->pf_ccr_offset + pf->ccr_base) - 63670715Sjon tmp->ccr_base; */ 63752506Simp pf->pf_ccr_window = tmp->pf_ccr_window; 63852506Simp break; 63952506Simp } 64052506Simp } 64152506Simp if (tmp == NULL) { 64255720Simp pf->ccr_rid = 0; 64355720Simp pf->ccr_res = bus_alloc_resource(dev, SYS_RES_MEMORY, 64470715Sjon &pf->ccr_rid, 0, ~0, 1 << 10, RF_ACTIVE); 64570715Sjon if (!pf->ccr_res) 64652506Simp goto bad; 647106914Smux DEVPRINTF((dev, "ccr_res == %lx-%lx, base=%x\n", 64870746Simp rman_get_start(pf->ccr_res), rman_get_end(pf->ccr_res), 64970746Simp pf->ccr_base)); 65061788Simp CARD_SET_RES_FLAGS(device_get_parent(dev), dev, SYS_RES_MEMORY, 65161788Simp pf->ccr_rid, PCCARD_A_MEM_ATTR); 65270715Sjon CARD_SET_MEMORY_OFFSET(device_get_parent(dev), dev, 65370748Simp pf->ccr_rid, pf->ccr_base, &pf->pf_ccr_offset); 65455720Simp pf->pf_ccrt = rman_get_bustag(pf->ccr_res); 65555720Simp pf->pf_ccrh = rman_get_bushandle(pf->ccr_res); 65655720Simp pf->pf_ccr_realsize = 1; 65752506Simp } 65852506Simp 65952506Simp reg = (pf->cfe->number & PCCARD_CCR_OPTION_CFINDEX); 66052506Simp reg |= PCCARD_CCR_OPTION_LEVIREQ; 66152506Simp if (pccard_mfc(pf->sc)) { 66252506Simp reg |= (PCCARD_CCR_OPTION_FUNC_ENABLE | 66352506Simp PCCARD_CCR_OPTION_ADDR_DECODE); 66482383Simp /* PCCARD_CCR_OPTION_IRQ_ENABLE set elsewhere as needed */ 66552506Simp } 66652506Simp pccard_ccr_write(pf, PCCARD_CCR_OPTION, reg); 66752506Simp 66852506Simp reg = 0; 66952506Simp if ((pf->cfe->flags & PCCARD_CFE_IO16) == 0) 67052506Simp reg |= PCCARD_CCR_STATUS_IOIS8; 67152506Simp if (pf->cfe->flags & PCCARD_CFE_AUDIO) 67252506Simp reg |= PCCARD_CCR_STATUS_AUDIO; 67352506Simp pccard_ccr_write(pf, PCCARD_CCR_STATUS, reg); 67452506Simp 67552506Simp pccard_ccr_write(pf, PCCARD_CCR_SOCKETCOPY, 0); 67652506Simp 677121905Simp if (pccard_mfc(pf->sc)) 678121905Simp pccard_mfc_adjust_iobase(pf, 0, 0, 0); 67952506Simp 68052506Simp#ifdef PCCARDDEBUG 68152506Simp if (pccard_debug) { 68252506Simp STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) { 68370715Sjon device_printf(tmp->sc->dev, 68455500Simp "function %d CCR at %d offset %x: " 68555500Simp "%x %x %x %x, %x %x %x %x, %x\n", 68670715Sjon tmp->number, tmp->pf_ccr_window, 68755500Simp tmp->pf_ccr_offset, 68855500Simp pccard_ccr_read(tmp, 0x00), 68955500Simp pccard_ccr_read(tmp, 0x02), 69055500Simp pccard_ccr_read(tmp, 0x04), 69155500Simp pccard_ccr_read(tmp, 0x06), 69255500Simp pccard_ccr_read(tmp, 0x0A), 69370715Sjon pccard_ccr_read(tmp, 0x0C), 69455500Simp pccard_ccr_read(tmp, 0x0E), 69555500Simp pccard_ccr_read(tmp, 0x10), 69655500Simp pccard_ccr_read(tmp, 0x12)); 69752506Simp } 69852506Simp } 69952506Simp#endif 70052506Simp pf->pf_flags |= PFF_ENABLED; 70152506Simp return (0); 70252506Simp 70352506Simp bad: 70452506Simp /* 70552506Simp * Decrement the reference count, and power down the socket, if 70652506Simp * necessary. 70752506Simp */ 70882378Sjon pf->sc->sc_enabled_count--; 70965098Simp DEVPRINTF((dev, "bad --enabled_count = %d\n", pf->sc->sc_enabled_count)); 71052506Simp 71152506Simp return (1); 71252506Simp} 71352506Simp 71452506Simp/* Disable PCCARD function. */ 71582378Sjonstatic void 71655720Simppccard_function_disable(struct pccard_function *pf) 71752506Simp{ 71852506Simp struct pccard_function *tmp; 71955720Simp device_t dev = pf->sc->dev; 72052506Simp 72152506Simp if (pf->cfe == NULL) 72261788Simp panic("pccard_function_disable: function not initialized"); 72352506Simp 72452506Simp if ((pf->pf_flags & PFF_ENABLED) == 0) { 72552506Simp /* 72652506Simp * Don't do anything if we're already disabled. 72752506Simp */ 72852506Simp return; 72952506Simp } 73052506Simp 73170715Sjon if (pf->intr_handler != NULL) { 73282378Sjon struct pccard_ivar *devi = PCCARD_IVAR(pf->dev); 73382378Sjon struct resource_list_entry *rle = 73482378Sjon resource_list_find(&devi->resources, SYS_RES_IRQ, 0); 73582378Sjon BUS_TEARDOWN_INTR(dev, pf->dev, rle->res, 73682378Sjon pf->intr_handler_cookie); 73770715Sjon } 73870715Sjon 73952506Simp /* 74052506Simp * it's possible for different functions' CCRs to be in the same 74152506Simp * underlying page. Check for that. Note we mark us as disabled 74252506Simp * first to avoid matching ourself. 74352506Simp */ 74452506Simp 74552506Simp pf->pf_flags &= ~PFF_ENABLED; 74652506Simp STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) { 74752506Simp if ((tmp->pf_flags & PFF_ENABLED) && 74852506Simp (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) && 74952506Simp ((pf->ccr_base + PCCARD_CCR_SIZE) <= 75082378Sjon (tmp->ccr_base - tmp->pf_ccr_offset + 75182378Sjon tmp->pf_ccr_realsize))) 75252506Simp break; 75352506Simp } 75452506Simp 75552506Simp /* Not used by anyone else; unmap the CCR. */ 75652506Simp if (tmp == NULL) { 75770715Sjon bus_release_resource(dev, SYS_RES_MEMORY, pf->ccr_rid, 75855720Simp pf->ccr_res); 75955720Simp pf->ccr_res = NULL; 76052506Simp } 76152506Simp 76252506Simp /* 76352506Simp * Decrement the reference count, and power down the socket, if 76452506Simp * necessary. 76552506Simp */ 76682378Sjon pf->sc->sc_enabled_count--; 76752506Simp} 76852506Simp 76966058Simp/* 77066058Simp * simulate the old "probe" routine. In the new world order, the driver 77166058Simp * needs to grab devices while in the old they were assigned to the device by 77266058Simp * the pccardd process. These symbols are exported to the upper layers. 77366058Simp */ 77474636Simpstatic int 77574636Simppccard_compat_do_probe(device_t bus, device_t dev) 77666058Simp{ 77766058Simp return (CARD_COMPAT_MATCH(dev)); 77866058Simp} 77966058Simp 78074636Simpstatic int 78174636Simppccard_compat_do_attach(device_t bus, device_t dev) 78266058Simp{ 78366058Simp int err; 78466058Simp 78566058Simp err = CARD_COMPAT_PROBE(dev); 786119462Simp if (err <= 0) 78766058Simp err = CARD_COMPAT_ATTACH(dev); 78866058Simp return (err); 78966058Simp} 79066058Simp 79153873Simp#define PCCARD_NPORT 2 79253873Simp#define PCCARD_NMEM 5 79353873Simp#define PCCARD_NIRQ 1 79453873Simp#define PCCARD_NDRQ 0 79553873Simp 79652506Simpstatic int 79752506Simppccard_add_children(device_t dev, int busno) 79852506Simp{ 79959193Simp /* Call parent to scan for any current children */ 80074632Simp return (0); 80152506Simp} 80252506Simp 80352506Simpstatic int 80452506Simppccard_probe(device_t dev) 80552506Simp{ 80667333Simp device_set_desc(dev, "16-bit PCCard bus"); 80774632Simp return (pccard_add_children(dev, device_get_unit(dev))); 80852506Simp} 80952506Simp 81059193Simpstatic int 81159193Simppccard_attach(device_t dev) 81259193Simp{ 81364850Simp struct pccard_softc *sc = PCCARD_SOFTC(dev); 81461788Simp 81559193Simp sc->dev = dev; 81661788Simp sc->sc_enabled_count = 0; 81774632Simp return (bus_generic_attach(dev)); 81859193Simp} 81959193Simp 82082378Sjonstatic int 82182378Sjonpccard_detach(device_t dev) 82282378Sjon{ 823106362Simp pccard_detach_card(dev); 82482378Sjon return 0; 82582378Sjon} 82682378Sjon 82787975Simpstatic int 82887975Simppccard_suspend(device_t self) 82987975Simp{ 830106362Simp pccard_detach_card(self); 83187975Simp return (0); 83287975Simp} 83387975Simp 83487975Simpstatic 83587975Simpint 83687975Simppccard_resume(device_t self) 83787975Simp{ 83887975Simp return (0); 83987975Simp} 84087975Simp 84153873Simpstatic void 84253873Simppccard_print_resources(struct resource_list *rl, const char *name, int type, 84353873Simp int count, const char *format) 84453873Simp{ 84553873Simp struct resource_list_entry *rle; 84653873Simp int printed; 84753873Simp int i; 84853873Simp 84953873Simp printed = 0; 85053873Simp for (i = 0; i < count; i++) { 85153873Simp rle = resource_list_find(rl, type, i); 85276424Simp if (rle != NULL) { 85353873Simp if (printed == 0) 85453873Simp printf(" %s ", name); 85553873Simp else if (printed > 0) 85653873Simp printf(","); 85753873Simp printed++; 85853873Simp printf(format, rle->start); 85953873Simp if (rle->count > 1) { 86053873Simp printf("-"); 86153873Simp printf(format, rle->start + rle->count - 1); 86253873Simp } 86353873Simp } else if (i > 3) { 86453873Simp /* check the first few regardless */ 86553873Simp break; 86653873Simp } 86753873Simp } 86853873Simp} 86953873Simp 87053873Simpstatic int 87153873Simppccard_print_child(device_t dev, device_t child) 87253873Simp{ 87366847Simp struct pccard_ivar *devi = PCCARD_IVAR(child); 87453873Simp struct resource_list *rl = &devi->resources; 87553873Simp int retval = 0; 87653873Simp 87753873Simp retval += bus_print_child_header(dev, child); 87853873Simp retval += printf(" at"); 87953873Simp 88076424Simp if (devi != NULL) { 88153873Simp pccard_print_resources(rl, "port", SYS_RES_IOPORT, 88253873Simp PCCARD_NPORT, "%#lx"); 88353873Simp pccard_print_resources(rl, "iomem", SYS_RES_MEMORY, 88453873Simp PCCARD_NMEM, "%#lx"); 88553873Simp pccard_print_resources(rl, "irq", SYS_RES_IRQ, PCCARD_NIRQ, 88653873Simp "%ld"); 88770715Sjon pccard_print_resources(rl, "drq", SYS_RES_DRQ, PCCARD_NDRQ, 88853873Simp "%ld"); 88967269Simp retval += printf(" function %d config %d", devi->fcn->number, 89067269Simp devi->fcn->cfe->number); 89153873Simp } 89253873Simp 89353873Simp retval += bus_print_child_footer(dev, child); 89453873Simp 89553873Simp return (retval); 89653873Simp} 89753873Simp 89853873Simpstatic int 89953873Simppccard_set_resource(device_t dev, device_t child, int type, int rid, 90053873Simp u_long start, u_long count) 90153873Simp{ 90266847Simp struct pccard_ivar *devi = PCCARD_IVAR(child); 90353873Simp struct resource_list *rl = &devi->resources; 90453873Simp 90553873Simp if (type != SYS_RES_IOPORT && type != SYS_RES_MEMORY 90653873Simp && type != SYS_RES_IRQ && type != SYS_RES_DRQ) 90774632Simp return (EINVAL); 90853873Simp if (rid < 0) 90974632Simp return (EINVAL); 91053873Simp if (type == SYS_RES_IOPORT && rid >= PCCARD_NPORT) 91174632Simp return (EINVAL); 91253873Simp if (type == SYS_RES_MEMORY && rid >= PCCARD_NMEM) 91374632Simp return (EINVAL); 91453873Simp if (type == SYS_RES_IRQ && rid >= PCCARD_NIRQ) 91574632Simp return (EINVAL); 91653873Simp if (type == SYS_RES_DRQ && rid >= PCCARD_NDRQ) 91774632Simp return (EINVAL); 91853873Simp 91953873Simp resource_list_add(rl, type, rid, start, start + count - 1, count); 92082378Sjon if (NULL != resource_list_alloc(rl, device_get_parent(dev), dev, 92182378Sjon type, &rid, start, start + count - 1, count, 0)) 92282378Sjon return 0; 92382378Sjon else 92482378Sjon return ENOMEM; 92553873Simp} 92653873Simp 92753873Simpstatic int 92853873Simppccard_get_resource(device_t dev, device_t child, int type, int rid, 92953873Simp u_long *startp, u_long *countp) 93053873Simp{ 93166847Simp struct pccard_ivar *devi = PCCARD_IVAR(child); 93253873Simp struct resource_list *rl = &devi->resources; 93353873Simp struct resource_list_entry *rle; 93453873Simp 93553873Simp rle = resource_list_find(rl, type, rid); 93676424Simp if (rle == NULL) 93774632Simp return (ENOENT); 93870715Sjon 93976424Simp if (startp != NULL) 94053873Simp *startp = rle->start; 94176424Simp if (countp != NULL) 94253873Simp *countp = rle->count; 94353873Simp 94474632Simp return (0); 94553873Simp} 94653873Simp 94753873Simpstatic void 94853873Simppccard_delete_resource(device_t dev, device_t child, int type, int rid) 94953873Simp{ 95066847Simp struct pccard_ivar *devi = PCCARD_IVAR(child); 95153873Simp struct resource_list *rl = &devi->resources; 95253873Simp resource_list_delete(rl, type, rid); 95353873Simp} 95453873Simp 95559193Simpstatic int 95659193Simppccard_set_res_flags(device_t dev, device_t child, int type, int rid, 957140692Simp uint32_t flags) 95859193Simp{ 95974632Simp return (CARD_SET_RES_FLAGS(device_get_parent(dev), child, type, 96074632Simp rid, flags)); 96159193Simp} 96259193Simp 96359193Simpstatic int 96459193Simppccard_set_memory_offset(device_t dev, device_t child, int rid, 965140692Simp uint32_t offset, uint32_t *deltap) 96670715Sjon 96759193Simp{ 96874632Simp return (CARD_SET_MEMORY_OFFSET(device_get_parent(dev), child, rid, 96974632Simp offset, deltap)); 97059193Simp} 97159193Simp 972104641Simpstatic void 973104641Simppccard_probe_nomatch(device_t bus, device_t child) 974104641Simp{ 975104641Simp struct pccard_ivar *devi = PCCARD_IVAR(child); 976104641Simp struct pccard_function *func = devi->fcn; 977104641Simp struct pccard_softc *sc = PCCARD_SOFTC(bus); 978104641Simp 979104641Simp device_printf(bus, "<unknown card>"); 980104641Simp printf(" (manufacturer=0x%04x, product=0x%04x) at function %d\n", 981104641Simp sc->card.manufacturer, sc->card.product, func->number); 982104641Simp device_printf(bus, " CIS info: %s, %s, %s\n", sc->card.cis1_info[0], 983104641Simp sc->card.cis1_info[1], sc->card.cis1_info[2]); 984104641Simp return; 985104641Simp} 986104641Simp 98766058Simpstatic int 988104641Simppccard_child_location_str(device_t bus, device_t child, char *buf, 989104641Simp size_t buflen) 990104641Simp{ 991104641Simp struct pccard_ivar *devi = PCCARD_IVAR(child); 992104641Simp struct pccard_function *func = devi->fcn; 993104641Simp 994104641Simp snprintf(buf, buflen, "function=%d", func->number); 995104641Simp return (0); 996104641Simp} 997104641Simp 998104641Simpstatic int 999104641Simppccard_child_pnpinfo_str(device_t bus, device_t child, char *buf, 1000104641Simp size_t buflen) 1001104641Simp{ 1002104641Simp struct pccard_ivar *devi = PCCARD_IVAR(child); 1003104641Simp struct pccard_function *func = devi->fcn; 1004104641Simp struct pccard_softc *sc = PCCARD_SOFTC(bus); 1005104641Simp 1006141959Simp /* XXX need to make sure that we've quoted the " in strings! */ 1007104641Simp snprintf(buf, buflen, "manufacturer=0x%04x product=0x%04x " 1008104641Simp "cisvendor=\"%s\" cisproduct=\"%s\" function_type=%d", 1009104641Simp sc->card.manufacturer, sc->card.product, sc->card.cis1_info[0], 1010104641Simp sc->card.cis1_info[1], func->function); 1011104641Simp return (0); 1012104641Simp} 1013104641Simp 1014104641Simpstatic int 101566058Simppccard_read_ivar(device_t bus, device_t child, int which, u_char *result) 101666058Simp{ 101766847Simp struct pccard_ivar *devi = PCCARD_IVAR(child); 101866779Simp struct pccard_function *func = devi->fcn; 101966779Simp struct pccard_softc *sc = PCCARD_SOFTC(bus); 102066779Simp 102166779Simp switch (which) { 102266779Simp default: 102366779Simp case PCCARD_IVAR_ETHADDR: 102482781Sshiba bcopy(func->pf_funce_lan_nid, result, ETHER_ADDR_LEN); 102566779Simp break; 102666779Simp case PCCARD_IVAR_VENDOR: 1027140692Simp *(uint32_t *) result = sc->card.manufacturer; 102866779Simp break; 102966779Simp case PCCARD_IVAR_PRODUCT: 1030140692Simp *(uint32_t *) result = sc->card.product; 103166779Simp break; 103290964Sshiba case PCCARD_IVAR_PRODEXT: 1033140692Simp *(uint16_t *) result = sc->card.prodext; 103490964Sshiba break; 103575761Simp case PCCARD_IVAR_FUNCTION: 1036140692Simp *(uint32_t *) result = func->function; 103775761Simp break; 103866779Simp case PCCARD_IVAR_FUNCTION_NUMBER: 103966847Simp if (!func) { 104066847Simp device_printf(bus, "No function number, bug!\n"); 104166847Simp return (ENOENT); 104266847Simp } 1043140692Simp *(uint32_t *) result = func->number; 104466779Simp break; 104566779Simp case PCCARD_IVAR_VENDOR_STR: 104666779Simp *(char **) result = sc->card.cis1_info[0]; 104766779Simp break; 104866779Simp case PCCARD_IVAR_PRODUCT_STR: 104966779Simp *(char **) result = sc->card.cis1_info[1]; 105066779Simp break; 105166779Simp case PCCARD_IVAR_CIS3_STR: 105266779Simp *(char **) result = sc->card.cis1_info[2]; 105366779Simp break; 105467167Simp case PCCARD_IVAR_CIS4_STR: 1055104610Simp *(char **) result = sc->card.cis1_info[3]; 105667167Simp break; 105766779Simp } 105866779Simp return (0); 105966058Simp} 106066058Simp 106166779Simpstatic void 106266779Simppccard_driver_added(device_t dev, driver_t *driver) 106366779Simp{ 106482378Sjon struct pccard_softc *sc = PCCARD_SOFTC(dev); 106582378Sjon struct pccard_function *pf; 106682378Sjon device_t child; 106782378Sjon 106882378Sjon STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) { 106982378Sjon if (STAILQ_EMPTY(&pf->cfe_head)) 107082378Sjon continue; 107182378Sjon child = pf->dev; 107282378Sjon if (device_get_state(child) != DS_NOTPRESENT) 107382378Sjon continue; 107482378Sjon if (pccard_function_enable(pf) == 0 && 107582378Sjon device_probe_and_attach(child) == 0) { 107682378Sjon DEVPRINTF((sc->dev, "function %d CCR at %d " 107782378Sjon "offset %x: %x %x %x %x, %x %x %x %x, %x\n", 107882378Sjon pf->number, pf->pf_ccr_window, pf->pf_ccr_offset, 107982378Sjon pccard_ccr_read(pf, 0x00), 108082378Sjon pccard_ccr_read(pf, 0x02), pccard_ccr_read(pf, 0x04), 108182378Sjon pccard_ccr_read(pf, 0x06), pccard_ccr_read(pf, 0x0A), 108282378Sjon pccard_ccr_read(pf, 0x0C), pccard_ccr_read(pf, 0x0E), 108382378Sjon pccard_ccr_read(pf, 0x10), pccard_ccr_read(pf, 0x12))); 108482378Sjon } else { 108586907Simp if (pf->cfe != NULL) 108686907Simp pccard_function_disable(pf); 108782378Sjon } 108882378Sjon } 108982378Sjon return; 109066779Simp} 109166058Simp 109267242Simpstatic struct resource * 109367242Simppccard_alloc_resource(device_t dev, device_t child, int type, int *rid, 109467242Simp u_long start, u_long end, u_long count, u_int flags) 109567242Simp{ 109682378Sjon struct pccard_ivar *dinfo; 109782378Sjon struct resource_list_entry *rle = 0; 109882378Sjon int passthrough = (device_get_parent(child) != dev); 1099121905Simp int isdefault = (start == 0 && end == ~0UL && count == 1); 1100104641Simp struct resource *r = NULL; 110167242Simp 1102121905Simp /* XXX I'm no longer sure this is right */ 110382378Sjon if (passthrough) { 110482378Sjon return (BUS_ALLOC_RESOURCE(device_get_parent(dev), child, 110582378Sjon type, rid, start, end, count, flags)); 110682378Sjon } 110770715Sjon 110882378Sjon dinfo = device_get_ivars(child); 110982378Sjon rle = resource_list_find(&dinfo->resources, type, *rid); 111070715Sjon 1111121905Simp if (rle == NULL && isdefault) 1112121905Simp return (NULL); /* no resource of that type/rid */ 1113121905Simp if (rle == NULL || rle->res == NULL) { 1114121905Simp /* Do we want this device to own it? */ 1115121905Simp /* XXX I think so, but that might be lame XXX */ 1116121905Simp r = bus_alloc_resource(dev, type, rid, start, end, 1117121905Simp count, flags /* XXX aligment? */); 1118121905Simp if (r == NULL) 1119121905Simp goto bad; 1120121905Simp resource_list_add(&dinfo->resources, type, *rid, 1121121905Simp rman_get_start(r), rman_get_end(r), count); 1122121905Simp rle = resource_list_find(&dinfo->resources, type, *rid); 1123121905Simp if (!rle) 1124121905Simp goto bad; 1125121905Simp rle->res = r; 112667269Simp } 1127121905Simp /* 1128121905Simp * XXX the following looks wrong, in theory, but likely it is 1129121905Simp * XXX needed because of how the CIS code allocates resources 1130121905Simp * XXX for this device. 1131121905Simp */ 1132113242Simp if (rman_get_device(rle->res) != dev) 1133104641Simp return (NULL); 1134104641Simp bus_release_resource(dev, type, *rid, rle->res); 1135104641Simp rle->res = NULL; 1136104641Simp switch(type) { 1137104641Simp case SYS_RES_IOPORT: 1138104641Simp case SYS_RES_MEMORY: 1139104641Simp if (!(flags & RF_ALIGNMENT_MASK)) 1140104641Simp flags |= rman_make_alignment_flags(rle->count); 1141104641Simp break; 1142104641Simp case SYS_RES_IRQ: 1143104641Simp flags |= RF_SHAREABLE; 1144104641Simp break; 1145104641Simp } 1146104641Simp rle->res = resource_list_alloc(&dinfo->resources, dev, child, 1147104641Simp type, rid, rle->start, rle->end, rle->count, flags); 1148104641Simp return (rle->res); 1149104641Simpbad:; 1150104641Simp device_printf(dev, "WARNING: Resource not reserved by pccard\n"); 1151104641Simp return (NULL); 115267242Simp} 115367242Simp 115467242Simpstatic int 115567242Simppccard_release_resource(device_t dev, device_t child, int type, int rid, 115667242Simp struct resource *r) 115767242Simp{ 115882378Sjon struct pccard_ivar *dinfo; 115982378Sjon int passthrough = (device_get_parent(child) != dev); 116082378Sjon struct resource_list_entry *rle = 0; 116182378Sjon int ret; 116282378Sjon int flags; 116370715Sjon 116482378Sjon if (passthrough) 116582378Sjon return BUS_RELEASE_RESOURCE(device_get_parent(dev), child, 116682378Sjon type, rid, r); 116770715Sjon 116882378Sjon dinfo = device_get_ivars(child); 116970715Sjon 117082378Sjon rle = resource_list_find(&dinfo->resources, type, rid); 117170715Sjon 117282378Sjon if (!rle) { 117382378Sjon device_printf(dev, "Allocated resource not found, " 117482378Sjon "%d %x %lx %lx\n", 117582378Sjon type, rid, rman_get_start(r), rman_get_size(r)); 117682378Sjon return ENOENT; 117770715Sjon } 117882378Sjon if (!rle->res) { 117982378Sjon device_printf(dev, "Allocated resource not recorded\n"); 118082378Sjon return ENOENT; 118170715Sjon } 118270715Sjon 118382378Sjon ret = BUS_RELEASE_RESOURCE(device_get_parent(dev), child, 118482378Sjon type, rid, r); 118582378Sjon switch(type) { 118682378Sjon case SYS_RES_IOPORT: 118782378Sjon case SYS_RES_MEMORY: 118882378Sjon flags = rman_make_alignment_flags(rle->count); 118982378Sjon break; 119082378Sjon case SYS_RES_IRQ: 119182378Sjon flags = RF_SHAREABLE; 119282378Sjon break; 119382378Sjon default: 119482378Sjon flags = 0; 119570715Sjon } 119682378Sjon rle->res = bus_alloc_resource(dev, type, &rid, 119782378Sjon rle->start, rle->end, rle->count, flags); 119882378Sjon if (rle->res == NULL) 119982378Sjon device_printf(dev, "release_resource: " 120082378Sjon "unable to reaquire resource\n"); 120182378Sjon return ret; 120267242Simp} 120367242Simp 120467333Simpstatic void 120567333Simppccard_child_detached(device_t parent, device_t dev) 120667333Simp{ 120767333Simp struct pccard_ivar *ivar = PCCARD_IVAR(dev); 120882378Sjon struct pccard_function *pf = ivar->fcn; 120967333Simp 121082378Sjon pccard_function_disable(pf); 121167333Simp} 121267333Simp 121370715Sjonstatic void 121470762Simppccard_intr(void *arg) 121570762Simp{ 121682378Sjon struct pccard_function *pf = (struct pccard_function*) arg; 121782378Sjon int reg; 1218102923Simp int doisr = 1; 121982378Sjon 122082383Simp /* 1221102923Simp * MFC cards know if they interrupted, so we have to ack the 1222102923Simp * interrupt and call the ISR. Non-MFC cards don't have these 1223102923Simp * bits, so they always get called. Many non-MFC cards have 1224102923Simp * this bit set always upon read, but some do not. 1225102923Simp * 1226102923Simp * We always ack the interrupt, even if there's no ISR 1227102923Simp * for the card. This is done on the theory that acking 1228102923Simp * the interrupt will pacify the card enough to keep an 1229102923Simp * interrupt storm from happening. Of course this won't 1230102923Simp * help in the non-MFC case. 1231116311Simp * 1232116311Simp * This has no impact for MPSAFEness of the client drivers. 1233116311Simp * We register this with whatever flags the intr_handler 1234116311Simp * was registered with. All these functions are MPSAFE. 123582383Simp */ 1236102923Simp if (pccard_mfc(pf->sc)) { 1237102923Simp reg = pccard_ccr_read(pf, PCCARD_CCR_STATUS); 1238102923Simp if (reg & PCCARD_CCR_STATUS_INTR) 1239102923Simp pccard_ccr_write(pf, PCCARD_CCR_STATUS, 1240102923Simp reg & ~PCCARD_CCR_STATUS_INTR); 1241102923Simp else 1242102923Simp doisr = 0; 1243102923Simp } 1244102923Simp if (pf->intr_handler != NULL && doisr) 124582378Sjon pf->intr_handler(pf->intr_handler_arg); 124670715Sjon} 124770715Sjon 124870715Sjonstatic int 124970762Simppccard_setup_intr(device_t dev, device_t child, struct resource *irq, 125070762Simp int flags, driver_intr_t *intr, void *arg, void **cookiep) 125170715Sjon{ 1252102713Simp struct pccard_softc *sc = PCCARD_SOFTC(dev); 125370715Sjon struct pccard_ivar *ivar = PCCARD_IVAR(child); 125470715Sjon struct pccard_function *func = ivar->fcn; 125590445Simp int err; 125670715Sjon 125770715Sjon if (func->intr_handler != NULL) 1258101762Simp panic("Only one interrupt handler per function allowed"); 125990445Simp err = bus_generic_setup_intr(dev, child, irq, flags, pccard_intr, 126090445Simp func, cookiep); 126190445Simp if (err != 0) 126290445Simp return (err); 126370715Sjon func->intr_handler = intr; 126470715Sjon func->intr_handler_arg = arg; 126582378Sjon func->intr_handler_cookie = *cookiep; 1266102713Simp if (pccard_mfc(sc)) { 1267102713Simp pccard_ccr_write(func, PCCARD_CCR_OPTION, 1268102713Simp pccard_ccr_read(func, PCCARD_CCR_OPTION) | 1269102713Simp PCCARD_CCR_OPTION_IREQ_ENABLE); 1270102713Simp } 127174632Simp return (0); 127270715Sjon} 127370715Sjon 127470715Sjonstatic int 127570762Simppccard_teardown_intr(device_t dev, device_t child, struct resource *r, 127670762Simp void *cookie) 127770715Sjon{ 1278102713Simp struct pccard_softc *sc = PCCARD_SOFTC(dev); 127970715Sjon struct pccard_ivar *ivar = PCCARD_IVAR(child); 128070715Sjon struct pccard_function *func = ivar->fcn; 128182378Sjon int ret; 128270715Sjon 1283102713Simp if (pccard_mfc(sc)) { 1284102713Simp pccard_ccr_write(func, PCCARD_CCR_OPTION, 1285102713Simp pccard_ccr_read(func, PCCARD_CCR_OPTION) & 1286102713Simp ~PCCARD_CCR_OPTION_IREQ_ENABLE); 1287102713Simp } 128890445Simp ret = bus_generic_teardown_intr(dev, child, r, cookie); 128982378Sjon if (ret == 0) { 129082378Sjon func->intr_handler = NULL; 129182378Sjon func->intr_handler_arg = NULL; 129282378Sjon func->intr_handler_cookie = NULL; 129382378Sjon } 129470715Sjon 129582378Sjon return (ret); 129670715Sjon} 129770715Sjon 1298121905Simpstatic int 1299121905Simppccard_activate_resource(device_t brdev, device_t child, int type, int rid, 1300121905Simp struct resource *r) 1301121905Simp{ 1302121905Simp struct pccard_ivar *ivar = PCCARD_IVAR(child); 1303121905Simp struct pccard_function *pf = ivar->fcn; 1304121905Simp 1305121905Simp switch(type) { 1306121905Simp case SYS_RES_IOPORT: 1307121905Simp /* 1308121905Simp * We need to adjust IOBASE[01] and IOSIZE if we're an MFC 1309121905Simp * card. 1310121905Simp */ 1311121905Simp if (pccard_mfc(pf->sc)) 1312121905Simp pccard_mfc_adjust_iobase(pf, rman_get_start(r), 0, 1313121905Simp rman_get_size(r)); 1314121905Simp break; 1315121905Simp default: 1316121905Simp break; 1317121905Simp } 1318121905Simp return (bus_generic_activate_resource(brdev, child, type, rid, r)); 1319121905Simp} 1320121905Simp 1321121905Simpstatic int 1322121905Simppccard_deactivate_resource(device_t brdev, device_t child, int type, 1323121905Simp int rid, struct resource *r) 1324121905Simp{ 1325121905Simp /* XXX undo pccard_activate_resource? XXX */ 1326121905Simp return (bus_generic_deactivate_resource(brdev, child, type, rid, r)); 1327121905Simp} 1328121905Simp 132952506Simpstatic device_method_t pccard_methods[] = { 133052506Simp /* Device interface */ 133152506Simp DEVMETHOD(device_probe, pccard_probe), 133259193Simp DEVMETHOD(device_attach, pccard_attach), 133382378Sjon DEVMETHOD(device_detach, pccard_detach), 133452506Simp DEVMETHOD(device_shutdown, bus_generic_shutdown), 133587975Simp DEVMETHOD(device_suspend, pccard_suspend), 133687975Simp DEVMETHOD(device_resume, pccard_resume), 133752506Simp 133852506Simp /* Bus interface */ 133952506Simp DEVMETHOD(bus_print_child, pccard_print_child), 134066779Simp DEVMETHOD(bus_driver_added, pccard_driver_added), 134167333Simp DEVMETHOD(bus_child_detached, pccard_child_detached), 134267242Simp DEVMETHOD(bus_alloc_resource, pccard_alloc_resource), 134367242Simp DEVMETHOD(bus_release_resource, pccard_release_resource), 1344121905Simp DEVMETHOD(bus_activate_resource, pccard_activate_resource), 1345121905Simp DEVMETHOD(bus_deactivate_resource, pccard_deactivate_resource), 134670715Sjon DEVMETHOD(bus_setup_intr, pccard_setup_intr), 134770715Sjon DEVMETHOD(bus_teardown_intr, pccard_teardown_intr), 134852506Simp DEVMETHOD(bus_set_resource, pccard_set_resource), 134952506Simp DEVMETHOD(bus_get_resource, pccard_get_resource), 135052506Simp DEVMETHOD(bus_delete_resource, pccard_delete_resource), 1351104641Simp DEVMETHOD(bus_probe_nomatch, pccard_probe_nomatch), 135266058Simp DEVMETHOD(bus_read_ivar, pccard_read_ivar), 1353104641Simp DEVMETHOD(bus_child_pnpinfo_str, pccard_child_pnpinfo_str), 1354104641Simp DEVMETHOD(bus_child_location_str, pccard_child_location_str), 135552506Simp 135659193Simp /* Card Interface */ 135759193Simp DEVMETHOD(card_set_res_flags, pccard_set_res_flags), 135859193Simp DEVMETHOD(card_set_memory_offset, pccard_set_memory_offset), 135959193Simp DEVMETHOD(card_attach_card, pccard_attach_card), 136059193Simp DEVMETHOD(card_detach_card, pccard_detach_card), 136174636Simp DEVMETHOD(card_compat_do_probe, pccard_compat_do_probe), 136274636Simp DEVMETHOD(card_compat_do_attach, pccard_compat_do_attach), 136397613Stakawata DEVMETHOD(card_do_product_lookup, pccard_do_product_lookup), 136459193Simp 136552506Simp { 0, 0 } 136652506Simp}; 136752506Simp 136852506Simpstatic driver_t pccard_driver = { 136952506Simp "pccard", 137052506Simp pccard_methods, 137164850Simp sizeof(struct pccard_softc) 137252506Simp}; 137352506Simp 137452506Simpdevclass_t pccard_devclass; 137552506Simp 1376101905Simp/* Maybe we need to have a slot device? */ 137753873SimpDRIVER_MODULE(pccard, pcic, pccard_driver, pccard_devclass, 0, 0); 1378101905SimpDRIVER_MODULE(pccard, cbb, pccard_driver, pccard_devclass, 0, 0); 137964927SimpMODULE_VERSION(pccard, 1); 1380