123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921 |
- /* $OpenBSD: pcmcia.c,v 1.46 2012/10/08 21:47:50 deraadt Exp $ */
- /* $NetBSD: pcmcia.c,v 1.9 1998/08/13 02:10:55 eeh Exp $ */
- /*
- * Copyright (c) 1997 Marc Horowitz. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Marc Horowitz.
- * 4. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- #include <sys/types.h>
- #include <sys/param.h>
- #include <sys/systm.h>
- #include <sys/device.h>
- #include <sys/malloc.h>
- #include <dev/pcmcia/pcmciareg.h>
- #include <dev/pcmcia/pcmciachip.h>
- #include <dev/pcmcia/pcmciavar.h>
- #ifdef PCMCIADEBUG
- #define DPRINTF(arg) printf arg
- #else
- #define DPRINTF(arg)
- #endif
- #ifdef PCMCIAVERBOSE
- int pcmcia_verbose = 1;
- #else
- int pcmcia_verbose = 0;
- #endif
- int pcmcia_match(struct device *, void *, void *);
- int pcmcia_submatch(struct device *, void *, void *);
- void pcmcia_attach(struct device *, struct device *, void *);
- int pcmcia_activate(struct device *, int);
- int pcmcia_print(void *, const char *);
- void pcmcia_card_detach_notify(struct device *, void *);
- static inline void pcmcia_socket_enable(pcmcia_chipset_tag_t,
- pcmcia_chipset_handle_t *);
- static inline void pcmcia_socket_disable(pcmcia_chipset_tag_t,
- pcmcia_chipset_handle_t *);
- int pcmcia_card_intr(void *);
- struct cfdriver pcmcia_cd = {
- NULL, "pcmcia", DV_DULL
- };
- struct cfattach pcmcia_ca = {
- sizeof(struct pcmcia_softc), pcmcia_match, pcmcia_attach, NULL,
- pcmcia_activate
- };
- int
- pcmcia_ccr_read(pf, ccr)
- struct pcmcia_function *pf;
- int ccr;
- {
- return (bus_space_read_1(pf->pf_ccrt, pf->pf_ccrh,
- pf->pf_ccr_offset + ccr));
- }
- void
- pcmcia_ccr_write(pf, ccr, val)
- struct pcmcia_function *pf;
- int ccr;
- int val;
- {
- if ((pf->ccr_mask) & (1 << (ccr / 2))) {
- bus_space_write_1(pf->pf_ccrt, pf->pf_ccrh,
- pf->pf_ccr_offset + ccr, val);
- }
- }
- int
- pcmcia_match(parent, match, aux)
- struct device *parent;
- void *match, *aux;
- {
- struct cfdata *cf = match;
- struct pcmciabus_attach_args *paa = aux;
- if (strcmp(paa->paa_busname, cf->cf_driver->cd_name))
- return 0;
- /* If the autoconfiguration got this far, there's a socket here. */
- return (1);
- }
- void
- pcmcia_attach(parent, self, aux)
- struct device *parent, *self;
- void *aux;
- {
- struct pcmciabus_attach_args *paa = aux;
- struct pcmcia_softc *sc = (struct pcmcia_softc *) self;
- printf("\n");
- sc->pct = paa->pct;
- sc->pch = paa->pch;
- sc->iobase = paa->iobase;
- sc->iosize = paa->iosize;
- sc->ih = NULL;
- }
- int
- pcmcia_activate(struct device *self, int act)
- {
- struct pcmcia_softc *sc = (struct pcmcia_softc *)self;
- struct pcmcia_function *pf;
- switch (act) {
- case DVACT_QUIESCE:
- case DVACT_SUSPEND:
- case DVACT_POWERDOWN:
- case DVACT_RESUME:
- for (pf = SIMPLEQ_FIRST(&sc->card.pf_head); pf != NULL;
- pf = SIMPLEQ_NEXT(pf, pf_list)) {
- if (SIMPLEQ_FIRST(&pf->cfe_head) == NULL ||
- pf->child == NULL)
- continue;
- config_suspend(pf->child, act);
- }
- break;
- case DVACT_DEACTIVATE:
- for (pf = SIMPLEQ_FIRST(&sc->card.pf_head); pf != NULL;
- pf = SIMPLEQ_NEXT(pf, pf_list)) {
- if (SIMPLEQ_FIRST(&pf->cfe_head) == NULL ||
- pf->child == NULL)
- continue;
- config_deactivate(pf->child);
- }
- break;
- }
- return (0);
- }
- int
- pcmcia_card_attach(dev)
- struct device *dev;
- {
- struct pcmcia_softc *sc = (struct pcmcia_softc *) dev;
- struct pcmcia_function *pf;
- struct pcmcia_attach_args paa;
- int attached;
- /*
- * this is here so that when socket_enable calls gettype, trt happens
- */
- SIMPLEQ_FIRST(&sc->card.pf_head) = NULL;
- pcmcia_chip_socket_enable(sc->pct, sc->pch);
- pcmcia_read_cis(sc);
- pcmcia_chip_socket_disable(sc->pct, sc->pch);
- pcmcia_check_cis_quirks(sc);
- /*
- * Bail now if there was an error in the CIS.
- */
- if (sc->card.error)
- return (1);
- #if 0
- if (SIMPLEQ_EMPTY(&sc->card.pf_head))
- return (1);
- #endif
- if (pcmcia_verbose)
- pcmcia_print_cis(sc);
- /*
- * If there was no function, this might be CIS-less card we still
- * want to probe. Fixup a function element for it.
- */
- if (SIMPLEQ_FIRST(&sc->card.pf_head) == NULL) {
- pf = malloc(sizeof *pf, M_DEVBUF, M_NOWAIT | M_ZERO);
- if (pf == NULL)
- panic("pcmcia_card_attach");
- pf->number = 0;
- pf->pf_flags = PFF_FAKE;
- pf->last_config_index = -1;
- SIMPLEQ_INIT(&pf->cfe_head);
- SIMPLEQ_INSERT_TAIL(&sc->card.pf_head, pf, pf_list);
- }
- attached = 0;
- for (pf = SIMPLEQ_FIRST(&sc->card.pf_head); pf != NULL;
- pf = SIMPLEQ_NEXT(pf, pf_list)) {
- pf->sc = sc;
- pf->child = NULL;
- pf->cfe = NULL;
- pf->ih_fct = NULL;
- pf->ih_arg = NULL;
- }
- for (pf = SIMPLEQ_FIRST(&sc->card.pf_head); pf != NULL;
- pf = SIMPLEQ_NEXT(pf, pf_list)) {
- paa.manufacturer = sc->card.manufacturer;
- paa.product = sc->card.product;
- paa.card = &sc->card;
- paa.pf = pf;
- pf->child = config_found_sm(&sc->dev, &paa, pcmcia_print,
- pcmcia_submatch);
- if (pf->child) {
- attached++;
- if ((pf->pf_flags & (PFF_FAKE | PFF_ENABLED)) ==
- PFF_ENABLED)
- DPRINTF(("%s: function %d CCR at %d offset %lx"
- ": %x %x %x %x, %x %x %x %x, %x\n",
- sc->dev.dv_xname, pf->number,
- pf->pf_ccr_window, pf->pf_ccr_offset,
- pcmcia_ccr_read(pf, 0x00),
- pcmcia_ccr_read(pf, 0x02),
- pcmcia_ccr_read(pf, 0x04),
- pcmcia_ccr_read(pf, 0x06),
- pcmcia_ccr_read(pf, 0x0A),
- pcmcia_ccr_read(pf, 0x0C),
- pcmcia_ccr_read(pf, 0x0E),
- pcmcia_ccr_read(pf, 0x10),
- pcmcia_ccr_read(pf, 0x12)));
- }
- }
- return (attached ? 0 : 1);
- }
- void
- pcmcia_card_detach(dev, flags)
- struct device *dev;
- int flags; /* DETACH_* flags */
- {
- struct pcmcia_softc *sc = (struct pcmcia_softc *) dev;
- struct pcmcia_function *pf;
- int error;
- /*
- * We are running on either the PCMCIA socket's event thread
- * or in user context detaching a device by user request.
- */
- for (pf = SIMPLEQ_FIRST(&sc->card.pf_head); pf != NULL;
- pf = SIMPLEQ_NEXT(pf, pf_list)) {
- if (SIMPLEQ_FIRST(&pf->cfe_head) == NULL)
- continue;
- if (pf->child == NULL)
- continue;
- DPRINTF(("%s: detaching %s (function %d)\n",
- sc->dev.dv_xname, pf->child->dv_xname, pf->number));
- if ((error = config_detach(pf->child, flags)) != 0) {
- printf("%s: error %d detaching %s (function %d)\n",
- sc->dev.dv_xname, error, pf->child->dv_xname,
- pf->number);
- } else
- pf->child = NULL;
- }
- }
- void
- pcmcia_card_deactivate(dev)
- struct device *dev;
- {
- struct pcmcia_softc *sc = (struct pcmcia_softc *) dev;
- struct pcmcia_function *pf;
- /*
- * We're in the chip's card removal interrupt handler.
- * Deactivate the child driver. The PCMCIA socket's
- * event thread will run later to finish the detach.
- */
- for (pf = SIMPLEQ_FIRST(&sc->card.pf_head); pf != NULL;
- pf = SIMPLEQ_NEXT(pf, pf_list)) {
- if (SIMPLEQ_FIRST(&pf->cfe_head) == NULL ||
- pf->child == NULL)
- continue;
- DPRINTF(("%s: deactivating %s (function %d)\n",
- sc->dev.dv_xname, pf->child->dv_xname, pf->number));
- config_deactivate(pf->child);
- }
- }
- int
- pcmcia_submatch(parent, match, aux)
- struct device *parent;
- void *match, *aux;
- {
- struct cfdata *cf = match;
- struct pcmcia_attach_args *paa = aux;
- if (cf->cf_loc[0 /* PCMCIACF_FUNCTION */] !=
- -1 /* PCMCIACF_FUNCTION_DEFAULT */ &&
- cf->cf_loc[0 /* PCMCIACF_FUNCTION */] != paa->pf->number)
- return (0);
- return ((*cf->cf_attach->ca_match)(parent, cf, aux));
- }
- int
- pcmcia_print(arg, pnp)
- void *arg;
- const char *pnp;
- {
- struct pcmcia_attach_args *pa = arg;
- struct pcmcia_softc *sc = pa->pf->sc;
- struct pcmcia_card *card = &sc->card;
- int i;
- if (pnp) {
- for (i = 0; i < 4 && card->cis1_info[i]; i++)
- printf("%s%s", i ? ", " : "\"", card->cis1_info[i]);
- if (i != 0)
- printf("\"");
- if (card->manufacturer != PCMCIA_VENDOR_INVALID &&
- card->product != PCMCIA_PRODUCT_INVALID) {
- if (i != 0)
- printf(" ");
- printf("(");
- if (card->manufacturer != PCMCIA_VENDOR_INVALID)
- printf("manufacturer 0x%x%s",
- card->manufacturer,
- card->product == PCMCIA_PRODUCT_INVALID ?
- "" : ", ");
- if (card->product != PCMCIA_PRODUCT_INVALID)
- printf("product 0x%x",
- card->product);
- printf(")");
- }
- if (i != 0)
- printf(" ");
- printf("at %s", pnp);
- }
- printf(" function %d", pa->pf->number);
- if (!pnp) {
- for (i = 0; i < 3 && card->cis1_info[i]; i++)
- printf("%s%s", i ? ", " : " \"", card->cis1_info[i]);
- if (i != 0)
- printf("\"");
- }
- return (UNCONF);
- }
- int
- pcmcia_card_gettype(dev)
- struct device *dev;
- {
- struct pcmcia_softc *sc = (struct pcmcia_softc *)dev;
- struct pcmcia_function *pf;
- /*
- * Set the iftype to memory if this card has no functions (not yet
- * probed), or only one function, and that is not initialized yet or
- * that is memory.
- */
- pf = SIMPLEQ_FIRST(&sc->card.pf_head);
- if (pf == NULL || (SIMPLEQ_NEXT(pf, pf_list) == NULL &&
- ((pf->pf_flags & PFF_FAKE) ||
- pf->cfe == NULL || pf->cfe->iftype == PCMCIA_IFTYPE_MEMORY)))
- return (PCMCIA_IFTYPE_MEMORY);
- else
- return (PCMCIA_IFTYPE_IO);
- }
- /*
- * Initialize a PCMCIA function. May be called as long as the function is
- * disabled.
- */
- void
- pcmcia_function_init(pf, cfe)
- struct pcmcia_function *pf;
- struct pcmcia_config_entry *cfe;
- {
- if (pf->pf_flags & PFF_ENABLED)
- panic("pcmcia_function_init: function is enabled");
- /* Remember which configuration entry we are using. */
- pf->cfe = cfe;
- }
- static inline void pcmcia_socket_enable(pct, pch)
- pcmcia_chipset_tag_t pct;
- pcmcia_chipset_handle_t *pch;
- {
- pcmcia_chip_socket_enable(pct, pch);
- }
- static inline void pcmcia_socket_disable(pct, pch)
- pcmcia_chipset_tag_t pct;
- pcmcia_chipset_handle_t *pch;
- {
- pcmcia_chip_socket_disable(pct, pch);
- }
- /* Enable a PCMCIA function */
- int
- pcmcia_function_enable(pf)
- struct pcmcia_function *pf;
- {
- struct pcmcia_function *tmp;
- int reg;
- if (pf->cfe == NULL)
- panic("pcmcia_function_enable: function not initialized");
- /*
- * Increase the reference count on the socket, enabling power, if
- * necessary.
- */
- if (pf->sc->sc_enabled_count++ == 0)
- pcmcia_chip_socket_enable(pf->sc->pct, pf->sc->pch);
- DPRINTF(("%s: ++enabled_count = %d\n", pf->sc->dev.dv_xname,
- pf->sc->sc_enabled_count));
- if (pf->pf_flags & PFF_ENABLED) {
- /*
- * Don't do anything if we're already enabled.
- */
- DPRINTF(("%s: pcmcia_function_enable on enabled func\n",
- pf->sc->dev.dv_xname));
- return (0);
- }
- /* If there was no CIS don't mess with CCR */
- if (pf->pf_flags & PFF_FAKE)
- goto done;
- /*
- * It's possible for different functions' CCRs to be in the same
- * underlying page. Check for that.
- */
- SIMPLEQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) {
- if ((tmp->pf_flags & PFF_ENABLED) &&
- (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) &&
- ((pf->ccr_base + PCMCIA_CCR_SIZE) <=
- (tmp->ccr_base - tmp->pf_ccr_offset +
- tmp->pf_ccr_realsize))) {
- pf->pf_ccrt = tmp->pf_ccrt;
- pf->pf_ccrh = tmp->pf_ccrh;
- pf->pf_ccr_realsize = tmp->pf_ccr_realsize;
- /*
- * pf->pf_ccr_offset = (tmp->pf_ccr_offset -
- * tmp->ccr_base) + pf->ccr_base;
- */
- pf->pf_ccr_offset =
- (tmp->pf_ccr_offset + pf->ccr_base) -
- tmp->ccr_base;
- pf->pf_ccr_window = tmp->pf_ccr_window;
- break;
- }
- }
- if (tmp == NULL) {
- if (pcmcia_mem_alloc(pf, PCMCIA_CCR_SIZE, &pf->pf_pcmh))
- goto bad;
- if (pcmcia_mem_map(pf, PCMCIA_MEM_ATTR, pf->ccr_base,
- PCMCIA_CCR_SIZE, &pf->pf_pcmh, &pf->pf_ccr_offset,
- &pf->pf_ccr_window)) {
- pcmcia_mem_free(pf, &pf->pf_pcmh);
- goto bad;
- }
- }
- reg = (pf->cfe->number & PCMCIA_CCR_OPTION_CFINDEX);
- reg |= PCMCIA_CCR_OPTION_LEVIREQ;
- if (pcmcia_mfc(pf->sc)) {
- reg |= PCMCIA_CCR_OPTION_FUNC_ENABLE;
- if (pf->ccr_mask & (1 << (PCMCIA_CCR_IOBASE0 / 2)))
- reg |= PCMCIA_CCR_OPTION_ADDR_DECODE;
- if (pf->ih_fct)
- reg |= PCMCIA_CCR_OPTION_IREQ_ENABLE;
- }
- pcmcia_ccr_write(pf, PCMCIA_CCR_OPTION, reg);
- reg = 0;
- if ((pf->cfe->flags & PCMCIA_CFE_IO16) == 0)
- reg |= PCMCIA_CCR_STATUS_IOIS8;
- if (pf->cfe->flags & PCMCIA_CFE_AUDIO)
- reg |= PCMCIA_CCR_STATUS_AUDIO;
- pcmcia_ccr_write(pf, PCMCIA_CCR_STATUS, reg);
- pcmcia_ccr_write(pf, PCMCIA_CCR_SOCKETCOPY, 0);
- if (pcmcia_mfc(pf->sc)) {
- pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE0,
- (pf->pf_mfc_iobase >> 0) & 0xff);
- pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE1,
- (pf->pf_mfc_iobase >> 8) & 0xff);
- pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE2,
- (pf->pf_mfc_iobase >> 16) & 0xff);
- pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE3,
- (pf->pf_mfc_iobase >> 24) & 0xff);
- pcmcia_ccr_write(pf, PCMCIA_CCR_IOSIZE,
- pf->pf_mfc_iomax - pf->pf_mfc_iobase);
- }
- #ifdef PCMCIADEBUG
- SIMPLEQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) {
- printf("%s: function %d CCR at %d offset %lx: "
- "%x %x %x %x, %x %x %x %x, %x\n",
- tmp->sc->dev.dv_xname, tmp->number,
- tmp->pf_ccr_window, tmp->pf_ccr_offset,
- pcmcia_ccr_read(tmp, 0x00),
- pcmcia_ccr_read(tmp, 0x02),
- pcmcia_ccr_read(tmp, 0x04),
- pcmcia_ccr_read(tmp, 0x06),
- pcmcia_ccr_read(tmp, 0x0A),
- pcmcia_ccr_read(tmp, 0x0C),
- pcmcia_ccr_read(tmp, 0x0E),
- pcmcia_ccr_read(tmp, 0x10),
- pcmcia_ccr_read(tmp, 0x12));
- }
- #endif
- done:
- pf->pf_flags |= PFF_ENABLED;
- delay(1000);
- return (0);
- bad:
- /*
- * Decrement the reference count, and power down the socket, if
- * necessary.
- */
- if (--pf->sc->sc_enabled_count == 0)
- pcmcia_chip_socket_disable(pf->sc->pct, pf->sc->pch);
- DPRINTF(("%s: --enabled_count = %d\n", pf->sc->dev.dv_xname,
- pf->sc->sc_enabled_count));
- return (1);
- }
- /* Disable PCMCIA function. */
- void
- pcmcia_function_disable(pf)
- struct pcmcia_function *pf;
- {
- struct pcmcia_function *tmp;
- if (pf->cfe == NULL)
- panic("pcmcia_function_enable: function not initialized");
- if ((pf->pf_flags & PFF_ENABLED) == 0) {
- /*
- * Don't do anything if we're already disabled.
- */
- return;
- }
- /* If there was no CIS don't mess with CCR */
- if (pf->pf_flags & PFF_FAKE) {
- pf->pf_flags &= ~PFF_ENABLED;
- goto done;
- }
- /*
- * it's possible for different functions' CCRs to be in the same
- * underlying page. Check for that. Note we mark us as disabled
- * first to avoid matching ourself.
- */
- pf->pf_flags &= ~PFF_ENABLED;
- SIMPLEQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) {
- if ((tmp->pf_flags & PFF_ENABLED) &&
- (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) &&
- ((pf->ccr_base + PCMCIA_CCR_SIZE) <=
- (tmp->ccr_base - tmp->pf_ccr_offset + tmp->pf_ccr_realsize)))
- break;
- }
- /* Not used by anyone else; unmap the CCR. */
- if (tmp == NULL) {
- pcmcia_mem_unmap(pf, pf->pf_ccr_window);
- pcmcia_mem_free(pf, &pf->pf_pcmh);
- }
- done:
- /*
- * Decrement the reference count, and power down the socket, if
- * necessary.
- */
- if (--pf->sc->sc_enabled_count == 0)
- pcmcia_chip_socket_disable(pf->sc->pct, pf->sc->pch);
- DPRINTF(("%s: --enabled_count = %d\n", pf->sc->dev.dv_xname,
- pf->sc->sc_enabled_count));
- }
- int
- pcmcia_io_map(pf, width, offset, size, pcihp, windowp)
- struct pcmcia_function *pf;
- int width;
- bus_addr_t offset;
- bus_size_t size;
- struct pcmcia_io_handle *pcihp;
- int *windowp;
- {
- int reg;
- if (pcmcia_chip_io_map(pf->sc->pct, pf->sc->pch,
- width, offset, size, pcihp, windowp))
- return (1);
- /*
- * XXX In the multifunction multi-iospace-per-function case, this
- * needs to cooperate with io_alloc to make sure that the spaces
- * don't overlap, and that the ccr's are set correctly.
- */
- if (pcmcia_mfc(pf->sc) &&
- (pf->ccr_mask & (1 << (PCMCIA_CCR_IOBASE0 / 2)))) {
- bus_addr_t iobase = pcihp->addr;
- bus_addr_t iomax = pcihp->addr + pcihp->size - 1;
- if (pf->pf_mfc_iomax == 0) {
- pf->pf_mfc_iobase = iobase;
- pf->pf_mfc_iomax = iomax;
- } else {
- if (iobase < pf->pf_mfc_iobase)
- pf->pf_mfc_iobase = iobase;
- if (iomax > pf->pf_mfc_iomax)
- pf->pf_mfc_iomax = iomax;
- }
- pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE0,
- (pf->pf_mfc_iobase >> 0) & 0xff);
- pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE1,
- (pf->pf_mfc_iobase >> 8) & 0xff);
- pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE2,
- (pf->pf_mfc_iobase >> 16) & 0xff);
- pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE3,
- (pf->pf_mfc_iobase >> 24) & 0xff);
- pcmcia_ccr_write(pf, PCMCIA_CCR_IOSIZE,
- pf->pf_mfc_iomax - pf->pf_mfc_iobase);
- reg = pcmcia_ccr_read(pf, PCMCIA_CCR_OPTION);
- reg |= PCMCIA_CCR_OPTION_ADDR_DECODE;
- pcmcia_ccr_write(pf, PCMCIA_CCR_OPTION, reg);
- }
- return (0);
- }
- void *
- pcmcia_intr_establish(pf, ipl, ih_fct, ih_arg, xname)
- struct pcmcia_function *pf;
- int ipl;
- int (*ih_fct)(void *);
- void *ih_arg;
- char *xname;
- {
- void *ret;
- int s, ihcnt, hiipl, reg;
- struct pcmcia_function *pf2;
- /* Behave differently if this is a multifunction card. */
- if (pcmcia_mfc(pf->sc)) {
- /*
- * Mask all the ipl's which are already used by this card,
- * and find the highest ipl number (lowest priority).
- */
- ihcnt = 0;
- SIMPLEQ_FOREACH(pf2, &pf->sc->card.pf_head, pf_list) {
- if (pf2->ih_fct) {
- DPRINTF(("%s: function %d has ih_fct %p\n",
- pf->sc->dev.dv_xname, pf2->number,
- pf2->ih_fct));
- if (ihcnt == 0)
- hiipl = pf2->ih_ipl;
- else if (pf2->ih_ipl > hiipl)
- hiipl = pf2->ih_ipl;
- ihcnt++;
- }
- }
- /*
- * Establish the real interrupt, changing the ipl if
- * necessary.
- */
- if (ihcnt == 0) {
- #ifdef DIAGNOSTIC
- if (pf->sc->ih != NULL)
- panic("card has intr handler, "
- "but no function does");
- #endif
- s = spltty();
- /* Set up the handler for the new function. */
- pf->ih_fct = ih_fct;
- pf->ih_arg = ih_arg;
- pf->ih_ipl = ipl;
- pf->sc->ih = pcmcia_chip_intr_establish(pf->sc->pct,
- pf->sc->pch, pf, ipl, pcmcia_card_intr, pf->sc,
- xname);
- splx(s);
- } else if (ipl > hiipl) {
- #ifdef DIAGNOSTIC
- if (pf->sc->ih == NULL)
- panic("functions have ih, "
- "but the card does not");
- #endif
- s = spltty();
- pcmcia_chip_intr_disestablish(pf->sc->pct, pf->sc->pch,
- pf->sc->ih);
- /* set up the handler for the new function */
- pf->ih_fct = ih_fct;
- pf->ih_arg = ih_arg;
- pf->ih_ipl = ipl;
- pf->sc->ih = pcmcia_chip_intr_establish(pf->sc->pct,
- pf->sc->pch, pf, ipl, pcmcia_card_intr, pf->sc,
- xname);
- splx(s);
- } else {
- s = spltty();
- /* Set up the handler for the new function. */
- pf->ih_fct = ih_fct;
- pf->ih_arg = ih_arg;
- pf->ih_ipl = ipl;
- splx(s);
- }
- ret = pf->sc->ih;
- if (ret != NULL) {
- reg = pcmcia_ccr_read(pf, PCMCIA_CCR_OPTION);
- reg |= PCMCIA_CCR_OPTION_IREQ_ENABLE;
- pcmcia_ccr_write(pf, PCMCIA_CCR_OPTION, reg);
- reg = pcmcia_ccr_read(pf, PCMCIA_CCR_STATUS);
- reg |= PCMCIA_CCR_STATUS_INTRACK;
- pcmcia_ccr_write(pf, PCMCIA_CCR_STATUS, reg);
- }
- } else
- ret = pcmcia_chip_intr_establish(pf->sc->pct, pf->sc->pch,
- pf, ipl, ih_fct, ih_arg, xname);
- return (ret);
- }
- void
- pcmcia_intr_disestablish(pf, ih)
- struct pcmcia_function *pf;
- void *ih;
- {
- int s, reg, ihcnt, hiipl;
- struct pcmcia_function *pf2;
- /* Behave differently if this is a multifunction card. */
- if (pcmcia_mfc(pf->sc)) {
- /*
- * Mask all the ipl's which are already used by this card,
- * and find the highest ipl number (lowest priority). Skip
- * the current function.
- */
- ihcnt = 0;
- SIMPLEQ_FOREACH(pf2, &pf->sc->card.pf_head, pf_list) {
- if (pf2 == pf)
- continue;
- if (pf2->ih_fct) {
- if (ihcnt == 0)
- hiipl = pf2->ih_ipl;
- else if (pf2->ih_ipl > hiipl)
- hiipl = pf2->ih_ipl;
- ihcnt++;
- }
- }
- /*
- * If the ih being removed is lower priority than the lowest
- * priority remaining interrupt, up the priority.
- */
- /*
- * ihcnt is the number of interrupt handlers *not* including
- * the one about to be removed.
- */
- if (ihcnt == 0) {
- #ifdef DIAGNOSTIC
- if (pf->sc->ih == NULL)
- panic("disestablishing last function, but card has no ih");
- #endif
- pcmcia_chip_intr_disestablish(pf->sc->pct, pf->sc->pch,
- pf->sc->ih);
- reg = pcmcia_ccr_read(pf, PCMCIA_CCR_OPTION);
- reg &= ~PCMCIA_CCR_OPTION_IREQ_ENABLE;
- pcmcia_ccr_write(pf, PCMCIA_CCR_OPTION, reg);
- pf->ih_fct = NULL;
- pf->ih_arg = NULL;
- pf->sc->ih = NULL;
- } else if (pf->ih_ipl > hiipl) {
- #ifdef DIAGNOSTIC
- if (pf->sc->ih == NULL)
- panic("changing ih ipl, but card has no ih");
- #endif
- s = spltty();
- pcmcia_chip_intr_disestablish(pf->sc->pct, pf->sc->pch,
- pf->sc->ih);
- pf->sc->ih = pcmcia_chip_intr_establish(pf->sc->pct,
- pf->sc->pch, pf, hiipl, pcmcia_card_intr, pf->sc,
- NULL);
- /* Null out the handler for this function. */
- pf->ih_fct = NULL;
- pf->ih_arg = NULL;
- splx(s);
- } else {
- s = spltty();
- pf->ih_fct = NULL;
- pf->ih_arg = NULL;
- splx(s);
- }
- } else
- pcmcia_chip_intr_disestablish(pf->sc->pct, pf->sc->pch, ih);
- }
- const char *
- pcmcia_intr_string(pf, ih)
- struct pcmcia_function *pf;
- void *ih;
- {
- return pcmcia_chip_intr_string(pf->sc->pct, pf->sc->pch, ih);
- }
- int
- pcmcia_card_intr(arg)
- void *arg;
- {
- struct pcmcia_softc *sc = arg;
- struct pcmcia_function *pf;
- int reg, ret, ret2;
- ret = 0;
- for (pf = SIMPLEQ_FIRST(&sc->card.pf_head); pf != NULL;
- pf = SIMPLEQ_NEXT(pf, pf_list)) {
- #ifdef PCMCIADEBUG
- printf("%s: intr flags=%x fct=%d cor=%02x csr=%02x pin=%02x",
- sc->dev.dv_xname, pf->pf_flags, pf->number,
- pcmcia_ccr_read(pf, PCMCIA_CCR_OPTION),
- pcmcia_ccr_read(pf, PCMCIA_CCR_STATUS),
- pcmcia_ccr_read(pf, PCMCIA_CCR_PIN));
- #endif
- if (pf->ih_fct != NULL &&
- (pf->ccr_mask & (1 << (PCMCIA_CCR_STATUS / 2)))) {
- reg = pcmcia_ccr_read(pf, PCMCIA_CCR_STATUS);
- if (reg & PCMCIA_CCR_STATUS_INTR) {
- ret2 = (*pf->ih_fct)(pf->ih_arg);
- if (ret2 != 0 && ret == 0)
- ret = ret2;
- reg = pcmcia_ccr_read(pf, PCMCIA_CCR_STATUS);
- #ifdef PCMCIADEBUG
- printf("; csr %02x->%02x",
- reg, reg & ~PCMCIA_CCR_STATUS_INTR);
- #endif
- pcmcia_ccr_write(pf, PCMCIA_CCR_STATUS,
- reg & ~PCMCIA_CCR_STATUS_INTR);
- }
- }
- #ifdef PCMCIADEBUG
- printf("\n");
- #endif
- }
- return (ret);
- }
|