pccard.c revision 144930
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 144930 2005-04-12 06:00:06Z 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> 53144930Simp#include <dev/pccard/pccard_cis.h> 5452506Simp 5555500Simp#include "power_if.h" 5659193Simp#include "card_if.h" 5755500Simp 5855500Simp#define PCCARDDEBUG 5955500Simp 6091786Simp/* sysctl vars */ 6191786SimpSYSCTL_NODE(_hw, OID_AUTO, pccard, CTLFLAG_RD, 0, "PCCARD parameters"); 6291786Simp 6391786Simpint pccard_debug = 0; 6491786SimpTUNABLE_INT("hw.pccard.debug", &pccard_debug); 6591786SimpSYSCTL_INT(_hw_pccard, OID_AUTO, debug, CTLFLAG_RW, 6691786Simp &pccard_debug, 0, 6791786Simp "pccard debug"); 6891786Simp 6991786Simpint pccard_cis_debug = 0; 7091786SimpTUNABLE_INT("hw.pccard.cis_debug", &pccard_cis_debug); 7191786SimpSYSCTL_INT(_hw_pccard, OID_AUTO, cis_debug, CTLFLAG_RW, 7291786Simp &pccard_cis_debug, 0, "pccard CIS debug"); 7391786Simp 7452506Simp#ifdef PCCARDDEBUG 7552506Simp#define DPRINTF(arg) if (pccard_debug) printf arg 7655500Simp#define DEVPRINTF(arg) if (pccard_debug) device_printf arg 7767333Simp#define PRVERBOSE(arg) printf arg 7867333Simp#define DEVPRVERBOSE(arg) device_printf arg 7952506Simp#else 8052506Simp#define DPRINTF(arg) 8155500Simp#define DEVPRINTF(arg) 8267333Simp#define PRVERBOSE(arg) if (bootverbose) printf arg 8367333Simp#define DEVPRVERBOSE(arg) if (bootverbose) device_printf arg 8452506Simp#endif 8552506Simp 8682378Sjonstatic int pccard_ccr_read(struct pccard_function *pf, int ccr); 8782378Sjonstatic void pccard_ccr_write(struct pccard_function *pf, int ccr, int val); 8882378Sjonstatic int pccard_attach_card(device_t dev); 89106362Simpstatic int pccard_detach_card(device_t dev); 9082378Sjonstatic void pccard_function_init(struct pccard_function *pf); 9182378Sjonstatic void pccard_function_free(struct pccard_function *pf); 9282378Sjonstatic int pccard_function_enable(struct pccard_function *pf); 9382378Sjonstatic void pccard_function_disable(struct pccard_function *pf); 9482378Sjonstatic int pccard_compat_do_probe(device_t bus, device_t dev); 9582378Sjonstatic int pccard_compat_do_attach(device_t bus, device_t dev); 9682378Sjonstatic int pccard_add_children(device_t dev, int busno); 9782378Sjonstatic int pccard_probe(device_t dev); 9882378Sjonstatic int pccard_attach(device_t dev); 9982378Sjonstatic int pccard_detach(device_t dev); 10082378Sjonstatic void pccard_print_resources(struct resource_list *rl, 10182378Sjon const char *name, int type, int count, const char *format); 10282378Sjonstatic int pccard_print_child(device_t dev, device_t child); 10382378Sjonstatic int pccard_set_resource(device_t dev, device_t child, int type, 10482378Sjon int rid, u_long start, u_long count); 10582378Sjonstatic int pccard_get_resource(device_t dev, device_t child, int type, 10682378Sjon int rid, u_long *startp, u_long *countp); 10782378Sjonstatic void pccard_delete_resource(device_t dev, device_t child, int type, 10882378Sjon int rid); 10982378Sjonstatic int pccard_set_res_flags(device_t dev, device_t child, int type, 110140692Simp int rid, uint32_t flags); 11182378Sjonstatic int pccard_set_memory_offset(device_t dev, device_t child, int rid, 112140692Simp uint32_t offset, uint32_t *deltap); 113104641Simpstatic void pccard_probe_nomatch(device_t cbdev, device_t child); 11482378Sjonstatic int pccard_read_ivar(device_t bus, device_t child, int which, 11582378Sjon u_char *result); 11682378Sjonstatic void pccard_driver_added(device_t dev, driver_t *driver); 11782378Sjonstatic struct resource *pccard_alloc_resource(device_t dev, 11882378Sjon device_t child, int type, int *rid, u_long start, 11982378Sjon u_long end, u_long count, u_int flags); 12082378Sjonstatic int pccard_release_resource(device_t dev, device_t child, int type, 12182378Sjon int rid, struct resource *r); 12282378Sjonstatic void pccard_child_detached(device_t parent, device_t dev); 12382378Sjonstatic void pccard_intr(void *arg); 12482378Sjonstatic int pccard_setup_intr(device_t dev, device_t child, 12582378Sjon struct resource *irq, int flags, driver_intr_t *intr, 12682378Sjon void *arg, void **cookiep); 12782378Sjonstatic int pccard_teardown_intr(device_t dev, device_t child, 12882378Sjon struct resource *r, void *cookie); 12952506Simp 13097613Stakawatastatic const struct pccard_product * 13197613Stakawatapccard_do_product_lookup(device_t bus, device_t dev, 13297613Stakawata const struct pccard_product *tab, size_t ent_size, 13397613Stakawata pccard_product_match_fn matchfn); 13497613Stakawata 13597613Stakawata 13682378Sjonstatic int 13774632Simppccard_ccr_read(struct pccard_function *pf, int ccr) 13852506Simp{ 13952506Simp return (bus_space_read_1(pf->pf_ccrt, pf->pf_ccrh, 14052506Simp pf->pf_ccr_offset + ccr)); 14152506Simp} 14252506Simp 14382378Sjonstatic void 14474632Simppccard_ccr_write(struct pccard_function *pf, int ccr, int val) 14552506Simp{ 14652506Simp if ((pf->ccr_mask) & (1 << (ccr / 2))) { 14752506Simp bus_space_write_1(pf->pf_ccrt, pf->pf_ccrh, 14852506Simp pf->pf_ccr_offset + ccr, val); 14952506Simp } 15052506Simp} 15152506Simp 15259193Simpstatic int 153113242Simppccard_set_default_descr(device_t dev) 154113242Simp{ 155121521Simp const char *vendorstr, *prodstr; 156133865Simp uint32_t vendor, prod; 157121521Simp char *str; 158113242Simp 159113242Simp if (pccard_get_vendor_str(dev, &vendorstr)) 160113242Simp return (0); 161113242Simp if (pccard_get_product_str(dev, &prodstr)) 162113242Simp return (0); 163133865Simp if (vendorstr != NULL && prodstr != NULL) { 164133865Simp str = malloc(strlen(vendorstr) + strlen(prodstr) + 2, M_DEVBUF, 165133865Simp M_WAITOK); 166133865Simp sprintf(str, "%s %s", vendorstr, prodstr); 167133865Simp device_set_desc_copy(dev, str); 168133865Simp free(str, M_DEVBUF); 169133865Simp } else { 170133865Simp if (pccard_get_vendor(dev, &vendor)) 171133865Simp return (0); 172133865Simp if (pccard_get_product(dev, &prod)) 173133865Simp return (0); 174133865Simp str = malloc(100, M_DEVBUF, M_WAITOK); 175133865Simp snprintf(str, 100, "vendor=0x%x product=0x%x", vendor, prod); 176133865Simp device_set_desc_copy(dev, str); 177133865Simp free(str, M_DEVBUF); 178133865Simp } 179113242Simp return (0); 180113242Simp} 181113242Simp 182113242Simpstatic int 18359193Simppccard_attach_card(device_t dev) 18452506Simp{ 18564850Simp struct pccard_softc *sc = PCCARD_SOFTC(dev); 18652506Simp struct pccard_function *pf; 18765917Simp struct pccard_ivar *ivar; 18861788Simp device_t child; 189102713Simp int i; 19052506Simp 19152506Simp /* 19252506Simp * this is here so that when socket_enable calls gettype, trt happens 19352506Simp */ 19452506Simp STAILQ_INIT(&sc->card.pf_head); 19552506Simp 19655500Simp DEVPRINTF((dev, "chip_socket_enable\n")); 19755500Simp POWER_ENABLE_SOCKET(device_get_parent(dev), dev); 19852506Simp 19955500Simp DEVPRINTF((dev, "read_cis\n")); 20052506Simp pccard_read_cis(sc); 20152506Simp 20255500Simp DEVPRINTF((dev, "check_cis_quirks\n")); 20352506Simp pccard_check_cis_quirks(dev); 20452506Simp 20552506Simp /* 20652506Simp * bail now if the card has no functions, or if there was an error in 20752506Simp * the cis. 20852506Simp */ 20952506Simp 21070715Sjon if (sc->card.error) { 211102713Simp device_printf(dev, "CARD ERROR!\n"); 21252506Simp return (1); 21370715Sjon } 21470715Sjon if (STAILQ_EMPTY(&sc->card.pf_head)) { 215102713Simp device_printf(dev, "Card has no functions!\n"); 21652506Simp return (1); 21770715Sjon } 21852506Simp 21990436Simp if (bootverbose || pccard_debug) 22052506Simp pccard_print_cis(dev); 22152506Simp 22255500Simp DEVPRINTF((dev, "functions scanning\n")); 223102713Simp i = -1; 22452506Simp STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) { 225102713Simp i++; 226102713Simp if (STAILQ_EMPTY(&pf->cfe_head)) { 227102713Simp device_printf(dev, 228102713Simp "Function %d has no config entries.!\n", i); 22952506Simp continue; 230102713Simp } 23152506Simp pf->sc = sc; 23252506Simp pf->cfe = NULL; 23364927Simp pf->dev = NULL; 23452506Simp } 235104641Simp DEVPRINTF((dev, "Card has %d functions. pccard_mfc is %d\n", i + 1, 236102713Simp pccard_mfc(sc))); 23782378Sjon 23852506Simp STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) { 23952506Simp if (STAILQ_EMPTY(&pf->cfe_head)) 24052506Simp continue; 24161788Simp /* 24261788Simp * In NetBSD, the drivers are responsible for activating 24361788Simp * each function of a card. I think that in FreeBSD we 24461788Simp * want to activate them enough for the usual bus_*_resource 24561788Simp * routines will do the right thing. This many mean a 24661788Simp * departure from the current NetBSD model. 24761788Simp * 248104641Simp * This seems to work well in practice for most cards. 249104641Simp * However, there are two cases that are problematic. 250104641Simp * If a driver wishes to pick and chose which config 251104641Simp * entry to use, then this method falls down. These 252104641Simp * are usually older cards. In addition, there are 253104641Simp * some cards that have multiple hardware units on the 254104641Simp * cards, but presents only one CIS chain. These cards 255104641Simp * are combination cards, but only one of these units 256104641Simp * can be on at a time. 25761788Simp */ 25867897Sdwmalone ivar = malloc(sizeof(struct pccard_ivar), M_DEVBUF, 259111119Simp M_WAITOK | M_ZERO); 260143815Simp resource_list_init(&ivar->resources); 26161788Simp child = device_add_child(dev, NULL, -1); 26265917Simp device_set_ivars(child, ivar); 26366847Simp ivar->fcn = pf; 26467187Simp pf->dev = child; 26567167Simp /* 26667167Simp * XXX We might want to move the next two lines into 26767167Simp * XXX the pccard interface layer. For the moment, this 26867167Simp * XXX is OK, but some drivers want to pick the config 26967167Simp * XXX entry to use as well as some address tweaks (mostly 27067167Simp * XXX due to bugs in decode logic that makes some 27167167Simp * XXX addresses illegal or broken). 27267167Simp */ 27365917Simp pccard_function_init(pf); 27482378Sjon if (sc->sc_enabled_count == 0) 27582378Sjon POWER_ENABLE_SOCKET(device_get_parent(dev), dev); 27667333Simp if (pccard_function_enable(pf) == 0 && 277113242Simp pccard_set_default_descr(child) == 0 && 27867333Simp device_probe_and_attach(child) == 0) { 27955500Simp DEVPRINTF((sc->dev, "function %d CCR at %d " 280121905Simp "offset %x mask %x: " 281121905Simp "%x %x %x %x, %x %x %x %x, %x\n", 28267167Simp pf->number, pf->pf_ccr_window, pf->pf_ccr_offset, 283121905Simp pf->ccr_mask, pccard_ccr_read(pf, 0x00), 28452506Simp pccard_ccr_read(pf, 0x02), pccard_ccr_read(pf, 0x04), 28552506Simp pccard_ccr_read(pf, 0x06), pccard_ccr_read(pf, 0x0A), 28652506Simp pccard_ccr_read(pf, 0x0C), pccard_ccr_read(pf, 0x0E), 28752506Simp pccard_ccr_read(pf, 0x10), pccard_ccr_read(pf, 0x12))); 28867167Simp } else { 28986907Simp if (pf->cfe != NULL) 29086907Simp pccard_function_disable(pf); 29152506Simp } 29252506Simp } 29374632Simp return (0); 29452506Simp} 29552506Simp 29659193Simpstatic int 297106362Simppccard_detach_card(device_t dev) 29852506Simp{ 29964850Simp struct pccard_softc *sc = PCCARD_SOFTC(dev); 30052506Simp struct pccard_function *pf; 30182378Sjon struct pccard_config_entry *cfe; 302119755Simp int state; 30352506Simp 30452506Simp /* 30552506Simp * We are running on either the PCCARD socket's event thread 30652506Simp * or in user context detaching a device by user request. 30752506Simp */ 30852506Simp STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) { 309119755Simp if (pf->dev == NULL) 310119755Simp continue; 311119755Simp state = device_get_state(pf->dev); 31282378Sjon if (state == DS_ATTACHED || state == DS_BUSY) 31382378Sjon device_detach(pf->dev); 31486907Simp if (pf->cfe != NULL) 31586907Simp pccard_function_disable(pf); 31682378Sjon pccard_function_free(pf); 317106896Simp device_delete_child(dev, pf->dev); 31852506Simp } 31982378Sjon if (sc->sc_enabled_count == 0) 32082378Sjon POWER_DISABLE_SOCKET(device_get_parent(dev), dev); 32182378Sjon 32282378Sjon while (NULL != (pf = STAILQ_FIRST(&sc->card.pf_head))) { 32382378Sjon while (NULL != (cfe = STAILQ_FIRST(&pf->cfe_head))) { 32482378Sjon STAILQ_REMOVE_HEAD(&pf->cfe_head, cfe_list); 32582378Sjon free(cfe, M_DEVBUF); 32682378Sjon } 32782378Sjon STAILQ_REMOVE_HEAD(&sc->card.pf_head, pf_list); 32882378Sjon free(pf, M_DEVBUF); 32982378Sjon } 33074632Simp return (0); 33152506Simp} 33252506Simp 33397613Stakawatastatic const struct pccard_product * 33497613Stakawatapccard_do_product_lookup(device_t bus, device_t dev, 335112359Simp const struct pccard_product *tab, size_t ent_size, 336112359Simp pccard_product_match_fn matchfn) 33766200Simp{ 33866200Simp const struct pccard_product *ent; 33966200Simp int matches; 340140692Simp uint32_t vendor; 341140692Simp uint32_t prod; 342121521Simp const char *vendorstr; 343121521Simp const char *prodstr; 344140366Simp const char *cis3str; 345140366Simp const char *cis4str; 34666200Simp 34766200Simp#ifdef DIAGNOSTIC 34866200Simp if (sizeof *ent > ent_size) 349112359Simp panic("pccard_product_lookup: bogus ent_size %jd", 350112359Simp (intmax_t) ent_size); 35166200Simp#endif 35266200Simp if (pccard_get_vendor(dev, &vendor)) 35366200Simp return (NULL); 35466200Simp if (pccard_get_product(dev, &prod)) 35566200Simp return (NULL); 35666200Simp if (pccard_get_vendor_str(dev, &vendorstr)) 35766200Simp return (NULL); 35866200Simp if (pccard_get_product_str(dev, &prodstr)) 35966200Simp return (NULL); 360140366Simp if (pccard_get_cis3_str(dev, &cis3str)) 361140366Simp return (NULL); 362140366Simp if (pccard_get_cis4_str(dev, &cis4str)) 363140366Simp return (NULL); 364113313Simp for (ent = tab; ent->pp_vendor != 0; ent = 36582378Sjon (const struct pccard_product *) ((const char *) ent + ent_size)) { 36666200Simp matches = 1; 36786642Simp if (ent->pp_vendor == PCCARD_VENDOR_ANY && 368113078Ssanpei ent->pp_product == PCCARD_PRODUCT_ANY && 36986642Simp ent->pp_cis[0] == NULL && 37086642Simp ent->pp_cis[1] == NULL) { 371113300Simp if (ent->pp_name) 372113300Simp device_printf(dev, 373113300Simp "Total wildcard entry ignored for %s\n", 374113300Simp ent->pp_name); 37586642Simp continue; 37686642Simp } 37766200Simp if (matches && ent->pp_vendor != PCCARD_VENDOR_ANY && 37866200Simp vendor != ent->pp_vendor) 37966200Simp matches = 0; 38066200Simp if (matches && ent->pp_product != PCCARD_PRODUCT_ANY && 38166200Simp prod != ent->pp_product) 38266200Simp matches = 0; 38371322Simp if (matches && ent->pp_cis[0] && 384133865Simp (vendorstr == NULL || 385133865Simp strcmp(ent->pp_cis[0], vendorstr) != 0)) 38666200Simp matches = 0; 38771322Simp if (matches && ent->pp_cis[1] && 388133865Simp (prodstr == NULL || 389133865Simp strcmp(ent->pp_cis[1], prodstr) != 0)) 39066200Simp matches = 0; 391140366Simp if (matches && ent->pp_cis[2] && 392140366Simp (cis3str == NULL || 393140366Simp strcmp(ent->pp_cis[2], cis3str) != 0)) 394140366Simp matches = 0; 395140366Simp if (matches && ent->pp_cis[3] && 396140366Simp (cis4str == NULL || 397140366Simp strcmp(ent->pp_cis[3], cis4str) != 0)) 398140366Simp matches = 0; 39966200Simp if (matchfn != NULL) 40066200Simp matches = (*matchfn)(dev, ent, matches); 40166200Simp if (matches) 40266200Simp return (ent); 40366200Simp } 40466200Simp return (NULL); 40566200Simp} 40666200Simp 40752506Simp/* 40852506Simp * Initialize a PCCARD function. May be called as long as the function is 40952506Simp * disabled. 41082382Simp * 41182382Simp * Note: pccard_function_init should not keep resources allocated. It should 41282382Simp * only set them up ala isa pnp, set the values in the rl lists, and return. 41382382Simp * Any resource held after pccard_function_init is called is a bug. However, 41482382Simp * the bus routines to get the resources also assume that pccard_function_init 41582382Simp * does this, so they need to be fixed too. 41652506Simp */ 41782378Sjonstatic void 41870715Sjonpccard_function_init(struct pccard_function *pf) 41952506Simp{ 42065917Simp struct pccard_config_entry *cfe; 421144930Simp int i, rid; 42267242Simp struct pccard_ivar *devi = PCCARD_IVAR(pf->dev); 42367242Simp struct resource_list *rl = &devi->resources; 42470762Simp struct resource_list_entry *rle; 42567242Simp struct resource *r = 0; 42667242Simp device_t bus; 42767424Simp int start; 42867424Simp int end; 42990897Simp int spaces; 43065917Simp 43170715Sjon if (pf->pf_flags & PFF_ENABLED) { 43270715Sjon printf("pccard_function_init: function is enabled"); 43370715Sjon return; 43470715Sjon } 43567242Simp bus = device_get_parent(pf->dev); 43652506Simp /* Remember which configuration entry we are using. */ 43772012Sphk STAILQ_FOREACH(cfe, &pf->cfe_head, cfe_list) { 438144930Simp if (cfe->iftype != PCCARD_IFTYPE_IO) 439144930Simp continue; 44067187Simp for (i = 0; i < cfe->num_iospace; i++) 44167187Simp cfe->iores[i] = NULL; 442144930Simp for (i = 0; i < cfe->num_memspace; i++) 443144930Simp cfe->memres[i] = NULL; 44467187Simp cfe->irqres = NULL; 44590897Simp spaces = 0; 44667187Simp for (i = 0; i < cfe->num_iospace; i++) { 44767424Simp start = cfe->iospace[i].start; 44867424Simp if (start) 44967424Simp end = start + cfe->iospace[i].length - 1; 45067424Simp else 451144930Simp end = ~0UL; 45290897Simp DEVPRINTF((bus, "I/O rid %d start %x end %x\n", 45390897Simp i, start, end)); 454144930Simp rid = i; 45567242Simp r = cfe->iores[i] = bus_alloc_resource(bus, 456144930Simp SYS_RES_IOPORT, &rid, start, end, 45770715Sjon cfe->iospace[i].length, 45867424Simp rman_make_alignment_flags(cfe->iospace[i].length)); 45976424Simp if (cfe->iores[i] == NULL) 46067187Simp goto not_this_one; 461144927Simp rle = resource_list_add(rl, SYS_RES_IOPORT, 462144930Simp rid, rman_get_start(r), rman_get_end(r), 46367242Simp cfe->iospace[i].length); 464144927Simp if (rle == NULL) 465144930Simp panic("Cannot add resource rid %d IOPORT", rid); 46676424Simp rle->res = r; 46790897Simp spaces++; 46867187Simp } 469144930Simp for (i = 0; i < cfe->num_memspace; i++) { 470144930Simp start = cfe->memspace[i].hostaddr; 471144930Simp if (start) 472144930Simp end = start + cfe->memspace[i].length - 1; 473144930Simp else 474144930Simp end = ~0UL; 475144930Simp DEVPRINTF((bus, "Memory rid %d start %x end %x\n", 476144930Simp i, start, end)); 477144930Simp rid = i; 478144930Simp r = cfe->memres[i] = bus_alloc_resource(bus, 479144930Simp SYS_RES_MEMORY, &rid, start, end, 480144930Simp cfe->memspace[i].length, 481144930Simp rman_make_alignment_flags(cfe->memspace[i].length)); 482144930Simp if (cfe->memres[i] == NULL) 483144930Simp goto not_this_one; 484144930Simp rle = resource_list_add(rl, SYS_RES_MEMORY, 485144930Simp rid, rman_get_start(r), rman_get_end(r), 486144930Simp cfe->memspace[i].length); 487144930Simp if (rle == NULL) 488144930Simp panic("Cannot add resource rid %d MEM", rid); 489144930Simp rle->res = r; 490144930Simp spaces++; 49167187Simp } 49290897Simp if (spaces == 0) { 493140488Simp DEVPRINTF((bus, "Neither memory nor I/O mapped\n")); 49490897Simp goto not_this_one; 49590897Simp } 49667187Simp if (cfe->irqmask) { 497144930Simp rid = 0; 498127135Snjl r = cfe->irqres = bus_alloc_resource_any(bus, 499144930Simp SYS_RES_IRQ, &rid, 0); 50076424Simp if (cfe->irqres == NULL) 50167187Simp goto not_this_one; 502144930Simp rle = resource_list_add(rl, SYS_RES_IRQ, rid, 50367242Simp rman_get_start(r), rman_get_end(r), 1); 504144927Simp if (rle == NULL) 505144930Simp panic("Cannot add resource rid %d IRQ", rid); 50676424Simp rle->res = r; 50767187Simp } 50867187Simp /* If we get to here, we've allocated all we need */ 50967167Simp pf->cfe = cfe; 51067187Simp break; 51167187Simp not_this_one:; 51267424Simp DEVPRVERBOSE((bus, "Allocation failed for cfe %d\n", 51367424Simp cfe->number)); 51467333Simp /* 51567333Simp * Release resources that we partially allocated 51667333Simp * from this config entry. 51767333Simp */ 51867187Simp for (i = 0; i < cfe->num_iospace; i++) { 519144930Simp r = cfe->iores[i]; 520144930Simp if (r == NULL) 521144930Simp continue; 522144930Simp rid = rman_get_rid(r); 523144930Simp bus_release_resource(bus, SYS_RES_IOPORT, rid, r); 524144930Simp rle = resource_list_find(rl, SYS_RES_IOPORT, rid); 525144930Simp rle->res = NULL; 526144930Simp resource_list_delete(rl, SYS_RES_IOPORT, rid); 52767187Simp cfe->iores[i] = NULL; 52867187Simp } 529144930Simp for (i = 0; i < cfe->num_memspace; i++) { 530144930Simp r = cfe->memres[i]; 531144930Simp if (r == NULL) 532144930Simp continue; 533144930Simp rid = rman_get_rid(r); 534144930Simp bus_release_resource(bus, SYS_RES_MEMORY, rid, r); 535144930Simp rle = resource_list_find(rl, SYS_RES_MEMORY, rid); 536144930Simp rle->res = NULL; 537144930Simp resource_list_delete(rl, SYS_RES_MEMORY, rid); 538144930Simp cfe->memres[i] = NULL; 539144930Simp } 54076424Simp if (cfe->irqmask && cfe->irqres != NULL) { 541144930Simp r = cfe->irqres; 542144930Simp rid = rman_get_rid(r); 543144930Simp bus_release_resource(bus, SYS_RES_IRQ, rid, r); 544144930Simp rle = resource_list_find(rl, SYS_RES_IRQ, rid); 54576424Simp rle->res = NULL; 546144930Simp resource_list_delete(rl, SYS_RES_IRQ, rid); 54767187Simp cfe->irqres = NULL; 54867187Simp } 54967167Simp } 55052506Simp} 55152506Simp 55282378Sjon/* 55382378Sjon * Free resources allocated by pccard_function_init(), May be called as long 55482378Sjon * as the function is disabled. 55582382Simp * 55682382Simp * NOTE: This function should be unnecessary. pccard_function_init should 55782382Simp * never keep resources initialized. 55882378Sjon */ 55982378Sjonstatic void 56082378Sjonpccard_function_free(struct pccard_function *pf) 56182378Sjon{ 56282378Sjon struct pccard_ivar *devi = PCCARD_IVAR(pf->dev); 56382378Sjon struct resource_list_entry *rle; 56482378Sjon 56582378Sjon if (pf->pf_flags & PFF_ENABLED) { 56682378Sjon printf("pccard_function_init: function is enabled"); 56782378Sjon return; 56882378Sjon } 56982378Sjon 570143785Simp STAILQ_FOREACH(rle, &devi->resources, link) { 57182378Sjon if (rle->res) { 572113242Simp if (rman_get_device(rle->res) != pf->sc->dev) 57382378Sjon device_printf(pf->sc->dev, 57482378Sjon "function_free: Resource still owned by " 57582378Sjon "child, oops. " 57682378Sjon "(type=%d, rid=%d, addr=%lx)\n", 57782378Sjon rle->type, rle->rid, 57882378Sjon rman_get_start(rle->res)); 57982378Sjon BUS_RELEASE_RESOURCE(device_get_parent(pf->sc->dev), 580113242Simp pf->sc->dev, rle->type, rle->rid, rle->res); 58182378Sjon rle->res = NULL; 58282378Sjon } 58382378Sjon } 58482378Sjon resource_list_free(&devi->resources); 58582378Sjon} 58682378Sjon 587121905Simpstatic void 588121905Simppccard_mfc_adjust_iobase(struct pccard_function *pf, bus_addr_t addr, 589121905Simp bus_addr_t offset, bus_size_t size) 590121905Simp{ 591121958Simp bus_size_t iosize, tmp; 592121905Simp 593121905Simp if (addr != 0) { 594121905Simp if (pf->pf_mfc_iomax == 0) { 595121905Simp pf->pf_mfc_iobase = addr + offset; 596121905Simp pf->pf_mfc_iomax = pf->pf_mfc_iobase + size; 597121905Simp } else { 598121905Simp /* this makes the assumption that nothing overlaps */ 599121905Simp if (pf->pf_mfc_iobase > addr + offset) 600121905Simp pf->pf_mfc_iobase = addr + offset; 601121905Simp if (pf->pf_mfc_iomax < addr + offset + size) 602121905Simp pf->pf_mfc_iomax = addr + offset + size; 603121905Simp } 604121905Simp } 605121905Simp 606121905Simp tmp = pf->pf_mfc_iomax - pf->pf_mfc_iobase; 607121905Simp /* round up to nearest (2^n)-1 */ 608121905Simp for (iosize = 1; iosize < tmp; iosize <<= 1) 609121905Simp ; 610121905Simp iosize--; 611121905Simp 612122032Simp DEVPRINTF((pf->dev, "MFC: I/O base %#jx IOSIZE %#jx\n", 613122032Simp (uintmax_t)pf->pf_mfc_iobase, (uintmax_t)(iosize + 1))); 614121905Simp pccard_ccr_write(pf, PCCARD_CCR_IOBASE0, 615121905Simp pf->pf_mfc_iobase & 0xff); 616121905Simp pccard_ccr_write(pf, PCCARD_CCR_IOBASE1, 617121905Simp (pf->pf_mfc_iobase >> 8) & 0xff); 618121905Simp pccard_ccr_write(pf, PCCARD_CCR_IOBASE2, 0); 619121905Simp pccard_ccr_write(pf, PCCARD_CCR_IOBASE3, 0); 620121905Simp pccard_ccr_write(pf, PCCARD_CCR_IOSIZE, iosize); 621121905Simp} 622121905Simp 62352506Simp/* Enable a PCCARD function */ 62482378Sjonstatic int 62555720Simppccard_function_enable(struct pccard_function *pf) 62652506Simp{ 62752506Simp struct pccard_function *tmp; 62852506Simp int reg; 62955720Simp device_t dev = pf->sc->dev; 63070746Simp 63167333Simp if (pf->cfe == NULL) { 63267333Simp DEVPRVERBOSE((dev, "No config entry could be allocated.\n")); 63374632Simp return (ENOMEM); 63467333Simp } 63552506Simp 63652506Simp /* 63752506Simp * Increase the reference count on the socket, enabling power, if 63852506Simp * necessary. 63952506Simp */ 64082378Sjon pf->sc->sc_enabled_count++; 64152506Simp 64252506Simp if (pf->pf_flags & PFF_ENABLED) { 64352506Simp /* 64452506Simp * Don't do anything if we're already enabled. 64552506Simp */ 64652506Simp return (0); 64752506Simp } 64852506Simp 64952506Simp /* 65052506Simp * it's possible for different functions' CCRs to be in the same 65152506Simp * underlying page. Check for that. 65252506Simp */ 65352506Simp STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) { 65452506Simp if ((tmp->pf_flags & PFF_ENABLED) && 65552506Simp (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) && 65652506Simp ((pf->ccr_base + PCCARD_CCR_SIZE) <= 65782378Sjon (tmp->ccr_base - tmp->pf_ccr_offset + 65882378Sjon tmp->pf_ccr_realsize))) { 65952506Simp pf->pf_ccrt = tmp->pf_ccrt; 66052506Simp pf->pf_ccrh = tmp->pf_ccrh; 66152506Simp pf->pf_ccr_realsize = tmp->pf_ccr_realsize; 66252506Simp 66352506Simp /* 66452506Simp * pf->pf_ccr_offset = (tmp->pf_ccr_offset - 66552506Simp * tmp->ccr_base) + pf->ccr_base; 66652506Simp */ 66770715Sjon /* pf->pf_ccr_offset = 66852506Simp (tmp->pf_ccr_offset + pf->ccr_base) - 66970715Sjon tmp->ccr_base; */ 67052506Simp pf->pf_ccr_window = tmp->pf_ccr_window; 67152506Simp break; 67252506Simp } 67352506Simp } 67452506Simp if (tmp == NULL) { 67555720Simp pf->ccr_rid = 0; 67655720Simp pf->ccr_res = bus_alloc_resource(dev, SYS_RES_MEMORY, 67770715Sjon &pf->ccr_rid, 0, ~0, 1 << 10, RF_ACTIVE); 67870715Sjon if (!pf->ccr_res) 67952506Simp goto bad; 680106914Smux DEVPRINTF((dev, "ccr_res == %lx-%lx, base=%x\n", 68170746Simp rman_get_start(pf->ccr_res), rman_get_end(pf->ccr_res), 68270746Simp pf->ccr_base)); 68361788Simp CARD_SET_RES_FLAGS(device_get_parent(dev), dev, SYS_RES_MEMORY, 68461788Simp pf->ccr_rid, PCCARD_A_MEM_ATTR); 68570715Sjon CARD_SET_MEMORY_OFFSET(device_get_parent(dev), dev, 68670748Simp pf->ccr_rid, pf->ccr_base, &pf->pf_ccr_offset); 68755720Simp pf->pf_ccrt = rman_get_bustag(pf->ccr_res); 68855720Simp pf->pf_ccrh = rman_get_bushandle(pf->ccr_res); 68955720Simp pf->pf_ccr_realsize = 1; 69052506Simp } 69152506Simp 69252506Simp reg = (pf->cfe->number & PCCARD_CCR_OPTION_CFINDEX); 69352506Simp reg |= PCCARD_CCR_OPTION_LEVIREQ; 69452506Simp if (pccard_mfc(pf->sc)) { 69552506Simp reg |= (PCCARD_CCR_OPTION_FUNC_ENABLE | 69652506Simp PCCARD_CCR_OPTION_ADDR_DECODE); 69782383Simp /* PCCARD_CCR_OPTION_IRQ_ENABLE set elsewhere as needed */ 69852506Simp } 69952506Simp pccard_ccr_write(pf, PCCARD_CCR_OPTION, reg); 70052506Simp 70152506Simp reg = 0; 70252506Simp if ((pf->cfe->flags & PCCARD_CFE_IO16) == 0) 70352506Simp reg |= PCCARD_CCR_STATUS_IOIS8; 70452506Simp if (pf->cfe->flags & PCCARD_CFE_AUDIO) 70552506Simp reg |= PCCARD_CCR_STATUS_AUDIO; 70652506Simp pccard_ccr_write(pf, PCCARD_CCR_STATUS, reg); 70752506Simp 70852506Simp pccard_ccr_write(pf, PCCARD_CCR_SOCKETCOPY, 0); 70952506Simp 710121905Simp if (pccard_mfc(pf->sc)) 711121905Simp pccard_mfc_adjust_iobase(pf, 0, 0, 0); 71252506Simp 71352506Simp#ifdef PCCARDDEBUG 71452506Simp if (pccard_debug) { 71552506Simp STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) { 71670715Sjon device_printf(tmp->sc->dev, 71755500Simp "function %d CCR at %d offset %x: " 71855500Simp "%x %x %x %x, %x %x %x %x, %x\n", 71970715Sjon tmp->number, tmp->pf_ccr_window, 72055500Simp tmp->pf_ccr_offset, 72155500Simp pccard_ccr_read(tmp, 0x00), 72255500Simp pccard_ccr_read(tmp, 0x02), 72355500Simp pccard_ccr_read(tmp, 0x04), 72455500Simp pccard_ccr_read(tmp, 0x06), 72555500Simp pccard_ccr_read(tmp, 0x0A), 72670715Sjon pccard_ccr_read(tmp, 0x0C), 72755500Simp pccard_ccr_read(tmp, 0x0E), 72855500Simp pccard_ccr_read(tmp, 0x10), 72955500Simp pccard_ccr_read(tmp, 0x12)); 73052506Simp } 73152506Simp } 73252506Simp#endif 73352506Simp pf->pf_flags |= PFF_ENABLED; 73452506Simp return (0); 73552506Simp 73652506Simp bad: 73752506Simp /* 73852506Simp * Decrement the reference count, and power down the socket, if 73952506Simp * necessary. 74052506Simp */ 74182378Sjon pf->sc->sc_enabled_count--; 74265098Simp DEVPRINTF((dev, "bad --enabled_count = %d\n", pf->sc->sc_enabled_count)); 74352506Simp 74452506Simp return (1); 74552506Simp} 74652506Simp 74752506Simp/* Disable PCCARD function. */ 74882378Sjonstatic void 74955720Simppccard_function_disable(struct pccard_function *pf) 75052506Simp{ 75152506Simp struct pccard_function *tmp; 75255720Simp device_t dev = pf->sc->dev; 75352506Simp 75452506Simp if (pf->cfe == NULL) 75561788Simp panic("pccard_function_disable: function not initialized"); 75652506Simp 75752506Simp if ((pf->pf_flags & PFF_ENABLED) == 0) { 75852506Simp /* 75952506Simp * Don't do anything if we're already disabled. 76052506Simp */ 76152506Simp return; 76252506Simp } 76352506Simp 76470715Sjon if (pf->intr_handler != NULL) { 76582378Sjon struct pccard_ivar *devi = PCCARD_IVAR(pf->dev); 76682378Sjon struct resource_list_entry *rle = 76782378Sjon resource_list_find(&devi->resources, SYS_RES_IRQ, 0); 768144927Simp if (rle == NULL) 769144927Simp panic("Can't disable an interrupt with no IRQ res\n"); 77082378Sjon BUS_TEARDOWN_INTR(dev, pf->dev, rle->res, 77182378Sjon pf->intr_handler_cookie); 77270715Sjon } 77370715Sjon 77452506Simp /* 77552506Simp * it's possible for different functions' CCRs to be in the same 77652506Simp * underlying page. Check for that. Note we mark us as disabled 77752506Simp * first to avoid matching ourself. 77852506Simp */ 77952506Simp 78052506Simp pf->pf_flags &= ~PFF_ENABLED; 78152506Simp STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) { 78252506Simp if ((tmp->pf_flags & PFF_ENABLED) && 78352506Simp (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) && 78452506Simp ((pf->ccr_base + PCCARD_CCR_SIZE) <= 78582378Sjon (tmp->ccr_base - tmp->pf_ccr_offset + 78682378Sjon tmp->pf_ccr_realsize))) 78752506Simp break; 78852506Simp } 78952506Simp 79052506Simp /* Not used by anyone else; unmap the CCR. */ 79152506Simp if (tmp == NULL) { 79270715Sjon bus_release_resource(dev, SYS_RES_MEMORY, pf->ccr_rid, 79355720Simp pf->ccr_res); 79455720Simp pf->ccr_res = NULL; 79552506Simp } 79652506Simp 79752506Simp /* 79852506Simp * Decrement the reference count, and power down the socket, if 79952506Simp * necessary. 80052506Simp */ 80182378Sjon pf->sc->sc_enabled_count--; 80252506Simp} 80352506Simp 80466058Simp/* 80566058Simp * simulate the old "probe" routine. In the new world order, the driver 80666058Simp * needs to grab devices while in the old they were assigned to the device by 80766058Simp * the pccardd process. These symbols are exported to the upper layers. 80866058Simp */ 80974636Simpstatic int 81074636Simppccard_compat_do_probe(device_t bus, device_t dev) 81166058Simp{ 81266058Simp return (CARD_COMPAT_MATCH(dev)); 81366058Simp} 81466058Simp 81574636Simpstatic int 81674636Simppccard_compat_do_attach(device_t bus, device_t dev) 81766058Simp{ 81866058Simp int err; 81966058Simp 82066058Simp err = CARD_COMPAT_PROBE(dev); 821119462Simp if (err <= 0) 82266058Simp err = CARD_COMPAT_ATTACH(dev); 82366058Simp return (err); 82466058Simp} 82566058Simp 82653873Simp#define PCCARD_NPORT 2 82753873Simp#define PCCARD_NMEM 5 82853873Simp#define PCCARD_NIRQ 1 82953873Simp#define PCCARD_NDRQ 0 83053873Simp 83152506Simpstatic int 83252506Simppccard_add_children(device_t dev, int busno) 83352506Simp{ 83459193Simp /* Call parent to scan for any current children */ 83574632Simp return (0); 83652506Simp} 83752506Simp 83852506Simpstatic int 83952506Simppccard_probe(device_t dev) 84052506Simp{ 84167333Simp device_set_desc(dev, "16-bit PCCard bus"); 84274632Simp return (pccard_add_children(dev, device_get_unit(dev))); 84352506Simp} 84452506Simp 84559193Simpstatic int 84659193Simppccard_attach(device_t dev) 84759193Simp{ 84864850Simp struct pccard_softc *sc = PCCARD_SOFTC(dev); 84961788Simp 85059193Simp sc->dev = dev; 85161788Simp sc->sc_enabled_count = 0; 85274632Simp return (bus_generic_attach(dev)); 85359193Simp} 85459193Simp 85582378Sjonstatic int 85682378Sjonpccard_detach(device_t dev) 85782378Sjon{ 858106362Simp pccard_detach_card(dev); 85982378Sjon return 0; 86082378Sjon} 86182378Sjon 86287975Simpstatic int 86387975Simppccard_suspend(device_t self) 86487975Simp{ 865106362Simp pccard_detach_card(self); 86687975Simp return (0); 86787975Simp} 86887975Simp 86987975Simpstatic 87087975Simpint 87187975Simppccard_resume(device_t self) 87287975Simp{ 87387975Simp return (0); 87487975Simp} 87587975Simp 87653873Simpstatic void 87753873Simppccard_print_resources(struct resource_list *rl, const char *name, int type, 87853873Simp int count, const char *format) 87953873Simp{ 88053873Simp struct resource_list_entry *rle; 88153873Simp int printed; 88253873Simp int i; 88353873Simp 88453873Simp printed = 0; 88553873Simp for (i = 0; i < count; i++) { 88653873Simp rle = resource_list_find(rl, type, i); 88776424Simp if (rle != NULL) { 88853873Simp if (printed == 0) 88953873Simp printf(" %s ", name); 89053873Simp else if (printed > 0) 89153873Simp printf(","); 89253873Simp printed++; 89353873Simp printf(format, rle->start); 89453873Simp if (rle->count > 1) { 89553873Simp printf("-"); 89653873Simp printf(format, rle->start + rle->count - 1); 89753873Simp } 89853873Simp } else if (i > 3) { 89953873Simp /* check the first few regardless */ 90053873Simp break; 90153873Simp } 90253873Simp } 90353873Simp} 90453873Simp 90553873Simpstatic int 90653873Simppccard_print_child(device_t dev, device_t child) 90753873Simp{ 90866847Simp struct pccard_ivar *devi = PCCARD_IVAR(child); 90953873Simp struct resource_list *rl = &devi->resources; 91053873Simp int retval = 0; 91153873Simp 91253873Simp retval += bus_print_child_header(dev, child); 91353873Simp retval += printf(" at"); 91453873Simp 91576424Simp if (devi != NULL) { 91653873Simp pccard_print_resources(rl, "port", SYS_RES_IOPORT, 91753873Simp PCCARD_NPORT, "%#lx"); 91853873Simp pccard_print_resources(rl, "iomem", SYS_RES_MEMORY, 91953873Simp PCCARD_NMEM, "%#lx"); 92053873Simp pccard_print_resources(rl, "irq", SYS_RES_IRQ, PCCARD_NIRQ, 92153873Simp "%ld"); 92270715Sjon pccard_print_resources(rl, "drq", SYS_RES_DRQ, PCCARD_NDRQ, 92353873Simp "%ld"); 92467269Simp retval += printf(" function %d config %d", devi->fcn->number, 92567269Simp devi->fcn->cfe->number); 92653873Simp } 92753873Simp 92853873Simp retval += bus_print_child_footer(dev, child); 92953873Simp 93053873Simp return (retval); 93153873Simp} 93253873Simp 93353873Simpstatic int 93453873Simppccard_set_resource(device_t dev, device_t child, int type, int rid, 93553873Simp u_long start, u_long count) 93653873Simp{ 93766847Simp struct pccard_ivar *devi = PCCARD_IVAR(child); 93853873Simp struct resource_list *rl = &devi->resources; 93953873Simp 94053873Simp if (type != SYS_RES_IOPORT && type != SYS_RES_MEMORY 94153873Simp && type != SYS_RES_IRQ && type != SYS_RES_DRQ) 94274632Simp return (EINVAL); 94353873Simp if (rid < 0) 94474632Simp return (EINVAL); 94553873Simp if (type == SYS_RES_IOPORT && rid >= PCCARD_NPORT) 94674632Simp return (EINVAL); 94753873Simp if (type == SYS_RES_MEMORY && rid >= PCCARD_NMEM) 94874632Simp return (EINVAL); 94953873Simp if (type == SYS_RES_IRQ && rid >= PCCARD_NIRQ) 95074632Simp return (EINVAL); 95153873Simp if (type == SYS_RES_DRQ && rid >= PCCARD_NDRQ) 95274632Simp return (EINVAL); 95353873Simp 95453873Simp resource_list_add(rl, type, rid, start, start + count - 1, count); 95582378Sjon if (NULL != resource_list_alloc(rl, device_get_parent(dev), dev, 95682378Sjon type, &rid, start, start + count - 1, count, 0)) 95782378Sjon return 0; 95882378Sjon else 95982378Sjon return ENOMEM; 96053873Simp} 96153873Simp 96253873Simpstatic int 96353873Simppccard_get_resource(device_t dev, device_t child, int type, int rid, 96453873Simp u_long *startp, u_long *countp) 96553873Simp{ 96666847Simp struct pccard_ivar *devi = PCCARD_IVAR(child); 96753873Simp struct resource_list *rl = &devi->resources; 96853873Simp struct resource_list_entry *rle; 96953873Simp 97053873Simp rle = resource_list_find(rl, type, rid); 97176424Simp if (rle == NULL) 97274632Simp return (ENOENT); 97370715Sjon 97476424Simp if (startp != NULL) 97553873Simp *startp = rle->start; 97676424Simp if (countp != NULL) 97753873Simp *countp = rle->count; 97853873Simp 97974632Simp return (0); 98053873Simp} 98153873Simp 98253873Simpstatic void 98353873Simppccard_delete_resource(device_t dev, device_t child, int type, int rid) 98453873Simp{ 98566847Simp struct pccard_ivar *devi = PCCARD_IVAR(child); 98653873Simp struct resource_list *rl = &devi->resources; 98753873Simp resource_list_delete(rl, type, rid); 98853873Simp} 98953873Simp 99059193Simpstatic int 99159193Simppccard_set_res_flags(device_t dev, device_t child, int type, int rid, 992140692Simp uint32_t flags) 99359193Simp{ 99474632Simp return (CARD_SET_RES_FLAGS(device_get_parent(dev), child, type, 99574632Simp rid, flags)); 99659193Simp} 99759193Simp 99859193Simpstatic int 99959193Simppccard_set_memory_offset(device_t dev, device_t child, int rid, 1000140692Simp uint32_t offset, uint32_t *deltap) 100170715Sjon 100259193Simp{ 100374632Simp return (CARD_SET_MEMORY_OFFSET(device_get_parent(dev), child, rid, 100474632Simp offset, deltap)); 100559193Simp} 100659193Simp 1007104641Simpstatic void 1008104641Simppccard_probe_nomatch(device_t bus, device_t child) 1009104641Simp{ 1010104641Simp struct pccard_ivar *devi = PCCARD_IVAR(child); 1011104641Simp struct pccard_function *func = devi->fcn; 1012104641Simp struct pccard_softc *sc = PCCARD_SOFTC(bus); 1013104641Simp 1014104641Simp device_printf(bus, "<unknown card>"); 1015104641Simp printf(" (manufacturer=0x%04x, product=0x%04x) at function %d\n", 1016104641Simp sc->card.manufacturer, sc->card.product, func->number); 1017104641Simp device_printf(bus, " CIS info: %s, %s, %s\n", sc->card.cis1_info[0], 1018104641Simp sc->card.cis1_info[1], sc->card.cis1_info[2]); 1019104641Simp return; 1020104641Simp} 1021104641Simp 102266058Simpstatic int 1023104641Simppccard_child_location_str(device_t bus, device_t child, char *buf, 1024104641Simp size_t buflen) 1025104641Simp{ 1026104641Simp struct pccard_ivar *devi = PCCARD_IVAR(child); 1027104641Simp struct pccard_function *func = devi->fcn; 1028104641Simp 1029104641Simp snprintf(buf, buflen, "function=%d", func->number); 1030104641Simp return (0); 1031104641Simp} 1032104641Simp 1033104641Simpstatic int 1034104641Simppccard_child_pnpinfo_str(device_t bus, device_t child, char *buf, 1035104641Simp size_t buflen) 1036104641Simp{ 1037104641Simp struct pccard_ivar *devi = PCCARD_IVAR(child); 1038104641Simp struct pccard_function *func = devi->fcn; 1039104641Simp struct pccard_softc *sc = PCCARD_SOFTC(bus); 1040104641Simp 1041141959Simp /* XXX need to make sure that we've quoted the " in strings! */ 1042104641Simp snprintf(buf, buflen, "manufacturer=0x%04x product=0x%04x " 1043104641Simp "cisvendor=\"%s\" cisproduct=\"%s\" function_type=%d", 1044104641Simp sc->card.manufacturer, sc->card.product, sc->card.cis1_info[0], 1045104641Simp sc->card.cis1_info[1], func->function); 1046104641Simp return (0); 1047104641Simp} 1048104641Simp 1049104641Simpstatic int 105066058Simppccard_read_ivar(device_t bus, device_t child, int which, u_char *result) 105166058Simp{ 105266847Simp struct pccard_ivar *devi = PCCARD_IVAR(child); 105366779Simp struct pccard_function *func = devi->fcn; 105466779Simp struct pccard_softc *sc = PCCARD_SOFTC(bus); 105566779Simp 105666779Simp switch (which) { 105766779Simp default: 105866779Simp case PCCARD_IVAR_ETHADDR: 105982781Sshiba bcopy(func->pf_funce_lan_nid, result, ETHER_ADDR_LEN); 106066779Simp break; 106166779Simp case PCCARD_IVAR_VENDOR: 1062140692Simp *(uint32_t *) result = sc->card.manufacturer; 106366779Simp break; 106466779Simp case PCCARD_IVAR_PRODUCT: 1065140692Simp *(uint32_t *) result = sc->card.product; 106666779Simp break; 106790964Sshiba case PCCARD_IVAR_PRODEXT: 1068140692Simp *(uint16_t *) result = sc->card.prodext; 106990964Sshiba break; 107075761Simp case PCCARD_IVAR_FUNCTION: 1071140692Simp *(uint32_t *) result = func->function; 107275761Simp break; 107366779Simp case PCCARD_IVAR_FUNCTION_NUMBER: 107466847Simp if (!func) { 107566847Simp device_printf(bus, "No function number, bug!\n"); 107666847Simp return (ENOENT); 107766847Simp } 1078140692Simp *(uint32_t *) result = func->number; 107966779Simp break; 108066779Simp case PCCARD_IVAR_VENDOR_STR: 108166779Simp *(char **) result = sc->card.cis1_info[0]; 108266779Simp break; 108366779Simp case PCCARD_IVAR_PRODUCT_STR: 108466779Simp *(char **) result = sc->card.cis1_info[1]; 108566779Simp break; 108666779Simp case PCCARD_IVAR_CIS3_STR: 108766779Simp *(char **) result = sc->card.cis1_info[2]; 108866779Simp break; 108967167Simp case PCCARD_IVAR_CIS4_STR: 1090104610Simp *(char **) result = sc->card.cis1_info[3]; 109167167Simp break; 109266779Simp } 109366779Simp return (0); 109466058Simp} 109566058Simp 109666779Simpstatic void 109766779Simppccard_driver_added(device_t dev, driver_t *driver) 109866779Simp{ 109982378Sjon struct pccard_softc *sc = PCCARD_SOFTC(dev); 110082378Sjon struct pccard_function *pf; 110182378Sjon device_t child; 110282378Sjon 110382378Sjon STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) { 110482378Sjon if (STAILQ_EMPTY(&pf->cfe_head)) 110582378Sjon continue; 110682378Sjon child = pf->dev; 110782378Sjon if (device_get_state(child) != DS_NOTPRESENT) 110882378Sjon continue; 110982378Sjon if (pccard_function_enable(pf) == 0 && 111082378Sjon device_probe_and_attach(child) == 0) { 111182378Sjon DEVPRINTF((sc->dev, "function %d CCR at %d " 111282378Sjon "offset %x: %x %x %x %x, %x %x %x %x, %x\n", 111382378Sjon pf->number, pf->pf_ccr_window, pf->pf_ccr_offset, 111482378Sjon pccard_ccr_read(pf, 0x00), 111582378Sjon pccard_ccr_read(pf, 0x02), pccard_ccr_read(pf, 0x04), 111682378Sjon pccard_ccr_read(pf, 0x06), pccard_ccr_read(pf, 0x0A), 111782378Sjon pccard_ccr_read(pf, 0x0C), pccard_ccr_read(pf, 0x0E), 111882378Sjon pccard_ccr_read(pf, 0x10), pccard_ccr_read(pf, 0x12))); 111982378Sjon } else { 112086907Simp if (pf->cfe != NULL) 112186907Simp pccard_function_disable(pf); 112282378Sjon } 112382378Sjon } 112482378Sjon return; 112566779Simp} 112666058Simp 112767242Simpstatic struct resource * 112867242Simppccard_alloc_resource(device_t dev, device_t child, int type, int *rid, 112967242Simp u_long start, u_long end, u_long count, u_int flags) 113067242Simp{ 113182378Sjon struct pccard_ivar *dinfo; 113282378Sjon struct resource_list_entry *rle = 0; 113382378Sjon int passthrough = (device_get_parent(child) != dev); 1134121905Simp int isdefault = (start == 0 && end == ~0UL && count == 1); 1135104641Simp struct resource *r = NULL; 113667242Simp 1137121905Simp /* XXX I'm no longer sure this is right */ 113882378Sjon if (passthrough) { 113982378Sjon return (BUS_ALLOC_RESOURCE(device_get_parent(dev), child, 114082378Sjon type, rid, start, end, count, flags)); 114182378Sjon } 114270715Sjon 114382378Sjon dinfo = device_get_ivars(child); 114482378Sjon rle = resource_list_find(&dinfo->resources, type, *rid); 114570715Sjon 1146121905Simp if (rle == NULL && isdefault) 1147121905Simp return (NULL); /* no resource of that type/rid */ 1148121905Simp if (rle == NULL || rle->res == NULL) { 1149121905Simp /* Do we want this device to own it? */ 1150121905Simp /* XXX I think so, but that might be lame XXX */ 1151121905Simp r = bus_alloc_resource(dev, type, rid, start, end, 1152121905Simp count, flags /* XXX aligment? */); 1153121905Simp if (r == NULL) 1154121905Simp goto bad; 1155121905Simp resource_list_add(&dinfo->resources, type, *rid, 1156121905Simp rman_get_start(r), rman_get_end(r), count); 1157121905Simp rle = resource_list_find(&dinfo->resources, type, *rid); 1158121905Simp if (!rle) 1159121905Simp goto bad; 1160121905Simp rle->res = r; 116167269Simp } 1162121905Simp /* 1163121905Simp * XXX the following looks wrong, in theory, but likely it is 1164121905Simp * XXX needed because of how the CIS code allocates resources 1165121905Simp * XXX for this device. 1166121905Simp */ 1167113242Simp if (rman_get_device(rle->res) != dev) 1168104641Simp return (NULL); 1169104641Simp bus_release_resource(dev, type, *rid, rle->res); 1170104641Simp rle->res = NULL; 1171104641Simp switch(type) { 1172104641Simp case SYS_RES_IOPORT: 1173104641Simp case SYS_RES_MEMORY: 1174104641Simp if (!(flags & RF_ALIGNMENT_MASK)) 1175104641Simp flags |= rman_make_alignment_flags(rle->count); 1176104641Simp break; 1177104641Simp case SYS_RES_IRQ: 1178104641Simp flags |= RF_SHAREABLE; 1179104641Simp break; 1180104641Simp } 1181104641Simp rle->res = resource_list_alloc(&dinfo->resources, dev, child, 1182104641Simp type, rid, rle->start, rle->end, rle->count, flags); 1183104641Simp return (rle->res); 1184104641Simpbad:; 1185104641Simp device_printf(dev, "WARNING: Resource not reserved by pccard\n"); 1186104641Simp return (NULL); 118767242Simp} 118867242Simp 118967242Simpstatic int 119067242Simppccard_release_resource(device_t dev, device_t child, int type, int rid, 119167242Simp struct resource *r) 119267242Simp{ 119382378Sjon struct pccard_ivar *dinfo; 119482378Sjon int passthrough = (device_get_parent(child) != dev); 119582378Sjon struct resource_list_entry *rle = 0; 119682378Sjon int ret; 119782378Sjon int flags; 119870715Sjon 119982378Sjon if (passthrough) 120082378Sjon return BUS_RELEASE_RESOURCE(device_get_parent(dev), child, 120182378Sjon type, rid, r); 120270715Sjon 120382378Sjon dinfo = device_get_ivars(child); 120470715Sjon 120582378Sjon rle = resource_list_find(&dinfo->resources, type, rid); 120670715Sjon 120782378Sjon if (!rle) { 120882378Sjon device_printf(dev, "Allocated resource not found, " 120982378Sjon "%d %x %lx %lx\n", 121082378Sjon type, rid, rman_get_start(r), rman_get_size(r)); 121182378Sjon return ENOENT; 121270715Sjon } 121382378Sjon if (!rle->res) { 121482378Sjon device_printf(dev, "Allocated resource not recorded\n"); 121582378Sjon return ENOENT; 121670715Sjon } 121770715Sjon 121882378Sjon ret = BUS_RELEASE_RESOURCE(device_get_parent(dev), child, 121982378Sjon type, rid, r); 122082378Sjon switch(type) { 122182378Sjon case SYS_RES_IOPORT: 122282378Sjon case SYS_RES_MEMORY: 122382378Sjon flags = rman_make_alignment_flags(rle->count); 122482378Sjon break; 122582378Sjon case SYS_RES_IRQ: 122682378Sjon flags = RF_SHAREABLE; 122782378Sjon break; 122882378Sjon default: 122982378Sjon flags = 0; 123070715Sjon } 123182378Sjon rle->res = bus_alloc_resource(dev, type, &rid, 123282378Sjon rle->start, rle->end, rle->count, flags); 123382378Sjon if (rle->res == NULL) 123482378Sjon device_printf(dev, "release_resource: " 123582378Sjon "unable to reaquire resource\n"); 123682378Sjon return ret; 123767242Simp} 123867242Simp 123967333Simpstatic void 124067333Simppccard_child_detached(device_t parent, device_t dev) 124167333Simp{ 124267333Simp struct pccard_ivar *ivar = PCCARD_IVAR(dev); 124382378Sjon struct pccard_function *pf = ivar->fcn; 124467333Simp 124582378Sjon pccard_function_disable(pf); 124667333Simp} 124767333Simp 124870715Sjonstatic void 124970762Simppccard_intr(void *arg) 125070762Simp{ 125182378Sjon struct pccard_function *pf = (struct pccard_function*) arg; 125282378Sjon int reg; 1253102923Simp int doisr = 1; 125482378Sjon 125582383Simp /* 1256102923Simp * MFC cards know if they interrupted, so we have to ack the 1257102923Simp * interrupt and call the ISR. Non-MFC cards don't have these 1258102923Simp * bits, so they always get called. Many non-MFC cards have 1259102923Simp * this bit set always upon read, but some do not. 1260102923Simp * 1261102923Simp * We always ack the interrupt, even if there's no ISR 1262102923Simp * for the card. This is done on the theory that acking 1263102923Simp * the interrupt will pacify the card enough to keep an 1264102923Simp * interrupt storm from happening. Of course this won't 1265102923Simp * help in the non-MFC case. 1266116311Simp * 1267116311Simp * This has no impact for MPSAFEness of the client drivers. 1268116311Simp * We register this with whatever flags the intr_handler 1269116311Simp * was registered with. All these functions are MPSAFE. 127082383Simp */ 1271102923Simp if (pccard_mfc(pf->sc)) { 1272102923Simp reg = pccard_ccr_read(pf, PCCARD_CCR_STATUS); 1273102923Simp if (reg & PCCARD_CCR_STATUS_INTR) 1274102923Simp pccard_ccr_write(pf, PCCARD_CCR_STATUS, 1275102923Simp reg & ~PCCARD_CCR_STATUS_INTR); 1276102923Simp else 1277102923Simp doisr = 0; 1278102923Simp } 1279102923Simp if (pf->intr_handler != NULL && doisr) 128082378Sjon pf->intr_handler(pf->intr_handler_arg); 128170715Sjon} 128270715Sjon 128370715Sjonstatic int 128470762Simppccard_setup_intr(device_t dev, device_t child, struct resource *irq, 128570762Simp int flags, driver_intr_t *intr, void *arg, void **cookiep) 128670715Sjon{ 1287102713Simp struct pccard_softc *sc = PCCARD_SOFTC(dev); 128870715Sjon struct pccard_ivar *ivar = PCCARD_IVAR(child); 128970715Sjon struct pccard_function *func = ivar->fcn; 129090445Simp int err; 129170715Sjon 129270715Sjon if (func->intr_handler != NULL) 1293101762Simp panic("Only one interrupt handler per function allowed"); 129490445Simp err = bus_generic_setup_intr(dev, child, irq, flags, pccard_intr, 129590445Simp func, cookiep); 129690445Simp if (err != 0) 129790445Simp return (err); 129870715Sjon func->intr_handler = intr; 129970715Sjon func->intr_handler_arg = arg; 130082378Sjon func->intr_handler_cookie = *cookiep; 1301102713Simp if (pccard_mfc(sc)) { 1302102713Simp pccard_ccr_write(func, PCCARD_CCR_OPTION, 1303102713Simp pccard_ccr_read(func, PCCARD_CCR_OPTION) | 1304102713Simp PCCARD_CCR_OPTION_IREQ_ENABLE); 1305102713Simp } 130674632Simp return (0); 130770715Sjon} 130870715Sjon 130970715Sjonstatic int 131070762Simppccard_teardown_intr(device_t dev, device_t child, struct resource *r, 131170762Simp void *cookie) 131270715Sjon{ 1313102713Simp struct pccard_softc *sc = PCCARD_SOFTC(dev); 131470715Sjon struct pccard_ivar *ivar = PCCARD_IVAR(child); 131570715Sjon struct pccard_function *func = ivar->fcn; 131682378Sjon int ret; 131770715Sjon 1318102713Simp if (pccard_mfc(sc)) { 1319102713Simp pccard_ccr_write(func, PCCARD_CCR_OPTION, 1320102713Simp pccard_ccr_read(func, PCCARD_CCR_OPTION) & 1321102713Simp ~PCCARD_CCR_OPTION_IREQ_ENABLE); 1322102713Simp } 132390445Simp ret = bus_generic_teardown_intr(dev, child, r, cookie); 132482378Sjon if (ret == 0) { 132582378Sjon func->intr_handler = NULL; 132682378Sjon func->intr_handler_arg = NULL; 132782378Sjon func->intr_handler_cookie = NULL; 132882378Sjon } 132970715Sjon 133082378Sjon return (ret); 133170715Sjon} 133270715Sjon 1333121905Simpstatic int 1334121905Simppccard_activate_resource(device_t brdev, device_t child, int type, int rid, 1335121905Simp struct resource *r) 1336121905Simp{ 1337121905Simp struct pccard_ivar *ivar = PCCARD_IVAR(child); 1338121905Simp struct pccard_function *pf = ivar->fcn; 1339121905Simp 1340121905Simp switch(type) { 1341121905Simp case SYS_RES_IOPORT: 1342121905Simp /* 1343121905Simp * We need to adjust IOBASE[01] and IOSIZE if we're an MFC 1344121905Simp * card. 1345121905Simp */ 1346121905Simp if (pccard_mfc(pf->sc)) 1347121905Simp pccard_mfc_adjust_iobase(pf, rman_get_start(r), 0, 1348121905Simp rman_get_size(r)); 1349121905Simp break; 1350121905Simp default: 1351121905Simp break; 1352121905Simp } 1353121905Simp return (bus_generic_activate_resource(brdev, child, type, rid, r)); 1354121905Simp} 1355121905Simp 1356121905Simpstatic int 1357121905Simppccard_deactivate_resource(device_t brdev, device_t child, int type, 1358121905Simp int rid, struct resource *r) 1359121905Simp{ 1360121905Simp /* XXX undo pccard_activate_resource? XXX */ 1361121905Simp return (bus_generic_deactivate_resource(brdev, child, type, rid, r)); 1362121905Simp} 1363121905Simp 136452506Simpstatic device_method_t pccard_methods[] = { 136552506Simp /* Device interface */ 136652506Simp DEVMETHOD(device_probe, pccard_probe), 136759193Simp DEVMETHOD(device_attach, pccard_attach), 136882378Sjon DEVMETHOD(device_detach, pccard_detach), 136952506Simp DEVMETHOD(device_shutdown, bus_generic_shutdown), 137087975Simp DEVMETHOD(device_suspend, pccard_suspend), 137187975Simp DEVMETHOD(device_resume, pccard_resume), 137252506Simp 137352506Simp /* Bus interface */ 137452506Simp DEVMETHOD(bus_print_child, pccard_print_child), 137566779Simp DEVMETHOD(bus_driver_added, pccard_driver_added), 137667333Simp DEVMETHOD(bus_child_detached, pccard_child_detached), 137767242Simp DEVMETHOD(bus_alloc_resource, pccard_alloc_resource), 137867242Simp DEVMETHOD(bus_release_resource, pccard_release_resource), 1379121905Simp DEVMETHOD(bus_activate_resource, pccard_activate_resource), 1380121905Simp DEVMETHOD(bus_deactivate_resource, pccard_deactivate_resource), 138170715Sjon DEVMETHOD(bus_setup_intr, pccard_setup_intr), 138270715Sjon DEVMETHOD(bus_teardown_intr, pccard_teardown_intr), 138352506Simp DEVMETHOD(bus_set_resource, pccard_set_resource), 138452506Simp DEVMETHOD(bus_get_resource, pccard_get_resource), 138552506Simp DEVMETHOD(bus_delete_resource, pccard_delete_resource), 1386104641Simp DEVMETHOD(bus_probe_nomatch, pccard_probe_nomatch), 138766058Simp DEVMETHOD(bus_read_ivar, pccard_read_ivar), 1388104641Simp DEVMETHOD(bus_child_pnpinfo_str, pccard_child_pnpinfo_str), 1389104641Simp DEVMETHOD(bus_child_location_str, pccard_child_location_str), 139052506Simp 139159193Simp /* Card Interface */ 139259193Simp DEVMETHOD(card_set_res_flags, pccard_set_res_flags), 139359193Simp DEVMETHOD(card_set_memory_offset, pccard_set_memory_offset), 139459193Simp DEVMETHOD(card_attach_card, pccard_attach_card), 139559193Simp DEVMETHOD(card_detach_card, pccard_detach_card), 139674636Simp DEVMETHOD(card_compat_do_probe, pccard_compat_do_probe), 139774636Simp DEVMETHOD(card_compat_do_attach, pccard_compat_do_attach), 139897613Stakawata DEVMETHOD(card_do_product_lookup, pccard_do_product_lookup), 139959193Simp 140052506Simp { 0, 0 } 140152506Simp}; 140252506Simp 140352506Simpstatic driver_t pccard_driver = { 140452506Simp "pccard", 140552506Simp pccard_methods, 140664850Simp sizeof(struct pccard_softc) 140752506Simp}; 140852506Simp 140952506Simpdevclass_t pccard_devclass; 141052506Simp 1411101905Simp/* Maybe we need to have a slot device? */ 141253873SimpDRIVER_MODULE(pccard, pcic, pccard_driver, pccard_devclass, 0, 0); 1413101905SimpDRIVER_MODULE(pccard, cbb, pccard_driver, pccard_devclass, 0, 0); 141464927SimpMODULE_VERSION(pccard, 1); 1415