pccard.c revision 150391
1321936Shselasky/* $NetBSD: pcmcia.c,v 1.23 2000/07/28 19:17:02 drochner Exp $ */ 2321936Shselasky 3321936Shselasky/*- 4321936Shselasky * Copyright (c) 1997 Marc Horowitz. All rights reserved. 5321936Shselasky * 6321936Shselasky * Redistribution and use in source and binary forms, with or without 7321936Shselasky * modification, are permitted provided that the following conditions 8321936Shselasky * are met: 9321936Shselasky * 1. Redistributions of source code must retain the above copyright 10321936Shselasky * notice, this list of conditions and the following disclaimer. 11321936Shselasky * 2. Redistributions in binary form must reproduce the above copyright 12321936Shselasky * notice, this list of conditions and the following disclaimer in the 13321936Shselasky * documentation and/or other materials provided with the distribution. 14321936Shselasky * 3. All advertising materials mentioning features or use of this software 15321936Shselasky * must display the following acknowledgement: 16321936Shselasky * This product includes software developed by Marc Horowitz. 17321936Shselasky * 4. The name of the author may not be used to endorse or promote products 18321936Shselasky * derived from this software without specific prior written permission. 19321936Shselasky * 20321936Shselasky * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21321936Shselasky * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22321936Shselasky * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23321936Shselasky * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24321936Shselasky * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25321936Shselasky * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26321936Shselasky * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27321936Shselasky * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28321936Shselasky * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29321936Shselasky * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30321936Shselasky */ 31321936Shselasky 32321936Shselasky#include <sys/cdefs.h> 33321936Shselasky__FBSDID("$FreeBSD: head/sys/dev/pccard/pccard.c 150391 2005-09-20 19:34:10Z imp $"); 34321936Shselasky 35321936Shselasky#include <sys/param.h> 36321936Shselasky#include <sys/systm.h> 37321936Shselasky#include <sys/malloc.h> 38321936Shselasky#include <sys/module.h> 39321936Shselasky#include <sys/kernel.h> 40321936Shselasky#include <sys/queue.h> 41321936Shselasky#include <sys/sysctl.h> 42321936Shselasky#include <sys/types.h> 43321936Shselasky 44321936Shselasky#include <sys/bus.h> 45321936Shselasky#include <machine/bus.h> 46321936Shselasky#include <sys/rman.h> 47321936Shselasky#include <machine/resource.h> 48321936Shselasky 49321936Shselasky#include <net/ethernet.h> 50321936Shselasky 51321936Shselasky#include <dev/pccard/pccardreg.h> 52321936Shselasky#include <dev/pccard/pccardvar.h> 53321936Shselasky#include <dev/pccard/pccardvarp.h> 54321936Shselasky#include <dev/pccard/pccard_cis.h> 55321936Shselasky 56321936Shselasky#include "power_if.h" 57321936Shselasky#include "card_if.h" 58321936Shselasky 59321936Shselasky#define PCCARDDEBUG 60321936Shselasky 61321936Shselasky/* sysctl vars */ 62321936ShselaskySYSCTL_NODE(_hw, OID_AUTO, pccard, CTLFLAG_RD, 0, "PCCARD parameters"); 63321936Shselasky 64321936Shselaskyint pccard_debug = 0; 65321936ShselaskyTUNABLE_INT("hw.pccard.debug", &pccard_debug); 66321936ShselaskySYSCTL_INT(_hw_pccard, OID_AUTO, debug, CTLFLAG_RW, 67321936Shselasky &pccard_debug, 0, 68321936Shselasky "pccard debug"); 69321936Shselasky 70321936Shselaskyint pccard_cis_debug = 0; 71321936ShselaskyTUNABLE_INT("hw.pccard.cis_debug", &pccard_cis_debug); 72321936ShselaskySYSCTL_INT(_hw_pccard, OID_AUTO, cis_debug, CTLFLAG_RW, 73321936Shselasky &pccard_cis_debug, 0, "pccard CIS debug"); 74321936Shselasky 75321936Shselasky#ifdef PCCARDDEBUG 76321936Shselasky#define DPRINTF(arg) if (pccard_debug) printf arg 77321936Shselasky#define DEVPRINTF(arg) if (pccard_debug) device_printf arg 78321936Shselasky#define PRVERBOSE(arg) printf arg 79321936Shselasky#define DEVPRVERBOSE(arg) device_printf arg 80321936Shselasky#else 81321936Shselasky#define DPRINTF(arg) 82321936Shselasky#define DEVPRINTF(arg) 83321936Shselasky#define PRVERBOSE(arg) if (bootverbose) printf arg 84321936Shselasky#define DEVPRVERBOSE(arg) if (bootverbose) device_printf arg 85321936Shselasky#endif 86321936Shselasky 87321936Shselaskystatic int pccard_ccr_read(struct pccard_function *pf, int ccr); 88321936Shselaskystatic void pccard_ccr_write(struct pccard_function *pf, int ccr, int val); 89321936Shselaskystatic int pccard_attach_card(device_t dev); 90321936Shselaskystatic int pccard_detach_card(device_t dev); 91321936Shselaskystatic void pccard_function_init(struct pccard_function *pf); 92321936Shselaskystatic void pccard_function_free(struct pccard_function *pf); 93321936Shselaskystatic int pccard_function_enable(struct pccard_function *pf); 94321936Shselaskystatic void pccard_function_disable(struct pccard_function *pf); 95321936Shselaskystatic int pccard_compat_do_probe(device_t bus, device_t dev); 96321936Shselaskystatic int pccard_compat_do_attach(device_t bus, device_t dev); 97321936Shselaskystatic int pccard_probe(device_t dev); 98321936Shselaskystatic int pccard_attach(device_t dev); 99321936Shselaskystatic int pccard_detach(device_t dev); 100321936Shselaskystatic void pccard_print_resources(struct resource_list *rl, 101321936Shselasky const char *name, int type, int count, const char *format); 102321936Shselaskystatic int pccard_print_child(device_t dev, device_t child); 103321936Shselaskystatic int pccard_set_resource(device_t dev, device_t child, int type, 104321936Shselasky int rid, u_long start, u_long count); 105321936Shselaskystatic int pccard_get_resource(device_t dev, device_t child, int type, 106321936Shselasky int rid, u_long *startp, u_long *countp); 107321936Shselaskystatic void pccard_delete_resource(device_t dev, device_t child, int type, 108321936Shselasky int rid); 109321936Shselaskystatic int pccard_set_res_flags(device_t dev, device_t child, int type, 110321936Shselasky int rid, uint32_t flags); 111321936Shselaskystatic int pccard_set_memory_offset(device_t dev, device_t child, int rid, 112321936Shselasky uint32_t offset, uint32_t *deltap); 113321936Shselaskystatic void pccard_probe_nomatch(device_t cbdev, device_t child); 114321936Shselaskystatic int pccard_read_ivar(device_t bus, device_t child, int which, 115321936Shselasky u_char *result); 116321936Shselaskystatic void pccard_driver_added(device_t dev, driver_t *driver); 117321936Shselaskystatic struct resource *pccard_alloc_resource(device_t dev, 118321936Shselasky device_t child, int type, int *rid, u_long start, 119321936Shselasky u_long end, u_long count, u_int flags); 120321936Shselaskystatic int pccard_release_resource(device_t dev, device_t child, int type, 121321936Shselasky int rid, struct resource *r); 122321936Shselaskystatic void pccard_child_detached(device_t parent, device_t dev); 123321936Shselaskystatic void pccard_intr(void *arg); 124321936Shselaskystatic int pccard_setup_intr(device_t dev, device_t child, 125321936Shselasky struct resource *irq, int flags, driver_intr_t *intr, 126321936Shselasky void *arg, void **cookiep); 127321936Shselaskystatic int pccard_teardown_intr(device_t dev, device_t child, 128321936Shselasky struct resource *r, void *cookie); 129321936Shselasky 130321936Shselaskystatic const struct pccard_product * 131321936Shselaskypccard_do_product_lookup(device_t bus, device_t dev, 132321936Shselasky const struct pccard_product *tab, size_t ent_size, 133321936Shselasky pccard_product_match_fn matchfn); 134321936Shselasky 135321936Shselasky 136321936Shselaskystatic int 137321936Shselaskypccard_ccr_read(struct pccard_function *pf, int ccr) 138321936Shselasky{ 139321936Shselasky return (bus_space_read_1(pf->pf_ccrt, pf->pf_ccrh, 140321936Shselasky pf->pf_ccr_offset + ccr)); 141321936Shselasky} 142321936Shselasky 143321936Shselaskystatic void 144321936Shselaskypccard_ccr_write(struct pccard_function *pf, int ccr, int val) 145321936Shselasky{ 146321936Shselasky if ((pf->ccr_mask) & (1 << (ccr / 2))) { 147321936Shselasky bus_space_write_1(pf->pf_ccrt, pf->pf_ccrh, 148321936Shselasky pf->pf_ccr_offset + ccr, val); 149321936Shselasky } 150321936Shselasky} 151321936Shselasky 152321936Shselaskystatic int 153321936Shselaskypccard_set_default_descr(device_t dev) 154321936Shselasky{ 155321936Shselasky const char *vendorstr, *prodstr; 156321936Shselasky uint32_t vendor, prod; 157321936Shselasky char *str; 158321936Shselasky 159321936Shselasky if (pccard_get_vendor_str(dev, &vendorstr)) 160321936Shselasky return (0); 161321936Shselasky if (pccard_get_product_str(dev, &prodstr)) 162321936Shselasky return (0); 163321936Shselasky if (vendorstr != NULL && prodstr != NULL) { 164321936Shselasky str = malloc(strlen(vendorstr) + strlen(prodstr) + 2, M_DEVBUF, 165321936Shselasky M_WAITOK); 166321936Shselasky sprintf(str, "%s %s", vendorstr, prodstr); 167321936Shselasky device_set_desc_copy(dev, str); 168321936Shselasky free(str, M_DEVBUF); 169321936Shselasky } else { 170321936Shselasky if (pccard_get_vendor(dev, &vendor)) 171321936Shselasky return (0); 172321936Shselasky if (pccard_get_product(dev, &prod)) 173321936Shselasky return (0); 174321936Shselasky str = malloc(100, M_DEVBUF, M_WAITOK); 175321936Shselasky snprintf(str, 100, "vendor=0x%x product=0x%x", vendor, prod); 176321936Shselasky device_set_desc_copy(dev, str); 177321936Shselasky free(str, M_DEVBUF); 178321936Shselasky } 179321936Shselasky return (0); 180321936Shselasky} 181321936Shselasky 182321936Shselaskystatic int 183321936Shselaskypccard_attach_card(device_t dev) 184321936Shselasky{ 185321936Shselasky struct pccard_softc *sc = PCCARD_SOFTC(dev); 186321936Shselasky struct pccard_function *pf; 187321936Shselasky struct pccard_ivar *ivar; 188321936Shselasky device_t child; 189321936Shselasky int i; 190321936Shselasky 191321936Shselasky /* 192321936Shselasky * this is here so that when socket_enable calls gettype, trt happens 193321936Shselasky */ 194321936Shselasky STAILQ_INIT(&sc->card.pf_head); 195321936Shselasky 196321936Shselasky DEVPRINTF((dev, "chip_socket_enable\n")); 197321936Shselasky POWER_ENABLE_SOCKET(device_get_parent(dev), dev); 198321936Shselasky 199321936Shselasky DEVPRINTF((dev, "read_cis\n")); 200321936Shselasky pccard_read_cis(sc); 201321936Shselasky 202321936Shselasky DEVPRINTF((dev, "check_cis_quirks\n")); 203321936Shselasky pccard_check_cis_quirks(dev); 204321936Shselasky 205321936Shselasky /* 206321936Shselasky * bail now if the card has no functions, or if there was an error in 207321936Shselasky * the cis. 208321936Shselasky */ 209321936Shselasky 210321936Shselasky if (sc->card.error) { 211321936Shselasky device_printf(dev, "CARD ERROR!\n"); 212321936Shselasky return (1); 213321936Shselasky } 214321936Shselasky if (STAILQ_EMPTY(&sc->card.pf_head)) { 215321936Shselasky device_printf(dev, "Card has no functions!\n"); 216321936Shselasky return (1); 217321936Shselasky } 218321936Shselasky 219321936Shselasky if (bootverbose || pccard_debug) 220321936Shselasky pccard_print_cis(dev); 221321936Shselasky 222321936Shselasky DEVPRINTF((dev, "functions scanning\n")); 223321936Shselasky i = -1; 224321936Shselasky STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) { 225321936Shselasky i++; 226321936Shselasky if (STAILQ_EMPTY(&pf->cfe_head)) { 227321936Shselasky device_printf(dev, 228321936Shselasky "Function %d has no config entries.!\n", i); 229321936Shselasky continue; 230321936Shselasky } 231321936Shselasky pf->sc = sc; 232321936Shselasky pf->cfe = NULL; 233321936Shselasky pf->dev = NULL; 234321936Shselasky } 235321936Shselasky DEVPRINTF((dev, "Card has %d functions. pccard_mfc is %d\n", i + 1, 236321936Shselasky pccard_mfc(sc))); 237321936Shselasky 238321936Shselasky STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) { 239321936Shselasky if (STAILQ_EMPTY(&pf->cfe_head)) 240321936Shselasky continue; 241321936Shselasky /* 242321936Shselasky * In NetBSD, the drivers are responsible for activating 243321936Shselasky * each function of a card. I think that in FreeBSD we 244321936Shselasky * want to activate them enough for the usual bus_*_resource 245321936Shselasky * routines will do the right thing. This many mean a 246321936Shselasky * departure from the current NetBSD model. 247321936Shselasky * 248321936Shselasky * This seems to work well in practice for most cards. 249321936Shselasky * However, there are two cases that are problematic. 250321936Shselasky * If a driver wishes to pick and chose which config 251321936Shselasky * entry to use, then this method falls down. These 252321936Shselasky * are usually older cards. In addition, there are 253321936Shselasky * some cards that have multiple hardware units on the 254321936Shselasky * cards, but presents only one CIS chain. These cards 255321936Shselasky * are combination cards, but only one of these units 256321936Shselasky * can be on at a time. 257321936Shselasky */ 258321936Shselasky ivar = malloc(sizeof(struct pccard_ivar), M_DEVBUF, 259321936Shselasky M_WAITOK | M_ZERO); 260321936Shselasky resource_list_init(&ivar->resources); 261321936Shselasky child = device_add_child(dev, NULL, -1); 262321936Shselasky device_set_ivars(child, ivar); 263321936Shselasky ivar->pf = pf; 264321936Shselasky pf->dev = child; 265321936Shselasky /* 266321936Shselasky * XXX We might want to move the next three lines into 267321936Shselasky * XXX the pccard interface layer. For the moment, this 268321936Shselasky * XXX is OK, but some drivers want to pick the config 269321936Shselasky * XXX entry to use as well as some address tweaks (mostly 270321936Shselasky * XXX due to bugs in decode logic that makes some 271321936Shselasky * XXX addresses illegal or broken). 272321936Shselasky */ 273321936Shselasky pccard_function_init(pf); 274321936Shselasky if (sc->sc_enabled_count == 0) 275321936Shselasky POWER_ENABLE_SOCKET(device_get_parent(dev), dev); 276321936Shselasky if (pccard_function_enable(pf) == 0 && 277321936Shselasky pccard_set_default_descr(child) == 0 && 278321936Shselasky device_probe_and_attach(child) == 0) { 279321936Shselasky DEVPRINTF((sc->dev, "function %d CCR at %d " 280321936Shselasky "offset %x mask %x: " 281321936Shselasky "%x %x %x %x, %x %x %x %x, %x\n", 282321936Shselasky pf->number, pf->pf_ccr_window, pf->pf_ccr_offset, 283321936Shselasky pf->ccr_mask, pccard_ccr_read(pf, 0x00), 284321936Shselasky pccard_ccr_read(pf, 0x02), pccard_ccr_read(pf, 0x04), 285321936Shselasky pccard_ccr_read(pf, 0x06), pccard_ccr_read(pf, 0x0A), 286321936Shselasky pccard_ccr_read(pf, 0x0C), pccard_ccr_read(pf, 0x0E), 287321936Shselasky pccard_ccr_read(pf, 0x10), pccard_ccr_read(pf, 0x12))); 288321936Shselasky } else { 289321936Shselasky if (pf->cfe != NULL) 290321936Shselasky pccard_function_disable(pf); 291321936Shselasky } 292321936Shselasky } 293321936Shselasky return (0); 294321936Shselasky} 295321936Shselasky 296321936Shselaskystatic int 297321936Shselaskypccard_detach_card(device_t dev) 298321936Shselasky{ 299321936Shselasky struct pccard_softc *sc = PCCARD_SOFTC(dev); 300321936Shselasky struct pccard_function *pf; 301321936Shselasky struct pccard_config_entry *cfe; 302321936Shselasky int state; 303321936Shselasky 304321936Shselasky /* 305321936Shselasky * We are running on either the PCCARD socket's event thread 306321936Shselasky * or in user context detaching a device by user request. 307321936Shselasky */ 308321936Shselasky STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) { 309321936Shselasky if (pf->dev == NULL) 310321936Shselasky continue; 311321936Shselasky state = device_get_state(pf->dev); 312321936Shselasky if (state == DS_ATTACHED || state == DS_BUSY) 313321936Shselasky device_detach(pf->dev); 314321936Shselasky if (pf->cfe != NULL) 315321936Shselasky pccard_function_disable(pf); 316321936Shselasky pccard_function_free(pf); 317321936Shselasky device_delete_child(dev, pf->dev); 318321936Shselasky } 319321936Shselasky if (sc->sc_enabled_count == 0) 320321936Shselasky POWER_DISABLE_SOCKET(device_get_parent(dev), dev); 321321936Shselasky 322321936Shselasky while (NULL != (pf = STAILQ_FIRST(&sc->card.pf_head))) { 323321936Shselasky while (NULL != (cfe = STAILQ_FIRST(&pf->cfe_head))) { 324321936Shselasky STAILQ_REMOVE_HEAD(&pf->cfe_head, cfe_list); 325321936Shselasky free(cfe, M_DEVBUF); 326321936Shselasky } 327321936Shselasky STAILQ_REMOVE_HEAD(&sc->card.pf_head, pf_list); 328321936Shselasky free(pf, M_DEVBUF); 329321936Shselasky } 330321936Shselasky return (0); 331321936Shselasky} 332321936Shselasky 333321936Shselaskystatic const struct pccard_product * 334321936Shselaskypccard_do_product_lookup(device_t bus, device_t dev, 335321936Shselasky const struct pccard_product *tab, size_t ent_size, 336321936Shselasky pccard_product_match_fn matchfn) 337321936Shselasky{ 338321936Shselasky const struct pccard_product *ent; 339321936Shselasky int matches; 340321936Shselasky uint32_t vendor; 341321936Shselasky uint32_t prod; 342321936Shselasky const char *vendorstr; 343321936Shselasky const char *prodstr; 344321936Shselasky const char *cis3str; 345321936Shselasky const char *cis4str; 346321936Shselasky 347321936Shselasky#ifdef DIAGNOSTIC 348321936Shselasky if (sizeof *ent > ent_size) 349321936Shselasky panic("pccard_product_lookup: bogus ent_size %jd", 350321936Shselasky (intmax_t) ent_size); 351321936Shselasky#endif 352321936Shselasky if (pccard_get_vendor(dev, &vendor)) 353321936Shselasky return (NULL); 354321936Shselasky if (pccard_get_product(dev, &prod)) 355321936Shselasky return (NULL); 356321936Shselasky if (pccard_get_vendor_str(dev, &vendorstr)) 357321936Shselasky return (NULL); 358321936Shselasky if (pccard_get_product_str(dev, &prodstr)) 359321936Shselasky return (NULL); 360321936Shselasky if (pccard_get_cis3_str(dev, &cis3str)) 361321936Shselasky return (NULL); 362321936Shselasky if (pccard_get_cis4_str(dev, &cis4str)) 363321936Shselasky return (NULL); 364321936Shselasky for (ent = tab; ent->pp_vendor != 0; ent = 365321936Shselasky (const struct pccard_product *) ((const char *) ent + ent_size)) { 366321936Shselasky matches = 1; 367321936Shselasky if (ent->pp_vendor == PCCARD_VENDOR_ANY && 368321936Shselasky ent->pp_product == PCCARD_PRODUCT_ANY && 369321936Shselasky ent->pp_cis[0] == NULL && 370321936Shselasky ent->pp_cis[1] == NULL) { 371321936Shselasky if (ent->pp_name) 372321936Shselasky device_printf(dev, 373321936Shselasky "Total wildcard entry ignored for %s\n", 374321936Shselasky ent->pp_name); 375321936Shselasky continue; 376321936Shselasky } 377321936Shselasky if (matches && ent->pp_vendor != PCCARD_VENDOR_ANY && 378321936Shselasky vendor != ent->pp_vendor) 379321936Shselasky matches = 0; 380321936Shselasky if (matches && ent->pp_product != PCCARD_PRODUCT_ANY && 381321936Shselasky prod != ent->pp_product) 382321936Shselasky matches = 0; 383321936Shselasky if (matches && ent->pp_cis[0] && 384321936Shselasky (vendorstr == NULL || 385321936Shselasky strcmp(ent->pp_cis[0], vendorstr) != 0)) 386321936Shselasky matches = 0; 387321936Shselasky if (matches && ent->pp_cis[1] && 388321936Shselasky (prodstr == NULL || 389321936Shselasky strcmp(ent->pp_cis[1], prodstr) != 0)) 390321936Shselasky matches = 0; 391321936Shselasky if (matches && ent->pp_cis[2] && 392321936Shselasky (cis3str == NULL || 393321936Shselasky strcmp(ent->pp_cis[2], cis3str) != 0)) 394321936Shselasky matches = 0; 395321936Shselasky if (matches && ent->pp_cis[3] && 396321936Shselasky (cis4str == NULL || 397321936Shselasky strcmp(ent->pp_cis[3], cis4str) != 0)) 398321936Shselasky matches = 0; 399321936Shselasky if (matchfn != NULL) 400321936Shselasky matches = (*matchfn)(dev, ent, matches); 401321936Shselasky if (matches) 402321936Shselasky return (ent); 403321936Shselasky } 404321936Shselasky return (NULL); 405321936Shselasky} 406321936Shselasky 407321936Shselasky/* 408321936Shselasky * Initialize a PCCARD function. May be called as long as the function is 409321936Shselasky * disabled. 410321936Shselasky * 411321936Shselasky * Note: pccard_function_init should not keep resources allocated. It should 412321936Shselasky * only set them up ala isa pnp, set the values in the rl lists, and return. 413321936Shselasky * Any resource held after pccard_function_init is called is a bug. However, 414321936Shselasky * the bus routines to get the resources also assume that pccard_function_init 415321936Shselasky * does this, so they need to be fixed too. 416321936Shselasky */ 417321936Shselaskystatic void 418321936Shselaskypccard_function_init(struct pccard_function *pf) 419321936Shselasky{ 420321936Shselasky struct pccard_config_entry *cfe; 421321936Shselasky struct pccard_ivar *devi = PCCARD_IVAR(pf->dev); 422321936Shselasky struct resource_list *rl = &devi->resources; 423321936Shselasky struct resource_list_entry *rle; 424321936Shselasky struct resource *r = 0; 425321936Shselasky device_t bus; 426321936Shselasky u_long start, end, len; 427321936Shselasky int i, rid, spaces; 428321936Shselasky 429321936Shselasky if (pf->pf_flags & PFF_ENABLED) { 430321936Shselasky printf("pccard_function_init: function is enabled"); 431321936Shselasky return; 432321936Shselasky } 433321936Shselasky bus = device_get_parent(pf->dev); 434321936Shselasky /* Remember which configuration entry we are using. */ 435321936Shselasky STAILQ_FOREACH(cfe, &pf->cfe_head, cfe_list) { 436321936Shselasky if (cfe->iftype != PCCARD_IFTYPE_IO) 437321936Shselasky continue; 438321936Shselasky spaces = 0; 439321936Shselasky for (i = 0; i < cfe->num_iospace; i++) { 440321936Shselasky start = cfe->iospace[i].start; 441321936Shselasky if (start) 442321936Shselasky end = start + cfe->iospace[i].length - 1; 443321936Shselasky else 444321936Shselasky end = ~0UL; 445321936Shselasky DEVPRINTF((bus, "I/O rid %d start %lx end %lx\n", 446321936Shselasky i, start, end)); 447321936Shselasky rid = i; 448321936Shselasky len = cfe->iospace[i].length; 449321936Shselasky r = bus_alloc_resource(bus, SYS_RES_IOPORT, &rid, 450321936Shselasky start, end, len, rman_make_alignment_flags(len)); 451321936Shselasky if (r == NULL) 452321936Shselasky goto not_this_one; 453321936Shselasky rle = resource_list_add(rl, SYS_RES_IOPORT, 454321936Shselasky rid, rman_get_start(r), rman_get_end(r), 455321936Shselasky cfe->iospace[i].length); 456321936Shselasky if (rle == NULL) 457321936Shselasky panic("Cannot add resource rid %d IOPORT", rid); 458321936Shselasky rle->res = r; 459321936Shselasky spaces++; 460321936Shselasky } 461321936Shselasky for (i = 0; i < cfe->num_memspace; i++) { 462321936Shselasky start = cfe->memspace[i].hostaddr; 463321936Shselasky if (start) 464321936Shselasky end = start + cfe->memspace[i].length - 1; 465321936Shselasky else 466321936Shselasky end = ~0UL; 467321936Shselasky DEVPRINTF((bus, "Memory rid %d start %lx end %lx\n", 468321936Shselasky i, start, end)); 469321936Shselasky rid = i; 470321936Shselasky len = cfe->memspace[i].length; 471321936Shselasky r = bus_alloc_resource(bus, SYS_RES_MEMORY, &rid, 472321936Shselasky start, end, len, rman_make_alignment_flags(len)); 473321936Shselasky if (r == NULL) 474321936Shselasky goto not_this_one; 475321936Shselasky rle = resource_list_add(rl, SYS_RES_MEMORY, 476321936Shselasky rid, rman_get_start(r), rman_get_end(r), 477321936Shselasky cfe->memspace[i].length); 478321936Shselasky if (rle == NULL) 479321936Shselasky panic("Cannot add resource rid %d MEM", rid); 480321936Shselasky rle->res = r; 481321936Shselasky spaces++; 482321936Shselasky } 483321936Shselasky if (spaces == 0) { 484321936Shselasky DEVPRINTF((bus, "Neither memory nor I/O mapped\n")); 485321936Shselasky goto not_this_one; 486321936Shselasky } 487321936Shselasky if (cfe->irqmask) { 488321936Shselasky rid = 0; 489321936Shselasky r = bus_alloc_resource_any(bus, SYS_RES_IRQ, &rid, 490321936Shselasky RF_SHAREABLE); 491321936Shselasky if (r == NULL) 492321936Shselasky goto not_this_one; 493321936Shselasky rle = resource_list_add(rl, SYS_RES_IRQ, rid, 494321936Shselasky rman_get_start(r), rman_get_end(r), 1); 495321936Shselasky if (rle == NULL) 496321936Shselasky panic("Cannot add resource rid %d IRQ", rid); 497321936Shselasky rle->res = r; 498321936Shselasky } 499321936Shselasky /* If we get to here, we've allocated all we need */ 500321936Shselasky pf->cfe = cfe; 501321936Shselasky break; 502321936Shselasky not_this_one:; 503321936Shselasky DEVPRVERBOSE((bus, "Allocation failed for cfe %d\n", 504321936Shselasky cfe->number)); 505321936Shselasky resource_list_purge(rl); 506321936Shselasky } 507321936Shselasky} 508321936Shselasky 509321936Shselasky/* 510321936Shselasky * Free resources allocated by pccard_function_init(), May be called as long 511321936Shselasky * as the function is disabled. 512321936Shselasky * 513321936Shselasky * NOTE: This function should be unnecessary. pccard_function_init should 514321936Shselasky * never keep resources initialized. 515321936Shselasky */ 516321936Shselaskystatic void 517321936Shselaskypccard_function_free(struct pccard_function *pf) 518321936Shselasky{ 519321936Shselasky struct pccard_ivar *devi = PCCARD_IVAR(pf->dev); 520321936Shselasky struct resource_list_entry *rle; 521321936Shselasky 522321936Shselasky if (pf->pf_flags & PFF_ENABLED) { 523321936Shselasky printf("pccard_function_init: function is enabled"); 524321936Shselasky return; 525321936Shselasky } 526321936Shselasky 527321936Shselasky STAILQ_FOREACH(rle, &devi->resources, link) { 528321936Shselasky if (rle->res) { 529321936Shselasky if (rman_get_device(rle->res) != pf->sc->dev) 530321936Shselasky device_printf(pf->sc->dev, 531321936Shselasky "function_free: Resource still owned by " 532321936Shselasky "child, oops. " 533321936Shselasky "(type=%d, rid=%d, addr=%lx)\n", 534321936Shselasky rle->type, rle->rid, 535321936Shselasky rman_get_start(rle->res)); 536321936Shselasky BUS_RELEASE_RESOURCE(device_get_parent(pf->sc->dev), 537321936Shselasky pf->sc->dev, rle->type, rle->rid, rle->res); 538321936Shselasky rle->res = NULL; 539321936Shselasky } 540321936Shselasky } 541321936Shselasky resource_list_free(&devi->resources); 542321936Shselasky} 543321936Shselasky 544321936Shselaskystatic void 545321936Shselaskypccard_mfc_adjust_iobase(struct pccard_function *pf, bus_addr_t addr, 546321936Shselasky bus_addr_t offset, bus_size_t size) 547321936Shselasky{ 548321936Shselasky bus_size_t iosize, tmp; 549321936Shselasky 550321936Shselasky if (addr != 0) { 551321936Shselasky if (pf->pf_mfc_iomax == 0) { 552321936Shselasky pf->pf_mfc_iobase = addr + offset; 553321936Shselasky pf->pf_mfc_iomax = pf->pf_mfc_iobase + size; 554321936Shselasky } else { 555321936Shselasky /* this makes the assumption that nothing overlaps */ 556321936Shselasky if (pf->pf_mfc_iobase > addr + offset) 557321936Shselasky pf->pf_mfc_iobase = addr + offset; 558321936Shselasky if (pf->pf_mfc_iomax < addr + offset + size) 559321936Shselasky pf->pf_mfc_iomax = addr + offset + size; 560321936Shselasky } 561321936Shselasky } 562321936Shselasky 563321936Shselasky tmp = pf->pf_mfc_iomax - pf->pf_mfc_iobase; 564321936Shselasky /* round up to nearest (2^n)-1 */ 565321936Shselasky for (iosize = 1; iosize < tmp; iosize <<= 1) 566321936Shselasky ; 567321936Shselasky iosize--; 568321936Shselasky 569321936Shselasky DEVPRINTF((pf->dev, "MFC: I/O base %#jx IOSIZE %#jx\n", 570321936Shselasky (uintmax_t)pf->pf_mfc_iobase, (uintmax_t)(iosize + 1))); 571321936Shselasky pccard_ccr_write(pf, PCCARD_CCR_IOBASE0, 572321936Shselasky pf->pf_mfc_iobase & 0xff); 573321936Shselasky pccard_ccr_write(pf, PCCARD_CCR_IOBASE1, 574321936Shselasky (pf->pf_mfc_iobase >> 8) & 0xff); 575321936Shselasky pccard_ccr_write(pf, PCCARD_CCR_IOBASE2, 0); 576321936Shselasky pccard_ccr_write(pf, PCCARD_CCR_IOBASE3, 0); 577321936Shselasky pccard_ccr_write(pf, PCCARD_CCR_IOSIZE, iosize); 578321936Shselasky} 579321936Shselasky 580321936Shselasky/* Enable a PCCARD function */ 581321936Shselaskystatic int 582321936Shselaskypccard_function_enable(struct pccard_function *pf) 583321936Shselasky{ 584321936Shselasky struct pccard_function *tmp; 585321936Shselasky int reg; 586321936Shselasky device_t dev = pf->sc->dev; 587321936Shselasky 588321936Shselasky if (pf->cfe == NULL) { 589321936Shselasky DEVPRVERBOSE((dev, "No config entry could be allocated.\n")); 590321936Shselasky return (ENOMEM); 591321936Shselasky } 592321936Shselasky 593321936Shselasky /* 594321936Shselasky * Increase the reference count on the socket, enabling power, if 595321936Shselasky * necessary. 596321936Shselasky */ 597321936Shselasky pf->sc->sc_enabled_count++; 598321936Shselasky 599321936Shselasky if (pf->pf_flags & PFF_ENABLED) { 600321936Shselasky /* 601321936Shselasky * Don't do anything if we're already enabled. 602321936Shselasky */ 603321936Shselasky return (0); 604321936Shselasky } 605321936Shselasky 606321936Shselasky /* 607321936Shselasky * it's possible for different functions' CCRs to be in the same 608321936Shselasky * underlying page. Check for that. 609321936Shselasky */ 610321936Shselasky STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) { 611321936Shselasky if ((tmp->pf_flags & PFF_ENABLED) && 612321936Shselasky (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) && 613321936Shselasky ((pf->ccr_base + PCCARD_CCR_SIZE) <= 614321936Shselasky (tmp->ccr_base - tmp->pf_ccr_offset + 615321936Shselasky tmp->pf_ccr_realsize))) { 616321936Shselasky pf->pf_ccrt = tmp->pf_ccrt; 617321936Shselasky pf->pf_ccrh = tmp->pf_ccrh; 618321936Shselasky pf->pf_ccr_realsize = tmp->pf_ccr_realsize; 619321936Shselasky 620321936Shselasky /* 621321936Shselasky * pf->pf_ccr_offset = (tmp->pf_ccr_offset - 622321936Shselasky * tmp->ccr_base) + pf->ccr_base; 623321936Shselasky */ 624321936Shselasky /* pf->pf_ccr_offset = 625321936Shselasky (tmp->pf_ccr_offset + pf->ccr_base) - 626321936Shselasky tmp->ccr_base; */ 627321936Shselasky pf->pf_ccr_window = tmp->pf_ccr_window; 628321936Shselasky break; 629321936Shselasky } 630321936Shselasky } 631321936Shselasky if (tmp == NULL) { 632321936Shselasky pf->ccr_rid = 0; 633321936Shselasky pf->ccr_res = bus_alloc_resource(dev, SYS_RES_MEMORY, 634321936Shselasky &pf->ccr_rid, 0, ~0, PCCARD_MEM_PAGE_SIZE, RF_ACTIVE); 635321936Shselasky if (!pf->ccr_res) 636321936Shselasky goto bad; 637321936Shselasky DEVPRINTF((dev, "ccr_res == %lx-%lx, base=%x\n", 638321936Shselasky rman_get_start(pf->ccr_res), rman_get_end(pf->ccr_res), 639321936Shselasky pf->ccr_base)); 640321936Shselasky CARD_SET_RES_FLAGS(device_get_parent(dev), dev, SYS_RES_MEMORY, 641321936Shselasky pf->ccr_rid, PCCARD_A_MEM_ATTR); 642321936Shselasky CARD_SET_MEMORY_OFFSET(device_get_parent(dev), dev, 643321936Shselasky pf->ccr_rid, pf->ccr_base, &pf->pf_ccr_offset); 644321936Shselasky pf->pf_ccrt = rman_get_bustag(pf->ccr_res); 645321936Shselasky pf->pf_ccrh = rman_get_bushandle(pf->ccr_res); 646321936Shselasky pf->pf_ccr_realsize = 1; 647321936Shselasky } 648321936Shselasky 649321936Shselasky reg = (pf->cfe->number & PCCARD_CCR_OPTION_CFINDEX); 650321936Shselasky reg |= PCCARD_CCR_OPTION_LEVIREQ; 651321936Shselasky if (pccard_mfc(pf->sc)) { 652321936Shselasky reg |= (PCCARD_CCR_OPTION_FUNC_ENABLE | 653321936Shselasky PCCARD_CCR_OPTION_ADDR_DECODE); 654321936Shselasky /* PCCARD_CCR_OPTION_IRQ_ENABLE set elsewhere as needed */ 655321936Shselasky } 656321936Shselasky pccard_ccr_write(pf, PCCARD_CCR_OPTION, reg); 657321936Shselasky 658321936Shselasky reg = 0; 659321936Shselasky if ((pf->cfe->flags & PCCARD_CFE_IO16) == 0) 660321936Shselasky reg |= PCCARD_CCR_STATUS_IOIS8; 661321936Shselasky if (pf->cfe->flags & PCCARD_CFE_AUDIO) 662321936Shselasky reg |= PCCARD_CCR_STATUS_AUDIO; 663321936Shselasky pccard_ccr_write(pf, PCCARD_CCR_STATUS, reg); 664321936Shselasky 665321936Shselasky pccard_ccr_write(pf, PCCARD_CCR_SOCKETCOPY, 0); 666321936Shselasky 667321936Shselasky if (pccard_mfc(pf->sc)) 668321936Shselasky pccard_mfc_adjust_iobase(pf, 0, 0, 0); 669321936Shselasky 670321936Shselasky#ifdef PCCARDDEBUG 671321936Shselasky if (pccard_debug) { 672321936Shselasky STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) { 673321936Shselasky device_printf(tmp->sc->dev, 674321936Shselasky "function %d CCR at %d offset %x: " 675321936Shselasky "%x %x %x %x, %x %x %x %x, %x\n", 676321936Shselasky tmp->number, tmp->pf_ccr_window, 677321936Shselasky tmp->pf_ccr_offset, 678321936Shselasky pccard_ccr_read(tmp, 0x00), 679321936Shselasky pccard_ccr_read(tmp, 0x02), 680321936Shselasky pccard_ccr_read(tmp, 0x04), 681321936Shselasky pccard_ccr_read(tmp, 0x06), 682321936Shselasky pccard_ccr_read(tmp, 0x0A), 683321936Shselasky pccard_ccr_read(tmp, 0x0C), 684321936Shselasky pccard_ccr_read(tmp, 0x0E), 685321936Shselasky pccard_ccr_read(tmp, 0x10), 686321936Shselasky pccard_ccr_read(tmp, 0x12)); 687321936Shselasky } 688321936Shselasky } 689321936Shselasky#endif 690321936Shselasky pf->pf_flags |= PFF_ENABLED; 691321936Shselasky return (0); 692321936Shselasky 693321936Shselasky bad: 694321936Shselasky /* 695321936Shselasky * Decrement the reference count, and power down the socket, if 696321936Shselasky * necessary. 697321936Shselasky */ 698321936Shselasky pf->sc->sc_enabled_count--; 699321936Shselasky DEVPRINTF((dev, "bad --enabled_count = %d\n", pf->sc->sc_enabled_count)); 700321936Shselasky 701321936Shselasky return (1); 702321936Shselasky} 703321936Shselasky 704321936Shselasky/* Disable PCCARD function. */ 705321936Shselaskystatic void 706321936Shselaskypccard_function_disable(struct pccard_function *pf) 707321936Shselasky{ 708321936Shselasky struct pccard_function *tmp; 709321936Shselasky device_t dev = pf->sc->dev; 710321936Shselasky 711321936Shselasky if (pf->cfe == NULL) 712321936Shselasky panic("pccard_function_disable: function not initialized"); 713321936Shselasky 714321936Shselasky if ((pf->pf_flags & PFF_ENABLED) == 0) { 715321936Shselasky /* 716321936Shselasky * Don't do anything if we're already disabled. 717321936Shselasky */ 718321936Shselasky return; 719321936Shselasky } 720321936Shselasky 721321936Shselasky if (pf->intr_handler != NULL) { 722321936Shselasky struct pccard_ivar *devi = PCCARD_IVAR(pf->dev); 723321936Shselasky struct resource_list_entry *rle = 724321936Shselasky resource_list_find(&devi->resources, SYS_RES_IRQ, 0); 725321936Shselasky if (rle == NULL) 726321936Shselasky panic("Can't disable an interrupt with no IRQ res\n"); 727321936Shselasky BUS_TEARDOWN_INTR(dev, pf->dev, rle->res, 728321936Shselasky pf->intr_handler_cookie); 729321936Shselasky } 730321936Shselasky 731321936Shselasky /* 732321936Shselasky * it's possible for different functions' CCRs to be in the same 733321936Shselasky * underlying page. Check for that. Note we mark us as disabled 734321936Shselasky * first to avoid matching ourself. 735321936Shselasky */ 736321936Shselasky 737321936Shselasky pf->pf_flags &= ~PFF_ENABLED; 738321936Shselasky STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) { 739321936Shselasky if ((tmp->pf_flags & PFF_ENABLED) && 740321936Shselasky (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) && 741321936Shselasky ((pf->ccr_base + PCCARD_CCR_SIZE) <= 742321936Shselasky (tmp->ccr_base - tmp->pf_ccr_offset + 743321936Shselasky tmp->pf_ccr_realsize))) 744321936Shselasky break; 745321936Shselasky } 746321936Shselasky 747321936Shselasky /* Not used by anyone else; unmap the CCR. */ 748321936Shselasky if (tmp == NULL) { 749321936Shselasky bus_release_resource(dev, SYS_RES_MEMORY, pf->ccr_rid, 750321936Shselasky pf->ccr_res); 751321936Shselasky pf->ccr_res = NULL; 752321936Shselasky } 753321936Shselasky 754321936Shselasky /* 755321936Shselasky * Decrement the reference count, and power down the socket, if 756321936Shselasky * necessary. 757321936Shselasky */ 758321936Shselasky pf->sc->sc_enabled_count--; 759321936Shselasky} 760321936Shselasky 761321936Shselasky/* 762321936Shselasky * simulate the old "probe" routine. In the new world order, the driver 763321936Shselasky * needs to grab devices while in the old they were assigned to the device by 764321936Shselasky * the pccardd process. These symbols are exported to the upper layers. 765321936Shselasky */ 766321936Shselaskystatic int 767321936Shselaskypccard_compat_do_probe(device_t bus, device_t dev) 768321936Shselasky{ 769321936Shselasky return (CARD_COMPAT_MATCH(dev)); 770321936Shselasky} 771321936Shselasky 772321936Shselaskystatic int 773321936Shselaskypccard_compat_do_attach(device_t bus, device_t dev) 774321936Shselasky{ 775321936Shselasky int err; 776321936Shselasky 777321936Shselasky err = CARD_COMPAT_PROBE(dev); 778321936Shselasky if (err <= 0) 779321936Shselasky err = CARD_COMPAT_ATTACH(dev); 780321936Shselasky return (err); 781321936Shselasky} 782321936Shselasky 783321936Shselasky#define PCCARD_NPORT 2 784321936Shselasky#define PCCARD_NMEM 5 785321936Shselasky#define PCCARD_NIRQ 1 786321936Shselasky#define PCCARD_NDRQ 0 787321936Shselasky 788321936Shselaskystatic int 789321936Shselaskypccard_probe(device_t dev) 790321936Shselasky{ 791321936Shselasky device_set_desc(dev, "16-bit PCCard bus"); 792321936Shselasky return (0); 793321936Shselasky} 794321936Shselasky 795321936Shselaskystatic int 796321936Shselaskypccard_attach(device_t dev) 797321936Shselasky{ 798321936Shselasky struct pccard_softc *sc = PCCARD_SOFTC(dev); 799321936Shselasky int err; 800321936Shselasky 801321936Shselasky sc->dev = dev; 802321936Shselasky sc->sc_enabled_count = 0; 803321936Shselasky if ((err = pccard_device_create(sc)) != 0) 804321936Shselasky return (err); 805321936Shselasky return (bus_generic_attach(dev)); 806321936Shselasky} 807321936Shselasky 808321936Shselaskystatic int 809321936Shselaskypccard_detach(device_t dev) 810321936Shselasky{ 811321936Shselasky pccard_detach_card(dev); 812321936Shselasky pccard_device_destroy(device_get_softc(dev)); 813321936Shselasky return (0); 814321936Shselasky} 815321936Shselasky 816321936Shselaskystatic int 817321936Shselaskypccard_suspend(device_t self) 818321936Shselasky{ 819321936Shselasky pccard_detach_card(self); 820321936Shselasky return (0); 821321936Shselasky} 822321936Shselasky 823321936Shselaskystatic 824321936Shselaskyint 825321936Shselaskypccard_resume(device_t self) 826321936Shselasky{ 827321936Shselasky return (0); 828321936Shselasky} 829321936Shselasky 830321936Shselaskystatic void 831321936Shselaskypccard_print_resources(struct resource_list *rl, const char *name, int type, 832321936Shselasky int count, const char *format) 833321936Shselasky{ 834321936Shselasky struct resource_list_entry *rle; 835321936Shselasky int printed; 836321936Shselasky int i; 837321936Shselasky 838321936Shselasky printed = 0; 839321936Shselasky for (i = 0; i < count; i++) { 840321936Shselasky rle = resource_list_find(rl, type, i); 841321936Shselasky if (rle != NULL) { 842321936Shselasky if (printed == 0) 843321936Shselasky printf(" %s ", name); 844321936Shselasky else if (printed > 0) 845321936Shselasky printf(","); 846321936Shselasky printed++; 847321936Shselasky printf(format, rle->start); 848321936Shselasky if (rle->count > 1) { 849321936Shselasky printf("-"); 850321936Shselasky printf(format, rle->start + rle->count - 1); 851321936Shselasky } 852321936Shselasky } else if (i > 3) { 853321936Shselasky /* check the first few regardless */ 854321936Shselasky break; 855321936Shselasky } 856321936Shselasky } 857321936Shselasky} 858321936Shselasky 859321936Shselaskystatic int 860321936Shselaskypccard_print_child(device_t dev, device_t child) 861321936Shselasky{ 862321936Shselasky struct pccard_ivar *devi = PCCARD_IVAR(child); 863321936Shselasky struct resource_list *rl = &devi->resources; 864321936Shselasky int retval = 0; 865321936Shselasky 866321936Shselasky retval += bus_print_child_header(dev, child); 867321936Shselasky retval += printf(" at"); 868321936Shselasky 869321936Shselasky if (devi != NULL) { 870321936Shselasky pccard_print_resources(rl, "port", SYS_RES_IOPORT, 871321936Shselasky PCCARD_NPORT, "%#lx"); 872321936Shselasky pccard_print_resources(rl, "iomem", SYS_RES_MEMORY, 873321936Shselasky PCCARD_NMEM, "%#lx"); 874321936Shselasky pccard_print_resources(rl, "irq", SYS_RES_IRQ, PCCARD_NIRQ, 875321936Shselasky "%ld"); 876321936Shselasky pccard_print_resources(rl, "drq", SYS_RES_DRQ, PCCARD_NDRQ, 877321936Shselasky "%ld"); 878321936Shselasky retval += printf(" function %d config %d", devi->pf->number, 879321936Shselasky devi->pf->cfe->number); 880321936Shselasky } 881321936Shselasky 882321936Shselasky retval += bus_print_child_footer(dev, child); 883321936Shselasky 884321936Shselasky return (retval); 885321936Shselasky} 886321936Shselasky 887321936Shselaskystatic int 888321936Shselaskypccard_set_resource(device_t dev, device_t child, int type, int rid, 889321936Shselasky u_long start, u_long count) 890321936Shselasky{ 891321936Shselasky struct pccard_ivar *devi = PCCARD_IVAR(child); 892321936Shselasky struct resource_list *rl = &devi->resources; 893321936Shselasky 894321936Shselasky if (type != SYS_RES_IOPORT && type != SYS_RES_MEMORY 895321936Shselasky && type != SYS_RES_IRQ && type != SYS_RES_DRQ) 896321936Shselasky return (EINVAL); 897321936Shselasky if (rid < 0) 898321936Shselasky return (EINVAL); 899321936Shselasky if (type == SYS_RES_IOPORT && rid >= PCCARD_NPORT) 900321936Shselasky return (EINVAL); 901321936Shselasky if (type == SYS_RES_MEMORY && rid >= PCCARD_NMEM) 902321936Shselasky return (EINVAL); 903321936Shselasky if (type == SYS_RES_IRQ && rid >= PCCARD_NIRQ) 904321936Shselasky return (EINVAL); 905321936Shselasky if (type == SYS_RES_DRQ && rid >= PCCARD_NDRQ) 906321936Shselasky return (EINVAL); 907321936Shselasky 908321936Shselasky resource_list_add(rl, type, rid, start, start + count - 1, count); 909321936Shselasky if (NULL != resource_list_alloc(rl, device_get_parent(dev), dev, 910321936Shselasky type, &rid, start, start + count - 1, count, 0)) 911321936Shselasky return 0; 912321936Shselasky else 913321936Shselasky return ENOMEM; 914321936Shselasky} 915321936Shselasky 916321936Shselaskystatic int 917321936Shselaskypccard_get_resource(device_t dev, device_t child, int type, int rid, 918321936Shselasky u_long *startp, u_long *countp) 919321936Shselasky{ 920321936Shselasky struct pccard_ivar *devi = PCCARD_IVAR(child); 921321936Shselasky struct resource_list *rl = &devi->resources; 922321936Shselasky struct resource_list_entry *rle; 923321936Shselasky 924321936Shselasky rle = resource_list_find(rl, type, rid); 925321936Shselasky if (rle == NULL) 926321936Shselasky return (ENOENT); 927321936Shselasky 928321936Shselasky if (startp != NULL) 929321936Shselasky *startp = rle->start; 930321936Shselasky if (countp != NULL) 931321936Shselasky *countp = rle->count; 932321936Shselasky 933321936Shselasky return (0); 934321936Shselasky} 935321936Shselasky 936321936Shselaskystatic void 937321936Shselaskypccard_delete_resource(device_t dev, device_t child, int type, int rid) 938321936Shselasky{ 939321936Shselasky struct pccard_ivar *devi = PCCARD_IVAR(child); 940321936Shselasky struct resource_list *rl = &devi->resources; 941321936Shselasky resource_list_delete(rl, type, rid); 942321936Shselasky} 943321936Shselasky 944321936Shselaskystatic int 945321936Shselaskypccard_set_res_flags(device_t dev, device_t child, int type, int rid, 946321936Shselasky uint32_t flags) 947321936Shselasky{ 948321936Shselasky return (CARD_SET_RES_FLAGS(device_get_parent(dev), child, type, 949321936Shselasky rid, flags)); 950321936Shselasky} 951321936Shselasky 952321936Shselaskystatic int 953321936Shselaskypccard_set_memory_offset(device_t dev, device_t child, int rid, 954321936Shselasky uint32_t offset, uint32_t *deltap) 955321936Shselasky 956321936Shselasky{ 957321936Shselasky return (CARD_SET_MEMORY_OFFSET(device_get_parent(dev), child, rid, 958321936Shselasky offset, deltap)); 959321936Shselasky} 960321936Shselasky 961321936Shselaskystatic void 962321936Shselaskypccard_probe_nomatch(device_t bus, device_t child) 963321936Shselasky{ 964321936Shselasky struct pccard_ivar *devi = PCCARD_IVAR(child); 965321936Shselasky struct pccard_function *pf = devi->pf; 966321936Shselasky struct pccard_softc *sc = PCCARD_SOFTC(bus); 967321936Shselasky int i; 968321936Shselasky 969321936Shselasky device_printf(bus, "<unknown card>"); 970321936Shselasky printf(" (manufacturer=0x%04x, product=0x%04x, function_type=%d) " 971321936Shselasky "at function %d\n", sc->card.manufacturer, sc->card.product, 972321936Shselasky pf->function, pf->number); 973321936Shselasky device_printf(bus, " CIS info: "); 974321936Shselasky for (i = 0; sc->card.cis1_info[i] != NULL && i < 4; i++) 975321936Shselasky printf("%s%s", i > 0 ? ", " : "", sc->card.cis1_info[i]); 976321936Shselasky printf("\n"); 977321936Shselasky return; 978321936Shselasky} 979321936Shselasky 980321936Shselaskystatic int 981321936Shselaskypccard_child_location_str(device_t bus, device_t child, char *buf, 982321936Shselasky size_t buflen) 983321936Shselasky{ 984321936Shselasky struct pccard_ivar *devi = PCCARD_IVAR(child); 985321936Shselasky struct pccard_function *pf = devi->pf; 986321936Shselasky 987321936Shselasky snprintf(buf, buflen, "function=%d", pf->number); 988321936Shselasky return (0); 989321936Shselasky} 990321936Shselasky 991321936Shselasky/* XXX Maybe this should be in subr_bus? */ 992321936Shselaskystatic void 993321936Shselaskypccard_safe_quote(char *dst, const char *src, size_t len) 994321936Shselasky{ 995321936Shselasky char *walker = dst, *ep = dst + len - 1; 996321936Shselasky 997321936Shselasky if (len == 0) 998321936Shselasky return; 999321936Shselasky while (walker < ep) 1000321936Shselasky { 1001321936Shselasky if (*src == '"') { 1002321936Shselasky if (ep - walker < 2) 1003321936Shselasky break; 1004321936Shselasky *walker++ = '\\'; 1005321936Shselasky } 1006321936Shselasky *walker++ = *src++; 1007321936Shselasky } 1008321936Shselasky *walker = '\0'; 1009321936Shselasky} 1010321936Shselasky 1011321936Shselaskystatic int 1012321936Shselaskypccard_child_pnpinfo_str(device_t bus, device_t child, char *buf, 1013321936Shselasky size_t buflen) 1014321936Shselasky{ 1015321936Shselasky struct pccard_ivar *devi = PCCARD_IVAR(child); 1016321936Shselasky struct pccard_function *pf = devi->pf; 1017321936Shselasky struct pccard_softc *sc = PCCARD_SOFTC(bus); 1018321936Shselasky char cis0[128], cis1[128]; 1019321936Shselasky 1020321936Shselasky pccard_safe_quote(cis0, sc->card.cis1_info[0], sizeof(cis0)); 1021321936Shselasky pccard_safe_quote(cis1, sc->card.cis1_info[1], sizeof(cis1)); 1022321936Shselasky snprintf(buf, buflen, "manufacturer=0x%04x product=0x%04x " 1023321936Shselasky "cisvendor=\"%s\" cisproduct=\"%s\" function_type=%d", 1024321936Shselasky sc->card.manufacturer, sc->card.product, cis0, cis1, pf->function); 1025321936Shselasky return (0); 1026321936Shselasky} 1027321936Shselasky 1028321936Shselaskystatic int 1029321936Shselaskypccard_read_ivar(device_t bus, device_t child, int which, u_char *result) 1030321936Shselasky{ 1031321936Shselasky struct pccard_ivar *devi = PCCARD_IVAR(child); 1032321936Shselasky struct pccard_function *pf = devi->pf; 1033321936Shselasky struct pccard_softc *sc = PCCARD_SOFTC(bus); 1034321936Shselasky 1035321936Shselasky if (!pf) 1036321936Shselasky panic("No pccard function pointer"); 1037321936Shselasky switch (which) { 1038321936Shselasky default: 1039321936Shselasky return (EINVAL); 1040321936Shselasky case PCCARD_IVAR_ETHADDR: 1041321936Shselasky bcopy(pf->pf_funce_lan_nid, result, ETHER_ADDR_LEN); 1042321936Shselasky break; 1043321936Shselasky case PCCARD_IVAR_VENDOR: 1044321936Shselasky *(uint32_t *)result = sc->card.manufacturer; 1045321936Shselasky break; 1046321936Shselasky case PCCARD_IVAR_PRODUCT: 1047321936Shselasky *(uint32_t *)result = sc->card.product; 1048321936Shselasky break; 1049321936Shselasky case PCCARD_IVAR_PRODEXT: 1050321936Shselasky *(uint16_t *)result = sc->card.prodext; 1051321936Shselasky break; 1052321936Shselasky case PCCARD_IVAR_FUNCTION: 1053321936Shselasky *(uint32_t *)result = pf->function; 1054321936Shselasky break; 1055321936Shselasky case PCCARD_IVAR_FUNCTION_NUMBER: 1056321936Shselasky *(uint32_t *)result = pf->number; 1057321936Shselasky break; 1058321936Shselasky case PCCARD_IVAR_VENDOR_STR: 1059321936Shselasky *(const char **)result = sc->card.cis1_info[0]; 1060321936Shselasky break; 1061321936Shselasky case PCCARD_IVAR_PRODUCT_STR: 1062321936Shselasky *(const char **)result = sc->card.cis1_info[1]; 1063321936Shselasky break; 1064321936Shselasky case PCCARD_IVAR_CIS3_STR: 1065321936Shselasky *(const char **)result = sc->card.cis1_info[2]; 1066321936Shselasky break; 1067321936Shselasky case PCCARD_IVAR_CIS4_STR: 1068321936Shselasky *(const char **)result = sc->card.cis1_info[3]; 1069321936Shselasky break; 1070321936Shselasky } 1071321936Shselasky return (0); 1072321936Shselasky} 1073321936Shselasky 1074321936Shselaskystatic void 1075321936Shselaskypccard_driver_added(device_t dev, driver_t *driver) 1076321936Shselasky{ 1077321936Shselasky struct pccard_softc *sc = PCCARD_SOFTC(dev); 1078321936Shselasky struct pccard_function *pf; 1079321936Shselasky device_t child; 1080321936Shselasky 1081321936Shselasky STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) { 1082321936Shselasky if (STAILQ_EMPTY(&pf->cfe_head)) 1083321936Shselasky continue; 1084321936Shselasky child = pf->dev; 1085321936Shselasky if (device_get_state(child) != DS_NOTPRESENT) 1086321936Shselasky continue; 1087321936Shselasky if (pccard_function_enable(pf) == 0 && 1088321936Shselasky device_probe_and_attach(child) == 0) { 1089321936Shselasky DEVPRINTF((sc->dev, "function %d CCR at %d " 1090321936Shselasky "offset %x: %x %x %x %x, %x %x %x %x, %x\n", 1091321936Shselasky pf->number, pf->pf_ccr_window, pf->pf_ccr_offset, 1092321936Shselasky pccard_ccr_read(pf, 0x00), 1093321936Shselasky pccard_ccr_read(pf, 0x02), pccard_ccr_read(pf, 0x04), 1094321936Shselasky pccard_ccr_read(pf, 0x06), pccard_ccr_read(pf, 0x0A), 1095321936Shselasky pccard_ccr_read(pf, 0x0C), pccard_ccr_read(pf, 0x0E), 1096321936Shselasky pccard_ccr_read(pf, 0x10), pccard_ccr_read(pf, 0x12))); 1097321936Shselasky } else { 1098321936Shselasky if (pf->cfe != NULL) 1099321936Shselasky pccard_function_disable(pf); 1100321936Shselasky } 1101321936Shselasky } 1102321936Shselasky return; 1103321936Shselasky} 1104321936Shselasky 1105321936Shselaskystatic struct resource * 1106321936Shselaskypccard_alloc_resource(device_t dev, device_t child, int type, int *rid, 1107321936Shselasky u_long start, u_long end, u_long count, u_int flags) 1108321936Shselasky{ 1109321936Shselasky struct pccard_ivar *dinfo; 1110321936Shselasky struct resource_list_entry *rle = 0; 1111321936Shselasky int passthrough = (device_get_parent(child) != dev); 1112321936Shselasky int isdefault = (start == 0 && end == ~0UL && count == 1); 1113321936Shselasky struct resource *r = NULL; 1114321936Shselasky 1115321936Shselasky /* XXX I'm no longer sure this is right */ 1116321936Shselasky if (passthrough) { 1117321936Shselasky return (BUS_ALLOC_RESOURCE(device_get_parent(dev), child, 1118321936Shselasky type, rid, start, end, count, flags)); 1119321936Shselasky } 1120321936Shselasky 1121321936Shselasky dinfo = device_get_ivars(child); 1122321936Shselasky rle = resource_list_find(&dinfo->resources, type, *rid); 1123321936Shselasky 1124321936Shselasky if (rle == NULL && isdefault) 1125321936Shselasky return (NULL); /* no resource of that type/rid */ 1126321936Shselasky if (rle == NULL || rle->res == NULL) { 1127321936Shselasky /* XXX Need to adjust flags */ 1128321936Shselasky r = bus_alloc_resource(dev, type, rid, start, end, 1129321936Shselasky count, flags); 1130321936Shselasky if (r == NULL) 1131321936Shselasky goto bad; 1132321936Shselasky resource_list_add(&dinfo->resources, type, *rid, 1133321936Shselasky rman_get_start(r), rman_get_end(r), count); 1134321936Shselasky rle = resource_list_find(&dinfo->resources, type, *rid); 1135321936Shselasky if (!rle) 1136321936Shselasky goto bad; 1137321936Shselasky rle->res = r; 1138321936Shselasky } 1139321936Shselasky /* 1140321936Shselasky * If dev doesn't own the device, then we can't give this device 1141321936Shselasky * out. 1142321936Shselasky */ 1143321936Shselasky if (rman_get_device(rle->res) != dev) 1144321936Shselasky return (NULL); 1145321936Shselasky rman_set_device(rle->res, child); 1146321936Shselasky if (flags & RF_ACTIVE) 1147321936Shselasky BUS_ACTIVATE_RESOURCE(dev, child, type, *rid, rle->res); 1148321936Shselasky return (rle->res); 1149321936Shselaskybad:; 1150321936Shselasky device_printf(dev, "WARNING: Resource not reserved by pccard\n"); 1151321936Shselasky return (NULL); 1152321936Shselasky} 1153321936Shselasky 1154321936Shselaskystatic int 1155321936Shselaskypccard_release_resource(device_t dev, device_t child, int type, int rid, 1156321936Shselasky struct resource *r) 1157321936Shselasky{ 1158321936Shselasky struct pccard_ivar *dinfo; 1159321936Shselasky int passthrough = (device_get_parent(child) != dev); 1160321936Shselasky struct resource_list_entry *rle = 0; 1161321936Shselasky 1162321936Shselasky if (passthrough) 1163321936Shselasky return BUS_RELEASE_RESOURCE(device_get_parent(dev), child, 1164321936Shselasky type, rid, r); 1165321936Shselasky 1166321936Shselasky dinfo = device_get_ivars(child); 1167321936Shselasky 1168321936Shselasky rle = resource_list_find(&dinfo->resources, type, rid); 1169321936Shselasky 1170321936Shselasky if (!rle) { 1171321936Shselasky device_printf(dev, "Allocated resource not found, " 1172321936Shselasky "%d %x %lx %lx\n", 1173321936Shselasky type, rid, rman_get_start(r), rman_get_size(r)); 1174321936Shselasky return ENOENT; 1175321936Shselasky } 1176321936Shselasky if (!rle->res) { 1177321936Shselasky device_printf(dev, "Allocated resource not recorded\n"); 1178321936Shselasky return ENOENT; 1179321936Shselasky } 1180321936Shselasky /* 1181321936Shselasky * Deactivate the resource (since it is being released), and 1182321936Shselasky * assign it to the bus. 1183321936Shselasky */ 1184321936Shselasky BUS_DEACTIVATE_RESOURCE(dev, child, type, rid, rle->res); 1185321936Shselasky rman_set_device(rle->res, dev); 1186321936Shselasky return (0); 1187321936Shselasky} 1188321936Shselasky 1189321936Shselaskystatic void 1190321936Shselaskypccard_child_detached(device_t parent, device_t dev) 1191321936Shselasky{ 1192321936Shselasky struct pccard_ivar *ivar = PCCARD_IVAR(dev); 1193321936Shselasky struct pccard_function *pf = ivar->pf; 1194321936Shselasky 1195321936Shselasky pccard_function_disable(pf); 1196321936Shselasky} 1197321936Shselasky 1198321936Shselaskystatic void 1199321936Shselaskypccard_intr(void *arg) 1200321936Shselasky{ 1201321936Shselasky struct pccard_function *pf = (struct pccard_function*) arg; 1202321936Shselasky int reg; 1203321936Shselasky int doisr = 1; 1204321936Shselasky 1205321936Shselasky /* 1206321936Shselasky * MFC cards know if they interrupted, so we have to ack the 1207321936Shselasky * interrupt and call the ISR. Non-MFC cards don't have these 1208321936Shselasky * bits, so they always get called. Many non-MFC cards have 1209321936Shselasky * this bit set always upon read, but some do not. 1210321936Shselasky * 1211321936Shselasky * We always ack the interrupt, even if there's no ISR 1212321936Shselasky * for the card. This is done on the theory that acking 1213321936Shselasky * the interrupt will pacify the card enough to keep an 1214321936Shselasky * interrupt storm from happening. Of course this won't 1215321936Shselasky * help in the non-MFC case. 1216321936Shselasky * 1217321936Shselasky * This has no impact for MPSAFEness of the client drivers. 1218321936Shselasky * We register this with whatever flags the intr_handler 1219321936Shselasky * was registered with. All these functions are MPSAFE. 1220321936Shselasky */ 1221321936Shselasky if (pccard_mfc(pf->sc)) { 1222321936Shselasky reg = pccard_ccr_read(pf, PCCARD_CCR_STATUS); 1223321936Shselasky if (reg & PCCARD_CCR_STATUS_INTR) 1224321936Shselasky pccard_ccr_write(pf, PCCARD_CCR_STATUS, 1225321936Shselasky reg & ~PCCARD_CCR_STATUS_INTR); 1226321936Shselasky else 1227321936Shselasky doisr = 0; 1228321936Shselasky } 1229321936Shselasky if (pf->intr_handler != NULL && doisr) 1230321936Shselasky pf->intr_handler(pf->intr_handler_arg); 1231321936Shselasky} 1232321936Shselasky 1233321936Shselaskystatic int 1234321936Shselaskypccard_setup_intr(device_t dev, device_t child, struct resource *irq, 1235321936Shselasky int flags, driver_intr_t *intr, void *arg, void **cookiep) 1236321936Shselasky{ 1237321936Shselasky struct pccard_softc *sc = PCCARD_SOFTC(dev); 1238321936Shselasky struct pccard_ivar *ivar = PCCARD_IVAR(child); 1239321936Shselasky struct pccard_function *pf = ivar->pf; 1240321936Shselasky int err; 1241321936Shselasky 1242321936Shselasky if (pf->intr_handler != NULL) 1243321936Shselasky panic("Only one interrupt handler per function allowed"); 1244321936Shselasky err = bus_generic_setup_intr(dev, child, irq, flags, pccard_intr, 1245321936Shselasky pf, cookiep); 1246321936Shselasky if (err != 0) 1247321936Shselasky return (err); 1248321936Shselasky pf->intr_handler = intr; 1249321936Shselasky pf->intr_handler_arg = arg; 1250321936Shselasky pf->intr_handler_cookie = *cookiep; 1251321936Shselasky if (pccard_mfc(sc)) { 1252321936Shselasky pccard_ccr_write(pf, PCCARD_CCR_OPTION, 1253321936Shselasky pccard_ccr_read(pf, PCCARD_CCR_OPTION) | 1254321936Shselasky PCCARD_CCR_OPTION_IREQ_ENABLE); 1255321936Shselasky } 1256321936Shselasky return (0); 1257321936Shselasky} 1258321936Shselasky 1259321936Shselaskystatic int 1260321936Shselaskypccard_teardown_intr(device_t dev, device_t child, struct resource *r, 1261321936Shselasky void *cookie) 1262321936Shselasky{ 1263321936Shselasky struct pccard_softc *sc = PCCARD_SOFTC(dev); 1264321936Shselasky struct pccard_ivar *ivar = PCCARD_IVAR(child); 1265321936Shselasky struct pccard_function *pf = ivar->pf; 1266321936Shselasky int ret; 1267321936Shselasky 1268321936Shselasky if (pccard_mfc(sc)) { 1269321936Shselasky pccard_ccr_write(pf, PCCARD_CCR_OPTION, 1270321936Shselasky pccard_ccr_read(pf, PCCARD_CCR_OPTION) & 1271321936Shselasky ~PCCARD_CCR_OPTION_IREQ_ENABLE); 1272321936Shselasky } 1273321936Shselasky ret = bus_generic_teardown_intr(dev, child, r, cookie); 1274321936Shselasky if (ret == 0) { 1275321936Shselasky pf->intr_handler = NULL; 1276321936Shselasky pf->intr_handler_arg = NULL; 1277321936Shselasky pf->intr_handler_cookie = NULL; 1278321936Shselasky } 1279321936Shselasky 1280321936Shselasky return (ret); 1281321936Shselasky} 1282321936Shselasky 1283321936Shselaskystatic int 1284321936Shselaskypccard_activate_resource(device_t brdev, device_t child, int type, int rid, 1285321936Shselasky struct resource *r) 1286321936Shselasky{ 1287321936Shselasky struct pccard_ivar *ivar = PCCARD_IVAR(child); 1288321936Shselasky struct pccard_function *pf = ivar->pf; 1289321936Shselasky 1290321936Shselasky switch(type) { 1291321936Shselasky case SYS_RES_IOPORT: 1292321936Shselasky /* 1293321936Shselasky * We need to adjust IOBASE[01] and IOSIZE if we're an MFC 1294321936Shselasky * card. 1295321936Shselasky */ 1296321936Shselasky if (pccard_mfc(pf->sc)) 1297321936Shselasky pccard_mfc_adjust_iobase(pf, rman_get_start(r), 0, 1298321936Shselasky rman_get_size(r)); 1299321936Shselasky break; 1300321936Shselasky default: 1301321936Shselasky break; 1302321936Shselasky } 1303321936Shselasky return (bus_generic_activate_resource(brdev, child, type, rid, r)); 1304321936Shselasky} 1305321936Shselasky 1306321936Shselaskystatic int 1307321936Shselaskypccard_deactivate_resource(device_t brdev, device_t child, int type, 1308321936Shselasky int rid, struct resource *r) 1309321936Shselasky{ 1310321936Shselasky /* XXX undo pccard_activate_resource? XXX */ 1311321936Shselasky return (bus_generic_deactivate_resource(brdev, child, type, rid, r)); 1312321936Shselasky} 1313321936Shselasky 1314321936Shselaskystatic int 1315321936Shselaskypccard_attr_read_impl(device_t brdev, device_t child, uint32_t offset, 1316321936Shselasky uint8_t *val) 1317321936Shselasky{ 1318321936Shselasky struct pccard_ivar *devi = PCCARD_IVAR(child); 1319321936Shselasky struct pccard_function *pf = devi->pf; 1320321936Shselasky 1321321936Shselasky /* 1322321936Shselasky * Optimization. Most of the time, devices want to access 1323321936Shselasky * the same page of the attribute memory that the CCR is in. 1324321936Shselasky * We take advantage of this fact here. 1325321936Shselasky */ 1326321936Shselasky if (offset / PCCARD_MEM_PAGE_SIZE == 1327321936Shselasky pf->ccr_base / PCCARD_MEM_PAGE_SIZE) 1328321936Shselasky *val = bus_space_read_1(pf->pf_ccrt, pf->pf_ccrh, 1329321936Shselasky offset % PCCARD_MEM_PAGE_SIZE); 1330321936Shselasky else { 1331321936Shselasky CARD_SET_MEMORY_OFFSET(brdev, child, pf->ccr_rid, offset, 1332321936Shselasky &offset); 1333321936Shselasky *val = bus_space_read_1(pf->pf_ccrt, pf->pf_ccrh, offset); 1334321936Shselasky CARD_SET_MEMORY_OFFSET(brdev, child, pf->ccr_rid, pf->ccr_base, 1335321936Shselasky &offset); 1336321936Shselasky } 1337321936Shselasky return 0; 1338321936Shselasky} 1339321936Shselasky 1340321936Shselaskystatic int 1341321936Shselaskypccard_attr_write_impl(device_t brdev, device_t child, uint32_t offset, 1342321936Shselasky uint8_t val) 1343321936Shselasky{ 1344321936Shselasky struct pccard_ivar *devi = PCCARD_IVAR(child); 1345321936Shselasky struct pccard_function *pf = devi->pf; 1346321936Shselasky 1347321936Shselasky /* 1348321936Shselasky * Optimization. Most of the time, devices want to access 1349321936Shselasky * the same page of the attribute memory that the CCR is in. 1350321936Shselasky * We take advantage of this fact here. 1351321936Shselasky */ 1352321936Shselasky if (offset / PCCARD_MEM_PAGE_SIZE == 1353321936Shselasky pf->ccr_base / PCCARD_MEM_PAGE_SIZE) 1354321936Shselasky bus_space_write_1(pf->pf_ccrt, pf->pf_ccrh, 1355321936Shselasky offset % PCCARD_MEM_PAGE_SIZE, val); 1356321936Shselasky else { 1357321936Shselasky CARD_SET_MEMORY_OFFSET(brdev, child, pf->ccr_rid, offset, 1358321936Shselasky &offset); 1359321936Shselasky bus_space_write_1(pf->pf_ccrt, pf->pf_ccrh, offset, val); 1360321936Shselasky CARD_SET_MEMORY_OFFSET(brdev, child, pf->ccr_rid, pf->ccr_base, 1361321936Shselasky &offset); 1362321936Shselasky } 1363321936Shselasky 1364321936Shselasky return 0; 1365321936Shselasky} 1366321936Shselasky 1367321936Shselaskystatic int 1368321936Shselaskypccard_ccr_read_impl(device_t brdev, device_t child, uint32_t offset, 1369321936Shselasky uint8_t *val) 1370321936Shselasky{ 1371321936Shselasky struct pccard_ivar *devi = PCCARD_IVAR(child); 1372321936Shselasky 1373321936Shselasky *val = pccard_ccr_read(devi->pf, offset); 1374321936Shselasky device_printf(child, "ccr_read of %#x (%#x) is %#x\n", offset, 1375321936Shselasky devi->pf->pf_ccr_offset, *val); 1376321936Shselasky return 0; 1377321936Shselasky} 1378321936Shselasky 1379321936Shselaskystatic int 1380321936Shselaskypccard_ccr_write_impl(device_t brdev, device_t child, uint32_t offset, 1381321936Shselasky uint8_t val) 1382321936Shselasky{ 1383321936Shselasky struct pccard_ivar *devi = PCCARD_IVAR(child); 1384321936Shselasky struct pccard_function *pf = devi->pf; 1385321936Shselasky 1386321936Shselasky /* 1387321936Shselasky * Can't use pccard_ccr_write since client drivers may access 1388321936Shselasky * registers not contained in the 'mask' if they are non-standard. 1389321936Shselasky */ 1390321936Shselasky device_printf(child, "ccr_write of %#x to %#x (%#x)\n", val, offset, 1391321936Shselasky devi->pf->pf_ccr_offset); 1392321936Shselasky bus_space_write_1(pf->pf_ccrt, pf->pf_ccrh, pf->pf_ccr_offset + offset, 1393321936Shselasky val); 1394321936Shselasky return 0; 1395321936Shselasky} 1396321936Shselasky 1397321936Shselasky 1398321936Shselaskystatic device_method_t pccard_methods[] = { 1399321936Shselasky /* Device interface */ 1400321936Shselasky DEVMETHOD(device_probe, pccard_probe), 1401321936Shselasky DEVMETHOD(device_attach, pccard_attach), 1402321936Shselasky DEVMETHOD(device_detach, pccard_detach), 1403321936Shselasky DEVMETHOD(device_shutdown, bus_generic_shutdown), 1404321936Shselasky DEVMETHOD(device_suspend, pccard_suspend), 1405321936Shselasky DEVMETHOD(device_resume, pccard_resume), 1406321936Shselasky 1407321936Shselasky /* Bus interface */ 1408321936Shselasky DEVMETHOD(bus_print_child, pccard_print_child), 1409321936Shselasky DEVMETHOD(bus_driver_added, pccard_driver_added), 1410321936Shselasky DEVMETHOD(bus_child_detached, pccard_child_detached), 1411321936Shselasky DEVMETHOD(bus_alloc_resource, pccard_alloc_resource), 1412321936Shselasky DEVMETHOD(bus_release_resource, pccard_release_resource), 1413321936Shselasky DEVMETHOD(bus_activate_resource, pccard_activate_resource), 1414321936Shselasky DEVMETHOD(bus_deactivate_resource, pccard_deactivate_resource), 1415321936Shselasky DEVMETHOD(bus_setup_intr, pccard_setup_intr), 1416321936Shselasky DEVMETHOD(bus_teardown_intr, pccard_teardown_intr), 1417321936Shselasky DEVMETHOD(bus_set_resource, pccard_set_resource), 1418321936Shselasky DEVMETHOD(bus_get_resource, pccard_get_resource), 1419321936Shselasky DEVMETHOD(bus_delete_resource, pccard_delete_resource), 1420321936Shselasky DEVMETHOD(bus_probe_nomatch, pccard_probe_nomatch), 1421321936Shselasky DEVMETHOD(bus_read_ivar, pccard_read_ivar), 1422321936Shselasky DEVMETHOD(bus_child_pnpinfo_str, pccard_child_pnpinfo_str), 1423321936Shselasky DEVMETHOD(bus_child_location_str, pccard_child_location_str), 1424321936Shselasky 1425321936Shselasky /* Card Interface */ 1426321936Shselasky DEVMETHOD(card_set_res_flags, pccard_set_res_flags), 1427321936Shselasky DEVMETHOD(card_set_memory_offset, pccard_set_memory_offset), 1428321936Shselasky DEVMETHOD(card_attach_card, pccard_attach_card), 1429321936Shselasky DEVMETHOD(card_detach_card, pccard_detach_card), 1430321936Shselasky DEVMETHOD(card_do_product_lookup, pccard_do_product_lookup), 1431321936Shselasky DEVMETHOD(card_compat_do_probe, pccard_compat_do_probe), 1432321936Shselasky DEVMETHOD(card_compat_do_attach, pccard_compat_do_attach), 1433321936Shselasky DEVMETHOD(card_cis_scan, pccard_scan_cis), 1434321936Shselasky DEVMETHOD(card_attr_read, pccard_attr_read_impl), 1435321936Shselasky DEVMETHOD(card_attr_write, pccard_attr_write_impl), 1436321936Shselasky DEVMETHOD(card_ccr_read, pccard_ccr_read_impl), 1437321936Shselasky DEVMETHOD(card_ccr_write, pccard_ccr_write_impl), 1438321936Shselasky 1439321936Shselasky { 0, 0 } 1440321936Shselasky}; 1441321936Shselasky 1442321936Shselaskystatic driver_t pccard_driver = { 1443321936Shselasky "pccard", 1444321936Shselasky pccard_methods, 1445321936Shselasky sizeof(struct pccard_softc) 1446321936Shselasky}; 1447321936Shselasky 1448321936Shselaskydevclass_t pccard_devclass; 1449321936Shselasky 1450321936Shselasky/* Maybe we need to have a slot device? */ 1451321936ShselaskyDRIVER_MODULE(pccard, pcic, pccard_driver, pccard_devclass, 0, 0); 1452321936ShselaskyDRIVER_MODULE(pccard, cbb, pccard_driver, pccard_devclass, 0, 0); 1453321936ShselaskyMODULE_VERSION(pccard, 1); 1454321936Shselasky