pccard.c revision 67167
166200Simp/* $NetBSD: pcmcia.c,v 1.23 2000/07/28 19:17:02 drochner Exp $ */ 252506Simp/* $FreeBSD: head/sys/dev/pccard/pccard.c 67167 2000-10-15 17:21:50Z imp $ */ 352506Simp 452506Simp/* 552506Simp * Copyright (c) 1997 Marc Horowitz. All rights reserved. 652506Simp * 752506Simp * Redistribution and use in source and binary forms, with or without 852506Simp * modification, are permitted provided that the following conditions 952506Simp * are met: 1052506Simp * 1. Redistributions of source code must retain the above copyright 1152506Simp * notice, this list of conditions and the following disclaimer. 1252506Simp * 2. Redistributions in binary form must reproduce the above copyright 1352506Simp * notice, this list of conditions and the following disclaimer in the 1452506Simp * documentation and/or other materials provided with the distribution. 1552506Simp * 3. All advertising materials mentioning features or use of this software 1652506Simp * must display the following acknowledgement: 1752506Simp * This product includes software developed by Marc Horowitz. 1852506Simp * 4. The name of the author may not be used to endorse or promote products 1952506Simp * derived from this software without specific prior written permission. 2052506Simp * 2152506Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 2252506Simp * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2352506Simp * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2452506Simp * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2552506Simp * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2652506Simp * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2752506Simp * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2852506Simp * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2952506Simp * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 3052506Simp * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3152506Simp */ 3252506Simp 3352506Simp#include <sys/param.h> 3452506Simp#include <sys/systm.h> 3552506Simp#include <sys/malloc.h> 3652506Simp#include <sys/module.h> 3752506Simp#include <sys/kernel.h> 3852506Simp#include <sys/queue.h> 3952506Simp#include <sys/types.h> 4052506Simp 4152506Simp#include <sys/bus.h> 4252506Simp#include <machine/bus.h> 4352506Simp#include <sys/rman.h> 4452506Simp#include <machine/resource.h> 4552506Simp 4652506Simp#include <dev/pccard/pccardreg.h> 4752506Simp#include <dev/pccard/pccardvar.h> 4852506Simp 4955500Simp#include "power_if.h" 5059193Simp#include "card_if.h" 5155500Simp 5255500Simp#define PCCARDDEBUG 5355500Simp 5452506Simp#ifdef PCCARDDEBUG 5555500Simpint pccard_debug = 1; 5652506Simp#define DPRINTF(arg) if (pccard_debug) printf arg 5755500Simp#define DEVPRINTF(arg) if (pccard_debug) device_printf arg 5852506Simp#else 5952506Simp#define DPRINTF(arg) 6055500Simp#define DEVPRINTF(arg) 6152506Simp#endif 6252506Simp 6352506Simp#ifdef PCCARDVERBOSE 6452506Simpint pccard_verbose = 1; 6552506Simp#else 6652506Simpint pccard_verbose = 0; 6752506Simp#endif 6852506Simp 6954250Simpint pccard_print(void *, const char *); 7052506Simp 7152506Simpint 7252506Simppccard_ccr_read(pf, ccr) 7352506Simp struct pccard_function *pf; 7452506Simp int ccr; 7552506Simp{ 7652506Simp return (bus_space_read_1(pf->pf_ccrt, pf->pf_ccrh, 7752506Simp pf->pf_ccr_offset + ccr)); 7852506Simp} 7952506Simp 8052506Simpvoid 8152506Simppccard_ccr_write(pf, ccr, val) 8252506Simp struct pccard_function *pf; 8352506Simp int ccr; 8452506Simp int val; 8552506Simp{ 8652506Simp 8752506Simp if ((pf->ccr_mask) & (1 << (ccr / 2))) { 8852506Simp bus_space_write_1(pf->pf_ccrt, pf->pf_ccrh, 8952506Simp pf->pf_ccr_offset + ccr, val); 9052506Simp } 9152506Simp} 9252506Simp 9359193Simpstatic int 9459193Simppccard_attach_card(device_t dev) 9552506Simp{ 9664850Simp struct pccard_softc *sc = PCCARD_SOFTC(dev); 9752506Simp struct pccard_function *pf; 9865917Simp struct pccard_ivar *ivar; 9961788Simp device_t child; 10052506Simp int attached; 10152506Simp 10255500Simp DEVPRINTF((dev, "pccard_card_attach\n")); 10352506Simp /* 10452506Simp * this is here so that when socket_enable calls gettype, trt happens 10552506Simp */ 10652506Simp STAILQ_INIT(&sc->card.pf_head); 10752506Simp 10855500Simp DEVPRINTF((dev, "chip_socket_enable\n")); 10955500Simp POWER_ENABLE_SOCKET(device_get_parent(dev), dev); 11052506Simp 11155500Simp DEVPRINTF((dev, "read_cis\n")); 11252506Simp pccard_read_cis(sc); 11352506Simp 11455500Simp DEVPRINTF((dev, "check_cis_quirks\n")); 11552506Simp pccard_check_cis_quirks(dev); 11652506Simp 11752506Simp /* 11852506Simp * bail now if the card has no functions, or if there was an error in 11952506Simp * the cis. 12052506Simp */ 12152506Simp 12252506Simp if (sc->card.error) 12352506Simp return (1); 12452506Simp if (STAILQ_EMPTY(&sc->card.pf_head)) 12552506Simp return (1); 12652506Simp 12761788Simp if (1) 12852506Simp pccard_print_cis(dev); 12952506Simp 13052506Simp attached = 0; 13152506Simp 13255500Simp DEVPRINTF((dev, "functions scanning\n")); 13352506Simp STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) { 13452506Simp if (STAILQ_EMPTY(&pf->cfe_head)) 13552506Simp continue; 13652506Simp 13752506Simp pf->sc = sc; 13852506Simp pf->cfe = NULL; 13964927Simp pf->dev = NULL; 14052506Simp } 14165098Simp#if 0 14264850Simp DEVPRINTF((dev, "chip_socket_disable\n")); 14364850Simp POWER_DISABLE_SOCKET(device_get_parent(dev), dev); 14465098Simp#endif 14564850Simp 14652506Simp STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) { 14752506Simp if (STAILQ_EMPTY(&pf->cfe_head)) 14852506Simp continue; 14961788Simp /* 15061788Simp * In NetBSD, the drivers are responsible for activating 15161788Simp * each function of a card. I think that in FreeBSD we 15261788Simp * want to activate them enough for the usual bus_*_resource 15361788Simp * routines will do the right thing. This many mean a 15461788Simp * departure from the current NetBSD model. 15561788Simp * 15661788Simp * This could get really ugly for multifunction cards. But 15761788Simp * it might also just fall out of the FreeBSD resource model. 15861788Simp * 15961788Simp */ 16061788Simp device_printf(dev, "Starting to attach....\n"); 16165917Simp ivar = malloc(sizeof(struct pccard_ivar), M_DEVBUF, M_WAITOK); 16267167Simp bzero(ivar, sizeof *ivar); 16361788Simp child = device_add_child(dev, NULL, -1); 16465917Simp device_set_ivars(child, ivar); 16566847Simp ivar->fcn = pf; 16667167Simp /* 16767167Simp * XXX We might want to move the next two lines into 16867167Simp * XXX the pccard interface layer. For the moment, this 16967167Simp * XXX is OK, but some drivers want to pick the config 17067167Simp * XXX entry to use as well as some address tweaks (mostly 17167167Simp * XXX due to bugs in decode logic that makes some 17267167Simp * XXX addresses illegal or broken). 17367167Simp */ 17465917Simp pccard_function_init(pf); 17561788Simp pccard_function_enable(pf); 17664850Simp device_printf(dev, "pf %p pf->sc %p\n", pf, pf->sc); 17761788Simp if (device_probe_and_attach(child) == 0) { 17852506Simp attached++; 17964927Simp pf->dev = child; 18052506Simp 18155500Simp DEVPRINTF((sc->dev, "function %d CCR at %d " 18267167Simp "offset %x: %x %x %x %x, %x %x %x %x, %x\n", 18367167Simp pf->number, pf->pf_ccr_window, pf->pf_ccr_offset, 18467167Simp pccard_ccr_read(pf, 0x00), 18552506Simp pccard_ccr_read(pf, 0x02), pccard_ccr_read(pf, 0x04), 18652506Simp pccard_ccr_read(pf, 0x06), pccard_ccr_read(pf, 0x0A), 18752506Simp pccard_ccr_read(pf, 0x0C), pccard_ccr_read(pf, 0x0E), 18852506Simp pccard_ccr_read(pf, 0x10), pccard_ccr_read(pf, 0x12))); 18967167Simp } else { 19067167Simp device_delete_child(dev, child); 19152506Simp } 19252506Simp } 19361788Simp return 0; 19452506Simp} 19552506Simp 19659193Simpstatic int 19759193Simppccard_detach_card(device_t dev, int flags) 19852506Simp{ 19964850Simp struct pccard_softc *sc = PCCARD_SOFTC(dev); 20052506Simp struct pccard_function *pf; 20152506Simp 20252506Simp /* 20352506Simp * We are running on either the PCCARD socket's event thread 20452506Simp * or in user context detaching a device by user request. 20552506Simp */ 20652506Simp STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) { 20752506Simp if (STAILQ_FIRST(&pf->cfe_head) == NULL) 20852506Simp continue; 20961788Simp 21061788Simp pccard_function_disable(pf); 21164927Simp if (pf->dev) 21264927Simp device_delete_child(dev, pf->dev); 21352506Simp } 21459193Simp return 0; 21552506Simp} 21652506Simp 21766200Simpconst struct pccard_product * 21866200Simppccard_product_lookup(device_t dev, const struct pccard_product *tab, 21966200Simp size_t ent_size, pccard_product_match_fn matchfn) 22066200Simp{ 22166200Simp const struct pccard_product *ent; 22266200Simp int matches; 22366200Simp u_int32_t fcn; 22466200Simp u_int32_t vendor; 22566200Simp u_int32_t prod; 22666200Simp char *vendorstr; 22766200Simp char *prodstr; 22866200Simp 22966200Simp#ifdef DIAGNOSTIC 23066200Simp if (sizeof *ent > ent_size) 23166200Simp panic("pccard_product_lookup: bogus ent_size %ld", 23266200Simp (long) ent_size); 23366200Simp#endif 23466200Simp if (pccard_get_vendor(dev, &vendor)) 23566200Simp return (NULL); 23666200Simp if (pccard_get_product(dev, &prod)) 23766200Simp return (NULL); 23866200Simp if (pccard_get_function_number(dev, &fcn)) 23966200Simp return (NULL); 24066200Simp if (pccard_get_vendor_str(dev, &vendorstr)) 24166200Simp return (NULL); 24266200Simp if (pccard_get_product_str(dev, &prodstr)) 24366200Simp return (NULL); 24466200Simp for (ent = tab; ent->pp_name != NULL; 24566200Simp ent = (const struct pccard_product *) 24666200Simp ((const char *) ent + ent_size)) { 24766200Simp matches = 1; 24866200Simp if (matches && ent->pp_vendor != PCCARD_VENDOR_ANY && 24966200Simp vendor != ent->pp_vendor) 25066200Simp matches = 0; 25166200Simp if (matches && ent->pp_product != PCCARD_PRODUCT_ANY && 25266200Simp prod != ent->pp_product) 25366200Simp matches = 0; 25466200Simp if (matches && fcn != ent->pp_expfunc) 25566200Simp matches = 0; 25666200Simp if (matches && ent->pp_vendor_str && 25766200Simp strcmp(ent->pp_vendor_str, vendorstr) != 0) 25866200Simp matches = 0; 25966200Simp if (matches && ent->pp_product_str && 26066200Simp strcmp(ent->pp_product_str, prodstr) != 0) 26166200Simp matches = 0; 26266200Simp if (matchfn != NULL) 26366200Simp matches = (*matchfn)(dev, ent, matches); 26466200Simp if (matches) 26566200Simp return (ent); 26666200Simp } 26766200Simp return (NULL); 26866200Simp} 26966200Simp 27059193Simpstatic int 27159193Simppccard_card_gettype(device_t dev, int *type) 27252506Simp{ 27364850Simp struct pccard_softc *sc = PCCARD_SOFTC(dev); 27452506Simp struct pccard_function *pf; 27552506Simp 27652506Simp /* 27752506Simp * set the iftype to memory if this card has no functions (not yet 27852506Simp * probed), or only one function, and that is not initialized yet or 27952506Simp * that is memory. 28052506Simp */ 28152506Simp pf = STAILQ_FIRST(&sc->card.pf_head); 28252506Simp if (pf == NULL || 28352506Simp (STAILQ_NEXT(pf, pf_list) == NULL && 28452506Simp (pf->cfe == NULL || pf->cfe->iftype == PCCARD_IFTYPE_MEMORY))) 28559193Simp *type = PCCARD_IFTYPE_MEMORY; 28652506Simp else 28759193Simp *type = PCCARD_IFTYPE_IO; 28859193Simp return 0; 28952506Simp} 29052506Simp 29152506Simp/* 29252506Simp * Initialize a PCCARD function. May be called as long as the function is 29352506Simp * disabled. 29452506Simp */ 29552506Simpvoid 29665917Simppccard_function_init(struct pccard_function *pf) 29752506Simp{ 29865917Simp struct pccard_config_entry *cfe; 29965917Simp 30052506Simp if (pf->pf_flags & PFF_ENABLED) 30152506Simp panic("pccard_function_init: function is enabled"); 30252506Simp 30352506Simp /* Remember which configuration entry we are using. */ 30465917Simp /* XXX 30565917Simp * need to look for one we can allocate the resources 30665917Simp * and then set them so the alloc_resources work later. 30765917Simp */ 30867167Simp for (cfe = STAILQ_FIRST(&pf->cfe_head); cfe != NULL; 30967167Simp cfe = STAILQ_NEXT(cfe, cfe_list)) { 31067167Simp pf->cfe = cfe; 31167167Simp /* 31267167Simp * XXX Need to try to allocate resources for this cfe and 31367167Simp * XXX if we succeed in getting ALL of them, we will break 31467167Simp * XXX out of the loop and use the reset of the resource 31567167Simp * XXX mechanism to make sure that the values that we get 31667167Simp * XXX here to work later. 31767167Simp */ 31867167Simp printf("%d: f %d type %d iospace %d 0x%lx-0x%lx mask 0x%lx memspace %d 0x%lx-0x%lx irqmask 0x%x\n", 31967167Simp cfe->number, cfe->flags, cfe->iftype, 32067167Simp cfe->num_iospace, cfe->iospace[0].start, 32167167Simp cfe->iospace[0].start + cfe->iospace[0].length - 1, 32267167Simp cfe->iomask, 32367167Simp cfe->num_memspace, cfe->memspace[0].hostaddr, 32467167Simp cfe->memspace[0].hostaddr + cfe->memspace[0].length - 1, 32567167Simp cfe->irqmask); 32667167Simp } 32752506Simp} 32852506Simp 32952506Simp/* Enable a PCCARD function */ 33052506Simpint 33155720Simppccard_function_enable(struct pccard_function *pf) 33252506Simp{ 33352506Simp struct pccard_function *tmp; 33452506Simp int reg; 33555720Simp device_t dev = pf->sc->dev; 33652506Simp 33752506Simp if (pf->cfe == NULL) 33852506Simp panic("pccard_function_enable: function not initialized"); 33952506Simp 34052506Simp /* 34152506Simp * Increase the reference count on the socket, enabling power, if 34252506Simp * necessary. 34352506Simp */ 34452506Simp if (pf->sc->sc_enabled_count++ == 0) 34555720Simp POWER_ENABLE_SOCKET(device_get_parent(dev), dev); 34655720Simp DEVPRINTF((dev, "++enabled_count = %d\n", pf->sc->sc_enabled_count)); 34752506Simp 34852506Simp if (pf->pf_flags & PFF_ENABLED) { 34952506Simp /* 35052506Simp * Don't do anything if we're already enabled. 35152506Simp */ 35252506Simp return (0); 35352506Simp } 35452506Simp 35552506Simp /* 35652506Simp * it's possible for different functions' CCRs to be in the same 35752506Simp * underlying page. Check for that. 35852506Simp */ 35952506Simp STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) { 36052506Simp if ((tmp->pf_flags & PFF_ENABLED) && 36152506Simp (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) && 36252506Simp ((pf->ccr_base + PCCARD_CCR_SIZE) <= 36352506Simp (tmp->ccr_base - tmp->pf_ccr_offset + 36452506Simp tmp->pf_ccr_realsize))) { 36552506Simp pf->pf_ccrt = tmp->pf_ccrt; 36652506Simp pf->pf_ccrh = tmp->pf_ccrh; 36752506Simp pf->pf_ccr_realsize = tmp->pf_ccr_realsize; 36852506Simp 36952506Simp /* 37052506Simp * pf->pf_ccr_offset = (tmp->pf_ccr_offset - 37152506Simp * tmp->ccr_base) + pf->ccr_base; 37252506Simp */ 37352506Simp pf->pf_ccr_offset = 37452506Simp (tmp->pf_ccr_offset + pf->ccr_base) - 37552506Simp tmp->ccr_base; 37652506Simp pf->pf_ccr_window = tmp->pf_ccr_window; 37752506Simp break; 37852506Simp } 37952506Simp } 38052506Simp 38152506Simp if (tmp == NULL) { 38255720Simp pf->ccr_rid = 0; 38355720Simp pf->ccr_res = bus_alloc_resource(dev, SYS_RES_MEMORY, 38465098Simp &pf->ccr_rid, 0xa0000, 0xdffff, 1 << 10, RF_ACTIVE); 38565098Simp if (!pf->ccr_res) { 38665098Simp DEVPRINTF((dev, "ccr_res == 0\n")); 38752506Simp goto bad; 38865098Simp } 38961788Simp CARD_SET_RES_FLAGS(device_get_parent(dev), dev, SYS_RES_MEMORY, 39061788Simp pf->ccr_rid, PCCARD_A_MEM_ATTR); 39165098Simp CARD_SET_MEMORY_OFFSET(device_get_parent(dev), dev, 39265098Simp pf->ccr_rid, (pf->ccr_rid >> 10) << 10); 39355720Simp pf->pf_ccrt = rman_get_bustag(pf->ccr_res); 39455720Simp pf->pf_ccrh = rman_get_bushandle(pf->ccr_res); 39555720Simp pf->pf_ccr_offset = rman_get_start(pf->ccr_res); 39655720Simp pf->pf_ccr_realsize = 1; 39752506Simp } 39852506Simp 39952506Simp reg = (pf->cfe->number & PCCARD_CCR_OPTION_CFINDEX); 40052506Simp reg |= PCCARD_CCR_OPTION_LEVIREQ; 40152506Simp if (pccard_mfc(pf->sc)) { 40252506Simp reg |= (PCCARD_CCR_OPTION_FUNC_ENABLE | 40352506Simp PCCARD_CCR_OPTION_ADDR_DECODE); 40467167Simp /* 40567167Simp * XXX Need to enable PCCARD_CCR_OPTION_IRQ_ENABLE if 40667167Simp * XXX we have an interrupt handler, but we don't know that 40767167Simp * XXX at this point. 40867167Simp */ 40967167Simp#if 0 41052506Simp if (pf->ih_fct) 41152506Simp reg |= PCCARD_CCR_OPTION_IREQ_ENABLE; 41267167Simp#endif 41352506Simp } 41452506Simp pccard_ccr_write(pf, PCCARD_CCR_OPTION, reg); 41552506Simp 41652506Simp reg = 0; 41752506Simp if ((pf->cfe->flags & PCCARD_CFE_IO16) == 0) 41852506Simp reg |= PCCARD_CCR_STATUS_IOIS8; 41952506Simp if (pf->cfe->flags & PCCARD_CFE_AUDIO) 42052506Simp reg |= PCCARD_CCR_STATUS_AUDIO; 42152506Simp pccard_ccr_write(pf, PCCARD_CCR_STATUS, reg); 42252506Simp 42352506Simp pccard_ccr_write(pf, PCCARD_CCR_SOCKETCOPY, 0); 42452506Simp 42552506Simp if (pccard_mfc(pf->sc)) { 42652506Simp long tmp, iosize; 42752506Simp 42852506Simp tmp = pf->pf_mfc_iomax - pf->pf_mfc_iobase; 42952506Simp /* round up to nearest (2^n)-1 */ 43052506Simp for (iosize = 1; iosize < tmp; iosize <<= 1) 43152506Simp ; 43252506Simp iosize--; 43352506Simp 43452506Simp pccard_ccr_write(pf, PCCARD_CCR_IOBASE0, 43552506Simp pf->pf_mfc_iobase & 0xff); 43652506Simp pccard_ccr_write(pf, PCCARD_CCR_IOBASE1, 43752506Simp (pf->pf_mfc_iobase >> 8) & 0xff); 43852506Simp pccard_ccr_write(pf, PCCARD_CCR_IOBASE2, 0); 43952506Simp pccard_ccr_write(pf, PCCARD_CCR_IOBASE3, 0); 44052506Simp 44152506Simp pccard_ccr_write(pf, PCCARD_CCR_IOSIZE, iosize); 44252506Simp } 44352506Simp 44452506Simp#ifdef PCCARDDEBUG 44552506Simp if (pccard_debug) { 44652506Simp STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) { 44755500Simp device_printf(tmp->sc->dev, 44855500Simp "function %d CCR at %d offset %x: " 44955500Simp "%x %x %x %x, %x %x %x %x, %x\n", 45055500Simp tmp->number, tmp->pf_ccr_window, 45155500Simp tmp->pf_ccr_offset, 45255500Simp pccard_ccr_read(tmp, 0x00), 45355500Simp pccard_ccr_read(tmp, 0x02), 45455500Simp pccard_ccr_read(tmp, 0x04), 45555500Simp pccard_ccr_read(tmp, 0x06), 45655500Simp pccard_ccr_read(tmp, 0x0A), 45755500Simp pccard_ccr_read(tmp, 0x0C), 45855500Simp pccard_ccr_read(tmp, 0x0E), 45955500Simp pccard_ccr_read(tmp, 0x10), 46055500Simp pccard_ccr_read(tmp, 0x12)); 46152506Simp } 46252506Simp } 46352506Simp#endif 46452506Simp pf->pf_flags |= PFF_ENABLED; 46552506Simp return (0); 46652506Simp 46752506Simp bad: 46852506Simp /* 46952506Simp * Decrement the reference count, and power down the socket, if 47052506Simp * necessary. 47152506Simp */ 47252506Simp if (--pf->sc->sc_enabled_count == 0) 47355720Simp POWER_DISABLE_SOCKET(device_get_parent(dev), dev); 47465098Simp DEVPRINTF((dev, "bad --enabled_count = %d\n", pf->sc->sc_enabled_count)); 47552506Simp 47652506Simp return (1); 47752506Simp} 47852506Simp 47952506Simp/* Disable PCCARD function. */ 48052506Simpvoid 48155720Simppccard_function_disable(struct pccard_function *pf) 48252506Simp{ 48352506Simp struct pccard_function *tmp; 48455720Simp device_t dev = pf->sc->dev; 48552506Simp 48652506Simp if (pf->cfe == NULL) 48761788Simp panic("pccard_function_disable: function not initialized"); 48852506Simp 48952506Simp if ((pf->pf_flags & PFF_ENABLED) == 0) { 49052506Simp /* 49152506Simp * Don't do anything if we're already disabled. 49252506Simp */ 49352506Simp return; 49452506Simp } 49552506Simp 49652506Simp /* 49752506Simp * it's possible for different functions' CCRs to be in the same 49852506Simp * underlying page. Check for that. Note we mark us as disabled 49952506Simp * first to avoid matching ourself. 50052506Simp */ 50152506Simp 50252506Simp pf->pf_flags &= ~PFF_ENABLED; 50352506Simp STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) { 50452506Simp if ((tmp->pf_flags & PFF_ENABLED) && 50552506Simp (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) && 50652506Simp ((pf->ccr_base + PCCARD_CCR_SIZE) <= 50752506Simp (tmp->ccr_base - tmp->pf_ccr_offset + tmp->pf_ccr_realsize))) 50852506Simp break; 50952506Simp } 51052506Simp 51152506Simp /* Not used by anyone else; unmap the CCR. */ 51252506Simp if (tmp == NULL) { 51355720Simp bus_release_resource(dev, SYS_RES_MEMORY, pf->ccr_rid, 51455720Simp pf->ccr_res); 51555720Simp pf->ccr_res = NULL; 51652506Simp } 51752506Simp 51852506Simp /* 51952506Simp * Decrement the reference count, and power down the socket, if 52052506Simp * necessary. 52152506Simp */ 52252506Simp if (--pf->sc->sc_enabled_count == 0) 52355720Simp POWER_DISABLE_SOCKET(device_get_parent(dev), dev); 52455720Simp DEVPRINTF((dev, "--enabled_count = %d\n", pf->sc->sc_enabled_count)); 52552506Simp} 52652506Simp 52755720Simp#if 0 52855720Simp/* XXX These functions are needed, but not like this XXX */ 52952506Simpint 53055720Simppccard_io_map(struct pccard_function *pf, int width, bus_addr_t offset, 53155720Simp bus_size_t size, struct pccard_io_handle *pcihp, int *windowp) 53252506Simp{ 53352506Simp int reg; 53452506Simp 53567167Simp if (pccard_chip_io_map(pf->sc->pct, pf->sc->pch, width, offset, size, 53667167Simp pcihp, windowp)) 53752506Simp return (1); 53852506Simp 53952506Simp /* 54052506Simp * XXX in the multifunction multi-iospace-per-function case, this 54152506Simp * needs to cooperate with io_alloc to make sure that the spaces 54252506Simp * don't overlap, and that the ccr's are set correctly 54352506Simp */ 54452506Simp 54552506Simp if (pccard_mfc(pf->sc)) { 54652506Simp long tmp, iosize; 54752506Simp 54852506Simp if (pf->pf_mfc_iomax == 0) { 54952506Simp pf->pf_mfc_iobase = pcihp->addr + offset; 55052506Simp pf->pf_mfc_iomax = pf->pf_mfc_iobase + size; 55152506Simp } else { 55252506Simp /* this makes the assumption that nothing overlaps */ 55352506Simp if (pf->pf_mfc_iobase > pcihp->addr + offset) 55452506Simp pf->pf_mfc_iobase = pcihp->addr + offset; 55552506Simp if (pf->pf_mfc_iomax < pcihp->addr + offset + size) 55652506Simp pf->pf_mfc_iomax = pcihp->addr + offset + size; 55752506Simp } 55852506Simp 55952506Simp tmp = pf->pf_mfc_iomax - pf->pf_mfc_iobase; 56052506Simp /* round up to nearest (2^n)-1 */ 56152506Simp for (iosize = 1; iosize >= tmp; iosize <<= 1) 56252506Simp ; 56352506Simp iosize--; 56452506Simp 56555720Simp pccard_ccr_write(pf, PCCARD_CCR_IOBASE0, 56655720Simp pf->pf_mfc_iobase & 0xff); 56752506Simp pccard_ccr_write(pf, PCCARD_CCR_IOBASE1, 56855720Simp (pf->pf_mfc_iobase >> 8) & 0xff); 56952506Simp pccard_ccr_write(pf, PCCARD_CCR_IOBASE2, 0); 57052506Simp pccard_ccr_write(pf, PCCARD_CCR_IOBASE3, 0); 57152506Simp 57252506Simp pccard_ccr_write(pf, PCCARD_CCR_IOSIZE, iosize); 57352506Simp 57452506Simp reg = pccard_ccr_read(pf, PCCARD_CCR_OPTION); 57552506Simp reg |= PCCARD_CCR_OPTION_ADDR_DECODE; 57652506Simp pccard_ccr_write(pf, PCCARD_CCR_OPTION, reg); 57752506Simp } 57852506Simp return (0); 57952506Simp} 58052506Simp 58152506Simpvoid 58255720Simppccard_io_unmap(struct pccard_function *pf, int window) 58352506Simp{ 58452506Simp 58552506Simp pccard_chip_io_unmap(pf->sc->pct, pf->sc->pch, window); 58652506Simp 58752506Simp /* XXX Anything for multi-function cards? */ 58852506Simp} 58952506Simp#endif 59052506Simp 59166058Simp/* 59266058Simp * simulate the old "probe" routine. In the new world order, the driver 59366058Simp * needs to grab devices while in the old they were assigned to the device by 59466058Simp * the pccardd process. These symbols are exported to the upper layers. 59566058Simp */ 59666058Simpint 59766058Simppccard_compat_probe(device_t dev) 59866058Simp{ 59966058Simp return (CARD_COMPAT_MATCH(dev)); 60066058Simp} 60166058Simp 60266058Simpint 60366058Simppccard_compat_attach(device_t dev) 60466058Simp{ 60566058Simp int err; 60666058Simp 60766058Simp err = CARD_COMPAT_PROBE(dev); 60866058Simp if (err == 0) 60966058Simp err = CARD_COMPAT_ATTACH(dev); 61066058Simp return (err); 61166058Simp} 61266058Simp 61353873Simp#define PCCARD_NPORT 2 61453873Simp#define PCCARD_NMEM 5 61553873Simp#define PCCARD_NIRQ 1 61653873Simp#define PCCARD_NDRQ 0 61753873Simp 61852506Simpstatic int 61952506Simppccard_add_children(device_t dev, int busno) 62052506Simp{ 62159193Simp /* Call parent to scan for any current children */ 62252506Simp return 0; 62352506Simp} 62452506Simp 62552506Simpstatic int 62652506Simppccard_probe(device_t dev) 62752506Simp{ 62852506Simp device_set_desc(dev, "PC Card bus -- newconfig version"); 62952506Simp return pccard_add_children(dev, device_get_unit(dev)); 63052506Simp} 63152506Simp 63259193Simpstatic int 63359193Simppccard_attach(device_t dev) 63459193Simp{ 63564850Simp struct pccard_softc *sc = PCCARD_SOFTC(dev); 63661788Simp 63759193Simp sc->dev = dev; 63861788Simp sc->sc_enabled_count = 0; 63964850Simp DEVPRINTF((dev, "pccard_attach %p\n", dev)); 64059193Simp return bus_generic_attach(dev); 64159193Simp} 64259193Simp 64353873Simpstatic void 64453873Simppccard_print_resources(struct resource_list *rl, const char *name, int type, 64553873Simp int count, const char *format) 64653873Simp{ 64753873Simp struct resource_list_entry *rle; 64853873Simp int printed; 64953873Simp int i; 65053873Simp 65153873Simp printed = 0; 65253873Simp for (i = 0; i < count; i++) { 65353873Simp rle = resource_list_find(rl, type, i); 65453873Simp if (rle) { 65553873Simp if (printed == 0) 65653873Simp printf(" %s ", name); 65753873Simp else if (printed > 0) 65853873Simp printf(","); 65953873Simp printed++; 66053873Simp printf(format, rle->start); 66153873Simp if (rle->count > 1) { 66253873Simp printf("-"); 66353873Simp printf(format, rle->start + rle->count - 1); 66453873Simp } 66553873Simp } else if (i > 3) { 66653873Simp /* check the first few regardless */ 66753873Simp break; 66853873Simp } 66953873Simp } 67053873Simp} 67153873Simp 67253873Simpstatic int 67353873Simppccard_print_child(device_t dev, device_t child) 67453873Simp{ 67566847Simp struct pccard_ivar *devi = PCCARD_IVAR(child); 67653873Simp struct resource_list *rl = &devi->resources; 67753873Simp int retval = 0; 67853873Simp 67953873Simp retval += bus_print_child_header(dev, child); 68053873Simp retval += printf(" at"); 68153873Simp 68253873Simp if (devi) { 68353873Simp pccard_print_resources(rl, "port", SYS_RES_IOPORT, 68453873Simp PCCARD_NPORT, "%#lx"); 68553873Simp pccard_print_resources(rl, "iomem", SYS_RES_MEMORY, 68653873Simp PCCARD_NMEM, "%#lx"); 68753873Simp pccard_print_resources(rl, "irq", SYS_RES_IRQ, PCCARD_NIRQ, 68853873Simp "%ld"); 68953873Simp pccard_print_resources(rl, "drq", SYS_RES_DRQ, PCCARD_NDRQ, 69053873Simp "%ld"); 69153873Simp } 69253873Simp 69353873Simp retval += bus_print_child_footer(dev, child); 69453873Simp 69553873Simp return (retval); 69653873Simp} 69753873Simp 69853873Simpstatic int 69953873Simppccard_set_resource(device_t dev, device_t child, int type, int rid, 70053873Simp u_long start, u_long count) 70153873Simp{ 70266847Simp struct pccard_ivar *devi = PCCARD_IVAR(child); 70353873Simp struct resource_list *rl = &devi->resources; 70453873Simp 70553873Simp if (type != SYS_RES_IOPORT && type != SYS_RES_MEMORY 70653873Simp && type != SYS_RES_IRQ && type != SYS_RES_DRQ) 70753873Simp return EINVAL; 70853873Simp if (rid < 0) 70953873Simp return EINVAL; 71053873Simp if (type == SYS_RES_IOPORT && rid >= PCCARD_NPORT) 71153873Simp return EINVAL; 71253873Simp if (type == SYS_RES_MEMORY && rid >= PCCARD_NMEM) 71353873Simp return EINVAL; 71453873Simp if (type == SYS_RES_IRQ && rid >= PCCARD_NIRQ) 71553873Simp return EINVAL; 71653873Simp if (type == SYS_RES_DRQ && rid >= PCCARD_NDRQ) 71753873Simp return EINVAL; 71853873Simp 71953873Simp resource_list_add(rl, type, rid, start, start + count - 1, count); 72053873Simp 72153873Simp return 0; 72253873Simp} 72353873Simp 72453873Simpstatic int 72553873Simppccard_get_resource(device_t dev, device_t child, int type, int rid, 72653873Simp u_long *startp, u_long *countp) 72753873Simp{ 72866847Simp struct pccard_ivar *devi = PCCARD_IVAR(child); 72953873Simp struct resource_list *rl = &devi->resources; 73053873Simp struct resource_list_entry *rle; 73153873Simp 73253873Simp rle = resource_list_find(rl, type, rid); 73353873Simp if (!rle) 73453873Simp return ENOENT; 73553873Simp 73653873Simp if (startp) 73753873Simp *startp = rle->start; 73853873Simp if (countp) 73953873Simp *countp = rle->count; 74053873Simp 74153873Simp return 0; 74253873Simp} 74353873Simp 74453873Simpstatic void 74553873Simppccard_delete_resource(device_t dev, device_t child, int type, int rid) 74653873Simp{ 74766847Simp struct pccard_ivar *devi = PCCARD_IVAR(child); 74853873Simp struct resource_list *rl = &devi->resources; 74953873Simp resource_list_delete(rl, type, rid); 75053873Simp} 75153873Simp 75259193Simpstatic int 75359193Simppccard_set_res_flags(device_t dev, device_t child, int type, int rid, 75459193Simp u_int32_t flags) 75559193Simp{ 75659193Simp return CARD_SET_RES_FLAGS(device_get_parent(dev), child, type, 75759193Simp rid, flags); 75859193Simp} 75959193Simp 76059193Simpstatic int 76159193Simppccard_set_memory_offset(device_t dev, device_t child, int rid, 76259193Simp u_int32_t offset) 76359193Simp{ 76459193Simp return CARD_SET_MEMORY_OFFSET(device_get_parent(dev), child, rid, 76559193Simp offset); 76659193Simp} 76759193Simp 76866058Simpstatic int 76966058Simppccard_read_ivar(device_t bus, device_t child, int which, u_char *result) 77066058Simp{ 77166847Simp struct pccard_ivar *devi = PCCARD_IVAR(child); 77266779Simp struct pccard_function *func = devi->fcn; 77366779Simp struct pccard_softc *sc = PCCARD_SOFTC(bus); 77466779Simp 77566058Simp /* PCCARD_IVAR_ETHADDR unhandled from oldcard */ 77666779Simp switch (which) { 77766779Simp default: 77866779Simp case PCCARD_IVAR_ETHADDR: 77966779Simp return (ENOENT); 78066779Simp break; 78166779Simp case PCCARD_IVAR_VENDOR: 78266779Simp *(u_int32_t *) result = sc->card.manufacturer; 78366779Simp break; 78466779Simp case PCCARD_IVAR_PRODUCT: 78566779Simp *(u_int32_t *) result = sc->card.product; 78666779Simp break; 78766779Simp case PCCARD_IVAR_FUNCTION_NUMBER: 78866847Simp if (!func) { 78966847Simp device_printf(bus, "No function number, bug!\n"); 79066847Simp return (ENOENT); 79166847Simp } 79266847Simp *(u_int32_t *) result = func->number; 79366779Simp break; 79466779Simp case PCCARD_IVAR_VENDOR_STR: 79566779Simp *(char **) result = sc->card.cis1_info[0]; 79666779Simp break; 79766779Simp case PCCARD_IVAR_PRODUCT_STR: 79866779Simp *(char **) result = sc->card.cis1_info[1]; 79966779Simp break; 80066779Simp case PCCARD_IVAR_CIS3_STR: 80166779Simp *(char **) result = sc->card.cis1_info[2]; 80266779Simp break; 80367167Simp case PCCARD_IVAR_CIS4_STR: 80467167Simp *(char **) result = sc->card.cis1_info[2]; 80567167Simp break; 80666779Simp } 80766779Simp return (0); 80866058Simp} 80966058Simp 81066779Simpstatic void 81166779Simppccard_driver_added(device_t dev, driver_t *driver) 81266779Simp{ 81367167Simp /* 81467167Simp * XXX eventually we need to attach stuff when we know we 81567167Simp * XXX have kids. For now we do nothing because we normally 81667167Simp * XXX add children ourselves. We don't want to necessarily 81767167Simp * XXX force a reprobe. 81867167Simp */ 81966779Simp} 82066058Simp 82152506Simpstatic device_method_t pccard_methods[] = { 82252506Simp /* Device interface */ 82352506Simp DEVMETHOD(device_probe, pccard_probe), 82459193Simp DEVMETHOD(device_attach, pccard_attach), 82561788Simp DEVMETHOD(device_detach, bus_generic_detach), 82652506Simp DEVMETHOD(device_shutdown, bus_generic_shutdown), 82752506Simp DEVMETHOD(device_suspend, bus_generic_suspend), 82852506Simp DEVMETHOD(device_resume, bus_generic_resume), 82952506Simp 83052506Simp /* Bus interface */ 83152506Simp DEVMETHOD(bus_print_child, pccard_print_child), 83266779Simp DEVMETHOD(bus_driver_added, pccard_driver_added), 83353873Simp DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), 83453873Simp DEVMETHOD(bus_release_resource, bus_generic_release_resource), 83552506Simp DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 83652506Simp DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 83752506Simp DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 83852506Simp DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 83952506Simp DEVMETHOD(bus_set_resource, pccard_set_resource), 84052506Simp DEVMETHOD(bus_get_resource, pccard_get_resource), 84152506Simp DEVMETHOD(bus_delete_resource, pccard_delete_resource), 84266058Simp DEVMETHOD(bus_read_ivar, pccard_read_ivar), 84352506Simp 84459193Simp /* Card Interface */ 84559193Simp DEVMETHOD(card_set_res_flags, pccard_set_res_flags), 84659193Simp DEVMETHOD(card_set_memory_offset, pccard_set_memory_offset), 84759193Simp DEVMETHOD(card_get_type, pccard_card_gettype), 84859193Simp DEVMETHOD(card_attach_card, pccard_attach_card), 84959193Simp DEVMETHOD(card_detach_card, pccard_detach_card), 85059193Simp 85152506Simp { 0, 0 } 85252506Simp}; 85352506Simp 85452506Simpstatic driver_t pccard_driver = { 85552506Simp "pccard", 85652506Simp pccard_methods, 85764850Simp sizeof(struct pccard_softc) 85852506Simp}; 85952506Simp 86052506Simpdevclass_t pccard_devclass; 86152506Simp 86253873SimpDRIVER_MODULE(pccard, pcic, pccard_driver, pccard_devclass, 0, 0); 86352506SimpDRIVER_MODULE(pccard, pc98pcic, pccard_driver, pccard_devclass, 0, 0); 86452506SimpDRIVER_MODULE(pccard, pccbb, pccard_driver, pccard_devclass, 0, 0); 86553873SimpDRIVER_MODULE(pccard, tcic, pccard_driver, pccard_devclass, 0, 0); 86664927SimpMODULE_VERSION(pccard, 1); 86764927SimpMODULE_DEPEND(pccard, pcic, 1, 1, 1); 868